Python Forum
Threading for keyboard input
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Threading for keyboard input
#1
Hi all,

I'm trying to build a simple command-line interface that has a normal task running, and responds to a key pressed by the user. But I'm not getting it right, and I might be over-complicating it..
The goal is a command-line tool to update the clock of an Arduino with RTC module. The Arduino sends it current time every second. What I want to achieve is that the command line looks something like below: user connects, the system time and Arduino time are shown (updated every second over the same line). If the user presses 'u' or 'q', the program updates or stops, respectively. The user input can be with or without return, I don't mind.

I attempted now to do it with two threads and input() and that sort of works. I also tried getch() and sys.stdin.read(1), but input() is so far most successful. What happens now is that the input-thread is started right away and the input '>' is not in the right spot. For elegance I looked into registering key presses rather than input(), but most solutions I found online use unnecessarily large libraries for this.

Any thoughts on how I should approach this are welcome :)

COM Ports available: COM1, COM2, COM3
Select COM port to connect: <user input>
Connected to COM-port. Press 'u' to update or 'q' to quit.
System date/time: 2018-10-11 09:44:00  <-- these lines are constantly updated
Arduino date/time: 2001-01-01 00:00:00 <-- 
> (optional line where it waits for user input)
Updating...
System date/time: 2018-10-11 09:44:02
Arduino date/time: 2018-10-11 09:44:02
import time
import threading


data_ready = threading.Event()
kill_flag = threading.Event()


def keyboard_poller():
    global key_pressed
    loop = True

    while loop:
        time.sleep(0.1)

        if kill_flag.isSet():
            loop = False

        ch = input(">")
        if ch:
            key_pressed = ch
            data_ready.set()


def main():
    curr_millis = time.time() * 1000
    prev_millis = curr_millis

    poller = threading.Thread(target=keyboard_poller)
    poller.start()

    loop = True

    while loop:
        curr_millis = time.time() * 1000
        if (curr_millis - prev_millis) >= 1000:
            print("Another second passed..." + str(curr_millis) + "\r")
            prev_millis = curr_millis
            # Do some extra stuff here

        if data_ready.isSet():
            if key_pressed.lower() == "q":
                kill_flag.set()
                loop = False
            else:
                print("You pressed: " + key_pressed)
            data_ready.clear()


if __name__ == "__main__":
    print("Started..")
    main()

    input("Press any key to exit...")
    exit()
Reply
#2
I only know multiprocessing because it does everything I want to do so there is no reason to learn threading. This is a simple program that terminates the Process when "q" is entered, and is a little messy because the function running as a separate process also prints to the screen to show that something is happening, but you can still input a "q". Hopefully this will help.

import time
from multiprocessing import Process

class TestClass():
    def test_f(self):
        ctr = 0
        while True:
            ctr += 1
            print("     ", ctr)
            time.sleep(1.0)

if __name__ == '__main__':
     ## run function in the background
     CT=TestClass()
     p = Process(target=CT.test_f)
     p.start()

     ## will not exit if function finishes, only when
     ## "q" is entered, but this is just a simple example
     stop_char=""
     while stop_char.lower() != "q":
         stop_char=input("Enter 'q' to quit ")
         if stop_char.lower() == "u":
             ## do something else
     print("terminate process")
     if p.is_alive():
         p.terminate()
Reply
#3
(Oct-11-2018, 10:50 AM)woooee Wrote: I only know multiprocessing because it does everything I want to do so there is no reason to learn threading.

multiprocessing.Process APIs are the same as threading.Thread, allowing painless switch from the latter to the former
Test everything in a Python shell (iPython, Azure Notebook, etc.)
  • Someone gave you an advice you liked? Test it - maybe the advice was actually bad.
  • Someone gave you an advice you think is bad? Test it before arguing - maybe it was good.
  • You posted a claim that something you did not test works? Be prepared to eat your hat.
Reply
#4
@woooee: You basically switched around the input-poll and the other process. That might not be a bad idea, although the problem you encounter as well is, indeed, the two threads using the print-statement will cause conflicts.

Either way is fine for me: the main polling the keyboard and having a separate thread for the other process, or vice versa. I guess with one process requiring the print, and one the input() in my current code, I would be better off polling for a key press rather than input().
How should I go about that in an easy way?
Reply
#5
Moving the quit to a GUI from the console https://www.tutorialspoint.com/python/py...amming.htm
import sys
if 3 == sys.version_info[0]: ## 3.X is default if dual system
    import tkinter as tk     ## Python 3.x
else:
    import Tkinter as tk     ## Python 2.x

import time
from multiprocessing import Process

class TestClass():
    def test_f(self):
        ctr = 0
        while True:
            ctr += 1
            print("     ", ctr)
            time.sleep(1.0)

    def tk_quit(self):
        root=tk.Tk()
        tk.Button(root, text="Quit", command=root.quit,
                  width=10).grid()
        root.mainloop()

if __name__ == '__main__':
     ## run function in the background
     CT=TestClass()
     p = Process(target=CT.test_f)
     p.start()

     CT.tk_quit()
     print("terminate process")
     if p.is_alive():
         p.terminate()
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  Concurrent futures threading running at same speed as non-threading billykid999 13 1,808 May-03-2023, 08:22 AM
Last Post: billykid999
  Help Switching between keyboard/Mic input in my code Extra 1 1,084 Aug-28-2022, 10:16 PM
Last Post: deanhystad
  Tutorials on sockets, threading and multi-threading? muzikman 2 2,113 Oct-01-2021, 08:32 PM
Last Post: muzikman
  Python - Keyboard module - Threading problem ppel123 1 3,059 Apr-13-2020, 04:49 PM
Last Post: deanhystad
  Keyboard Module Python - Suppress input while writing to window ppel123 0 2,785 Apr-08-2020, 02:51 PM
Last Post: ppel123
  Python - Most effective way to correct keyboard-user-input. ppel123 8 4,146 Apr-08-2020, 07:41 AM
Last Post: ppel123

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020