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