foxneSs
foxneSs

Reputation: 2269

How to use threads to get input from keyboard in python 3?

I am making a snake game which requires the player to press the WASD keys without stopping the game process to to get input from player. So I can't use input() for this situation because then the game stops ticking to get input.

I found a getch() function which immediately gives input without pressing enter, but this function also stops game ticking to get input like input(). I decided to use threading module to get input via getch() in different thread. The problem is that getch() isn't working while in different thread and I'm not sure why.

import threading, time
from msvcrt import getch

key = "lol" #it never changes because getch() in thread1 is useless

def thread1():
    while True:
        key = getch() #this simply is almost ignored by interpreter, the only thing it
        #gives is that delays print() unless you press any key
        print("this is thread1()")

threading.Thread(target = thread1).start()

while True:
    time.sleep(1)
    print(key)

So why getch() is useless when it is in thread1()?

Upvotes: 0

Views: 17739

Answers (2)

Michael0x2a
Michael0x2a

Reputation: 64038

The problem was that you're creating a local variable key inside thread1 instead of overwriting the existing one. The quick-and-easy solution would be to declare key to be global inside thread1.

Finally, you should consider using locks. I don't know if it's necessary or not, but I'd imagine weird things could happen if you try and write a value to key in the thread while printing it out at the same time.

The working code:

import threading, time
from msvcrt import getch

key = "lol"

def thread1():
    global key
    lock = threading.Lock()
    while True:
        with lock:
            key = getch()

threading.Thread(target = thread1).start()

while True:
    time.sleep(1)
    print(key)

Upvotes: 5

Disconnect3d
Disconnect3d

Reputation: 312

I tried using getch but it didn't work for me... (win7 here).

You can try using tkinter module // but I still can't make it running with threads

# Respond to a key without the need to press enter
import tkinter as tk    #on python 2.x use "import Tkinter as tk"

def keypress(event):
    if event.keysym == 'Escape':
        root.destroy()
    x = event.char
    if x == "w":
        print ("W pressed")
    elif x == "a":
        print ("A pressed")
    elif x == "s":
        print ("S pressed")
    elif x == "d":
        print ("D pressed")
    else:
        print (x)

root = tk.Tk()
print ("Press a key (Escape key to exit):")
root.bind_all('<Key>', keypress)
# don't show the tk window
root.withdraw()
root.mainloop()

As Michael0x2a says you may try using library made for game-making - pygame or pyglet.

@EDIT @Michael0x2a: Are you sure your code works? Whatever I press it always prints the same key.

@EDIT2: Thanks!

Upvotes: 0

Related Questions