Created
September 5, 2016 08:42
-
-
Save anonymous/56473f34704f3e9725076fd2215cdf94 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import pynput.keyboard # from pynput.keyboard import Key, Listener, Controller | |
import operator | |
import functools | |
from pynput._util.xorg_keysyms import KEYSYMS | |
import traceback | |
reset_queue_key = pynput.keyboard.Key.pause | |
log_function_calls = False | |
def log_calls(f): | |
if not log_function_calls: | |
return f | |
def f_with_call_logging(*args): | |
print("[begin] " + f.__name__) | |
f(*args) | |
print("[ended] " + f.__name__) | |
return f_with_call_logging | |
@log_calls | |
def ends_with_sublist(sub, lst): | |
n = len(sub) | |
if n > len(lst) or len(sub) == 0 or len(lst) == 0: | |
return False | |
matched = 0 | |
ret = False | |
for i in range(len(sub), 0, -1): | |
if sub[:i] == lst[-i:]: | |
matched = i | |
break | |
print("matched : ", matched, "/", n) | |
return matched == n | |
class HotKeyMan(object): | |
def __init__(self): | |
self._pressing = list() | |
#self._press_history = list() | |
self._comb_history = list() | |
self._is_comb = False | |
self._registered_hotkeys = dict() | |
self._registered_sequences = dict() | |
self._log_calls = False | |
# def register_hotkey(self, hotkeys_list, call): | |
# if not self._validate_hotkeys(hotkeys_list): | |
# print("invalid hotkeys") | |
# return | |
# self._registered_hotkeys[frozenset(hotkeys_list)] = call | |
# print("[hotkey registered] " + str(frozenset(hotkeys_list))) | |
def register_comb_sequence(self, sequence_list, call): | |
if not self._validate_sequence(sequence_list): | |
print("invalid sequence") | |
return | |
comb_seq = list() | |
for key_combination in sequence_list: | |
if isinstance(key_combination, str): | |
comb_seq.append(frozenset([key_combination,])) | |
elif isinstance(key_combination, list) or isinstance(key_combination, tuple): | |
comb_seq.append(frozenset(key_combination)) | |
else: | |
print("invalid sequence") | |
return | |
self._registered_sequences[tuple(comb_seq)] = call | |
print("[sequence registered] " + str(tuple(comb_seq))) | |
@staticmethod | |
def _validate_hotkeys(hotkeys_list): | |
#TODO | |
pass | |
return True | |
@staticmethod | |
def _validate_sequence(sequence_list): | |
#TODO | |
pass | |
return True | |
@log_calls | |
def _on_press(self, key): | |
if hasattr(key, "name"): | |
self._pressing.insert(0, key.name) | |
elif hasattr(key, "char"): | |
self._pressing.insert(0, key.char) | |
self._pressing = self._pressing[:10] # limit length | |
self._handle_key_sequences() | |
return True | |
# def _handle_pressing_keys(self): | |
# combinations = set() | |
# for i in range(1, len(self._pressing) + 1): | |
# combinations_by_i = (frozenset(c) for c in itertools.combinations(self._pressing, i)) | |
# combinations = combinations.union(combinations_by_i) | |
# #print("combinations: ") | |
# for c in combinations: | |
# #print(" " + str(c)) | |
# if c in self._registered_hotkeys: | |
# print("[TRIGGERED] " + str(c)) | |
# self._registered_hotkeys[c]() | |
# #print("/combinations") | |
@log_calls | |
def _handle_key_sequences(self): | |
#self._press_history.append(frozenset(self._pressing)) | |
#self._press_history = self._press_history[-10:] | |
if len(self._pressing) > 1 and not self._is_comb: | |
self._comb_history.pop() | |
self._comb_history.append(frozenset(self._pressing)) | |
self._comb_history = self._comb_history[-10:] | |
for key_seq, func in self._registered_sequences.items(): | |
# print(" key_seq : ", str(key_seq), "\n", "comb_history : ", self._comb_history) | |
if ends_with_sublist(key_seq, tuple(self._comb_history)): | |
print("[TRIGGERED] " + str(key_seq)) | |
self._registered_sequences[key_seq]() | |
@log_calls | |
def _on_release(self, key): | |
try: | |
if hasattr(key, "name"): | |
self._pressing.remove(key.name) | |
elif hasattr(key, "char"): | |
self._pressing.remove(key.char) | |
else: | |
# TODO | |
#print("============= WHAT HAPPENED? ===============") | |
pass | |
#print("released {}".format(key)) | |
except: | |
print(dir(key)) | |
traceback.print_stack() | |
self._pressing.clear() | |
if self._pressing: | |
self._is_comb = True | |
else: | |
self._is_comb = False | |
if key == reset_queue_key: | |
self._pressing.clear() | |
#return False # Stop listener | |
def listen(self): | |
# Collect events until released | |
with pynput.keyboard.Listener(on_press=self._on_press, | |
on_release=self._on_release) as listener: | |
listener.join() | |
print("stopped") | |
#hkm = HotKeyMan() | |
#hkm.register_comb_sequence([('alt', 'r'), 'h', 'a', 'l', 'l', 'o'], lambda:print('wtb: true programmer')) | |
#hkm.register_comb_sequence([("alt", "r")], lambda:print("foo")) | |
#hkm.register_comb_sequence([("alt", "r"), ("alt", "y")], lambda:print("bar")) | |
#def fdo(): | |
# print("t e s t") | |
#hkm.register_comb_sequence(list("test"), fdo) | |
#hkm.listen() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment