【问题标题】:Python threading blocked by keyboard library?Python线程被键盘库阻止?
【发布时间】:2022-01-04 03:30:19
【问题描述】:

在构建可以切换为垃圾邮件的脚本时。我遇到了以下问题。 首先是脚本的正常运行版本:

import keyboard
import threading

def spam_this():
    status = 0
    while True:
        if keyboard.is_pressed("F9") and status == 0:
            status = 1
            event.wait(1)
        if keyboard.is_pressed("F9") and status == 1:
            status = 0
            event.wait(1)
        while status == 1:
            if keyboard.is_pressed("F9") and status == 1:
                status = 0
                event.wait(1)
            print("test")

event = threading.Event()
threading.Thread(target=spam_this).start()

上面的脚本完美运行。但是,当我将print("test") 更改为keyboard.write("test") 时。脚本中断。

import keyboard
import threading

def spam_this():
    status = 0
    while True:
        if keyboard.is_pressed("F9") and status == 0:
            status = 1
            event.wait(1)
        if keyboard.is_pressed("F9") and status == 1:
            status = 0
            event.wait(1)
        while status == 1:
            if keyboard.is_pressed("F9") and status == 1:
                status = 0
                event.wait(1)
            keyboard.write("test")

event = threading.Event()
threading.Thread(target=spam_this).start()

这个版本的带有keyboard.write() 功能的脚本可以使用隐含的切换键“F9”来启动,但是当我尝试通过再次按“F9”来关闭开关时,它不会像@987654326 那样停止@自己的版本。

注意:我不知道如何在标题中描述这个问题。我使用术语“阻塞”是因为其效果类似于 time.sleep() 之类的阻塞方法在尝试创建带有切换的 while True: 循环时所做的。

【问题讨论】:

  • 如果您在while status == 1 中运行代码,那么您不必检查and status == 1
  • 如果你使用True/False而不是0/1,那么你可以使用status = not status并且在while之前只使用一个if(没有and status == ...)`。

标签: python multithreading keyboard


【解决方案1】:
import threading
import keyboard

# global variable
status = False

def spam_this():
    print('start: spam_this')
    while True:
        if status is True:
            print("test")
            keyboard.write("test")
            event.wait(0.1)
        
            
def test(event=None):
    global status
    status = not status
    print('change:', status)

event = threading.Event()
keyboard.add_hotkey("F9", test)
#alternatively:
#keyboard.on_key_press("F9", test)
threading.Thread(target=spam_this).start()

对@furas 的回答进行了一些修改。

  1. 对于test 函数,添加了一个参数event=None,否则keyboard.on_press_key 会将F9 按键事件传递给测试函数,从而导致typeError

  2. test函数中,event.wait()由于错误被移除,经测试,keyboard.on_press_keykeyboard.add_hotkey函数确实有内置延迟,所以只要F9键没有按住,内置延迟绰绰有余。

  3. 无论是使用on_key_press 还是add_hotkey,都应在调用所需的“热键方法”后初始化线程。否则线程将阻塞python脚本的主循环。(这部分我无法解释为什么,只是反复试验导致了这个结论。)

  4. keyboard.wait() 已被删除,因为未使用此功能。

数字 1 和 3 是最重要的变化 (对于那些不想阅读次要部分的人)

【讨论】:

    【解决方案2】:

    keyboard 也可以在thread 中运行自己的代码,并且两个线程之间可能存在冲突。 Python 使用GIL 一次只运行一个线程——所以当你的线程正在运行时,它可能会阻塞应该在屏幕上写入文本的线程。如果我在write() 之后使用even.wait(0.1),代码效果会更好,因此Python 可以切换线程并在屏幕上发送文本。如果您使用更长的值,那么它也可以工作,但是如果您非常快地按下键,那么它可能仍然运行 writewait 并且它无法检查 is_pressed("F9") 并且不会停止它 - 如果您使用 @ 你应该看到它987654330@write之后

    还有其他问题-它可能会在按键后写入最后一个文本,它应该使用break退出while并跳过write

    import threading
    import keyboard
    
    def spam_this():
        status = 0
        while True:
            if keyboard.is_pressed("F9") and status == 0:
                status = 1
                event.wait(1)
            if keyboard.is_pressed("F9") and status == 1:
                status = 0
                event.wait(1)
            while status == 1:
                if keyboard.is_pressed("F9") and status == 1:
                    print('stop')
                    status = 0
                    event.wait(1)
                    break
                keyboard.write("test")
                event.wait(0.1)
    
    event = threading.Event()
    threading.Thread(target=spam_this).start()
    

    但我会把它减少到

    import threading
    import keyboard
    
    def spam_this():
        print('start spam_this')
        status = False
        while True:
            if keyboard.is_pressed("F9"):
                status = not status
                print('status:', status)
                event.wait(0.1)
            if status is True:
                keyboard.write("test")
                event.wait(0.1)
    
    event = threading.Event()
    threading.Thread(target=spam_this).start()
    

    但它还有另一个问题 - 如果您按住键的时间更长,那么它会多次切换status。我添加了print('status:', status) 来展示它。

    我想像这样使用keyboard.add_hotkey

    import threading
    import keyboard
    
    # global variable
    status = False
    
    def spam_this():
        print('start: spam_this')
        while True:
            if status is True:
                keyboard.write("test")
                event.wait(0.1)
    
    def test():
        global status
        
        status = not status
        print('change:', status)
        event.wait(0.5)
        
    event = threading.Event()
    threading.Thread(target=spam_this).start()
        
    keyboard.add_hotkey("F9", test)
    keyboard.wait()
    

    但是当您按住按键时,系统可能会再次开始发送相同的按键。

    我没有测试keyboard.on_press_key() - 也许它会解决它。

    文档:keyboard

    【讨论】:

    • 我确实在status 切换部分之后添加了event.wait(1),因为我注意到按下键时01 状态之间快速变化,但我没有想到添加@ 987654346@ 在keyboard.write() 之后。在使用event.wait() 进行进一步测试后。有时在测试的时候设置为0.2可以实现toggle,但是还是很不靠谱。至于keyboard.add_hotkey 方法,之后threading 阻塞了主要功能。我会在它工作时发布它的更新版本。
    • 经过测试,on_key_press 方法也很有效。
    猜你喜欢
    • 2023-01-18
    • 1970-01-01
    • 1970-01-01
    • 2013-08-23
    • 2021-12-23
    • 1970-01-01
    • 2014-07-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多