0

This is a question related to one of my previous questions. Back then I was working on a project that requires keyboard inputs to manipulate the python program. And I managed to do it using keyboard module. But there was a little issue. When I use keyboard module, I cannot type in a text box of another application. Simply the keyboard is locked. Can I do the same without blocking the keyboard? This is the code for a simple program that pressing 'q' would stop a for loop.

import keyboard
import os
import threading
import time

class main_prog:
    def __init__(self):
        self.loop_running = False
        self.double_previous = False
        self.start_all_threads()

    def start_loop(self, num_to_go): 
        self.loop_running = True
        for i in range(num_to_go):
            if not self.loop_running:
                break
            print(i)
            time.sleep(1)
            if self.double_previous:
                print('Double of the previous value is {}'.format(2*i))
                self.double_previous = False
        os._exit(0)

    def start_all_threads(self):
        if not self.loop_running:
            x = int(input('How far you want the count to go: '))
            t1=threading.Thread(target=self.start_loop, args=[x])
            t2=threading.Thread(target=self.start_listening_kb)
            t1.start()
            t2.start()
            t1.join()
            t2.join()

    def start_listening_kb(self):
        while True:
            if keyboard.read_key(suppress=True) == 'q':
                self.loop_running = False
            if keyboard.read_key(suppress=True) == 'd':
                self.double_previous = True

if __name__ == '__main__':
    main_prog()

I tried the pynput module also. But it blocks the keyboard too. What I want is only when the terminal (that runs this python program) is selected, pressing 'q' and 'd' doing the things that they supposed to do. How can I achieve this?

1 Answer 1

1

Use pynput.

Also, your program is not thread-safe. You have different threads that read and write self.loop_running and self.double_previous without any synchronization. I have made it thread-safe by using threading.Event.

import os
import threading
import time
import pynput

class main_prog:
    def __init__(self):
        self.loop_running = threading.Event()
        self.double_previous = threading.Event()
        self.start_all_threads()
    
    def start_loop(self, num_to_go): 
        self.loop_running.set()
        for i in range(num_to_go):
            if not self.loop_running.is_set():
                break
            print(i)
            time.sleep(1)
            if self.double_previous.is_set():
                print('Double of the previous value is {}'.format(2*i))
                self.double_previous.clear()
        
        # Stops listening to keyboard events
        #self.listener.stop() # Not needed if the process is just about to end
        os._exit(0)
    
    def start_all_threads(self):
        if not self.loop_running.is_set():
            x = int(input('How far you want the count to go: '))
            
            # Collect keyboard events in a non-blocking fashion
            self.listener = pynput.keyboard.Listener(on_press=self.on_press)
            self.listener.start()
            
            t1 = threading.Thread(target=self.start_loop, args=[x])
            t1.start()
            t1.join()
    
    def on_press(self, key):
        # print(key)
        try:
            if key.char == 'q':
                self.loop_running.clear()
            elif key.char == 'd':
                self.double_previous.set()
        except AttributeError:
            pass

if __name__ == '__main__':
    main_prog()
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.