diff options
| author | Nippy <nippy@rp1.hu> | 2026-05-09 13:33:09 +0200 |
|---|---|---|
| committer | Nippy <nippy@rp1.hu> | 2026-05-09 13:33:09 +0200 |
| commit | a2b924d7e9492b978ad6dc33b6c1ffcb304b4bc5 (patch) | |
| tree | 1a8769217f84bfe9d6216fafaadaf8cdd876d457 /raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/server/evdev | |
| parent | 34b9c34f982b2596cfa9e368a2d7f74e9a17477c (diff) | |
| download | RaveOS-PKGBUILD-a2b924d7e9492b978ad6dc33b6c1ffcb304b4bc5.tar.gz RaveOS-PKGBUILD-a2b924d7e9492b978ad6dc33b6c1ffcb304b4bc5.zip | |
raveos update
Diffstat (limited to 'raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/server/evdev')
5 files changed, 0 insertions, 913 deletions
diff --git a/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/server/evdev/handlers.go b/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/server/evdev/handlers.go deleted file mode 100644 index 54a7bca..0000000 --- a/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/server/evdev/handlers.go +++ /dev/null @@ -1,20 +0,0 @@ -package evdev - -import ( - "net" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/server/models" -) - -func HandleRequest(conn net.Conn, req models.Request, m *Manager) { - switch req.Method { - case "evdev.getState": - handleGetState(conn, req, m) - default: - models.RespondError(conn, req.ID, "unknown method: "+req.Method) - } -} - -func handleGetState(conn net.Conn, req models.Request, m *Manager) { - models.Respond(conn, req.ID, m.GetState()) -} diff --git a/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/server/evdev/handlers_test.go b/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/server/evdev/handlers_test.go deleted file mode 100644 index f9bd21d..0000000 --- a/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/server/evdev/handlers_test.go +++ /dev/null @@ -1,130 +0,0 @@ -package evdev - -import ( - "bytes" - "encoding/json" - "errors" - "net" - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - mocks "github.com/AvengeMedia/DankMaterialShell/core/internal/mocks/evdev" - "github.com/AvengeMedia/DankMaterialShell/core/internal/server/models" -) - -type mockNetConn struct { - net.Conn - readBuf *bytes.Buffer - writeBuf *bytes.Buffer - closed bool -} - -func newMockNetConn() *mockNetConn { - return &mockNetConn{ - readBuf: &bytes.Buffer{}, - writeBuf: &bytes.Buffer{}, - } -} - -func (m *mockNetConn) Read(b []byte) (n int, err error) { - return m.readBuf.Read(b) -} - -func (m *mockNetConn) Write(b []byte) (n int, err error) { - return m.writeBuf.Write(b) -} - -func (m *mockNetConn) Close() error { - m.closed = true - return nil -} - -func TestHandleRequest(t *testing.T) { - t.Run("getState request", func(t *testing.T) { - mockDevice := mocks.NewMockEvdevDevice(t) - mockDevice.EXPECT().ReadOne().Return(nil, errors.New("test")).Maybe() - - m := &Manager{ - devices: []EvdevDevice{mockDevice}, - state: State{Available: true, CapsLock: true}, - closeChan: make(chan struct{}), - } - - conn := newMockNetConn() - req := models.Request{ - ID: 123, - Method: "evdev.getState", - Params: map[string]any{}, - } - - HandleRequest(conn, req, m) - - var resp models.Response[State] - err := json.NewDecoder(conn.writeBuf).Decode(&resp) - require.NoError(t, err) - - assert.Equal(t, 123, resp.ID) - assert.NotNil(t, resp.Result) - assert.True(t, resp.Result.Available) - assert.True(t, resp.Result.CapsLock) - }) - - t.Run("unknown method", func(t *testing.T) { - mockDevice := mocks.NewMockEvdevDevice(t) - mockDevice.EXPECT().ReadOne().Return(nil, errors.New("test")).Maybe() - - m := &Manager{ - devices: []EvdevDevice{mockDevice}, - state: State{Available: true, CapsLock: false}, - closeChan: make(chan struct{}), - } - - conn := newMockNetConn() - req := models.Request{ - ID: 456, - Method: "evdev.unknownMethod", - Params: map[string]any{}, - } - - HandleRequest(conn, req, m) - - var resp models.Response[any] - err := json.NewDecoder(conn.writeBuf).Decode(&resp) - require.NoError(t, err) - - assert.Equal(t, 456, resp.ID) - assert.NotEmpty(t, resp.Error) - assert.Contains(t, resp.Error, "unknown method") - }) -} - -func TestHandleGetState(t *testing.T) { - mockDevice := mocks.NewMockEvdevDevice(t) - mockDevice.EXPECT().ReadOne().Return(nil, errors.New("test")).Maybe() - - m := &Manager{ - devices: []EvdevDevice{mockDevice}, - state: State{Available: true, CapsLock: false}, - closeChan: make(chan struct{}), - } - - conn := newMockNetConn() - req := models.Request{ - ID: 789, - Method: "evdev.getState", - Params: map[string]any{}, - } - - handleGetState(conn, req, m) - - var resp models.Response[State] - err := json.NewDecoder(conn.writeBuf).Decode(&resp) - require.NoError(t, err) - - assert.Equal(t, 789, resp.ID) - assert.NotNil(t, resp.Result) - assert.True(t, resp.Result.Available) - assert.False(t, resp.Result.CapsLock) -} diff --git a/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/server/evdev/manager.go b/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/server/evdev/manager.go deleted file mode 100644 index b578481..0000000 --- a/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/server/evdev/manager.go +++ /dev/null @@ -1,413 +0,0 @@ -package evdev - -import ( - "fmt" - "os" - "path/filepath" - "strings" - "sync" - "time" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/log" - "github.com/AvengeMedia/DankMaterialShell/core/pkg/syncmap" - "github.com/fsnotify/fsnotify" - evdev "github.com/holoplot/go-evdev" -) - -const ( - evKeyType = 0x01 - evLedType = 0x11 - keyCapslockKey = 58 - ledCapslockKey = 1 - keyStateOn = 1 -) - -type EvdevDevice interface { - Name() (string, error) - Path() string - Close() error - ReadOne() (*evdev.InputEvent, error) - State(t evdev.EvType) (evdev.StateMap, error) -} - -type Manager struct { - devices []EvdevDevice - devicesMutex sync.RWMutex - monitoredPaths map[string]bool - state State - stateMutex sync.RWMutex - subscribers syncmap.Map[string, chan State] - closeChan chan struct{} - closeOnce sync.Once - watcher *fsnotify.Watcher -} - -func NewManager() (*Manager, error) { - devices, err := findKeyboards() - if err != nil { - return nil, fmt.Errorf("failed to find keyboards: %w", err) - } - - initialCapsLock := readInitialCapsLockState(devices[0]) - - watcher, err := fsnotify.NewWatcher() - if err != nil { - log.Warnf("Failed to create fsnotify watcher, hotplug detection disabled: %v", err) - watcher = nil - } else if err := watcher.Add("/dev/input"); err != nil { - log.Warnf("Failed to watch /dev/input, hotplug detection disabled: %v", err) - watcher.Close() - watcher = nil - } - - monitoredPaths := make(map[string]bool) - for _, device := range devices { - monitoredPaths[device.Path()] = true - } - - m := &Manager{ - devices: devices, - monitoredPaths: monitoredPaths, - state: State{Available: true, CapsLock: initialCapsLock}, - - closeChan: make(chan struct{}), - watcher: watcher, - } - - for i, device := range devices { - go m.monitorDevice(device, i) - } - - if watcher != nil { - go m.watchForNewKeyboards() - } - - return m, nil -} - -func readInitialCapsLockState(device EvdevDevice) bool { - ledStates, err := device.State(evLedType) - if err != nil { - log.Debugf("Could not read LED state: %v", err) - return false - } - - return ledStates[ledCapslockKey] -} - -func findKeyboards() ([]EvdevDevice, error) { - pattern := "/dev/input/event*" - matches, err := filepath.Glob(pattern) - if err != nil { - return nil, fmt.Errorf("failed to glob input devices: %w", err) - } - - if len(matches) == 0 { - return nil, fmt.Errorf("no input devices found") - } - - var keyboards []EvdevDevice - for _, path := range matches { - device, err := evdev.Open(path) - if err != nil { - continue - } - - if !isKeyboard(device) { - device.Close() - continue - } - - deviceName, _ := device.Name() - log.Debugf("Found keyboard: %s at %s", deviceName, path) - keyboards = append(keyboards, device) - } - - if len(keyboards) == 0 { - return nil, fmt.Errorf("no keyboard device found") - } - - return keyboards, nil -} - -func isKeyboard(device EvdevDevice) bool { - deviceName, err := device.Name() - if err != nil { - return false - } - - name := strings.ToLower(deviceName) - - switch { - case strings.Contains(name, "keyboard"): - return true - case strings.Contains(name, "kbd"): - return true - case strings.Contains(name, "input") && strings.Contains(name, "key"): - return true - } - - keyStates, err := device.State(evKeyType) - if err != nil { - return false - } - - hasKeyA := len(keyStates) > 30 - hasKeyZ := len(keyStates) > 44 - hasEnter := len(keyStates) > 28 - - return hasKeyA && hasKeyZ && hasEnter && len(keyStates) > 100 -} - -func (m *Manager) watchForNewKeyboards() { - defer func() { - if r := recover(); r != nil { - log.Errorf("Panic in keyboard hotplug monitor: %v", r) - } - }() - - for { - select { - case <-m.closeChan: - return - case event, ok := <-m.watcher.Events: - if !ok { - return - } - - if !strings.HasPrefix(filepath.Base(event.Name), "event") { - continue - } - - if event.Op&fsnotify.Create == fsnotify.Create { - time.Sleep(100 * time.Millisecond) - - m.devicesMutex.Lock() - if m.monitoredPaths[event.Name] { - m.devicesMutex.Unlock() - continue - } - - device, err := evdev.Open(event.Name) - if err != nil { - m.devicesMutex.Unlock() - continue - } - - if !isKeyboard(device) { - device.Close() - m.devicesMutex.Unlock() - continue - } - - deviceName, _ := device.Name() - log.Debugf("Hotplugged keyboard: %s at %s", deviceName, event.Name) - - m.devices = append(m.devices, device) - m.monitoredPaths[event.Name] = true - deviceIndex := len(m.devices) - 1 - m.devicesMutex.Unlock() - - go m.monitorDevice(device, deviceIndex) - } else if event.Op&fsnotify.Remove == fsnotify.Remove { - m.devicesMutex.Lock() - if !m.monitoredPaths[event.Name] { - m.devicesMutex.Unlock() - continue - } - - delete(m.monitoredPaths, event.Name) - for i, device := range m.devices { - if device != nil && device.Path() == event.Name { - log.Debugf("Keyboard removed: %s", event.Name) - device.Close() - m.devices[i] = nil - break - } - } - m.devicesMutex.Unlock() - } - - case err, ok := <-m.watcher.Errors: - if !ok { - return - } - log.Warnf("Keyboard hotplug watcher error: %v", err) - } - } -} - -func (m *Manager) monitorDevice(device EvdevDevice, deviceIndex int) { - defer func() { - if r := recover(); r != nil { - log.Errorf("Panic in evdev monitor: %v", r) - } - }() - - for { - select { - case <-m.closeChan: - return - default: - } - - event, err := device.ReadOne() - if err != nil { - if isClosedError(err) { - return - } - log.Warnf("Failed to read evdev event: %v", err) - time.Sleep(100 * time.Millisecond) - continue - } - - if event == nil { - continue - } - - if event.Type == evKeyType && event.Code == keyCapslockKey && event.Value == keyStateOn { - time.Sleep(50 * time.Millisecond) - m.readAndUpdateCapsLockState(deviceIndex) - } else if event.Type == evLedType && event.Code == ledCapslockKey { - capsLockState := event.Value == keyStateOn - m.updateCapsLockStateDirect(capsLockState) - } - } -} - -func isClosedError(err error) bool { - if err == nil { - return false - } - - errStr := err.Error() - switch { - case strings.Contains(errStr, "closed"): - return true - case strings.Contains(errStr, "bad file descriptor"): - return true - default: - return false - } -} - -func (m *Manager) readAndUpdateCapsLockState(deviceIndex int) { - m.devicesMutex.RLock() - if deviceIndex >= len(m.devices) { - m.devicesMutex.RUnlock() - return - } - device := m.devices[deviceIndex] - m.devicesMutex.RUnlock() - - ledStates, err := device.State(evLedType) - if err != nil { - log.Warnf("Failed to read LED state: %v", err) - 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) -} - -func (m *Manager) updateCapsLockStateDirect(capsLockState bool) { - m.stateMutex.Lock() - if m.state.CapsLock == capsLockState { - m.stateMutex.Unlock() - return - } - - m.state.CapsLock = capsLockState - newState := m.state - m.stateMutex.Unlock() - - log.Debugf("Caps lock state: %v", newState.CapsLock) - m.notifySubscribers(newState) -} - -func (m *Manager) GetState() State { - m.stateMutex.RLock() - defer m.stateMutex.RUnlock() - return m.state -} - -func (m *Manager) Subscribe(id string) chan State { - ch := make(chan State, 16) - m.subscribers.Store(id, ch) - return ch -} - -func (m *Manager) Unsubscribe(id string) { - if val, ok := m.subscribers.LoadAndDelete(id); ok { - close(val) - } -} - -func (m *Manager) notifySubscribers(state State) { - m.subscribers.Range(func(key string, ch chan State) bool { - select { - case ch <- state: - default: - } - return true - }) -} - -func (m *Manager) Close() { - m.closeOnce.Do(func() { - close(m.closeChan) - - if m.watcher != nil { - m.watcher.Close() - } - - m.devicesMutex.Lock() - for _, device := range m.devices { - if device == nil { - continue - } - if err := device.Close(); err != nil && !isClosedError(err) { - log.Warnf("Error closing evdev device: %v", err) - } - } - m.devicesMutex.Unlock() - - m.subscribers.Range(func(key string, ch chan State) bool { - close(ch) - m.subscribers.Delete(key) - return true - }) - }) -} - -func InitializeManager() (*Manager, error) { - if os.Getuid() != 0 && !hasInputGroupAccess() { - return nil, fmt.Errorf("insufficient permissions to access input devices") - } - - return NewManager() -} - -func hasInputGroupAccess() bool { - pattern := "/dev/input/event*" - matches, err := filepath.Glob(pattern) - if err != nil || len(matches) == 0 { - return false - } - - testFile, err := os.Open(matches[0]) - if err != nil { - return false - } - testFile.Close() - return true -} diff --git a/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/server/evdev/manager_test.go b/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/server/evdev/manager_test.go deleted file mode 100644 index 667c078..0000000 --- a/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/server/evdev/manager_test.go +++ /dev/null @@ -1,344 +0,0 @@ -package evdev - -import ( - "errors" - "testing" - - evdev "github.com/holoplot/go-evdev" - "github.com/stretchr/testify/assert" - - mocks "github.com/AvengeMedia/DankMaterialShell/core/internal/mocks/evdev" -) - -func TestManager_Creation(t *testing.T) { - t.Run("manager created successfully with caps lock off", func(t *testing.T) { - mockDevice := mocks.NewMockEvdevDevice(t) - mockDevice.EXPECT().ReadOne().Return(nil, errors.New("test")).Maybe() - - m := &Manager{ - devices: []EvdevDevice{mockDevice}, - state: State{Available: true, CapsLock: false}, - closeChan: make(chan struct{}), - } - - assert.NotNil(t, m) - assert.True(t, m.state.Available) - assert.False(t, m.state.CapsLock) - }) - - t.Run("manager created successfully with caps lock on", func(t *testing.T) { - mockDevice := mocks.NewMockEvdevDevice(t) - mockDevice.EXPECT().ReadOne().Return(nil, errors.New("test")).Maybe() - - m := &Manager{ - devices: []EvdevDevice{mockDevice}, - state: State{Available: true, CapsLock: true}, - closeChan: make(chan struct{}), - } - - assert.NotNil(t, m) - assert.True(t, m.state.Available) - assert.True(t, m.state.CapsLock) - }) -} - -func TestManager_GetState(t *testing.T) { - mockDevice := mocks.NewMockEvdevDevice(t) - mockDevice.EXPECT().ReadOne().Return(nil, errors.New("test")).Maybe() - - m := &Manager{ - devices: []EvdevDevice{mockDevice}, - monitoredPaths: make(map[string]bool), - state: State{Available: true, CapsLock: false}, - closeChan: make(chan struct{}), - } - - state := m.GetState() - assert.True(t, state.Available) - assert.False(t, state.CapsLock) -} - -func TestManager_Subscribe(t *testing.T) { - mockDevice := mocks.NewMockEvdevDevice(t) - mockDevice.EXPECT().ReadOne().Return(nil, errors.New("test")).Maybe() - - m := &Manager{ - devices: []EvdevDevice{mockDevice}, - monitoredPaths: make(map[string]bool), - state: State{Available: true, CapsLock: false}, - closeChan: make(chan struct{}), - } - - ch := m.Subscribe("test-client") - assert.NotNil(t, ch) - count := 0 - m.subscribers.Range(func(key string, ch chan State) bool { - count++ - return true - }) - assert.Equal(t, 1, count) -} - -func TestManager_Unsubscribe(t *testing.T) { - mockDevice := mocks.NewMockEvdevDevice(t) - mockDevice.EXPECT().ReadOne().Return(nil, errors.New("test")).Maybe() - - m := &Manager{ - devices: []EvdevDevice{mockDevice}, - monitoredPaths: make(map[string]bool), - state: State{Available: true, CapsLock: false}, - closeChan: make(chan struct{}), - } - - ch := m.Subscribe("test-client") - count := 0 - m.subscribers.Range(func(key string, ch chan State) bool { - count++ - return true - }) - assert.Equal(t, 1, count) - - m.Unsubscribe("test-client") - count = 0 - m.subscribers.Range(func(key string, ch chan State) bool { - count++ - return true - }) - assert.Equal(t, 0, count) - - select { - case _, ok := <-ch: - assert.False(t, ok, "channel should be closed") - default: - t.Error("channel should be closed") - } -} - -func TestManager_UpdateCapsLock(t *testing.T) { - mockDevice := mocks.NewMockEvdevDevice(t) - mockDevice.EXPECT().ReadOne().Return(nil, errors.New("test")).Maybe() - - m := &Manager{ - devices: []EvdevDevice{mockDevice}, - monitoredPaths: make(map[string]bool), - state: State{Available: true, CapsLock: false}, - closeChan: make(chan struct{}), - } - - ch := m.Subscribe("test-client") - - ledStateOn := evdev.StateMap{ledCapslockKey: true} - mockDevice.EXPECT().State(evdev.EvType(evLedType)).Return(ledStateOn, nil).Once() - - go func() { - m.readAndUpdateCapsLockState(0) - }() - - newState := <-ch - assert.True(t, newState.CapsLock) - - ledStateOff := evdev.StateMap{ledCapslockKey: false} - mockDevice.EXPECT().State(evdev.EvType(evLedType)).Return(ledStateOff, nil).Once() - - go func() { - m.readAndUpdateCapsLockState(0) - }() - - newState = <-ch - assert.False(t, newState.CapsLock) -} - -func TestManager_Close(t *testing.T) { - mockDevice := mocks.NewMockEvdevDevice(t) - mockDevice.EXPECT().Close().Return(nil).Once() - mockDevice.EXPECT().ReadOne().Return(nil, errors.New("test")).Maybe() - - m := &Manager{ - devices: []EvdevDevice{mockDevice}, - monitoredPaths: make(map[string]bool), - state: State{Available: true, CapsLock: false}, - closeChan: make(chan struct{}), - } - - ch1 := m.Subscribe("client1") - ch2 := m.Subscribe("client2") - - m.Close() - - select { - case _, ok := <-ch1: - assert.False(t, ok, "channel 1 should be closed") - default: - t.Error("channel 1 should be closed") - } - - select { - case _, ok := <-ch2: - assert.False(t, ok, "channel 2 should be closed") - default: - t.Error("channel 2 should be closed") - } - - count := 0 - m.subscribers.Range(func(key string, ch chan State) bool { - count++ - return true - }) - assert.Equal(t, 0, count) - - m.Close() -} - -func TestIsKeyboard(t *testing.T) { - tests := []struct { - name string - devName string - expected bool - }{ - {"keyboard in name", "AT Translated Set 2 keyboard", true}, - {"kbd in name", "USB kbd", true}, - {"input and key", "input key device", true}, - {"random device", "Mouse", false}, - {"empty name", "", false}, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - mockDevice := mocks.NewMockEvdevDevice(t) - mockDevice.EXPECT().Name().Return(tt.devName, nil).Once() - - if !tt.expected { - mockDevice.EXPECT().State(evdev.EvType(evKeyType)).Return(evdev.StateMap{}, nil).Maybe() - } - - result := isKeyboard(mockDevice) - assert.Equal(t, tt.expected, result) - }) - } -} - -func TestIsKeyboard_ErrorHandling(t *testing.T) { - mockDevice := mocks.NewMockEvdevDevice(t) - mockDevice.EXPECT().Name().Return("", errors.New("device error")).Once() - - result := isKeyboard(mockDevice) - assert.False(t, result) -} - -func TestManager_MonitorDevice(t *testing.T) { - t.Run("caps lock key press updates state", func(t *testing.T) { - mockDevice := mocks.NewMockEvdevDevice(t) - - capsLockEvent := &evdev.InputEvent{ - Type: evKeyType, - Code: keyCapslockKey, - Value: keyStateOn, - } - - ledState := evdev.StateMap{ledCapslockKey: true} - - mockDevice.EXPECT().ReadOne().Return(capsLockEvent, nil).Once() - mockDevice.EXPECT().State(evdev.EvType(evLedType)).Return(ledState, nil).Once() - mockDevice.EXPECT().ReadOne().Return(nil, errors.New("stop")).Maybe() - mockDevice.EXPECT().Close().Return(nil).Maybe() - - m := &Manager{ - devices: []EvdevDevice{mockDevice}, - state: State{Available: true, CapsLock: false}, - closeChan: make(chan struct{}), - } - - ch := m.Subscribe("test") - - go m.monitorDevice(mockDevice, 0) - - state := <-ch - assert.True(t, state.CapsLock) - - m.Close() - }) -} - -func TestIsClosedError(t *testing.T) { - tests := []struct { - name string - err error - expected bool - }{ - {"nil error", nil, false}, - {"closed error", errors.New("device closed"), true}, - {"bad file descriptor", errors.New("bad file descriptor"), true}, - {"other error", errors.New("some other error"), false}, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - result := isClosedError(tt.err) - assert.Equal(t, tt.expected, result) - }) - } -} - -func TestNotifySubscribers(t *testing.T) { - mockDevice := mocks.NewMockEvdevDevice(t) - mockDevice.EXPECT().ReadOne().Return(nil, errors.New("test")).Maybe() - mockDevice.EXPECT().Close().Return(nil).Maybe() - - m := &Manager{ - devices: []EvdevDevice{mockDevice}, - monitoredPaths: make(map[string]bool), - state: State{Available: true, CapsLock: false}, - closeChan: make(chan struct{}), - } - - ch1 := m.Subscribe("client1") - ch2 := m.Subscribe("client2") - - newState := State{Available: true, CapsLock: true} - go m.notifySubscribers(newState) - - state1 := <-ch1 - state2 := <-ch2 - - assert.Equal(t, newState, state1) - assert.Equal(t, newState, state2) - - m.Close() -} - -func TestReadInitialCapsLockState(t *testing.T) { - t.Run("caps lock is on", func(t *testing.T) { - mockDevice := mocks.NewMockEvdevDevice(t) - ledState := evdev.StateMap{ - ledCapslockKey: true, - } - mockDevice.EXPECT().State(evdev.EvType(evLedType)).Return(ledState, nil).Once() - - result := readInitialCapsLockState(mockDevice) - assert.True(t, result) - }) - - t.Run("caps lock is off", func(t *testing.T) { - mockDevice := mocks.NewMockEvdevDevice(t) - ledState := evdev.StateMap{ - ledCapslockKey: false, - } - mockDevice.EXPECT().State(evdev.EvType(evLedType)).Return(ledState, nil).Once() - - result := readInitialCapsLockState(mockDevice) - assert.False(t, result) - }) - - t.Run("error reading LED state", func(t *testing.T) { - mockDevice := mocks.NewMockEvdevDevice(t) - mockDevice.EXPECT().State(evdev.EvType(evLedType)).Return(nil, errors.New("read error")).Once() - - result := readInitialCapsLockState(mockDevice) - assert.False(t, result) - }) -} - -func TestHasInputGroupAccess(t *testing.T) { - result := hasInputGroupAccess() - t.Logf("hasInputGroupAccess: %v", result) -} diff --git a/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/server/evdev/models.go b/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/server/evdev/models.go deleted file mode 100644 index df8ec9e..0000000 --- a/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/server/evdev/models.go +++ /dev/null @@ -1,6 +0,0 @@ -package evdev - -type State struct { - Available bool `json:"available"` - CapsLock bool `json:"capsLock"` -} |