58 lines
1.5 KiB
Python
58 lines
1.5 KiB
Python
|
|
"""Einstellungs-Dialog für whisper-local (Windows)."""
|
||
|
|
|
||
|
|
from __future__ import annotations
|
||
|
|
|
||
|
|
import ctypes
|
||
|
|
import threading
|
||
|
|
from typing import Callable
|
||
|
|
|
||
|
|
import sounddevice as sd
|
||
|
|
|
||
|
|
from whisper_local.config import Config, save_config
|
||
|
|
|
||
|
|
|
||
|
|
def pynput_to_evdev_key(key) -> str:
|
||
|
|
"""Konvertiert pynput-Key zu evdev-Key-Namen (z.B. Key.f12 → 'KEY_F12')."""
|
||
|
|
from pynput.keyboard import Key, KeyCode
|
||
|
|
|
||
|
|
if isinstance(key, Key):
|
||
|
|
return f"KEY_{key.name.upper()}"
|
||
|
|
if isinstance(key, KeyCode) and key.char:
|
||
|
|
return f"KEY_{key.char.upper()}"
|
||
|
|
return ""
|
||
|
|
|
||
|
|
|
||
|
|
def check_hotkey_conflict(evdev_name: str) -> bool:
|
||
|
|
"""Gibt True zurück wenn die Taste per Win32-RegisterHotKey belegt ist."""
|
||
|
|
from whisper_local.hotkey._pynput import _evdev_to_pynput_key
|
||
|
|
from pynput.keyboard import Key
|
||
|
|
|
||
|
|
try:
|
||
|
|
pynput_key = _evdev_to_pynput_key(evdev_name)
|
||
|
|
except ValueError:
|
||
|
|
return False
|
||
|
|
|
||
|
|
if not isinstance(pynput_key, Key):
|
||
|
|
return False
|
||
|
|
|
||
|
|
vk = getattr(pynput_key.value, "vk", None)
|
||
|
|
if vk is None:
|
||
|
|
return False
|
||
|
|
|
||
|
|
HOTKEY_ID = 0x7FFF
|
||
|
|
user32 = ctypes.windll.user32
|
||
|
|
if user32.RegisterHotKey(None, HOTKEY_ID, 0, vk):
|
||
|
|
user32.UnregisterHotKey(None, HOTKEY_ID)
|
||
|
|
return False
|
||
|
|
return True
|
||
|
|
|
||
|
|
|
||
|
|
def list_microphones() -> list[tuple[str, int]]:
|
||
|
|
"""Gibt Liste aller Eingabegeräte als (name, index) zurück."""
|
||
|
|
devices = sd.query_devices()
|
||
|
|
return [
|
||
|
|
(dev["name"], idx)
|
||
|
|
for idx, dev in enumerate(devices)
|
||
|
|
if dev["max_input_channels"] > 0
|
||
|
|
]
|