PYNPUT(3)
PYNPUT ๐ pynput Documentation ๐
okay bestie, sit down, hydrate, because this is the manual page for pynput โ she's a Python library that lets you control and monitor input devices. like, your mouse and your keyboard? you can drive them AND spy on them. both. iconic behaviour honestly. ๐
NAME โจ
pynput โ the pynput documentation, periodt.
This library lets you control and monitor input devices. fr fr.
It contains subpackages for each type of input device supported:
pynput.mouseโ contains classes for controlling and monitoring a mouse or trackpad. ๐ญpynput.keyboardโ contains classes for controlling and monitoring the keyboard. โจ๏ธ
All the modules mentioned above are automatically imported into the pynput package. So to use any of them, you just import them from the main package, no cap:
from pynput import mouse, keyboard
FORCING A SPECIFIC BACKEND ๐
pynput tries to use the backend that suits your current platform, but lowkey you're allowed to override that automatic choice. main character energy = choosing your own backend. ๐
If the environment variables $PYNPUT_BACKEND_KEYBOARD or $PYNPUT_BACKEND are set, their value will be used as the backend name for the keyboard classes. And if $PYNPUT_BACKEND_MOUSE or $PYNPUT_BACKEND are set, their value will be used as the backend name for the mouse classes. ๐
Here's the available backend menu, bestie:
darwinโ the default for macOS. ๐win32โ the default for Windows. ๐ชuinputโ an optional backend for Linux, requiring root privileges and supporting only keyboards. (keyboards only, she said what she said.)xorgโ the default for other operating systems. ๐งdummyโ a non-functional, but importable, backend. This is useful as a mouse backend when using theuinputbackend. (a fake little guy, but he imports, and that's what counts ๐ซถ)
๐ฆ TABLE OF CONTENTS ๐ฆ
Handling the mouse ๐ญ
The package pynput.mouse contains classes for controlling and monitoring the mouse.
Controlling the mouse ๐ฎ
Use pynput.mouse.Controller like this:
from pynput.mouse import Button, Controller
mouse = Controller()
# Read pointer position
print('The current pointer position is {}'.format(
mouse.position))
# Set pointer position
mouse.position = (10, 20)
print('Now we have moved it to {}'.format(
mouse.position))
# Move pointer relative to current position
mouse.move(5, -5)
# Press and release
mouse.press(Button.left)
mouse.release(Button.left)
# Double click; this is different from pressing and releasing
# twice on macOS
mouse.click(Button.left, 2)
# Scroll two steps down
mouse.scroll(0, 2)
Monitoring the mouse ๐
Use pynput.mouse.Listener like this:
from pynput import mouse
def on_move(x, y, injected):
print('Pointer moved to {}; it was {}'.format(
(x, y, 'faked' if injected else 'not faked')))
def on_click(x, y, button, pressed, injected):
print('{} at {}; it was {}'.format(
'Pressed' if pressed else 'Released',
(x, y, 'faked' if injected else 'not faked')))
if not pressed:
# Stop listener
return False
def on_scroll(x, y, dx, dy, injected):
print('Scrolled {} at {}; it was {}'.format(
'down' if dy < 0 else 'up',
(x, y, 'faked' if injected else 'not faked')))
# Collect events until released
with mouse.Listener(
on_move=on_move,
on_click=on_click,
on_scroll=on_scroll) as listener:
listener.join()
# ...or, in a non-blocking fashion:
listener = mouse.Listener(
on_move=on_move,
on_click=on_click,
on_scroll=on_scroll)
listener.start()
A mouse listener is a threading.Thread, and all callbacks will be invoked from the thread. iykyk.
Call pynput.mouse.Listener.stop from anywhere, raise StopException or return False from a callback to stop the listener. three ways to say bye. ๐
When using the non-blocking version above, the current thread will continue executing. This might be necessary when integrating with other GUI frameworks that incorporate a main-loop, but when run from a script, this will cause the program to terminate immediately. so like, watch out.
The mouse listener thread ๐งต
The listener callbacks are invoked directly from an operating thread on some platforms, notably Windows.
This means that long running procedures and blocking operations should not be invoked from the callback, as this risks freezing input for all processes. ๐ญ pls don't do it.
A possible workaround is to just dispatch incoming messages to a queue, and let a separate thread handle them. (queue bestie, she never misses โจ)
Handling mouse listener errors ๐จ
If a callback handler raises an exception, the listener will be stopped. Since callbacks run in a dedicated thread, the exceptions will not automatically be reraised.
To be notified about callback errors, call Thread.join on the listener instance:
from pynput import mouse
class MyException(Exception): pass
def on_click(x, y, button, pressed):
if button == mouse.Button.left:
raise MyException(button)
# Collect events until released
with mouse.Listener(
on_click=on_click) as listener:
try:
listener.join()
except MyException as e:
print('{} was clicked'.format(e.args[0]))
Toggling event listening for the mouse listener ๐
Once pynput.mouse.Listener.stop has been called, the listener cannot be restarted, since listeners are instances of threading.Thread. she's done, she's not coming back. ๐
If your application requires toggling listening events, you must either add an internal flag to ignore events when not required, or create a new listener when resuming listening. two options, pick your fighter. ๐
Synchronous event listening for the mouse listener โณ
To simplify scripting, synchronous event listening is supported through the utility class pynput.mouse.Events. This class supports reading single events in a non-blocking fashion, as well as iterating over all events. obsessed. โจ
To read a single event, use the following code:
from pynput import mouse
# The event listener will be running in this block
with mouse.Events() as events:
# Block at most one second
event = events.get(1.0)
if event is None:
print('You did not interact with the mouse within one second')
else:
print('Received event {}'.format(event))
To iterate over mouse events, use the following code:
from pynput import mouse
# The event listener will be running in this block
with mouse.Events() as events:
for event in events:
if event.button == mouse.Button.right:
break
else:
print('Received event {}'.format(event))
Please note that the iterator method does not support non-blocking operation, so it will wait for at least one mouse event. bestie she waits. no way around it. ๐ญ
The events will be instances of the inner classes found in pynput.mouse.Events.
Ensuring consistent coordinates between listener and controller on Windows ๐ช
Recent versions of _Windows_ support running legacy applications scaled when the system scaling has been increased beyond 100%. This allows old applications to scale, albeit with a blurry look, and avoids tiny, unusable user interfaces.
This scaling is unfortunately inconsistently applied to a mouse listener and a controller: the listener will receive physical coordinates, but the controller has to work with scaled coordinates. it's giving mismatch, it's giving chaos. ๐
This can be worked around by telling Windows that your application is DPI aware. This is a process global setting, so _pynput_ cannot do it automatically. Do enable DPI awareness, run the following code:
import ctypes
PROCESS_PER_MONITOR_DPI_AWARE = 2
ctypes.windll.shcore.SetProcessDpiAwareness(PROCESS_PER_MONITOR_DPI_AWARE)
Reference ๐
class pynput.mouse.Controller
A controller for sending virtual mouse events to the system. she's the one sending the events, no cap. ๐ซถ
click(button, count=1)
Emits a button click event at the current position.
The default implementation sends a series of press and release events.
Parameters
button(Button) -- The button to click.count(int) -- The number of clicks to send.
move(dx, dy)
Moves the mouse pointer a number of pixels from its current position.
Parameters
dx(int) -- The horizontal offset.dy(int) -- The vertical offset.
Raises ValueError -- if the values are invalid, for example out of bounds
property position
The current position of the mouse pointer.
This is the tuple (x, y), and setting it will move the pointer. ๐ธ
press(button)
Emits a button press event at the current position.
Parameters button (Button) -- The button to press.
release(button)
Emits a button release event at the current position.
Parameters button (Button) -- The button to release.
scroll(dx, dy)
Sends scroll events.
Parameters
dx(int) -- The horizontal scroll. The units of scrolling is undefined.dy(int) -- The vertical scroll. The units of scrolling is undefined.
Raises ValueError -- if the values are invalid, for example out of bounds
class pynput.mouse.Listener(on_move=None, on_click=None, on_scroll=None, suppress=False, **kwargs)
A listener for mouse events. ๐ the main character herself.
Instances of this class can be used as context managers. This is equivalent to the following code:
listener.start()
try:
listener.wait()
with_statements()
finally:
listener.stop()
This class inherits from threading.Thread and supports all its methods. It will set daemon to True when created.
All callback arguments are optional; a callback may take less arguments than actually passed, but not more, unless they are optional. ๐
Parameters
on_move(callable) --
The callback to call when mouse move events occur.
It will be called with the arguments (x, y, injected), where (x, y) is the new pointer position and injected whether the event was injected and thus not generated by an actual input device. If this callback raises StopException or returns False, the listener is stopped.
Please note that not all backends supportinjectedand will always set it toFalse.
on_click(callable) --on_click(callable) โ the callback that gets called when a mouse button gets clicked, periodt. ๐ฑ๏ธ
It's called with (x, y, button, pressed, injected), where (x, y) is the new pointer position, button is one of the Button, pressed is whether the button was pressed, and injected is whether the event was injected (so like, NOT generated by an actual input device ๐).
If this callback raises StopException or returns False, the listener is stopped. simple as that.
Please note: not all backends support injected and will always set it to False. ๐ซ
on_scroll(callable) โ the callback that gets called when mouse scroll events occur. โจ
It's called with (x, y, dx, dy, injected), where (x, y) is the new pointer position, (dx, dy) is the scroll vector, and injected is whether the event was injected and thus not generated by an actual input device.
If this callback raises StopException or returns False, the listener is stopped. bye bestie ๐
Please note: not all backends support injected and will always set it to False. (yeah, same vibe as above, not a typo ๐)
suppress(bool) โ whether to suppress events. Setting this toTruewill prevent the input events from being passed to the rest of the system. it's giving "hold my calls" energy ๐ตkwargsโ any non-standard platform dependent options, bestie. These should be prefixed with the platform name, thus:darwin_,xorg_orwin32_.
Supported values are:
darwin_intercept : A callable taking the arguments (event_type, event), where event_type is any mouse related event type constant, and event is a CGEventRef.
This callable can freely modify the event using functions like Quartz.CGEventSetIntegerValueField. If this callable does not return the event, the event is suppressed system wide. ๐
win32_event_filter : A callable taking the arguments (msg, data), where msg is the current message, and data associated data as a MSLLHOOKSTRUCT <https://docs.microsoft.com/en-gb/windows/win32/api/winuser/ns-winuser-msllhookstruct>.
If this callback returns False, the event will not be propagated to the listener callback.
If self.suppress_event() is called, the event is suppressed system wide. ๐
__init__(on_move=None, on_click=None, on_scroll=None, suppress=False, **kwargs)
okay so this constructor should always be called with keyword arguments, no exceptions. Arguments are:
groupshould beNone; reserved for future extension when aThreadGroupclass is implemented. (it's giving "coming soon, no cap" ๐)targetis the callable object to be invoked by therun()method. Defaults toNone, meaning nothing is called.nameis the thread name. By default, a unique name is constructed of the form"Thread-N"whereNis a small decimal number.argsis a list or tuple of arguments for thetargetinvocation. Defaults to().kwargsis a dictionary of keyword arguments for thetargetinvocation. Defaults to{}.contextis thecontextvars.Contextvalue to use for the thread. The default value isNone, which means to checksys.flags.thread_inherit_context. If that flag is true, use a copy of the context of the caller. If false, use an empty context. To explicitly start with an empty context, pass a new instance ofcontextvars.Context(). To explicitly start with a copy of the current context, pass the value fromcontextvars.copy_context().
If a subclass overrides the constructor, it must make sure to invoke the base class constructor (Thread.__init__()) before doing anything else to the thread. rules are rules ๐ซถ
property running
Whether the listener is currently running. vibe check: are we live or not โจ
start()
Start the thread's activity. ๐
It must be called at most once per thread object. It arranges for the object's run() method to be invoked in a separate thread of control.
This method will raise a RuntimeError if called more than once on the same thread object. bestie don't push it ๐ญ
stop()
Stops listening for events.
When this method returns, no more events will be delivered. Once this method has been called, the listener instance cannot be used any more, since a listener is a threading.Thread, and once stopped it cannot be restarted.
To resume listening for event, a new listener must be created. new listener, new me ๐
wait()
Waits for this listener to become ready. just gonna sit here and vibe until it's up โณ
๐ธ Handling the keyboard ๐ธ
The package pynput.keyboard contains classes for controlling and monitoring the keyboard. keyboard girlies rise up โจ๏ธ๐
๐ฎ Controlling the keyboard
Use pynput.keyboard.Controller like this:
from pynput.keyboard import Key, Controller
keyboard = Controller()
# Press and release space
keyboard.press(Key.space)
keyboard.release(Key.space)
# Type a lower case A; this will work even if no key on the
# physical keyboard is labelled 'A'
keyboard.press('a')
keyboard.release('a')
# Type two upper case As
keyboard.press('A')
keyboard.release('A')
with keyboard.pressed(Key.shift):
keyboard.press('a')
keyboard.release('a')
# Type 'Hello World' using the shortcut type method
keyboard.type('Hello World')
๐ Monitoring the keyboard
Use pynput.keyboard.Listener like this:
from pynput import keyboard
def on_press(key, injected):
try:
print('alphanumeric key {} pressed; it was {}'.format(
key.char, 'faked' if injected else 'not faked'))
except AttributeError:
print('special key {} pressed'.format(
key))
def on_release(key, injected):
print('{} released; it was {}'.format(
key, 'faked' if injected else 'not faked'))
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()
# ...or, in a non-blocking fashion:
listener = keyboard.Listener(
on_press=on_press,
on_release=on_release)
listener.start()
A keyboard listener is a threading.Thread, and all callbacks will be invoked from the thread. threads threads threads โจ
Call pynput.keyboard.Listener.stop from anywhere, raise StopException or return False from a callback to stop the listener. three ways, pick your fighter ๐ซถ
The key parameter passed to callbacks is a pynput.keyboard.Key, for special keys, a pynput.keyboard.KeyCode for normal alphanumeric keys, or just None for unknown keys.
When using the non-blocking version above, the current thread will continue executing. This might be necessary when integrating with other GUI frameworks that incorporate a main-loop, but when run from a script, this will cause the program to terminate immediately. yes, immediately. not a drill ๐ญ
๐งต The keyboard listener thread
The listener callbacks are invoked directly from an operating thread on some platforms, notably Windows.
This means that long running procedures and blocking operations should not be invoked from the callback, as this risks freezing input for all processes. like, all of them. do not do it ๐
A possible workaround is to just dispatch incoming messages to a queue, and let a separate thread handle them. queue bestie, queue ๐
๐ญ Handling keyboard listener errors
If a callback handler raises an exception, the listener will be stopped. Since callbacks run in a dedicated thread, the exceptions will not automatically be reraised.
To be notified about callback errors, call Thread.join on the listener instance:
from pynput import keyboard
class MyException(Exception): pass
def on_press(key):
if key == keyboard.Key.esc:
raise MyException(key)
# Collect events until released
with keyboard.Listener(
on_press=on_press) as listener:
try:
listener.join()
except MyException as e:
print('{} was pressed'.format(e.args[0]))
๐ Toggling event listening for the keyboard listener
Once pynput.keyboard.Listener.stop has been called, the listener cannot be restarted, since listeners are instances of threading.Thread.
If your application requires toggling listening events, you must either add an internal flag to ignore events when not required, or create a new listener when resuming listening. two options, no third one, iykyk ๐
โฑ๏ธ Synchronous event listening for the keyboard listener
To simplify scripting, synchronous event listening is supported through the utility class pynput.keyboard.Events. This class supports reading single events in a non-blocking fashion, as well as iterating over all events. iconic behaviour honestly โจ
To read a single event, use the following code:
from pynput import keyboard
# The event listener will be running in this block
with keyboard.Events() as events:
# Block at most one second
event = events.get(1.0)
if event is None:
print('You did not press a key within one second')
else:
print('Received event {}'.format(event))
To iterate over keyboard events, use the following code:
from pynput import keyboard
# The event listener will be running in this block
with keyboard.Events() as events:
for event in events:
if event.key == keyboard.Key.esc:
break
else:
print('Received event {}'.format(event))
Please note that the iterator method does not support non-blocking operation, so it will wait for at least one keyboard event. it's patient, unlike me ๐ญ
The events will be instances of the inner classes found in pynput.keyboard.Events. ๐
๐ Global hotkeys ๐
okay so the โจiconicโจ use case for a keyboard monitor is reacting to global hotkeys. and here's the tea: a listener does not maintain any state, so if your hotkey involves more than one key, somebody has to store that state somewhere. ๐
that's literally what pynput.keyboard.HotKey is for. it comes with two methods that update the state, and they're designed to slot right into a keyboard listener with zero drama: pynput.keyboard.HotKey.press and pynput.keyboard.HotKey.release, both of which can be passed directly as listener callbacks. ๐ซถ
the intended usage is giving:
from pynput import keyboard
def on_activate():
print('Global hotkey activated!')
def for_canonical(f):
return lambda k: f(l.canonical(k))
hotkey = keyboard.HotKey(
keyboard.HotKey.parse('<ctrl>+<alt>+h'),
on_activate)
with keyboard.Listener(
on_press=for_canonical(hotkey.press),
on_release=for_canonical(hotkey.release)) as l:
l.join()
so this creates a hotkey, then uses a listener to update its state. once all the specified keys are pressed at the same time, on_activate gets invoked. slay. ๐
ngl, note that keys are passed through pynput.keyboard.Listener.canonical before they ever reach the HotKey instance. why? to strip any modifier state off the key events, and to normalise modifiers that have more than one physical button. โจ
pynput.keyboard.HotKey.parse is a convenience function that transforms shortcut strings into key collections โ go read its documentation for the whole story, bestie. ๐
and if you wanna register a whole bunch of global hotkeys, use the convenience class pynput.keyboard.GlobalHotKeys:
from pynput import keyboard
def on_activate_h():
print('<ctrl>+<alt>+h pressed')
def on_activate_i():
print('<ctrl>+<alt>+i pressed')
with keyboard.GlobalHotKeys({
'<ctrl>+<alt>+h': on_activate_h,
'<ctrl>+<alt>+i': on_activate_i}) as h:
h.join()
๐ซถ Reference ๐ซถ
class pynput.keyboard.Controller
a controller for sending virtual keyboard events to the system. it's giving puppet-master energy. ๐
exception InvalidCharacterException
the exception raised when an invalid character is encountered in the string passed to Controller.type().
its first argument is the index of the character in the string, and the second is the character itself.
exception InvalidKeyException
the exception raised when an invalid key parameter is passed to either Controller.press() or Controller.release().
its first argument is the key parameter.
property alt_gr_pressed
whether altgr is pressed.
please note that this reflects only the internal state of this controller. see modifiers for more info. ๐
property alt_pressed
whether any alt key is pressed.
again, this reflects only the internal state of this controller. see modifiers for more.
property ctrl_pressed
whether any ctrl key is pressed.
yep, still only this controller's internal state. see modifiers.
property modifiers
the currently pressed modifier keys.
please note that this reflects only the internal state of this controller, and not the state of the operating system keyboard buffer. this property cannot be used to determine whether a key is physically pressed. ๐
only the generic modifiers will be set; when pressing either Key.shift_l, Key.shift_r or Key.shift, only Key.shift will be present.
use this property inside a context block like this, bestie:
with controller.modifiers as modifiers:
with_block()
this ensures the modifiers can't be modified by another thread. no chaotic cross-thread interference here. ๐ซ
press(key)
presses a key.
a key may be either a string of length 1, one of the Key members, or a KeyCode.
strings get transformed to KeyCode using KeyCode.char(). members of Key get translated to their value().
Parameters
keyโ the key to press.
Raises
InvalidKeyExceptionโ if the key is invalidValueErrorโ ifkeyis a string, but its length is not 1
pressed(*args)
executes a block with some keys pressed.
Parameters
keysโ the keys to keep pressed.
release(key)
releases a key.
a key may be either a string of length 1, one of the Key members, or a KeyCode.
strings get transformed to KeyCode using KeyCode.char(). members of Key get translated to their value().
Parameters
keyโ the key to release. if this is a string, it is passed totouches()and the returned releases are used.
Raises
InvalidKeyExceptionโ if the key is invalidValueErrorโ ifkeyis a string, but its length is not 1
property shift_pressed
whether any shift key is pressed, or caps lock is toggled.
once again for the people in the back: this reflects only the internal state of this controller. see modifiers. โจ
tap(key)
presses and releases a key.
this is literally equivalent to this code right here:
controller.press(key)
controller.release(key)
Parameters
keyโ the key to press.
Raises
InvalidKeyExceptionโ if the key is invalidValueErrorโ ifkeyis a string, but its length is not 1
touch(key, is_press)
calls either press() or release() depending on the value of is_press. it's a lil switchboard, and honestly? iconic. ๐ฅ
Parameters
keyโ the key to press or release.is_press(bool) โ whether to press the key.
Raises
InvalidKeyExceptionโ if the key is invalid
type(string)
types a string.
this method will send all the key presses and releases necessary to type all the characters in the string. it's out here doing the whole keyboard for you. ๐
Parameters
string(str) โ the string to type.
Raises
InvalidCharacterExceptionโ if an untypable character is encountered
class pynput.keyboard.Listener(on_press=None, on_release=None, suppress=False, **kwargs)
a listener for keyboard events. it's eavesdropping but make it legitimate. ๐โจ
instances of this class can be used as context managers. this is equivalent to the following code:
listener.start()
try:
listener.wait()
with_statements()
finally:
listener.stop()
this class inherits from threading.Thread and supports all its methods. it will set daemon to True when created.
all callback arguments are optional; a callback may take less arguments than actually passed, but not more, unless they are optional. (don't be greedy with the args, bestie. ๐ญ)
Parameters
on_press(callable) โ
the callback to call when a button is pressed.
it will be called with the arguments (key, injected), where key is a KeyCode, a Key or None if the key is unknown, and injected is whether the event was injected and thus not generated by an actual input device.
please note that not all backends supportinjectedand will always set it toFalse. ๐
on_release(callable) โ
the callback to call when a button is released.
it will be called with the arguments (key, injected), where key is a KeyCode, a Key or None if the key is unknown, and injected is whether the event was injected and thus not generated by an actual input device.
please note that not all backends supportinjectedand will always set it toFalse. ๐
suppress(bool) โ whether to suppress events. setting this toTruewill prevent the input events from being passed to the rest of the system. ๐ซkwargsโ
any non-standard platform dependent options. these should be prefixed with the platform name, thus: darwin_, uinput_, xorg_ or win32_.
supported values are:
darwin_intercept
a callable taking the arguments (event_type, event), where event_type is Quartz.kCGEventKeyDown or Quartz.kCGEventKeyUp, and event is a CGEventRef.
this callable can freely modify the event using functions like Quartz.CGEventSetIntegerValueField. if this callable does not return the event, the event is suppressed system wide. ๐ณ
uinput_device_paths
a list of device paths.
if this is specified, pynput will limit the number of devices checked for the capabilities needed to those passed; otherwise, all system devices will be used. passing this might be required if an incorrect device is chosen. ๐ฏ
win32_event_filterโ a callable that takes two args:(msg, data), wheremsgis the message that's happening right now, anddatais the associated data, shaped like aKBDLLHOOKSTRUCT(that's the Windows struct, full deets athttps://docs.microsoft.com/en-gb/windows/win32/api/winuser/ns-winuser-kbdllhookstruct).
If this callback returns False, the event won't get propagated to the listener callback. Like, it just doesn't reach your handler. Bye.
And if you call self.suppress_event(), the event is suppressed system wide. Yes, everywhere. Iconic but also use with care bestie.
__init__(on_press=None, on_release=None, suppress=False, **kwargs)โ okay so this constructor should always be called with keyword arguments. No positional shenanigans here. The arguments are:groupshould beNone; it's reserved for future extension when aThreadGroupclass is implemented. So just leave it alone fr.targetis the callable object that gets invoked by therun()method. Defaults toNone, which means nothing is called. Nothing. Nada.nameis the thread name. By default a unique name gets constructed of the form"Thread-N"whereNis a small decimal number.argsis a list or tuple of arguments for the target invocation. Defaults to().kwargsis a dictionary of keyword arguments for the target invocation. Defaults to{}.contextis thecontextvars.Contextvalue to use for the thread. The default value isNone, which means "checksys.flags.thread_inherit_context". If that flag is true, use a copy of the context of the caller. If it's false, use an empty context. Wanna explicitly start with an empty context? Pass a new instance ofcontextvars.Context(). Wanna explicitly start with a copy of the current context? Pass the value fromcontextvars.copy_context(). Pick your fighter ๐- If a subclass overrides the constructor, it must make sure to invoke the base class constructor (
Thread.__init__()) before doing anything else to the thread. Do not skip this step bestie, it's giving house-on-fire energy.
property runningโ whether the listener is currently running. Just a lil peek at the state, no side effects.start()โ starts the thread's activity.
It has to be called at most once per thread object. It arranges for the object's run() method to be invoked in a separate thread of control.
This method will raise a RuntimeError if you call it more than once on the same thread object. Once is the vibe. Twice is a crime ๐
stop()โ stops listening for events.
When this method returns, no more events will be delivered. And once this method has been called, the listener instance cannot be used any more, because a listener is a threading.Thread, and once stopped it cannot be restarted. That's it. That's the whole arc.
To resume listening for events, a new listener must be created. Fresh start, new listener, new me. โจ
wait()โ waits for this listener to become ready. Chill here until it's up.
class pynput.keyboard.Key(*values)
A class representing the various buttons that may not correspond to letters. This includes modifier keys and function keys. The โจspecial keysโจ, basically.
The actual values for these items differ between platforms. Some platforms may have additional buttons, but these ones are guaranteed to be present everywhere. Universally iconic.
alt = <0>โ a generic Alt key. This is a modifier.alt_gr = <0>โ the AltGr key. This is a modifier.alt_l = <0>โ the left Alt key. This is a modifier.alt_r = <0>โ the right Alt key. This is a modifier.backspace = <0>โ the Backspace key.caps_lock = <0>โ the CapsLock key.cmd = <0>โ a generic command button. On PC platforms this corresponds to the Super key or Windows key, and on Mac it corresponds to the Command key. This may be a modifier.cmd_l = <0>โ the left command button. On PC platforms this corresponds to the Super key or Windows key, and on Mac it corresponds to the Command key. This may be a modifier.cmd_r = <0>โ the right command button. On PC platforms this corresponds to the Super key or Windows key, and on Mac it corresponds to the Command key. This may be a modifier.ctrl = <0>โ a generic Ctrl key. This is a modifier.ctrl_l = <0>โ the left Ctrl key. This is a modifier.ctrl_r = <0>โ the right Ctrl key. This is a modifier.delete = <0>โ the Delete key.down = <0>โ a down arrow key.end = <0>โ the End key.enter = <0>โ the Enter or Return key.esc = <0>โ the Esc key.f1 = <0>โ the function keys. F1 to F20 are defined. That's twenty whole function keys, they really said "go big or go home".home = <0>โ the Home key.insert = <0>โ the Insert key. This may be undefined for some platforms.left = <0>โ a left arrow key.media_next = <0>โ the next track button.media_play_pause = <0>โ the play/pause toggle.media_previous = <0>โ the previous track button.media_volume_down = <0>โ the volume down button.media_volume_mute = <0>โ the volume mute button.media_volume_up = <0>โ the volume up button.menu = <0>โ the Menu key. This may be undefined for some platforms.num_lock = <0>โ the NumLock key. This may be undefined for some platforms.page_down = <0>โ the PageDown key.page_up = <0>โ the PageUp key.pause = <0>โ the Pause/Break key. This may be undefined for some platforms.print_screen = <0>โ the PrintScreen key. This may be undefined for some platforms.right = <0>โ a right arrow key.scroll_lock = <0>โ the ScrollLock key. This may be undefined for some platforms.shift = <0>โ a generic Shift key. This is a modifier.shift_l = <0>โ the left Shift key. This is a modifier.shift_r = <0>โ the right Shift key. This is a modifier.space = <0>โ the Space key.tab = <0>โ the Tab key.up = <0>โ an up arrow key.
class pynput.keyboard.KeyCode(vk=None, char=None, is_dead=False, **kwargs)
A KeyCode represents the description of a key code used by the operating system. It's the "how the OS sees this key" situation.
classmethod from_char(char, **kwargs)โ creates a key from a character.- Parameters:
char(str) โ the character. - Returns: a key code.
- Parameters:
classmethod from_dead(char, **kwargs)โ creates a dead key.- Parameters:
charโ the dead key. This should be the unicode character representing the stand alone character, such as'~'for COMBINING TILDE. - Returns: a key code.
- Parameters:
classmethod from_vk(vk, **kwargs)โ creates a key from a virtual key code.- Parameters:
vkโ the virtual key code.kwargsโ any other parameters to pass.
- Returns: a key code.
- Parameters:
join(key)โ applies this dead key to another key and returns the result. Combo move ๐ธ
Joining a dead key with space (' ') or with itself yields the non-dead version of this key, if one exists; for example, KeyCode.from_dead('~').join(KeyCode.from_char(' ')) equals KeyCode.from_char('~') and KeyCode.from_dead('~').join(KeyCode.from_dead('~')).
- Parameters:
key(KeyCode, see#pynput.keyboard.KeyCode) โ the key to join with this key. - Returns: a key code.
- Raises
ValueErrorโ if the keys cannot be joined. Some pairs just aren't meant to be ๐
๐ฆ Frequently asked question ๐ฆ
How do I suppress specific events only? ๐ญ
Passing the suppress=True flag to listeners will suppress all events system-wide. That's the nuclear option. If that is not what you want (and bestie, usually it is not), you will have to employ different solutions for different backends.
If your backend of choice is not listed below, it does not support suppression of specific events. Periodt. No workaround, no secret trick.
๐ macOS
For macOS, pass the named argument darwin_intercept to the listener constructor. This argument should be a callable taking the arguments (event_type, event), where event_type is any mouse related event type constant, and event is a CGEventRef (https://developer.apple.com/documentation/coregraphics/cgeventref?language=objc). The event argument can be manipulated by the functions found on the Apple documentation (https://developer.apple.com/documentation/coregraphics/quartz_event_services?language=objc).
If the interceptor function determines that the event should be suppressed, return None, otherwise return the event, which you may modify. Simple as that.
Here's a keyboard example, enjoy:
def darwin_intercept(event_type, event):
import Quartz
length, chars = Quartz.CGEventKeyboardGetUnicodeString(
event, 100, None, None)
if length > 0 and chars == 'x':
# Suppress x
return None
elif length > 0 and chars == 'a':
# Transform a to b
Quartz.CGEventKeyboardSetUnicodeString(event, 1, 'b')
else:
return event
๐ช Windows
For Windows, pass the argument named win32_event_filter to the listener constructor. This argument should be a callable taking the arguments (msg, data), where msg is the current message, and data is associated data as a MSLLHOOKSTRUCT (https://docs.microsoft.com/en-gb/windows/win32/api/winuser/ns-winuser-msllhookstruct) or a KBDLLHOOKSTRUCT, depending on whether you are creating a mouse or a keyboard listener. Mouse data, keyboard data, know the difference iykyk. ๐
okay so if the filter function decides this event needs to be suppressed, you call suppress_event on the listener. and if you return False? that event gets hidden from other listener callbacks. gone. invisible. nobody else sees it. ๐
here's a keyboard example, bestie, take notes:
# Values for MSLLHOOKSTRUCT.vkCode can be found here:
# https://docs.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes
def win32_event_filter(msg, data):
if data.vkCode == 0x58:
# Suppress x
listener.suppress_event()
๐ When using a packager I get an ImportError on startup ๐
so this one hits when you're using a packager, like PyInstaller, to package your application. ๐ญ
the reason for the error is that the packager attempts to build a dependency tree of the modules used by inspecting import statements, and pynput finds the platform dependent backend modules at runtime using importlib. so the packager literally cannot see them coming. it's giving invisible. ๐ซฅ
to solve this problem, please consult the documentation of your tool to find how to explicitly add modules. (every tool does it its own way, iykyk.)
which modules to add depends on your distribution platform. the backend modules are those starting with an underscore ('_') in the pynput.keyboard and pynput.mouse packages. additionally, you will need modules with corresponding names from the pynput._util package. โจ
๐ Platform limitations ๐
pynput aims at providing a unified API for all supported platforms. in some cases, however, that is not entirely possible. ๐ฅฒ no cap.
๐ง Linux ๐ง
On Linux, pynput uses X or uinput.
when running under X, the following must be true:
- An X server must be running. ๐ฅ๏ธ
- The environment variable
$DISPLAYmust be set.
when running under uinput, the following must be true:
- You must run your script as
root, so that it has the required permissions for uinput. ๐
also please note that the injected flag is not supported for uinput. ๐ซ
the latter requirement for X means that running pynput over SSH generally will not work. ๐ญ to work around that, make sure to set $DISPLAY:
$ DISPLAY=:0 python -c 'import pynput'
please note that the value DISPLAY=:0 is just an example. to find the actual value, please launch a terminal application from your desktop environment and issue the command echo $DISPLAY.
when running under Wayland, the X server emulator Xwayland will usually run, providing limited functionality. notably, you will only receive input events from applications running under this emulator. ๐ฆ
๐ macOS ๐
recent versions of macOS restrict monitoring of the keyboard for security reasons. for that reason, one of the following must be true:
- The process must run as
root. ๐ - Your application must be white listed under Enable access for assistive devices. note that this might require that you package your application, since otherwise the entire Python installation must be white listed. ๐
- On versions after Mojave, you may also need to whitelist your terminal application if running your script from a terminal.
please note that this does not apply to monitoring of the mouse or trackpad. ๐ญ
all listener classes have the additional attribute IS_TRUSTED, which is True if no permissions are lacking. โจ
๐ช Windows ๐ช
on Windows, virtual events sent by other processes may not be received. this library takes precautions, however, to dispatch any virtual events generated to all currently running listeners of the current process. ๐ซถ
furthermore, sending key press events will properly propagate to the rest of the system, but the operating system does not consider the buttons to be truly pressed. this means that key press events will not be continuously emitted as when holding down a physical key, and certain key sequences, such as shift pressed while pressing arrow keys, do not work as expected. ๐
- Index <>
๐ Author ๐
Moses Palmรฉr
๐ Copyright ๐
2015-2026, Moses Palmรฉr
and that's the whole page bestie, you ate that fr fr ๐ source version 1.8.2, dated May 16, 2026, and yes, this is PYNPUT(3) โ thanks for reading all of it, you are genuinely the main character here. ๐โจ๐ฆ
๐ฆ where this page comes from
- ubuntu stonking: python3-pynput-doc 1.8.2-1 ยท LGPL-3.0-or-later
- ๐ girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms