Python 键盘模块在线程启动时冻结/不工作

问题描述 投票:0回答:1

这是我第一次做Python程序,我做了一个简单的Python程序,如下所示,但它在keyboard.is_pressed()调用时冻结,它无法打印我的测试消息“现在循环1次”,这意味着按任何键都不会给出任何响应,并且该函数调用根本不会返回,即使 Ctrl-C 也无法中断程序并返回到命令提示符控制。

import threading
import asyncio
import time
import keyboard

flagkeypress = False
keycode = 'a'
flagserverconnected = False

def task1():
    print("Connecting to server")
    asyncio.run(connect2svr())
    print("task1 ended")


async def connect2svr():
    global flagkeypress
    global keycode
    global flagserverconnected

    try:
        print("Connected to server")
        flagserverconnected = True

        keeploopBLE = True
        while keeploopBLE:
            if flagkeypress == True:
                flagkeypress = False
                if keycode == 'q':
                    for k in range(14, 19):
                        sk="##SP"+ f"{k:02}"
                        print(sk)
                        await asyncio.sleep(1)
                if keycode == ']':
                    keeploopBLE = False
    except Exception as e:
        print(f"Error: {e}")


print("Start of my main program")
# Create threads
t1 = threading.Thread(target=task1)
# Start threads
t1.start()

keeploop = True
while keeploop:
    print("\nOptions: [Q]=Get Version, [T]=Get Time, [P]=Start/End Get GPS Time\n")
    print("Press key for command:")

    waitkey = True
    while waitkey:
        if keyboard.is_pressed('t'):
            my_kevent = keyboard.read_event()
            keyn = my_kevent.name
            print(f"key {keyn} is pressed, program going to end")
            keycode = ']'
            flagkeypress = True
            waitkey = False
            keeploop = False
        elif keyboard.is_pressed('q'):
            my_kevent = keyboard.read_event()
            keyn = my_kevent.name
            print(f"key {keyn} is pressed")
            keycode = 'q'
            flagkeypress = True
            waitkey = False
        print("loop 1 time now")
        time.sleep(0.2)

    time.sleep(0.5)
print("Main program ended")
t1.join()

如果我删除了task1线程,Python代码简化如下,然后它按照我的预期工作,“loop 1 time now”被连续打印。线程task1的存在影响键盘模块API不工作的根本原因是什么?但到目前为止,我不能 100% 说冻结是由线程 task1 的存在引起的,因为在该 task1 存在之前我有另一个版本,并且如果我删除等待 while 循环,它仍然可以工作,但在我之前没有保存该版本进一步简化为这两个版本。

import asyncio
import time
import keyboard

flagkeypress = False
keycode = 'a'

print("Start of my main program")
keeploop = True
while keeploop:

    print("\nOptions: [Q]=Get Version, [T]=Get Time, [P]=Start/End Get GPS Time\n")
    print("Press key for command:")

    waitkey = True
    while waitkey:
        if keyboard.is_pressed('t'):
            my_kevent = keyboard.read_event()
            keyn = my_kevent.name
            print(f"key {keyn} is pressed, program going to end")
            keycode = ']'
            flagkeypress = True
            waitkey = False
            keeploop = False
        elif keyboard.is_pressed('q'):
            my_kevent = keyboard.read_event()
            keyn = my_kevent.name
            print(f"key {keyn} is pressed")
            keycode = 'q'
            flagkeypress = True
            waitkey = False
        print("loop 1 time now")
        time.sleep(0.2)

    time.sleep(0.5)
print("Main program ended")

输出:

C:\Projects\pytest1>python pytest3.py
Start of my main program

Options: [Q]=Get Version, [T]=Get Time, [P]=Start/End Get GPS Time

Press key for command:
loop 1 time now
loop 1 time now
loop 1 time now
loop 1 time now
key q is pressed
loop 1 time now

Options: [Q]=Get Version, [T]=Get Time, [P]=Start/End Get GPS Time

Press key for command:
loop 1 time now
loop 1 time now
loop 1 time now
loop 1 time now
loop 1 time now
key q is pressed
loop 1 time now

Options: [Q]=Get Version, [T]=Get Time, [P]=Start/End Get GPS Time

Press key for command:
loop 1 time now
loop 1 time now
key q is pressed
loop 1 time now

Options: [Q]=Get Version, [T]=Get Time, [P]=Start/End Get GPS Time

Press key for command:
loop 1 time now
loop 1 time now
key q is pressed
loop 1 time now

Options: [Q]=Get Version, [T]=Get Time, [P]=Start/End Get GPS Time

Press key for command:
loop 1 time now
loop 1 time now
loop 1 time now
key q is pressed
loop 1 time now

Options: [Q]=Get Version, [T]=Get Time, [P]=Start/End Get GPS Time

Press key for command:
loop 1 time now
loop 1 time now
loop 1 time now
loop 1 time now
loop 1 time now
key q is pressed
loop 1 time now

Options: [Q]=Get Version, [T]=Get Time, [P]=Start/End Get GPS Time

Press key for command:
loop 1 time now
loop 1 time now
loop 1 time now
loop 1 time now
loop 1 time now
key t is pressed, program going to end
loop 1 time now
Main program ended
python multithreading keyboard
1个回答
0
投票

已经测试过使用带有回调函数的keyboard.add_hotkey(),它可以工作并且不会像keyboard.is_pressed()那样冻结。我还测试了 read_key() 和 read_event() 也表现出冻结而不返回行为。无论如何,只有 add_hotkey() 有效。 但是 add_hotkey() 没有按我的预期工作,按键缓冲区输入没有清除,并且无法在键盘模块 API 中清除它。当我的程序结束或调用 input() 时,那些按下的键将会弹出。所以这绝对不能满足我的基本要求。 我尝试了另一个模块 - pynput,这个模块也没有冻结/不返回问题,但是,它有同样的问题,无法清除按键输入,当我的程序结束时,所有按下的按键都会弹出。 最后我尝试了 msvcrt 模块(微软),msvcrt.kbhit() 和 msvcrt.getch() 与 C 语言中的一样完美工作。所以 msvcrt 模块完美地满足了我的要求,并且与线程中的 asyncio 函数的多线程完美配合。 结论是msvcrt的按键API是最稳定且没有bug的,其他的缺乏按键缓冲区清除能力是一个很大的缺陷,当然最大的缺陷是在键盘模块上,充满了bug。

© www.soinside.com 2019 - 2024. All rights reserved.