1 /* 2 * Copyright 2004-2011 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 * Axel Dörfler, axeld@pinc-software.de. 9 */ 10 11 12 #include "Keymap.h" 13 14 #include <new> 15 #include <stdio.h> 16 #include <string.h> 17 18 #include <ByteOrder.h> 19 #include <File.h> 20 21 #include <input_globals.h> 22 23 24 static const uint32 kModifierKeys = B_SHIFT_KEY | B_COMMAND_KEY | B_CONTROL_KEY 25 | B_CAPS_LOCK | B_OPTION_KEY | B_MENU_KEY; 26 27 28 static void 29 print_key(char *chars, int32 offset) 30 { 31 int size = chars[offset++]; 32 33 switch (size) { 34 case 0: 35 // Not mapped 36 printf("N/A"); 37 break; 38 39 case 1: 40 // 1-byte UTF-8/ASCII character 41 printf("%c", chars[offset]); 42 break; 43 44 default: 45 { 46 // 2-, 3-, or 4-byte UTF-8 character 47 char *str = new char[size + 1]; 48 strncpy(str, &chars[offset], size); 49 str[size] = 0; 50 printf("%s", str); 51 delete[] str; 52 break; 53 } 54 } 55 56 printf("\t"); 57 } 58 59 60 // #pragma mark - 61 62 63 Keymap::Keymap() 64 : 65 fModificationMessage(NULL) 66 { 67 } 68 69 70 Keymap::~Keymap() 71 { 72 delete fModificationMessage; 73 } 74 75 76 void 77 Keymap::SetTarget(BMessenger target, BMessage* modificationMessage) 78 { 79 delete fModificationMessage; 80 81 fTarget = target; 82 fModificationMessage = modificationMessage; 83 } 84 85 86 void 87 Keymap::SetName(const char* name) 88 { 89 strlcpy(fName, name, sizeof(fName)); 90 } 91 92 93 void 94 Keymap::DumpKeymap() 95 { 96 // Print a chart of the normal, shift, option, and option+shift 97 // keys. 98 printf("Key #\tNormal\tShift\tCaps\tC+S\tOption\tO+S\tO+C\tO+C+S\t" 99 "Control\n"); 100 for (int i = 0; i < 128; i++) { 101 printf(" 0x%x\t", i); 102 print_key(fChars, fKeys.normal_map[i]); 103 print_key(fChars, fKeys.shift_map[i]); 104 print_key(fChars, fKeys.caps_map[i]); 105 print_key(fChars, fKeys.caps_shift_map[i]); 106 print_key(fChars, fKeys.option_map[i]); 107 print_key(fChars, fKeys.option_shift_map[i]); 108 print_key(fChars, fKeys.option_caps_map[i]); 109 print_key(fChars, fKeys.option_caps_shift_map[i]); 110 print_key(fChars, fKeys.control_map[i]); 111 printf("\n"); 112 } 113 } 114 115 116 //! Load a map from a file 117 status_t 118 Keymap::Load(const entry_ref& ref) 119 { 120 BEntry entry; 121 status_t status = entry.SetTo(&ref, true); 122 if (status != B_OK) 123 return status; 124 125 BFile file(&entry, B_READ_ONLY); 126 status = SetTo(file); 127 if (status != B_OK) 128 return status; 129 130 // fetch name from attribute and fall back to filename 131 132 ssize_t bytesRead = file.ReadAttr("keymap:name", B_STRING_TYPE, 0, fName, 133 sizeof(fName)); 134 if (bytesRead > 0) 135 fName[bytesRead] = '\0'; 136 else 137 strlcpy(fName, ref.name, sizeof(fName)); 138 139 return B_OK; 140 } 141 142 143 //! We save a map to a file 144 status_t 145 Keymap::Save(const entry_ref& ref) 146 { 147 BFile file; 148 status_t status = file.SetTo(&ref, 149 B_WRITE_ONLY | B_CREATE_FILE | B_ERASE_FILE); 150 if (status != B_OK) { 151 printf("error %s\n", strerror(status)); 152 return status; 153 } 154 155 for (uint32 i = 0; i < sizeof(fKeys) / 4; i++) 156 ((uint32*)&fKeys)[i] = B_HOST_TO_BENDIAN_INT32(((uint32*)&fKeys)[i]); 157 158 ssize_t bytesWritten = file.Write(&fKeys, sizeof(fKeys)); 159 if (bytesWritten < (ssize_t)sizeof(fKeys)) 160 status = bytesWritten < 0 ? bytesWritten : B_IO_ERROR; 161 162 for (uint32 i = 0; i < sizeof(fKeys) / 4; i++) 163 ((uint32*)&fKeys)[i] = B_BENDIAN_TO_HOST_INT32(((uint32*)&fKeys)[i]); 164 165 if (status == B_OK) { 166 fCharsSize = B_HOST_TO_BENDIAN_INT32(fCharsSize); 167 168 bytesWritten = file.Write(&fCharsSize, sizeof(uint32)); 169 if (bytesWritten < (ssize_t)sizeof(uint32)) 170 status = bytesWritten < 0 ? bytesWritten : B_IO_ERROR; 171 172 fCharsSize = B_BENDIAN_TO_HOST_INT32(fCharsSize); 173 } 174 175 if (status == B_OK) { 176 bytesWritten = file.Write(fChars, fCharsSize); 177 if (bytesWritten < (ssize_t)fCharsSize) 178 status = bytesWritten < 0 ? bytesWritten : B_IO_ERROR; 179 } 180 181 if (status == B_OK) { 182 file.WriteAttr("keymap:name", B_STRING_TYPE, 0, fName, strlen(fName)); 183 // Failing would be non-fatal 184 } 185 186 return status; 187 } 188 189 190 status_t 191 Keymap::SetModifier(uint32 keyCode, uint32 modifier) 192 { 193 const uint32 kSingleKeys = B_LEFT_SHIFT_KEY | B_RIGHT_SHIFT_KEY 194 | B_LEFT_COMMAND_KEY | B_RIGHT_COMMAND_KEY | B_LEFT_CONTROL_KEY 195 | B_RIGHT_CONTROL_KEY | B_LEFT_OPTION_KEY | B_RIGHT_OPTION_KEY; 196 197 if ((modifier & kSingleKeys) != 0) 198 modifier &= kSingleKeys; 199 else if ((modifier & kModifierKeys) != 0) 200 modifier &= kModifierKeys; 201 202 if (modifier == B_CAPS_LOCK) 203 fKeys.caps_key = keyCode; 204 else if (modifier == B_NUM_LOCK) 205 fKeys.num_key = keyCode; 206 else if (modifier == B_SCROLL_LOCK) 207 fKeys.scroll_key = keyCode; 208 else if (modifier == B_LEFT_SHIFT_KEY) 209 fKeys.left_shift_key = keyCode; 210 else if (modifier == B_RIGHT_SHIFT_KEY) 211 fKeys.right_shift_key = keyCode; 212 else if (modifier == B_LEFT_COMMAND_KEY) 213 fKeys.left_command_key = keyCode; 214 else if (modifier == B_RIGHT_COMMAND_KEY) 215 fKeys.right_command_key = keyCode; 216 else if (modifier == B_LEFT_CONTROL_KEY) 217 fKeys.left_control_key = keyCode; 218 else if (modifier == B_RIGHT_CONTROL_KEY) 219 fKeys.right_control_key = keyCode; 220 else if (modifier == B_LEFT_OPTION_KEY) 221 fKeys.left_option_key = keyCode; 222 else if (modifier == B_RIGHT_OPTION_KEY) 223 fKeys.right_option_key = keyCode; 224 else if (modifier == B_MENU_KEY) 225 fKeys.menu_key = keyCode; 226 else 227 return B_BAD_VALUE; 228 229 if (fModificationMessage != NULL) 230 fTarget.SendMessage(fModificationMessage); 231 232 return B_OK; 233 } 234 235 236 //! Enables/disables the "deadness" of the given keycode/modifier combo. 237 void 238 Keymap::SetDeadKeyEnabled(uint32 keyCode, uint32 modifiers, bool enabled) 239 { 240 uint32 tableMask = 0; 241 int32 offset = Offset(keyCode, modifiers, &tableMask); 242 uint8 deadKeyIndex = DeadKeyIndex(offset); 243 if (deadKeyIndex > 0) { 244 uint32* deadTables[] = { 245 &fKeys.acute_tables, 246 &fKeys.grave_tables, 247 &fKeys.circumflex_tables, 248 &fKeys.dieresis_tables, 249 &fKeys.tilde_tables 250 }; 251 252 if (enabled) 253 (*deadTables[deadKeyIndex - 1]) |= tableMask; 254 else 255 (*deadTables[deadKeyIndex - 1]) &= ~tableMask; 256 257 if (fModificationMessage != NULL) 258 fTarget.SendMessage(fModificationMessage); 259 } 260 } 261 262 263 /*! Returns the trigger character string that is currently set for the dead 264 key with the given index (which is 1..5). 265 */ 266 void 267 Keymap::GetDeadKeyTrigger(dead_key_index deadKeyIndex, BString& outTrigger) 268 { 269 outTrigger = ""; 270 if (deadKeyIndex < 1 || deadKeyIndex > 5) 271 return; 272 273 int32 deadOffsets[] = { 274 fKeys.acute_dead_key[1], 275 fKeys.grave_dead_key[1], 276 fKeys.circumflex_dead_key[1], 277 fKeys.dieresis_dead_key[1], 278 fKeys.tilde_dead_key[1] 279 }; 280 281 int32 offset = deadOffsets[deadKeyIndex - 1]; 282 if (offset < 0 || offset >= (int32)fCharsSize) 283 return; 284 285 uint32 deadNumBytes = fChars[offset]; 286 if (!deadNumBytes) 287 return; 288 289 outTrigger.SetTo(&fChars[offset + 1], deadNumBytes); 290 } 291 292 293 /*! Sets the trigger character string that shall be used for the dead key 294 with the given index (which is 1..5). 295 */ 296 void 297 Keymap::SetDeadKeyTrigger(dead_key_index deadKeyIndex, const BString& trigger) 298 { 299 if (deadKeyIndex < 1 || deadKeyIndex > 5) 300 return; 301 302 int32 deadOffsets[] = { 303 fKeys.acute_dead_key[1], 304 fKeys.grave_dead_key[1], 305 fKeys.circumflex_dead_key[1], 306 fKeys.dieresis_dead_key[1], 307 fKeys.tilde_dead_key[1] 308 }; 309 310 int32 offset = deadOffsets[deadKeyIndex - 1]; 311 if (offset < 0 || offset >= (int32)fCharsSize) 312 return; 313 314 if (_SetChars(offset, trigger.String(), trigger.Length())) { 315 // reset modifier table such that new dead key is enabled wherever 316 // it is available 317 uint32* deadTables[] = { 318 &fKeys.acute_tables, 319 &fKeys.grave_tables, 320 &fKeys.circumflex_tables, 321 &fKeys.dieresis_tables, 322 &fKeys.tilde_tables 323 }; 324 *deadTables[deadKeyIndex - 1] 325 = B_CONTROL_TABLE | B_OPTION_CAPS_SHIFT_TABLE | B_OPTION_CAPS_TABLE 326 | B_OPTION_SHIFT_TABLE | B_OPTION_TABLE | B_CAPS_SHIFT_TABLE 327 | B_CAPS_TABLE | B_SHIFT_TABLE | B_NORMAL_TABLE; 328 329 if (fModificationMessage != NULL) 330 fTarget.SendMessage(fModificationMessage); 331 } 332 } 333 334 335 //! We make our input server use the map in /boot/home/config/settings/Keymap 336 status_t 337 Keymap::Use() 338 { 339 return _restore_key_map_(); 340 } 341 342 343 void 344 Keymap::SetKey(uint32 keyCode, uint32 modifiers, int8 deadKey, 345 const char* bytes, int32 numBytes) 346 { 347 int32 offset = Offset(keyCode, modifiers); 348 if (offset < 0) 349 return; 350 351 if (numBytes == -1) 352 numBytes = strlen(bytes); 353 if (numBytes > 6) 354 return; 355 356 if (_SetChars(offset, bytes, numBytes)) { 357 if (fModificationMessage != NULL) 358 fTarget.SendMessage(fModificationMessage); 359 } 360 } 361 362 363 Keymap& 364 Keymap::operator=(const Keymap& other) 365 { 366 if (this == &other) 367 return *this; 368 369 delete[] fChars; 370 delete fModificationMessage; 371 372 fChars = new(std::nothrow) char[other.fCharsSize]; 373 if (fChars != NULL) { 374 memcpy(fChars, other.fChars, other.fCharsSize); 375 fCharsSize = other.fCharsSize; 376 } else 377 fCharsSize = 0; 378 379 memcpy(&fKeys, &other.fKeys, sizeof(key_map)); 380 strlcpy(fName, other.fName, sizeof(fName)); 381 382 fTarget = other.fTarget; 383 384 if (other.fModificationMessage != NULL) 385 fModificationMessage = new BMessage(*other.fModificationMessage); 386 387 return *this; 388 } 389 390 391 bool 392 Keymap::_SetChars(int32 offset, const char* bytes, int32 numBytes) 393 { 394 int32 oldNumBytes = fChars[offset]; 395 396 if (oldNumBytes == numBytes 397 && !memcmp(&fChars[offset + 1], bytes, numBytes)) { 398 // nothing to do 399 return false; 400 } 401 402 int32 diff = numBytes - oldNumBytes; 403 if (diff != 0) { 404 fCharsSize += diff; 405 406 if (diff > 0) { 407 // make space for the new data 408 char* chars = new(std::nothrow) char[fCharsSize]; 409 if (chars != NULL) { 410 memcpy(chars, fChars, offset + oldNumBytes + 1); 411 memcpy(&chars[offset + 1 + numBytes], 412 &fChars[offset + 1 + oldNumBytes], 413 fCharsSize - 2 - offset - diff); 414 delete[] fChars; 415 fChars = chars; 416 } else 417 return false; 418 } else if (diff < 0) { 419 // shrink table 420 memmove(&fChars[offset + numBytes], &fChars[offset + oldNumBytes], 421 fCharsSize - offset - 2 - diff); 422 } 423 424 // update offsets 425 int32* data = fKeys.control_map; 426 int32 size = sizeof(fKeys.control_map) / 4 * 9 427 + sizeof(fKeys.acute_dead_key) / 4 * 5; 428 for (int32 i = 0; i < size; i++) { 429 if (data[i] > offset) 430 data[i] += diff; 431 } 432 } 433 434 memcpy(&fChars[offset + 1], bytes, numBytes); 435 fChars[offset] = numBytes; 436 437 return true; 438 } 439