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