mirror of https://github.com/jetkvm/kvm.git
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)
This commit is contained in:
parent
703625d59a
commit
704d65bde6
10
hidrpc.go
10
hidrpc.go
|
|
@ -65,15 +65,17 @@ func handleHidRPCMessage(message hidrpc.Message, session *Session) {
|
|||
|
||||
func onHidMessage(msg hidQueueMessage, session *Session) {
|
||||
data := msg.Data
|
||||
dataLen := len(data)
|
||||
|
||||
scopedLogger := hidRPCLogger.With().
|
||||
Str("channel", msg.channel).
|
||||
Bytes("data", data).
|
||||
Int("data_len", dataLen).
|
||||
Bytes("data", data[:min(dataLen, 32)]).
|
||||
Logger()
|
||||
scopedLogger.Debug().Msg("HID RPC message received")
|
||||
|
||||
if len(data) < 1 {
|
||||
scopedLogger.Warn().Int("length", len(data)).Msg("received empty data in HID RPC message handler")
|
||||
if dataLen < 1 {
|
||||
scopedLogger.Warn().Msg("received empty data in HID RPC message handler")
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -96,7 +98,7 @@ func onHidMessage(msg hidQueueMessage, session *Session) {
|
|||
r <- nil
|
||||
}()
|
||||
select {
|
||||
case <-time.After(1 * time.Second):
|
||||
case <-time.After(30 * time.Second):
|
||||
scopedLogger.Warn().Msg("HID RPC message timed out")
|
||||
case <-r:
|
||||
scopedLogger.Debug().Dur("duration", time.Since(t)).Msg("HID RPC message handled")
|
||||
|
|
|
|||
|
|
@ -55,10 +55,10 @@ var keyboardReportDesc = []byte{
|
|||
0x95, 0x06, /* REPORT_COUNT (6) */
|
||||
0x75, 0x08, /* REPORT_SIZE (8) */
|
||||
0x15, 0x00, /* LOGICAL_MINIMUM (0) */
|
||||
0x25, 0x65, /* LOGICAL_MAXIMUM (101) */
|
||||
0x25, 104, /* LOGICAL_MAXIMUM (104-key) */
|
||||
0x05, 0x07, /* USAGE_PAGE (Keyboard) */
|
||||
0x19, 0x00, /* USAGE_MINIMUM (Reserved) */
|
||||
0x29, 0x65, /* USAGE_MAXIMUM (Keyboard Application) */
|
||||
0x29, 0xE7, /* USAGE_MAXIMUM (Keyboard Right GUI) */
|
||||
0x81, 0x00, /* INPUT (Data,Ary,Abs) */
|
||||
0xc0, /* END_COLLECTION */
|
||||
}
|
||||
|
|
@ -153,6 +153,16 @@ func (u *UsbGadget) SetOnKeysDownChange(f func(state KeysDownState)) {
|
|||
u.onKeysDownChange = &f
|
||||
}
|
||||
|
||||
var suspendedKeyDownMessages bool = false
|
||||
|
||||
func (u *UsbGadget) SuspendKeyDownMessages() {
|
||||
suspendedKeyDownMessages = true
|
||||
}
|
||||
|
||||
func (u *UsbGadget) ResumeSuspendKeyDownMessages() {
|
||||
suspendedKeyDownMessages = false
|
||||
}
|
||||
|
||||
func (u *UsbGadget) SetOnKeepAliveReset(f func()) {
|
||||
u.onKeepAliveReset = &f
|
||||
}
|
||||
|
|
@ -169,9 +179,9 @@ func (u *UsbGadget) scheduleAutoRelease(key byte) {
|
|||
}
|
||||
|
||||
// TODO: make this configurable
|
||||
// We currently hardcode the duration to 100ms
|
||||
// We currently hardcode the duration to the default of 100ms
|
||||
// However, it should be the same as the duration of the keep-alive reset called baseExtension.
|
||||
u.kbdAutoReleaseTimers[key] = time.AfterFunc(100*time.Millisecond, func() {
|
||||
u.kbdAutoReleaseTimers[key] = time.AfterFunc(DefaultAutoReleaseDuration, func() {
|
||||
u.performAutoRelease(key)
|
||||
})
|
||||
}
|
||||
|
|
@ -314,6 +324,7 @@ var keyboardWriteHidFileLock sync.Mutex
|
|||
func (u *UsbGadget) keyboardWriteHidFile(modifier byte, keys []byte) error {
|
||||
keyboardWriteHidFileLock.Lock()
|
||||
defer keyboardWriteHidFileLock.Unlock()
|
||||
|
||||
if err := u.openKeyboardHidFile(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -353,7 +364,7 @@ func (u *UsbGadget) UpdateKeysDown(modifier byte, keys []byte) KeysDownState {
|
|||
u.keysDownState = state
|
||||
u.keyboardStateLock.Unlock()
|
||||
|
||||
if u.onKeysDownChange != nil {
|
||||
if u.onKeysDownChange != nil && !suspendedKeyDownMessages {
|
||||
(*u.onKeysDownChange)(state) // this enques to the outgoing hidrpc queue via usb.go → currentSession.enqueueKeysDownState(...)
|
||||
}
|
||||
return state
|
||||
|
|
@ -484,6 +495,10 @@ func (u *UsbGadget) keypressReport(key byte, press bool) (KeysDownState, error)
|
|||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1132,7 +1132,11 @@ func isClearKeyStep(step hidrpc.KeyboardMacroStep) bool {
|
|||
}
|
||||
|
||||
func rpcDoExecuteKeyboardMacro(ctx context.Context, macro []hidrpc.KeyboardMacroStep) error {
|
||||
logger.Debug().Interface("macro", macro).Msg("Executing keyboard macro")
|
||||
logger.Debug().Int("macro_steps", len(macro)).Msg("Executing keyboard macro")
|
||||
|
||||
// don't report keyboard state changes while executing the macro
|
||||
gadget.SuspendKeyDownMessages()
|
||||
defer gadget.ResumeSuspendKeyDownMessages()
|
||||
|
||||
for i, step := range macro {
|
||||
delay := time.Duration(step.Delay) * time.Millisecond
|
||||
|
|
@ -1153,7 +1157,8 @@ func rpcDoExecuteKeyboardMacro(ctx context.Context, macro []hidrpc.KeyboardMacro
|
|||
case <-time.After(delay):
|
||||
// Sleep completed normally
|
||||
case <-ctx.Done():
|
||||
// make sure keyboard state is reset
|
||||
// make sure keyboard state is reset and the client gets notified
|
||||
gadget.ResumeSuspendKeyDownMessages()
|
||||
err := rpcKeyboardReport(0, keyboardClearStateKeys)
|
||||
if err != nil {
|
||||
logger.Warn().Err(err).Msg("failed to reset keyboard state")
|
||||
|
|
|
|||
|
|
@ -188,18 +188,18 @@ export default function PasteModal() {
|
|||
type="number"
|
||||
label="Delay between keys"
|
||||
placeholder="Delay between keys"
|
||||
min={50}
|
||||
min={0}
|
||||
max={65534}
|
||||
value={delayValue}
|
||||
onChange={e => {
|
||||
setDelayValue(parseInt(e.target.value, 10));
|
||||
}}
|
||||
/>
|
||||
{delayValue < 50 || delayValue > 65534 && (
|
||||
{delayValue < defaultDelay || delayValue > 65534 && (
|
||||
<div className="mt-2 flex items-center gap-x-2">
|
||||
<ExclamationCircleIcon className="h-4 w-4 text-red-500 dark:text-red-400" />
|
||||
<span className="text-xs text-red-500 dark:text-red-400">
|
||||
Delay must be between 50 and 65534
|
||||
Delay should be between 20 and 65534
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -277,7 +277,6 @@ export default function useKeyboard() {
|
|||
cancelKeepAlive();
|
||||
}, [cancelKeepAlive]);
|
||||
|
||||
|
||||
// executeMacro is used to execute a macro consisting of multiple steps.
|
||||
// Each step can have multiple keys, multiple modifiers and a delay.
|
||||
// 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()) {
|
||||
const keyValues = (step.keys || []).map(key => keys[key]).filter(Boolean);
|
||||
const modifierMask: number = (step.modifiers || [])
|
||||
|
||||
.map(mod => modifiers[mod])
|
||||
|
||||
.reduce((acc, val) => acc + val, 0);
|
||||
|
||||
// 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]);
|
||||
|
||||
const executeMacroClientSide = useCallback(async (steps: MacroSteps) => {
|
||||
const promises: (() => Promise<void>)[] = [];
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue