magmax / python-readchar

Python library to read characters and key strokes
MIT License
143 stars 45 forks source link

Example: running this in a background thread? #43

Open tartavull opened 5 years ago

AuHau commented 5 years ago

Hmm not sure, but to be honest, why would you like to do that? It does not really make sense to me...

GrandMoff100 commented 3 years ago

Think about making a game. Wanting to update the screen but then waiting for user input. I guess you could run everything else in a thread but the keystroke input waiting. But then again why can't we run the keystroke detection in a thread?

Cube707 commented 2 years ago

a little late but for others looking for this. This code is only testes for the new Version beeing developed under #79

from threading import Thread
from time import time, sleep
from readchar import key, readkey

# construct an inverted code -> key-name mapping
# we need to revese the items so that aliases won't overrive the original name later on
known_keys = {v: k for k, v in reversed(vars(key).items()) if not k.startswith("__")}

def keylogger():
    global running

    print("starting keylogger...")
    while running:
        try:
            data = readkey()
        except KeyboardInterrupt:
            running = False
            break
        if data in known_keys:
            data = known_keys[data]
        print(f"{data}-key was pressed")

    print("stopping keylogger...")

def main():
    while running:
        print(f"LOG: current time is {time()}")
        sleep(1)

running = True

if __name__ == "__main__":
    Thread(name="keylogger", target=keylogger).start()
    main()

For cases where a timeout is required, spawning a subprocess instead of a thread means it can be killed. See the following:

from multiprocessing import Process
from time import sleep, time

from readchar import key, readkey

# construct an inverted code -> key-name mapping
# we need to revese the items so that aliases won't overrive the original name later on
known_keys = {v: k for k, v in reversed(vars(key).items()) if not k.startswith("__")}

def keylogger():

    print("starting keylogger...")
    while True:
        try:
            data = readkey()
        except KeyboardInterrupt:
            break
        if data in known_keys:
            data = known_keys[data]
        print(f"{data}-key was pressed")

if __name__ == "__main__":
    p = Process(name="keylogger", target=keylogger)
    p.start()
    sleep(5)
    print("timeout..")
    p.kill()
max-l commented 1 year ago

I have a strange case where CTRL+C causes readchar.readkey() to block forever.

The thread calling readchar.readkey() is a background thread (reason explained below)

Unfortunately I can't reproduce it in a simple code snippet, It occures in an app with a lot of things going on.

I was able to solve the problem by replacing readchar.config.INTERRUPT_KEYS with an empty array:

readchar.config.INTERRUPT_KEYS = []

@AuHau not blocking the main thread is essential in use cases where you want to intercept os signals, the main thread must be paused with signal.pause()

if __name__ == "__main__":

    def _sigint(p1, p2):
        print("sigint received")

    signal.signal(signal.SIGINT, _sigint)

    Thread(name="keyreader", target=keylogger).start()

    signal.pause()
Cube707 commented 1 year ago

@max-l without a way to reproduce, I can really help you. However, here are some thought on the matter:

When you start the separate thread, you also need to terminate both threads in some way. You may have had cases where you had to press CTRL+C two times to stop the program, once for each thread. One other way is to set a flag when one terminates, that also stops the other one (like running in the example)

Now if you mess around with SIGINT you might get cases, where a CTRL+C doesn't reach readchar properly, because it is interrupted beforehand or something similar.

If you find a way to reproduce this Problem, feel free to open an issue

Cube707 commented 1 year ago

As this is only for documentation purposous, I will lock it.

If you have problem or suggestions, feel free to open another issue