1 /* 2 * Copyright 2004-2010, Haiku, Inc. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Jérôme Duval 7 */ 8 9 10 #include "Keymap.h" 11 12 #include <ByteOrder.h> 13 #include <File.h> 14 #include <InputServerTypes.h> 15 #include <Message.h> 16 #ifdef CONSOLED 17 # include <FindDirectory.h> 18 #else 19 # include <input_globals.h> 20 #endif 21 22 #include <errno.h> 23 #include <new> 24 #include <stdlib.h> 25 #include <stdio.h> 26 #include <string.h> 27 28 29 static void 30 print_key(char *chars, int32 offset) 31 { 32 int size = chars[offset++]; 33 34 switch (size) { 35 case 0: 36 // Not mapped 37 printf("N/A"); 38 break; 39 40 case 1: 41 // 1-byte UTF-8/ASCII character 42 printf("%c", chars[offset]); 43 break; 44 45 default: 46 { 47 // 2-, 3-, or 4-byte UTF-8 character 48 char *str = new (std::nothrow) char[size + 1]; 49 if (str == NULL) 50 break; 51 52 strncpy(str, &(chars[offset]), size); 53 str[size] = 0; 54 printf("%s", str); 55 delete [] str; 56 break; 57 } 58 } 59 60 printf("\t"); 61 } 62 63 64 // #pragma mark - 65 66 67 void 68 Keymap::DumpKeymap() 69 { 70 // Print a chart of the normal, shift, option, and option+shift 71 // keys. 72 printf("Key #\tNormal\tShift\tCaps\tC+S\tOption\tO+S\tO+C\tO+C+S\tControl\n"); 73 74 for (int i = 0; i < 128; i++) { 75 printf(" 0x%x\t", i); 76 print_key(fChars, fKeys.normal_map[i]); 77 print_key(fChars, fKeys.shift_map[i]); 78 print_key(fChars, fKeys.caps_map[i]); 79 print_key(fChars, fKeys.caps_shift_map[i]); 80 print_key(fChars, fKeys.option_map[i]); 81 print_key(fChars, fKeys.option_shift_map[i]); 82 print_key(fChars, fKeys.option_caps_map[i]); 83 print_key(fChars, fKeys.option_caps_shift_map[i]); 84 print_key(fChars, fKeys.control_map[i]); 85 printf("\n"); 86 } 87 } 88 89 90 Keymap::Keymap() 91 : 92 fChars(NULL) 93 { 94 #ifndef CONSOLED 95 key_map *keys; 96 _get_key_map(&keys, &fChars, &fCharsSize); 97 98 if (keys) { 99 memcpy(&fKeys, keys, sizeof(key_map)); 100 free(keys); 101 } 102 #endif 103 } 104 105 106 Keymap::~Keymap() 107 { 108 free(fChars); 109 } 110 111 112 /* we need to know if a key is a modifier key to choose 113 a valid key when several are pressed together 114 */ 115 bool 116 Keymap::IsModifierKey(uint32 keyCode) 117 { 118 return keyCode == fKeys.caps_key 119 || keyCode == fKeys.num_key 120 || keyCode == fKeys.scroll_key 121 || keyCode == fKeys.left_shift_key 122 || keyCode == fKeys.right_shift_key 123 || keyCode == fKeys.left_command_key 124 || keyCode == fKeys.right_command_key 125 || keyCode == fKeys.left_control_key 126 || keyCode == fKeys.right_control_key 127 || keyCode == fKeys.left_option_key 128 || keyCode == fKeys.right_option_key 129 || keyCode == fKeys.menu_key; 130 } 131 132 133 //! We need to know a modifier for a key 134 uint32 135 Keymap::Modifier(uint32 keyCode) 136 { 137 if (keyCode == fKeys.caps_key) 138 return B_CAPS_LOCK; 139 if (keyCode == fKeys.num_key) 140 return B_NUM_LOCK; 141 if (keyCode == fKeys.scroll_key) 142 return B_SCROLL_LOCK; 143 if (keyCode == fKeys.left_shift_key) 144 return B_LEFT_SHIFT_KEY | B_SHIFT_KEY; 145 if (keyCode == fKeys.right_shift_key) 146 return B_RIGHT_SHIFT_KEY | B_SHIFT_KEY; 147 if (keyCode == fKeys.left_command_key) 148 return B_LEFT_COMMAND_KEY | B_COMMAND_KEY; 149 if (keyCode == fKeys.right_command_key) 150 return B_RIGHT_COMMAND_KEY | B_COMMAND_KEY; 151 if (keyCode == fKeys.left_control_key) 152 return B_LEFT_CONTROL_KEY | B_CONTROL_KEY; 153 if (keyCode == fKeys.right_control_key) 154 return B_RIGHT_CONTROL_KEY | B_CONTROL_KEY; 155 if (keyCode == fKeys.left_option_key) 156 return B_LEFT_OPTION_KEY | B_OPTION_KEY; 157 if (keyCode == fKeys.right_option_key) 158 return B_RIGHT_OPTION_KEY | B_OPTION_KEY; 159 if (keyCode == fKeys.menu_key) 160 return B_MENU_KEY; 161 162 return 0; 163 } 164 165 166 uint32 167 Keymap::KeyForModifier(uint32 modifier) 168 { 169 if (modifier == B_CAPS_LOCK) 170 return fKeys.caps_key; 171 if (modifier == B_NUM_LOCK) 172 return fKeys.num_key; 173 if (modifier == B_SCROLL_LOCK) 174 return fKeys.scroll_key; 175 if (modifier == B_LEFT_SHIFT_KEY || modifier == B_SHIFT_KEY) 176 return fKeys.left_shift_key; 177 if (modifier == B_RIGHT_SHIFT_KEY) 178 return fKeys.right_shift_key; 179 if (modifier == B_LEFT_COMMAND_KEY || modifier == B_COMMAND_KEY) 180 return fKeys.left_command_key; 181 if (modifier == B_RIGHT_COMMAND_KEY) 182 return fKeys.right_command_key; 183 if (modifier == B_LEFT_CONTROL_KEY || modifier == B_CONTROL_KEY) 184 return fKeys.left_control_key; 185 if (modifier == B_RIGHT_CONTROL_KEY) 186 return fKeys.right_control_key; 187 if (modifier == B_LEFT_OPTION_KEY || modifier == B_OPTION_KEY) 188 return fKeys.left_option_key; 189 if (modifier == B_RIGHT_OPTION_KEY) 190 return fKeys.right_option_key; 191 if (modifier == B_MENU_KEY) 192 return fKeys.menu_key; 193 194 return 0; 195 } 196 197 198 //! Tell if a key is a dead key, needed for draw a dead key 199 uint8 200 Keymap::IsDeadKey(uint32 keyCode, uint32 modifiers) 201 { 202 if (keyCode >= 256) 203 return 0; 204 205 int32 offset; 206 uint32 tableMask = 0; 207 208 switch (modifiers & 0xcf) { 209 case B_SHIFT_KEY: offset = fKeys.shift_map[keyCode]; tableMask = B_SHIFT_TABLE; break; 210 case B_CAPS_LOCK: offset = fKeys.caps_map[keyCode]; tableMask = B_CAPS_TABLE; break; 211 case B_CAPS_LOCK|B_SHIFT_KEY: offset = fKeys.caps_shift_map[keyCode]; tableMask = B_CAPS_SHIFT_TABLE; break; 212 case B_OPTION_KEY: offset = fKeys.option_map[keyCode]; tableMask = B_OPTION_TABLE; break; 213 case B_OPTION_KEY|B_SHIFT_KEY: offset = fKeys.option_shift_map[keyCode]; tableMask = B_OPTION_SHIFT_TABLE; break; 214 case B_OPTION_KEY|B_CAPS_LOCK: offset = fKeys.option_caps_map[keyCode]; tableMask = B_OPTION_CAPS_TABLE; break; 215 case B_OPTION_KEY|B_SHIFT_KEY|B_CAPS_LOCK: offset = fKeys.option_caps_shift_map[keyCode]; tableMask = B_OPTION_CAPS_SHIFT_TABLE; break; 216 case B_CONTROL_KEY: offset = fKeys.control_map[keyCode]; tableMask = B_CONTROL_TABLE; break; 217 default: offset = fKeys.normal_map[keyCode]; tableMask = B_NORMAL_TABLE; break; 218 } 219 220 if (offset <= 0 || offset > fCharsSize) 221 return 0; 222 223 uint32 numBytes = fChars[offset]; 224 if (!numBytes) 225 return 0; 226 227 char chars[4]; 228 strncpy(chars, &(fChars[offset+1]), numBytes ); 229 chars[numBytes] = 0; 230 231 int32 deadOffsets[] = { 232 fKeys.acute_dead_key[1], 233 fKeys.grave_dead_key[1], 234 fKeys.circumflex_dead_key[1], 235 fKeys.dieresis_dead_key[1], 236 fKeys.tilde_dead_key[1] 237 }; 238 239 uint32 deadTables[] = { 240 fKeys.acute_tables, 241 fKeys.grave_tables, 242 fKeys.circumflex_tables, 243 fKeys.dieresis_tables, 244 fKeys.tilde_tables 245 }; 246 247 for (int32 i = 0; i < 5; i++) { 248 if ((deadTables[i] & tableMask) == 0) 249 continue; 250 251 if (offset == deadOffsets[i]) 252 return i + 1; 253 254 uint32 deadNumBytes = fChars[deadOffsets[i]]; 255 if (!deadNumBytes) 256 continue; 257 258 if (!strncmp(chars, &(fChars[deadOffsets[i] + 1]), deadNumBytes)) 259 return i + 1; 260 } 261 return 0; 262 } 263 264 265 //! Tell if a key is a dead second key, needed for draw a dead second key 266 bool 267 Keymap::IsDeadSecondKey(uint32 keyCode, uint32 modifiers, uint8 activeDeadKey) 268 { 269 if (!activeDeadKey || keyCode >= 256) 270 return false; 271 272 int32 offset; 273 274 switch (modifiers & 0xcf) { 275 case B_SHIFT_KEY: offset = fKeys.shift_map[keyCode]; break; 276 case B_CAPS_LOCK: offset = fKeys.caps_map[keyCode]; break; 277 case B_CAPS_LOCK|B_SHIFT_KEY: offset = fKeys.caps_shift_map[keyCode]; break; 278 case B_OPTION_KEY: offset = fKeys.option_map[keyCode]; break; 279 case B_OPTION_KEY|B_SHIFT_KEY: offset = fKeys.option_shift_map[keyCode]; break; 280 case B_OPTION_KEY|B_CAPS_LOCK: offset = fKeys.option_caps_map[keyCode]; break; 281 case B_OPTION_KEY|B_SHIFT_KEY|B_CAPS_LOCK: offset = fKeys.option_caps_shift_map[keyCode]; break; 282 case B_CONTROL_KEY: offset = fKeys.control_map[keyCode]; break; 283 default: offset = fKeys.normal_map[keyCode]; break; 284 } 285 286 if (offset <= 0 || offset > fCharsSize) 287 return false; 288 289 uint32 numBytes = fChars[offset]; 290 if (!numBytes) 291 return false; 292 293 int32* deadOffsets[] = { 294 fKeys.acute_dead_key, 295 fKeys.grave_dead_key, 296 fKeys.circumflex_dead_key, 297 fKeys.dieresis_dead_key, 298 fKeys.tilde_dead_key 299 }; 300 301 int32 *deadOffset = deadOffsets[activeDeadKey-1]; 302 303 for (int32 i=0; i<32; i++) { 304 if (offset == deadOffset[i]) 305 return true; 306 307 uint32 deadNumBytes = fChars[deadOffset[i]]; 308 if (!deadNumBytes) 309 continue; 310 311 if (!strncmp(&(fChars[offset+1]), &(fChars[deadOffset[i]+1]), deadNumBytes)) 312 return true; 313 314 i++; 315 } 316 317 return false; 318 } 319 320 321 //! Get the char for a key given modifiers and active dead key 322 void 323 Keymap::GetChars(uint32 keyCode, uint32 modifiers, uint8 activeDeadKey, 324 char** chars, int32* numBytes) 325 { 326 *numBytes = 0; 327 *chars = NULL; 328 329 if (keyCode >= 256) 330 return; 331 332 // here we take NUMLOCK into account 333 if (modifiers & B_NUM_LOCK) { 334 switch (keyCode) { 335 case 0x37: 336 case 0x38: 337 case 0x39: 338 case 0x48: 339 case 0x49: 340 case 0x4a: 341 case 0x58: 342 case 0x59: 343 case 0x5a: 344 case 0x64: 345 case 0x65: 346 modifiers ^= B_SHIFT_KEY; 347 break; 348 } 349 } 350 351 int32 offset; 352 353 // here we choose the right map given the modifiers 354 switch (modifiers & 0xcf) { 355 case B_SHIFT_KEY: offset = fKeys.shift_map[keyCode]; break; 356 case B_CAPS_LOCK: offset = fKeys.caps_map[keyCode]; break; 357 case B_CAPS_LOCK|B_SHIFT_KEY: offset = fKeys.caps_shift_map[keyCode]; break; 358 case B_OPTION_KEY: offset = fKeys.option_map[keyCode]; break; 359 case B_OPTION_KEY|B_SHIFT_KEY: offset = fKeys.option_shift_map[keyCode]; break; 360 case B_OPTION_KEY|B_CAPS_LOCK: offset = fKeys.option_caps_map[keyCode]; break; 361 case B_OPTION_KEY|B_SHIFT_KEY|B_CAPS_LOCK: offset = fKeys.option_caps_shift_map[keyCode]; break; 362 case B_CONTROL_KEY: offset = fKeys.control_map[keyCode]; break; 363 364 default: 365 offset = fKeys.normal_map[keyCode]; 366 break; 367 } 368 369 if (offset <= 0) 370 return; 371 372 // here we get the char size 373 *numBytes = fChars[offset]; 374 if (!*numBytes) 375 return; 376 377 // here we take an potential active dead key 378 int32 *deadKey; 379 switch (activeDeadKey) { 380 case 1: deadKey = fKeys.acute_dead_key; break; 381 case 2: deadKey = fKeys.grave_dead_key; break; 382 case 3: deadKey = fKeys.circumflex_dead_key; break; 383 case 4: deadKey = fKeys.dieresis_dead_key; break; 384 case 5: deadKey = fKeys.tilde_dead_key; break; 385 default: 386 { 387 // if not dead, we copy and return the char 388 char *str = *chars = new (std::nothrow) char[*numBytes + 1]; 389 if (str == NULL) { 390 *numBytes = 0; 391 return; 392 } 393 strncpy(str, &(fChars[offset + 1]), *numBytes); 394 str[*numBytes] = 0; 395 return; 396 } 397 } 398 399 // if dead key, we search for our current offset char in the dead key offset table 400 // string comparison is needed 401 for (int32 i = 0; i < 32; i++) { 402 if (strncmp(&(fChars[offset + 1]), &(fChars[deadKey[i] + 1]), *numBytes) == 0) { 403 *numBytes = fChars[deadKey[i + 1]]; 404 405 switch (*numBytes) { 406 case 0: 407 // Not mapped 408 *chars = NULL; 409 break; 410 default: 411 { 412 // 1-, 2-, 3-, or 4-byte UTF-8 character 413 char *str = *chars = new (std::nothrow) char[*numBytes + 1]; 414 if (str == NULL) { 415 *numBytes = 0; 416 return; 417 } 418 strncpy(str, &fChars[deadKey[i + 1] + 1], *numBytes); 419 str[*numBytes] = 0; 420 break; 421 } 422 } 423 return; 424 } 425 i++; 426 } 427 428 // if not found we return the whole sequence (the dead key itself plus 429 // the following char) 430 int32 deadKeyNumBytes = fChars[deadKey[1]]; 431 int32 fullNumBytes = deadKeyNumBytes + *numBytes; 432 *chars = new (std::nothrow) char[fullNumBytes + 1]; 433 if (*chars == NULL) { 434 *numBytes = 0; 435 return; 436 } 437 strncpy(*chars, &fChars[deadKey[1] + 1], deadKeyNumBytes); 438 strncpy(*chars + deadKeyNumBytes, &fChars[offset + 1], *numBytes); 439 *numBytes = fullNumBytes; 440 (*chars)[fullNumBytes] = 0; 441 } 442 443 444 status_t 445 Keymap::LoadCurrent() 446 { 447 #ifndef CONSOLED 448 key_map* keys = NULL; 449 free(fChars); 450 fChars = NULL; 451 452 _get_key_map(&keys, &fChars, &fCharsSize); 453 if (!keys) { 454 fprintf(stderr, "error while getting current keymap!\n"); 455 return B_ERROR; 456 } 457 memcpy(&fKeys, keys, sizeof(fKeys)); 458 free(keys); 459 return B_OK; 460 #else // CONSOLED 461 char path[PATH_MAX]; 462 status_t status = find_directory(B_USER_SETTINGS_DIRECTORY, -1, false, 463 path, sizeof(path)); 464 if (status != B_OK) 465 return status; 466 467 strlcat(path, "/Key_map", sizeof(path)); 468 int file = open(path, O_RDONLY); 469 if (file < 0) 470 return errno; 471 472 if (read(file, &fKeys, sizeof(fKeys)) < (ssize_t)sizeof(fKeys)) { 473 fprintf(stderr, "error reading keymap keys\n"); 474 return B_BAD_VALUE; 475 } 476 477 for (uint32 i = 0; i < sizeof(fKeys) / 4; i++) 478 ((uint32*)&fKeys)[i] = B_BENDIAN_TO_HOST_INT32(((uint32*)&fKeys)[i]); 479 480 if (read(file, &fCharsSize, sizeof(uint32)) < (ssize_t)sizeof(uint32)) { 481 fprintf(stderr, "error reading keymap size\n"); 482 return B_BAD_VALUE; 483 } 484 485 fCharsSize = B_BENDIAN_TO_HOST_INT32(fCharsSize); 486 if (fCharsSize < 0) 487 return B_BAD_VALUE; 488 489 fChars = new char[fCharsSize]; 490 491 if (read(file, fChars, fCharsSize) < 0) { 492 fprintf(stderr, "error reading keymap chars\n"); 493 return B_ERROR; 494 } 495 496 return B_OK; 497 #endif // CONSOLED 498 } 499 500