pynput icon indicating copy to clipboard operation
pynput copied to clipboard

I can't use pynput in MacOS Monterey 12.0.1 + M1 environment

Open yejunxi opened this issue 3 years ago • 14 comments
trafficstars

Description Hello, I want to ask for help, I can't use pynput in MacOS Monterey 12.0.1 + M1 environment

 File "/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.8/lib/python3.8/contextlib.py", line 113, in __enter__
    return next(self.gen)
  File "/Users/yjx/Documents/my/xueqiu2/venv/lib/python3.8/site-packages/pynput/_util/darwin.py", line 130, in keycode_context
    layout = _wrap_value(CarbonExtra.TISGetInputSourceProperty(
  File "/Users/yjx/Documents/my/xueqiu2/venv/lib/python3.8/site-packages/pynput/_util/darwin.py", line 45, in _wrap_value
    return objc.objc_object(c_void_p=value)
AttributeError: 'NoneType' object has no attribute 'value'
Exception in thread Thread-6:
Traceback (most recent call last):
  File "/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.8/lib/python3.8/threading.py", line 932, in _bootstrap_inner
    self.run()
  File "/Users/yjx/Documents/my/xueqiu2/venv/lib/python3.8/site-packages/pynput/_util/__init__.py", line 193, in run
    self._run()
  File "/Users/yjx/Documents/my/xueqiu2/venv/lib/python3.8/site-packages/pynput/keyboard/_darwin.py", line 250, in _run
    with keycode_context() as context:
  File "/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.8/lib/python3.8/contextlib.py", line 113, in __enter__
    return next(self.gen)
  File "/Users/yjx/Documents/my/xueqiu2/venv/lib/python3.8/site-packages/pynput/_util/darwin.py", line 130, in keycode_context
    layout = _wrap_value(CarbonExtra.TISGetInputSourceProperty(
  File "/Users/yjx/Documents/my/xueqiu2/venv/lib/python3.8/site-packages/pynput/_util/darwin.py", line 45, in _wrap_value
    return objc.objc_object(c_void_p=value)
AttributeError: 'NoneType' object has no attribute 'value'

Platform and pynput version System:macOS Monterey 12.0.1 + M1 pynput 1.7.5 python 3.8

To Reproduce Use official examples

#!venv/bin/python3

import os

from pynput import keyboard

def on_press(key):
    try:
        print('alphanumeric key {0} pressed'.format(
            key.char))
    except AttributeError:
        print('special key {0} pressed'.format(
            key))

def on_release(key):
    print('{0} released'.format(
        key))
    if key == keyboard.Key.esc:
        # Stop listener
        return False

# Collect events until released
with keyboard.Listener(
        on_press=on_press,
        on_release=on_release) as listener:
    listener.join()
os.system('echo "Press any key to continue..." && read')

yejunxi avatar Nov 29 '21 10:11 yejunxi

I made a temporary solution, but I hope the author can help to see why

drawin.py

def _wrap_value(value):
    """Converts a pointer to a *Python objc* value.

    :param value: The pointer to convert.

    :return: a wrapped value
    """
    if value is None:
        return
    return objc.objc_object(c_void_p=value)

yejunxi avatar Nov 30 '21 01:11 yejunxi

Thank you for your report and proposed fix.

I think your proposition is the way to go; previously this library used a function loaded by ctypes, and I presume it just silently returned None when passed None, whereas the new managed method presumably checks its arguments.

I have included your fix in the branch fixup-macos-objc-none. If you should find time, please test it; otherwise, I will merge it eventually.

moses-palmer avatar Dec 05 '21 14:12 moses-palmer

Thank you for your report and proposed fix.

I think your proposition is the way to go; previously this library used a function loaded by ctypes, and I presume it just silently returned None when passed None, whereas the new managed method presumably checks its arguments.

I have included your fix in the branch fixup-macos-objc-none. If you should find time, please test it; otherwise, I will merge it eventually.

I've tested this branch on my M1 mbp with Big Sur, no errors like before. Maybe you could merge it now.

tevenfeng avatar Dec 30 '21 03:12 tevenfeng

I'm having similar issues with my M1 mac running macOS Ventura but only when I use pynput with Qt... seems to fail similarly to the above issue with TISGetInputSourceProperty crashing my app.

I have rearranged Qt / pynput startup order and encountered some lazy load race conditions / timing issues with pyobjc behind the scenes such that I can get both to work in simple setups but I have another setup where I'm getting the following trace and haven't had much luck finding out why... I'll keep plugging away on it and share what I find.

All of the issues I've had (race conditions, and the following) stem from the same spot (or nearby) with regards to the keycode_context creation and involve Carbon API calls.

  ffi_call_SYSV (in libffi.dylib) + 80
  TSMGetInputSourceProperty (in HIToolbox) + 44
  isValidateInputSourceRef (in HIToolbox) + 92
  islGetInputSourceListWithAdditions (in HIToolbox) + 160
  _dispatch_assert_queue_fail (in libdispatch.dylib) + 0
  0xffff80018b7f991c
  _sigtramp (in libsystem_platform.dylib) + 56

g0t4 avatar Oct 07 '22 23:10 g0t4

I also ran into a crash when TSMCurrentAsciiCapableKeyboardLayoutInputSourceRefCreate was invoked (if I bypass the call to TISGetInputSourceProperty... so I commented out both calls and key logging worked... :)

g0t4 avatar Oct 07 '22 23:10 g0t4

In my case, I'm also using a QT as a frontend. I'm creating a Controller at the start, and a Listener on demand. My app crashes when starting the Listener.

I've modified _wrap_value in _util/darwin.py to log some info:

def _wrap_value(value):
    """Converts a pointer to a *Python objc* value.

    :param value: The pointer to convert.

    :return: a wrapped value
    """
    print(f"Called _wrap_value({value})")
    object = objc.objc_object(c_void_p=value) if value is not None else None
    print(f"Called _wrap_value({value}) = {object}")
    return object

When loading Controller at the start, I get this:

Called _wrap_value(4649539536)
Called _wrap_value(4649539536) = <TSMInputSource 0x1152257d0> KB Layout: Latin American (id=89)
Called _wrap_value(5195413504)
Called _wrap_value(5195413504) = b'\x02\x10\x00\x01\x00\x03\x00\x00\x1b\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x08\x03\x00\x00<\x1c\x00\x00P"\x00\x00\...

And then, when starting the listener:

Called _wrap_value(4649539536)

And then it crashes. Maybe it has something to do with the pointer being reused?

EDIT: Turned off the Controller, and the Listener keeps crashing the app :(

perroboc avatar Oct 21 '22 14:10 perroboc

It’s an issue with pyobjc and how it registers/resolves arg types and results

try adding this when your script/program starts up (before invoking pynput) and see if the issue resolves:

import objc import CoreFoundation

objc.registerCFSignature("CFStringRef", b"^{__CFString=}", CoreFoundation.CFStringGetTypeID(), "NSString")

On Fri, Oct 21, 2022 at 9:26 AM Alvaro @.***> wrote:

In my case, I'm also using a QT as a frontend. I'm creating a Controller at the start, and a Listener on demand.

I've modified _wrap_value in _util/darwin.py to log some info:

def _wrap_value(value): """Converts a pointer to a Python objc value. :param value: The pointer to convert. :return: a wrapped value """ print(f"Called _wrap_value({value})") object = objc.objc_object(c_void_p=value) if value is not None else None print(f"Called _wrap_value({value}) = {object}") return object

When loading Controller at the start, I get this:

Called _wrap_value(4649539536) Called _wrap_value(4649539536) = <TSMInputSource 0x1152257d0> KB Layout: Latin American (id=89) Called _wrap_value(5195413504) Called _wrap_value(5195413504) = b'\x02\x10\x00\x01\x00\x03\x00\x00\x1b\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x08\x03\x00\x00<\x1c\x00\x00P"\x00\x00...

And then, when starting the listener:

Called _wrap_value(4649539536)

And then it crashes. Maybe it has something to do with the pointer being reused?

— Reply to this email directly, view it on GitHub https://github.com/moses-palmer/pynput/issues/424#issuecomment-1287042585, or unsubscribe https://github.com/notifications/unsubscribe-auth/AABL7XPNHJN46ZFW6QZXR5TWEKRZHANCNFSM5I6ZI2FQ . You are receiving this because you commented.Message ID: @.***>

g0t4 avatar Oct 21 '22 16:10 g0t4

It’s an issue with pyobjc and how it registers/resolves arg types and results try adding this when your script/program starts up (before invoking pynput) and see if the issue resolves: import objc import CoreFoundation objc.registerCFSignature("CFStringRef", b"^{__CFString=}", CoreFoundation.CFStringGetTypeID(), "NSString")

Sadly, no, it keeps crashing only when Listener.start/join is called, even if Controller is not started, but my bug seems to be a new one...

... Something to do with the thread it's running in. The Controller is called on the main thread, while the listener in its own new thread. If I start the Controller and the Listener in the same object the application doesn't crash.

This MUST be a bug with objc way of creating objects from pointers. This line is the culprit: https://github.com/moses-palmer/pynput/blob/078491edf7025033c22a364ee76fb9e79db65fcc/lib/pynput/_util/darwin.py#L45

When invoking that line on creating a Listener from a new thread, on MacOS Monterey Apple Silicon, it crashes. The same software on Windows runs fine.

perroboc avatar Oct 21 '22 19:10 perroboc

So @g0t4 is right on this one. If I start the pynput keyboard Listener before QT, it works. But if I start it after QT, it fails and crashes the app.

perroboc avatar Oct 23 '22 17:10 perroboc

I'm having similar issues with my M1 mac running macOS Ventura but only when I use pynput with Qt... seems to fail similarly to the above issue with TISGetInputSourceProperty crashing my app.

I have rearranged Qt / pynput startup order and encountered some lazy load race conditions / timing issues with pyobjc behind the scenes such that I can get both to work in simple setups but I have another setup where I'm getting the following trace and haven't had much luck finding out why... I'll keep plugging away on it and share what I find.

All of the issues I've had (race conditions, and the following) stem from the same spot (or nearby) with regards to the keycode_context creation and involve Carbon API calls.

  ffi_call_SYSV (in libffi.dylib) + 80
  TSMGetInputSourceProperty (in HIToolbox) + 44
  isValidateInputSourceRef (in HIToolbox) + 92
  islGetInputSourceListWithAdditions (in HIToolbox) + 160
  _dispatch_assert_queue_fail (in libdispatch.dylib) + 0
  0xffff80018b7f991c
  _sigtramp (in libsystem_platform.dylib) + 56

@g0t4 Hi!

I'm having an issue with all the same symptoms as this, only using tkinter instead. Your proposed fix does not seem to work for me either.

Is there an issue we can file with pyobjc or do you know of an existing one to track the progress of this? It's impractical in my case to start the listener before I start tkinter.

Thank you.

Amund211 avatar May 30 '23 00:05 Amund211

Also impractical for me, and this is enough of a blocker that I'll have to switch away to another library. @moses-palmer can we reopen this issue for more visibility please?

Raymo111 avatar Apr 30 '24 03:04 Raymo111

@Raymo111, sure, I'll reopen.

moses-palmer avatar May 06 '24 08:05 moses-palmer

EDIT: I take it back, #541 does fix it for me! I probably installed it wrong the first time.

I think I'm running into the same issue, using PySide6 on a Macbook Air M2. It crashes when trying to start a Listener. #541 didn't fix it for me.

Macbook Air M2, Sonoma 14.4.1
python=3.12
pynput=1.7.7
Crashed Thread:        15

Exception Type:        EXC_BREAKPOINT (SIGTRAP)
Exception Codes:       0x0000000000000001, 0x000000018e340828

Termination Reason:    Namespace SIGNAL, Code 5 Trace/BPT trap: 5
Terminating Process:   exc handler [21598]
Thread 15 Crashed:
0   libdispatch.dylib             	       0x18e340828 _dispatch_assert_queue_fail + 120
1   libdispatch.dylib             	       0x18e3407b0 dispatch_assert_queue + 196
2   HIToolbox                     	       0x198d696c4 islGetInputSourceListWithAdditions + 160
3   HIToolbox                     	       0x198d6bd00 isValidateInputSourceRef + 92
4   HIToolbox                     	       0x198d6bbc0 TSMGetInputSourceProperty + 44
5   libffi.8.dylib                	       0x1012ac04c ffi_call_SYSV + 76
6   libffi.8.dylib                	       0x1012a974c ffi_call_int + 1208
7   _ctypes.cpython-312-darwin.so 	       0x10128c958 _ctypes_callproc + 1216
8   _ctypes.cpython-312-darwin.so 	       0x10128647c PyCFuncPtr_call + 1208

jzluo avatar May 31 '24 00:05 jzluo

I can confirm that #541 fixes the issue (M1 chip, Sonoma 14.5)

alexeykomp avatar Sep 12 '24 05:09 alexeykomp