Skip to content
Open
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
3 changes: 2 additions & 1 deletion lib/pynput/keyboard/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,8 @@ def press(self, key):
if key in self._keys and key not in self._state:
self._state.add(key)
if self._state == self._keys:
self._on_activate()
if self._on_activate() is False:
raise Listener.StopException()

def release(self, key):
"""Updates the hotkey state for a released key.
Expand Down
3 changes: 2 additions & 1 deletion lib/pynput/keyboard/_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -712,7 +712,8 @@ def __init__(self, on_press=None, on_release=None, suppress=False,
on_press=on_press, on_release=on_release, suppress=suppress)
# pylint: enable=W0223

def canonical(self, key):
@staticmethod
def canonical(key):
"""Performs normalisation of a key.

This method attempts to convert key events to their canonical form, so
Expand Down
71 changes: 71 additions & 0 deletions tools/keyboard-mixin-test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@

# insert in front of sys.path because of system package already installed
import os
import sys
sys.path.insert(0,
os.path.join(os.path.dirname(__file__), '..', 'lib'))

import functools

from pynput import keyboard

__author__ = "Paolo Pastori"

"""
I was looking for a way to use both HotKeys and regular callabacks
(i.e. on_press and on_release) and still being able to pass the
suppress argument to the Listener.

The main issue was the call for keyboard.Listener.canonical.
"""

# these might be provided by the package
def notify_hotkeys(hotkeys, is_press):
"""Decorator factory to add HotKey capabilities to event callbacks.
"""
def decorator(callback):
@functools.wraps(callback)
def wrapper(key):
if callback(key) is False:
return False
can_key = keyboard.Listener.canonical(key)
hot_callback = 'press' if is_press else 'release'
for hk in hotkeys:
getattr(hk, hot_callback)(can_key)
return wrapper
return decorator

def activate_hotkeys(hotkeys):
return notify_hotkeys(hotkeys, True)

def deactivate_hotkeys(hotkeys):
return notify_hotkeys(hotkeys, False)


def on_ctrl_c():
print("=> HotKey('<ctrl>+c')")
return False

hotkeys = [
keyboard.HotKey(
keyboard.HotKey.parse('<ctrl>+c'),
on_ctrl_c)
]

@activate_hotkeys(hotkeys)
def on_press(key):
print("=> {}".format(key))

@deactivate_hotkeys(hotkeys)
def on_release(key):
print("=< {}".format(key))
if key == keyboard.Key.esc:
return False


with keyboard.Listener(
on_press=on_press,
on_release=on_release,
suppress=True) as listener:
print("Press ESC or Ctrl-C to exit")
listener.join()