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 uint32 159 Keymap::KeyForModifier(uint32 modifier) 160 { 161 if (modifier == B_LEFT_COMMAND_KEY) 162 return fKeys.left_command_key; 163 if (modifier == B_RIGHT_COMMAND_KEY) 164 return fKeys.right_command_key; 165 if (modifier == B_LEFT_CONTROL_KEY) 166 return fKeys.left_control_key; 167 if (modifier == B_RIGHT_CONTROL_KEY) 168 return fKeys.right_control_key; 169 170 return 0; 171 } 172 173 //! Tell if a key is a dead key, needed for draw a dead key 174 uint8 175 Keymap::IsDeadKey(uint32 keyCode, uint32 modifiers) 176 { 177 if (keyCode >= 256) 178 return 0; 179 180 int32 offset; 181 uint32 tableMask = 0; 182 183 switch (modifiers & 0xcf) { 184 case B_SHIFT_KEY: offset = fKeys.shift_map[keyCode]; tableMask = B_SHIFT_TABLE; break; 185 case B_CAPS_LOCK: offset = fKeys.caps_map[keyCode]; tableMask = B_CAPS_TABLE; break; 186 case B_CAPS_LOCK|B_SHIFT_KEY: offset = fKeys.caps_shift_map[keyCode]; tableMask = B_CAPS_SHIFT_TABLE; break; 187 case B_OPTION_KEY: offset = fKeys.option_map[keyCode]; tableMask = B_OPTION_TABLE; break; 188 case B_OPTION_KEY|B_SHIFT_KEY: offset = fKeys.option_shift_map[keyCode]; tableMask = B_OPTION_SHIFT_TABLE; break; 189 case B_OPTION_KEY|B_CAPS_LOCK: offset = fKeys.option_caps_map[keyCode]; tableMask = B_OPTION_CAPS_TABLE; break; 190 case B_OPTION_KEY|B_SHIFT_KEY|B_CAPS_LOCK: offset = fKeys.option_caps_shift_map[keyCode]; tableMask = B_OPTION_CAPS_SHIFT_TABLE; break; 191 case B_CONTROL_KEY: offset = fKeys.control_map[keyCode]; tableMask = B_CONTROL_TABLE; break; 192 default: offset = fKeys.normal_map[keyCode]; tableMask = B_NORMAL_TABLE; break; 193 } 194 195 if (offset <= 0 || offset > fCharsSize) 196 return 0; 197 198 uint32 numBytes = fChars[offset]; 199 if (!numBytes) 200 return 0; 201 202 char chars[4]; 203 strncpy(chars, &(fChars[offset+1]), numBytes ); 204 chars[numBytes] = 0; 205 206 int32 deadOffsets[] = { 207 fKeys.acute_dead_key[1], 208 fKeys.grave_dead_key[1], 209 fKeys.circumflex_dead_key[1], 210 fKeys.dieresis_dead_key[1], 211 fKeys.tilde_dead_key[1] 212 }; 213 214 uint32 deadTables[] = { 215 fKeys.acute_tables, 216 fKeys.grave_tables, 217 fKeys.circumflex_tables, 218 fKeys.dieresis_tables, 219 fKeys.tilde_tables 220 }; 221 222 for (int32 i = 0; i < 5; i++) { 223 if ((deadTables[i] & tableMask) == 0) 224 continue; 225 226 if (offset == deadOffsets[i]) 227 return i + 1; 228 229 uint32 deadNumBytes = fChars[deadOffsets[i]]; 230 if (!deadNumBytes) 231 continue; 232 233 if (!strncmp(chars, &(fChars[deadOffsets[i] + 1]), deadNumBytes)) 234 return i + 1; 235 } 236 return 0; 237 } 238 239 240 //! Tell if a key is a dead second key, needed for draw a dead second key 241 bool 242 Keymap::IsDeadSecondKey(uint32 keyCode, uint32 modifiers, uint8 activeDeadKey) 243 { 244 if (!activeDeadKey || keyCode >= 256) 245 return false; 246 247 int32 offset; 248 249 switch (modifiers & 0xcf) { 250 case B_SHIFT_KEY: offset = fKeys.shift_map[keyCode]; break; 251 case B_CAPS_LOCK: offset = fKeys.caps_map[keyCode]; break; 252 case B_CAPS_LOCK|B_SHIFT_KEY: offset = fKeys.caps_shift_map[keyCode]; break; 253 case B_OPTION_KEY: offset = fKeys.option_map[keyCode]; break; 254 case B_OPTION_KEY|B_SHIFT_KEY: offset = fKeys.option_shift_map[keyCode]; break; 255 case B_OPTION_KEY|B_CAPS_LOCK: offset = fKeys.option_caps_map[keyCode]; break; 256 case B_OPTION_KEY|B_SHIFT_KEY|B_CAPS_LOCK: offset = fKeys.option_caps_shift_map[keyCode]; break; 257 case B_CONTROL_KEY: offset = fKeys.control_map[keyCode]; break; 258 default: offset = fKeys.normal_map[keyCode]; break; 259 } 260 261 if (offset <= 0 || offset > fCharsSize) 262 return false; 263 264 uint32 numBytes = fChars[offset]; 265 if (!numBytes) 266 return false; 267 268 int32* deadOffsets[] = { 269 fKeys.acute_dead_key, 270 fKeys.grave_dead_key, 271 fKeys.circumflex_dead_key, 272 fKeys.dieresis_dead_key, 273 fKeys.tilde_dead_key 274 }; 275 276 int32 *deadOffset = deadOffsets[activeDeadKey-1]; 277 278 for (int32 i=0; i<32; i++) { 279 if (offset == deadOffset[i]) 280 return true; 281 282 uint32 deadNumBytes = fChars[deadOffset[i]]; 283 if (!deadNumBytes) 284 continue; 285 286 if (!strncmp(&(fChars[offset+1]), &(fChars[deadOffset[i]+1]), deadNumBytes)) 287 return true; 288 289 i++; 290 } 291 292 return false; 293 } 294 295 296 //! Get the char for a key given modifiers and active dead key 297 void 298 Keymap::GetChars(uint32 keyCode, uint32 modifiers, uint8 activeDeadKey, 299 char** chars, int32* numBytes) 300 { 301 *numBytes = 0; 302 *chars = NULL; 303 304 if (keyCode >= 256) 305 return; 306 307 // here we take NUMLOCK into account 308 if (modifiers & B_NUM_LOCK) { 309 switch (keyCode) { 310 case 0x37: 311 case 0x38: 312 case 0x39: 313 case 0x48: 314 case 0x49: 315 case 0x4a: 316 case 0x58: 317 case 0x59: 318 case 0x5a: 319 case 0x64: 320 case 0x65: 321 modifiers ^= B_SHIFT_KEY; 322 break; 323 } 324 } 325 326 int32 offset; 327 328 // here we choose the right map given the modifiers 329 switch (modifiers & 0xcf) { 330 case B_SHIFT_KEY: offset = fKeys.shift_map[keyCode]; break; 331 case B_CAPS_LOCK: offset = fKeys.caps_map[keyCode]; break; 332 case B_CAPS_LOCK|B_SHIFT_KEY: offset = fKeys.caps_shift_map[keyCode]; break; 333 case B_OPTION_KEY: offset = fKeys.option_map[keyCode]; break; 334 case B_OPTION_KEY|B_SHIFT_KEY: offset = fKeys.option_shift_map[keyCode]; break; 335 case B_OPTION_KEY|B_CAPS_LOCK: offset = fKeys.option_caps_map[keyCode]; break; 336 case B_OPTION_KEY|B_SHIFT_KEY|B_CAPS_LOCK: offset = fKeys.option_caps_shift_map[keyCode]; break; 337 case B_CONTROL_KEY: offset = fKeys.control_map[keyCode]; break; 338 339 default: 340 offset = fKeys.normal_map[keyCode]; 341 break; 342 } 343 344 if (offset <= 0) 345 return; 346 347 // here we get the char size 348 *numBytes = fChars[offset]; 349 if (!*numBytes) 350 return; 351 352 // here we take an potential active dead key 353 int32 *deadKey; 354 switch (activeDeadKey) { 355 case 1: deadKey = fKeys.acute_dead_key; break; 356 case 2: deadKey = fKeys.grave_dead_key; break; 357 case 3: deadKey = fKeys.circumflex_dead_key; break; 358 case 4: deadKey = fKeys.dieresis_dead_key; break; 359 case 5: deadKey = fKeys.tilde_dead_key; break; 360 default: 361 { 362 // if not dead, we copy and return the char 363 char *str = *chars = new (std::nothrow) char[*numBytes + 1]; 364 if (str == NULL) { 365 *numBytes = 0; 366 return; 367 } 368 strncpy(str, &(fChars[offset + 1]), *numBytes); 369 str[*numBytes] = 0; 370 return; 371 } 372 } 373 374 // if dead key, we search for our current offset char in the dead key offset table 375 // string comparison is needed 376 for (int32 i = 0; i < 32; i++) { 377 if (strncmp(&(fChars[offset + 1]), &(fChars[deadKey[i] + 1]), *numBytes) == 0) { 378 *numBytes = fChars[deadKey[i + 1]]; 379 380 switch (*numBytes) { 381 case 0: 382 // Not mapped 383 *chars = NULL; 384 break; 385 default: 386 { 387 // 1-, 2-, 3-, or 4-byte UTF-8 character 388 char *str = *chars = new (std::nothrow) char[*numBytes + 1]; 389 if (str == NULL) { 390 *numBytes = 0; 391 return; 392 } 393 strncpy(str, &fChars[deadKey[i + 1] + 1], *numBytes); 394 str[*numBytes] = 0; 395 break; 396 } 397 } 398 return; 399 } 400 i++; 401 } 402 403 // if not found we return the current char mapped 404 *chars = new (std::nothrow) char[*numBytes + 1]; 405 if (*chars == NULL) { 406 *numBytes = 0; 407 return; 408 } 409 410 strncpy(*chars, &(fChars[offset + 1]), *numBytes ); 411 (*chars)[*numBytes] = 0; 412 } 413 414 415 status_t 416 Keymap::LoadCurrent() 417 { 418 key_map *keys = NULL; 419 free(fChars); 420 fChars = NULL; 421 422 _get_key_map(&keys, &fChars, &fCharsSize); 423 if (!keys) { 424 fprintf(stderr, "error while getting current keymap!\n"); 425 return B_ERROR; 426 } 427 memcpy(&fKeys, keys, sizeof(fKeys)); 428 free(keys); 429 return B_OK; 430 } 431 432