refactor: convert hotkey module to package with evdev backend

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Vitali Graf
2026-04-08 10:28:52 +02:00
parent 5c8eecbb8b
commit f9bc2204c7
3 changed files with 32 additions and 9 deletions
+4 -3
View File
@@ -1,14 +1,16 @@
import asyncio import asyncio
import sys
from unittest.mock import AsyncMock, MagicMock, patch from unittest.mock import AsyncMock, MagicMock, patch
import pytest import pytest
from whisper_local.hotkey import HotkeyListener pytestmark = pytest.mark.skipif(sys.platform != "linux", reason="evdev only available on Linux")
@pytest.fixture @pytest.fixture
def listener(): def listener():
return HotkeyListener(key_name="KEY_F12") from whisper_local.hotkey._evdev import EvdevHotkeyListener
return EvdevHotkeyListener(key_name="KEY_F12")
class TestHotkeyListener: class TestHotkeyListener:
@@ -33,6 +35,5 @@ class TestHotkeyListener:
@pytest.mark.asyncio @pytest.mark.asyncio
async def test_no_callback_no_error(self, listener): async def test_no_callback_no_error(self, listener):
# Kein Callback gesetzt — soll nicht crashen
await listener._handle_key_event(key_down=True) await listener._handle_key_event(key_down=True)
await listener._handle_key_event(key_down=False) await listener._handle_key_event(key_down=False)
+24
View File
@@ -0,0 +1,24 @@
"""Hotkey-Listener — plattformspezifische Backends hinter gemeinsamem Interface."""
import sys
from typing import Callable, Coroutine, Protocol, runtime_checkable
AsyncCallback = Callable[[], Coroutine]
@runtime_checkable
class HotkeyListener(Protocol):
on_press: AsyncCallback | None
on_release: AsyncCallback | None
async def listen(self) -> None: ...
def create_listener(key_name: str = "KEY_F12") -> HotkeyListener:
"""Erstellt den plattformspezifischen HotkeyListener."""
if sys.platform == "linux":
from whisper_local.hotkey._evdev import EvdevHotkeyListener
return EvdevHotkeyListener(key_name)
else:
from whisper_local.hotkey._pynput import PynputHotkeyListener
return PynputHotkeyListener(key_name)
@@ -1,16 +1,14 @@
"""Hotkey-Listener via evdev für Push-to-Talk.""" """Hotkey-Listener via evdev für Push-to-Talk (Linux)."""
import asyncio import asyncio
import logging import logging
from pathlib import Path
from typing import Callable, Coroutine
import evdev import evdev
from evdev import InputDevice, categorize, ecodes from evdev import InputDevice, categorize, ecodes
logger = logging.getLogger(__name__) from whisper_local.hotkey import AsyncCallback
AsyncCallback = Callable[[], Coroutine] logger = logging.getLogger(__name__)
def find_keyboard_devices(key_name: str) -> list[InputDevice]: def find_keyboard_devices(key_name: str) -> list[InputDevice]:
@@ -31,7 +29,7 @@ def find_keyboard_devices(key_name: str) -> list[InputDevice]:
return matches return matches
class HotkeyListener: class EvdevHotkeyListener:
def __init__(self, key_name: str = "KEY_F12"): def __init__(self, key_name: str = "KEY_F12"):
self.key_name = key_name self.key_name = key_name
self.key_code = ecodes.ecodes.get(key_name) self.key_code = ecodes.ecodes.get(key_name)