首页 > 解决方案 > 如何正确终止 pynput 调用?现在它使我的 X 崩溃(self.socket_error)

问题描述

我正在尝试使用 pynput('pijnput' 转换为痛苦的坑:-))模块来捕获键盘。这是我的代码:

    class KeyPress:
    def __init__(self,parent):
        self.parent=parent

    def on_press(self,key):
        #keyboard.Listener.stop()
        try:
            self.parent.pressedKey=key.char
            self.parent.pressedKeyCode=None
        except AttributeError:
            self.parent.pressedKey=key
            self.parent.pressedKeyCode=key.value.vk
        return False


    def on_release(self,key):
        if key == keyboard.Key.esc:
            # Stop listener
            return False

    # Collect events until released
    def run(self):
        with keyboard.Listener(
                on_press=self.on_press,
                on_release=self.on_release,suppress=True) as listener:
            listener.join()

我创建了一个子类,它将键和 keyCode 分配给主类的属性如果我运行它,它可以正常工作,直到我按下一定数量的键然后 X 崩溃并出现此错误。起初我在 ipython + tmux 中运行它,但也在纯 bash 中运行,这种情况发生了。

Exception in thread Thread-131:
Traceback (most recent call last):
  File "/usr/lib/python3.7/threading.py", line 917, in _bootstrap_inner
    self.run()
  File "/usr/lib/python3.7/site-packages/pynput/_util/__init__.py", line 136, in run
    self._run()
  File "/usr/lib/python3.7/site-packages/pynput/keyboard/_xorg.py", line 499, in _run
    super(Listener, self)._run()
  File "/usr/lib/python3.7/site-packages/pynput/_util/xorg.py", line 370, in _run
    self._display_record = Xlib.display.Display()
  File "/usr/lib/python3.7/site-packages/Xlib/display.py", line 89, in __init__
    self.display = _BaseDisplay(display)
  File "/usr/lib/python3.7/site-packages/Xlib/display.py", line 71, in __init__
    protocol_display.Display.__init__(self, *args, **keys)
  File "/usr/lib/python3.7/site-packages/Xlib/protocol/display.py", line 163, in __init__
    auth_prot_data = auth_data)
  File "/usr/lib/python3.7/site-packages/Xlib/protocol/display.py", line 1070, in __init__
    display.send_and_recv(request = -1)
  File "/usr/lib/python3.7/site-packages/Xlib/protocol/display.py", line 610, in send_and_recv
    raise self.socket_error
Xlib.error.ConnectionClosedError: Display connection closed by server

我的猜测是我创建了太多线程,因为我没有终止它们。虽然我假设'with'构造会处理这个问题?这个对吗 ?如果是这样,我应该怎么做才能让它发挥作用?

提前致谢

标签: pythonpynput

解决方案


当您返回 False pynput 停止但线程仍处于打开状态时,当您返回它时,它会创建一个全新的线程并重复该过程,我将 pynput 置于一个循环中并最终得到许多线程,我在我的只有 1 个线程使用 pynput 的代码是这样的:

from pynput.keyboard import Key, Listener, Controller
listener = None
keyPressed = None

def on_press(key):
    if key == Key.enter:

        # here add a bolean that will detect when enter pressed

        global saveFile
        saveFile = True  

def on_release(key):
    global xPosition
    global yPosition
    global zPosition

   # in my case I'm moving and object with the keys so if I keep my finger on it it 
   #keeps calling this method, you can simple have a string that is equal to key.char 
   #to know the pressed key from anywhere

    global keyPressed
    keyPressed = key.char

    if key.char == ('d'):
        xPosition -= 0.03
    elif key.char == ('a'):
        xPosition += 0.03
    elif key.char == ('w'):
        zPosition += 0.03    
    elif key.char == ('s'):
        zPosition -= 0.03
    elif key.char == ('q'):
        yPosition += 0.03   
    elif key.char == ('e'):
        yPosition -= 0.03   

def CheckWhichKeyIsPressed():
    global listener

    # here is the secret, create only if it doesn't exist yet
    if listener == None:  
        listener = Listener(on_press=on_press, on_release=on_release,suppress=True)
        listener.start()

通过仅在尚未创建线程的情况下创建线程,我设法只有 1 个始终在监听,然后我使用 on_press 和 on_release 更改变量,在我的情况下,SaveFile 布尔值在使用后被关闭,所以尽快当用户再次按下回车键时,pynput 将把它捡起来,我可以保存一个新文件:

global saveFile
if saveFile:
        saveFile = False
        SaveFile()

有了这个 pynput 总是在听并告诉你你只用 1 个线程按下了什么键


推荐阅读