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