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.cpp 10 // Author: Sandor Vroemisse, Jérôme Duval 11 // Description: Keymap Preferences 12 // Created : July 12, 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 #include <input_globals.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 /* 79 file format in big endian : 80 struct key_map 81 uint32 size of following charset 82 charset (offsets go into this with size of character followed by character) 83 */ 84 // we load a map from a file 85 status_t 86 Keymap::Load(entry_ref &ref) 87 { 88 status_t err; 89 BEntry entry(&ref, true); 90 if ((err = entry.InitCheck()) != B_OK) { 91 fprintf(stderr, "error loading keymap: %s\n", strerror(err)); 92 return err; 93 } 94 95 BFile file(&entry, B_READ_ONLY); 96 if ((err = file.InitCheck()) != B_OK) { 97 fprintf(stderr, "error loading keymap: %s\n", strerror(err)); 98 return err; 99 } 100 101 if ((err = file.Read(&fKeys, sizeof(fKeys))) < (ssize_t)sizeof(fKeys)) { 102 fprintf(stderr, "error reading keymap keys: %s\n", strerror(err)); 103 return B_BAD_VALUE; 104 } 105 106 for (uint32 i=0; i<sizeof(fKeys)/4; i++) 107 ((uint32*)&fKeys)[i] = B_BENDIAN_TO_HOST_INT32(((uint32*)&fKeys)[i]); 108 109 if ((err = file.Read(&fCharsSize, sizeof(uint32))) < (ssize_t)sizeof(uint32)) { 110 fprintf(stderr, "error reading keymap size: %s\n", strerror(err)); 111 return B_BAD_VALUE; 112 } 113 114 fCharsSize = B_BENDIAN_TO_HOST_INT32(fCharsSize); 115 if (!fChars) 116 delete[] fChars; 117 fChars = new char[fCharsSize]; 118 err = file.Read(fChars, fCharsSize); 119 if (err < B_OK) { 120 fprintf(stderr, "error reading keymap chars: %s\n", strerror(err)); 121 } 122 return err; 123 } 124 125 126 // we save a map from a file 127 status_t 128 Keymap::Save(entry_ref &ref) 129 { 130 status_t err; 131 132 BFile file(&ref, B_WRITE_ONLY | B_CREATE_FILE | B_ERASE_FILE ); 133 if ((err = file.InitCheck()) != B_OK) { 134 printf("error %s\n", strerror(err)); 135 return err; 136 } 137 138 for (uint32 i=0; i<sizeof(fKeys)/4; i++) 139 ((uint32*)&fKeys)[i] = B_HOST_TO_BENDIAN_INT32(((uint32*)&fKeys)[i]); 140 141 if ((err = file.Write(&fKeys, sizeof(fKeys))) < (ssize_t)sizeof(fKeys)) { 142 return err; 143 } 144 145 for (uint32 i=0; i<sizeof(fKeys)/4; i++) 146 ((uint32*)&fKeys)[i] = B_BENDIAN_TO_HOST_INT32(((uint32*)&fKeys)[i]); 147 148 fCharsSize = B_HOST_TO_BENDIAN_INT32(fCharsSize); 149 150 if ((err = file.Write(&fCharsSize, sizeof(uint32))) < (ssize_t)sizeof(uint32)) { 151 return B_BAD_VALUE; 152 } 153 154 fCharsSize = B_BENDIAN_TO_HOST_INT32(fCharsSize); 155 156 if ((err = file.Write(fChars, fCharsSize)) < (ssize_t)fCharsSize) 157 return err; 158 159 return B_OK; 160 } 161 162 163 /* we need to know if a key is a modifier key to choose 164 a valid key when several are pressed together 165 */ 166 bool 167 Keymap::IsModifierKey(uint32 keyCode) 168 { 169 if ((keyCode == fKeys.caps_key) 170 || (keyCode == fKeys.num_key) 171 || (keyCode == fKeys.scroll_key) 172 || (keyCode == fKeys.left_shift_key) 173 || (keyCode == fKeys.right_shift_key) 174 || (keyCode == fKeys.left_command_key) 175 || (keyCode == fKeys.right_command_key) 176 || (keyCode == fKeys.left_control_key) 177 || (keyCode == fKeys.right_control_key) 178 || (keyCode == fKeys.left_option_key) 179 || (keyCode == fKeys.right_option_key) 180 || (keyCode == fKeys.menu_key)) 181 return true; 182 return false; 183 } 184 185 186 // tell if a key is a dead key, needed for draw a dead key 187 uint8 188 Keymap::IsDeadKey(uint32 keyCode, uint32 modifiers) 189 { 190 int32 offset; 191 uint32 tableMask = 0; 192 193 switch (modifiers & 0xcf) { 194 case B_SHIFT_KEY: offset = fKeys.shift_map[keyCode]; tableMask = B_SHIFT_TABLE; break; 195 case B_CAPS_LOCK: offset = fKeys.caps_map[keyCode]; tableMask = B_CAPS_TABLE; break; 196 case B_CAPS_LOCK|B_SHIFT_KEY: offset = fKeys.caps_shift_map[keyCode]; tableMask = B_CAPS_SHIFT_TABLE; break; 197 case B_OPTION_KEY: offset = fKeys.option_map[keyCode]; tableMask = B_OPTION_TABLE; break; 198 case B_OPTION_KEY|B_SHIFT_KEY: offset = fKeys.option_shift_map[keyCode]; tableMask = B_OPTION_SHIFT_TABLE; break; 199 case B_OPTION_KEY|B_CAPS_LOCK: offset = fKeys.option_caps_map[keyCode]; tableMask = B_OPTION_CAPS_TABLE; break; 200 case B_OPTION_KEY|B_SHIFT_KEY|B_CAPS_LOCK: offset = fKeys.option_caps_shift_map[keyCode]; tableMask = B_OPTION_CAPS_SHIFT_TABLE; break; 201 case B_CONTROL_KEY: offset = fKeys.control_map[keyCode]; tableMask = B_CONTROL_TABLE; break; 202 default: offset = fKeys.normal_map[keyCode]; tableMask = B_NORMAL_TABLE; break; 203 } 204 205 if (offset<=0) 206 return 0; 207 uint32 numBytes = fChars[offset]; 208 209 if (!numBytes) 210 return 0; 211 212 char chars[4]; 213 strncpy(chars, &(fChars[offset+1]), numBytes ); 214 chars[numBytes] = 0; 215 216 int32 deadOffsets[] = { 217 fKeys.acute_dead_key[1], 218 fKeys.grave_dead_key[1], 219 fKeys.circumflex_dead_key[1], 220 fKeys.dieresis_dead_key[1], 221 fKeys.tilde_dead_key[1] 222 }; 223 224 uint32 deadTables[] = { 225 fKeys.acute_tables, 226 fKeys.grave_tables, 227 fKeys.circumflex_tables, 228 fKeys.dieresis_tables, 229 fKeys.tilde_tables 230 }; 231 232 for (int32 i=0; i<5; i++) { 233 if ((deadTables[i] & tableMask) == 0) 234 continue; 235 236 if (offset == deadOffsets[i]) 237 return i+1; 238 239 uint32 deadNumBytes = fChars[deadOffsets[i]]; 240 241 if (!deadNumBytes) 242 continue; 243 244 if (strncmp(chars, &(fChars[deadOffsets[i]+1]), deadNumBytes ) == 0) { 245 return i+1; 246 } 247 } 248 return 0; 249 } 250 251 252 // tell if a key is a dead second key, needed for draw a dead second key 253 bool 254 Keymap::IsDeadSecondKey(uint32 keyCode, uint32 modifiers, uint8 activeDeadKey) 255 { 256 if (!activeDeadKey) 257 return false; 258 259 int32 offset; 260 261 switch (modifiers & 0xcf) { 262 case B_SHIFT_KEY: offset = fKeys.shift_map[keyCode]; break; 263 case B_CAPS_LOCK: offset = fKeys.caps_map[keyCode]; break; 264 case B_CAPS_LOCK|B_SHIFT_KEY: offset = fKeys.caps_shift_map[keyCode]; break; 265 case B_OPTION_KEY: offset = fKeys.option_map[keyCode]; break; 266 case B_OPTION_KEY|B_SHIFT_KEY: offset = fKeys.option_shift_map[keyCode]; break; 267 case B_OPTION_KEY|B_CAPS_LOCK: offset = fKeys.option_caps_map[keyCode]; break; 268 case B_OPTION_KEY|B_SHIFT_KEY|B_CAPS_LOCK: offset = fKeys.option_caps_shift_map[keyCode]; break; 269 case B_CONTROL_KEY: offset = fKeys.control_map[keyCode]; break; 270 default: offset = fKeys.normal_map[keyCode]; break; 271 } 272 273 uint32 numBytes = fChars[offset]; 274 275 if (!numBytes) 276 return false; 277 278 int32* deadOffsets[] = { 279 fKeys.acute_dead_key, 280 fKeys.grave_dead_key, 281 fKeys.circumflex_dead_key, 282 fKeys.dieresis_dead_key, 283 fKeys.tilde_dead_key 284 }; 285 286 int32 *deadOffset = deadOffsets[activeDeadKey-1]; 287 288 for (int32 i=0; i<32; i++) { 289 if (offset == deadOffset[i]) 290 return true; 291 292 uint32 deadNumBytes = fChars[deadOffset[i]]; 293 294 if (!deadNumBytes) 295 continue; 296 297 if (strncmp(&(fChars[offset+1]), &(fChars[deadOffset[i]+1]), deadNumBytes ) == 0) 298 return true; 299 i++; 300 } 301 return false; 302 } 303 304 305 // get the char for a key given modifiers and active dead key 306 void 307 Keymap::GetChars(uint32 keyCode, uint32 modifiers, uint8 activeDeadKey, char** chars, int32* numBytes) 308 { 309 int32 offset; 310 311 *numBytes = 0; 312 *chars = NULL; 313 314 // here we take NUMLOCK into account 315 if (modifiers & B_NUM_LOCK) 316 switch (keyCode) { 317 case 0x37: 318 case 0x38: 319 case 0x39: 320 case 0x48: 321 case 0x49: 322 case 0x4a: 323 case 0x58: 324 case 0x59: 325 case 0x5a: 326 case 0x64: 327 case 0x65: 328 modifiers ^= B_SHIFT_KEY; 329 } 330 331 // here we choose the right map given the modifiers 332 switch (modifiers & 0xcf) { 333 case B_SHIFT_KEY: offset = fKeys.shift_map[keyCode]; break; 334 case B_CAPS_LOCK: offset = fKeys.caps_map[keyCode]; break; 335 case B_CAPS_LOCK|B_SHIFT_KEY: offset = fKeys.caps_shift_map[keyCode]; break; 336 case B_OPTION_KEY: offset = fKeys.option_map[keyCode]; break; 337 case B_OPTION_KEY|B_SHIFT_KEY: offset = fKeys.option_shift_map[keyCode]; break; 338 case B_OPTION_KEY|B_CAPS_LOCK: offset = fKeys.option_caps_map[keyCode]; break; 339 case B_OPTION_KEY|B_SHIFT_KEY|B_CAPS_LOCK: offset = fKeys.option_caps_shift_map[keyCode]; break; 340 case B_CONTROL_KEY: offset = fKeys.control_map[keyCode]; break; 341 default: offset = fKeys.normal_map[keyCode]; break; 342 } 343 344 // here we get the char size 345 *numBytes = fChars[offset]; 346 347 if (!*numBytes) 348 return; 349 350 // here we take an potential active dead key 351 int32 *dead_key; 352 switch(activeDeadKey) { 353 case 1: dead_key = fKeys.acute_dead_key; break; 354 case 2: dead_key = fKeys.grave_dead_key; break; 355 case 3: dead_key = fKeys.circumflex_dead_key; break; 356 case 4: dead_key = fKeys.dieresis_dead_key; break; 357 case 5: dead_key = fKeys.tilde_dead_key; break; 358 default: 359 { 360 // if not dead, we copy and return the char 361 char *str = *chars = new char[*numBytes + 1]; 362 strncpy(str, &(fChars[offset+1]), *numBytes ); 363 str[*numBytes] = 0; 364 return; 365 } 366 } 367 368 // if dead key, we search for our current offset char in the dead key offset table 369 // string comparison is needed 370 for (int32 i=0; i<32; i++) { 371 if (strncmp(&(fChars[offset+1]), &(fChars[dead_key[i]+1]), *numBytes ) == 0) { 372 *numBytes = fChars[dead_key[i+1]]; 373 374 switch( *numBytes ) { 375 case 0: 376 // Not mapped 377 *chars = NULL; 378 break; 379 default: 380 // 1-, 2-, 3-, or 4-byte UTF-8 character 381 { 382 char *str = *chars = new char[*numBytes + 1]; 383 strncpy(str, &fChars[dead_key[i+1]+1], *numBytes ); 384 str[*numBytes] = 0; 385 } 386 break; 387 } 388 return; 389 } 390 i++; 391 } 392 393 // if not found we return the current char mapped 394 *chars = new char[*numBytes + 1]; 395 strncpy(*chars, &(fChars[offset+1]), *numBytes ); 396 (*chars)[*numBytes] = 0; 397 398 } 399 400 401 // we make our input server use the map in /boot/home/config/settings/Keymap 402 status_t 403 Keymap::Use() 404 { 405 return _restore_key_map_(); 406 } 407