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 102-key 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 "# [ caps ] [ 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 "# [shft] [ \\ ] [ z ] [ x ] [ c ] [ v ] [ b ] [ n ] [ m ] [ , ] [ . ] [ / ] [ shift ] [ up] [ 1 ] [ 2 ] [ 3 ] [ent]\n" 825 "# 0x4b 0x69 0x4c 0x4d 0x4e 0x4f 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5a 0x5b\n" 826 "#\n" 827 "# [ ctrl ] [ cmd ] [ space ] [ cmd ] [ ctrl ] [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: Key 0x69 does not exist on US keyboards\n" 840 "#\tNOTE: On a Microsoft Natural Keyboard:\n" 841 "#\t\t\tleft option = 0x66\n" 842 "#\t\t\tright option = 0x67\n" 843 "#\t\t\tmenu key = 0x68\n" 844 "#\tNOTE: On an Apple Extended Keyboard:\n" 845 "#\t\t\tleft option = 0x66\n" 846 "#\t\t\tright option = 0x67\n" 847 "#\t\t\tkeypad '=' = 0x6a\n" 848 "#\t\t\tpower key = 0x6b\n"); 849 850 #if (defined(__BEOS__) || defined(__HAIKU__)) 851 if (runs != NULL) { 852 runs->runs[3].offset = bytes; 853 runs->runs[3].font = *be_fixed_font; 854 runs->runs[3].color = kTextColor; 855 } 856 #endif 857 858 bytes += fprintf(file, "Version = %" B_PRIu32 "\n" 859 "CapsLock = 0x%02" B_PRIx32 "\n" 860 "ScrollLock = 0x%02" B_PRIx32 "\n" 861 "NumLock = 0x%02" B_PRIx32 "\n" 862 "LShift = 0x%02" B_PRIx32 "\n" 863 "RShift = 0x%02" B_PRIx32 "\n" 864 "LCommand = 0x%02" B_PRIx32 "\n" 865 "RCommand = 0x%02" B_PRIx32 "\n" 866 "LControl = 0x%02" B_PRIx32 "\n" 867 "RControl = 0x%02" B_PRIx32 "\n" 868 "LOption = 0x%02" B_PRIx32 "\n" 869 "ROption = 0x%02" B_PRIx32 "\n" 870 "Menu = 0x%02" B_PRIx32 "\n", 871 fKeys.version, fKeys.caps_key, fKeys.scroll_key, fKeys.num_key, 872 fKeys.left_shift_key, fKeys.right_shift_key, fKeys.left_command_key, 873 fKeys.right_command_key, fKeys.left_control_key, fKeys.right_control_key, 874 fKeys.left_option_key, fKeys.right_option_key, fKeys.menu_key); 875 876 #if (defined(__BEOS__) || defined(__HAIKU__)) 877 if (runs != NULL) { 878 runs->runs[4].offset = bytes; 879 runs->runs[4].font = *be_fixed_font; 880 runs->runs[4].color = kCommentColor; 881 } 882 #endif 883 884 bytes += fprintf(file, "#\n" 885 "# Lock settings\n" 886 "# To set NumLock, do the following:\n" 887 "# LockSettings = NumLock\n" 888 "#\n" 889 "# To set everything, do the following:\n" 890 "# LockSettings = CapsLock NumLock ScrollLock\n" 891 "#\n"); 892 893 #if (defined(__BEOS__) || defined(__HAIKU__)) 894 if (runs != NULL) { 895 runs->runs[5].offset = bytes; 896 runs->runs[5].font = *be_fixed_font; 897 runs->runs[5].color = kTextColor; 898 } 899 #endif 900 901 bytes += fprintf(file, "LockSettings = "); 902 if ((fKeys.lock_settings & B_CAPS_LOCK) != 0) 903 bytes += fprintf(file, "CapsLock "); 904 if ((fKeys.lock_settings & B_NUM_LOCK) != 0) 905 bytes += fprintf(file, "NumLock "); 906 if ((fKeys.lock_settings & B_SCROLL_LOCK) != 0) 907 bytes += fprintf(file, "ScrollLock "); 908 bytes += fprintf(file, "\n"); 909 910 #if (defined(__BEOS__) || defined(__HAIKU__)) 911 if (runs != NULL) { 912 runs->runs[6].offset = bytes; 913 runs->runs[6].font = *be_fixed_font; 914 runs->runs[6].color = kCommentColor; 915 } 916 #endif 917 918 bytes += fprintf(file, "# Legend:\n" 919 "# n = Normal\n" 920 "# s = Shift\n" 921 "# c = Control\n" 922 "# C = CapsLock\n" 923 "# o = Option\n" 924 "# Key n s c o os C Cs Co Cos \n"); 925 926 #if (defined(__BEOS__) || defined(__HAIKU__)) 927 if (runs != NULL) { 928 runs->runs[7].offset = bytes; 929 runs->runs[7].font = *be_fixed_font; 930 runs->runs[7].color = kTextColor; 931 } 932 #endif 933 934 for (int i = 0; i < 128; i++) { 935 char normalKey[32]; 936 char shiftKey[32]; 937 char controlKey[32]; 938 char optionKey[32]; 939 char optionShiftKey[32]; 940 char capsKey[32]; 941 char capsShiftKey[32]; 942 char optionCapsKey[32]; 943 char optionCapsShiftKey[32]; 944 945 GetKey(fChars, fKeys.normal_map[i], normalKey, 32); 946 GetKey(fChars, fKeys.shift_map[i], shiftKey, 32); 947 GetKey(fChars, fKeys.control_map[i], controlKey, 32); 948 GetKey(fChars, fKeys.option_map[i], optionKey, 32); 949 GetKey(fChars, fKeys.option_shift_map[i], optionShiftKey, 32); 950 GetKey(fChars, fKeys.caps_map[i], capsKey, 32); 951 GetKey(fChars, fKeys.caps_shift_map[i], capsShiftKey, 32); 952 GetKey(fChars, fKeys.option_caps_map[i], optionCapsKey, 32); 953 GetKey(fChars, fKeys.option_caps_shift_map[i], optionCapsShiftKey, 32); 954 955 fprintf(file, "Key 0x%02x = %-9s%-9s%-9s%-9s%-9s%-9s%-9s%-9s%-9s\n", i, 956 normalKey, shiftKey, controlKey, optionKey, optionShiftKey, capsKey, 957 capsShiftKey, optionCapsKey, optionCapsShiftKey); 958 } 959 960 int32* deadOffsets[] = { 961 fKeys.acute_dead_key, 962 fKeys.grave_dead_key, 963 fKeys.circumflex_dead_key, 964 fKeys.dieresis_dead_key, 965 fKeys.tilde_dead_key 966 }; 967 968 char labels[][12] = { 969 "Acute", 970 "Grave", 971 "Circumflex", 972 "Diaeresis", 973 "Tilde" 974 }; 975 976 uint32 deadTables[] = { 977 fKeys.acute_tables, 978 fKeys.grave_tables, 979 fKeys.circumflex_tables, 980 fKeys.dieresis_tables, 981 fKeys.tilde_tables 982 }; 983 984 for (int i = 0; i < 5; i++) { 985 for (int deadIndex = 0; deadIndex < 32; deadIndex++) { 986 char deadKey[32]; 987 char secondKey[32]; 988 if (!GetKey(fChars, deadOffsets[i][deadIndex++], deadKey, 32)) 989 break; 990 991 GetKey(fChars, deadOffsets[i][deadIndex], secondKey, 32); 992 fprintf(file, "%s %-9s = %-9s\n", labels[i], deadKey, secondKey); 993 } 994 995 fprintf(file, "%sTab = ", labels[i]); 996 997 if (deadTables[i] & B_NORMAL_TABLE) 998 fprintf(file, "Normal "); 999 if (deadTables[i] & B_SHIFT_TABLE) 1000 fprintf(file, "Shift "); 1001 if (deadTables[i] & B_CONTROL_TABLE) 1002 fprintf(file, "Control "); 1003 if (deadTables[i] & B_OPTION_TABLE) 1004 fprintf(file, "Option "); 1005 if (deadTables[i] & B_OPTION_SHIFT_TABLE) 1006 fprintf(file, "Option-Shift "); 1007 if (deadTables[i] & B_CAPS_TABLE) 1008 fprintf(file, "CapsLock "); 1009 if (deadTables[i] & B_CAPS_SHIFT_TABLE) 1010 fprintf(file, "CapsLock-Shift "); 1011 if (deadTables[i] & B_OPTION_CAPS_TABLE) 1012 fprintf(file, "CapsLock-Option "); 1013 if (deadTables[i] & B_OPTION_CAPS_SHIFT_TABLE) 1014 fprintf(file, "CapsLock-Option-Shift "); 1015 fprintf(file, "\n"); 1016 } 1017 } 1018 1019 1020 void 1021 Keymap::_ComputeChars(const char* buffer, struct re_registers& regs, int i, 1022 int& offset) 1023 { 1024 char* current = &fChars[offset + 1]; 1025 char hexChars[12]; 1026 uint32 length = 0; 1027 1028 if (strncmp(buffer + regs.start[i], "''", regs.end[i] - regs.start[i]) == 0) 1029 length = 0; 1030 else if (sscanf(buffer + regs.start[i], "'%s'", current) > 0) { 1031 if (current[0] == '\\') 1032 current[0] = current[1]; 1033 else if (current[0] == '\'') 1034 current[0] = ' '; 1035 length = 1; 1036 } else if (sscanf(buffer + regs.start[i], "0x%s", hexChars) > 0) { 1037 length = strlen(hexChars) / 2; 1038 for (uint32 j = 0; j < length; j++) 1039 sscanf(hexChars + 2*j, "%02hhx", current + j); 1040 } 1041 1042 fChars[offset] = length; 1043 offset += length + 1; 1044 } 1045 1046 1047 void 1048 Keymap::_ComputeTables(const char* buffer, struct re_registers& regs, 1049 uint32& table) 1050 { 1051 for (int32 i = 1; i <= 9; i++) { 1052 int32 length = regs.end[i] - regs.start[i]; 1053 if (length <= 0) 1054 break; 1055 1056 const char* start = buffer + regs.start[i]; 1057 1058 if (strncmp(start, "Normal", length) == 0) 1059 table |= B_NORMAL_TABLE; 1060 else if (strncmp(start, "Shift", length) == 0) 1061 table |= B_SHIFT_TABLE; 1062 else if (strncmp(start, "Control", length) == 0) 1063 table |= B_CONTROL_TABLE; 1064 else if (strncmp(start, "Option", length) == 0) 1065 table |= B_OPTION_TABLE; 1066 else if (strncmp(start, "Option-Shift", length) == 0) 1067 table |= B_OPTION_SHIFT_TABLE; 1068 else if (strncmp(start, "CapsLock", length) == 0) 1069 table |= B_CAPS_TABLE; 1070 else if (strncmp(start, "CapsLock-Shift", length) == 0) 1071 table |= B_CAPS_SHIFT_TABLE; 1072 else if (strncmp(start, "CapsLock-Option", length) == 0) 1073 table |= B_OPTION_CAPS_TABLE; 1074 else if (strncmp(start, "CapsLock-Option-Shift", length) == 0) 1075 table |= B_OPTION_CAPS_SHIFT_TABLE; 1076 } 1077 } 1078