Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 13 additions & 9 deletions lib/pynput/_util/darwin.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,26 +28,29 @@
import six

import objc
import HIServices
from HIServices import (
AXIsProcessTrusted
)

from CoreFoundation import (
CFRelease
)

from Quartz import (
CFMachPortCreateRunLoopSource,
CFRunLoopGetCurrent,
CFRunLoopAddSource,
CFRunLoopGetCurrent,
kCFRunLoopDefaultMode,
CGEventTapEnable,
CFRunLoopRunInMode,
kCFRunLoopRunTimedOut,
CFRunLoopStop,
CGEventTapCreate,
CGEventTapEnable,
kCFRunLoopDefaultMode,
kCFRunLoopRunTimedOut,
kCGEventTapOptionDefault,
kCGEventTapOptionListenOnly,
kCGSessionEventTap,
kCGHeadInsertEventTap,
kCGSessionEventTap)
kCGEventTapOptionListenOnly,
kCGEventTapOptionDefault
)


from . import AbstractListener
Expand Down Expand Up @@ -77,6 +80,7 @@ def _wrapped(value):
yield value
finally:
CFRelease(wrapped_value)
CFRelease(wrapped_value)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this double release intentional?



class CarbonExtra(object):
Expand Down Expand Up @@ -204,7 +208,7 @@ class ListenerMixin(object):
IS_TRUSTED = False

def _run(self):
self.IS_TRUSTED = HIServices.AXIsProcessTrusted()
self.IS_TRUSTED = AXIsProcessTrusted()
if not self.IS_TRUSTED:
self._log.warning(
'This process is not trusted! Input event monitoring will not '
Expand Down
12 changes: 6 additions & 6 deletions lib/pynput/keyboard/_darwin.py
Original file line number Diff line number Diff line change
Expand Up @@ -268,12 +268,12 @@ def __init__(self, *args, **kwargs):
None)

def _run(self):
with keycode_context() as context:
self._context = context
try:
super(Listener, self)._run()
finally:
self._context = None
context = keycode_context()
self._context = context
try:
super(Listener, self)._run()
finally:
self._context = None

def _handle(self, _proxy, event_type, event, _refcon):
# Convert the event to a KeyCode; this may fail, and in that case we
Expand Down
8 changes: 6 additions & 2 deletions lib/pynput/keyboard/_win32.py
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,7 @@ class Listener(ListenerMixin, _base.Listener):
#: The Windows hook ID for low level keyboard events, ``WH_KEYBOARD_LL``
_EVENTS = 13

_WM_INPUTLANGCHANGEREQUEST = 0x0050
_WM_INPUTLANGCHANGE = 0x0051
_WM_KEYDOWN = 0x0100
_WM_KEYUP = 0x0101
Expand All @@ -218,6 +219,7 @@ class Listener(ListenerMixin, _base.Listener):
#: Additional window messages to propagate to the subclass handler.
_WM_NOTIFICATIONS = (
_WM_INPUTLANGCHANGE,
_WM_INPUTLANGCHANGEREQUEST,
)

#: A mapping from keysym to special key
Expand Down Expand Up @@ -298,9 +300,11 @@ def _receive(self):
# pylint: enable=R0201

def _on_notification(self, code, wparam, lparam):
"""Receives ``WM_INPUTLANGCHANGE`` and updates the cached layout.
"""Receives ``WM_INPUTLANGCHANGE`` or ``WM_INPUTLANGCHANGE_REQUEST''
and updates the cached layout.
"""
if code == self._WM_INPUTLANGCHANGE:
if code == self._WM_INPUTLANGCHANGE \
or code == self._WM_INPUTLANGCHANGEREQUEST:
self._translator.update_layout()

def _event_to_key(self, msg, vk):
Expand Down
96 changes: 61 additions & 35 deletions lib/pynput/mouse/_darwin.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,32 @@

import enum
import Quartz
from Quartz import (
CGDisplayPixelsHigh,
kCGEventMouseMoved,
CGEventPost,
kCGHIDEventTap,
CGEventCreateMouseEvent,
CGEventCreateScrollWheelEvent,
kCGScrollEventUnitPixel,
CGEventSetIntegerValueField,
kCGMouseEventClickState,
CGEventMaskBit,
kCGEventLeftMouseDown,
kCGEventLeftMouseUp,
kCGEventLeftMouseDragged,
kCGEventRightMouseUp,
kCGEventRightMouseDown,
kCGEventOtherMouseDown,
kCGEventRightMouseDragged,
kCGEventOtherMouseUp,
kCGEventOtherMouseDragged,
kCGEventScrollWheel,
CGEventGetLocation,
CGEventGetIntegerValueField,
kCGScrollWheelEventDeltaAxis2,
kCGScrollWheelEventDeltaAxis1
)

from AppKit import NSEvent

Expand Down Expand Up @@ -72,18 +98,18 @@ def __init__(self, *args, **kwargs):
def _position_get(self):
pos = NSEvent.mouseLocation()

return pos.x, Quartz.CGDisplayPixelsHigh(0) - pos.y
return pos.x, CGDisplayPixelsHigh(0) - pos.y

def _position_set(self, pos):
try:
(_, _, mouse_type), mouse_button = self._drag_button.value
except AttributeError:
mouse_type = Quartz.kCGEventMouseMoved
mouse_type = kCGEventMouseMoved
mouse_button = 0

Quartz.CGEventPost(
Quartz.kCGHIDEventTap,
Quartz.CGEventCreateMouseEvent(
CGEventPost(
kCGHIDEventTap,
CGEventCreateMouseEvent(
None,
mouse_type,
pos,
Expand All @@ -93,18 +119,18 @@ def _scroll(self, dx, dy):
dx = int(dx)
dy = int(dy)

Quartz.CGEventPost(
Quartz.kCGHIDEventTap,
Quartz.CGEventCreateScrollWheelEvent(
CGEventPost(
kCGHIDEventTap,
CGEventCreateScrollWheelEvent(
None,
Quartz.kCGScrollEventUnitPixel,
kCGScrollEventUnitPixel,
2,
dy * self._SCROLL_SPEED,
dx * self._SCROLL_SPEED))

def _press(self, button):
(press, _, _), mouse_button = button.value
event = Quartz.CGEventCreateMouseEvent(
event = CGEventCreateMouseEvent(
None,
press,
self.position,
Expand All @@ -113,32 +139,32 @@ def _press(self, button):
# If we are performing a click, we need to set this state flag
if self._click is not None:
self._click += 1
Quartz.CGEventSetIntegerValueField(
CGEventSetIntegerValueField(
event,
Quartz.kCGMouseEventClickState,
kCGMouseEventClickState,
self._click)

Quartz.CGEventPost(Quartz.kCGHIDEventTap, event)
CGEventPost(kCGHIDEventTap, event)

# Store the button to enable dragging
self._drag_button = button

def _release(self, button):
(_, release, _), mouse_button = button.value
event = Quartz.CGEventCreateMouseEvent(
event = CGEventCreateMouseEvent(
None,
release,
self.position,
mouse_button)

# If we are performing a click, we need to set this state flag
if self._click is not None:
Quartz.CGEventSetIntegerValueField(
CGEventSetIntegerValueField(
event,
Quartz.kCGMouseEventClickState,
kCGMouseEventClickState,
self._click)

Quartz.CGEventPost(Quartz.kCGHIDEventTap, event)
CGEventPost(kCGHIDEventTap, event)

if button == self._drag_button:
self._drag_button = None
Expand All @@ -154,17 +180,17 @@ def __exit__(self, exc_type, value, traceback):
class Listener(ListenerMixin, _base.Listener):
#: The events that we listen to
_EVENTS = (
Quartz.CGEventMaskBit(Quartz.kCGEventMouseMoved) |
Quartz.CGEventMaskBit(Quartz.kCGEventLeftMouseDown) |
Quartz.CGEventMaskBit(Quartz.kCGEventLeftMouseUp) |
Quartz.CGEventMaskBit(Quartz.kCGEventLeftMouseDragged) |
Quartz.CGEventMaskBit(Quartz.kCGEventRightMouseDown) |
Quartz.CGEventMaskBit(Quartz.kCGEventRightMouseUp) |
Quartz.CGEventMaskBit(Quartz.kCGEventRightMouseDragged) |
Quartz.CGEventMaskBit(Quartz.kCGEventOtherMouseDown) |
Quartz.CGEventMaskBit(Quartz.kCGEventOtherMouseUp) |
Quartz.CGEventMaskBit(Quartz.kCGEventOtherMouseDragged) |
Quartz.CGEventMaskBit(Quartz.kCGEventScrollWheel))
CGEventMaskBit(kCGEventMouseMoved) |
CGEventMaskBit(kCGEventLeftMouseDown) |
CGEventMaskBit(kCGEventLeftMouseUp) |
CGEventMaskBit(kCGEventLeftMouseDragged) |
CGEventMaskBit(kCGEventRightMouseDown) |
CGEventMaskBit(kCGEventRightMouseUp) |
CGEventMaskBit(kCGEventRightMouseDragged) |
CGEventMaskBit(kCGEventOtherMouseDown) |
CGEventMaskBit(kCGEventOtherMouseUp) |
CGEventMaskBit(kCGEventOtherMouseDragged) |
CGEventMaskBit(kCGEventScrollWheel))

def __init__(self, *args, **kwargs):
super(Listener, self).__init__(*args, **kwargs)
Expand All @@ -178,22 +204,22 @@ def _handle(self, _proxy, event_type, event, _refcon):
This method will call the callbacks registered on initialisation.
"""
try:
(px, py) = Quartz.CGEventGetLocation(event)
(px, py) = CGEventGetLocation(event)
except AttributeError:
# This happens during teardown of the virtual machine
return

# Quickly detect the most common event type
if event_type == Quartz.kCGEventMouseMoved:
if event_type == kCGEventMouseMoved:
self.on_move(px, py)

elif event_type == Quartz.kCGEventScrollWheel:
dx = Quartz.CGEventGetIntegerValueField(
elif event_type == kCGEventScrollWheel:
dx = CGEventGetIntegerValueField(
event,
Quartz.kCGScrollWheelEventDeltaAxis2)
dy = Quartz.CGEventGetIntegerValueField(
kCGScrollWheelEventDeltaAxis2)
dy = CGEventGetIntegerValueField(
event,
Quartz.kCGScrollWheelEventDeltaAxis1)
kCGScrollWheelEventDeltaAxis1)
self.on_scroll(px, py, dx, dy)

else:
Expand Down