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