fix: ptt auto-detect falls back to toggle mode
Textual does not expose key-release events, so KittyPtt hold-mode never received key_up and stayed transmitting. Auto-detect now tries evdev first, then falls back to toggle (press-on/press-off). Default mode changed to toggle.
This commit is contained in:
@@ -18,8 +18,8 @@ tuimble --host mumble.example.com --user myname
|
|||||||
|
|
||||||
## Push-to-Talk Modes
|
## Push-to-Talk Modes
|
||||||
|
|
||||||
- **hold** — hold key to transmit, release to stop (default)
|
- **toggle** — press to start, press again to stop (default)
|
||||||
- **toggle** — press to start, press again to stop
|
- **hold** — hold key to transmit, release to stop (requires evdev)
|
||||||
|
|
||||||
## Configuration
|
## Configuration
|
||||||
|
|
||||||
|
|||||||
@@ -410,18 +410,15 @@ class TuimbleApp(App):
|
|||||||
|
|
||||||
def on_key(self, event: events.Key) -> None:
|
def on_key(self, event: events.Key) -> None:
|
||||||
"""Handle PTT key events."""
|
"""Handle PTT key events."""
|
||||||
ptt_key = self._config.ptt.key
|
if event.key != self._config.ptt.key:
|
||||||
|
return
|
||||||
|
|
||||||
if isinstance(self._ptt, KittyPtt):
|
if isinstance(self._ptt, TogglePtt):
|
||||||
if event.key == ptt_key:
|
self._ptt.toggle()
|
||||||
is_release = getattr(event, "key_type", None)
|
elif isinstance(self._ptt, KittyPtt):
|
||||||
if is_release == "release":
|
# Kitty hold-mode requires key-release events that Textual
|
||||||
self._ptt.key_up()
|
# does not expose; kept for explicit backend="kitty" only.
|
||||||
else:
|
self._ptt.key_down()
|
||||||
self._ptt.key_down()
|
|
||||||
elif isinstance(self._ptt, TogglePtt):
|
|
||||||
if event.key == ptt_key:
|
|
||||||
self._ptt.toggle()
|
|
||||||
|
|
||||||
def _on_ptt_change(self, transmitting: bool) -> None:
|
def _on_ptt_change(self, transmitting: bool) -> None:
|
||||||
self._audio.capturing = transmitting
|
self._audio.capturing = transmitting
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ class AudioConfig:
|
|||||||
@dataclass
|
@dataclass
|
||||||
class PttConfig:
|
class PttConfig:
|
||||||
key: str = "f4"
|
key: str = "f4"
|
||||||
mode: str = "hold" # hold | toggle
|
mode: str = "toggle" # toggle | hold (hold requires evdev)
|
||||||
backend: str = "auto" # auto | kitty | evdev | toggle
|
backend: str = "auto" # auto | kitty | evdev | toggle
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -139,6 +139,12 @@ def detect_backend(callback: Callback, preference: str = "auto") -> PttBackend:
|
|||||||
if preference == "toggle":
|
if preference == "toggle":
|
||||||
return TogglePtt(callback)
|
return TogglePtt(callback)
|
||||||
|
|
||||||
# auto: try kitty first (will be validated at runtime by the app),
|
# auto: Textual does not expose key-release events, so kitty
|
||||||
# then evdev, then toggle
|
# hold-mode is not viable. Try evdev, fall back to toggle.
|
||||||
return KittyPtt(callback)
|
try:
|
||||||
|
import evdev as _evdev # noqa: F811
|
||||||
|
|
||||||
|
_ = _evdev.list_devices()
|
||||||
|
return EvdevPtt(callback)
|
||||||
|
except Exception:
|
||||||
|
return TogglePtt(callback)
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ def test_default_config():
|
|||||||
assert cfg.server.host == "localhost"
|
assert cfg.server.host == "localhost"
|
||||||
assert cfg.server.port == 64738
|
assert cfg.server.port == 64738
|
||||||
assert cfg.audio.sample_rate == 48000
|
assert cfg.audio.sample_rate == 48000
|
||||||
assert cfg.ptt.mode == "hold"
|
assert cfg.ptt.mode == "toggle"
|
||||||
|
|
||||||
|
|
||||||
def test_server_config():
|
def test_server_config():
|
||||||
|
|||||||
Reference in New Issue
Block a user