1 /* 2 * Copyright 2004-2006, Haiku, Inc. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Jérôme Duval 7 */ 8 9 10 #include "Keymap.h" 11 12 #include <ByteOrder.h> 13 #include <File.h> 14 #include <InputServerTypes.h> 15 #include <Message.h> 16 #include <input_globals.h> 17 18 #include <new> 19 #include <stdlib.h> 20 #include <stdio.h> 21 #include <string.h> 22 23 24 static void 25 print_key(char *chars, int32 offset) 26 { 27 int size = chars[offset++]; 28 29 switch (size) { 30 case 0: 31 // Not mapped 32 printf("N/A"); 33 break; 34 35 case 1: 36 // 1-byte UTF-8/ASCII character 37 printf("%c", chars[offset]); 38 break; 39 40 default: 41 { 42 // 2-, 3-, or 4-byte UTF-8 character 43 char *str = new (std::nothrow) char[size + 1]; 44 if (str == NULL) 45 break; 46 47 strncpy(str, &(chars[offset]), size); 48 str[size] = 0; 49 printf("%s", str); 50 delete [] str; 51 break; 52 } 53 } 54 55 printf("\t"); 56 } 57 58 59 // #pragma mark - 60 61 62 void 63 Keymap::DumpKeymap() 64 { 65 // Print a chart of the normal, shift, option, and option+shift 66 // keys. 67 printf("Key #\tNormal\tShift\tCaps\tC+S\tOption\tO+S\tO+C\tO+C+S\tControl\n"); 68 69 for (int i = 0; i < 128; i++) { 70 printf(" 0x%x\t", i); 71 print_key(fChars, fKeys.normal_map[i]); 72 print_key(fChars, fKeys.shift_map[i]); 73 print_key(fChars, fKeys.caps_map[i]); 74 print_key(fChars, fKeys.caps_shift_map[i]); 75 print_key(fChars, fKeys.option_map[i]); 76 print_key(fChars, fKeys.option_shift_map[i]); 77 print_key(fChars, fKeys.option_caps_map[i]); 78 print_key(fChars, fKeys.option_caps_shift_map[i]); 79 print_key(fChars, fKeys.control_map[i]); 80 printf("\n"); 81 } 82 } 83 84 85 Keymap::Keymap() 86 : 87 fChars(NULL) 88 { 89 key_map *keys; 90 _get_key_map(&keys, &fChars, &fCharsSize); 91 92 if (keys) { 93 memcpy(&fKeys, keys, sizeof(key_map)); 94 free(keys); 95 } 96 } 97 98 99 Keymap::~Keymap() 100 { 101 free(fChars); 102 } 103 104 105 /* we need to know if a key is a modifier key to choose 106 a valid key when several are pressed together 107 */ 108 bool 109 Keymap::IsModifierKey(uint32 keyCode) 110 { 111 return keyCode == fKeys.caps_key 112 || keyCode == fKeys.num_key 113 || keyCode == fKeys.scroll_key 114 || keyCode == fKeys.left_shift_key 115 || keyCode == fKeys.right_shift_key 116 || keyCode == fKeys.left_command_key 117 || keyCode == fKeys.right_command_key 118 || keyCode == fKeys.left_control_key 119 || keyCode == fKeys.right_control_key 120 || keyCode == fKeys.left_option_key 121 || keyCode == fKeys.right_option_key 122 || keyCode == fKeys.menu_key; 123 } 124 125 126 //! We need to know a modifier for a key 127 uint32 128 Keymap::Modifier(uint32 keyCode) 129 { 130 if (keyCode == fKeys.caps_key) 131 return B_CAPS_LOCK; 132 if (keyCode == fKeys.num_key) 133 return B_NUM_LOCK; 134 if (keyCode == fKeys.scroll_key) 135 return B_SCROLL_LOCK; 136 if (keyCode == fKeys.left_shift_key) 137 return B_LEFT_SHIFT_KEY | B_SHIFT_KEY; 138 if (keyCode == fKeys.right_shift_key) 139 return B_RIGHT_SHIFT_KEY | B_SHIFT_KEY; 140 if (keyCode == fKeys.left_command_key) 141 return B_LEFT_COMMAND_KEY | B_COMMAND_KEY; 142 if (keyCode == fKeys.right_command_key) 143 return B_RIGHT_COMMAND_KEY | B_COMMAND_KEY; 144 if (keyCode == fKeys.left_control_key) 145 return B_LEFT_CONTROL_KEY | B_CONTROL_KEY; 146 if (keyCode == fKeys.right_control_key) 147 return B_RIGHT_CONTROL_KEY | B_CONTROL_KEY; 148 if (keyCode == fKeys.left_option_key) 149 return B_LEFT_OPTION_KEY | B_OPTION_KEY; 150 if (keyCode == fKeys.right_option_key) 151 return B_RIGHT_OPTION_KEY | B_OPTION_KEY; 152 if (keyCode == fKeys.menu_key) 153 return B_MENU_KEY; 154 155 return 0; 156 } 157 158 159 uint32 160 Keymap::KeyForModifier(uint32 modifier) 161 { 162 if (modifier == B_CAPS_LOCK) 163 return fKeys.caps_key; 164 if (modifier == B_NUM_LOCK) 165 return fKeys.num_key; 166 if (modifier == B_SCROLL_LOCK) 167 return fKeys.scroll_key; 168 if (modifier == B_LEFT_SHIFT_KEY || modifier == B_SHIFT_KEY) 169 return fKeys.left_shift_key; 170 if (modifier == B_RIGHT_SHIFT_KEY) 171 return fKeys.right_shift_key; 172 if (modifier == B_LEFT_COMMAND_KEY || modifier == B_COMMAND_KEY) 173 return fKeys.left_command_key; 174 if (modifier == B_RIGHT_COMMAND_KEY) 175 return fKeys.right_command_key; 176 if (modifier == B_LEFT_CONTROL_KEY || modifier == B_CONTROL_KEY) 177 return fKeys.left_control_key; 178 if (modifier == B_RIGHT_CONTROL_KEY) 179 return fKeys.right_control_key; 180 if (modifier == B_LEFT_OPTION_KEY || modifier == B_OPTION_KEY) 181 return fKeys.left_option_key; 182 if (modifier == B_RIGHT_OPTION_KEY) 183 return fKeys.right_option_key; 184 if (modifier == B_MENU_KEY) 185 return fKeys.menu_key; 186 187 return 0; 188 } 189 190 191 //! Tell if a key is a dead key, needed for draw a dead key 192 uint8 193 Keymap::IsDeadKey(uint32 keyCode, uint32 modifiers) 194 { 195 if (keyCode >= 256) 196 return 0; 197 198 int32 offset; 199 uint32 tableMask = 0; 200 201 switch (modifiers & 0xcf) { 202 case B_SHIFT_KEY: offset = fKeys.shift_map[keyCode]; tableMask = B_SHIFT_TABLE; break; 203 case B_CAPS_LOCK: offset = fKeys.caps_map[keyCode]; tableMask = B_CAPS_TABLE; break; 204 case B_CAPS_LOCK|B_SHIFT_KEY: offset = fKeys.caps_shift_map[keyCode]; tableMask = B_CAPS_SHIFT_TABLE; break; 205 case B_OPTION_KEY: offset = fKeys.option_map[keyCode]; tableMask = B_OPTION_TABLE; break; 206 case B_OPTION_KEY|B_SHIFT_KEY: offset = fKeys.option_shift_map[keyCode]; tableMask = B_OPTION_SHIFT_TABLE; break; 207 case B_OPTION_KEY|B_CAPS_LOCK: offset = fKeys.option_caps_map[keyCode]; tableMask = B_OPTION_CAPS_TABLE; break; 208 case B_OPTION_KEY|B_SHIFT_KEY|B_CAPS_LOCK: offset = fKeys.option_caps_shift_map[keyCode]; tableMask = B_OPTION_CAPS_SHIFT_TABLE; break; 209 case B_CONTROL_KEY: offset = fKeys.control_map[keyCode]; tableMask = B_CONTROL_TABLE; break; 210 default: offset = fKeys.normal_map[keyCode]; tableMask = B_NORMAL_TABLE; break; 211 } 212 213 if (offset <= 0 || offset > fCharsSize) 214 return 0; 215 216 uint32 numBytes = fChars[offset]; 217 if (!numBytes) 218 return 0; 219 220 char chars[4]; 221 strncpy(chars, &(fChars[offset+1]), numBytes ); 222 chars[numBytes] = 0; 223 224 int32 deadOffsets[] = { 225 fKeys.acute_dead_key[1], 226 fKeys.grave_dead_key[1], 227 fKeys.circumflex_dead_key[1], 228 fKeys.dieresis_dead_key[1], 229 fKeys.tilde_dead_key[1] 230 }; 231 232 uint32 deadTables[] = { 233 fKeys.acute_tables, 234 fKeys.grave_tables, 235 fKeys.circumflex_tables, 236 fKeys.dieresis_tables, 237 fKeys.tilde_tables 238 }; 239 240 for (int32 i = 0; i < 5; i++) { 241 if ((deadTables[i] & tableMask) == 0) 242 continue; 243 244 if (offset == deadOffsets[i]) 245 return i + 1; 246 247 uint32 deadNumBytes = fChars[deadOffsets[i]]; 248 if (!deadNumBytes) 249 continue; 250 251 if (!strncmp(chars, &(fChars[deadOffsets[i] + 1]), deadNumBytes)) 252 return i + 1; 253 } 254 return 0; 255 } 256 257 258 //! Tell if a key is a dead second key, needed for draw a dead second key 259 bool 260 Keymap::IsDeadSecondKey(uint32 keyCode, uint32 modifiers, uint8 activeDeadKey) 261 { 262 if (!activeDeadKey || keyCode >= 256) 263 return false; 264 265 int32 offset; 266 267 switch (modifiers & 0xcf) { 268 case B_SHIFT_KEY: offset = fKeys.shift_map[keyCode]; break; 269 case B_CAPS_LOCK: offset = fKeys.caps_map[keyCode]; break; 270 case B_CAPS_LOCK|B_SHIFT_KEY: offset = fKeys.caps_shift_map[keyCode]; break; 271 case B_OPTION_KEY: offset = fKeys.option_map[keyCode]; break; 272 case B_OPTION_KEY|B_SHIFT_KEY: offset = fKeys.option_shift_map[keyCode]; break; 273 case B_OPTION_KEY|B_CAPS_LOCK: offset = fKeys.option_caps_map[keyCode]; break; 274 case B_OPTION_KEY|B_SHIFT_KEY|B_CAPS_LOCK: offset = fKeys.option_caps_shift_map[keyCode]; break; 275 case B_CONTROL_KEY: offset = fKeys.control_map[keyCode]; break; 276 default: offset = fKeys.normal_map[keyCode]; break; 277 } 278 279 if (offset <= 0 || offset > fCharsSize) 280 return false; 281 282 uint32 numBytes = fChars[offset]; 283 if (!numBytes) 284 return false; 285 286 int32* deadOffsets[] = { 287 fKeys.acute_dead_key, 288 fKeys.grave_dead_key, 289 fKeys.circumflex_dead_key, 290 fKeys.dieresis_dead_key, 291 fKeys.tilde_dead_key 292 }; 293 294 int32 *deadOffset = deadOffsets[activeDeadKey-1]; 295 296 for (int32 i=0; i<32; i++) { 297 if (offset == deadOffset[i]) 298 return true; 299 300 uint32 deadNumBytes = fChars[deadOffset[i]]; 301 if (!deadNumBytes) 302 continue; 303 304 if (!strncmp(&(fChars[offset+1]), &(fChars[deadOffset[i]+1]), deadNumBytes)) 305 return true; 306 307 i++; 308 } 309 310 return false; 311 } 312 313 314 //! Get the char for a key given modifiers and active dead key 315 void 316 Keymap::GetChars(uint32 keyCode, uint32 modifiers, uint8 activeDeadKey, 317 char** chars, int32* numBytes) 318 { 319 *numBytes = 0; 320 *chars = NULL; 321 322 if (keyCode >= 256) 323 return; 324 325 // here we take NUMLOCK into account 326 if (modifiers & B_NUM_LOCK) { 327 switch (keyCode) { 328 case 0x37: 329 case 0x38: 330 case 0x39: 331 case 0x48: 332 case 0x49: 333 case 0x4a: 334 case 0x58: 335 case 0x59: 336 case 0x5a: 337 case 0x64: 338 case 0x65: 339 modifiers ^= B_SHIFT_KEY; 340 break; 341 } 342 } 343 344 int32 offset; 345 346 // here we choose the right map given the modifiers 347 switch (modifiers & 0xcf) { 348 case B_SHIFT_KEY: offset = fKeys.shift_map[keyCode]; break; 349 case B_CAPS_LOCK: offset = fKeys.caps_map[keyCode]; break; 350 case B_CAPS_LOCK|B_SHIFT_KEY: offset = fKeys.caps_shift_map[keyCode]; break; 351 case B_OPTION_KEY: offset = fKeys.option_map[keyCode]; break; 352 case B_OPTION_KEY|B_SHIFT_KEY: offset = fKeys.option_shift_map[keyCode]; break; 353 case B_OPTION_KEY|B_CAPS_LOCK: offset = fKeys.option_caps_map[keyCode]; break; 354 case B_OPTION_KEY|B_SHIFT_KEY|B_CAPS_LOCK: offset = fKeys.option_caps_shift_map[keyCode]; break; 355 case B_CONTROL_KEY: offset = fKeys.control_map[keyCode]; break; 356 357 default: 358 offset = fKeys.normal_map[keyCode]; 359 break; 360 } 361 362 if (offset <= 0) 363 return; 364 365 // here we get the char size 366 *numBytes = fChars[offset]; 367 if (!*numBytes) 368 return; 369 370 // here we take an potential active dead key 371 int32 *deadKey; 372 switch (activeDeadKey) { 373 case 1: deadKey = fKeys.acute_dead_key; break; 374 case 2: deadKey = fKeys.grave_dead_key; break; 375 case 3: deadKey = fKeys.circumflex_dead_key; break; 376 case 4: deadKey = fKeys.dieresis_dead_key; break; 377 case 5: deadKey = fKeys.tilde_dead_key; break; 378 default: 379 { 380 // if not dead, we copy and return the char 381 char *str = *chars = new (std::nothrow) char[*numBytes + 1]; 382 if (str == NULL) { 383 *numBytes = 0; 384 return; 385 } 386 strncpy(str, &(fChars[offset + 1]), *numBytes); 387 str[*numBytes] = 0; 388 return; 389 } 390 } 391 392 // if dead key, we search for our current offset char in the dead key offset table 393 // string comparison is needed 394 for (int32 i = 0; i < 32; i++) { 395 if (strncmp(&(fChars[offset + 1]), &(fChars[deadKey[i] + 1]), *numBytes) == 0) { 396 *numBytes = fChars[deadKey[i + 1]]; 397 398 switch (*numBytes) { 399 case 0: 400 // Not mapped 401 *chars = NULL; 402 break; 403 default: 404 { 405 // 1-, 2-, 3-, or 4-byte UTF-8 character 406 char *str = *chars = new (std::nothrow) char[*numBytes + 1]; 407 if (str == NULL) { 408 *numBytes = 0; 409 return; 410 } 411 strncpy(str, &fChars[deadKey[i + 1] + 1], *numBytes); 412 str[*numBytes] = 0; 413 break; 414 } 415 } 416 return; 417 } 418 i++; 419 } 420 421 // if not found we return the whole sequence (the dead key itself plus 422 // the following char) 423 int32 deadKeyNumBytes = fChars[deadKey[1]]; 424 int32 fullNumBytes = deadKeyNumBytes + *numBytes; 425 *chars = new (std::nothrow) char[fullNumBytes + 1]; 426 if (*chars == NULL) { 427 *numBytes = 0; 428 return; 429 } 430 strncpy(*chars, &fChars[deadKey[1] + 1], deadKeyNumBytes); 431 strncpy(*chars + deadKeyNumBytes, &fChars[offset + 1], *numBytes); 432 *numBytes = fullNumBytes; 433 (*chars)[fullNumBytes] = 0; 434 } 435 436 437 status_t 438 Keymap::LoadCurrent() 439 { 440 key_map *keys = NULL; 441 free(fChars); 442 fChars = NULL; 443 444 _get_key_map(&keys, &fChars, &fCharsSize); 445 if (!keys) { 446 fprintf(stderr, "error while getting current keymap!\n"); 447 return B_ERROR; 448 } 449 memcpy(&fKeys, keys, sizeof(fKeys)); 450 free(keys); 451 return B_OK; 452 } 453 454