1 /* 2 * Copyright 2011 Haiku Inc. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * John Scipione, jscipione@gmail.com 7 */ 8 9 10 #include "ModifierKeysWindow.h" 11 12 #include <stdio.h> 13 #include <stdlib.h> 14 #include <string.h> 15 16 #include <Catalog.h> 17 #include <GroupLayout.h> 18 #include <GridLayoutBuilder.h> 19 #include <GroupLayoutBuilder.h> 20 #include <Locale.h> 21 #include <LayoutBuilder.h> 22 #include <MenuItem.h> 23 #include <Message.h> 24 #include <Size.h> 25 #include <StringView.h> 26 27 #include "KeymapApplication.h" 28 29 30 enum { 31 MENU_ITEM_CAPS_LOCK = 0, 32 MENU_ITEM_CONTROL, 33 MENU_ITEM_OPTION, 34 MENU_ITEM_COMMAND, 35 MENU_ITEM_SEPERATOR, 36 MENU_ITEM_DISABLED 37 }; 38 39 static const uint32 kMsgUpdateModifier = 'upmd'; 40 static const uint32 kMsgApplyModifiers = 'apmd'; 41 static const uint32 kMsgRevertModifiers = 'rvmd'; 42 43 44 #undef B_TRANSLATE_CONTEXT 45 #define B_TRANSLATE_CONTEXT "Modifier Keys window" 46 47 48 ModifierKeysWindow::ModifierKeysWindow() 49 : 50 BWindow(BRect(80, 50, 400, 260), B_TRANSLATE("Modifier Keys"), 51 B_TITLED_WINDOW, B_NOT_RESIZABLE | B_NOT_ZOOMABLE 52 | B_AUTO_UPDATE_SIZE_LIMITS) 53 { 54 get_key_map(&fCurrentMap, &fCurrentBuffer); 55 get_key_map(&fSavedMap, &fSavedBuffer); 56 57 BStringView* capsLockStringView 58 = new BStringView("caps", B_TRANSLATE("Caps Lock:")); 59 capsLockStringView->SetExplicitMaxSize( 60 BSize(B_SIZE_UNLIMITED, B_SIZE_UNSET)); 61 62 BStringView* controlStringView 63 = new BStringView("control", B_TRANSLATE("Control:")); 64 controlStringView->SetExplicitMaxSize( 65 BSize(B_SIZE_UNLIMITED, B_SIZE_UNSET)); 66 67 BStringView* optionStringView 68 = new BStringView("option", B_TRANSLATE("Option:")); 69 optionStringView->SetExplicitMaxSize( 70 BSize(B_SIZE_UNLIMITED, B_SIZE_UNSET)); 71 72 BStringView* commandStringView 73 = new BStringView("command", B_TRANSLATE("Command:")); 74 commandStringView->SetExplicitMaxSize( 75 BSize(B_SIZE_UNLIMITED, B_SIZE_UNSET)); 76 77 fCancelButton = new BButton("CancelButton", B_TRANSLATE("Cancel"), 78 new BMessage(B_QUIT_REQUESTED)); 79 80 fRevertButton = new BButton("revertButton", B_TRANSLATE("Revert"), 81 new BMessage(kMsgRevertModifiers)); 82 fRevertButton->SetEnabled(false); 83 84 fOkButton = new BButton("OkButton", B_TRANSLATE("OK"), 85 new BMessage(kMsgApplyModifiers)); 86 fOkButton->MakeDefault(true); 87 88 // Build the layout 89 SetLayout(new BGroupLayout(B_VERTICAL)); 90 91 AddChild(BGroupLayoutBuilder(B_VERTICAL, 10) 92 .Add(BGridLayoutBuilder(10, 10) 93 .Add(capsLockStringView, 0, 0) 94 .Add(_CreateCapsLockMenuField(), 1, 0) 95 96 .Add(controlStringView, 0, 1) 97 .Add(_CreateControlMenuField(), 1, 1) 98 99 .Add(optionStringView, 0, 2) 100 .Add(_CreateOptionMenuField(), 1, 2) 101 102 .Add(commandStringView, 0, 3) 103 .Add(_CreateCommandMenuField(), 1, 3) 104 ) 105 .AddGlue() 106 .AddGroup(B_HORIZONTAL, 10) 107 .Add(fCancelButton) 108 .AddGlue() 109 .Add(fRevertButton) 110 .Add(fOkButton) 111 .End() 112 .SetInsets(10, 10, 10, 10) 113 ); 114 115 CenterOnScreen(); 116 } 117 118 119 ModifierKeysWindow::~ModifierKeysWindow() 120 { 121 be_app->PostMessage(kMsgCloseModifierKeysWindow); 122 } 123 124 125 void 126 ModifierKeysWindow::MessageReceived(BMessage* message) 127 { 128 switch (message->what) { 129 case kMsgUpdateModifier: 130 { 131 int32 menu = MENU_ITEM_CAPS_LOCK; 132 int32 key = -1; 133 134 for (; menu <= MENU_ITEM_COMMAND; menu++) { 135 if (message->FindInt32(_KeyToString(menu), &key) == B_OK) 136 break; 137 } 138 139 if (key == -1) { 140 // No option was found, don't update 141 return; 142 } 143 144 // Now 'menu' contains the menu we want to set and 'key' contains 145 // the option we want to set it to. 146 147 switch (menu) { 148 case MENU_ITEM_CAPS_LOCK: 149 fCurrentMap->caps_key = _KeyToKeyCode(key); 150 fCapsLockMenu->ItemAt(key)->SetMarked(true); 151 break; 152 153 case MENU_ITEM_CONTROL: 154 fCurrentMap->left_control_key 155 = _KeyToKeyCode(key); 156 if (key != MENU_ITEM_CAPS_LOCK) { 157 fCurrentMap->right_control_key 158 = _KeyToKeyCode(key, true); 159 } 160 161 fControlMenu->ItemAt(key)->SetMarked(true); 162 break; 163 164 case MENU_ITEM_OPTION: 165 fCurrentMap->left_option_key 166 = _KeyToKeyCode(key); 167 if (key != MENU_ITEM_CAPS_LOCK) { 168 fCurrentMap->right_option_key 169 = _KeyToKeyCode(key, true); 170 } 171 172 fOptionMenu->ItemAt(key)->SetMarked(true); 173 break; 174 175 case MENU_ITEM_COMMAND: 176 fCurrentMap->left_command_key 177 = _KeyToKeyCode(key); 178 if (key != MENU_ITEM_CAPS_LOCK) { 179 fCurrentMap->right_command_key 180 = _KeyToKeyCode(key, true); 181 } 182 183 fCommandMenu->ItemAt(key)->SetMarked(true); 184 break; 185 } 186 187 fRevertButton->SetEnabled(memcmp(fCurrentMap, fSavedMap, 188 sizeof(key_map))); 189 break; 190 } 191 192 // Ok button 193 case kMsgApplyModifiers: 194 { 195 BMessage* updateModifiers = new BMessage(kMsgUpdateModifiers); 196 197 if (fCurrentMap->caps_key != fSavedMap->caps_key) 198 updateModifiers->AddUInt32("caps_key", fCurrentMap->caps_key); 199 200 if (fCurrentMap->left_control_key != fSavedMap->left_control_key) { 201 updateModifiers->AddUInt32("left_control_key", 202 fCurrentMap->left_control_key); 203 } 204 205 if (fCurrentMap->right_control_key 206 != fSavedMap->right_control_key) { 207 updateModifiers->AddUInt32("right_control_key", 208 fCurrentMap->right_control_key); 209 } 210 211 if (fCurrentMap->left_option_key != fSavedMap->left_option_key) { 212 updateModifiers->AddUInt32("left_option_key", 213 fCurrentMap->left_option_key); 214 } 215 216 if (fCurrentMap->right_option_key != fSavedMap->right_option_key) { 217 updateModifiers->AddUInt32("right_option_key", 218 fCurrentMap->right_option_key); 219 } 220 221 if (fCurrentMap->left_command_key != fSavedMap->left_command_key) { 222 updateModifiers->AddUInt32("left_command_key", 223 fCurrentMap->left_command_key); 224 } 225 226 if (fCurrentMap->right_command_key 227 != fSavedMap->right_command_key) { 228 updateModifiers->AddUInt32("right_command_key", 229 fCurrentMap->right_command_key); 230 } 231 232 // Tell KeymapWindow to update the modifier keys 233 be_app->PostMessage(updateModifiers); 234 235 // We are done here, close the window 236 this->PostMessage(B_QUIT_REQUESTED); 237 break; 238 } 239 240 // Revert button 241 case kMsgRevertModifiers: 242 memcpy(fCurrentMap, fSavedMap, sizeof(key_map)); 243 244 _MarkMenuItems(); 245 fRevertButton->SetEnabled(false); 246 break; 247 248 default: 249 BWindow::MessageReceived(message); 250 } 251 } 252 253 254 BMenuField* 255 ModifierKeysWindow::_CreateCapsLockMenuField() 256 { 257 fCapsLockMenu = new BPopUpMenu( 258 B_TRANSLATE(_KeyToString(MENU_ITEM_CAPS_LOCK)), true, true); 259 260 for (int32 key = MENU_ITEM_CAPS_LOCK; key <= MENU_ITEM_DISABLED; key++) { 261 if (key == MENU_ITEM_SEPERATOR) { 262 BSeparatorItem* separator = new BSeparatorItem; 263 fCapsLockMenu->AddItem(separator, key); 264 } else { 265 BMessage* message = new BMessage(kMsgUpdateModifier); 266 message->AddInt32(_KeyToString(MENU_ITEM_CAPS_LOCK), key); 267 268 BMenuItem* item = new BMenuItem(B_TRANSLATE(_KeyToString(key)), 269 message); 270 271 if (fCurrentMap->caps_key == _KeyToKeyCode(key)) 272 item->SetMarked(true); 273 274 fCapsLockMenu->AddItem(item, key); 275 } 276 } 277 278 return new BMenuField(NULL, fCapsLockMenu); 279 } 280 281 282 BMenuField* 283 ModifierKeysWindow::_CreateControlMenuField() 284 { 285 fControlMenu = new BPopUpMenu( 286 B_TRANSLATE(_KeyToString(MENU_ITEM_CONTROL)), true, true); 287 288 for (int32 key = MENU_ITEM_CAPS_LOCK; key <= MENU_ITEM_COMMAND; key++) { 289 BMessage* message = new BMessage(kMsgUpdateModifier); 290 message->AddInt32(_KeyToString(MENU_ITEM_CONTROL), key); 291 292 BMenuItem* item = new BMenuItem(B_TRANSLATE(_KeyToString(key)), 293 message); 294 295 if (fCurrentMap->left_control_key == _KeyToKeyCode(key) 296 && fCurrentMap->right_control_key == _KeyToKeyCode(key, true)) 297 item->SetMarked(true); 298 299 fControlMenu->AddItem(item, key); 300 } 301 302 return new BMenuField(NULL, fControlMenu); 303 } 304 305 306 BMenuField* 307 ModifierKeysWindow::_CreateOptionMenuField() 308 { 309 fOptionMenu = new BPopUpMenu( 310 B_TRANSLATE(_KeyToString(MENU_ITEM_OPTION)), true, true); 311 312 for (int32 key = MENU_ITEM_CAPS_LOCK; key <= MENU_ITEM_COMMAND; key++) { 313 BMessage* message = new BMessage(kMsgUpdateModifier); 314 message->AddInt32(_KeyToString(MENU_ITEM_OPTION), key); 315 316 BMenuItem* item = new BMenuItem(B_TRANSLATE(_KeyToString(key)), 317 message); 318 319 if (fCurrentMap->left_option_key == _KeyToKeyCode(key) 320 && fCurrentMap->right_option_key == _KeyToKeyCode(key, true)) 321 item->SetMarked(true); 322 323 fOptionMenu->AddItem(item, key); 324 } 325 326 return new BMenuField(NULL, fOptionMenu); 327 } 328 329 330 BMenuField* 331 ModifierKeysWindow::_CreateCommandMenuField() 332 { 333 fCommandMenu = new BPopUpMenu( 334 B_TRANSLATE(_KeyToString(MENU_ITEM_COMMAND)), true, true); 335 336 for (int32 key = MENU_ITEM_CAPS_LOCK; key <= MENU_ITEM_COMMAND; key++) { 337 BMessage* message = new BMessage(kMsgUpdateModifier); 338 message->AddInt32(_KeyToString(MENU_ITEM_COMMAND), key); 339 340 BMenuItem* item = new BMenuItem(B_TRANSLATE(_KeyToString(key)), 341 message); 342 343 if (fCurrentMap->left_command_key == _KeyToKeyCode(key) 344 && fCurrentMap->right_command_key == _KeyToKeyCode(key, true)) 345 item->SetMarked(true); 346 347 fCommandMenu->AddItem(item, key); 348 } 349 350 return new BMenuField(NULL, fCommandMenu); 351 } 352 353 354 void 355 ModifierKeysWindow::_MarkMenuItems() 356 { 357 for (int32 key = MENU_ITEM_CAPS_LOCK; key <= MENU_ITEM_COMMAND; key++) { 358 if (fCurrentMap->caps_key == _KeyToKeyCode(key)) 359 fCapsLockMenu->ItemAt(key)->SetMarked(true); 360 361 if (fCurrentMap->left_control_key == _KeyToKeyCode(key) 362 && fCurrentMap->right_control_key == _KeyToKeyCode(key, true)) 363 fControlMenu->ItemAt(key)->SetMarked(true); 364 365 if (fCurrentMap->left_option_key == _KeyToKeyCode(key) 366 && fCurrentMap->right_option_key == _KeyToKeyCode(key, true)) 367 fOptionMenu->ItemAt(key)->SetMarked(true); 368 369 if (fCurrentMap->left_command_key == _KeyToKeyCode(key) 370 && fCurrentMap->right_command_key == _KeyToKeyCode(key, true)) 371 fCommandMenu->ItemAt(key)->SetMarked(true); 372 } 373 374 // Check if caps lock is disabled 375 if (fCurrentMap->caps_key == _KeyToKeyCode(MENU_ITEM_DISABLED)) 376 fCapsLockMenu->ItemAt(MENU_ITEM_DISABLED)->SetMarked(true); 377 } 378 379 380 const char* 381 ModifierKeysWindow::_KeyToString(int32 key) 382 { 383 switch (key) { 384 case MENU_ITEM_CAPS_LOCK: 385 return "Caps Lock"; 386 case MENU_ITEM_CONTROL: 387 return "Control"; 388 case MENU_ITEM_OPTION: 389 return "Option"; 390 case MENU_ITEM_COMMAND: 391 return "Command"; 392 case MENU_ITEM_DISABLED: 393 return "Disabled"; 394 } 395 396 return ""; 397 } 398 399 400 uint32 401 ModifierKeysWindow::_KeyToKeyCode(int32 key, bool right) 402 { 403 switch (key) { 404 case MENU_ITEM_CAPS_LOCK: 405 return 0x3b; 406 case MENU_ITEM_CONTROL: 407 if (right) 408 return 0x60; 409 return 0x5c; 410 case MENU_ITEM_OPTION: 411 if (right) 412 return 0x67; 413 return 0x66; 414 case MENU_ITEM_COMMAND: 415 if (right) 416 return 0x5f; 417 return 0x5d; 418 case MENU_ITEM_DISABLED: 419 return 0; 420 } 421 422 return 0; 423 } 424