first commit
This commit is contained in:
@@ -0,0 +1,100 @@
|
||||
"""Консольный бэкенд клавиш — для разработки и теста в Linux.
|
||||
|
||||
Глобальный хук клавиатуры (библиотека keyboard) на Linux требует root,
|
||||
поэтому здесь клавиши имитируются вводом в терминале:
|
||||
|
||||
Enter — нажать/отпустить «Слушай» (первое нажатие = начать запись,
|
||||
второе = отпустить и обработать; аналог удержания кнопки);
|
||||
s + Enter — «Замолчи»;
|
||||
r + Enter — «Повтори»;
|
||||
q + Enter — выход.
|
||||
|
||||
На Windows-ПК отец получит настоящие глобальные клавиши (keyboard_hook.py).
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import threading
|
||||
|
||||
from .base import KeyEvents
|
||||
|
||||
|
||||
class ConsoleBackend:
|
||||
name = "console"
|
||||
|
||||
def __init__(self, events: KeyEvents) -> None:
|
||||
self._events = events
|
||||
self._talk_held = False
|
||||
self._running = False
|
||||
|
||||
def start(self) -> None:
|
||||
import threading
|
||||
|
||||
self._running = True
|
||||
thread = threading.Thread(target=self._loop, daemon=True)
|
||||
thread.start()
|
||||
|
||||
def stop(self) -> None:
|
||||
self._running = False
|
||||
|
||||
# --- внутреннее ------------------------------------------------------
|
||||
def _loop(self) -> None:
|
||||
# Одиночные клавиши БЕЗ Enter (readchar): работает без root, когда
|
||||
# окно терминала в фокусе. Пробел = настоящий пробел, как на Windows.
|
||||
try:
|
||||
import readchar
|
||||
use_readchar = True
|
||||
except ImportError:
|
||||
use_readchar = False # фолбэк: строки + Enter (старое поведение)
|
||||
|
||||
if use_readchar:
|
||||
self._loop_readchar(readchar)
|
||||
else:
|
||||
self._loop_lines()
|
||||
|
||||
def _loop_readchar(self, readchar) -> None:
|
||||
while self._running:
|
||||
key = readchar.readkey()
|
||||
if key in ("\r", "\n"):
|
||||
continue # Enter игнорируем (не part of управления)
|
||||
if key == " ":
|
||||
self._events.on_dialog_toggle() # ПРОБЕЛ = тумблер диалога
|
||||
elif key == "s":
|
||||
self._events.on_stop()
|
||||
elif key == "r":
|
||||
self._events.on_repeat()
|
||||
elif key in ("q", "\x03"): # q или Ctrl+C
|
||||
self._events.on_quit()
|
||||
return
|
||||
# остальные клавиши игнорируются
|
||||
|
||||
def _loop_lines(self) -> None:
|
||||
"""Фолбэк: строки через Enter (если readchar не установлен)."""
|
||||
if self._events.on_dialog_toggle:
|
||||
print(" (readchar не установлен: пробел имитируй 'd' + Enter; "
|
||||
"pip install readchar — включит настоящий пробел)")
|
||||
while self._running:
|
||||
try:
|
||||
line = input()
|
||||
except EOFError: # stdin закрылся — выходим
|
||||
self._events.on_quit()
|
||||
return
|
||||
|
||||
cmd = line.strip().lower()
|
||||
if cmd == "q":
|
||||
self._events.on_quit()
|
||||
return
|
||||
if cmd in ("d", "space", "пробел"):
|
||||
if self._events.on_dialog_toggle:
|
||||
self._events.on_dialog_toggle()
|
||||
elif cmd == "s":
|
||||
self._events.on_stop()
|
||||
elif cmd == "r":
|
||||
self._events.on_repeat()
|
||||
elif cmd == "":
|
||||
# Enter без текста = нажатие/отпускание «Слушай» (push-to-talk)
|
||||
if self._talk_held:
|
||||
self._talk_held = False
|
||||
self._events.on_talk_up()
|
||||
else:
|
||||
self._talk_held = True
|
||||
self._events.on_talk_down()
|
||||
Reference in New Issue
Block a user