1 /* 2 * Copyright 2004-2006, Jérôme Duval. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 7 #include "KeyboardInputDevice.h" 8 #include "kb_mouse_driver.h" 9 10 #include <Application.h> 11 #include <Directory.h> 12 #include <Entry.h> 13 #include <NodeMonitor.h> 14 #include <Path.h> 15 #include <String.h> 16 17 #include <errno.h> 18 #include <new> 19 #include <stdlib.h> 20 #include <unistd.h> 21 22 23 #if DEBUG 24 FILE *KeyboardInputDevice::sLogFile = NULL; 25 #endif 26 27 const static uint32 kKeyboardThreadPriority = B_FIRST_REAL_TIME_PRIORITY + 4; 28 const static char *kKeyboardDevicesDirectory = "/dev/input/keyboard"; 29 30 // "/dev/" is automatically prepended by StartMonitoringDevice() 31 const static char *kKeyboardDevicesDirectoryPS2 = "input/keyboard/at"; 32 const static char *kKeyboardDevicesDirectoryUSB = "input/keyboard/usb"; 33 34 const static uint32 kATKeycodeMap[] = { 35 0x1, // Esc 36 0x12, // 1 37 0x13, // 2 38 0x14, // 3 39 0x15, // 4 40 0x16, // 5 41 0x17, // 6 42 0x18, // 7 43 0x19, // 8 44 0x1a, // 9 45 0x1b, // 0 46 0x1c, // - 47 0x1d, // = 48 0x1e, // BACKSPACE 49 0x26, // TAB 50 0x27, // Q 51 0x28, // W 52 0x29, // E 53 0x2a, // R 54 0x2b, // T 55 0x2c, // Y 56 0x2d, // U 57 0x2e, // I 58 0x2f, // O 59 0x30, // P 60 0x31, // [ 61 0x32, // ] 62 0x47, // ENTER 63 0x5c, // Left Control 64 0x3c, // A 65 0x3d, // S 66 0x3e, // D 67 0x3f, // F 68 0x40, // G 69 0x41, // H 70 0x42, // J 71 0x43, // K 72 0x44, // L 73 0x45, // ; 74 0x46, // ' 75 0x11, // ` 76 0x4b, // Left Shift 77 0x33, // \ (backslash -- note: don't remove non-white-space after BS char) 78 0x4c, // Z 79 0x4d, // X 80 0x4e, // C 81 0x4f, // V 82 0x50, // B 83 0x51, // N 84 0x52, // M 85 0x53, // , 86 0x54, // . 87 0x55, // / 88 0x56, // Right Shift 89 0x24, // * 90 0x5d, // Left Alt 91 0x5e, // Space 92 0x3b, // Caps 93 0x02, // F1 94 0x03, // F2 95 0x04, // F3 96 0x05, // F4 97 0x06, // F5 98 0x07, // F6 99 0x08, // F7 100 0x09, // F8 101 0x0a, // F9 102 0x0b, // F10 103 0x22, // Num 104 0x0f, // Scroll 105 0x37, // KP 7 106 0x38, // KP 8 107 0x39, // KP 9 108 0x25, // KP - 109 0x48, // KP 4 110 0x49, // KP 5 111 0x4a, // KP 6 112 0x3a, // KP + 113 0x58, // KP 1 114 0x59, // KP 2 115 0x5a, // KP 3 116 0x64, // KP 0 117 0x65, // KP . 118 0x00, // UNMAPPED 119 0x00, // UNMAPPED 120 0x69, // < 121 0x0c, // F11 122 0x0d, // F12 123 0x00, // UNMAPPED 124 0x00, // UNMAPPED 90 125 0x00, // UNMAPPED 126 0x00, // UNMAPPED 127 0x00, // UNMAPPED 128 0x00, // UNMAPPED 129 0x00, // UNMAPPED 130 0x00, // UNMAPPED 131 0x00, // UNMAPPED 132 0x00, // UNMAPPED 133 0x00, // UNMAPPED 134 0x00, // UNMAPPED 100 135 0x00, // UNMAPPED 136 0x00, // UNMAPPED 137 0x00, // UNMAPPED 138 0x00, // UNMAPPED 139 0x00, // UNMAPPED 140 0x00, // UNMAPPED 141 0x00, // UNMAPPED 142 0x00, // UNMAPPED 143 0x00, // UNMAPPED 144 0x00, // UNMAPPED 110 145 0x00, // UNMAPPED 146 0x6e, // Katakana/Hiragana, second key right to spacebar, japanese 147 0x00, // UNMAPPED 148 0x00, // UNMAPPED 149 0x6b, // Ro (\\ key, japanese) 150 0x00, // UNMAPPED 151 0x00, // UNMAPPED 152 0x00, // UNMAPPED 153 0x00, // UNMAPPED 154 0x00, // UNMAPPED 120 155 0x6d, // Henkan, first key right to spacebar, japanese 156 0x00, // UNMAPPED 157 0x6c, // Muhenkan, key left to spacebar, japanese 158 0x00, // UNMAPPED 159 0x6a, // Yen (macron key, japanese) 160 0x70, // Keypad . on Brazilian ABNT2 161 0x00, // UNMAPPED 162 0x00, // UNMAPPED 163 0x00, // UNMAPPED 164 0x00, // UNMAPPED 130 165 0x00, // UNMAPPED 166 0x00, // UNMAPPED 167 0x00, // UNMAPPED 168 0x00, // UNMAPPED 169 0x00, // UNMAPPED 170 0x00, // UNMAPPED 171 0x00, // UNMAPPED 172 0x00, // UNMAPPED 173 0x00, // UNMAPPED 174 0x00, // UNMAPPED 140 175 0x00, // UNMAPPED 176 0x00, // UNMAPPED 177 0x00, // UNMAPPED 178 0x00, // UNMAPPED 179 0x00, // UNMAPPED 180 0x00, // UNMAPPED 181 0x00, // UNMAPPED 182 0x00, // UNMAPPED 183 0x00, // UNMAPPED 184 0x00, // UNMAPPED 150 185 0x00, // UNMAPPED 186 0x00, // UNMAPPED 187 0x00, // UNMAPPED 188 0x00, // UNMAPPED 189 0x00, // UNMAPPED 190 0x5b, // KP Enter 191 0x60, // Right Control 192 0x00, // UNMAPPED 193 0x00, // UNMAPPED 194 0x00, // UNMAPPED 160 195 0x00, // UNMAPPED 196 0x00, // UNMAPPED 197 0x00, // UNMAPPED 198 0x00, // UNMAPPED 199 0x00, // UNMAPPED 200 0x00, // UNMAPPED 201 0x00, // UNMAPPED 202 0x00, // UNMAPPED 203 0x00, // UNMAPPED 204 0x00, // UNMAPPED 170 205 0x00, // UNMAPPED 206 0x00, // UNMAPPED 207 0x00, // UNMAPPED 208 0x00, // UNMAPPED 209 0x00, // UNMAPPED 210 0x00, // UNMAPPED 211 0x00, // UNMAPPED 212 0x00, // UNMAPPED 213 0x00, // UNMAPPED 214 0x00, // UNMAPPED 180 215 0x23, // KP / 216 0x00, // UNMAPPED 217 0x0e, // Print Screen 218 0x5f, // Right Alt 219 0x00, // UNMAPPED 220 0x00, // UNMAPPED 221 0x00, // UNMAPPED 222 0x00, // UNMAPPED 223 0x00, // UNMAPPED 224 0x00, // UNMAPPED 190 225 0x00, // UNMAPPED 226 0x00, // UNMAPPED 227 0x00, // UNMAPPED 228 0x00, // UNMAPPED 229 0x00, // UNMAPPED 230 0x00, // UNMAPPED 231 0x00, // UNMAPPED 232 0x7f, // Break 233 0x20, // Home 234 0x57, // Up Arrow 200 235 0x21, // Page Up 236 0x00, // UNMAPPED 237 0x61, // Left Arrow 238 0x00, // UNMAPPED 239 0x63, // Right Arrow 240 0x00, // UNMAPPED 241 0x35, // End 242 0x62, // Down Arrow 243 0x36, // Page Down 244 0x1f, // Insert 200 245 0x34, // Delete 246 0x00, // UNMAPPED 247 0x00, // UNMAPPED 248 0x00, // UNMAPPED 249 0x00, // UNMAPPED 250 0x00, // UNMAPPED 251 0x00, // UNMAPPED 252 0x00, // UNMAPPED 253 0x66, // Left Gui 254 0x67, // Right Gui 210 255 0x68, // Menu 256 0x00, // UNMAPPED 257 0x00, // UNMAPPED 258 0x00, // UNMAPPED 259 0x00, // UNMAPPED 260 0x00, // UNMAPPED 261 0x00, // UNMAPPED 262 0x00, // UNMAPPED 263 0x00, // UNMAPPED 264 0x00, // UNMAPPED 220 265 0x00, // UNMAPPED 266 0x00, // UNMAPPED 267 0x00, // UNMAPPED 268 0x00, // UNMAPPED 269 0x00, // UNMAPPED 270 0x00, // UNMAPPED 271 0x00, // UNMAPPED 272 0x00, // UNMAPPED 273 0x00, // UNMAPPED 274 0x00, // UNMAPPED 275 0x00, // UNMAPPED 276 0x00, // UNMAPPED 277 0x00, // UNMAPPED 278 0x00, // UNMAPPED 279 0x00, // UNMAPPED 280 0x00, // UNMAPPED 281 0x00, // UNMAPPED 282 0x00, // UNMAPPED 283 0x00, // UNMAPPED 284 0x00, // UNMAPPED 285 0x00, // UNMAPPED 286 0x00, // UNMAPPED 287 0x00, // UNMAPPED 288 0x00, // UNMAPPED 289 0x00, // UNMAPPED 290 0x00, // UNMAPPED 291 0x00, // UNMAPPED 292 0x00, // UNMAPPED 293 0x00, // UNMAPPED 294 0x00, // UNMAPPED 295 0x00, // UNMAPPED 296 0x00, // UNMAPPED 297 0x00, // UNMAPPED 298 0x00, // UNMAPPED 299 0x00, // UNMAPPED 300 0x00, // UNMAPPED 301 0x00, // UNMAPPED 302 0x00, // UNMAPPED 303 0x00, // UNMAPPED 304 0x00, // UNMAPPED 305 0x00, // UNMAPPED 306 0x00, // UNMAPPED 307 0x00, // UNMAPPED 308 0x00, // UNMAPPED 309 0x00, // UNMAPPED 310 0x00, // UNMAPPED 311 0x00, // UNMAPPED 312 0x00, // UNMAPPED 313 0x00, // UNMAPPED 314 0x00, // UNMAPPED 315 0x00, // UNMAPPED 316 0x00, // UNMAPPED 317 0x00, // UNMAPPED 318 0x00, // UNMAPPED 319 0x00, // UNMAPPED 320 0x00, // UNMAPPED 321 0x00, // UNMAPPED 322 0x00, // UNMAPPED 323 0x00, // UNMAPPED 324 0x00, // UNMAPPED 325 326 }; 327 328 329 extern "C" 330 BInputServerDevice * 331 instantiate_input_device() 332 { 333 return new (std::nothrow) KeyboardInputDevice(); 334 } 335 336 337 static char * 338 get_short_name(const char *longName) 339 { 340 CALLED(); 341 BString string(longName); 342 BString name; 343 344 int32 slash = string.FindLast("/"); 345 string.CopyInto(name, slash + 1, string.Length() - slash); 346 int32 index = atoi(name.String()) + 1; 347 348 int32 previousSlash = string.FindLast("/", slash); 349 string.CopyInto(name, previousSlash + 1, slash - previousSlash - 1); 350 351 // some special handling so that we get "USB" and "AT" instead of "usb"/"at" 352 if (name.Length() < 4) 353 name.ToUpper(); 354 else 355 name.Capitalize(); 356 357 name << " Keyboard " << index; 358 359 return strdup(name.String()); 360 } 361 362 363 // #pragma mark - 364 365 366 KeyboardInputDevice::KeyboardInputDevice() 367 : 368 fTMWindow(NULL) 369 { 370 #if DEBUG 371 if (sLogFile == NULL) 372 sLogFile = fopen("/var/log/keyboard_device_log.log", "a"); 373 #endif 374 CALLED(); 375 } 376 377 378 KeyboardInputDevice::~KeyboardInputDevice() 379 { 380 CALLED(); 381 StopMonitoringDevice(kKeyboardDevicesDirectoryUSB); 382 StopMonitoringDevice(kKeyboardDevicesDirectoryPS2); 383 384 int count = fDevices.CountItems(); 385 while (count-- > 0) { 386 delete (keyboard_device *)fDevices.RemoveItem((int32)0); 387 } 388 389 #if DEBUG 390 fclose(sLogFile); 391 #endif 392 } 393 394 395 status_t 396 KeyboardInputDevice::SystemShuttingDown() 397 { 398 CALLED(); 399 if (fTMWindow) 400 fTMWindow->PostMessage(SYSTEM_SHUTTING_DOWN); 401 402 return B_OK; 403 } 404 405 406 status_t 407 KeyboardInputDevice::_InitFromSettings(void *cookie, uint32 opcode) 408 { 409 CALLED(); 410 411 keyboard_device *device = (keyboard_device *)cookie; 412 413 if (opcode == 0 || opcode == B_KEY_REPEAT_RATE_CHANGED) { 414 if (get_key_repeat_rate(&device->settings.key_repeat_rate) != B_OK) 415 LOG_ERR("error when get_key_repeat_rate\n"); 416 else if (ioctl(device->fd, KB_SET_KEY_REPEAT_RATE, 417 &device->settings.key_repeat_rate) != B_OK) 418 LOG_ERR("error when KB_SET_KEY_REPEAT_RATE, fd:%d\n", device->fd); 419 } 420 421 if (opcode == 0 || opcode == B_KEY_REPEAT_DELAY_CHANGED) { 422 if (get_key_repeat_delay(&device->settings.key_repeat_delay) != B_OK) 423 LOG_ERR("error when get_key_repeat_delay\n"); 424 else if (ioctl(device->fd, KB_SET_KEY_REPEAT_DELAY, 425 &device->settings.key_repeat_delay) != B_OK) 426 LOG_ERR("error when KB_SET_KEY_REPEAT_DELAY, fd:%d\n", device->fd); 427 } 428 429 if (opcode == 0 430 || opcode == B_KEY_MAP_CHANGED 431 || opcode == B_KEY_LOCKS_CHANGED) { 432 fKeymap.LoadCurrent(); 433 device->modifiers = fKeymap.Locks(); 434 _SetLeds(device); 435 } 436 437 return B_OK; 438 } 439 440 441 status_t 442 KeyboardInputDevice::InitCheck() 443 { 444 CALLED(); 445 // TODO: this doesn't belong here! 446 _RecursiveScan(kKeyboardDevicesDirectory); 447 448 StartMonitoringDevice(kKeyboardDevicesDirectoryPS2); 449 StartMonitoringDevice(kKeyboardDevicesDirectoryUSB); 450 451 return B_OK; 452 } 453 454 455 status_t 456 KeyboardInputDevice::Start(const char *name, void *cookie) 457 { 458 CALLED(); 459 keyboard_device *device = (keyboard_device *)cookie; 460 461 if ((device->fd = open(device->path, O_RDWR)) < B_OK) { 462 fprintf(stderr, "error when opening %s: %s\n", device->path, strerror(errno)); 463 return B_ERROR; 464 } 465 466 _InitFromSettings(device); 467 468 char threadName[B_OS_NAME_LENGTH]; 469 snprintf(threadName, B_OS_NAME_LENGTH, "%s watcher", name); 470 471 device->active = true; 472 device->device_watcher = spawn_thread(_DeviceWatcher, threadName, 473 kKeyboardThreadPriority, device); 474 if (device->device_watcher < B_OK) 475 return device->device_watcher; 476 477 resume_thread(device->device_watcher); 478 return B_OK; 479 } 480 481 482 status_t 483 KeyboardInputDevice::Stop(const char *name, void *cookie) 484 { 485 CALLED(); 486 keyboard_device *device = (keyboard_device *)cookie; 487 488 LOG("Stop(%s)\n", name); 489 490 close(device->fd); 491 device->fd = -1; 492 493 device->active = false; 494 if (device->device_watcher >= 0) { 495 suspend_thread(device->device_watcher); 496 resume_thread(device->device_watcher); 497 status_t dummy; 498 wait_for_thread(device->device_watcher, &dummy); 499 } 500 501 if (fTMWindow) { 502 fTMWindow->PostMessage(B_QUIT_REQUESTED); 503 fTMWindow = NULL; 504 } 505 506 return B_OK; 507 } 508 509 510 status_t 511 KeyboardInputDevice::Control(const char *name, void *cookie, 512 uint32 command, BMessage *message) 513 { 514 CALLED(); 515 LOG("Control(%s, code: %lu)\n", name, command); 516 517 if (command == B_NODE_MONITOR) 518 _HandleMonitor(message); 519 else if (command >= B_KEY_MAP_CHANGED 520 && command <= B_KEY_REPEAT_RATE_CHANGED) { 521 _InitFromSettings(cookie, command); 522 } 523 return B_OK; 524 } 525 526 527 status_t 528 KeyboardInputDevice::_HandleMonitor(BMessage *message) 529 { 530 CALLED(); 531 int32 opcode = 0; 532 status_t status; 533 if ((status = message->FindInt32("opcode", &opcode)) < B_OK) 534 return status; 535 536 if (opcode != B_ENTRY_CREATED 537 && opcode != B_ENTRY_REMOVED) 538 return B_OK; 539 540 BEntry entry; 541 BPath path; 542 dev_t device; 543 ino_t directory; 544 const char *name = NULL; 545 546 message->FindInt32("device", &device); 547 message->FindInt64("directory", &directory); 548 message->FindString("name", &name); 549 550 entry_ref ref(device, directory, name); 551 552 if ((status = entry.SetTo(&ref)) != B_OK) 553 return status; 554 if ((status = entry.GetPath(&path)) != B_OK) 555 return status; 556 if ((status = path.InitCheck()) != B_OK) 557 return status; 558 559 if (opcode == B_ENTRY_CREATED) 560 _AddDevice(path.Path()); 561 else 562 _RemoveDevice(path.Path()); 563 564 return status; 565 } 566 567 568 status_t 569 KeyboardInputDevice::_AddDevice(const char *path) 570 { 571 CALLED(); 572 keyboard_device *device = new (std::nothrow) keyboard_device(path); 573 if (device == NULL) 574 return B_NO_MEMORY; 575 576 device->owner = this; 577 578 input_device_ref *devices[2]; 579 devices[0] = &device->device_ref; 580 devices[1] = NULL; 581 582 fDevices.AddItem(device); 583 584 return RegisterDevices(devices); 585 } 586 587 588 status_t 589 KeyboardInputDevice::_RemoveDevice(const char *path) 590 { 591 CALLED(); 592 keyboard_device *device; 593 for (int i = 0; (device = (keyboard_device *)fDevices.ItemAt(i)) != NULL; i++) { 594 if (!strcmp(device->path, path)) { 595 fDevices.RemoveItem(device); 596 597 input_device_ref *devices[2]; 598 devices[0] = &device->device_ref; 599 devices[1] = NULL; 600 UnregisterDevices(devices); 601 602 delete device; 603 return B_OK; 604 } 605 } 606 607 return B_ENTRY_NOT_FOUND; 608 } 609 610 611 /*static*/ int32 612 KeyboardInputDevice::_DeviceWatcher(void *arg) 613 { 614 CALLED(); 615 keyboard_device* device = (keyboard_device *)arg; 616 KeyboardInputDevice* owner = device->owner; 617 uint8 buffer[16]; 618 uint8 activeDeadKey = 0; 619 Keymap* keymap = &owner->fKeymap; 620 uint32 lastKeyCode = 0; 621 uint32 repeatCount = 1; 622 uint8 states[16]; 623 624 memset(states, 0, sizeof(states)); 625 626 LOG("%s\n", __PRETTY_FUNCTION__); 627 628 while (device->active) { 629 if (ioctl(device->fd, KB_READ, &buffer) != B_OK) 630 return 0; 631 632 uint32 keycode = 0; 633 bool isKeyDown = false; 634 bigtime_t timestamp = 0; 635 636 LOG("KB_READ :"); 637 638 if (device->isAT) { 639 at_kbd_io *at_kbd = (at_kbd_io *)buffer; 640 if (at_kbd->scancode > 0) 641 keycode = kATKeycodeMap[at_kbd->scancode-1]; 642 isKeyDown = at_kbd->is_keydown; 643 timestamp = at_kbd->timestamp; 644 LOG(" %02x", at_kbd->scancode); 645 } else { 646 raw_key_info *raw_kbd = (raw_key_info *)buffer; 647 isKeyDown = raw_kbd->is_keydown; 648 timestamp = raw_kbd->timestamp; 649 keycode = raw_kbd->be_keycode; 650 } 651 652 if (keycode == 0) 653 continue; 654 655 LOG(" %Ld, %02x, %02lx\n", timestamp, isKeyDown, keycode); 656 657 if (isKeyDown && keycode == 0x68) { 658 // MENU KEY for OpenTracker 5.2.0+ 659 bool noOtherKeyPressed = true; 660 for (int32 i = 0; i < 16; i++) { 661 if (states[i] != 0) { 662 noOtherKeyPressed = false; 663 break; 664 } 665 } 666 667 if (noOtherKeyPressed) { 668 BMessenger deskbar("application/x-vnd.Be-TSKB"); 669 if (deskbar.IsValid()) 670 deskbar.SendMessage('BeMn'); 671 } 672 } 673 674 if (keycode < 256) { 675 if (isKeyDown) 676 states[(keycode) >> 3] |= (1 << (7 - (keycode & 0x7))); 677 else 678 states[(keycode) >> 3] &= (!(1 << (7 - (keycode & 0x7)))); 679 } 680 681 if (isKeyDown 682 && keycode == 0x34 // DELETE KEY 683 && (states[0x5c >> 3] & (1 << (7 - (0x5c & 0x7)))) 684 && (states[0x5d >> 3] & (1 << (7 - (0x5d & 0x7))))) { 685 LOG("TeamMonitor called\n"); 686 687 // show the team monitor 688 if (owner->fTMWindow == NULL) 689 owner->fTMWindow = new (std::nothrow) TMWindow(); 690 691 if (owner->fTMWindow != NULL) { 692 owner->fTMWindow->Enable(); 693 694 // cancel timer only for R5 695 if (ioctl(device->fd, KB_CANCEL_CONTROL_ALT_DEL, NULL) == B_OK) 696 LOG("KB_CANCEL_CONTROL_ALT_DEL : OK\n"); 697 } 698 } 699 700 uint32 modifiers = keymap->Modifier(keycode); 701 if (modifiers 702 && (!(modifiers & (B_CAPS_LOCK | B_NUM_LOCK | B_SCROLL_LOCK)) 703 || isKeyDown)) { 704 BMessage *msg = new BMessage; 705 if (msg == NULL) 706 continue; 707 708 msg->AddInt64("when", timestamp); 709 msg->what = B_MODIFIERS_CHANGED; 710 msg->AddInt32("be:old_modifiers", device->modifiers); 711 712 if ((isKeyDown && !(modifiers & (B_CAPS_LOCK | B_NUM_LOCK | B_SCROLL_LOCK))) 713 || (isKeyDown && !(device->modifiers & modifiers))) 714 device->modifiers |= modifiers; 715 else 716 device->modifiers &= ~modifiers; 717 718 msg->AddInt32("modifiers", device->modifiers); 719 msg->AddData("states", B_UINT8_TYPE, states, 16); 720 721 if (owner->EnqueueMessage(msg)!=B_OK) 722 delete msg; 723 724 if (modifiers & (B_CAPS_LOCK | B_NUM_LOCK | B_SCROLL_LOCK)) 725 owner->_SetLeds(device); 726 } 727 728 uint8 newDeadKey = 0; 729 if (activeDeadKey == 0) 730 newDeadKey = keymap->IsDeadKey(keycode, device->modifiers); 731 732 if (newDeadKey == 0) { 733 char *string = NULL, *rawString = NULL; 734 int32 numBytes = 0, rawNumBytes = 0; 735 keymap->GetChars(keycode, device->modifiers, activeDeadKey, &string, &numBytes); 736 keymap->GetChars(keycode, 0, 0, &rawString, &rawNumBytes); 737 738 BMessage *msg = new BMessage; 739 if (msg == NULL) 740 continue; 741 742 if (numBytes > 0) 743 msg->what = isKeyDown ? B_KEY_DOWN : B_KEY_UP; 744 else 745 msg->what = isKeyDown ? B_UNMAPPED_KEY_DOWN : B_UNMAPPED_KEY_UP; 746 747 msg->AddInt64("when", timestamp); 748 msg->AddInt32("key", keycode); 749 msg->AddInt32("modifiers", device->modifiers); 750 msg->AddData("states", B_UINT8_TYPE, states, 16); 751 if (numBytes > 0) { 752 for (int i = 0; i < numBytes; i++) { 753 msg->AddInt8("byte", (int8)string[i]); 754 } 755 msg->AddString("bytes", string); 756 757 if (rawNumBytes <= 0) { 758 rawNumBytes = 1; 759 delete[] rawString; 760 rawString = string; 761 } else 762 delete[] string; 763 764 if (isKeyDown && lastKeyCode == keycode) { 765 repeatCount++; 766 msg->AddInt32("be:key_repeat", repeatCount); 767 } else 768 repeatCount = 1; 769 } else 770 delete[] string; 771 772 if (rawNumBytes > 0) 773 msg->AddInt32("raw_char", (uint32)((uint8)rawString[0] & 0x7f)); 774 775 delete[] rawString; 776 777 if (isKeyDown && !modifiers && activeDeadKey != 0 778 && device->input_method_started) { 779 // a dead key was completed 780 device->EnqueueInlineInputMethod(B_INPUT_METHOD_CHANGED, 781 string, true, msg); 782 } else if (owner->EnqueueMessage(msg) != B_OK) 783 delete msg; 784 } else if (isKeyDown) { 785 // start of a dead key 786 if (device->EnqueueInlineInputMethod(B_INPUT_METHOD_STARTED) == B_OK) { 787 char *string = NULL; 788 int32 numBytes = 0; 789 keymap->GetChars(keycode, device->modifiers, 0, &string, &numBytes); 790 791 if (device->EnqueueInlineInputMethod(B_INPUT_METHOD_CHANGED, string) == B_OK) 792 device->input_method_started = true; 793 } 794 } 795 796 if (!isKeyDown && !modifiers) { 797 if (activeDeadKey != 0) { 798 device->EnqueueInlineInputMethod(B_INPUT_METHOD_STOPPED); 799 device->input_method_started = false; 800 } 801 802 activeDeadKey = newDeadKey; 803 } 804 805 lastKeyCode = isKeyDown ? keycode : 0; 806 } 807 808 return 0; 809 } 810 811 812 void 813 KeyboardInputDevice::_RecursiveScan(const char *directory) 814 { 815 CALLED(); 816 BEntry entry; 817 BDirectory dir(directory); 818 while (dir.GetNextEntry(&entry) == B_OK) { 819 BPath path; 820 entry.GetPath(&path); 821 if (entry.IsDirectory()) 822 _RecursiveScan(path.Path()); 823 else 824 _AddDevice(path.Path()); 825 } 826 } 827 828 829 void 830 KeyboardInputDevice::_SetLeds(keyboard_device *device) 831 { 832 if (device->fd < 0) 833 return; 834 835 uint32 locks = device->modifiers; 836 char lock_io[3]; 837 memset(lock_io, 0, sizeof(lock_io)); 838 if (locks & B_NUM_LOCK) 839 lock_io[0] = 1; 840 if (locks & B_CAPS_LOCK) 841 lock_io[1] = 1; 842 if (locks & B_SCROLL_LOCK) 843 lock_io[2] = 1; 844 845 ioctl(device->fd, KB_SET_LEDS, &lock_io); 846 } 847 848 849 // #pragma mark - 850 851 852 keyboard_device::keyboard_device(const char *path) 853 : BHandler("keyboard device"), 854 owner(NULL), 855 fd(-1), 856 device_watcher(-1), 857 active(false), 858 input_method_started(false) 859 { 860 strcpy(this->path, path); 861 device_ref.name = get_short_name(path); 862 device_ref.type = B_KEYBOARD_DEVICE; 863 device_ref.cookie = this; 864 865 isAT = strstr(path, "keyboard/at") != NULL; 866 867 if (be_app->Lock()) { 868 be_app->AddHandler(this); 869 be_app->Unlock(); 870 } 871 } 872 873 874 keyboard_device::~keyboard_device() 875 { 876 free(device_ref.name); 877 878 if (be_app->Lock()) { 879 be_app->RemoveHandler(this); 880 be_app->Unlock(); 881 } 882 } 883 884 885 status_t 886 keyboard_device::EnqueueInlineInputMethod(int32 opcode, 887 const char* string, bool confirmed, BMessage* keyDown) 888 { 889 BMessage* message = new BMessage(B_INPUT_METHOD_EVENT); 890 if (message == NULL) 891 return B_NO_MEMORY; 892 893 message->AddInt32("be:opcode", opcode); 894 message->AddBool("be:inline_only", true); 895 896 if (string != NULL) 897 message->AddString("be:string", string); 898 if (confirmed) 899 message->AddBool("be:confirmed", true); 900 if (keyDown) 901 message->AddMessage("be:translated", keyDown); 902 if (opcode == B_INPUT_METHOD_STARTED) 903 message->AddMessenger("be:reply_to", this); 904 905 status_t status = owner->EnqueueMessage(message); 906 if (status != B_OK) 907 delete message; 908 909 return status; 910 } 911 912 913 void 914 keyboard_device::MessageReceived(BMessage *message) 915 { 916 if (message->what != B_INPUT_METHOD_EVENT) { 917 BHandler::MessageReceived(message); 918 return; 919 } 920 921 int32 opcode; 922 if (message->FindInt32("be:opcode", &opcode) != B_OK) 923 return; 924 925 if (opcode == B_INPUT_METHOD_STOPPED) 926 input_method_started = false; 927 } 928 929