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