I needed to have input shown for some things in a game I play on Linux, but Linux doesn’t seem to have any good input display programs. I decided it would be good enough to have python print to a pair of xterm windows (one for keyboard and one for mouse) using pynput. I do this using two different python programs because the only way I found to have one python programs deal with two terminals is to constantly write to a file and use tail -f, and I didn’t want to do that.
Because both programs ended up being so small and simple, I tried to write it so that the key/mouse listeners would run their functions as fast as possible. But I might have missed some things that could be done. I’m wondering if anyone knows of any other ways to optimize this for response time. I know it won’t make anything close to a noticeable difference, I’m just asking out of curiosity.
mouse_listener.py
from pynput import mouse
def main():
print_count = 0
def on_click(x, y, button, pressed, local_print=print):
nonlocal print_count
try:
if print_count >= 10:
local_print(f"--- {button.name} mouse {'pressed' if pressed else 'released'}")
print_count = 0
else:
local_print(f" {button.name} mouse {'pressed' if pressed else 'released'}")
print_count += 1
except AttributeError:
pass
def on_scroll(x, y, dx, dy, local_print=print):
nonlocal print_count
try:
if print_count >= 10:
local_print(f"--- {'scroll up' if dy == 1 else 'scroll down'}")
print_count = 0
else:
local_print(f" {'scroll up' if dy == 1 else 'scroll down'}")
print_count += 1
except AttributeError:
pass
try:
listener = mouse.Listener(on_click=on_click, on_scroll=on_scroll)
listener.start()
listener.join()
except KeyboardInterrupt:
listener.stop()
main()
key_listener.py
from pynput import keyboard
def main():
print_count = 0
held = set() # this is needed because it keeps calling on_press when you hold a key
def on_press(key, local_print=print, held_local=held, hold=held.add, str_lower=str.lower):
nonlocal print_count
if key not in held_local:
try:
if print_count >= 10:
local_print(f"--- {key.name} pressed")
print_count = 0
else:
local_print(f" {key.name} pressed")
print_count += 1
except AttributeError:
if print_count >= 10:
local_print(f"--- {str_lower(key.char) if key.char is not None else 5} pressed")
print_count = 0
else:
local_print(f" {str_lower(key.char) if key.char is not None else 5} pressed")
print_count += 1
hold(key)
def on_release(key, local_print=print, unhold=held.remove, str_lower=str.lower):
nonlocal print_count
try:
if print_count >= 10:
local_print(f"--- {key.name} released")
print_count = 0
else:
local_print(f" {key.name} released")
print_count += 1
except AttributeError:
if print_count >= 10:
local_print(f"--- {str_lower(key.char) if key.char is not None else 5} released")
print_count = 0
else:
local_print(f" {str_lower(key.char) if key.char is not None else 5} released")
print_count += 1
try:
unhold(key)
except KeyError:
pass
try:
listener = keyboard.Listener(on_press=on_press, on_release=on_release)
listener.start()
listener.join()
except KeyboardInterrupt:
listener.stop()
main()
xterm_opener.sh
xterm -xrm 'XTerm.vt100.allowTitleOps: false' -T "keyboard" -geometry 28x16 -e python3 '/home/USERNAME/input_listener/key_listener.py' &
xterm -xrm 'XTerm.vt100.allowTitleOps: false' -T "mouse" -geometry 28x16 -e python3 '/home/USERNAME/input_listener/mouse_listener.py'