57 lines
2.8 KiB
Python
57 lines
2.8 KiB
Python
"""Бэкенд глобальных клавиш на библиотеке keyboard — целевой для Windows.
|
|
|
|
Перехватывает клавиши ГЛОБАЛЬНО (окно может быть свёрнуто) — именно то,
|
|
что нужно отцу. Требования/ограничения библиотеки keyboard:
|
|
- Windows: работает без админ-прав;
|
|
- Linux: требует root (поэтому в разработке используем console-бэкенд);
|
|
- проект библиотеки не развивается с 2020 — если на Windows появятся
|
|
проблемы, заменяем на pynput (интерфейс KeyEvents менять не придётся).
|
|
|
|
Клавиши задаются в .env (HOTKEY_TALK / HOTKEY_STOP / HOTKEY_REPEAT);
|
|
по умолчанию: space / esc / enter. Имена — как в библиотеке keyboard
|
|
(numpad-клавиши подберём при настройке на Windows, напр. «num 0», «num enter»).
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
from .base import KeyEvents
|
|
|
|
|
|
class KeyboardHookBackend:
|
|
name = "keys"
|
|
|
|
def __init__(self, events: KeyEvents, talk: str = "num 0",
|
|
stop_key: str = "esc", repeat: str = "enter",
|
|
dialog: str = "space") -> None:
|
|
self._events = events
|
|
self._talk = talk
|
|
self._stop_key = stop_key
|
|
self._repeat = repeat
|
|
self._dialog = dialog # ПРОБЕЛ: тумблер диалога
|
|
self._started = False
|
|
|
|
def start(self) -> None:
|
|
import keyboard # ленивый импорт: на Linux без root упадёт — см. console
|
|
|
|
if self._dialog and self._events.on_dialog_toggle:
|
|
keyboard.add_hotkey(self._dialog, self._events.on_dialog_toggle, suppress=True)
|
|
if self._talk:
|
|
keyboard.on_press_key(self._talk, self._talk_press)
|
|
keyboard.on_release_key(self._talk, self._talk_release)
|
|
keyboard.add_hotkey(self._stop_key, self._events.on_stop, suppress=True)
|
|
keyboard.add_hotkey(self._repeat, self._events.on_repeat, suppress=True)
|
|
self._started = True
|
|
|
|
def stop(self) -> None:
|
|
if self._started:
|
|
import keyboard
|
|
keyboard.unhook_all()
|
|
self._started = False
|
|
|
|
# --- внутреннее ------------------------------------------------------
|
|
def _talk_press(self, event) -> None: # noqa: ANN001
|
|
# Библиотека шлёт повторные down-события при удержании; лишние вызовы
|
|
# безопасны: машина состояний игнорирует on_talk_down в состоянии listening.
|
|
self._events.on_talk_down()
|
|
|
|
def _talk_release(self, event) -> None: # noqa: ANN001
|
|
self._events.on_talk_up() |