-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathkeyboardShortcuts.py
More file actions
90 lines (76 loc) · 2.88 KB
/
keyboardShortcuts.py
File metadata and controls
90 lines (76 loc) · 2.88 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
from PyQt5 import QtCore
import keyboard
import queue
class keyboardShortcuts(QtCore.QThread):
"""Creates/removes global hotkeys and emits events when they fire."""
new_key_press = QtCore.pyqtSignal()
def __init__(self, keybind_queue, keypress_queue, poll_ms=200, parent=None):
super().__init__(parent)
self.keybind_queue = keybind_queue
self.keypress_queue = keypress_queue
self.poll_ms = int(poll_ms)
# app_name -> {"value": <key>, "hotkey_up": <id>, "hotkey_down": <id>}
self.binds = {}
self._running = True
def stop(self):
"""Stop thread and remove any registered hotkeys."""
self._running = False
def _emit_volume_change(self, app, direction):
self.keypress_queue.put({app: direction})
self.new_key_press.emit()
def _remove_bind(self, app):
"""Remove hotkeys for a given app if present."""
info = self.binds.get(app)
if not info:
return
for key in ("hotkey_up", "hotkey_down"):
hotkey_id = info.get(key)
if hotkey_id is not None:
try:
keyboard.remove_hotkey(hotkey_id)
except Exception:
pass
self.binds.pop(app, None)
def clear_hotkeys(self):
"""Remove all hotkeys currently registered by this thread."""
for app in list(self.binds.keys()):
self._remove_bind(app)
def _apply_binds(self, new_binds):
"""
new_binds expected like: {app_name: "k", ...}
Creates:
shift+page up+<k> -> volume up for app_name
shift+page down+<k> -> volume down for app_name
"""
for app, key in new_binds.items():
# Remove existing hotkeys for this app before re-adding
self._remove_bind(app)
hotkey_up_str = f"shift+page up+{key}"
hotkey_down_str = f"shift+page down+{key}"
self.binds[app] = {
"value": key,
"hotkey_up": keyboard.add_hotkey(
hotkey_up_str,
self._emit_volume_change,
args=[app, "up"],
suppress=True,
),
"hotkey_down": keyboard.add_hotkey(
hotkey_down_str,
self._emit_volume_change,
args=[app, "down"],
suppress=True,
),
}
def run(self):
while self._running and not self.isInterruptionRequested():
# Drain any pending bind updates quickly
try:
while True:
new_binds = self.keybind_queue.get_nowait()
self._apply_binds(new_binds)
except queue.Empty:
pass
self.msleep(self.poll_ms)
# Cleanup on exit
self.clear_hotkeys()