moses-palmer / pynput

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

Crash on MacOS 12.6 (M1) when pressing caps_lock #510

Open perroboc opened 1 year ago

perroboc commented 1 year ago

Description Keyboard listening on MacOS (M1 Pro) works and logs all keys. But it crashes after pressing Caps Lock

Platform and pynput version macOS Monterey (12.6), M1 Pro. Pynput 1.7.6, Pyside6 6.4.0, Python 3.10. I'm also using a Latin American keyboard layout.

To Reproduce https://github.com/alvaromunoz/pynput-macos-issues/blob/ba17e4b83f1eb239454d73ba96adf7f5fe71673b/caps_lock.py

import sys

from PySide6 import (
    QtWidgets,
)

from pynput import keyboard

class MainWindow(QtWidgets.QMainWindow):
    def __init__(self):
        super().__init__()

        self.setWindowTitle("Listener Demo 1")

        central_widget = QtWidgets.QWidget()

        layout = QtWidgets.QVBoxLayout()
        central_widget.setLayout(layout)

        label_description = QtWidgets.QLabel("Press Caps lock to crash.")
        layout.addWidget(label_description)

        label = QtWidgets.QLabel("Press any key")
        layout.addWidget(label)

        def on_press(key):
            label.setText("You pressed {0}".format(key))

        def on_release(key):
            label.setText("You released {0}".format(key))

        listener = keyboard.Listener(
            on_press=on_press,
            on_release=on_release)
        listener.start()

        self.setCentralWidget(central_widget)

app = QtWidgets.QApplication(sys.argv)

window = MainWindow()
window.show()

app.exec()

OUTPUT:

zsh: trace trap
moses-palmer commented 1 year ago

Thank you for your report.

From what I have gathered, zsh report this error on unhandled signals, in this SIGTRAP. This should not happen in the library code nor in the Python runtime code. I suspect that the culprit is a native library, perhaps some part of pyobjc.

Perhaps adding some print statements in Listener._event_to_key would provide some hints as to where the error occurs?

perroboc commented 1 year ago

From other tests, and comparing it to the keyboard library, this happens because MacOS requires a delay when pressing caps lock. If I press it with the delay, pynput doesn’t crash.

On 29-11-2022, at 15:32, moses-palmer - notifications at github.com @.***> wrote:

Thank you for your report.

From what I have gathered, zsh report this error on unhandled signals, in this SIGTRAP. This should not happen in the library code nor in the Python runtime code. I suspect that the culprit is a native library, perhaps some part of pyobjc.

Perhaps adding some print statements in Listener._event_to_key https://github.com/moses-palmer/pynput/blob/078491edf7025033c22a364ee76fb9e79db65fcc/lib/pynput/keyboard/_darwin.py#L311 would provide some hints as to where the error occurs?

— Reply to this email directly, view it on GitHub https://github.com/moses-palmer/pynput/issues/510#issuecomment-1331114871, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAUYXVOXCQH57P6CNYHM3D3WKZD3HANCNFSM6AAAAAARM5QAJU. You are receiving this because you authored the thread.

moses-palmer commented 1 year ago

That's peculiar—a SIGTRAP because of a missing delay?

Would you mind posting a diff that fixes the code above?

perroboc commented 1 year ago

I’d LOVE to, but I haven’t found a fix yet. Further tests show that even holding the button does NOT fix the issue, sorry.

Here's a video showing the difference the behavior when holding the key or not:

Is there any way to read the SIGTRAP dumps?

HaujetZhao commented 1 year ago

MacOS uses tap Capslock to switch InputMethod of non-English language, click it get a keycode 0xFF, I think it's a media-key stands for switching IME. Hold capslock triggers the true capslock keycode.

Can be configured in: Settings > Keyboard > IME

hgiesel commented 7 months ago

Just encountered this issue again. Did anybody find a solution to this, or the cause of the SIGTRAP?

Darcy-C commented 7 months ago

I do believe this problem is related to IME.

For whatever reason, I found when I comment the line, the problem disappears.

_EVENTS = (
    Quartz.CGEventMaskBit(Quartz.kCGEventKeyDown) |
    Quartz.CGEventMaskBit(Quartz.kCGEventKeyUp) |
    Quartz.CGEventMaskBit(Quartz.kCGEventFlagsChanged) 
    | Quartz.CGEventMaskBit(Quartz.NSSystemDefined) # 👈 comment it if you do not want the media keys
)

But Commenting this line will also lead to loss of the ability to listen to the system defined key.


I am trying to use faulthandler to locate the line which triggered the unwanted exit, and it shows the following tracebacks.

Python error: Aborted

Thread 0x0000000175903000 (most recent call first):
  File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/pynput/_util/darwin.py", line 215 in _run
  File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/pynput/keyboard/_darwin.py", line 253 in _run
  File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/pynput/_util/__init__.py", line 210 in run
  File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/threading.py", line 1016 in _bootstrap_inner
  File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/threading.py", line 973 in _bootstrap

which points to the line on my machine

result = Quartz.CFRunLoopRunInMode(
                        Quartz.kCFRunLoopDefaultMode, 1, False)

It seems like the problem has not happened inside python codebase. Just like moses-palmer said, It's related to pyobjc.

hgiesel commented 7 months ago

Maybe because NSSystemDefined is deprecated?