Skip to content

Commit 48adc34

Browse files
authored
Add files via upload
1 parent 7b5b164 commit 48adc34

File tree

1 file changed

+213
-0
lines changed

1 file changed

+213
-0
lines changed

simplehotkeys.py

Lines changed: 213 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,213 @@
1+
import threading, time
2+
3+
IN_WHILE_SLEEP = 0.01
4+
PRESS_VS_LONGPRESS = 370/1000
5+
LONGPRESS_VS_TOOLONGPRESS = 1600/1000
6+
DOUBLEPRESS_BETWEEN = 300/1000
7+
CALL_THREADED = True
8+
9+
10+
## pynput ##
11+
import pynput.keyboard
12+
13+
pynput_keys_DOWN = []
14+
15+
def pynput_on_press_lambda (key):
16+
global pynput_keys_DOWN
17+
if not key in pynput_keys_DOWN:
18+
pynput_keys_DOWN.append(key)
19+
20+
def pynput_on_release_lambda (key):
21+
global pynput_keys_DOWN
22+
pynput_keys_DOWN=[x for x in pynput_keys_DOWN if x != key]
23+
24+
pynput_listener = pynput.keyboard.Listener(
25+
on_press=pynput_on_press_lambda,
26+
on_release=pynput_on_release_lambda
27+
).start()
28+
29+
def pynput_pressed(keys=[]): # are these keys pressed? dont care about other keys
30+
for k in keys:
31+
if k not in pynput_keys_DOWN:
32+
return False
33+
return True
34+
35+
def pynput_pressed_exclusively(keys=[]): # are exactly these keys pressed? other keys cant be pressed
36+
if len(pynput_keys_DOWN) == len(keys):
37+
return pynput_pressed(keys)
38+
else:
39+
#print(pynput_keys_DOWN)
40+
return False
41+
## pynput ##
42+
43+
'''
44+
## keyboard ## - keyboard library can be also used (but was removed because contained bugs)
45+
import keyboard
46+
47+
def keyboard_pressed(keys=[]): ## IF PRESSED + DONT CARE ABOUT OTHER KEYS => ITS NOT EXCLUSIVELY PRESSED
48+
for k in keys:
49+
if not keyboard.is_pressed(k):
50+
return False
51+
return True
52+
53+
## keyboard ##
54+
'''
55+
56+
57+
58+
def pressed (keys=[]):
59+
# TODO: convert keys=<string list> to pynput key list
60+
#return keyboard_pressed(keys)
61+
return pynput_pressed_exclusively(keys)
62+
63+
64+
65+
def _keys_are_same(k1, k2):
66+
if len(k1) == len(k2):
67+
for k in k1:
68+
if not k in k2:
69+
return False
70+
return True
71+
else:
72+
return False
73+
74+
def _handler_is_running(id):
75+
global registered_hotkeys
76+
for r in registered_hotkeys:
77+
if id in r:
78+
return True
79+
return False
80+
81+
def _get_handler_id(k):
82+
global registered_hotkeys
83+
for i in range(len(registered_hotkeys)):
84+
if _keys_are_same(registered_hotkeys[i][0],k):
85+
return registered_hotkeys[i][-1]
86+
return 0
87+
88+
89+
## HAMDLERS ##
90+
91+
#TODO: def key_press_time(...): # return values to callback function (for custom press types)
92+
#TODO: call_function (keydown_or_keyup, number, time_before, duration, [<the_real_order_of_keys>])
93+
94+
def press (keys=[], on_press=lambda: None):
95+
id = _get_handler_id(keys)
96+
while True:
97+
while not pressed(keys):
98+
time.sleep(IN_WHILE_SLEEP)
99+
if not _handler_is_running(id): return
100+
101+
on_press()
102+
103+
while pressed(keys):
104+
time.sleep(IN_WHILE_SLEEP)
105+
106+
def press_longpress_toolongpress (keys=[], on_press=lambda: None, on_longpress=lambda: None, on_toolongpress=lambda: None):
107+
id = _get_handler_id(keys)
108+
while True:
109+
while not pressed(keys):
110+
time.sleep(IN_WHILE_SLEEP)
111+
if not _handler_is_running(id): return
112+
113+
t = time.time()
114+
115+
while pressed(keys):
116+
time.sleep(IN_WHILE_SLEEP)
117+
118+
t = time.time() - t
119+
120+
if t < PRESS_VS_LONGPRESS:
121+
on_press()
122+
elif t < LONGPRESS_VS_TOOLONGPRESS:
123+
on_longpress()
124+
else:
125+
on_toolongpress()
126+
127+
def press_doublepress_longpress_toolongpress (keys=[], on_press=lambda: None, on_doublepress=lambda: None, on_longpress=lambda: None, on_toolongpress=lambda: None):
128+
id = _get_handler_id(keys)
129+
while True:
130+
while not pressed(keys):
131+
time.sleep(IN_WHILE_SLEEP)
132+
if not _handler_is_running(id): return
133+
134+
t = time.time()
135+
136+
while pressed(keys):
137+
time.sleep(IN_WHILE_SLEEP)
138+
139+
t = time.time() - t
140+
141+
if t < PRESS_VS_LONGPRESS:
142+
tt = time.time()
143+
while not pressed(keys) and time.time()-tt <= DOUBLEPRESS_BETWEEN:
144+
time.sleep(IN_WHILE_SLEEP)
145+
146+
tt = time.time()-tt
147+
if tt < DOUBLEPRESS_BETWEEN:
148+
on_doublepress()
149+
else:
150+
on_press()
151+
152+
while pressed(keys):
153+
time.sleep(IN_WHILE_SLEEP)
154+
155+
elif t < LONGPRESS_VS_TOOLONGPRESS:
156+
on_longpress()
157+
else:
158+
on_toolongpress()
159+
160+
161+
162+
registered_hotkeys = [] # [keys,on_..., inique_id]
163+
last_thread_number = 0
164+
165+
def catch_hotkey (timeout=10):
166+
global pynput_keys_DOWN
167+
t = time.time() + timeout
168+
keys = []
169+
while t > time.time():
170+
if len(keys) < len(pynput_keys_DOWN):
171+
keys = pynput_keys_DOWN
172+
elif len(keys) > len(pynput_keys_DOWN):
173+
return keys
174+
time.sleep(IN_WHILE_SLEEP)
175+
176+
177+
def add_hotkey (keys=[], _callback_press=None, _callback_longpress=None, _callback_toolongpress=None, _callback_doublepress=None):
178+
global registered_hotkeys, last_thread_number
179+
180+
for i in range(len(registered_hotkeys)):
181+
if _keys_are_same(registered_hotkeys[i][0], keys):
182+
registered_hotkeys.pop(i)
183+
break
184+
185+
if CALL_THREADED:
186+
callback_press = lambda: threading.Thread(target=_callback_press).start() # if _callback_press is not None else None
187+
callback_longpress = lambda: threading.Thread(target=_callback_longpress).start()
188+
callback_toolongpress = lambda: threading.Thread(target=_callback_toolongpress).start()
189+
callback_doublepress = lambda: threading.Thread(target=_callback_doublepress).start()
190+
else:
191+
callback_press = _callback_press
192+
callback_longpress = _callback_longpress
193+
callback_toolongpress = _callback_toolongpress
194+
callback_doublepress = _callback_doublepress
195+
196+
197+
last_thread_number = last_thread_number+1
198+
registered_hotkeys.append([keys, callback_press, callback_longpress, callback_toolongpress, callback_doublepress, last_thread_number])
199+
200+
201+
if _callback_press is None and _callback_doublepress is None and _callback_longpress is None and _callback_toolongpress is None: # remove
202+
return
203+
elif _callback_press is not None and (_callback_doublepress is None and _callback_longpress is None and _callback_toolongpress is None): # press
204+
th = threading.Thread(target=press, args=(keys, callback_press))
205+
elif _callback_doublepress is None: # press_longpress_toolongpress
206+
th = threading.Thread(target=press_longpress_toolongpress, args=(keys, callback_press, callback_longpress, callback_toolongpress))
207+
else:
208+
th = threading.Thread(target=press_doublepress_longpress_toolongpress, args=(keys, callback_press, callback_doublepress, callback_longpress, callback_toolongpress)) # press_doublepress_longpress_toolongpress
209+
210+
th.daemon = True
211+
th.start()
212+
213+

0 commit comments

Comments
 (0)