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