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