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