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