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 } 203 204 205 Keymap::~Keymap() 206 { 207 } 208 209 210 status_t 211 Keymap::LoadSource(const char* name) 212 { 213 FILE* file = fopen(name, "r"); 214 if (file == NULL) 215 return errno; 216 217 status_t status = LoadSource(file); 218 fclose(file); 219 220 return status; 221 } 222 223 224 status_t 225 Keymap::LoadSource(FILE* file) 226 { 227 // Setup regexp parser 228 229 reg_syntax_t syntax = RE_CHAR_CLASSES; 230 re_set_syntax(syntax); 231 232 const char* error = re_compile_pattern(versionPattern, 233 strlen(versionPattern), &versionBuf); 234 if (error) 235 fprintf(stderr, error); 236 error = re_compile_pattern(capslockPattern, strlen(capslockPattern), 237 &capslockBuf); 238 if (error) 239 fprintf(stderr, error); 240 error = re_compile_pattern(scrolllockPattern, strlen(scrolllockPattern), 241 &scrolllockBuf); 242 if (error) 243 fprintf(stderr, error); 244 error = re_compile_pattern(numlockPattern, strlen(numlockPattern), 245 &numlockBuf); 246 if (error) 247 fprintf(stderr, error); 248 error = re_compile_pattern(lshiftPattern, strlen(lshiftPattern), &lshiftBuf); 249 if (error) 250 fprintf(stderr, error); 251 error = re_compile_pattern(rshiftPattern, strlen(rshiftPattern), &rshiftBuf); 252 if (error) 253 fprintf(stderr, error); 254 error = re_compile_pattern(lcommandPattern, strlen(lcommandPattern), 255 &lcommandBuf); 256 if (error) 257 fprintf(stderr, error); 258 error = re_compile_pattern(rcommandPattern, strlen(rcommandPattern), 259 &rcommandBuf); 260 if (error) 261 fprintf(stderr, error); 262 error = re_compile_pattern(lcontrolPattern, strlen(lcontrolPattern), 263 &lcontrolBuf); 264 if (error) 265 fprintf(stderr, error); 266 error = re_compile_pattern(rcontrolPattern, strlen(rcontrolPattern), 267 &rcontrolBuf); 268 if (error) 269 fprintf(stderr, error); 270 error = re_compile_pattern(loptionPattern, strlen(loptionPattern), 271 &loptionBuf); 272 if (error) 273 fprintf(stderr, error); 274 error = re_compile_pattern(roptionPattern, strlen(roptionPattern), 275 &roptionBuf); 276 if (error) 277 fprintf(stderr, error); 278 error = re_compile_pattern(menuPattern, strlen(menuPattern), &menuBuf); 279 if (error) 280 fprintf(stderr, error); 281 error = re_compile_pattern(locksettingsPattern, strlen(locksettingsPattern), 282 &locksettingsBuf); 283 if (error) 284 fprintf(stderr, error); 285 error = re_compile_pattern(keyPattern, strlen(keyPattern), &keyBuf); 286 if (error) 287 fprintf(stderr, error); 288 error = re_compile_pattern(acutePattern, strlen(acutePattern), ´Buf); 289 if (error) 290 fprintf(stderr, error); 291 error = re_compile_pattern(gravePattern, strlen(gravePattern), &graveBuf); 292 if (error) 293 fprintf(stderr, error); 294 error = re_compile_pattern(circumflexPattern, strlen(circumflexPattern), 295 &circumflexBuf); 296 if (error) 297 fprintf(stderr, error); 298 error = re_compile_pattern(diaeresisPattern, strlen(diaeresisPattern), 299 &diaeresisBuf); 300 if (error) 301 fprintf(stderr, error); 302 error = re_compile_pattern(tildePattern, strlen(tildePattern), &tildeBuf); 303 if (error) 304 fprintf(stderr, error); 305 error = re_compile_pattern(acutetabPattern, strlen(acutetabPattern), 306 ´tabBuf); 307 if (error) 308 fprintf(stderr, error); 309 error = re_compile_pattern(gravetabPattern, strlen(gravetabPattern), 310 &gravetabBuf); 311 if (error) 312 fprintf(stderr, error); 313 error = re_compile_pattern(circumflextabPattern, 314 strlen(circumflextabPattern), &circumflextabBuf); 315 if (error) 316 fprintf(stderr, error); 317 error = re_compile_pattern(diaeresistabPattern, strlen(diaeresistabPattern), 318 &diaeresistabBuf); 319 if (error) 320 fprintf(stderr, error); 321 error = re_compile_pattern(tildetabPattern, strlen(tildetabPattern), 322 &tildetabBuf); 323 if (error) 324 fprintf(stderr, error); 325 326 // Read file 327 328 delete[] fChars; 329 fChars = new char[CHARS_TABLE_MAXSIZE]; 330 fCharsSize = CHARS_TABLE_MAXSIZE; 331 int offset = 0; 332 int acuteOffset = 0; 333 int graveOffset = 0; 334 int circumflexOffset = 0; 335 int diaeresisOffset = 0; 336 int tildeOffset = 0; 337 338 int32* maps[] = { 339 fKeys.normal_map, 340 fKeys.shift_map, 341 fKeys.control_map, 342 fKeys.option_map, 343 fKeys.option_shift_map, 344 fKeys.caps_map, 345 fKeys.caps_shift_map, 346 fKeys.option_caps_map, 347 fKeys.option_caps_shift_map 348 }; 349 350 char buffer[1024]; 351 352 while (fgets(buffer, sizeof(buffer) - 1, file) != NULL) { 353 if (buffer[0] == '#' || buffer[0] == '\n') 354 continue; 355 356 size_t length = strlen(buffer); 357 358 struct re_registers regs; 359 if (re_search(&versionBuf, buffer, length, 0, length, ®s) >= 0) { 360 sscanf(buffer + regs.start[1], "%" B_SCNu32, &fKeys.version); 361 } else if (re_search(&capslockBuf, buffer, length, 0, length, ®s) 362 >= 0) { 363 sscanf(buffer + regs.start[1], "0x%" B_SCNx32, &fKeys.caps_key); 364 } else if (re_search(&scrolllockBuf, buffer, length, 0, length, ®s) 365 >= 0) { 366 sscanf(buffer + regs.start[1], "0x%" B_SCNx32, &fKeys.scroll_key); 367 } else if (re_search(&numlockBuf, buffer, length, 0, length, ®s) 368 >= 0) { 369 sscanf(buffer + regs.start[1], "0x%" B_SCNx32, &fKeys.num_key); 370 } else if (re_search(&lshiftBuf, buffer, length, 0, length, ®s) 371 >= 0) { 372 sscanf(buffer + regs.start[1], "0x%" B_SCNx32, 373 &fKeys.left_shift_key); 374 } else if (re_search(&rshiftBuf, buffer, length, 0, length, ®s) 375 >= 0) { 376 sscanf(buffer + regs.start[1], "0x%" B_SCNx32, 377 &fKeys.right_shift_key); 378 } else if (re_search(&lcommandBuf, buffer, length, 0, length, ®s) 379 >= 0) { 380 sscanf(buffer + regs.start[1], "0x%" B_SCNx32, 381 &fKeys.left_command_key); 382 } else if (re_search(&rcommandBuf, buffer, length, 0, length, ®s) 383 >= 0) { 384 sscanf(buffer + regs.start[1], "0x%" B_SCNx32, 385 &fKeys.right_command_key); 386 } else if (re_search(&lcontrolBuf, buffer, length, 0, length, ®s) 387 >= 0) { 388 sscanf(buffer + regs.start[1], "0x%" B_SCNx32, 389 &fKeys.left_control_key); 390 } else if (re_search(&rcontrolBuf, buffer, length, 0, length, ®s) 391 >= 0) { 392 sscanf(buffer + regs.start[1], "0x%" B_SCNx32, 393 &fKeys.right_control_key); 394 } else if (re_search(&loptionBuf, buffer, length, 0, length, ®s) 395 >= 0) { 396 sscanf(buffer + regs.start[1], "0x%" B_SCNx32, 397 &fKeys.left_option_key); 398 } else if (re_search(&roptionBuf, buffer, length, 0, length, ®s) 399 >= 0) { 400 sscanf(buffer + regs.start[1], "0x%" B_SCNx32, 401 &fKeys.right_option_key); 402 } else if (re_search(&menuBuf, buffer, length, 0, length, ®s) >= 0) { 403 sscanf(buffer + regs.start[1], "0x%" B_SCNx32, &fKeys.menu_key); 404 } else if (re_search(&locksettingsBuf, buffer, length, 0, length, ®s) 405 >= 0) { 406 fKeys.lock_settings = 0; 407 for (int32 i = 1; i <= 3; i++) { 408 const char* start = buffer + regs.start[i]; 409 length = regs.end[i] - regs.start[i]; 410 if (length == 0) 411 break; 412 413 if (!strncmp(start, "CapsLock", length)) 414 fKeys.lock_settings |= B_CAPS_LOCK; 415 else if (!strncmp(start, "NumLock", length)) 416 fKeys.lock_settings |= B_NUM_LOCK; 417 else if (!strncmp(start, "ScrollLock", length)) 418 fKeys.lock_settings |= B_SCROLL_LOCK; 419 } 420 } else if (re_search(&keyBuf, buffer, length, 0, length, ®s) >= 0) { 421 uint32 keyCode; 422 if (sscanf(buffer + regs.start[1], "0x%" B_SCNx32, &keyCode) > 0) { 423 for (int i = 2; i <= 10; i++) { 424 maps[i - 2][keyCode] = offset; 425 _ComputeChars(buffer, regs, i, offset); 426 } 427 } 428 } else if (re_search(´Buf, buffer, length, 0, length, ®s) >= 0) { 429 for (int i = 1; i <= 2; i++) { 430 fKeys.acute_dead_key[acuteOffset++] = offset; 431 _ComputeChars(buffer, regs, i, offset); 432 } 433 } else if (re_search(&graveBuf, buffer, length, 0, length, ®s) >= 0) { 434 for (int i = 1; i <= 2; i++) { 435 fKeys.grave_dead_key[graveOffset++] = offset; 436 _ComputeChars(buffer, regs, i, offset); 437 } 438 } else if (re_search(&circumflexBuf, buffer, length, 0, length, ®s) 439 >= 0) { 440 for (int i = 1; i <= 2; i++) { 441 fKeys.circumflex_dead_key[circumflexOffset++] = offset; 442 _ComputeChars(buffer, regs, i, offset); 443 } 444 } else if (re_search(&diaeresisBuf, buffer, length, 0, length, ®s) 445 >= 0) { 446 for (int i = 1; i <= 2; i++) { 447 fKeys.dieresis_dead_key[diaeresisOffset++] = offset; 448 _ComputeChars(buffer, regs, i, offset); 449 } 450 } else if (re_search(&tildeBuf, buffer, length, 0, length, ®s) >= 0) { 451 for (int i = 1; i <= 2; i++) { 452 fKeys.tilde_dead_key[tildeOffset++] = offset; 453 _ComputeChars(buffer, regs, i, offset); 454 } 455 } else if (re_search(´tabBuf, buffer, length, 0, length, ®s) 456 >= 0) { 457 _ComputeTables(buffer, regs, fKeys.acute_tables); 458 } else if (re_search(&gravetabBuf, buffer, length, 0, length, ®s) 459 >= 0) { 460 _ComputeTables(buffer, regs, fKeys.grave_tables); 461 } else if (re_search(&circumflextabBuf, buffer, length, 0, length, ®s) 462 >= 0) { 463 _ComputeTables(buffer, regs, fKeys.circumflex_tables); 464 } else if (re_search(&diaeresistabBuf, buffer, length, 0, length, ®s) 465 >= 0) { 466 _ComputeTables(buffer, regs, fKeys.dieresis_tables); 467 } else if (re_search(&tildetabBuf, buffer, length, 0, length, ®s) 468 >= 0) { 469 _ComputeTables(buffer, regs, fKeys.tilde_tables); 470 } 471 } 472 473 fCharsSize = offset; 474 475 if (fKeys.version != 3) 476 return KEYMAP_ERROR_UNKNOWN_VERSION; 477 478 return B_OK; 479 } 480 481 482 status_t 483 Keymap::SaveAsCurrent() 484 { 485 #if (defined(__BEOS__) || defined(__HAIKU__)) 486 BPath path; 487 status_t status = find_directory(B_USER_SETTINGS_DIRECTORY, &path, true); 488 if (status != B_OK) 489 return status; 490 491 path.Append("Key_map"); 492 493 status = Save(path.Path()); 494 if (status != B_OK) 495 return status; 496 497 Use(); 498 return B_OK; 499 #else // ! __BEOS__ 500 fprintf(stderr, "Unsupported operation on this platform!\n"); 501 exit(1); 502 #endif // ! __BEOS__ 503 } 504 505 506 //! Save a binary keymap to a file. 507 status_t 508 Keymap::Save(const char* name) 509 { 510 BFile file; 511 status_t status = file.SetTo(name, 512 B_WRITE_ONLY | B_CREATE_FILE | B_ERASE_FILE); 513 if (status != B_OK) 514 return status; 515 516 // convert to big endian 517 for (uint32 i = 0; i < sizeof(fKeys) / sizeof(uint32); i++) { 518 ((uint32*)&fKeys)[i] = B_HOST_TO_BENDIAN_INT32(((uint32*)&fKeys)[i]); 519 } 520 521 ssize_t bytesWritten = file.Write(&fKeys, sizeof(fKeys)); 522 523 // convert endian back 524 for (uint32 i = 0; i < sizeof(fKeys) / sizeof(uint32); i++) { 525 ((uint32*)&fKeys)[i] = B_BENDIAN_TO_HOST_INT32(((uint32*)&fKeys)[i]); 526 } 527 528 if (bytesWritten < (ssize_t)sizeof(fKeys)) 529 return B_ERROR; 530 if (bytesWritten < B_OK) 531 return bytesWritten; 532 533 uint32 charSize = B_HOST_TO_BENDIAN_INT32(fCharsSize); 534 535 bytesWritten = file.Write(&charSize, sizeof(uint32)); 536 if (bytesWritten < (ssize_t)sizeof(uint32)) 537 return B_ERROR; 538 if (bytesWritten < B_OK) 539 return bytesWritten; 540 541 bytesWritten = file.Write(fChars, fCharsSize); 542 if (bytesWritten < (ssize_t)fCharsSize) 543 return B_ERROR; 544 if (bytesWritten < B_OK) 545 return bytesWritten; 546 547 return B_OK; 548 } 549 550 551 status_t 552 Keymap::SaveAsSource(const char* name) 553 { 554 FILE* file = fopen(name, "w"); 555 if (file == NULL) 556 return errno; 557 558 #if (defined(__BEOS__) || defined(__HAIKU__)) 559 text_run_array* textRuns; 560 _SaveSourceText(file, &textRuns); 561 562 if (textRuns != NULL) { 563 ssize_t dataSize; 564 void* data = BTextView::FlattenRunArray(textRuns, &dataSize); 565 if (data != NULL) { 566 BNode node(name); 567 node.WriteAttr("styles", B_RAW_TYPE, 0, data, dataSize); 568 569 free(data); 570 } 571 572 BTextView::FreeRunArray(textRuns); 573 } 574 #else 575 _SaveSourceText(file); 576 #endif 577 578 fclose(file); 579 580 return B_OK; 581 } 582 583 584 status_t 585 Keymap::SaveAsSource(FILE* file) 586 { 587 _SaveSourceText(file); 588 return B_OK; 589 } 590 591 592 /*! Save a keymap as C source file - this is used to get the default keymap 593 into the input_server, for example. 594 \a mapName is usually the path of the input keymap, and is used as the 595 name of the keymap (the path will be removed, as well as its suffix). 596 */ 597 status_t 598 Keymap::SaveAsCppHeader(const char* fileName, const char* mapName) 599 { 600 BString name = mapName; 601 602 // cut off path 603 int32 index = name.FindLast('/'); 604 if (index > 0) 605 name.Remove(0, index + 1); 606 607 // prune ".keymap" 608 index = name.FindLast('.'); 609 if (index > 0) 610 name.Truncate(index); 611 612 FILE* file = fopen(fileName, "w"); 613 if (file == NULL) 614 return errno; 615 616 fprintf(file, "/*\n" 617 " * Haiku Keymap\n" 618 " * This file is generated automatically. Don't edit!\n" 619 " */\n\n"); 620 fprintf(file, "#include <InterfaceDefs.h>\n\n"); 621 fprintf(file, "const char *kSystemKeymapName = \"%s\";\n\n", name.String()); 622 fprintf(file, "const key_map kSystemKeymap = {\n"); 623 fprintf(file, "\tversion:%" B_PRIu32 ",\n", fKeys.version); 624 fprintf(file, "\tcaps_key:0x%" B_PRIx32 ",\n", fKeys.caps_key); 625 fprintf(file, "\tscroll_key:0x%" B_PRIx32 ",\n", fKeys.scroll_key); 626 fprintf(file, "\tnum_key:0x%" B_PRIx32 ",\n", fKeys.num_key); 627 fprintf(file, "\tleft_shift_key:0x%" B_PRIx32 ",\n", fKeys.left_shift_key); 628 fprintf(file, "\tright_shift_key:0x%" B_PRIx32 ",\n", 629 fKeys.right_shift_key); 630 fprintf(file, "\tleft_command_key:0x%" B_PRIx32 ",\n", 631 fKeys.left_command_key); 632 fprintf(file, "\tright_command_key:0x%" B_PRIx32 ",\n", 633 fKeys.right_command_key); 634 fprintf(file, "\tleft_control_key:0x%" B_PRIx32 ",\n", 635 fKeys.left_control_key); 636 fprintf(file, "\tright_control_key:0x%" B_PRIx32 ",\n", 637 fKeys.right_control_key); 638 fprintf(file, "\tleft_option_key:0x%" B_PRIx32 ",\n", 639 fKeys.left_option_key); 640 fprintf(file, "\tright_option_key:0x%" B_PRIx32 ",\n", 641 fKeys.right_option_key); 642 fprintf(file, "\tmenu_key:0x%" B_PRIx32 ",\n", fKeys.menu_key); 643 fprintf(file, "\tlock_settings:0x%" B_PRIx32 ",\n", fKeys.lock_settings); 644 645 dump_map(file, "control_map", fKeys.control_map); 646 dump_map(file, "option_caps_shift_map", fKeys.option_caps_shift_map); 647 dump_map(file, "option_caps_map", fKeys.option_caps_map); 648 dump_map(file, "option_shift_map", fKeys.option_shift_map); 649 dump_map(file, "option_map", fKeys.option_map); 650 dump_map(file, "caps_shift_map", fKeys.caps_shift_map); 651 dump_map(file, "caps_map", fKeys.caps_map); 652 dump_map(file, "shift_map", fKeys.shift_map); 653 dump_map(file, "normal_map", fKeys.normal_map); 654 655 dump_keys(file, "acute_dead_key", fKeys.acute_dead_key); 656 dump_keys(file, "grave_dead_key", fKeys.grave_dead_key); 657 658 dump_keys(file, "circumflex_dead_key", fKeys.circumflex_dead_key); 659 dump_keys(file, "dieresis_dead_key", fKeys.dieresis_dead_key); 660 dump_keys(file, "tilde_dead_key", fKeys.tilde_dead_key); 661 662 fprintf(file, "\tacute_tables:0x%" B_PRIx32 ",\n", fKeys.acute_tables); 663 fprintf(file, "\tgrave_tables:0x%" B_PRIx32 ",\n", fKeys.grave_tables); 664 fprintf(file, "\tcircumflex_tables:0x%" B_PRIx32 ",\n", 665 fKeys.circumflex_tables); 666 fprintf(file, "\tdieresis_tables:0x%" B_PRIx32 ",\n", 667 fKeys.dieresis_tables); 668 fprintf(file, "\ttilde_tables:0x%" B_PRIx32 ",\n", fKeys.tilde_tables); 669 670 fprintf(file, "};\n\n"); 671 672 fprintf(file, "const char kSystemKeyChars[] = {\n"); 673 for (uint32 i = 0; i < fCharsSize; i++) { 674 if (i % 10 == 0) { 675 if (i > 0) 676 fprintf(file, "\n"); 677 fprintf(file, "\t"); 678 } else 679 fprintf(file, " "); 680 681 fprintf(file, "0x%02x,", (uint8)fChars[i]); 682 } 683 fprintf(file, "\n};\n\n"); 684 685 fprintf(file, "const uint32 kSystemKeyCharsSize = %" B_PRIu32 ";\n", 686 fCharsSize); 687 fclose(file); 688 689 return B_OK; 690 } 691 692 693 //! We make our input server use the map in /boot/home/config/settings/Keymap 694 status_t 695 Keymap::Use() 696 { 697 #if (defined(__BEOS__) || defined(__HAIKU__)) 698 return _restore_key_map_(); 699 700 #else // ! __BEOS__ 701 fprintf(stderr, "Unsupported operation on this platform!\n"); 702 exit(1); 703 #endif // ! __BEOS__ 704 } 705 706 707 void 708 Keymap::RestoreSystemDefault() 709 { 710 #if (defined(__BEOS__) || defined(__HAIKU__)) 711 // work-around to get rid of this stupid find_directory_r() on Zeta 712 # ifdef find_directory 713 # undef find_directory 714 # endif 715 BPath path; 716 if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) != B_OK) 717 return; 718 719 path.Append("Key_map"); 720 721 BEntry entry(path.Path()); 722 entry.Remove(); 723 724 _restore_key_map_(); 725 #else // ! __BEOS__ 726 fprintf(stderr, "Unsupported operation on this platform!\n"); 727 exit(1); 728 #endif // ! __BEOS__ 729 } 730 731 732 /*static*/ bool 733 Keymap::GetKey(const char* chars, int32 offset, char* buffer, size_t bufferSize) 734 { 735 uint8 size = (uint8)chars[offset++]; 736 char string[1024]; 737 738 switch (size) { 739 case 0: 740 // Not mapped 741 strlcpy(buffer, "''", bufferSize); 742 return false; 743 744 case 1: 745 // 1-byte UTF-8/ASCII character 746 if ((uint8)chars[offset] < 0x20 || (uint8)chars[offset] > 0x7e) 747 sprintf(string, "0x%02x", (uint8)chars[offset]); 748 else { 749 sprintf(string, "'%s%c'", 750 (chars[offset] == '\\' || chars[offset] == '\'') ? "\\" : "", 751 chars[offset]); 752 } 753 break; 754 755 default: 756 // multi-byte UTF-8 character 757 sprintf(string, "0x"); 758 for (int i = 0; i < size; i++) { 759 sprintf(string + 2 * (i + 1), "%02x", (uint8)chars[offset + i]); 760 } 761 break; 762 } 763 764 strlcpy(buffer, string, bufferSize); 765 return true; 766 } 767 768 769 #if (defined(__BEOS__) || defined(__HAIKU__)) 770 void 771 Keymap::_SaveSourceText(FILE* file, text_run_array** _textRuns) 772 { 773 text_run_array* runs = NULL; 774 if (_textRuns != NULL) { 775 runs = BTextView::AllocRunArray(8); 776 *_textRuns = runs; 777 } 778 #else 779 void 780 Keymap::_SaveSourceText(FILE* file) 781 { 782 #endif 783 784 static const rgb_color kCommentColor = (rgb_color){200, 92, 92, 255}; 785 static const rgb_color kTextColor = (rgb_color){0, 0, 0, 255}; 786 787 #if (defined(__BEOS__) || defined(__HAIKU__)) 788 BFont font = *be_fixed_font; 789 790 if (runs != NULL) { 791 runs->runs[0].offset = 0; 792 runs->runs[0].font = font; 793 runs->runs[0].color = kCommentColor; 794 } 795 #endif 796 797 int bytes = fprintf(file, "#!/bin/keymap -s\n" 798 "#\n" 799 "#\tRaw key numbering for 101 keyboard...\n"); 800 801 #if (defined(__BEOS__) || defined(__HAIKU__)) 802 if (runs != NULL) { 803 runs->runs[1].offset = bytes; 804 runs->runs[1].font = font; 805 runs->runs[1].font.SetSize(9); 806 runs->runs[1].color = kCommentColor; 807 } 808 #endif 809 810 bytes += fprintf(file, "# [sys] [brk]\n" 811 "# 0x7e 0x7f\n" 812 "# [esc] [ f1] [ f2] [ f3] [ f4] [ f5] [ f6] [ f7] [ f8] [ f9] [f10] [f11] [f12] [prn] [scr] [pau]\n" 813 "# 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" 814 "#\n" 815 "# [ ` ] [ 1 ] [ 2 ] [ 3 ] [ 4 ] [ 5 ] [ 6 ] [ 7 ] [ 8 ] [ 9 ] [ 0 ] [ - ] [ = ] [bck] [ins] [hme] [pup] [num] [ / ] [ * ] [ - ]\n" 816 "# 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1a 0x1b 0x1c 0x1d 0x1e 0x1f 0x20 0x21 0x22 0x23 0x24 0x25\n" 817 "#\n" 818 "# [tab] [ q ] [ w ] [ e ] [ r ] [ t ] [ y ] [ u ] [ i ] [ o ] [ p ] [ [ ] [ ] ] [ \\ ] [del] [end] [pdn] [ 7 ] [ 8 ] [ 9 ] [ + ]\n" 819 "# 0x26 0x27 0x28 0x29 0x2a 0x2b 0x2c 0x2d 0x2e 0x2f 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3a\n" 820 "#\n" 821 "# [cap] [ a ] [ s ] [ d ] [ f ] [ g ] [ h ] [ j ] [ k ] [ l ] [ ; ] [ ' ] [ enter ] [ 4 ] [ 5 ] [ 6 ]\n" 822 "# 0x3b 0x3c 0x3d 0x3e 0x3f 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4a\n" 823 "#\n" 824 "# [shift] [ z ] [ x ] [ c ] [ v ] [ b ] [ n ] [ m ] [ , ] [ . ] [ / ] [shift] [ up] [ 1 ] [ 2 ] [ 3 ] [ent]\n" 825 "# 0x4b 0x4c 0x4d 0x4e 0x4f 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5a 0x5b\n" 826 "#\n" 827 "# [ctr] [cmd] [ space ] [cmd] [ctr] [lft] [dwn] [rgt] [ 0 ] [ . ]\n" 828 "# 0x5c 0x5d 0x5e 0x5f 0x60 0x61 0x62 0x63 0x64 0x65\n"); 829 830 #if (defined(__BEOS__) || defined(__HAIKU__)) 831 if (runs != NULL) { 832 runs->runs[2].offset = bytes; 833 runs->runs[2].font = font; 834 runs->runs[2].color = kCommentColor; 835 } 836 #endif 837 838 bytes += fprintf(file, "#\n" 839 "#\tNOTE: On a Microsoft Natural Keyboard:\n" 840 "#\t\t\tleft option = 0x66\n" 841 "#\t\t\tright option = 0x67\n" 842 "#\t\t\tmenu key = 0x68\n" 843 "#\tNOTE: On an Apple Extended Keyboard:\n" 844 "#\t\t\tleft option = 0x66\n" 845 "#\t\t\tright option = 0x67\n" 846 "#\t\t\tkeypad '=' = 0x6a\n" 847 "#\t\t\tpower key = 0x6b\n"); 848 849 #if (defined(__BEOS__) || defined(__HAIKU__)) 850 if (runs != NULL) { 851 runs->runs[3].offset = bytes; 852 runs->runs[3].font = *be_fixed_font; 853 runs->runs[3].color = kTextColor; 854 } 855 #endif 856 857 bytes += fprintf(file, "Version = %" B_PRIu32 "\n" 858 "CapsLock = 0x%02" B_PRIx32 "\n" 859 "ScrollLock = 0x%02" B_PRIx32 "\n" 860 "NumLock = 0x%02" B_PRIx32 "\n" 861 "LShift = 0x%02" B_PRIx32 "\n" 862 "RShift = 0x%02" B_PRIx32 "\n" 863 "LCommand = 0x%02" B_PRIx32 "\n" 864 "RCommand = 0x%02" B_PRIx32 "\n" 865 "LControl = 0x%02" B_PRIx32 "\n" 866 "RControl = 0x%02" B_PRIx32 "\n" 867 "LOption = 0x%02" B_PRIx32 "\n" 868 "ROption = 0x%02" B_PRIx32 "\n" 869 "Menu = 0x%02" B_PRIx32 "\n", 870 fKeys.version, fKeys.caps_key, fKeys.scroll_key, fKeys.num_key, 871 fKeys.left_shift_key, fKeys.right_shift_key, fKeys.left_command_key, 872 fKeys.right_command_key, fKeys.left_control_key, fKeys.right_control_key, 873 fKeys.left_option_key, fKeys.right_option_key, fKeys.menu_key); 874 875 #if (defined(__BEOS__) || defined(__HAIKU__)) 876 if (runs != NULL) { 877 runs->runs[4].offset = bytes; 878 runs->runs[4].font = *be_fixed_font; 879 runs->runs[4].color = kCommentColor; 880 } 881 #endif 882 883 bytes += fprintf(file, "#\n" 884 "# Lock settings\n" 885 "# To set NumLock, do the following:\n" 886 "# LockSettings = NumLock\n" 887 "#\n" 888 "# To set everything, do the following:\n" 889 "# LockSettings = CapsLock NumLock ScrollLock\n" 890 "#\n"); 891 892 #if (defined(__BEOS__) || defined(__HAIKU__)) 893 if (runs != NULL) { 894 runs->runs[5].offset = bytes; 895 runs->runs[5].font = *be_fixed_font; 896 runs->runs[5].color = kTextColor; 897 } 898 #endif 899 900 bytes += fprintf(file, "LockSettings = "); 901 if ((fKeys.lock_settings & B_CAPS_LOCK) != 0) 902 bytes += fprintf(file, "CapsLock "); 903 if ((fKeys.lock_settings & B_NUM_LOCK) != 0) 904 bytes += fprintf(file, "NumLock "); 905 if ((fKeys.lock_settings & B_SCROLL_LOCK) != 0) 906 bytes += fprintf(file, "ScrollLock "); 907 bytes += fprintf(file, "\n"); 908 909 #if (defined(__BEOS__) || defined(__HAIKU__)) 910 if (runs != NULL) { 911 runs->runs[6].offset = bytes; 912 runs->runs[6].font = *be_fixed_font; 913 runs->runs[6].color = kCommentColor; 914 } 915 #endif 916 917 bytes += fprintf(file, "# Legend:\n" 918 "# n = Normal\n" 919 "# s = Shift\n" 920 "# c = Control\n" 921 "# C = CapsLock\n" 922 "# o = Option\n" 923 "# Key n s c o os C Cs Co Cos \n"); 924 925 #if (defined(__BEOS__) || defined(__HAIKU__)) 926 if (runs != NULL) { 927 runs->runs[7].offset = bytes; 928 runs->runs[7].font = *be_fixed_font; 929 runs->runs[7].color = kTextColor; 930 } 931 #endif 932 933 for (int i = 0; i < 128; i++) { 934 char normalKey[32]; 935 char shiftKey[32]; 936 char controlKey[32]; 937 char optionKey[32]; 938 char optionShiftKey[32]; 939 char capsKey[32]; 940 char capsShiftKey[32]; 941 char optionCapsKey[32]; 942 char optionCapsShiftKey[32]; 943 944 GetKey(fChars, fKeys.normal_map[i], normalKey, 32); 945 GetKey(fChars, fKeys.shift_map[i], shiftKey, 32); 946 GetKey(fChars, fKeys.control_map[i], controlKey, 32); 947 GetKey(fChars, fKeys.option_map[i], optionKey, 32); 948 GetKey(fChars, fKeys.option_shift_map[i], optionShiftKey, 32); 949 GetKey(fChars, fKeys.caps_map[i], capsKey, 32); 950 GetKey(fChars, fKeys.caps_shift_map[i], capsShiftKey, 32); 951 GetKey(fChars, fKeys.option_caps_map[i], optionCapsKey, 32); 952 GetKey(fChars, fKeys.option_caps_shift_map[i], optionCapsShiftKey, 32); 953 954 fprintf(file, "Key 0x%02x = %-9s%-9s%-9s%-9s%-9s%-9s%-9s%-9s%-9s\n", i, 955 normalKey, shiftKey, controlKey, optionKey, optionShiftKey, capsKey, 956 capsShiftKey, optionCapsKey, optionCapsShiftKey); 957 } 958 959 int32* deadOffsets[] = { 960 fKeys.acute_dead_key, 961 fKeys.grave_dead_key, 962 fKeys.circumflex_dead_key, 963 fKeys.dieresis_dead_key, 964 fKeys.tilde_dead_key 965 }; 966 967 char labels[][12] = { 968 "Acute", 969 "Grave", 970 "Circumflex", 971 "Diaeresis", 972 "Tilde" 973 }; 974 975 uint32 deadTables[] = { 976 fKeys.acute_tables, 977 fKeys.grave_tables, 978 fKeys.circumflex_tables, 979 fKeys.dieresis_tables, 980 fKeys.tilde_tables 981 }; 982 983 for (int i = 0; i < 5; i++) { 984 for (int deadIndex = 0; deadIndex < 32; deadIndex++) { 985 char deadKey[32]; 986 char secondKey[32]; 987 if (!GetKey(fChars, deadOffsets[i][deadIndex++], deadKey, 32)) 988 break; 989 990 GetKey(fChars, deadOffsets[i][deadIndex], secondKey, 32); 991 fprintf(file, "%s %-9s = %-9s\n", labels[i], deadKey, secondKey); 992 } 993 994 fprintf(file, "%sTab = ", labels[i]); 995 996 if (deadTables[i] & B_NORMAL_TABLE) 997 fprintf(file, "Normal "); 998 if (deadTables[i] & B_SHIFT_TABLE) 999 fprintf(file, "Shift "); 1000 if (deadTables[i] & B_CONTROL_TABLE) 1001 fprintf(file, "Control "); 1002 if (deadTables[i] & B_OPTION_TABLE) 1003 fprintf(file, "Option "); 1004 if (deadTables[i] & B_OPTION_SHIFT_TABLE) 1005 fprintf(file, "Option-Shift "); 1006 if (deadTables[i] & B_CAPS_TABLE) 1007 fprintf(file, "CapsLock "); 1008 if (deadTables[i] & B_CAPS_SHIFT_TABLE) 1009 fprintf(file, "CapsLock-Shift "); 1010 if (deadTables[i] & B_OPTION_CAPS_TABLE) 1011 fprintf(file, "CapsLock-Option "); 1012 if (deadTables[i] & B_OPTION_CAPS_SHIFT_TABLE) 1013 fprintf(file, "CapsLock-Option-Shift "); 1014 fprintf(file, "\n"); 1015 } 1016 } 1017 1018 1019 void 1020 Keymap::_ComputeChars(const char* buffer, struct re_registers& regs, int i, 1021 int& offset) 1022 { 1023 char* current = &fChars[offset + 1]; 1024 char hexChars[12]; 1025 uint32 length = 0; 1026 1027 if (strncmp(buffer + regs.start[i], "''", regs.end[i] - regs.start[i]) == 0) 1028 length = 0; 1029 else if (sscanf(buffer + regs.start[i], "'%s'", current) > 0) { 1030 if (current[0] == '\\') 1031 current[0] = current[1]; 1032 else if (current[0] == '\'') 1033 current[0] = ' '; 1034 length = 1; 1035 } else if (sscanf(buffer + regs.start[i], "0x%s", hexChars) > 0) { 1036 length = strlen(hexChars) / 2; 1037 for (uint32 j = 0; j < length; j++) 1038 sscanf(hexChars + 2*j, "%02hhx", current + j); 1039 } 1040 1041 fChars[offset] = length; 1042 offset += length + 1; 1043 } 1044 1045 1046 void 1047 Keymap::_ComputeTables(const char* buffer, struct re_registers& regs, 1048 uint32& table) 1049 { 1050 for (int32 i = 1; i <= 9; i++) { 1051 int32 length = regs.end[i] - regs.start[i]; 1052 if (length <= 0) 1053 break; 1054 1055 const char* start = buffer + regs.start[i]; 1056 1057 if (strncmp(start, "Normal", length) == 0) 1058 table |= B_NORMAL_TABLE; 1059 else if (strncmp(start, "Shift", length) == 0) 1060 table |= B_SHIFT_TABLE; 1061 else if (strncmp(start, "Control", length) == 0) 1062 table |= B_CONTROL_TABLE; 1063 else if (strncmp(start, "Option", length) == 0) 1064 table |= B_OPTION_TABLE; 1065 else if (strncmp(start, "Option-Shift", length) == 0) 1066 table |= B_OPTION_SHIFT_TABLE; 1067 else if (strncmp(start, "CapsLock", length) == 0) 1068 table |= B_CAPS_TABLE; 1069 else if (strncmp(start, "CapsLock-Shift", length) == 0) 1070 table |= B_CAPS_SHIFT_TABLE; 1071 else if (strncmp(start, "CapsLock-Option", length) == 0) 1072 table |= B_OPTION_CAPS_TABLE; 1073 else if (strncmp(start, "CapsLock-Option-Shift", length) == 0) 1074 table |= B_OPTION_CAPS_SHIFT_TABLE; 1075 } 1076 } 1077