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