1 /* 2 * Copyright 2008-2011 Michael Lotz <mmlr@mlotz.ch> 3 * Distributed under the terms of the MIT license. 4 */ 5 6 7 #include <new> 8 #include <stdlib.h> 9 #include <string.h> 10 11 #include <usb/USB_hid.h> 12 #include <util/AutoLock.h> 13 14 #include <debug.h> 15 #include <kernel.h> 16 17 #include "Driver.h" 18 #include "KeyboardProtocolHandler.h" 19 20 #include "HIDCollection.h" 21 #include "HIDDevice.h" 22 #include "HIDReport.h" 23 #include "HIDReportItem.h" 24 25 #include <keyboard_mouse_driver.h> 26 27 28 #define LEFT_ALT_KEY 0x04 29 #define RIGHT_ALT_KEY 0x40 30 #define ALT_KEYS (LEFT_ALT_KEY | RIGHT_ALT_KEY) 31 32 #define KEYBOARD_HANDLER_COOKIE_FLAG_READER 0x01 33 #define KEYBOARD_HANDLER_COOKIE_FLAG_DEBUGGER 0x02 34 35 36 #if KEYBOARD_SUPPORTS_KDL 37 static bool sDebugKeyboardFound = false; 38 static usb_id sDebugKeyboardPipe = 0; 39 static size_t sDebugKeyboardReportSize = 0; 40 static int32 sDebuggerCommandAdded = 0; 41 42 43 static int 44 debug_get_keyboard_config(int argc, char **argv) 45 { 46 set_debug_variable("_usbPipeID", (uint64)sDebugKeyboardPipe); 47 set_debug_variable("_usbReportSize", (uint64)sDebugKeyboardReportSize); 48 return 0; 49 } 50 #endif 51 52 53 // #pragma mark - 54 55 56 KeyboardProtocolHandler::KeyboardProtocolHandler(HIDReport &inputReport, 57 HIDReport *outputReport) 58 : 59 ProtocolHandler(inputReport.Device(), "input/keyboard/" DEVICE_PATH_SUFFIX 60 "/", 512), 61 fInputReport(inputReport), 62 fOutputReport(outputReport), 63 fRepeatDelay(300000), 64 fRepeatRate(35000), 65 fCurrentRepeatDelay(B_INFINITE_TIMEOUT), 66 fCurrentRepeatKey(0), 67 fKeyCount(0), 68 fModifierCount(0), 69 fLastModifiers(0), 70 fCurrentKeys(NULL), 71 fLastKeys(NULL), 72 fHasReader(0), 73 fHasDebugReader(false) 74 { 75 mutex_init(&fLock, "usb keyboard"); 76 77 // find modifiers and keys 78 bool debugUsable = false; 79 80 for (uint32 i = 0; i < inputReport.CountItems(); i++) { 81 HIDReportItem *item = inputReport.ItemAt(i); 82 if (!item->HasData()) 83 continue; 84 85 if (item->UsagePage() == B_HID_USAGE_PAGE_KEYBOARD 86 || item->UsagePage() == B_HID_USAGE_PAGE_CONSUMER 87 || item->UsagePage() == B_HID_USAGE_PAGE_BUTTON) { 88 TRACE("keyboard item with usage %" B_PRIx32 "\n", 89 item->Usage()); 90 91 debugUsable = true; 92 93 if (item->UsageID() >= B_HID_UID_KB_LEFT_CONTROL 94 && item->UsageID() <= B_HID_UID_KB_RIGHT_GUI) { 95 if (fModifierCount < MAX_MODIFIERS) 96 fModifiers[fModifierCount++] = item; 97 } else if (fKeyCount < MAX_KEYS) 98 fKeys[fKeyCount++] = item; 99 } 100 } 101 102 #if KEYBOARD_SUPPORTS_KDL 103 if (!sDebugKeyboardFound && debugUsable) { 104 // It's a keyboard, not just some additional buttons, set up the kernel 105 // debugger info here so that it is ready on panics or crashes that 106 // don't go through the emergency keys. If we also found LEDs we assume 107 // it is a full sized keyboard and discourage further setting the info. 108 sDebugKeyboardPipe = fInputReport.Device()->InterruptPipe(); 109 sDebugKeyboardReportSize = fInputReport.Parser()->MaxReportSize(); 110 if (outputReport != NULL) 111 sDebugKeyboardFound = true; 112 } 113 #endif 114 115 TRACE("keyboard device with %" B_PRIu32 " keys and %" B_PRIu32 116 " modifiers\n", fKeyCount, fModifierCount); 117 TRACE("input report: %u; output report: %u\n", inputReport.ID(), 118 outputReport != NULL ? outputReport->ID() : 255); 119 120 fLastKeys = (uint16 *)malloc(fKeyCount * 2 * sizeof(uint16)); 121 fCurrentKeys = &fLastKeys[fKeyCount]; 122 if (fLastKeys == NULL) { 123 fStatus = B_NO_MEMORY; 124 return; 125 } 126 127 memset(fLastKeys, 0, fKeyCount * 2 * sizeof(uint16)); 128 129 // find leds if we have an output report 130 for (uint32 i = 0; i < MAX_LEDS; i++) 131 fLEDs[i] = NULL; 132 133 if (outputReport != NULL) { 134 for (uint32 i = 0; i < outputReport->CountItems(); i++) { 135 HIDReportItem *item = outputReport->ItemAt(i); 136 if (!item->HasData()) 137 continue; 138 139 // the led item array is identity mapped with what we get from 140 // the input_server for the set-leds command 141 if (item->UsagePage() == B_HID_USAGE_PAGE_LED) { 142 switch (item->UsageID()) { 143 case B_HID_UID_LED_NUM_LOCK: 144 fLEDs[0] = item; 145 break; 146 case B_HID_UID_LED_CAPS_LOCK: 147 fLEDs[1] = item; 148 break; 149 case B_HID_UID_LED_SCROLL_LOCK: 150 fLEDs[2] = item; 151 break; 152 } 153 } 154 } 155 } 156 157 #if KEYBOARD_SUPPORTS_KDL 158 if (atomic_add(&sDebuggerCommandAdded, 1) == 0) { 159 add_debugger_command("get_usb_keyboard_config", 160 &debug_get_keyboard_config, 161 "Gets the required config of the USB keyboard"); 162 } 163 #endif 164 } 165 166 167 KeyboardProtocolHandler::~KeyboardProtocolHandler() 168 { 169 free(fLastKeys); 170 171 #if KEYBOARD_SUPPORTS_KDL 172 if (atomic_add(&sDebuggerCommandAdded, -1) == 1) { 173 remove_debugger_command("get_usb_keyboard_config", 174 &debug_get_keyboard_config); 175 } 176 #endif 177 178 mutex_destroy(&fLock); 179 } 180 181 182 void 183 KeyboardProtocolHandler::AddHandlers(HIDDevice &device, 184 HIDCollection &collection, ProtocolHandler *&handlerList) 185 { 186 bool handled = false; 187 switch (collection.UsagePage()) { 188 case B_HID_USAGE_PAGE_GENERIC_DESKTOP: 189 { 190 switch (collection.UsageID()) { 191 case B_HID_UID_GD_KEYBOARD: 192 case B_HID_UID_GD_KEYPAD: 193 #if 0 194 // This is not specific enough to deserve a keyboard device on 195 // its own (some mice have one such descriptor, for example). 196 // If your keyboard uses this, do a more extensive check of 197 // the descriptor to make sure there actually are keys in it. 198 case B_HID_UID_GD_SYSTEM_CONTROL: 199 #endif 200 handled = true; 201 } 202 203 break; 204 } 205 206 case B_HID_USAGE_PAGE_CONSUMER: 207 { 208 switch (collection.UsageID()) { 209 case B_HID_UID_CON_CONSUMER_CONTROL: 210 handled = true; 211 } 212 213 break; 214 } 215 } 216 217 if (!handled) { 218 TRACE("collection not a supported keyboard subset\n"); 219 return; 220 } 221 222 HIDParser &parser = device.Parser(); 223 uint32 maxReportCount = parser.CountReports(HID_REPORT_TYPE_INPUT); 224 if (maxReportCount == 0) 225 return; 226 227 uint32 inputReportCount = 0; 228 HIDReport *inputReports[maxReportCount]; 229 collection.BuildReportList(HID_REPORT_TYPE_INPUT, inputReports, 230 inputReportCount); 231 232 TRACE("input report count: %" B_PRIu32 "\n", inputReportCount); 233 234 for (uint32 i = 0; i < inputReportCount; i++) { 235 HIDReport *inputReport = inputReports[i]; 236 237 // bool mayHaveOutput = false; 238 bool foundKeyboardUsage = false; 239 for (uint32 j = 0; j < inputReport->CountItems(); j++) { 240 HIDReportItem *item = inputReport->ItemAt(j); 241 if (!item->HasData()) 242 continue; 243 244 if (item->UsagePage() == B_HID_USAGE_PAGE_KEYBOARD 245 || (item->UsagePage() == B_HID_USAGE_PAGE_CONSUMER 246 && item->Array()) 247 || (item->UsagePage() == B_HID_USAGE_PAGE_BUTTON 248 && item->Array())) { 249 // found at least one item with a keyboard usage or with 250 // a consumer/button usage that is handled like a key 251 // mayHaveOutput = item->UsagePage() == B_HID_USAGE_PAGE_KEYBOARD; 252 foundKeyboardUsage = true; 253 break; 254 } 255 } 256 257 if (!foundKeyboardUsage) 258 continue; 259 260 bool foundOutputReport = false; 261 HIDReport *outputReport = NULL; 262 do { 263 // try to find the led output report 264 maxReportCount = parser.CountReports(HID_REPORT_TYPE_OUTPUT); 265 if (maxReportCount == 0) 266 break; 267 268 uint32 outputReportCount = 0; 269 HIDReport *outputReports[maxReportCount]; 270 collection.BuildReportList(HID_REPORT_TYPE_OUTPUT, 271 outputReports, outputReportCount); 272 273 for (uint32 j = 0; j < outputReportCount; j++) { 274 outputReport = outputReports[j]; 275 276 for (uint32 k = 0; k < outputReport->CountItems(); k++) { 277 HIDReportItem *item = outputReport->ItemAt(k); 278 if (item->UsagePage() == B_HID_USAGE_PAGE_LED) { 279 foundOutputReport = true; 280 break; 281 } 282 } 283 284 if (foundOutputReport) 285 break; 286 } 287 } while (false); 288 289 ProtocolHandler *newHandler = new(std::nothrow) KeyboardProtocolHandler( 290 *inputReport, foundOutputReport ? outputReport : NULL); 291 if (newHandler == NULL) { 292 TRACE("failed to allocated keyboard protocol handler\n"); 293 continue; 294 } 295 296 newHandler->SetNextHandler(handlerList); 297 handlerList = newHandler; 298 } 299 } 300 301 302 status_t 303 KeyboardProtocolHandler::Open(uint32 flags, uint32 *cookie) 304 { 305 status_t status = ProtocolHandler::Open(flags, cookie); 306 if (status != B_OK) { 307 TRACE_ALWAYS("keyboard device failed to open: %s\n", 308 strerror(status)); 309 return status; 310 } 311 312 if (Device()->OpenCount() == 1) { 313 fCurrentRepeatDelay = B_INFINITE_TIMEOUT; 314 fCurrentRepeatKey = 0; 315 } 316 317 return B_OK; 318 } 319 320 321 status_t 322 KeyboardProtocolHandler::Close(uint32 *cookie) 323 { 324 if ((*cookie & KEYBOARD_HANDLER_COOKIE_FLAG_DEBUGGER) != 0) 325 fHasDebugReader = false; 326 if ((*cookie & KEYBOARD_HANDLER_COOKIE_FLAG_READER) != 0) 327 atomic_and(&fHasReader, 0); 328 329 return ProtocolHandler::Close(cookie); 330 } 331 332 333 status_t 334 KeyboardProtocolHandler::Control(uint32 *cookie, uint32 op, void *buffer, 335 size_t length) 336 { 337 switch (op) { 338 case KB_READ: 339 { 340 if (*cookie == 0) { 341 if (atomic_or(&fHasReader, 1) != 0) 342 return B_BUSY; 343 344 // We're the first, so we become the only reader 345 *cookie = KEYBOARD_HANDLER_COOKIE_FLAG_READER; 346 } 347 348 while (true) { 349 MutexLocker locker(fLock); 350 351 bigtime_t enterTime = system_time(); 352 while (RingBufferReadable() == 0) { 353 status_t result = _ReadReport(fCurrentRepeatDelay, cookie); 354 if (result != B_OK && result != B_TIMED_OUT) 355 return result; 356 357 if (!Device()->IsOpen()) 358 return B_ERROR; 359 360 if (RingBufferReadable() == 0 && fCurrentRepeatKey != 0 361 && system_time() - enterTime > fCurrentRepeatDelay) { 362 // this case is for handling key repeats, it means no 363 // interrupt transfer has happened or it didn't produce 364 // any new key events, but a repeated key down is due 365 _WriteKey(fCurrentRepeatKey, true); 366 367 // the next timeout is reduced to the repeat_rate 368 fCurrentRepeatDelay = fRepeatRate; 369 break; 370 } 371 } 372 373 if (fHasDebugReader 374 && (*cookie & KEYBOARD_HANDLER_COOKIE_FLAG_DEBUGGER) 375 == 0) { 376 // Handover buffer to the debugger instead 377 locker.Unlock(); 378 snooze(25000); 379 continue; 380 } 381 382 if (!IS_USER_ADDRESS(buffer)) 383 return B_BAD_ADDRESS; 384 385 // process what is in the ring_buffer, it could be written 386 // there because we handled an interrupt transfer or because 387 // we wrote the current repeat key 388 return RingBufferRead(buffer, sizeof(raw_key_info)); 389 } 390 } 391 392 case KB_SET_LEDS: 393 { 394 uint8 ledData[4]; 395 if (!IS_USER_ADDRESS(buffer) 396 || user_memcpy(ledData, buffer, sizeof(ledData)) != B_OK) { 397 return B_BAD_ADDRESS; 398 } 399 return _SetLEDs(ledData); 400 } 401 402 case KB_SET_KEY_REPEAT_RATE: 403 { 404 int32 repeatRate; 405 if (!IS_USER_ADDRESS(buffer) 406 || user_memcpy(&repeatRate, buffer, sizeof(repeatRate)) 407 != B_OK) { 408 return B_BAD_ADDRESS; 409 } 410 411 if (repeatRate == 0 || repeatRate > 1000000) 412 return B_BAD_VALUE; 413 414 fRepeatRate = 10000000 / repeatRate; 415 return B_OK; 416 } 417 418 case KB_GET_KEY_REPEAT_RATE: 419 { 420 int32 repeatRate = 10000000 / fRepeatRate; 421 if (!IS_USER_ADDRESS(buffer) 422 || user_memcpy(buffer, &repeatRate, sizeof(repeatRate)) 423 != B_OK) { 424 return B_BAD_ADDRESS; 425 } 426 return B_OK; 427 } 428 429 case KB_SET_KEY_REPEAT_DELAY: 430 if (!IS_USER_ADDRESS(buffer) 431 || user_memcpy(&fRepeatDelay, buffer, sizeof(fRepeatDelay)) 432 != B_OK) { 433 return B_BAD_ADDRESS; 434 } 435 return B_OK; 436 437 case KB_GET_KEY_REPEAT_DELAY: 438 if (!IS_USER_ADDRESS(buffer) 439 || user_memcpy(buffer, &fRepeatDelay, sizeof(fRepeatDelay)) 440 != B_OK) { 441 return B_BAD_ADDRESS; 442 } 443 return B_OK; 444 445 case KB_SET_DEBUG_READER: 446 #if KEYBOARD_SUPPORTS_KDL 447 if (fHasDebugReader) 448 return B_BUSY; 449 450 *cookie |= KEYBOARD_HANDLER_COOKIE_FLAG_DEBUGGER; 451 fHasDebugReader = true; 452 return B_OK; 453 #else 454 return B_NOT_SUPPORTED; 455 #endif 456 } 457 458 TRACE_ALWAYS("keyboard device unhandled control 0x%08" B_PRIx32 "\n", op); 459 return B_ERROR; 460 } 461 462 463 void 464 KeyboardProtocolHandler::_WriteKey(uint32 key, bool down) 465 { 466 raw_key_info info; 467 info.keycode = key; 468 info.is_keydown = down; 469 info.timestamp = system_time(); 470 RingBufferWrite(&info, sizeof(raw_key_info)); 471 } 472 473 474 status_t 475 KeyboardProtocolHandler::_SetLEDs(uint8 *data) 476 { 477 if (fOutputReport == NULL || fOutputReport->Device()->IsRemoved()) 478 return B_ERROR; 479 480 for (uint32 i = 0; i < MAX_LEDS; i++) { 481 if (fLEDs[i] == NULL) 482 continue; 483 484 fLEDs[i]->SetData(data[i]); 485 } 486 487 return fOutputReport->SendReport(); 488 } 489 490 491 status_t 492 KeyboardProtocolHandler::_ReadReport(bigtime_t timeout, uint32 *cookie) 493 { 494 status_t result = fInputReport.WaitForReport(timeout); 495 if (result != B_OK) { 496 if (fInputReport.Device()->IsRemoved()) { 497 TRACE("device has been removed\n"); 498 return B_ERROR; 499 } 500 501 if ((*cookie & PROTOCOL_HANDLER_COOKIE_FLAG_CLOSED) != 0) 502 return B_CANCELED; 503 504 if (result != B_TIMED_OUT && result != B_INTERRUPTED) { 505 // we expect timeouts as we do repeat key handling this way, 506 // interrupts happen when other reports come in on the same 507 // endpoint 508 TRACE_ALWAYS("error waiting for report: %s\n", strerror(result)); 509 } 510 511 // signal that we simply want to try again 512 return B_OK; 513 } 514 515 TRACE("got keyboard input report\n"); 516 517 uint8 modifiers = 0; 518 for (uint32 i = 0; i < fModifierCount; i++) { 519 HIDReportItem *modifier = fModifiers[i]; 520 if (modifier == NULL) 521 break; 522 523 if (modifier->Extract() == B_OK && modifier->Valid()) { 524 modifiers |= (modifier->Data() & 1) 525 << (modifier->UsageID() - B_HID_UID_KB_LEFT_CONTROL); 526 } 527 } 528 529 for (uint32 i = 0; i < fKeyCount; i++) { 530 HIDReportItem *key = fKeys[i]; 531 if (key == NULL) 532 break; 533 534 if (key->Extract() == B_OK && key->Valid()) { 535 // handle both array and bitmap based keyboard reports 536 if (key->Array()) { 537 fCurrentKeys[i] = key->Data(); 538 } else { 539 if (key->Data() == 1) 540 fCurrentKeys[i] = key->UsageID(); 541 else 542 fCurrentKeys[i] = 0; 543 } 544 } 545 else 546 fCurrentKeys[i] = 0; 547 } 548 549 fInputReport.DoneProcessing(); 550 551 static const uint32 kModifierTable[] = { 552 KEY_ControlL, 553 KEY_ShiftL, 554 KEY_AltL, 555 KEY_WinL, 556 KEY_ControlR, 557 KEY_ShiftR, 558 KEY_AltR, 559 KEY_WinR 560 }; 561 562 // find modifier changes and push them into the buffer 563 uint8 modifierChange = fLastModifiers ^ modifiers; 564 for (uint8 i = 0; modifierChange; i++, modifierChange >>= 1) { 565 if (modifierChange & 1) 566 _WriteKey(kModifierTable[i], (modifiers >> i) & 1); 567 } 568 569 fLastModifiers = modifiers; 570 571 static const uint32 kKeyTable[] = { 572 0x00, // ERROR 573 0x00, // ERROR 574 0x00, // ERROR 575 0x00, // ERROR 576 0x3c, // A 577 0x50, // B 578 0x4e, // C 579 0x3e, // D 580 0x29, // E 581 0x3f, // F 582 0x40, // G 583 0x41, // H 584 0x2e, // I 585 0x42, // J 586 0x43, // K 587 0x44, // L 588 0x52, // M 589 0x51, // N 590 0x2f, // O 591 0x30, // P 592 0x27, // Q 593 0x2a, // R 594 0x3d, // S 595 0x2b, // T 596 0x2d, // U 597 0x4f, // V 598 0x28, // W 599 0x4d, // X 600 0x2c, // Y 601 0x4c, // Z 602 0x12, // 1 603 0x13, // 2 604 0x14, // 3 605 0x15, // 4 606 0x16, // 5 607 0x17, // 6 608 0x18, // 7 609 0x19, // 8 610 0x1a, // 9 611 0x1b, // 0 612 0x47, // enter 613 0x01, // Esc 614 0x1e, // Backspace 615 0x26, // Tab 616 0x5e, // Space 617 0x1c, // - 618 0x1d, // = 619 0x31, // [ 620 0x32, // ] 621 0x33, // backslash 622 0x33, // backslash 623 0x45, // ; 624 0x46, // ' 625 0x11, // ` 626 0x53, // , 627 0x54, // . 628 0x55, // / 629 KEY_CapsLock, // Caps 630 0x02, // F1 631 0x03, // F2 632 0x04, // F3 633 0x05, // F4 634 0x06, // F5 635 0x07, // F6 636 0x08, // F7 637 0x09, // F8 638 0x0a, // F9 639 0x0b, // F10 640 0x0c, // F11 641 0x0d, // F12 642 0x0e, // PrintScreen 643 KEY_Scroll, // Scroll Lock 644 KEY_Pause, // Pause (0x7f with Ctrl) 645 0x1f, // Insert 646 0x20, // Home 647 0x21, // Page up 648 0x34, // Delete 649 0x35, // End 650 0x36, // Page down 651 0x63, // Right arrow 652 0x61, // Left arrow 653 0x62, // Down arrow 654 0x57, // Up arrow 655 0x22, // Num Lock 656 0x23, // Pad / 657 0x24, // Pad * 658 0x25, // Pad - 659 0x3a, // Pad + 660 0x5b, // Pad Enter 661 0x58, // Pad 1 662 0x59, // Pad 2 663 0x5a, // Pad 3 664 0x48, // Pad 4 665 0x49, // Pad 5 666 0x4a, // Pad 6 667 0x37, // Pad 7 668 0x38, // Pad 8 669 0x39, // Pad 9 670 0x64, // Pad 0 671 0x65, // Pad . 672 0x69, // < 673 KEY_Menu, // Menu 674 KEY_Power, // Power 675 KEY_NumEqual, // Pad = 676 0x00, // F13 unmapped 677 0x00, // F14 unmapped 678 0x00, // F15 unmapped 679 0x00, // F16 unmapped 680 0x00, // F17 unmapped 681 0x00, // F18 unmapped 682 0x00, // F19 unmapped 683 0x00, // F20 unmapped 684 0x00, // F21 unmapped 685 0x00, // F22 unmapped 686 0x00, // F23 unmapped 687 0x00, // F24 unmapped 688 0x00, // Execute unmapped 689 0x00, // Help unmapped 690 0x00, // Menu unmapped 691 0x00, // Select unmapped 692 0x00, // Stop unmapped 693 0x00, // Again unmapped 694 0x00, // Undo unmapped 695 0x00, // Cut unmapped 696 0x00, // Copy unmapped 697 0x00, // Paste unmapped 698 0x00, // Find unmapped 699 0x00, // Mute unmapped 700 0x00, // Volume up unmapped 701 0x00, // Volume down unmapped 702 0x00, // CapsLock unmapped 703 0x00, // NumLock unmapped 704 0x00, // Scroll lock unmapped 705 0x70, // Keypad . on Brazilian ABNT2 706 0x00, // = sign 707 0x6b, // Ro (\\ key, japanese) 708 0x6e, // Katakana/Hiragana, second key right to spacebar, japanese 709 0x6a, // Yen (macron key, japanese) 710 0x6d, // Henkan, first key right to spacebar, japanese 711 0x6c, // Muhenkan, key left to spacebar, japanese 712 0x00, // Keyboard International6 unmapped 713 0x00, // Keyboard International7 unmapped 714 0x00, // Keyboard International8 unmapped 715 0x00, // Keyboard International9 unmapped 716 0xf0, // Hangul, korean, Kana, Mac japanese USB 717 0xf1, // Hangul_Hanja, korean, Eisu, Mac japanese USB 718 }; 719 720 static const size_t kKeyTableSize 721 = sizeof(kKeyTable) / sizeof(kKeyTable[0]); 722 723 bool phantomState = true; 724 for (size_t i = 0; i < fKeyCount; i++) { 725 if (fCurrentKeys[i] != 1 726 || fKeys[i]->UsagePage() != B_HID_USAGE_PAGE_KEYBOARD) { 727 phantomState = false; 728 break; 729 } 730 } 731 732 if (phantomState) { 733 // no valid key information is present in this state and we don't 734 // want to overwrite our last buffer as otherwise we generate 735 // spurious key ups now and spurious key downs when leaving the 736 // phantom state again 737 return B_OK; 738 } 739 740 static bool sysReqPressed = false; 741 742 bool keyDown = false; 743 uint16 *current = fLastKeys; 744 uint16 *compare = fCurrentKeys; 745 for (int32 twice = 0; twice < 2; twice++) { 746 for (size_t i = 0; i < fKeyCount; i++) { 747 if (current[i] == 0 || (current[i] == 1 748 && fKeys[i]->UsagePage() == B_HID_USAGE_PAGE_KEYBOARD)) 749 continue; 750 751 bool found = false; 752 for (size_t j = 0; j < fKeyCount; j++) { 753 if (compare[j] == current[i]) { 754 found = true; 755 break; 756 } 757 } 758 759 if (found) 760 continue; 761 762 // a change occured 763 uint32 key = 0; 764 if (fKeys[i]->UsagePage() == B_HID_USAGE_PAGE_KEYBOARD) { 765 if (current[i] < kKeyTableSize) 766 key = kKeyTable[current[i]]; 767 768 if (key == KEY_Pause && (modifiers & ALT_KEYS) != 0) 769 key = KEY_Break; 770 else if (key == 0xe && (modifiers & ALT_KEYS) != 0) { 771 key = KEY_SysRq; 772 sysReqPressed = keyDown; 773 } else if (sysReqPressed && keyDown 774 && current[i] >= 4 && current[i] <= 29 775 && (fLastModifiers & ALT_KEYS) != 0) { 776 // Alt-SysReq+letter was pressed 777 #if KEYBOARD_SUPPORTS_KDL 778 sDebugKeyboardPipe 779 = fInputReport.Device()->InterruptPipe(); 780 sDebugKeyboardReportSize 781 = fInputReport.Parser()->MaxReportSize(); 782 #endif 783 784 char letter = current[i] - 4 + 'a'; 785 786 if (debug_emergency_key_pressed(letter)) { 787 // we probably have lost some keys, so reset our key 788 // state 789 sysReqPressed = false; 790 continue; 791 } 792 } 793 } 794 795 if (key == 0) { 796 // unmapped normal key or consumer/button key 797 key = fInputReport.Usages()[0] + current[i]; 798 } 799 800 _WriteKey(key, keyDown); 801 802 if (keyDown) { 803 // repeat handling 804 fCurrentRepeatKey = key; 805 fCurrentRepeatDelay = fRepeatDelay; 806 } else { 807 // cancel the repeats if they are for this key 808 if (fCurrentRepeatKey == key) { 809 fCurrentRepeatDelay = B_INFINITE_TIMEOUT; 810 fCurrentRepeatKey = 0; 811 } 812 } 813 } 814 815 current = fCurrentKeys; 816 compare = fLastKeys; 817 keyDown = true; 818 } 819 820 memcpy(fLastKeys, fCurrentKeys, fKeyCount * sizeof(uint16)); 821 return B_OK; 822 } 823