moses-palmer / pynput

Sends virtual input commands
GNU Lesser General Public License v3.0
1.79k stars 248 forks source link

"BrokenPipeError" crashes the X server when suppress = True #404

Closed Minabsapi closed 2 years ago

Minabsapi commented 3 years ago

Description I wrote a script using notably pynput and curses. To mitigate a terminal input issue when in a curses window I passed the variable suppress = True to pynput's listener, which crashes the X server after some input.

Here are the relevant parts of my script

...
from pynput import keyboard
...

user_input = ()

## Methods

def keypress(key):
        global user_input
        try:
                user_input = (False, key.char)
        except AttributeError:
                user_input = (True, key)
        return False
...
while True:
    with keyboard.Listener(
            on_release=keypress,
            suppress=True
    ) as listener:
            listener.join():
    ...

I redirected my script's stderr to a log file and this is what it captured:

Exception in thread Thread-2:
Traceback (most recent call last):
  File "/usr/lib/python3/dist-packages/Xlib/protocol/display.py", line 584, in send_and_recv
    i = self.socket.send(self.data_send)
BrokenPipeError: [Errno 32] Broken pipe

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/lib/python3.8/threading.py", line 932, in _bootstrap_inner
    self.run()
  File "/home/minabsapi/.local/lib/python3.8/site-packages/pynput/_util/__init__.py", line 144, in run
    self._run()
  File "/home/minabsapi/.local/lib/python3.8/site-packages/pynput/keyboard/_xorg.py", line 530, in _run
    super(Listener, self)._run()
  File "/home/minabsapi/.local/lib/python3.8/site-packages/pynput/_util/xorg.py", line 401, in _run
    self._suppress_stop(dm)
  File "/usr/lib/python3.8/contextlib.py", line 120, in __exit__
    next(self.gen)
  File "/home/minabsapi/.local/lib/python3.8/site-packages/pynput/_util/xorg.py", line 74, in display_manager
    display.sync()
  File "/usr/lib/python3/dist-packages/Xlib/display.py", line 182, in sync
    self.get_pointer_control()
  File "/usr/lib/python3/dist-packages/Xlib/display.py", line 833, in get_pointer_control
    return request.GetPointerControl(display = self.display)
  File "/usr/lib/python3/dist-packages/Xlib/protocol/rq.py", line 1369, in __init__
    self.reply()
  File "/usr/lib/python3/dist-packages/Xlib/protocol/rq.py", line 1381, in reply
    self._display.send_and_recv(request = self._serial)
  File "/usr/lib/python3/dist-packages/Xlib/protocol/display.py", line 586, in send_and_recv
    self.close_internal('server: %s' % err[1])
TypeError: 'BrokenPipeError' object is not subscriptable

Platform and pynput version GNU/Linux Ubuntu 20.04 pynput 1.6.8

Note Might be related to issue #231, though not using exit() in the handler didn't mitigate the issue

dp0s commented 3 years ago

I can confirm that the option "suppress = True" has often led to an Xserver crash, after which I have to re-login. I'm using Linux Mint 19. It doesn't happen immediately after starting the listener, but a short random time later.

moses-palmer commented 3 years ago

Thank you for your report, and sorry for this late reply.

The PR #382 may contain a fix for this. Is it possible for you to test?

dp0s commented 3 years ago

I would definitely like to test this on my local computer. How do I copy a version of pynput including the requested changes?

moses-palmer commented 3 years ago

To install a version of pynput with the proposed fix:

pip install https://github.com/moses-palmer/pynput/archive/fixup-xorg-display-cleanup.zip

Please note that this will likely require you to install Python development libraries on your system.

moses-palmer commented 2 years ago

This fix has now been added to the master branch, so I will close this issue. If the problem persist, please reopen.