Compare commits

..

3 Commits

Author SHA1 Message Date
Marc Brooks 3818ac3df1
Merge 0321a7473a into 703625d59a 2025-09-25 23:39:13 +02:00
Marc Brooks 0321a7473a
Move the HID keyboard descriptor LED state
Seems to interfere with boot mode
2025-09-25 16:36:28 -05:00
Marc Brooks 704d65bde6
Reduce traffic during pastes
Suspend KeyDownMessages while processing a macro.
Make sure we don't emit huge debugging traces.
Allow 30 seconds for RPC to finish (not ideal)
Reduced default delay between keys (and allow as low as 0)
2025-09-25 12:25:10 -05:00
2 changed files with 38 additions and 13 deletions

View File

@ -31,6 +31,8 @@ var keyboardReportDesc = []byte{
0x05, 0x01, /* USAGE_PAGE (Generic Desktop) */ 0x05, 0x01, /* USAGE_PAGE (Generic Desktop) */
0x09, 0x06, /* USAGE (Keyboard) */ 0x09, 0x06, /* USAGE (Keyboard) */
0xa1, 0x01, /* COLLECTION (Application) */ 0xa1, 0x01, /* COLLECTION (Application) */
/* 8 modifier bits */
0x05, 0x07, /* USAGE_PAGE (Keyboard) */ 0x05, 0x07, /* USAGE_PAGE (Keyboard) */
0x19, 0xe0, /* USAGE_MINIMUM (Keyboard LeftControl) */ 0x19, 0xe0, /* USAGE_MINIMUM (Keyboard LeftControl) */
0x29, 0xe7, /* USAGE_MAXIMUM (Keyboard Right GUI) */ 0x29, 0xe7, /* USAGE_MAXIMUM (Keyboard Right GUI) */
@ -39,27 +41,47 @@ var keyboardReportDesc = []byte{
0x75, 0x01, /* REPORT_SIZE (1) */ 0x75, 0x01, /* REPORT_SIZE (1) */
0x95, 0x08, /* REPORT_COUNT (8) */ 0x95, 0x08, /* REPORT_COUNT (8) */
0x81, 0x02, /* INPUT (Data,Var,Abs) */ 0x81, 0x02, /* INPUT (Data,Var,Abs) */
/* 8 bits of padding */
0x95, 0x01, /* REPORT_COUNT (1) */ 0x95, 0x01, /* REPORT_COUNT (1) */
0x75, 0x08, /* REPORT_SIZE (8) */ 0x75, 0x08, /* REPORT_SIZE (8) */
0x81, 0x03, /* INPUT (Cnst,Var,Abs) */ 0x81, 0x03, /* INPUT (Cnst,Var,Abs) */
/* 6 key codes for the 104 key keyboard */
0x95, 0x06, /* REPORT_COUNT (6) */
0x75, 0x08, /* REPORT_SIZE (8) */
0x15, 0x00, /* LOGICAL_MINIMUM (0) */
0x25, 0xE7, /* LOGICAL_MAXIMUM (104-key HID) */
0x05, 0x07, /* USAGE_PAGE (Keyboard) */
0x19, 0x00, /* USAGE_MINIMUM (Reserved) */
0x29, 0xE7, /* USAGE_MAXIMUM (Keyboard Right GUI) */
0x81, 0x00, /* INPUT (Data,Ary,Abs) */
/* LED report 5 bits for Num Lock through Kana */
0x95, 0x05, /* REPORT_COUNT (5) */ 0x95, 0x05, /* REPORT_COUNT (5) */
0x75, 0x01, /* REPORT_SIZE (1) */ 0x75, 0x01, /* REPORT_SIZE (1) */
0x05, 0x08, /* USAGE_PAGE (LEDs) */ 0x05, 0x08, /* USAGE_PAGE (LEDs) */
0x19, 0x01, /* USAGE_MINIMUM (Num Lock) */ 0x19, 0x01, /* USAGE_MINIMUM (Num Lock) */
0x29, 0x05, /* USAGE_MAXIMUM (Kana) */ 0x29, 0x05, /* USAGE_MAXIMUM (Kana) */
0x91, 0x02, /* OUTPUT (Data,Var,Abs) */ 0x91, 0x02, /* OUTPUT (Data,Var,Abs) */
/* 1 bit of padding for the Power LED (ignored) */
0x95, 0x01, /* REPORT_COUNT (1) */ 0x95, 0x01, /* REPORT_COUNT (1) */
0x75, 0x03, /* REPORT_SIZE (3) */ 0x75, 0x03, /* REPORT_SIZE (1) */
0x91, 0x03, /* OUTPUT (Cnst,Var,Abs) */
/* LED report 1 bit for Shift */
0x95, 0x01, /* REPORT_COUNT (1) */
0x75, 0x01, /* REPORT_SIZE (1) */
0x05, 0x08, /* USAGE_PAGE (LEDs) */
0x19, 0x07, /* USAGE_MINIMUM (Shift) */
0x29, 0x07, /* USAGE_MAXIMUM (Shift) */
0x91, 0x02, /* OUTPUT (Data,Var,Abs) */
/* 1 bit of padding for the rest of the byte */
0x95, 0x01, /* REPORT_COUNT (1) */
0x75, 0x03, /* REPORT_SIZE (1) */
0x91, 0x03, /* OUTPUT (Cnst,Var,Abs) */ 0x91, 0x03, /* OUTPUT (Cnst,Var,Abs) */
0x95, 0x06, /* REPORT_COUNT (6) */
0x75, 0x08, /* REPORT_SIZE (8) */
0x15, 0x00, /* LOGICAL_MINIMUM (0) */
0x25, 0x65, /* LOGICAL_MAXIMUM (101) */
0x05, 0x07, /* USAGE_PAGE (Keyboard) */
0x19, 0x00, /* USAGE_MINIMUM (Reserved) */
0x29, 0x65, /* USAGE_MAXIMUM (Keyboard Application) */
0x81, 0x00, /* INPUT (Data,Ary,Abs) */
0xc0, /* END_COLLECTION */ 0xc0, /* END_COLLECTION */
} }
@ -324,6 +346,7 @@ var keyboardWriteHidFileLock sync.Mutex
func (u *UsbGadget) keyboardWriteHidFile(modifier byte, keys []byte) error { func (u *UsbGadget) keyboardWriteHidFile(modifier byte, keys []byte) error {
keyboardWriteHidFileLock.Lock() keyboardWriteHidFileLock.Lock()
defer keyboardWriteHidFileLock.Unlock() defer keyboardWriteHidFileLock.Unlock()
if err := u.openKeyboardHidFile(); err != nil { if err := u.openKeyboardHidFile(); err != nil {
return err return err
} }
@ -494,6 +517,10 @@ func (u *UsbGadget) keypressReport(key byte, press bool) (KeysDownState, error)
} }
err := u.keyboardWriteHidFile(modifier, keys) err := u.keyboardWriteHidFile(modifier, keys)
if err != nil {
u.log.Warn().Uint8("modifier", modifier).Uints8("keys", keys).Msg("Could not write keyboard report to hidg0")
}
return u.UpdateKeysDown(modifier, keys), err return u.UpdateKeysDown(modifier, keys), err
} }

View File

@ -277,7 +277,6 @@ export default function useKeyboard() {
cancelKeepAlive(); cancelKeepAlive();
}, [cancelKeepAlive]); }, [cancelKeepAlive]);
// executeMacro is used to execute a macro consisting of multiple steps. // executeMacro is used to execute a macro consisting of multiple steps.
// Each step can have multiple keys, multiple modifiers and a delay. // Each step can have multiple keys, multiple modifiers and a delay.
// The keys and modifiers are pressed together and held for the delay duration. // The keys and modifiers are pressed together and held for the delay duration.
@ -292,9 +291,7 @@ export default function useKeyboard() {
for (const [_, step] of steps.entries()) { for (const [_, step] of steps.entries()) {
const keyValues = (step.keys || []).map(key => keys[key]).filter(Boolean); const keyValues = (step.keys || []).map(key => keys[key]).filter(Boolean);
const modifierMask: number = (step.modifiers || []) const modifierMask: number = (step.modifiers || [])
.map(mod => modifiers[mod]) .map(mod => modifiers[mod])
.reduce((acc, val) => acc + val, 0); .reduce((acc, val) => acc + val, 0);
// If the step has keys and/or modifiers, press them and hold for the delay // If the step has keys and/or modifiers, press them and hold for the delay
@ -306,6 +303,7 @@ export default function useKeyboard() {
sendKeyboardMacroEventHidRpc(macro); sendKeyboardMacroEventHidRpc(macro);
}, [sendKeyboardMacroEventHidRpc]); }, [sendKeyboardMacroEventHidRpc]);
const executeMacroClientSide = useCallback(async (steps: MacroSteps) => { const executeMacroClientSide = useCallback(async (steps: MacroSteps) => {
const promises: (() => Promise<void>)[] = []; const promises: (() => Promise<void>)[] = [];