1 /* 2 * Copyright 2004-2009, Haiku, Inc. All Rights Reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Jérôme Duval 7 * Axel Dörfler, axeld@pinc-software.de. 8 */ 9 10 11 #include "Keymap.h" 12 13 #include <errno.h> 14 #include <stdlib.h> 15 #include <string.h> 16 17 #include <ByteOrder.h> 18 #include <Entry.h> 19 #include <File.h> 20 #include <FindDirectory.h> 21 #include <Path.h> 22 #include <String.h> 23 24 25 #define CHARS_TABLE_MAXSIZE 10000 26 27 28 extern status_t _restore_key_map_(); 29 30 31 // i couldn't put patterns and pattern bufs on the stack without segfaulting 32 // regexp patterns 33 const char versionPattern[] 34 = "Version[[:space:]]+=[[:space:]]+\\([[:digit:]]+\\)"; 35 const char capslockPattern[] 36 = "CapsLock[[:space:]]+=[[:space:]]+\\([[:alnum:]]+\\)"; 37 const char scrolllockPattern[] 38 = "ScrollLock[[:space:]]+=[[:space:]]+\\([[:alnum:]]+\\)"; 39 const char numlockPattern[] 40 = "NumLock[[:space:]]+=[[:space:]]+\\([[:alnum:]]+\\)"; 41 const char lshiftPattern[] = "LShift[[:space:]]+=[[:space:]]+\\([[:alnum:]]+\\)"; 42 const char rshiftPattern[] = "RShift[[:space:]]+=[[:space:]]+\\([[:alnum:]]+\\)"; 43 const char lcommandPattern[] 44 = "LCommand[[:space:]]+=[[:space:]]+\\([[:alnum:]]+\\)"; 45 const char rcommandPattern[] 46 = "RCommand[[:space:]]+=[[:space:]]+\\([[:alnum:]]+\\)"; 47 const char lcontrolPattern[] 48 = "LControl[[:space:]]+=[[:space:]]+\\([[:alnum:]]+\\)"; 49 const char rcontrolPattern[] 50 = "RControl[[:space:]]+=[[:space:]]+\\([[:alnum:]]+\\)"; 51 const char loptionPattern[] 52 = "LOption[[:space:]]+=[[:space:]]+\\([[:alnum:]]+\\)"; 53 const char roptionPattern[] 54 = "ROption[[:space:]]+=[[:space:]]+\\([[:alnum:]]+\\)"; 55 const char menuPattern[] = "Menu[[:space:]]+=[[:space:]]+\\([[:alnum:]]+\\)"; 56 const char locksettingsPattern[] 57 = "LockSettings[[:space:]]+=[[:space:]]+\\([[:alnum:]]*\\)" 58 "[[:space:]]*\\([[:alnum:]]*\\)" 59 "[[:space:]]*\\([[:alnum:]]*\\)[[:space:]]*"; 60 const char keyPattern[] = "Key[[:space:]]+\\([[:alnum:]]+\\)[[:space:]]+=" 61 "[[:space:]]+\\([[:alnum:]]+\\|'.*'\\)" 62 "[[:space:]]+\\([[:alnum:]]+\\|'.*'\\)" 63 "[[:space:]]+\\([[:alnum:]]+\\|'.*'\\)" 64 "[[:space:]]+\\([[:alnum:]]+\\|'.*'\\)" 65 "[[:space:]]+\\([[:alnum:]]+\\|'.*'\\)" 66 "[[:space:]]+\\([[:alnum:]]+\\|'.*'\\)" 67 "[[:space:]]+\\([[:alnum:]]+\\|'.*'\\)" 68 "[[:space:]]+\\([[:alnum:]]+\\|'.*'\\)" 69 "[[:space:]]+\\([[:alnum:]]+\\|'.*'\\)" 70 "[[:space:]]+"; 71 72 73 const char acutePattern[] = "Acute[[:space:]]+\\([[:alnum:]]+\\|'.*'\\)" 74 "[[:space:]]+=[[:space:]]+\\([[:alnum:]]+\\|'.*'\\)[[:space:]]+"; 75 const char gravePattern[] = "Grave[[:space:]]+\\([[:alnum:]]+\\|'.*'\\)" 76 "[[:space:]]+=[[:space:]]+\\([[:alnum:]]+\\|'.*'\\)[[:space:]]+"; 77 const char circumflexPattern[] = "Circumflex[[:space:]]+\\([[:alnum:]]" 78 "+\\|'.*'\\)[[:space:]]+=[[:space:]]+\\([[:alnum:]]+\\|'.*'\\)[[:space:]]+"; 79 const char diaeresisPattern[] = "Diaeresis[[:space:]]+\\([[:alnum:]]+\\|'.*'\\)" 80 "[[:space:]]+=[[:space:]]+\\([[:alnum:]]+\\|'.*'\\)[[:space:]]+"; 81 const char tildePattern[] = "Tilde[[:space:]]+\\([[:alnum:]]+\\|'.*'\\)" 82 "[[:space:]]+=[[:space:]]+\\([[:alnum:]]+\\|'.*'\\)[[:space:]]+"; 83 const char acutetabPattern[] = "AcuteTab[[:space:]]+=" 84 "[[:space:]]+\\([[:alnum:]-]*\\)" 85 "[[:space:]]*\\([[:alnum:]-]*\\)" 86 "[[:space:]]*\\([[:alnum:]-]*\\)" 87 "[[:space:]]*\\([[:alnum:]-]*\\)" 88 "[[:space:]]*\\([[:alnum:]-]*\\)" 89 "[[:space:]]*\\([[:alnum:]-]*\\)" 90 "[[:space:]]*\\([[:alnum:]-]*\\)" 91 "[[:space:]]*\\([[:alnum:]-]*\\)" 92 "[[:space:]]*\\([[:alnum:]-]*\\)[[:space:]]*" ; 93 const char gravetabPattern[] = "GraveTab[[:space:]]+=" 94 "[[:space:]]+\\([[:alnum:]-]*\\)" 95 "[[:space:]]*\\([[:alnum:]-]*\\)" 96 "[[:space:]]*\\([[:alnum:]-]*\\)" 97 "[[:space:]]*\\([[:alnum:]-]*\\)" 98 "[[:space:]]*\\([[:alnum:]-]*\\)" 99 "[[:space:]]*\\([[:alnum:]-]*\\)" 100 "[[:space:]]*\\([[:alnum:]-]*\\)" 101 "[[:space:]]*\\([[:alnum:]-]*\\)" 102 "[[:space:]]*\\([[:alnum:]-]*\\)[[:space:]]*" ; 103 const char circumflextabPattern[] = "CircumflexTab[[:space:]]+=" 104 "[[:space:]]+\\([[:alnum:]-]*\\)" 105 "[[:space:]]*\\([[:alnum:]-]*\\)" 106 "[[:space:]]*\\([[:alnum:]-]*\\)" 107 "[[:space:]]*\\([[:alnum:]-]*\\)" 108 "[[:space:]]*\\([[:alnum:]-]*\\)" 109 "[[:space:]]*\\([[:alnum:]-]*\\)" 110 "[[:space:]]*\\([[:alnum:]-]*\\)" 111 "[[:space:]]*\\([[:alnum:]-]*\\)" 112 "[[:space:]]*\\([[:alnum:]-]*\\)[[:space:]]*" ; 113 const char diaeresistabPattern[] = "DiaeresisTab[[:space:]]+=" 114 "[[:space:]]+\\([[:alnum:]-]*\\)" 115 "[[:space:]]*\\([[:alnum:]-]*\\)" 116 "[[:space:]]*\\([[:alnum:]-]*\\)" 117 "[[:space:]]*\\([[:alnum:]-]*\\)" 118 "[[:space:]]*\\([[:alnum:]-]*\\)" 119 "[[:space:]]*\\([[:alnum:]-]*\\)" 120 "[[:space:]]*\\([[:alnum:]-]*\\)" 121 "[[:space:]]*\\([[:alnum:]-]*\\)" 122 "[[:space:]]*\\([[:alnum:]-]*\\)[[:space:]]*" ; 123 const char tildetabPattern[] = "TildeTab[[:space:]]+=" 124 "[[:space:]]+\\([[:alnum:]-]*\\)" 125 "[[:space:]]*\\([[:alnum:]-]*\\)" 126 "[[:space:]]*\\([[:alnum:]-]*\\)" 127 "[[:space:]]*\\([[:alnum:]-]*\\)" 128 "[[:space:]]*\\([[:alnum:]-]*\\)" 129 "[[:space:]]*\\([[:alnum:]-]*\\)" 130 "[[:space:]]*\\([[:alnum:]-]*\\)" 131 "[[:space:]]*\\([[:alnum:]-]*\\)" 132 "[[:space:]]*\\([[:alnum:]-]*\\)[[:space:]]*" ; 133 134 135 // re_pattern_buffer buffers 136 struct re_pattern_buffer versionBuf; 137 struct re_pattern_buffer capslockBuf; 138 struct re_pattern_buffer scrolllockBuf; 139 struct re_pattern_buffer numlockBuf; 140 struct re_pattern_buffer lshiftBuf; 141 struct re_pattern_buffer rshiftBuf; 142 struct re_pattern_buffer lcommandBuf; 143 struct re_pattern_buffer rcommandBuf; 144 struct re_pattern_buffer lcontrolBuf; 145 struct re_pattern_buffer rcontrolBuf; 146 struct re_pattern_buffer loptionBuf; 147 struct re_pattern_buffer roptionBuf; 148 struct re_pattern_buffer menuBuf; 149 struct re_pattern_buffer locksettingsBuf; 150 struct re_pattern_buffer keyBuf; 151 struct re_pattern_buffer acuteBuf; 152 struct re_pattern_buffer graveBuf; 153 struct re_pattern_buffer circumflexBuf; 154 struct re_pattern_buffer diaeresisBuf; 155 struct re_pattern_buffer tildeBuf; 156 struct re_pattern_buffer acutetabBuf; 157 struct re_pattern_buffer gravetabBuf; 158 struct re_pattern_buffer circumflextabBuf; 159 struct re_pattern_buffer diaeresistabBuf; 160 struct re_pattern_buffer tildetabBuf; 161 162 163 void 164 dump_map(FILE* file, const char* name, int32* map) 165 { 166 fprintf(file, "\t%s:{\n", name); 167 168 for (uint32 i = 0; i < 16; i++) { 169 fprintf(file, "\t\t"); 170 for (uint32 j = 0; j < 8; j++) { 171 fprintf(file, "0x%04lx,%s", map[i * 8 + j], j < 7 ? " " : ""); 172 } 173 fprintf(file, "\n"); 174 } 175 fprintf(file, "\t},\n"); 176 } 177 178 179 void 180 dump_keys(FILE* file, const char* name, int32* keys) 181 { 182 fprintf(file, "\t%s:{\n", name); 183 184 for (uint32 i = 0; i < 4; i++) { 185 fprintf(file, "\t\t"); 186 for (uint32 j = 0; j < 8; j++) { 187 fprintf(file, "0x%04lx,%s", keys[i * 8 + j], j < 7 ? " " : ""); 188 } 189 fprintf(file, "\n"); 190 } 191 fprintf(file, "\t},\n"); 192 } 193 194 195 // #pragma mark - 196 197 198 Keymap::Keymap() 199 : 200 fChars(NULL), 201 fCharsSize(0) 202 { 203 memset(&fKeys, 0, sizeof(fKeys)); 204 } 205 206 207 Keymap::~Keymap() 208 { 209 delete[] fChars; 210 } 211 212 213 status_t 214 Keymap::LoadCurrent() 215 { 216 #if (defined(__BEOS__) || defined(__HAIKU__)) 217 key_map* keys = NULL; 218 get_key_map(&keys, &fChars); 219 if (!keys) 220 return B_ERROR; 221 222 memcpy(&fKeys, keys, sizeof(fKeys)); 223 free(keys); 224 return B_OK; 225 #else // ! __BEOS__ 226 fprintf(stderr, "Unsupported operation on this platform!\n"); 227 exit(1); 228 #endif // ! __BEOS__ 229 } 230 231 232 /*! Load a map from a file. 233 234 file format in big endian: 235 struct key_map 236 uint32 size of following charset 237 charset (offsets go into this with size of character followed by 238 character) 239 */ 240 status_t 241 Keymap::Load(const char* name) 242 { 243 FILE* file = fopen(name, "r"); 244 if (file == NULL) 245 return errno; 246 247 return Load(file); 248 } 249 250 251 status_t 252 Keymap::Load(FILE* file) 253 { 254 if (fread(&fKeys, sizeof(fKeys), 1, file) < 1) 255 return B_BAD_VALUE; 256 257 // convert from big-endian 258 for (uint32 i = 0; i < sizeof(fKeys) / 4; i++) { 259 ((uint32*)&fKeys)[i] = B_BENDIAN_TO_HOST_INT32(((uint32*)&fKeys)[i]); 260 } 261 262 if (fKeys.version != 3) 263 return KEYMAP_ERROR_UNKNOWN_VERSION; 264 265 if (fread(&fCharsSize, sizeof(uint32), 1, file) < 1) 266 return B_BAD_VALUE; 267 268 fCharsSize = B_BENDIAN_TO_HOST_INT32(fCharsSize); 269 if (fCharsSize > 16 * 1024) 270 return B_BAD_DATA; 271 272 delete[] fChars; 273 fChars = new char[fCharsSize]; 274 275 if (fread(fChars, 1, fCharsSize, file) != fCharsSize) 276 return B_BAD_VALUE; 277 278 return B_OK; 279 } 280 281 282 status_t 283 Keymap::LoadSource(const char* name) 284 { 285 FILE* file = fopen(name, "r"); 286 if (file == NULL) 287 return errno; 288 289 status_t status = LoadSource(file); 290 fclose(file); 291 292 return status; 293 } 294 295 296 status_t 297 Keymap::LoadSource(FILE* file) 298 { 299 // Setup regexp parser 300 301 reg_syntax_t syntax = RE_CHAR_CLASSES; 302 re_set_syntax(syntax); 303 304 const char* error = re_compile_pattern(versionPattern, 305 strlen(versionPattern), &versionBuf); 306 if (error) 307 fprintf(stderr, error); 308 error = re_compile_pattern(capslockPattern, strlen(capslockPattern), 309 &capslockBuf); 310 if (error) 311 fprintf(stderr, error); 312 error = re_compile_pattern(scrolllockPattern, strlen(scrolllockPattern), 313 &scrolllockBuf); 314 if (error) 315 fprintf(stderr, error); 316 error = re_compile_pattern(numlockPattern, strlen(numlockPattern), 317 &numlockBuf); 318 if (error) 319 fprintf(stderr, error); 320 error = re_compile_pattern(lshiftPattern, strlen(lshiftPattern), &lshiftBuf); 321 if (error) 322 fprintf(stderr, error); 323 error = re_compile_pattern(rshiftPattern, strlen(rshiftPattern), &rshiftBuf); 324 if (error) 325 fprintf(stderr, error); 326 error = re_compile_pattern(lcommandPattern, strlen(lcommandPattern), 327 &lcommandBuf); 328 if (error) 329 fprintf(stderr, error); 330 error = re_compile_pattern(rcommandPattern, strlen(rcommandPattern), 331 &rcommandBuf); 332 if (error) 333 fprintf(stderr, error); 334 error = re_compile_pattern(lcontrolPattern, strlen(lcontrolPattern), 335 &lcontrolBuf); 336 if (error) 337 fprintf(stderr, error); 338 error = re_compile_pattern(rcontrolPattern, strlen(rcontrolPattern), 339 &rcontrolBuf); 340 if (error) 341 fprintf(stderr, error); 342 error = re_compile_pattern(loptionPattern, strlen(loptionPattern), 343 &loptionBuf); 344 if (error) 345 fprintf(stderr, error); 346 error = re_compile_pattern(roptionPattern, strlen(roptionPattern), 347 &roptionBuf); 348 if (error) 349 fprintf(stderr, error); 350 error = re_compile_pattern(menuPattern, strlen(menuPattern), &menuBuf); 351 if (error) 352 fprintf(stderr, error); 353 error = re_compile_pattern(locksettingsPattern, strlen(locksettingsPattern), 354 &locksettingsBuf); 355 if (error) 356 fprintf(stderr, error); 357 error = re_compile_pattern(keyPattern, strlen(keyPattern), &keyBuf); 358 if (error) 359 fprintf(stderr, error); 360 error = re_compile_pattern(acutePattern, strlen(acutePattern), ´Buf); 361 if (error) 362 fprintf(stderr, error); 363 error = re_compile_pattern(gravePattern, strlen(gravePattern), &graveBuf); 364 if (error) 365 fprintf(stderr, error); 366 error = re_compile_pattern(circumflexPattern, strlen(circumflexPattern), 367 &circumflexBuf); 368 if (error) 369 fprintf(stderr, error); 370 error = re_compile_pattern(diaeresisPattern, strlen(diaeresisPattern), 371 &diaeresisBuf); 372 if (error) 373 fprintf(stderr, error); 374 error = re_compile_pattern(tildePattern, strlen(tildePattern), &tildeBuf); 375 if (error) 376 fprintf(stderr, error); 377 error = re_compile_pattern(acutetabPattern, strlen(acutetabPattern), 378 ´tabBuf); 379 if (error) 380 fprintf(stderr, error); 381 error = re_compile_pattern(gravetabPattern, strlen(gravetabPattern), 382 &gravetabBuf); 383 if (error) 384 fprintf(stderr, error); 385 error = re_compile_pattern(circumflextabPattern, 386 strlen(circumflextabPattern), &circumflextabBuf); 387 if (error) 388 fprintf(stderr, error); 389 error = re_compile_pattern(diaeresistabPattern, strlen(diaeresistabPattern), 390 &diaeresistabBuf); 391 if (error) 392 fprintf(stderr, error); 393 error = re_compile_pattern(tildetabPattern, strlen(tildetabPattern), 394 &tildetabBuf); 395 if (error) 396 fprintf(stderr, error); 397 398 // Read file 399 400 delete[] fChars; 401 fChars = new char[CHARS_TABLE_MAXSIZE]; 402 fCharsSize = CHARS_TABLE_MAXSIZE; 403 int offset = 0; 404 int acuteOffset = 0; 405 int graveOffset = 0; 406 int circumflexOffset = 0; 407 int diaeresisOffset = 0; 408 int tildeOffset = 0; 409 410 int32* maps[] = { 411 fKeys.normal_map, 412 fKeys.shift_map, 413 fKeys.control_map, 414 fKeys.option_map, 415 fKeys.option_shift_map, 416 fKeys.caps_map, 417 fKeys.caps_shift_map, 418 fKeys.option_caps_map, 419 fKeys.option_caps_shift_map 420 }; 421 422 char buffer[1024]; 423 424 while (fgets(buffer, sizeof(buffer) - 1, file) != NULL) { 425 if (buffer[0] == '#' || buffer[0] == '\n') 426 continue; 427 428 size_t length = strlen(buffer); 429 430 struct re_registers regs; 431 if (re_search(&versionBuf, buffer, length, 0, length, ®s) >= 0) { 432 sscanf(buffer + regs.start[1], "%ld", &fKeys.version); 433 } else if (re_search(&capslockBuf, buffer, length, 0, length, ®s) 434 >= 0) { 435 sscanf(buffer + regs.start[1], "0x%lx", &fKeys.caps_key); 436 } else if (re_search(&scrolllockBuf, buffer, length, 0, length, ®s) 437 >= 0) { 438 sscanf(buffer + regs.start[1], "0x%lx", &fKeys.scroll_key); 439 } else if (re_search(&numlockBuf, buffer, length, 0, length, ®s) 440 >= 0) { 441 sscanf(buffer + regs.start[1], "0x%lx", &fKeys.num_key); 442 } else if (re_search(&lshiftBuf, buffer, length, 0, length, ®s) 443 >= 0) { 444 sscanf(buffer + regs.start[1], "0x%lx", &fKeys.left_shift_key); 445 } else if (re_search(&rshiftBuf, buffer, length, 0, length, ®s) 446 >= 0) { 447 sscanf(buffer + regs.start[1], "0x%lx", &fKeys.right_shift_key); 448 } else if (re_search(&lcommandBuf, buffer, length, 0, length, ®s) 449 >= 0) { 450 sscanf(buffer + regs.start[1], "0x%lx", &fKeys.left_command_key); 451 } else if (re_search(&rcommandBuf, buffer, length, 0, length, ®s) 452 >= 0) { 453 sscanf(buffer + regs.start[1], "0x%lx", &fKeys.right_command_key); 454 } else if (re_search(&lcontrolBuf, buffer, length, 0, length, ®s) 455 >= 0) { 456 sscanf(buffer + regs.start[1], "0x%lx", &fKeys.left_control_key); 457 } else if (re_search(&rcontrolBuf, buffer, length, 0, length, ®s) 458 >= 0) { 459 sscanf(buffer + regs.start[1], "0x%lx", &fKeys.right_control_key); 460 } else if (re_search(&loptionBuf, buffer, length, 0, length, ®s) 461 >= 0) { 462 sscanf(buffer + regs.start[1], "0x%lx", &fKeys.left_option_key); 463 } else if (re_search(&roptionBuf, buffer, length, 0, length, ®s) 464 >= 0) { 465 sscanf(buffer + regs.start[1], "0x%lx", &fKeys.right_option_key); 466 } else if (re_search(&menuBuf, buffer, length, 0, length, ®s) >= 0) { 467 sscanf(buffer + regs.start[1], "0x%lx", &fKeys.menu_key); 468 } else if (re_search(&locksettingsBuf, buffer, length, 0, length, ®s) 469 >= 0) { 470 fKeys.lock_settings = 0; 471 for (int32 i = 1; i <= 3; i++) { 472 const char* start = buffer + regs.start[i]; 473 length = regs.end[i] - regs.start[i]; 474 if (length == 0) 475 break; 476 477 if (!strncmp(start, "CapsLock", length)) 478 fKeys.lock_settings |= B_CAPS_LOCK; 479 else if (!strncmp(start, "NumLock", length)) 480 fKeys.lock_settings |= B_NUM_LOCK; 481 else if (!strncmp(start, "ScrollLock", length)) 482 fKeys.lock_settings |= B_SCROLL_LOCK; 483 } 484 } else if (re_search(&keyBuf, buffer, length, 0, length, ®s) >= 0) { 485 uint32 keyCode; 486 if (sscanf(buffer + regs.start[1], "0x%lx", &keyCode) > 0) { 487 for (int i = 2; i <= 10; i++) { 488 maps[i - 2][keyCode] = offset; 489 _ComputeChars(buffer, regs, i, offset); 490 } 491 } 492 } else if (re_search(´Buf, buffer, length, 0, length, ®s) >= 0) { 493 for (int i = 1; i <= 2; i++) { 494 fKeys.acute_dead_key[acuteOffset++] = offset; 495 _ComputeChars(buffer, regs, i, offset); 496 } 497 } else if (re_search(&graveBuf, buffer, length, 0, length, ®s) >= 0) { 498 for (int i = 1; i <= 2; i++) { 499 fKeys.grave_dead_key[graveOffset++] = offset; 500 _ComputeChars(buffer, regs, i, offset); 501 } 502 } else if (re_search(&circumflexBuf, buffer, length, 0, length, ®s) 503 >= 0) { 504 for (int i = 1; i <= 2; i++) { 505 fKeys.circumflex_dead_key[circumflexOffset++] = offset; 506 _ComputeChars(buffer, regs, i, offset); 507 } 508 } else if (re_search(&diaeresisBuf, buffer, length, 0, length, ®s) 509 >= 0) { 510 for (int i = 1; i <= 2; i++) { 511 fKeys.dieresis_dead_key[diaeresisOffset++] = offset; 512 _ComputeChars(buffer, regs, i, offset); 513 } 514 } else if (re_search(&tildeBuf, buffer, length, 0, length, ®s) >= 0) { 515 for (int i = 1; i <= 2; i++) { 516 fKeys.tilde_dead_key[tildeOffset++] = offset; 517 _ComputeChars(buffer, regs, i, offset); 518 } 519 } else if (re_search(´tabBuf, buffer, length, 0, length, ®s) 520 >= 0) { 521 _ComputeTables(buffer, regs, fKeys.acute_tables); 522 } else if (re_search(&gravetabBuf, buffer, length, 0, length, ®s) 523 >= 0) { 524 _ComputeTables(buffer, regs, fKeys.grave_tables); 525 } else if (re_search(&circumflextabBuf, buffer, length, 0, length, ®s) 526 >= 0) { 527 _ComputeTables(buffer, regs, fKeys.circumflex_tables); 528 } else if (re_search(&diaeresistabBuf, buffer, length, 0, length, ®s) 529 >= 0) { 530 _ComputeTables(buffer, regs, fKeys.dieresis_tables); 531 } else if (re_search(&tildetabBuf, buffer, length, 0, length, ®s) 532 >= 0) { 533 _ComputeTables(buffer, regs, fKeys.tilde_tables); 534 } 535 } 536 537 fCharsSize = offset; 538 539 if (fKeys.version != 3) 540 return KEYMAP_ERROR_UNKNOWN_VERSION; 541 542 return B_OK; 543 } 544 545 546 status_t 547 Keymap::SaveAsCurrent() 548 { 549 #if (defined(__BEOS__) || defined(__HAIKU__)) 550 BPath path; 551 status_t status = find_directory(B_USER_SETTINGS_DIRECTORY, &path, true); 552 if (status != B_OK) 553 return status; 554 555 path.Append("Key_map"); 556 557 status = Save(path.Path()); 558 if (status != B_OK) 559 return status; 560 561 Use(); 562 return B_OK; 563 #else // ! __BEOS__ 564 fprintf(stderr, "Unsupported operation on this platform!\n"); 565 exit(1); 566 #endif // ! __BEOS__ 567 } 568 569 570 //! Save a binary keymap to a file. 571 status_t 572 Keymap::Save(const char* name) 573 { 574 BFile file; 575 status_t status = file.SetTo(name, 576 B_WRITE_ONLY | B_CREATE_FILE | B_ERASE_FILE); 577 if (status != B_OK) 578 return status; 579 580 // convert to big endian 581 for (uint32 i = 0; i < sizeof(fKeys) / sizeof(uint32); i++) { 582 ((uint32*)&fKeys)[i] = B_HOST_TO_BENDIAN_INT32(((uint32*)&fKeys)[i]); 583 } 584 585 ssize_t bytesWritten = file.Write(&fKeys, sizeof(fKeys)); 586 587 // convert endian back 588 for (uint32 i = 0; i < sizeof(fKeys) / sizeof(uint32); i++) { 589 ((uint32*)&fKeys)[i] = B_BENDIAN_TO_HOST_INT32(((uint32*)&fKeys)[i]); 590 } 591 592 if (bytesWritten < (ssize_t)sizeof(fKeys)) 593 return B_ERROR; 594 if (bytesWritten < B_OK) 595 return bytesWritten; 596 597 uint32 charSize = B_HOST_TO_BENDIAN_INT32(fCharsSize); 598 599 bytesWritten = file.Write(&charSize, sizeof(uint32)); 600 if (bytesWritten < (ssize_t)sizeof(uint32)) 601 return B_ERROR; 602 if (bytesWritten < B_OK) 603 return bytesWritten; 604 605 bytesWritten = file.Write(fChars, fCharsSize); 606 if (bytesWritten < (ssize_t)fCharsSize) 607 return B_ERROR; 608 if (bytesWritten < B_OK) 609 return bytesWritten; 610 611 return B_OK; 612 } 613 614 615 status_t 616 Keymap::SaveAsSource(const char* name) 617 { 618 FILE* file = fopen(name, "w"); 619 if (file == NULL) 620 return errno; 621 622 #if (defined(__BEOS__) || defined(__HAIKU__)) 623 text_run_array* textRuns; 624 _SaveSourceText(file, &textRuns); 625 626 if (textRuns != NULL) { 627 ssize_t dataSize; 628 void* data = BTextView::FlattenRunArray(textRuns, &dataSize); 629 if (data != NULL) { 630 BNode node(name); 631 node.WriteAttr("styles", B_RAW_TYPE, 0, data, dataSize); 632 633 free(data); 634 } 635 636 BTextView::FreeRunArray(textRuns); 637 } 638 #else 639 _SaveSourceText(file); 640 #endif 641 642 return B_OK; 643 } 644 645 646 status_t 647 Keymap::SaveAsSource(FILE* file) 648 { 649 _SaveSourceText(file); 650 return B_OK; 651 } 652 653 654 /*! Save a keymap as C source file - this is used to get the default keymap 655 into the input_server, for example. 656 \a mapName is usually the path of the input keymap, and is used as the 657 name of the keymap (the path will be removed, as well as its suffix). 658 */ 659 status_t 660 Keymap::SaveAsCppHeader(const char* fileName, const char* mapName) 661 { 662 BString name = mapName; 663 664 // cut off path 665 int32 index = name.FindLast('/'); 666 if (index > 0) 667 name.Remove(0, index + 1); 668 669 // prune ".keymap" 670 index = name.FindLast('.'); 671 if (index > 0) 672 name.Truncate(index); 673 674 FILE* file = fopen(fileName, "w"); 675 if (file == NULL) 676 return errno; 677 678 fprintf(file, "/*\n" 679 " * Haiku Keymap\n" 680 " * This file is generated automatically. Don't edit!\n" 681 " */\n\n"); 682 fprintf(file, "#include <InterfaceDefs.h>\n\n"); 683 fprintf(file, "const char *kSystemKeymapName = \"%s\";\n\n", name.String()); 684 fprintf(file, "const key_map kSystemKeymap = {\n"); 685 fprintf(file, "\tversion:%ld,\n", fKeys.version); 686 fprintf(file, "\tcaps_key:0x%lx,\n", fKeys.caps_key); 687 fprintf(file, "\tscroll_key:0x%lx,\n", fKeys.scroll_key); 688 fprintf(file, "\tnum_key:0x%lx,\n", fKeys.num_key); 689 fprintf(file, "\tleft_shift_key:0x%lx,\n", fKeys.left_shift_key); 690 fprintf(file, "\tright_shift_key:0x%lx,\n", fKeys.right_shift_key); 691 fprintf(file, "\tleft_command_key:0x%lx,\n", fKeys.left_command_key); 692 fprintf(file, "\tright_command_key:0x%lx,\n", fKeys.right_command_key); 693 fprintf(file, "\tleft_control_key:0x%lx,\n", fKeys.left_control_key); 694 fprintf(file, "\tright_control_key:0x%lx,\n", fKeys.right_control_key); 695 fprintf(file, "\tleft_option_key:0x%lx,\n", fKeys.left_option_key); 696 fprintf(file, "\tright_option_key:0x%lx,\n", fKeys.right_option_key); 697 fprintf(file, "\tmenu_key:0x%lx,\n", fKeys.menu_key); 698 fprintf(file, "\tlock_settings:0x%lx,\n", fKeys.lock_settings); 699 700 dump_map(file, "control_map", fKeys.control_map); 701 dump_map(file, "option_caps_shift_map", fKeys.option_caps_shift_map); 702 dump_map(file, "option_caps_map", fKeys.option_caps_map); 703 dump_map(file, "option_shift_map", fKeys.option_shift_map); 704 dump_map(file, "option_map", fKeys.option_map); 705 dump_map(file, "caps_shift_map", fKeys.caps_shift_map); 706 dump_map(file, "caps_map", fKeys.caps_map); 707 dump_map(file, "shift_map", fKeys.shift_map); 708 dump_map(file, "normal_map", fKeys.normal_map); 709 710 dump_keys(file, "acute_dead_key", fKeys.acute_dead_key); 711 dump_keys(file, "grave_dead_key", fKeys.grave_dead_key); 712 713 dump_keys(file, "circumflex_dead_key", fKeys.circumflex_dead_key); 714 dump_keys(file, "dieresis_dead_key", fKeys.dieresis_dead_key); 715 dump_keys(file, "tilde_dead_key", fKeys.tilde_dead_key); 716 717 fprintf(file, "\tacute_tables:0x%lx,\n", fKeys.acute_tables); 718 fprintf(file, "\tgrave_tables:0x%lx,\n", fKeys.grave_tables); 719 fprintf(file, "\tcircumflex_tables:0x%lx,\n", fKeys.circumflex_tables); 720 fprintf(file, "\tdieresis_tables:0x%lx,\n", fKeys.dieresis_tables); 721 fprintf(file, "\ttilde_tables:0x%lx,\n", fKeys.tilde_tables); 722 723 fprintf(file, "};\n\n"); 724 725 fprintf(file, "const char kSystemKeyChars[] = {\n"); 726 for (uint32 i = 0; i < fCharsSize; i++) { 727 if (i % 10 == 0) { 728 if (i > 0) 729 fprintf(file, "\n"); 730 fprintf(file, "\t"); 731 } else 732 fprintf(file, " "); 733 734 fprintf(file, "0x%02x,", (uint8)fChars[i]); 735 } 736 fprintf(file, "\n};\n\n"); 737 738 fprintf(file, "const uint32 kSystemKeyCharsSize = %ld;\n", fCharsSize); 739 fclose(file); 740 741 return B_OK; 742 } 743 744 745 //! We make our input server use the map in /boot/home/config/settings/Keymap 746 status_t 747 Keymap::Use() 748 { 749 #if (defined(__BEOS__) || defined(__HAIKU__)) 750 return _restore_key_map_(); 751 752 #else // ! __BEOS__ 753 fprintf(stderr, "Unsupported operation on this platform!\n"); 754 exit(1); 755 #endif // ! __BEOS__ 756 } 757 758 759 /*! We need to know if a key is a modifier key to choose 760 a valid key when several are pressed together 761 */ 762 bool 763 Keymap::IsModifierKey(uint32 keyCode) 764 { 765 return keyCode == fKeys.caps_key 766 || keyCode == fKeys.num_key 767 || keyCode == fKeys.left_shift_key 768 || keyCode == fKeys.right_shift_key 769 || keyCode == fKeys.left_command_key 770 || keyCode == fKeys.right_command_key 771 || keyCode == fKeys.left_control_key 772 || keyCode == fKeys.right_control_key 773 || keyCode == fKeys.left_option_key 774 || keyCode == fKeys.right_option_key 775 || keyCode == fKeys.menu_key; 776 } 777 778 779 //! Tell if a key is a dead key, needed for draw a dead key 780 uint8 781 Keymap::IsDeadKey(uint32 keyCode, uint32 modifiers) 782 { 783 int32 offset; 784 uint32 tableMask = 0; 785 786 switch (modifiers & 0xcf) { 787 case B_SHIFT_KEY: 788 offset = fKeys.shift_map[keyCode]; 789 tableMask = B_SHIFT_TABLE; 790 break; 791 case B_CAPS_LOCK: 792 offset = fKeys.caps_map[keyCode]; 793 tableMask = B_CAPS_TABLE; 794 break; 795 case B_CAPS_LOCK | B_SHIFT_KEY: 796 offset = fKeys.caps_shift_map[keyCode]; 797 tableMask = B_CAPS_SHIFT_TABLE; 798 break; 799 case B_OPTION_KEY: 800 offset = fKeys.option_map[keyCode]; 801 tableMask = B_OPTION_TABLE; 802 break; 803 case B_OPTION_KEY | B_SHIFT_KEY: 804 offset = fKeys.option_shift_map[keyCode]; 805 tableMask = B_OPTION_SHIFT_TABLE; 806 break; 807 case B_OPTION_KEY | B_CAPS_LOCK: 808 offset = fKeys.option_caps_map[keyCode]; 809 tableMask = B_OPTION_CAPS_TABLE; 810 break; 811 case B_OPTION_KEY | B_SHIFT_KEY | B_CAPS_LOCK: 812 offset = fKeys.option_caps_shift_map[keyCode]; 813 tableMask = B_OPTION_CAPS_SHIFT_TABLE; 814 break; 815 case B_CONTROL_KEY: 816 offset = fKeys.control_map[keyCode]; 817 tableMask = B_CONTROL_TABLE; 818 break; 819 820 default: 821 offset = fKeys.normal_map[keyCode]; 822 tableMask = B_NORMAL_TABLE; 823 break; 824 } 825 826 if (offset <= 0) 827 return 0; 828 uint32 numBytes = fChars[offset]; 829 830 if (!numBytes) 831 return 0; 832 833 char chars[4]; 834 strncpy(chars, &(fChars[offset+1]), numBytes); 835 chars[numBytes] = 0; 836 837 int32 deadOffsets[] = { 838 fKeys.acute_dead_key[1], 839 fKeys.grave_dead_key[1], 840 fKeys.circumflex_dead_key[1], 841 fKeys.dieresis_dead_key[1], 842 fKeys.tilde_dead_key[1] 843 }; 844 845 uint32 deadTables[] = { 846 fKeys.acute_tables, 847 fKeys.grave_tables, 848 fKeys.circumflex_tables, 849 fKeys.dieresis_tables, 850 fKeys.tilde_tables 851 }; 852 853 for (int32 i = 0; i < 5; i++) { 854 if ((deadTables[i] & tableMask) == 0) 855 continue; 856 857 if (offset == deadOffsets[i]) 858 return i+1; 859 860 uint32 deadNumBytes = fChars[deadOffsets[i]]; 861 862 if (!deadNumBytes) 863 continue; 864 865 if (strncmp(chars, &fChars[deadOffsets[i] + 1], deadNumBytes) == 0) 866 return i + 1; 867 } 868 return 0; 869 } 870 871 872 //! Tell if a key is a dead second key, needed for draw a dead second key 873 bool 874 Keymap::IsDeadSecondKey(uint32 keyCode, uint32 modifiers, uint8 activeDeadKey) 875 { 876 if (!activeDeadKey) 877 return false; 878 879 int32 offset; 880 881 switch (modifiers & 0xcf) { 882 case B_SHIFT_KEY: 883 offset = fKeys.shift_map[keyCode]; 884 break; 885 case B_CAPS_LOCK: 886 offset = fKeys.caps_map[keyCode]; 887 break; 888 case B_CAPS_LOCK | B_SHIFT_KEY: 889 offset = fKeys.caps_shift_map[keyCode]; 890 break; 891 case B_OPTION_KEY: 892 offset = fKeys.option_map[keyCode]; 893 break; 894 case B_OPTION_KEY | B_SHIFT_KEY: 895 offset = fKeys.option_shift_map[keyCode]; 896 break; 897 case B_OPTION_KEY | B_CAPS_LOCK: 898 offset = fKeys.option_caps_map[keyCode]; 899 break; 900 case B_OPTION_KEY | B_SHIFT_KEY|B_CAPS_LOCK: 901 offset = fKeys.option_caps_shift_map[keyCode]; 902 break; 903 case B_CONTROL_KEY: 904 offset = fKeys.control_map[keyCode]; 905 break; 906 907 default: 908 offset = fKeys.normal_map[keyCode]; 909 break; 910 } 911 912 uint32 numBytes = fChars[offset]; 913 914 if (!numBytes) 915 return false; 916 917 int32* deadOffsets[] = { 918 fKeys.acute_dead_key, 919 fKeys.grave_dead_key, 920 fKeys.circumflex_dead_key, 921 fKeys.dieresis_dead_key, 922 fKeys.tilde_dead_key 923 }; 924 925 int32 *deadOffset = deadOffsets[activeDeadKey - 1]; 926 927 for (int32 i = 0; i < 32; i++) { 928 if (offset == deadOffset[i]) 929 return true; 930 931 uint32 deadNumBytes = fChars[deadOffset[i]]; 932 933 if (!deadNumBytes) 934 continue; 935 936 if (strncmp(&fChars[offset + 1], &fChars[deadOffset[i] + 1], 937 deadNumBytes) == 0) 938 return true; 939 940 i++; 941 } 942 return false; 943 } 944 945 946 //! Get the char for a key given modifiers and active dead key 947 void 948 Keymap::GetChars(uint32 keyCode, uint32 modifiers, uint8 activeDeadKey, 949 char** chars, int32* numBytes) 950 { 951 int32 offset; 952 953 *numBytes = 0; 954 *chars = NULL; 955 956 // here we take NUMLOCK into account 957 if (modifiers & B_NUM_LOCK) { 958 switch (keyCode) { 959 case 0x37: 960 case 0x38: 961 case 0x39: 962 case 0x48: 963 case 0x49: 964 case 0x4a: 965 case 0x58: 966 case 0x59: 967 case 0x5a: 968 case 0x64: 969 case 0x65: 970 modifiers ^= B_SHIFT_KEY; 971 } 972 } 973 974 // here we choose the right map given the modifiers 975 switch (modifiers & 0xcf) { 976 case B_SHIFT_KEY: 977 offset = fKeys.shift_map[keyCode]; 978 break; 979 case B_CAPS_LOCK: 980 offset = fKeys.caps_map[keyCode]; 981 break; 982 case B_CAPS_LOCK | B_SHIFT_KEY: 983 offset = fKeys.caps_shift_map[keyCode]; 984 break; 985 case B_OPTION_KEY: 986 offset = fKeys.option_map[keyCode]; 987 break; 988 case B_OPTION_KEY | B_SHIFT_KEY: 989 offset = fKeys.option_shift_map[keyCode]; 990 break; 991 case B_OPTION_KEY | B_CAPS_LOCK: 992 offset = fKeys.option_caps_map[keyCode]; 993 break; 994 case B_OPTION_KEY | B_SHIFT_KEY | B_CAPS_LOCK: 995 offset = fKeys.option_caps_shift_map[keyCode]; 996 break; 997 case B_CONTROL_KEY: 998 offset = fKeys.control_map[keyCode]; 999 break; 1000 1001 default: 1002 offset = fKeys.normal_map[keyCode]; 1003 break; 1004 } 1005 1006 // here we get the char size 1007 *numBytes = fChars[offset]; 1008 1009 if (!*numBytes) 1010 return; 1011 1012 // here we take an potential active dead key 1013 int32* deadKey; 1014 switch (activeDeadKey) { 1015 case 1: 1016 deadKey = fKeys.acute_dead_key; 1017 break; 1018 case 2: 1019 deadKey = fKeys.grave_dead_key; 1020 break; 1021 case 3: 1022 deadKey = fKeys.circumflex_dead_key; 1023 break; 1024 case 4: 1025 deadKey = fKeys.dieresis_dead_key; 1026 break; 1027 case 5: 1028 deadKey = fKeys.tilde_dead_key; 1029 break; 1030 1031 default: 1032 // if not dead, we copy and return the char 1033 char *str = *chars = new char[*numBytes + 1]; 1034 strncpy(str, &fChars[offset + 1], *numBytes); 1035 str[*numBytes] = 0; 1036 return; 1037 } 1038 1039 // If dead key, we search for our current offset char in the dead key offset 1040 // table string comparison is needed 1041 for (int32 i = 0; i < 32; i++) { 1042 if (!strncmp(&fChars[offset + 1], &fChars[deadKey[i] + 1], *numBytes)) { 1043 *numBytes = fChars[deadKey[i + 1]]; 1044 1045 switch (*numBytes) { 1046 case 0: 1047 // Not mapped 1048 *chars = NULL; 1049 break; 1050 1051 default: 1052 // 1-, 2-, 3-, or 4-byte UTF-8 character 1053 char* str = *chars = new char[*numBytes + 1]; 1054 strncpy(str, &fChars[deadKey[i + 1] + 1], *numBytes); 1055 str[*numBytes] = 0; 1056 break; 1057 } 1058 return; 1059 } 1060 i++; 1061 } 1062 1063 // if not found we return the current char mapped 1064 *chars = new char[*numBytes + 1]; 1065 strncpy(*chars, &(fChars[offset+1]), *numBytes); 1066 (*chars)[*numBytes] = 0; 1067 } 1068 1069 1070 void 1071 Keymap::RestoreSystemDefault() 1072 { 1073 #if (defined(__BEOS__) || defined(__HAIKU__)) 1074 // work-around to get rid of this stupid find_directory_r() on Zeta 1075 # ifdef find_directory 1076 # undef find_directory 1077 # endif 1078 BPath path; 1079 if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) != B_OK) 1080 return; 1081 1082 path.Append("Key_map"); 1083 1084 BEntry entry(path.Path()); 1085 entry.Remove(); 1086 1087 _restore_key_map_(); 1088 #else // ! __BEOS__ 1089 fprintf(stderr, "Unsupported operation on this platform!\n"); 1090 exit(1); 1091 #endif // ! __BEOS__ 1092 } 1093 1094 1095 /*static*/ bool 1096 Keymap::GetKey(const char* chars, int32 offset, char* buffer, size_t bufferSize) 1097 { 1098 uint8 size = (uint8)chars[offset++]; 1099 char string[1024]; 1100 1101 switch (size) { 1102 case 0: 1103 // Not mapped 1104 strlcpy(buffer, "''", bufferSize); 1105 return false; 1106 1107 case 1: 1108 // 1-byte UTF-8/ASCII character 1109 if ((uint8)chars[offset] < 0x20 || (uint8)chars[offset] > 0x7e) 1110 sprintf(string, "0x%02x", (uint8)chars[offset]); 1111 else { 1112 sprintf(string, "'%s%c'", 1113 (chars[offset] == '\\' || chars[offset] == '\'') ? "\\" : "", 1114 chars[offset]); 1115 } 1116 break; 1117 1118 default: 1119 // multi-byte UTF-8 character 1120 sprintf(string, "0x"); 1121 for (int i = 0; i < size; i++) { 1122 sprintf(string + 2 * (i + 1), "%02x", (uint8)chars[offset + i]); 1123 } 1124 break; 1125 } 1126 1127 strlcpy(buffer, string, bufferSize); 1128 return true; 1129 } 1130 1131 1132 #if (defined(__BEOS__) || defined(__HAIKU__)) 1133 void 1134 Keymap::_SaveSourceText(FILE* file, text_run_array** _textRuns) 1135 { 1136 text_run_array* runs = NULL; 1137 if (_textRuns != NULL) { 1138 runs = BTextView::AllocRunArray(8); 1139 *_textRuns = runs; 1140 } 1141 #else 1142 void 1143 Keymap::_SaveSourceText(FILE* file) 1144 { 1145 #endif 1146 1147 static const rgb_color kCommentColor = (rgb_color){200, 92, 92, 255}; 1148 static const rgb_color kTextColor = (rgb_color){0, 0, 0, 255}; 1149 1150 #if (defined(__BEOS__) || defined(__HAIKU__)) 1151 BFont font = *be_fixed_font; 1152 1153 if (runs != NULL) { 1154 runs->runs[0].offset = 0; 1155 runs->runs[0].font = font; 1156 runs->runs[0].color = kCommentColor; 1157 } 1158 #endif 1159 1160 int bytes = fprintf(file, "#!/bin/keymap -l\n" 1161 "#\n" 1162 "#\tRaw key numbering for 101 keyboard...\n"); 1163 1164 #if (defined(__BEOS__) || defined(__HAIKU__)) 1165 if (runs != NULL) { 1166 runs->runs[1].offset = bytes; 1167 runs->runs[1].font = font; 1168 runs->runs[1].font.SetSize(9); 1169 runs->runs[1].color = kCommentColor; 1170 } 1171 #endif 1172 1173 bytes += fprintf(file, "# [sys] [brk]\n" 1174 "# 0x7e 0x7f\n" 1175 "# [esc] [ f1] [ f2] [ f3] [ f4] [ f5] [ f6] [ f7] [ f8] [ f9] [f10] [f11] [f12] [prn] [scr] [pau]\n" 1176 "# 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0a 0x0b 0x0c 0x0d 0x0e 0x0f 0x10 K E Y P A D K E Y S\n" 1177 "#\n" 1178 "# [ ` ] [ 1 ] [ 2 ] [ 3 ] [ 4 ] [ 5 ] [ 6 ] [ 7 ] [ 8 ] [ 9 ] [ 0 ] [ - ] [ = ] [bck] [ins] [hme] [pup] [num] [ / ] [ * ] [ - ]\n" 1179 "# 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1a 0x1b 0x1c 0x1d 0x1e 0x1f 0x20 0x21 0x22 0x23 0x24 0x25\n" 1180 "#\n" 1181 "# [tab] [ q ] [ w ] [ e ] [ r ] [ t ] [ y ] [ u ] [ i ] [ o ] [ p ] [ [ ] [ ] ] [ \\ ] [del] [end] [pdn] [ 7 ] [ 8 ] [ 9 ] [ + ]\n" 1182 "# 0x26 0x27 0x28 0x29 0x2a 0x2b 0x2c 0x2d 0x2e 0x2f 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3a\n" 1183 "#\n" 1184 "# [cap] [ a ] [ s ] [ d ] [ f ] [ g ] [ h ] [ j ] [ k ] [ l ] [ ; ] [ ' ] [ enter ] [ 4 ] [ 5 ] [ 6 ]\n" 1185 "# 0x3b 0x3c 0x3d 0x3e 0x3f 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4a\n" 1186 "#\n" 1187 "# [shift] [ z ] [ x ] [ c ] [ v ] [ b ] [ n ] [ m ] [ , ] [ . ] [ / ] [shift] [ up] [ 1 ] [ 2 ] [ 3 ] [ent]\n" 1188 "# 0x4b 0x4c 0x4d 0x4e 0x4f 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5a 0x5b\n" 1189 "#\n" 1190 "# [ctr] [cmd] [ space ] [cmd] [ctr] [lft] [dwn] [rgt] [ 0 ] [ . ]\n" 1191 "# 0x5c 0x5d 0x5e 0x5f 0x60 0x61 0x62 0x63 0x64 0x65\n"); 1192 1193 #if (defined(__BEOS__) || defined(__HAIKU__)) 1194 if (runs != NULL) { 1195 runs->runs[2].offset = bytes; 1196 runs->runs[2].font = font; 1197 runs->runs[2].color = kCommentColor; 1198 } 1199 #endif 1200 1201 bytes += fprintf(file, "#\n" 1202 "#\tNOTE: On a Microsoft Natural Keyboard:\n" 1203 "#\t\t\tleft option = 0x66\n" 1204 "#\t\t\tright option = 0x67\n" 1205 "#\t\t\tmenu key = 0x68\n" 1206 "#\tNOTE: On an Apple Extended Keyboard:\n" 1207 "#\t\t\tleft option = 0x66\n" 1208 "#\t\t\tright option = 0x67\n" 1209 "#\t\t\tkeypad '=' = 0x6a\n" 1210 "#\t\t\tpower key = 0x6b\n"); 1211 1212 #if (defined(__BEOS__) || defined(__HAIKU__)) 1213 if (runs != NULL) { 1214 runs->runs[3].offset = bytes; 1215 runs->runs[3].font = *be_fixed_font; 1216 runs->runs[3].color = kTextColor; 1217 } 1218 #endif 1219 1220 bytes += fprintf(file, "Version = %ld\n" 1221 "CapsLock = 0x%02lx\n" 1222 "ScrollLock = 0x%02lx\n" 1223 "NumLock = 0x%02lx\n" 1224 "LShift = 0x%02lx\n" 1225 "RShift = 0x%02lx\n" 1226 "LCommand = 0x%02lx\n" 1227 "RCommand = 0x%02lx\n" 1228 "LControl = 0x%02lx\n" 1229 "RControl = 0x%02lx\n" 1230 "LOption = 0x%02lx\n" 1231 "ROption = 0x%02lx\n" 1232 "Menu = 0x%02lx\n", 1233 fKeys.version, fKeys.caps_key, fKeys.scroll_key, fKeys.num_key, 1234 fKeys.left_shift_key, fKeys.right_shift_key, fKeys.left_command_key, 1235 fKeys.right_command_key, fKeys.left_control_key, fKeys.right_control_key, 1236 fKeys.left_option_key, fKeys.right_option_key, fKeys.menu_key); 1237 1238 #if (defined(__BEOS__) || defined(__HAIKU__)) 1239 if (runs != NULL) { 1240 runs->runs[4].offset = bytes; 1241 runs->runs[4].font = *be_fixed_font; 1242 runs->runs[4].color = kCommentColor; 1243 } 1244 #endif 1245 1246 bytes += fprintf(file, "#\n" 1247 "# Lock settings\n" 1248 "# To set NumLock, do the following:\n" 1249 "# LockSettings = NumLock\n" 1250 "#\n" 1251 "# To set everything, do the following:\n" 1252 "# LockSettings = CapsLock NumLock ScrollLock\n" 1253 "#\n"); 1254 1255 #if (defined(__BEOS__) || defined(__HAIKU__)) 1256 if (runs != NULL) { 1257 runs->runs[5].offset = bytes; 1258 runs->runs[5].font = *be_fixed_font; 1259 runs->runs[5].color = kTextColor; 1260 } 1261 #endif 1262 1263 bytes += fprintf(file, "LockSettings = "); 1264 if ((fKeys.lock_settings & B_CAPS_LOCK) != 0) 1265 bytes += fprintf(file, "CapsLock "); 1266 if ((fKeys.lock_settings & B_NUM_LOCK) != 0) 1267 bytes += fprintf(file, "NumLock "); 1268 if ((fKeys.lock_settings & B_SCROLL_LOCK) != 0) 1269 bytes += fprintf(file, "ScrollLock "); 1270 bytes += fprintf(file, "\n"); 1271 1272 #if (defined(__BEOS__) || defined(__HAIKU__)) 1273 if (runs != NULL) { 1274 runs->runs[6].offset = bytes; 1275 runs->runs[6].font = *be_fixed_font; 1276 runs->runs[6].color = kCommentColor; 1277 } 1278 #endif 1279 1280 bytes += fprintf(file, "# Legend:\n" 1281 "# n = Normal\n" 1282 "# s = Shift\n" 1283 "# c = Control\n" 1284 "# C = CapsLock\n" 1285 "# o = Option\n" 1286 "# Key n s c o os C Cs Co Cos \n"); 1287 1288 #if (defined(__BEOS__) || defined(__HAIKU__)) 1289 if (runs != NULL) { 1290 runs->runs[7].offset = bytes; 1291 runs->runs[7].font = *be_fixed_font; 1292 runs->runs[7].color = kTextColor; 1293 } 1294 #endif 1295 1296 for (int i = 0; i < 128; i++) { 1297 char normalKey[32]; 1298 char shiftKey[32]; 1299 char controlKey[32]; 1300 char optionKey[32]; 1301 char optionShiftKey[32]; 1302 char capsKey[32]; 1303 char capsShiftKey[32]; 1304 char optionCapsKey[32]; 1305 char optionCapsShiftKey[32]; 1306 1307 GetKey(fChars, fKeys.normal_map[i], normalKey, 32); 1308 GetKey(fChars, fKeys.shift_map[i], shiftKey, 32); 1309 GetKey(fChars, fKeys.control_map[i], controlKey, 32); 1310 GetKey(fChars, fKeys.option_map[i], optionKey, 32); 1311 GetKey(fChars, fKeys.option_shift_map[i], optionShiftKey, 32); 1312 GetKey(fChars, fKeys.caps_map[i], capsKey, 32); 1313 GetKey(fChars, fKeys.caps_shift_map[i], capsShiftKey, 32); 1314 GetKey(fChars, fKeys.option_caps_map[i], optionCapsKey, 32); 1315 GetKey(fChars, fKeys.option_caps_shift_map[i], optionCapsShiftKey, 32); 1316 1317 fprintf(file, "Key 0x%02x = %-9s%-9s%-9s%-9s%-9s%-9s%-9s%-9s%-9s\n", i, 1318 normalKey, shiftKey, controlKey, optionKey, optionShiftKey, capsKey, 1319 capsShiftKey, optionCapsKey, optionCapsShiftKey); 1320 } 1321 1322 int32* deadOffsets[] = { 1323 fKeys.acute_dead_key, 1324 fKeys.grave_dead_key, 1325 fKeys.circumflex_dead_key, 1326 fKeys.dieresis_dead_key, 1327 fKeys.tilde_dead_key 1328 }; 1329 1330 char labels[][12] = { 1331 "Acute", 1332 "Grave", 1333 "Circumflex", 1334 "Diaeresis", 1335 "Tilde" 1336 }; 1337 1338 uint32 deadTables[] = { 1339 fKeys.acute_tables, 1340 fKeys.grave_tables, 1341 fKeys.circumflex_tables, 1342 fKeys.dieresis_tables, 1343 fKeys.tilde_tables 1344 }; 1345 1346 for (int i = 0; i < 5; i++) { 1347 for (int deadIndex = 0; deadIndex < 32; deadIndex++) { 1348 char deadKey[32]; 1349 char secondKey[32]; 1350 if (!GetKey(fChars, deadOffsets[i][deadIndex++], deadKey, 32)) 1351 break; 1352 1353 GetKey(fChars, deadOffsets[i][deadIndex], secondKey, 32); 1354 fprintf(file, "%s %-9s = %-9s\n", labels[i], deadKey, secondKey); 1355 } 1356 1357 fprintf(file, "%sTab = ", labels[i]); 1358 1359 if (deadTables[i] & B_NORMAL_TABLE) 1360 fprintf(file, "Normal "); 1361 if (deadTables[i] & B_SHIFT_TABLE) 1362 fprintf(file, "Shift "); 1363 if (deadTables[i] & B_CONTROL_TABLE) 1364 fprintf(file, "Control "); 1365 if (deadTables[i] & B_OPTION_TABLE) 1366 fprintf(file, "Option "); 1367 if (deadTables[i] & B_OPTION_SHIFT_TABLE) 1368 fprintf(file, "Option-Shift "); 1369 if (deadTables[i] & B_CAPS_TABLE) 1370 fprintf(file, "CapsLock "); 1371 if (deadTables[i] & B_CAPS_SHIFT_TABLE) 1372 fprintf(file, "CapsLock-Shift "); 1373 if (deadTables[i] & B_OPTION_CAPS_TABLE) 1374 fprintf(file, "CapsLock-Option "); 1375 if (deadTables[i] & B_OPTION_CAPS_SHIFT_TABLE) 1376 fprintf(file, "CapsLock-Option-Shift "); 1377 fprintf(file, "\n"); 1378 } 1379 } 1380 1381 1382 void 1383 Keymap::_ComputeChars(const char* buffer, struct re_registers& regs, int i, 1384 int& offset) 1385 { 1386 char* current = &fChars[offset + 1]; 1387 char hexChars[12]; 1388 uint32 length = 0; 1389 1390 if (strncmp(buffer + regs.start[i], "''", regs.end[i] - regs.start[i]) == 0) 1391 length = 0; 1392 else if (sscanf(buffer + regs.start[i], "'%s'", current) > 0) { 1393 if (current[0] == '\\') 1394 current[0] = current[1]; 1395 else if (current[0] == '\'') 1396 current[0] = ' '; 1397 length = 1; 1398 } else if (sscanf(buffer + regs.start[i], "0x%s", hexChars) > 0) { 1399 length = strlen(hexChars) / 2; 1400 for (uint32 j = 0; j < length; j++) 1401 sscanf(hexChars + 2*j, "%02hhx", current + j); 1402 } 1403 1404 fChars[offset] = length; 1405 offset += length + 1; 1406 } 1407 1408 1409 void 1410 Keymap::_ComputeTables(const char* buffer, struct re_registers& regs, 1411 uint32& table) 1412 { 1413 for (int32 i = 1; i <= 9; i++) { 1414 int32 length = regs.end[i] - regs.start[i]; 1415 if (length <= 0) 1416 break; 1417 1418 const char* start = buffer + regs.start[i]; 1419 1420 if (strncmp(start, "Normal", length) == 0) 1421 table |= B_NORMAL_TABLE; 1422 else if (strncmp(start, "Shift", length) == 0) 1423 table |= B_SHIFT_TABLE; 1424 else if (strncmp(start, "Control", length) == 0) 1425 table |= B_CONTROL_TABLE; 1426 else if (strncmp(start, "Option", length) == 0) 1427 table |= B_OPTION_TABLE; 1428 else if (strncmp(start, "Option-Shift", length) == 0) 1429 table |= B_OPTION_SHIFT_TABLE; 1430 else if (strncmp(start, "CapsLock", length) == 0) 1431 table |= B_CAPS_TABLE; 1432 else if (strncmp(start, "CapsLock-Shift", length) == 0) 1433 table |= B_CAPS_SHIFT_TABLE; 1434 else if (strncmp(start, "CapsLock-Option", length) == 0) 1435 table |= B_OPTION_CAPS_TABLE; 1436 else if (strncmp(start, "CapsLock-Option-Shift", length) == 0) 1437 table |= B_OPTION_CAPS_SHIFT_TABLE; 1438 } 1439 } 1440