refactor: enhance keyboard auto-release functionality and key state management

This commit is contained in:
Adam Shiervani 2025-09-16 12:28:57 +02:00 committed by Siyuan Miao
parent e3eb8330fe
commit 60263359b9
3 changed files with 65 additions and 59 deletions

View File

@ -158,25 +158,27 @@ func (u *UsbGadget) SetOnKeysDownChange(f func(state KeysDownState)) {
u.onKeysDownChange = &f u.onKeysDownChange = &f
} }
func (u *UsbGadget) scheduleAutoRelease() { func (u *UsbGadget) scheduleAutoRelease(key byte) {
u.kbdAutoReleaseLock.Lock() u.kbdAutoReleaseLock.Lock()
defer unlockWithLog(&u.kbdAutoReleaseLock, u.log, "autoRelease scheduled") defer unlockWithLog(&u.kbdAutoReleaseLock, u.log, "autoRelease scheduled")
if u.kbdAutoReleaseTimer != nil { if u.kbdAutoReleaseTimers[key] != nil {
u.kbdAutoReleaseTimer.Stop() u.kbdAutoReleaseTimers[key].Stop()
} }
u.kbdAutoReleaseTimer = time.AfterFunc(autoReleaseKeyboardInterval, func() { u.kbdAutoReleaseTimers[key] = time.AfterFunc(autoReleaseKeyboardInterval, func() {
u.performAutoRelease() u.performAutoRelease(key)
}) })
} }
func (u *UsbGadget) cancelAutoRelease() { func (u *UsbGadget) cancelAutoRelease(key byte) {
u.kbdAutoReleaseLock.Lock() u.kbdAutoReleaseLock.Lock()
defer unlockWithLog(&u.kbdAutoReleaseLock, u.log, "autoRelease cancelled") defer unlockWithLog(&u.kbdAutoReleaseLock, u.log, "autoRelease cancelled")
if u.kbdAutoReleaseTimer != nil { if timer := u.kbdAutoReleaseTimers[key]; timer != nil {
u.kbdAutoReleaseTimer.Stop() timer.Stop()
u.kbdAutoReleaseTimers[key] = nil
delete(u.kbdAutoReleaseTimers, key)
} }
} }
@ -184,27 +186,35 @@ func (u *UsbGadget) DelayAutoRelease() {
u.kbdAutoReleaseLock.Lock() u.kbdAutoReleaseLock.Lock()
defer unlockWithLog(&u.kbdAutoReleaseLock, u.log, "autoRelease delayed") defer unlockWithLog(&u.kbdAutoReleaseLock, u.log, "autoRelease delayed")
if u.kbdAutoReleaseTimer == nil { if u.kbdAutoReleaseTimers == nil {
return return
} }
u.kbdAutoReleaseTimer.Reset(autoReleaseKeyboardInterval) for _, timer := range u.kbdAutoReleaseTimers {
} if timer != nil {
timer.Reset(autoReleaseKeyboardInterval)
func (u *UsbGadget) performAutoRelease() { }
select { }
case <-u.keyboardStateCtx.Done():
return
default:
} }
func (u *UsbGadget) performAutoRelease(key byte) {
u.kbdAutoReleaseLock.Lock() u.kbdAutoReleaseLock.Lock()
key := u.kbdAutoReleaseLastKey if u.kbdAutoReleaseTimers[key] == nil {
u.log.Warn().Uint8("key", key).Msg("autoRelease timer not found")
u.kbdAutoReleaseLock.Unlock()
return
}
u.kbdAutoReleaseTimers[key].Stop()
u.kbdAutoReleaseTimers[key] = nil
delete(u.kbdAutoReleaseTimers, key)
u.kbdAutoReleaseLock.Unlock()
// Skip if already released // Skip if already released
state := u.GetKeysDownState() state := u.GetKeysDownState()
alreadyReleased := true alreadyReleased := true
for i := range state.Keys { for i := range state.Keys {
if state.Keys[i] == key { if state.Keys[i] == key {
alreadyReleased = false alreadyReleased = false
@ -216,10 +226,7 @@ func (u *UsbGadget) performAutoRelease() {
return return
} }
u.kbdAutoReleaseTimer = nil u.keypressReport(key, false)
u.kbdAutoReleaseLock.Unlock()
u.keypressReport(key, false) // autoRelease the ket
} }
func (u *UsbGadget) listenKeyboardEvents() { func (u *UsbGadget) listenKeyboardEvents() {
@ -311,7 +318,7 @@ func (u *UsbGadget) keyboardWriteHidFile(modifier byte, keys []byte) error {
return nil return nil
} }
func (u *UsbGadget) UpdateKeysDown(modifier byte, keys []byte) { func (u *UsbGadget) UpdateKeysDown(modifier byte, keys []byte) KeysDownState {
// if we just reported an error roll over, we should clear the keys // if we just reported an error roll over, we should clear the keys
if keys[0] == hidErrorRollOver { if keys[0] == hidErrorRollOver {
for i := range keys { for i := range keys {
@ -329,7 +336,7 @@ func (u *UsbGadget) UpdateKeysDown(modifier byte, keys []byte) {
if u.keysDownState.Modifier == state.Modifier && if u.keysDownState.Modifier == state.Modifier &&
bytes.Equal(u.keysDownState.Keys, state.Keys) { bytes.Equal(u.keysDownState.Keys, state.Keys) {
u.keyboardStateLock.Unlock() u.keyboardStateLock.Unlock()
return // No change in key down state return state // No change in key down state
} }
u.keysDownState = state u.keysDownState = state
@ -338,7 +345,7 @@ func (u *UsbGadget) UpdateKeysDown(modifier byte, keys []byte) {
if u.onKeysDownChange != nil { if u.onKeysDownChange != nil {
(*u.onKeysDownChange)(state) // this enques to the outgoing hidrpc queue via usb.go → currentSession.enqueueKeysDownState(...) (*u.onKeysDownChange)(state) // this enques to the outgoing hidrpc queue via usb.go → currentSession.enqueueKeysDownState(...)
} }
return return state
} }
func (u *UsbGadget) KeyboardReport(modifier byte, keys []byte) error { func (u *UsbGadget) KeyboardReport(modifier byte, keys []byte) error {
@ -397,7 +404,7 @@ var KeyCodeToMaskMap = map[byte]byte{
RightSuper: ModifierMaskRightSuper, RightSuper: ModifierMaskRightSuper,
} }
func (u *UsbGadget) keypressReport(key byte, press bool) error { func (u *UsbGadget) keypressReport(key byte, press bool) (KeysDownState, error) {
defer u.resetUserInputTime() defer u.resetUserInputTime()
l := u.log.With().Uint8("key", key).Bool("press", press).Logger() l := u.log.With().Uint8("key", key).Bool("press", press).Logger()
@ -466,21 +473,20 @@ func (u *UsbGadget) keypressReport(key byte, press bool) error {
} }
err := u.keyboardWriteHidFile(modifier, keys) err := u.keyboardWriteHidFile(modifier, keys)
u.UpdateKeysDown(modifier, keys) return u.UpdateKeysDown(modifier, keys), err
return err
} }
func (u *UsbGadget) KeypressReport(key byte, press bool) error { func (u *UsbGadget) KeypressReport(key byte, press bool) error {
u.kbdAutoReleaseLock.Lock() state, err := u.keypressReport(key, press)
u.kbdAutoReleaseLastKey = key isRolledOver := state.Keys[0] == hidErrorRollOver
u.kbdAutoReleaseLock.Unlock()
if press { if isRolledOver {
u.scheduleAutoRelease() u.cancelAutoRelease(key)
} else if press {
u.scheduleAutoRelease(key)
} else { } else {
u.cancelAutoRelease() u.cancelAutoRelease(key)
} }
err := u.keypressReport(key, press)
return err return err
} }

View File

@ -69,8 +69,7 @@ type UsbGadget struct {
keysDownState KeysDownState // keyboard dynamic state (modifier keys and pressed keys) keysDownState KeysDownState // keyboard dynamic state (modifier keys and pressed keys)
kbdAutoReleaseLock sync.Mutex kbdAutoReleaseLock sync.Mutex
kbdAutoReleaseTimer *time.Timer kbdAutoReleaseTimers map[byte]*time.Timer
kbdAutoReleaseLastKey byte
keyboardStateLock sync.Mutex keyboardStateLock sync.Mutex
keyboardStateCtx context.Context keyboardStateCtx context.Context
@ -136,6 +135,7 @@ func newUsbGadget(name string, configMap map[string]gadgetConfigItem, enabledDev
keyboardStateCancel: keyboardCancel, keyboardStateCancel: keyboardCancel,
keyboardState: 0, keyboardState: 0,
keysDownState: KeysDownState{Modifier: 0, Keys: []byte{0, 0, 0, 0, 0, 0}}, // must be initialized to hidKeyBufferSize (6) zero bytes keysDownState: KeysDownState{Modifier: 0, Keys: []byte{0, 0, 0, 0, 0, 0}}, // must be initialized to hidKeyBufferSize (6) zero bytes
kbdAutoReleaseTimers: make(map[byte]*time.Timer),
enabledDevices: *enabledDevices, enabledDevices: *enabledDevices,
lastUserInput: time.Now(), lastUserInput: time.Now(),
log: logger, log: logger,
@ -163,10 +163,10 @@ func (u *UsbGadget) Close() error {
// Stop auto-release timer // Stop auto-release timer
u.kbdAutoReleaseLock.Lock() u.kbdAutoReleaseLock.Lock()
if u.kbdAutoReleaseTimer != nil { for _, timer := range u.kbdAutoReleaseTimers {
u.kbdAutoReleaseTimer.Stop() timer.Stop()
u.kbdAutoReleaseTimer = nil
} }
u.kbdAutoReleaseTimers = make(map[byte]*time.Timer)
u.kbdAutoReleaseLock.Unlock() u.kbdAutoReleaseLock.Unlock()
// Close HID files // Close HID files