pynput
pynput copied to clipboard
Would it be possible to start the listener reporting events if the keys you're listening for are already pressed?
Description Ah, the listener only runs the pressed callback if it detects a press. That's fine and good, but what if the user presses the key during program startup and never unpressed it? It would be nice if there was either a option or a way to start with emitting the events in this situation, although it would be 'fake'.
Platform and pynput version
Linux sleipnir 5.15.0-41-generic #44~20.04.1-Ubuntu SMP Fri Jun 24 13:27:29 UTC 2022 x86_64 x86_64 x86_64 GNU/Linux
pynput 1.7.6
Gnome 3.36.8
X11
To Reproduce If possible, please include a short standalone code sample that reproduces the bug. Remember to surround it with code block markers to maintain indentation!
Thank you for your report.
I suppose that this could be achieved by querying the state of the keyboard and mouse when instantiation listeners, and then sending fake events for pressed buttons. At the moment I'm uncertain whether this is supported for all backends however.
I'm currently no longer using the api (converted to asyncio and prompt toolkit).
I don't know why, maybe because it's async, but it seems that api doesn't have this problem. This is what i'm doing there now:
skip = False
escape = False
def checkDownload():
'''threading.get_native_id() in this and other acesses of these variables
confirms all accesses are in synchronous functions on one thread so
there is no need to use any lock, async or not.
'''
global skip
global escape
if escape:
raise StopProgram()
if skip:
skip = False
raise StopDownload()
def checkEscape():
global escape
if escape:
raise StopProgram()
@asynccontextmanager
async def lock_keys() -> None:
'''blocks key echoing for this console and recognizes most keys
including many combinations, user kill still works, alt+tab...
it also serves as a quit program and skip download shortcut
'''
done = asyncio.Event()
input = create_input()
def keys_ready():
global skip
global escape
#escape needs flush in unix platforms, so this chain
for key_press in chain(input.read_keys(), input.flush_keys()):
if key_press.key == 'escape' or key_press.key == 'c-c': #esc or control-c
escape = True
done.set()
else:
skip = True
with input.raw_mode():
with input.attach(keys_ready):
typer.echo(typer.style(f' Press escape to quit, and most other non-meta keys to skip downloads', bold=True))
yield done
Then i call with lock_keys():
on the sections where i want these keys to be checked. It's easy to then convert some things to async variants (eg: using httpx and asyncio.sleep) if you need it for responsiveness to the keys.
(note the weird 'thing' with escape, which needs that flush to register, otherwise it only gets recognized in the 'next' keypress).
Maybe you can get inspiration.