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