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