Skip to content

Commit 704d65b

Browse files
committed
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)
1 parent 703625d commit 704d65b

File tree

5 files changed

+37
-17
lines changed

5 files changed

+37
-17
lines changed

hidrpc.go

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -65,15 +65,17 @@ func handleHidRPCMessage(message hidrpc.Message, session *Session) {
6565

6666
func onHidMessage(msg hidQueueMessage, session *Session) {
6767
data := msg.Data
68+
dataLen := len(data)
6869

6970
scopedLogger := hidRPCLogger.With().
7071
Str("channel", msg.channel).
71-
Bytes("data", data).
72+
Int("data_len", dataLen).
73+
Bytes("data", data[:min(dataLen, 32)]).
7274
Logger()
7375
scopedLogger.Debug().Msg("HID RPC message received")
7476

75-
if len(data) < 1 {
76-
scopedLogger.Warn().Int("length", len(data)).Msg("received empty data in HID RPC message handler")
77+
if dataLen < 1 {
78+
scopedLogger.Warn().Msg("received empty data in HID RPC message handler")
7779
return
7880
}
7981

@@ -96,7 +98,7 @@ func onHidMessage(msg hidQueueMessage, session *Session) {
9698
r <- nil
9799
}()
98100
select {
99-
case <-time.After(1 * time.Second):
101+
case <-time.After(30 * time.Second):
100102
scopedLogger.Warn().Msg("HID RPC message timed out")
101103
case <-r:
102104
scopedLogger.Debug().Dur("duration", time.Since(t)).Msg("HID RPC message handled")

internal/usbgadget/hid_keyboard.go

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -55,10 +55,10 @@ var keyboardReportDesc = []byte{
5555
0x95, 0x06, /* REPORT_COUNT (6) */
5656
0x75, 0x08, /* REPORT_SIZE (8) */
5757
0x15, 0x00, /* LOGICAL_MINIMUM (0) */
58-
0x25, 0x65, /* LOGICAL_MAXIMUM (101) */
58+
0x25, 104, /* LOGICAL_MAXIMUM (104-key) */
5959
0x05, 0x07, /* USAGE_PAGE (Keyboard) */
6060
0x19, 0x00, /* USAGE_MINIMUM (Reserved) */
61-
0x29, 0x65, /* USAGE_MAXIMUM (Keyboard Application) */
61+
0x29, 0xE7, /* USAGE_MAXIMUM (Keyboard Right GUI) */
6262
0x81, 0x00, /* INPUT (Data,Ary,Abs) */
6363
0xc0, /* END_COLLECTION */
6464
}
@@ -153,6 +153,16 @@ func (u *UsbGadget) SetOnKeysDownChange(f func(state KeysDownState)) {
153153
u.onKeysDownChange = &f
154154
}
155155

156+
var suspendedKeyDownMessages bool = false
157+
158+
func (u *UsbGadget) SuspendKeyDownMessages() {
159+
suspendedKeyDownMessages = true
160+
}
161+
162+
func (u *UsbGadget) ResumeSuspendKeyDownMessages() {
163+
suspendedKeyDownMessages = false
164+
}
165+
156166
func (u *UsbGadget) SetOnKeepAliveReset(f func()) {
157167
u.onKeepAliveReset = &f
158168
}
@@ -169,9 +179,9 @@ func (u *UsbGadget) scheduleAutoRelease(key byte) {
169179
}
170180

171181
// TODO: make this configurable
172-
// We currently hardcode the duration to 100ms
182+
// We currently hardcode the duration to the default of 100ms
173183
// However, it should be the same as the duration of the keep-alive reset called baseExtension.
174-
u.kbdAutoReleaseTimers[key] = time.AfterFunc(100*time.Millisecond, func() {
184+
u.kbdAutoReleaseTimers[key] = time.AfterFunc(DefaultAutoReleaseDuration, func() {
175185
u.performAutoRelease(key)
176186
})
177187
}
@@ -314,6 +324,7 @@ var keyboardWriteHidFileLock sync.Mutex
314324
func (u *UsbGadget) keyboardWriteHidFile(modifier byte, keys []byte) error {
315325
keyboardWriteHidFileLock.Lock()
316326
defer keyboardWriteHidFileLock.Unlock()
327+
317328
if err := u.openKeyboardHidFile(); err != nil {
318329
return err
319330
}
@@ -353,7 +364,7 @@ func (u *UsbGadget) UpdateKeysDown(modifier byte, keys []byte) KeysDownState {
353364
u.keysDownState = state
354365
u.keyboardStateLock.Unlock()
355366

356-
if u.onKeysDownChange != nil {
367+
if u.onKeysDownChange != nil && !suspendedKeyDownMessages {
357368
(*u.onKeysDownChange)(state) // this enques to the outgoing hidrpc queue via usb.go → currentSession.enqueueKeysDownState(...)
358369
}
359370
return state
@@ -484,6 +495,10 @@ func (u *UsbGadget) keypressReport(key byte, press bool) (KeysDownState, error)
484495
}
485496

486497
err := u.keyboardWriteHidFile(modifier, keys)
498+
if err != nil {
499+
u.log.Warn().Uint8("modifier", modifier).Uints8("keys", keys).Msg("Could not write keyboard report to hidg0")
500+
}
501+
487502
return u.UpdateKeysDown(modifier, keys), err
488503
}
489504

jsonrpc.go

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1132,7 +1132,11 @@ func isClearKeyStep(step hidrpc.KeyboardMacroStep) bool {
11321132
}
11331133

11341134
func rpcDoExecuteKeyboardMacro(ctx context.Context, macro []hidrpc.KeyboardMacroStep) error {
1135-
logger.Debug().Interface("macro", macro).Msg("Executing keyboard macro")
1135+
logger.Debug().Int("macro_steps", len(macro)).Msg("Executing keyboard macro")
1136+
1137+
// don't report keyboard state changes while executing the macro
1138+
gadget.SuspendKeyDownMessages()
1139+
defer gadget.ResumeSuspendKeyDownMessages()
11361140

11371141
for i, step := range macro {
11381142
delay := time.Duration(step.Delay) * time.Millisecond
@@ -1153,7 +1157,8 @@ func rpcDoExecuteKeyboardMacro(ctx context.Context, macro []hidrpc.KeyboardMacro
11531157
case <-time.After(delay):
11541158
// Sleep completed normally
11551159
case <-ctx.Done():
1156-
// make sure keyboard state is reset
1160+
// make sure keyboard state is reset and the client gets notified
1161+
gadget.ResumeSuspendKeyDownMessages()
11571162
err := rpcKeyboardReport(0, keyboardClearStateKeys)
11581163
if err != nil {
11591164
logger.Warn().Err(err).Msg("failed to reset keyboard state")

ui/src/components/popovers/PasteModal.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -188,18 +188,18 @@ export default function PasteModal() {
188188
type="number"
189189
label="Delay between keys"
190190
placeholder="Delay between keys"
191-
min={50}
191+
min={0}
192192
max={65534}
193193
value={delayValue}
194194
onChange={e => {
195195
setDelayValue(parseInt(e.target.value, 10));
196196
}}
197197
/>
198-
{delayValue < 50 || delayValue > 65534 && (
198+
{delayValue < defaultDelay || delayValue > 65534 && (
199199
<div className="mt-2 flex items-center gap-x-2">
200200
<ExclamationCircleIcon className="h-4 w-4 text-red-500 dark:text-red-400" />
201201
<span className="text-xs text-red-500 dark:text-red-400">
202-
Delay must be between 50 and 65534
202+
Delay should be between 20 and 65534
203203
</span>
204204
</div>
205205
)}

ui/src/hooks/useKeyboard.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -277,7 +277,6 @@ export default function useKeyboard() {
277277
cancelKeepAlive();
278278
}, [cancelKeepAlive]);
279279

280-
281280
// executeMacro is used to execute a macro consisting of multiple steps.
282281
// Each step can have multiple keys, multiple modifiers and a delay.
283282
// The keys and modifiers are pressed together and held for the delay duration.
@@ -292,9 +291,7 @@ export default function useKeyboard() {
292291
for (const [_, step] of steps.entries()) {
293292
const keyValues = (step.keys || []).map(key => keys[key]).filter(Boolean);
294293
const modifierMask: number = (step.modifiers || [])
295-
296294
.map(mod => modifiers[mod])
297-
298295
.reduce((acc, val) => acc + val, 0);
299296

300297
// If the step has keys and/or modifiers, press them and hold for the delay
@@ -306,6 +303,7 @@ export default function useKeyboard() {
306303

307304
sendKeyboardMacroEventHidRpc(macro);
308305
}, [sendKeyboardMacroEventHidRpc]);
306+
309307
const executeMacroClientSide = useCallback(async (steps: MacroSteps) => {
310308
const promises: (() => Promise<void>)[] = [];
311309

0 commit comments

Comments
 (0)