Skip to content

Commit 2696067

Browse files
committed
Clean up the keyboard HID report
Was declaring too much output breaking boot keyboard on some devices. Got rid of the lockec-Shift LED. Added a short snooze when we get errors reading the LED state.
1 parent cd5cd38 commit 2696067

File tree

4 files changed

+86
-87
lines changed

4 files changed

+86
-87
lines changed

internal/usbgadget/hid_keyboard.go

Lines changed: 39 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -28,61 +28,50 @@ var keyboardConfig = gadgetConfigItem{
2828

2929
// Source: https://www.kernel.org/doc/Documentation/usb/gadget_hid.txt
3030
var keyboardReportDesc = []byte{
31-
0x05, 0x01, /* USAGE_PAGE (Generic Desktop) */
32-
0x09, 0x06, /* USAGE (Keyboard) */
33-
0xa1, 0x01, /* COLLECTION (Application) */
31+
/* boot mode descriptor */
32+
0x05, 0x01, /* USAGE_PAGE-global (Generic Desktop) */
33+
0x09, 0x06, /* USAGE-local (Keyboard) */
34+
0xA1, 0x01, /* COLLECTION-main (Application) */
3435

3536
/* 8 modifier bits */
36-
0x05, 0x07, /* USAGE_PAGE (Keyboard) */
37-
0x19, 0xe0, /* USAGE_MINIMUM (Keyboard LeftControl) */
38-
0x29, 0xe7, /* USAGE_MAXIMUM (Keyboard Right GUI) */
39-
0x15, 0x00, /* LOGICAL_MINIMUM (0) */
40-
0x25, 0x01, /* LOGICAL_MAXIMUM (1) */
41-
0x75, 0x01, /* REPORT_SIZE (1) */
42-
0x95, 0x08, /* REPORT_COUNT (8) */
43-
0x81, 0x02, /* INPUT (Data,Var,Abs) */
37+
0x05, 0x07, /* USAGE_PAGE-global (Keyboard) */
38+
0x19, 0xe0, /* USAGE_MINIMUM-local 0xE0 (Keyboard LeftControl) */
39+
0x29, 0xe7, /* USAGE_MAXIMUM-local 0xE7 (Keyboard Right GUI) */
40+
0x15, 0x00, /* LOGICAL_MINIMUM-global (0) Modifier bit off) */
41+
0x25, 0x01, /* LOGICAL_MAXIMUM-global (1) Modifier bit on) */
42+
0x75, 0x01, /* REPORT_SIZE-global (1) one bit per modifier */
43+
0x95, 0x08, /* REPORT_COUNT-global (8) 8 total bits */
44+
0x81, 0x02, /* INPUT-main (Data,Var,Abs) Modifier bits 0-7 */
4445

4546
/* 8 bits of padding */
46-
0x95, 0x01, /* REPORT_COUNT (1) */
47-
0x75, 0x08, /* REPORT_SIZE (8) */
48-
0x81, 0x03, /* INPUT (Cnst,Var,Abs) */
47+
0x95, 0x01, /* REPORT_COUNT-global (1) one field */
48+
0x75, 0x08, /* REPORT_SIZE-global (8) */
49+
0x81, 0x03, /* INPUT-main (Cnst,Var,Abs) reserved byte */
4950

5051
/* 6 key codes for the 104 key keyboard */
51-
0x95, 0x06, /* REPORT_COUNT (6) */
52-
0x75, 0x08, /* REPORT_SIZE (8) */
53-
0x15, 0x00, /* LOGICAL_MINIMUM (0) */
54-
0x25, 0xE7, /* LOGICAL_MAXIMUM (104-key HID) */
55-
0x05, 0x07, /* USAGE_PAGE (Keyboard) */
56-
0x19, 0x00, /* USAGE_MINIMUM (Reserved) */
57-
0x29, 0xE7, /* USAGE_MAXIMUM (Keyboard Right GUI) */
58-
0x81, 0x00, /* INPUT (Data,Ary,Abs) */
52+
0x95, 0x06, /* REPORT_COUNT-global (6) keycodes */
53+
0x75, 0x08, /* REPORT_SIZE-global (8) bits each (a byte) */
54+
0x15, 0x00, /* LOGICAL_MINIMUM-global (0) */
55+
0x25, 0xDF, /* LOGICAL_MAXIMUM-global 0xDF (104-key HID codes) */
56+
0x05, 0x07, /* USAGE_PAGE-global (Keyboard) */
57+
0x19, 0x00, /* USAGE_MINIMUM-local (Reserved/0) no key */
58+
0x29, 0xE7, /* USAGE_MAXIMUM-local (Keyboard Right GUI) */
59+
0x81, 0x00, /* INPUT-main (Data,Ary,Abs) array of keycodes */
5960

6061
/* LED report 5 bits for Num Lock through Kana */
61-
0x95, 0x05, /* REPORT_COUNT (5) */
62-
0x75, 0x01, /* REPORT_SIZE (1) */
63-
0x05, 0x08, /* USAGE_PAGE (LEDs) */
64-
0x19, 0x01, /* USAGE_MINIMUM (Num Lock) */
65-
0x29, 0x05, /* USAGE_MAXIMUM (Kana) */
66-
0x91, 0x02, /* OUTPUT (Data,Var,Abs) */
67-
68-
/* 1 bit of padding for the Power LED (ignored) */
69-
0x95, 0x01, /* REPORT_COUNT (1) */
70-
0x75, 0x03, /* REPORT_SIZE (3) */
71-
0x91, 0x03, /* OUTPUT (Cnst,Var,Abs) */
72-
73-
/* LED report 1 bit for Shift */
74-
0x95, 0x01, /* REPORT_COUNT (1) */
75-
0x75, 0x01, /* REPORT_SIZE (1) */
76-
0x05, 0x08, /* USAGE_PAGE (LEDs) */
77-
0x19, 0x07, /* USAGE_MINIMUM (Shift) */
78-
0x29, 0x07, /* USAGE_MAXIMUM (Shift) */
79-
0x91, 0x02, /* OUTPUT (Data,Var,Abs) */
80-
81-
/* 1 bit of padding for the rest of the byte */
82-
0x95, 0x01, /* REPORT_COUNT (1) */
83-
0x75, 0x03, /* REPORT_SIZE (3) */
84-
0x91, 0x03, /* OUTPUT (Cnst,Var,Abs) */
85-
0xc0, /* END_COLLECTION */
62+
0x95, 0x05, /* REPORT_COUNT-global (5) 5 LED bits */
63+
0x75, 0x01, /* REPORT_SIZE-global (1) each 1 bit */
64+
0x05, 0x08, /* USAGE_PAGE-global (LEDs) */
65+
0x19, 0x01, /* USAGE_MINIMUM-local (Num Lock) */
66+
0x29, 0x05, /* USAGE_MAXIMUM-local (Kana) */
67+
0x91, 0x02, /* OUTPUT-main (Data,Var,Abs) bits 0-4 */
68+
69+
/* 3 bits of padding for the rest of the byte */
70+
0x95, 0x01, /* REPORT_COUNT-global (1) one field */
71+
0x75, 0x03, /* REPORT_SIZE-global (3) of three bits */
72+
0x91, 0x03, /* OUTPUT-main (Cnst,Var,Abs) bit 7 pad */
73+
74+
0xC0, /* END_COLLECTION */
8675
}
8776

8877
const (
@@ -96,9 +85,7 @@ const (
9685
KeyboardLedMaskScrollLock = 1 << 2
9786
KeyboardLedMaskCompose = 1 << 3
9887
KeyboardLedMaskKana = 1 << 4
99-
// power on/off LED is 5
100-
KeyboardLedMaskShift = 1 << 6
101-
ValidKeyboardLedMasks = KeyboardLedMaskNumLock | KeyboardLedMaskCapsLock | KeyboardLedMaskScrollLock | KeyboardLedMaskCompose | KeyboardLedMaskKana | KeyboardLedMaskShift
88+
ValidKeyboardLedMasks = KeyboardLedMaskNumLock | KeyboardLedMaskCapsLock | KeyboardLedMaskScrollLock | KeyboardLedMaskCompose | KeyboardLedMaskKana
10289
)
10390

10491
// Synchronization between LED states and CAPS LOCK, NUM LOCK, SCROLL LOCK,
@@ -111,7 +98,6 @@ type KeyboardState struct {
11198
ScrollLock bool `json:"scroll_lock"`
11299
Compose bool `json:"compose"`
113100
Kana bool `json:"kana"`
114-
Shift bool `json:"shift"` // This is not part of the main USB HID spec
115101
raw byte
116102
}
117103

@@ -128,7 +114,6 @@ func getKeyboardState(b byte) KeyboardState {
128114
ScrollLock: b&KeyboardLedMaskScrollLock != 0,
129115
Compose: b&KeyboardLedMaskCompose != 0,
130116
Kana: b&KeyboardLedMaskKana != 0,
131-
Shift: b&KeyboardLedMaskShift != 0,
132117
raw: b,
133118
}
134119
}
@@ -295,12 +280,13 @@ func (u *UsbGadget) listenKeyboardEvents() {
295280
time.Sleep(time.Second)
296281
continue
297282
}
298-
// reset the counter
283+
// reset the suppression counter
299284
u.resetLogSuppressionCounter("keyboardHidFileNil")
300285

301286
n, err := u.keyboardHidFile.Read(buf)
302287
if err != nil {
303288
u.logWithSuppression("keyboardHidFileRead", 100, &l, err, "failed to read")
289+
time.Sleep(100 * time.Millisecond) // Small backoff on read errors to avoid tight looping
304290
continue
305291
}
306292
u.resetLogSuppressionCounter("keyboardHidFileRead")

ui/src/components/InfoBar.tsx

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -166,10 +166,6 @@ export default function InfoBar() {
166166
{keyboardLedState.kana ? (
167167
<div className="shrink-0 p-1 px-1.5 text-xs">{m.info_kana()}</div>
168168
) : null}
169-
170-
{keyboardLedState.shift ? (
171-
<div className="shrink-0 p-1 px-1.5 text-xs">{m.info_shift()}</div>
172-
) : null}
173169
</div>
174170
</div>
175171
</div>

ui/src/hooks/stores.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -473,7 +473,6 @@ export interface KeyboardLedState {
473473
scroll_lock: boolean;
474474
compose: boolean;
475475
kana: boolean;
476-
shift: boolean; // Optional, as not all keyboards have a shift LED
477476
};
478477

479478
export const hidKeyBufferSize = 6;
@@ -509,7 +508,7 @@ export interface HidState {
509508
}
510509

511510
export const useHidStore = create<HidState>(set => ({
512-
keyboardLedState: { num_lock: false, caps_lock: false, scroll_lock: false, compose: false, kana: false, shift: false } as KeyboardLedState,
511+
keyboardLedState: { num_lock: false, caps_lock: false, scroll_lock: false, compose: false, kana: false } as KeyboardLedState,
513512
setKeyboardLedState: (ledState: KeyboardLedState): void => set({ keyboardLedState: ledState }),
514513

515514
keysDownState: { modifier: 0, keys: [0, 0, 0, 0, 0, 0] } as KeysDownState,

ui/src/keyboardMappings.ts

Lines changed: 46 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,12 @@
33
// [Universal Serial Bus HID Usage Tables: Section 10](https://www.usb.org/sites/default/files/documents/hut1_12v2.pdf)
44
// These are all the key codes (not scan codes) that an 85/101/102 keyboard might have on it
55
export const keys = {
6-
Again: 0x79,
6+
Again: 0x79, // aka Clear
77
AlternateErase: 0x9d,
88
AltGr: 0xe6, // aka AltRight
99
AltLeft: 0xe2,
1010
AltRight: 0xe6,
11-
Application: 0x65,
11+
Application: 0x65, // aka ContextMenu
1212
ArrowDown: 0x51,
1313
ArrowLeft: 0x50,
1414
ArrowRight: 0x4f,
@@ -25,11 +25,10 @@ export const keys = {
2525
ClearAgain: 0xa2,
2626
Comma: 0x36,
2727
Compose: 0xe3,
28-
ContextMenu: 0x65,
2928
ControlLeft: 0xe0,
3029
ControlRight: 0xe4,
3130
Copy: 0x7c,
32-
CrSel: 0xa3,
31+
CrSel: 0xa3, // aka Props
3332
CurrencySubunit: 0xb5,
3433
CurrencyUnit: 0xb4,
3534
Cut: 0x7b,
@@ -49,7 +48,7 @@ export const keys = {
4948
Enter: 0x28,
5049
Equal: 0x2e,
5150
Escape: 0x29,
52-
Execute: 0x74,
51+
Execute: 0x74, // aka Open
5352
ExSel: 0xa4,
5453
F1: 0x3a,
5554
F2: 0x3b,
@@ -77,14 +76,14 @@ export const keys = {
7776
F24: 0x73,
7877
Find: 0x7e,
7978
Grave: 0x35,
80-
HashTilde: 0x32, // non-US # and ~
79+
HashTilde: 0x32, // non-US # and ~ (typically near Enter key)
8180
Help: 0x75,
8281
Home: 0x4a,
8382
Insert: 0x49,
8483
International7: 0x8d,
8584
International8: 0x8e,
8685
International9: 0x8f,
87-
IntlBackslash: 0x64, // non-US \ and |
86+
IntlBackslash: 0x64, // non-US \ and | (typically near Left Shift key)
8887
KeyA: 0x04,
8988
KeyB: 0x05,
9089
KeyC: 0x06,
@@ -111,27 +110,47 @@ export const keys = {
111110
KeyX: 0x1b,
112111
KeyY: 0x1c,
113112
KeyZ: 0x1d,
114-
KeyRO: 0x87,
115-
KatakanaHiragana: 0x88,
116-
Yen: 0x89,
117-
Henkan: 0x8a,
118-
Muhenkan: 0x8b,
119-
KPJPComma: 0x8c,
120-
Hangeul: 0x90,
121-
Hanja: 0x91,
122-
Katakana: 0x92,
123-
Hiragana: 0x93,
124-
ZenkakuHankaku: 0x94,
113+
RO: 0x87, // aka International1
114+
KatakanaHiragana: 0x88, // aka International2
115+
Yen: 0x89, // aka International3
116+
Henkan: 0x8a, // aka International4
117+
Muhenkan: 0x8b, // aka International5
118+
KPJPComma: 0x8c, // aka International6
119+
Hangeul: 0x90, // aka Lang1
120+
Hanja: 0x91, // aka Lang2
121+
Katakana: 0x92, // aka Lang3
122+
Hiragana: 0x93, // aka Lang4
123+
ZenkakuHankaku: 0x94, // aka Lang5
125124
LockingCapsLock: 0x82,
126125
LockingNumLock: 0x83,
127126
LockingScrollLock: 0x84,
128127
Lang6: 0x95,
129128
Lang7: 0x96,
130129
Lang8: 0x97,
131130
Lang9: 0x98,
131+
MediaBack: 0xF1,
132+
MediaCalc: 0xFB,
133+
MediaCoffee: 0xF9,
134+
MediaEdit: 0xF7,
135+
MediaEjectCD: 0xEC,
136+
MediaFind: 0xF4,
137+
MediaForward: 0xF2,
138+
MediaMute: 0xEF,
139+
MediaNextSong: 0xEB,
140+
MediaPlayPause: 0xE8,
141+
MediaPreviousSong: 0xEA,
142+
MediaRefresh: 0xFA,
143+
MediaScrollDown: 0xF6,
144+
MediaScrollUp: 0xF5,
145+
MediaSleep: 0xF8,
146+
MediaStop: 0xF3,
147+
MediaStopCD: 0xE9,
148+
MediaVolumeDown: 0xEE,
149+
MediaVolumeUp: 0xED,
150+
MediaWWW: 0xF0,
132151
Menu: 0x76,
133-
MetaLeft: 0xe3,
134-
MetaRight: 0xe7,
152+
MetaLeft: 0xe3, // aka LeftGUI
153+
MetaRight: 0xe7, // aka RightGUI
135154
Minus: 0x2d,
136155
Mute: 0x7f,
137156
NumLock: 0x53, // and Clear
@@ -157,9 +176,8 @@ export const keys = {
157176
NumpadClearEntry: 0xd9,
158177
NumpadColon: 0xcb,
159178
NumpadComma: 0x85,
160-
NumpadDecimal: 0x63, // and Delete
179+
NumpadDecimal: 0x63, // and NumpadDelete
161180
NumpadDecimalBase: 0xdc,
162-
NumpadDelete: 0x63,
163181
NumpadDivide: 0x54,
164182
NumpadDownArrow: 0x5a,
165183
NumpadEnd: 0x59,
@@ -211,14 +229,14 @@ export const keys = {
211229
PageUp: 0x4b,
212230
Paste: 0x7d,
213231
Pause: 0x48,
214-
Period: 0x37, // aka Dot
232+
Period: 0x37, // aka Dot
215233
Power: 0x66,
216-
PrintScreen: 0x46,
234+
PrintScreen: 0x46, // aka SysRq
217235
Prior: 0x9d,
218-
Quote: 0x34, // aka Single Quote or Apostrophe
236+
Quote: 0x34, // aka Single Quote or Apostrophe
219237
Return: 0x9e,
220-
ScrollLock: 0x47,
221-
Select: 0x77,
238+
ScrollLock: 0x47, // aka ScrLk
239+
Select: 0x77, // aka Front
222240
Semicolon: 0x33,
223241
Separator: 0x9f,
224242
ShiftLeft: 0xe1,
@@ -240,7 +258,7 @@ export const deadKeys = {
240258
Breve: 0x02d8,
241259
Caron: 0x02c7,
242260
Cedilla: 0x00b8,
243-
Circumflex: 0x005e, // or 0x02c6?
261+
Circumflex: 0x02c6,
244262
Comma: 0x002c,
245263
Dot: 0x00b7,
246264
DoubleAcute: 0x02dd,

0 commit comments

Comments
 (0)