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
debug_get_keyboard_config(int argc,char ** argv)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
KeyboardProtocolHandler(HIDReport & inputReport,HIDReport * outputReport)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
~KeyboardProtocolHandler()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
AddHandlers(HIDDevice & device,HIDCollection & collection,ProtocolHandler * & handlerList)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
Open(uint32 flags,uint32 * cookie)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
Close(uint32 * cookie)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
Control(uint32 * cookie,uint32 op,void * buffer,size_t length)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
_WriteKey(uint32 key,bool down)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
_SetLEDs(uint8 * data)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
_ReadReport(bigtime_t timeout,uint32 * cookie)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