python中的键盘输入(通过pynput)和线程
我正在尝试用Python 3制作一种基于文本的游戏。在游戏中,我需要聆听键盘输入,特别是在屏幕上打印内容时,测量按键按下的时间。我试着从一个简单的例子开始 首先,以下代码使用python中的键盘输入(通过pynput)和线程,python,multithreading,input,Python,Multithreading,Input,我正在尝试用Python 3制作一种基于文本的游戏。在游戏中,我需要聆听键盘输入,特别是在屏幕上打印内容时,测量按键按下的时间。我试着从一个简单的例子开始 首先,以下代码使用pynput,成功地测量了用户按下键的时间长度: from pynput import keyboard import time print("Press and hold any key to measure duration of keypress. Esc ends program") # A
pynput
,成功地测量了用户按下键的时间长度:
from pynput import keyboard
import time
print("Press and hold any key to measure duration of keypress. Esc ends program")
# A dictionary of keys pressed down right now and the time each was pressed down at
keys_currently_pressed = {}
def on_press(key):
global keys_currently_pressed
# Record the key and the time it was pressed only if we don't already have it
if key not in keys_currently_pressed:
keys_currently_pressed[key] = time.time()
def on_release(key):
global keys_currently_pressed
if key in keys_currently_pressed:
animate = False
duration = time.time() - keys_currently_pressed[key]
print("The key",key," was pressed for",str(duration)[0:5],"seconds")
del keys_currently_pressed[key]
if key == keyboard.Key.esc:
# Stop the listener
return False
with keyboard.Listener(on_press = on_press, on_release=on_release, suppress=True) as listener:
listener.join()
现在我想做的是,只有当用户按下一个键时,才能在屏幕上打印一个基于文本的“动画”。在下面的示例中,我的“动画”只是每半秒打印一次“*”
。
到目前为止,我已经尝试让第二个线程处理“动画”,但对于多线程,我完全是个新手。以下代码将在正确的时间启动动画,但不会停止动画
from pynput import keyboard
import sys
import time
import threading
print("Press and hold any key to measure duration of keypress. Esc ends program")
# A dictionary of keys pressed down right now and the time each was pressed down at
keys_currently_pressed = {}
def my_animation():
# A simple "animation" that prints a new "*" every half second
limit = 60 # just in case, don't do more than this many iterations
j = 0
while j<limit:
j += 1
sys.stdout.write("*")
time.sleep(0.5)
anim = threading.Thread(target=my_animation)
def on_press(key):
global keys_currently_pressed
# Record the key and the time it was pressed only if we don't already have it
if key not in keys_currently_pressed:
keys_currently_pressed[key] = time.time()
anim.start()
def on_release(key):
global keys_currently_pressed
if key in keys_currently_pressed:
animate = False
duration = time.time() - keys_currently_pressed[key]
print("The key",key," was pressed for",str(duration)[0:5],"seconds")
del keys_currently_pressed[key]
if key == keyboard.Key.esc:
# Stop the listener
return False
with keyboard.Listener(on_press = on_press, on_release=on_release, suppress=True) as listener: listener.join()
最终,我希望能够用更复杂的动画来实现这一点。比如说
def mysquare(delay):
print("@"*10)
time.sleep(delay)
for i in range(8):
print("@" + " "*8 + "@")
time.sleep(delay)
print("@"*10)
正确的方法是什么?非常感谢
监听器
已经使用了线程
,因此不需要在单独的线程中运行动画。您可以在当前胎面花纹中运行它
with keyboard.Listener(on_press = on_press, on_release=on_release, suppress=True) as listener:
#... your code ...
listener.join()
或者不使用而使用。。。作为…
listener = keyboard.Listener(on_press = on_press, on_release=on_release, suppress=True)
listener.start()
#... your code ...
#listener.wait()
listener.join()
您甚至可以在那里运行长时间运行的代码,即无休止的while
循环,该循环将检查变量animate
是否为True
,并编写新的*
我必须在Linux上添加sys.stdout.flush()
,才能在屏幕上看到*
我的版本: 当您按下任何按钮时,它会一直运行动画,但也有带有变量
counter
的代码将动画限制为6个移动。如果在运行动画时按“新建”键,则会重置此计数器,动画将变长
此循环必须一直运行,以检查是否有新动画-动画完成后无法完成此循环
from pynput import keyboard
import sys
import time
# --- functions ---
def on_press(key):
global keys_currently_pressed
global animate
#global counter
# Record the key and the time it was pressed only if we don't already have it
if key not in keys_currently_pressed and key != keyboard.Key.esc:
keys_currently_pressed[key] = time.time()
animate = True
#counter = 0 # reset counter on new key
def on_release(key):
global keys_currently_pressed
global animate
if key in keys_currently_pressed:
duration = time.time() - keys_currently_pressed[key]
print("The key", key, "was pressed for", str(duration)[0:5], "seconds")
del keys_currently_pressed[key]
if not keys_currently_pressed:
animate = False
if key == keyboard.Key.esc:
# Stop the listener
return False
# --- main ---
print("Press and hold any key to measure duration of keypress. Esc ends program")
# A dictionary of keys pressed down right now and the time each was pressed down at
keys_currently_pressed = {}
animate = False # default value at start (to use in `while` loop)
#limit = 6 # limit animation to 6 moves
#counter = 0 # count animation moves
with keyboard.Listener(on_press = on_press, on_release=on_release, suppress=True) as listener:
while listener.is_alive(): # infinite loop which runs all time
if animate:
#sys.stdout.write("\b *") # animation with removing previous `*`
sys.stdout.write("*") # normal animation
sys.stdout.flush() # send buffer on screen
#counter += 1
#if counter >= limit:
# counter = 0
# animate = False
time.sleep(0.5)
listener.join()
listener
已在单独的线程中运行,因此无需使用其他线程进行动画。您可以在与之间的当前线程中运行代码。。。作为监听器
和listener.join()
——它可以是长时间运行的循环,用于检查变量和更新屏幕。它的工作原理与PyGame类似,PyGame也会运行循环,始终检查是否有东西需要移动和重画elements@furas谢谢你的提示,我已经试着按照你的建议去做了,现在在最新的问题编辑中显示出来了——但我似乎无法让它起作用。谢谢你,这非常有帮助,这对我很有用。但是假设动画比一遍又一遍地打印同一个角色更复杂,就像假设它是通过ascii艺术绘制某种形状一样。我编辑了这个问题,以得到一个类似这样的例子。这种方法能适应这样做吗?如果你需要更复杂的动画,那么你将需要在while loop
中使用更复杂的代码。同样,这个动画应该在每个循环中只画一帧-不要运行内部循环。如果你想用sleep绘制mysquare
,那么这个想法是错误的-你应该只有一个循环-`while listener.is_alive()`-它应该控制时间并绘制新元素。好的,谢谢你的建议。我想我可以用一种计数器跟踪动画状态,在开始一个新动画时,计数器会被重置。我接受这个答案。
from pynput import keyboard
import sys
import time
# --- functions ---
def on_press(key):
global keys_currently_pressed
global animate
#global counter
# Record the key and the time it was pressed only if we don't already have it
if key not in keys_currently_pressed and key != keyboard.Key.esc:
keys_currently_pressed[key] = time.time()
animate = True
#counter = 0 # reset counter on new key
def on_release(key):
global keys_currently_pressed
global animate
if key in keys_currently_pressed:
duration = time.time() - keys_currently_pressed[key]
print("The key", key, "was pressed for", str(duration)[0:5], "seconds")
del keys_currently_pressed[key]
if not keys_currently_pressed:
animate = False
if key == keyboard.Key.esc:
# Stop the listener
return False
# --- main ---
print("Press and hold any key to measure duration of keypress. Esc ends program")
# A dictionary of keys pressed down right now and the time each was pressed down at
keys_currently_pressed = {}
animate = False # default value at start (to use in `while` loop)
#limit = 6 # limit animation to 6 moves
#counter = 0 # count animation moves
with keyboard.Listener(on_press = on_press, on_release=on_release, suppress=True) as listener:
while listener.is_alive(): # infinite loop which runs all time
if animate:
#sys.stdout.write("\b *") # animation with removing previous `*`
sys.stdout.write("*") # normal animation
sys.stdout.flush() # send buffer on screen
#counter += 1
#if counter >= limit:
# counter = 0
# animate = False
time.sleep(0.5)
listener.join()