mirror of
https://github.com/yusufipk/dikte.git
synced 2026-09-11 10:56:10 +00:00
Stop the KDE shortcut and the built-in listener from doubling a press
The listener reads /dev/input and reacts the instant a key goes down. The KDE shortcut answers the same press by launching a whole Python process, which then talks over IPC, so its toggle lands a few hundred milliseconds later. The 400 ms guard caught that echo only when the machine happened to be quick, and otherwise the recording was started and stopped by one press: "No speech detected". Route the two apart. A toggle arriving from outside the process right behind a listener trigger is that echo, and its lateness also proves the KDE shortcut is live, which leaves the listener with nothing to do but double every press. So retire it, remember that in the config, and say so in the tray rather than changing behaviour silently.
This commit is contained in:
@@ -34,6 +34,11 @@ from worker import Pipeline # noqa: E402
|
||||
SERVER_NAME = "dikte-" + str(os.getuid())
|
||||
IDLE, RECORDING, BUSY = "idle", "recording", "busy"
|
||||
|
||||
# The KDE shortcut answers a key press by launching a whole Python process, so
|
||||
# its toggle lands well after the built-in listener has handled the same press.
|
||||
# Anything arriving inside this window is that echo, not a second press.
|
||||
ECHO_MS = 2000
|
||||
|
||||
|
||||
class Dikte:
|
||||
def __init__(self, app):
|
||||
@@ -53,11 +58,12 @@ class Dikte:
|
||||
self.pipeline.stage.connect(self.overlay.show_busy)
|
||||
self.pipeline.finished.connect(self._on_finished)
|
||||
self.pipeline.failed.connect(self._on_error)
|
||||
self.evdev.triggered.connect(self.toggle)
|
||||
self.evdev.triggered.connect(self._on_evdev)
|
||||
self.evdev.failed.connect(self._on_error)
|
||||
|
||||
self.elapsed = QElapsedTimer()
|
||||
self.last_toggle = QElapsedTimer()
|
||||
self.last_evdev = QElapsedTimer()
|
||||
self.ticker = QTimer()
|
||||
self.ticker.setInterval(100)
|
||||
self.ticker.timeout.connect(self._tick)
|
||||
@@ -73,7 +79,7 @@ class Dikte:
|
||||
# are only passed to addAction(), and garbage collection eats them.
|
||||
self.menu = QMenu()
|
||||
self.toggle_action = QAction(t("Start recording"), self.menu)
|
||||
self.toggle_action.triggered.connect(self.toggle)
|
||||
self.toggle_action.triggered.connect(self._toggle)
|
||||
self.menu.addAction(self.toggle_action)
|
||||
|
||||
self.cancel_action = QAction(t("Cancel recording"), self.menu)
|
||||
@@ -102,7 +108,7 @@ class Dikte:
|
||||
|
||||
def _tray_clicked(self, reason):
|
||||
if reason == QSystemTrayIcon.ActivationReason.Trigger:
|
||||
self.toggle()
|
||||
self._toggle()
|
||||
|
||||
def _set_icon(self, name):
|
||||
icon = QIcon.fromTheme(name)
|
||||
@@ -129,8 +135,36 @@ class Dikte:
|
||||
# ---- actions ---------------------------------------------------------
|
||||
|
||||
def toggle(self):
|
||||
# With both the KDE shortcut and the built-in listener active the key
|
||||
# arrives twice; swallow the immediate repeat.
|
||||
"""A toggle from outside this process: the KDE shortcut, or the CLI."""
|
||||
# The built-in listener sees the key press the instant it happens, so a
|
||||
# toggle arriving right behind one is the KDE shortcut catching up on
|
||||
# that same press. Its lateness is also the proof we were waiting for
|
||||
# that the shortcut is live, which leaves the listener with nothing to
|
||||
# do but double every press.
|
||||
if (self.evdev.running and self.last_evdev.isValid()
|
||||
and self.last_evdev.elapsed() < ECHO_MS):
|
||||
self._retire_listener()
|
||||
return
|
||||
self._toggle()
|
||||
|
||||
def _on_evdev(self):
|
||||
self.last_evdev.restart()
|
||||
self._toggle()
|
||||
|
||||
def _retire_listener(self):
|
||||
self.evdev.stop()
|
||||
self.conf["evdev_hotkey"] = False
|
||||
self.conf.save()
|
||||
self.tray.showMessage(
|
||||
"Dikte",
|
||||
t("The KDE shortcut is live now, so the built-in listener has been "
|
||||
"turned off. It was doubling every key press."),
|
||||
QSystemTrayIcon.MessageIcon.Information, 8000,
|
||||
)
|
||||
|
||||
def _toggle(self):
|
||||
# Two /dev/input nodes can carry the same keyboard, and a menu click can
|
||||
# land on top of a key press; swallow the immediate repeat.
|
||||
if self.last_toggle.isValid() and self.last_toggle.elapsed() < 400:
|
||||
return
|
||||
self.last_toggle.restart()
|
||||
|
||||
@@ -122,7 +122,9 @@ class EvdevHotkey(QObject):
|
||||
held = set()
|
||||
try:
|
||||
while not self._stop.is_set():
|
||||
ready, _, _ = select.select(fds, [], [], 0.4)
|
||||
# Short enough that stop() does not stall its caller waiting for
|
||||
# the read to come back around.
|
||||
ready, _, _ = select.select(fds, [], [], 0.15)
|
||||
for fd in ready:
|
||||
try:
|
||||
data = os.read(fd, self.EVENT_SIZE * 64)
|
||||
|
||||
@@ -61,6 +61,10 @@ TR = {
|
||||
"{service} hesapta kredi kalmadığını söylüyor (HTTP 402).",
|
||||
"{service} is rate limiting you (HTTP 429). Try again in a moment.":
|
||||
"{service} hız sınırı uyguluyor (HTTP 429). Birazdan tekrar dene.",
|
||||
"The KDE shortcut is live now, so the built-in listener has been "
|
||||
"turned off. It was doubling every key press.":
|
||||
"KDE kısayolu artık çalışıyor, bu yüzden dahili dinleyici kapatıldı. "
|
||||
"Her tuşa basışı ikiye katlıyordu.",
|
||||
"No speech detected": "Ses algılanmadı",
|
||||
"No speech detected ({level} dB)": "Ses algılanmadı ({level} dB)",
|
||||
"Discarded a stock phrase: “{text}”": "Kalıp cümle atıldı: “{text}”",
|
||||
|
||||
Reference in New Issue
Block a user