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