feat: add hotkey conflict detection and microphone listing helpers

Implementiere drei Hilfsfunktionen in _settings.py:
- check_hotkey_conflict(): Prüft mit Win32 RegisterHotKey ob eine Taste belegt ist
- list_microphones(): Gibt alle Eingabegeräte als (name, index) Tupel zurück
- pynput_to_evdev_key(): Konvertiert pynput Keys zu evdev Key-Namen

Alle Tests (9 neue + 9 existierende) bestehen.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-10 21:13:00 +02:00
parent 2630d4c7a5
commit 32c40827e0
2 changed files with 134 additions and 0 deletions
+77
View File
@@ -105,3 +105,80 @@ class TestApplySystemTheme:
mock_set.assert_called_once_with("light")
finally:
root.destroy()
@pytest.mark.skipif(sys.platform != "win32", reason="Settings nur auf Windows")
class TestCheckHotkeyConflict:
def test_returns_false_when_key_is_free(self):
from unittest.mock import patch, MagicMock
from whisper_local.tray._settings import check_hotkey_conflict
mock_user32 = MagicMock()
mock_user32.RegisterHotKey.return_value = 1 # Erfolg
with patch("ctypes.windll") as mock_windll:
mock_windll.user32 = mock_user32
result = check_hotkey_conflict("KEY_F12")
assert result is False
mock_user32.UnregisterHotKey.assert_called_once()
def test_returns_true_when_key_is_taken(self):
from unittest.mock import patch, MagicMock
from whisper_local.tray._settings import check_hotkey_conflict
mock_user32 = MagicMock()
mock_user32.RegisterHotKey.return_value = 0 # Belegt
with patch("ctypes.windll") as mock_windll:
mock_windll.user32 = mock_user32
result = check_hotkey_conflict("KEY_F12")
assert result is True
mock_user32.UnregisterHotKey.assert_not_called()
def test_returns_false_for_unknown_key(self):
from whisper_local.tray._settings import check_hotkey_conflict
result = check_hotkey_conflict("KEY_NONEXISTENT_999")
assert result is False
class TestListMicrophones:
def test_returns_only_input_devices(self):
from unittest.mock import patch
from whisper_local.tray._settings import list_microphones
fake_devices = [
{"name": "Speakers", "max_input_channels": 0},
{"name": "Headset Mic", "max_input_channels": 1},
{"name": "USB Mic", "max_input_channels": 2},
]
with patch("sounddevice.query_devices", return_value=fake_devices):
result = list_microphones()
assert result == [("Headset Mic", 1), ("USB Mic", 2)]
def test_returns_empty_list_when_no_input(self):
from unittest.mock import patch
from whisper_local.tray._settings import list_microphones
with patch("sounddevice.query_devices", return_value=[]):
result = list_microphones()
assert result == []
class TestPynputToEvdevKey:
def test_function_key(self):
from pynput.keyboard import Key
from whisper_local.tray._settings import pynput_to_evdev_key
assert pynput_to_evdev_key(Key.f12) == "KEY_F12"
def test_space_key(self):
from pynput.keyboard import Key
from whisper_local.tray._settings import pynput_to_evdev_key
assert pynput_to_evdev_key(Key.space) == "KEY_SPACE"
def test_char_key(self):
from pynput.keyboard import KeyCode
from whisper_local.tray._settings import pynput_to_evdev_key
key = KeyCode.from_char("a")
assert pynput_to_evdev_key(key) == "KEY_A"
def test_unknown_returns_empty(self):
from whisper_local.tray._settings import pynput_to_evdev_key
assert pynput_to_evdev_key(None) == ""