feat: Linux-Hotkey-Record via evdev
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -268,3 +268,110 @@ class TestCreateTray:
|
||||
assert AppState.WAITING is not None
|
||||
assert AppState.RECORDING is not None
|
||||
assert AppState.TRANSCRIBING is not None
|
||||
|
||||
|
||||
@pytest.mark.skipif(sys.platform != "linux", reason="evdev-Record nur auf Linux")
|
||||
class TestRecordHotkeyEvdev:
|
||||
def test_first_keydown_triggers_on_result(self):
|
||||
import threading
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
fake_event = MagicMock()
|
||||
fake_event.type = 1 # EV_KEY
|
||||
fake_event.code = 88 # KEY_F12
|
||||
fake_event.value = 1 # Keydown
|
||||
|
||||
fake_device = MagicMock()
|
||||
fake_device.fd = 42
|
||||
fake_device.read.return_value = iter([fake_event])
|
||||
fake_device.close = MagicMock()
|
||||
|
||||
cancel = threading.Event()
|
||||
results: list[tuple[str, bool]] = []
|
||||
|
||||
def on_result(name, conflict):
|
||||
results.append((name, conflict))
|
||||
|
||||
with patch(
|
||||
"whisper_local.tray._hotkey_record_evdev.find_all_keyboards",
|
||||
return_value=[fake_device],
|
||||
), patch(
|
||||
"whisper_local.tray._hotkey_record_evdev.selectors.DefaultSelector"
|
||||
) as mock_sel_cls:
|
||||
mock_sel = MagicMock()
|
||||
mock_sel_cls.return_value = mock_sel
|
||||
sel_key = MagicMock()
|
||||
sel_key.data = fake_device
|
||||
mock_sel.select.return_value = [(sel_key, None)]
|
||||
from whisper_local.tray._hotkey_record_evdev import record_hotkey
|
||||
record_hotkey(on_result, cancel)
|
||||
|
||||
assert results == [("KEY_F12", False)]
|
||||
fake_device.close.assert_called_once()
|
||||
|
||||
def test_cancel_event_stops_recording(self):
|
||||
import threading
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
fake_device = MagicMock()
|
||||
fake_device.fd = 42
|
||||
fake_device.read.return_value = iter([])
|
||||
fake_device.close = MagicMock()
|
||||
|
||||
cancel = threading.Event()
|
||||
cancel.set()
|
||||
|
||||
results: list[tuple[str, bool]] = []
|
||||
|
||||
with patch(
|
||||
"whisper_local.tray._hotkey_record_evdev.find_all_keyboards",
|
||||
return_value=[fake_device],
|
||||
), patch(
|
||||
"whisper_local.tray._hotkey_record_evdev.selectors.DefaultSelector"
|
||||
) as mock_sel_cls:
|
||||
mock_sel = MagicMock()
|
||||
mock_sel_cls.return_value = mock_sel
|
||||
mock_sel.select.return_value = []
|
||||
from whisper_local.tray._hotkey_record_evdev import record_hotkey
|
||||
record_hotkey(lambda n, c: results.append((n, c)), cancel)
|
||||
|
||||
assert results == []
|
||||
fake_device.close.assert_called_once()
|
||||
|
||||
def test_ignores_key_up_events(self):
|
||||
import threading
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
key_up = MagicMock()
|
||||
key_up.type = 1
|
||||
key_up.code = 88
|
||||
key_up.value = 0
|
||||
|
||||
key_down = MagicMock()
|
||||
key_down.type = 1
|
||||
key_down.code = 88
|
||||
key_down.value = 1
|
||||
|
||||
fake_device = MagicMock()
|
||||
fake_device.fd = 42
|
||||
fake_device.read.return_value = iter([key_up, key_down])
|
||||
fake_device.close = MagicMock()
|
||||
|
||||
cancel = threading.Event()
|
||||
results: list[tuple[str, bool]] = []
|
||||
|
||||
with patch(
|
||||
"whisper_local.tray._hotkey_record_evdev.find_all_keyboards",
|
||||
return_value=[fake_device],
|
||||
), patch(
|
||||
"whisper_local.tray._hotkey_record_evdev.selectors.DefaultSelector"
|
||||
) as mock_sel_cls:
|
||||
mock_sel = MagicMock()
|
||||
mock_sel_cls.return_value = mock_sel
|
||||
sel_key = MagicMock()
|
||||
sel_key.data = fake_device
|
||||
mock_sel.select.return_value = [(sel_key, None)]
|
||||
from whisper_local.tray._hotkey_record_evdev import record_hotkey
|
||||
record_hotkey(lambda n, c: results.append((n, c)), cancel)
|
||||
|
||||
assert results == [("KEY_F12", False)]
|
||||
|
||||
Reference in New Issue
Block a user