1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2026-08-05 04:58:30 -04:00

evdev: resolve capslock state from any available keyboard

fixes #2991
port 1.5
This commit is contained in:
bbedward
2026-08-03 19:59:12 -04:00
parent 27483e68dc
commit dc8a47644a
2 changed files with 47 additions and 25 deletions
+25 -21
View File
@@ -48,7 +48,7 @@ func NewManager() (*Manager, error) {
return nil, fmt.Errorf("failed to find keyboards: %w", err) return nil, fmt.Errorf("failed to find keyboards: %w", err)
} }
initialCapsLock := readInitialCapsLockState(devices[0]) initialCapsLock, _ := capsLockFromDevices(devices)
watcher, err := fsnotify.NewWatcher() watcher, err := fsnotify.NewWatcher()
if err != nil { if err != nil {
@@ -85,14 +85,21 @@ func NewManager() (*Manager, error) {
return m, nil return m, nil
} }
func readInitialCapsLockState(device EvdevDevice) bool { func capsLockFromDevices(devices []EvdevDevice) (bool, bool) {
ledStates, err := device.State(evLedType) for _, device := range devices {
if err != nil { if device == nil {
log.Debugf("Could not read LED state: %v", err) continue
return false }
ledStates, err := device.State(evLedType)
if err != nil || len(ledStates) == 0 {
continue
}
return ledStates[ledCapslockKey], true
} }
return ledStates[ledCapslockKey] return false, false
} }
func findKeyboards() ([]EvdevDevice, error) { func findKeyboards() ([]EvdevDevice, error) {
@@ -297,25 +304,22 @@ func (m *Manager) readAndUpdateCapsLockState(deviceIndex int) {
m.devicesMutex.RUnlock() m.devicesMutex.RUnlock()
return return
} }
device := m.devices[deviceIndex] ordered := make([]EvdevDevice, 0, len(m.devices))
ordered = append(ordered, m.devices[deviceIndex])
for i, device := range m.devices {
if i == deviceIndex {
continue
}
ordered = append(ordered, device)
}
m.devicesMutex.RUnlock() m.devicesMutex.RUnlock()
ledStates, err := device.State(evLedType) capsLockState, ok := capsLockFromDevices(ordered)
if err != nil { if !ok {
log.Warnf("Failed to read LED state: %v", err) log.Debug("No LED-capable device available for caps lock state")
return return
} }
if len(ledStates) == 0 {
log.Debug("No LED state available (empty map)")
// This means the device either:
// - doesn't support LED reporting at all, or
// - the kernel returned an empty state
return
}
capsLockState := ledStates[ledCapslockKey]
m.updateCapsLockStateDirect(capsLockState) m.updateCapsLockStateDirect(capsLockState)
} }
+22 -4
View File
@@ -306,7 +306,7 @@ func TestNotifySubscribers(t *testing.T) {
m.Close() m.Close()
} }
func TestReadInitialCapsLockState(t *testing.T) { func TestCapsLockFromDevices(t *testing.T) {
t.Run("caps lock is on", func(t *testing.T) { t.Run("caps lock is on", func(t *testing.T) {
mockDevice := mocks.NewMockEvdevDevice(t) mockDevice := mocks.NewMockEvdevDevice(t)
ledState := evdev.StateMap{ ledState := evdev.StateMap{
@@ -314,7 +314,8 @@ func TestReadInitialCapsLockState(t *testing.T) {
} }
mockDevice.EXPECT().State(evdev.EvType(evLedType)).Return(ledState, nil).Once() mockDevice.EXPECT().State(evdev.EvType(evLedType)).Return(ledState, nil).Once()
result := readInitialCapsLockState(mockDevice) result, ok := capsLockFromDevices([]EvdevDevice{mockDevice})
assert.True(t, ok)
assert.True(t, result) assert.True(t, result)
}) })
@@ -325,7 +326,8 @@ func TestReadInitialCapsLockState(t *testing.T) {
} }
mockDevice.EXPECT().State(evdev.EvType(evLedType)).Return(ledState, nil).Once() mockDevice.EXPECT().State(evdev.EvType(evLedType)).Return(ledState, nil).Once()
result := readInitialCapsLockState(mockDevice) result, ok := capsLockFromDevices([]EvdevDevice{mockDevice})
assert.True(t, ok)
assert.False(t, result) assert.False(t, result)
}) })
@@ -333,9 +335,25 @@ func TestReadInitialCapsLockState(t *testing.T) {
mockDevice := mocks.NewMockEvdevDevice(t) mockDevice := mocks.NewMockEvdevDevice(t)
mockDevice.EXPECT().State(evdev.EvType(evLedType)).Return(nil, errors.New("read error")).Once() mockDevice.EXPECT().State(evdev.EvType(evLedType)).Return(nil, errors.New("read error")).Once()
result := readInitialCapsLockState(mockDevice) result, ok := capsLockFromDevices([]EvdevDevice{mockDevice})
assert.False(t, ok)
assert.False(t, result) assert.False(t, result)
}) })
t.Run("falls back past device without LED state", func(t *testing.T) {
noLedDevice := mocks.NewMockEvdevDevice(t)
noLedDevice.EXPECT().State(evdev.EvType(evLedType)).Return(evdev.StateMap{}, nil).Once()
ledDevice := mocks.NewMockEvdevDevice(t)
ledState := evdev.StateMap{
ledCapslockKey: true,
}
ledDevice.EXPECT().State(evdev.EvType(evLedType)).Return(ledState, nil).Once()
result, ok := capsLockFromDevices([]EvdevDevice{noLedDevice, nil, ledDevice})
assert.True(t, ok)
assert.True(t, result)
})
} }
func TestHasInputGroupAccess(t *testing.T) { func TestHasInputGroupAccess(t *testing.T) {