Skip to main content

Monitor and control user input devices

Project description

pynput

This library allows you to control and monitor input devices.

Currently, mouse and keyboard input and monitoring are supported.

See here for the full documentation.

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 {0}'.format(
    mouse.position))

# Set pointer position
mouse.position = (10, 20)
print('Now we have moved it to {0}'.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):
    print('Pointer moved to {0}'.format(
        (x, y)))

def on_click(x, y, button, pressed):
    print('{0} at {1}'.format(
        'Pressed' if pressed else 'Released',
        (x, y)))
    if not pressed:
        # Stop listener
        return False

def on_scroll(x, y, dx, dy):
    print('Scrolled {0} at {1}'.format(
        'down' if dy < 0 else 'up',
        (x, y)))

# 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.

Call pynput.mouse.Listener.stop from anywhere, raise StopException or return False from a callback to stop the listener.

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.

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.

A possible workaround is to just dispatch incoming messages to a queue, and let a separate thread handle them.

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('{0} 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.

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.

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.

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.

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.

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)

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):
    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()

# ...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.

Call pynput.keyboard.Listener.stop from anywhere, raise StopException or return False from a callback to stop the listener.

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.

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.

A possible workaround is to just dispatch incoming messages to a queue, and let a separate thread handle them.

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('{0} 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.

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.

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.

The events will be instances of the inner classes found in pynput.keyboard.Events.

Global hotkeys

A common use case for keyboard monitors is reacting to global hotkeys. Since a listener does not maintain any state, hotkeys involving multiple keys must store this state somewhere.

pynput provides the class pynput.keyboard.HotKey for this purpose. It contains two methods to update the state, designed to be easily interoperable with a keyboard listener: pynput.keyboard.HotKey.press and pynput.keyboard.HotKey.release which can be directly passed as listener callbacks.

The intended usage is as follows:

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()

This will create a hotkey, and then use a listener to update its state. Once all the specified keys are pressed simultaneously, on_activate will be invoked.

Note that keys are passed through pynput.keyboard.Listener.canonical before being passed to the HotKey instance. This is to remove any modifier state from the key events, and to normalise modifiers with more than one physical button.

The method pynput.keyboard.HotKey.parse is a convenience function to transform shortcut strings to key collections. Please see its documentation for more information.

To register a number 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()

Release Notes

v1.7.1 (2020-08-30) - Corrected release notes

  • Corrected thanks for arbitrary unicode character support for Xorg.

v1.7.0 (2020-08-30) - A new backend and many new features and bug fixes

  • Added a new uinput based keyboard backend for Linux, when no X server is availalbe.

  • Allow typing arbitrary unicode characters on Xorg backend. Thanks to gdiShun!

  • Allow overriding the automatically selected backend with an environment varaible, and added a dummy backend.

  • Added support for mouse side button on Windows. Thanks to danielkovarik!

  • Added convenience method to tap keys.

  • Allow specifying raw virtual key codes in hotkeys.

  • Improved error messages when a backend cannot be loaded.

  • Include more information in stringification of events.

  • Corrected return value of Events.get to that specified by the documentation.

  • Corrected keyboard listener not to type random characters on certain keyboard layouts.

  • Corrected errors when pressing certain keys on Windows, where the operating system reports that they are dead but no combining version exists.

  • Improved documentation.

v1.6.8 (2020-02-28) - Various fixes

  • Updated documentation.

  • Corrected lint warnings and tests.

  • Do not use internal types in argtypes for win32 functions; this renders them uncallable for other code running in the same runtime.

  • Include scan codes in events on Windows. Thanks to bhudax!

  • Correctly apply transformation to scroll event values on Windows. Thanks to DOCCA0!

v1.6.7 (2020-02-17) - Various fixes

  • Corrected infinite scrolling on macOS when providing non-integer deltas. Thanks to Iván Munsuri Ibáñez!

  • Corrected controller and listener handling of media keys on macOS. Thanks to Iván Munsuri Ibáñez!

v1.6.6 (2020-01-23) - Corrected hot key documentation

  • The code examples for the simple pynput.keyboard.HotKey now work. Thanks to jfongattw!

v1.6.5 (2020-01-08) - Corrected media key mappings

  • Corrected media key mappings on macOS. Thanks to Luis Nachtigall!

v1.6.4 (2020-01-03) - Corrected imports yet again

  • Corrected imports for keyboard Controller. Thanks to rhystedstone!

v1.6.3 (2019-12-28) - Corrected imports again

  • Corrected imports for keyboard Controller. Thanks to Matt Iversen!

v1.6.2 (2019-12-28) - Corrected imports

  • Corrected imports for keyboard Controller. Thanks to Matt Iversen!

v1.6.1 (2019-12-27) - Corrections for Windows

  • Corrected global hotkeys on Windows.

  • Corrected pressed / released state for keyboard listener on Windows. Thanks to segalion!

v1.6.0 (2019-12-11) - Global Hotkeys

  • Added support for global hotkeys.

  • Added support for streaming listener events synchronously.

v1.5.2 (2019-12-06) - Corrected media key names for Xorg

  • Removed media flag from Xorg keys.

v1.5.1 (2019-12-06) - Corrected media key names for macOS

  • Corrected attribute names for media keys on macOS. Thanks to ah3243!

v1.5.0 (2019-12-04) - Various improvements

  • Corrected keyboard listener on Windows. Thanks to akiratakasaki, segalion, SpecialCharacter!

  • Corrected handling of some special keys, including arrow keys, when combined with modifiers on Windows. Thanks to tuessetr!

  • Updated documentation to include information about DPI scaling on Windows. Thanks to david-szarka!

  • Added experimental support for media keys. Thanks to ShivamJoker, StormTersteeg!

v1.4.5 (2019-11-05) - Corrected errors on Python 3.8

  • Corrected errors about using in operator for enums on Python 3.8 on macOS.

v1.4.4 (2019-09-24) - Actually corrected keyboard listener on macOS

  • Included commit to correctly fall back on CGEventKeyboardGetUnicodeString.

  • Corrected deprecation warnings about Enum usage on Python 3.8.

v1.4.3 (2019-09-24) - Corrected keyboard listener on macOS again

  • Correctly fall back on CGEventKeyboardGetUnicodeString.

  • Updated documentation.

v1.4.2 (2019-03-22) - Corrected keyboard listener on macOS

  • Use CGEventKeyboardGetUnicodeString in macOS keyboard listener to send correct characters.

  • Include keysym instead of key code in Xorg keyboard listener.

  • Corrected logging to not include expected StopException.

  • Updated and corrected documentation.

v1.4.1 (2018-09-07) - Logging

  • Log unhandled exceptions raised by listener callbacks.

v1.4 (2018-07-03) - Event suppression

  • Added possibility to fully suppress events when listening.

  • Added support for typing some control characters.

  • Added support for mouse drag events on OSX. Thanks to jungledrum!

  • Include the key code in keyboard listener events.

  • Correctly handle the numeric key pad on Xorg with num lock active. Thanks to TheoRet!

  • Corrected handling of current thread keyboard layout on Windows. Thanks to Schmettaling!

  • Corrected stopping of listeners on Xorg.

  • Corrected import of Xlib.keysymdef.xkb on Xorg. Thanks to Glandos!

v1.3.10 (2018-02-05) - Do not crash under Xephyr

  • Do not crash when Xlib.display.Display.get_input_focus returns an integer, as it may when running under Xephyr. Thanks to Eli Skeggs!

v1.3.9 (2018-01-12) - Correctly handle the letter A on OSX

  • Corrected check for virtual key code when generating keyboard events on OSX. This fixes an issue where pressing A with shift explicitly pressed would still type a miniscule letter.

v1.3.8 (2017-12-08) - Do not crash on some keyboard layouts on OSX

  • Fall back on a different method to retrieve the keyboard layout on OSX. This helps for some keyboard layouts, such as Chinese. Thanks to haoflynet!

v1.3.7 (2017-08-23) - Xorg corrections

  • Include mouse buttons up to 30 for Xorg.

v1.3.6 (2017-08-13) - win32 corrections

  • Corrected double delivery of fake keyboard events on Windows.

  • Corrected handling of synthetic unicode keys on Windows.

v1.3.5 (2017-06-07) - Corrected dependencies again

  • Reverted changes in 1.3.3.

  • Corrected platform specifier for Python 2 on Linux.

v1.3.4 (2017-06-05) - Xorg corrections

  • Corrected bounds check for values on Xorg.

v1.3.3 (2017-06-05) - Make dependencies non-optional

  • Made platform depdendencies non-optional.

v1.3.2 (2017-05-15) - Fix for button click on Mac

  • Corrected regression from previous release where button clicks would crash the Mac mouse listener.

v1.3.1 (2017-05-12) - Fixes for unknown buttons on Linux

  • Fall back on Button.unknown for unknown mouse buttons in Xorg mouse listener.

v1.3 (2017-04-10) - Platform specific features

  • Added ability to stop event propagation on Windows. This will prevent events from reaching other applications.

  • Added ability to ignore events on Windows. This is a workaround for systems where the keyboard monitor interferes with normal keyboard events.

  • Added ability to modify events on OSX. This allows intercepting and altering input events before they reach other applications.

  • Corrected crash on OSX when some types of third party input sources are installed.

v1.2 (2017-01-06) - Improved error handling

  • Allow catching exceptions thrown from listener callbacks. This changes the API, as joining a listener now potentially raises unhandled exceptions, and unhandled exceptions will stop listeners.

  • Added support for the numeric keypad on Linux.

  • Improved documentation.

  • Thanks to jollysean and gilleswijnker for their input!

v1.1.7 (2017-01-02) - Handle middle button on Windows

  • Listen for and dispatch middle button mouse clicks on Windows.

v1.1.6 (2016-11-24) - Corrected context manager for pressing keys

  • Corrected bug in pynput.keyboard.Controller.pressed which caused it to never release the key. Many thanks to Toby Southwell!

v1.1.5 (2016-11-17) - Corrected modifier key combinations on Linux

  • Corrected handling of modifier keys to allow them to be composable on Linux.

v1.1.4 (2016-10-30) - Small bugfixes

  • Corrected error generation when GetKeyboardState fails.

  • Make sure to apply shift state to borrowed keys on X.

  • Use pylint.

v1.1.3 (2016-09-27) - Changed Xlib backend library

  • Changed Xlib library.

v1.1.2 (2016-09-26) - Added missing type for Python 2

  • Added missing LPDWORD for Python 2 on Windows.

v1.1.1 (2016-09-26) - Fixes for listeners and controllers on Windows

  • Corrected keyboard listener on Windows. Modifier keys and other keys changing the state of the keyboard are now handled correctly.

  • Corrected mouse click and release on Windows.

  • Corrected code samples.

v1.1 (2016-06-22) - Simplified usage on Linux

  • Propagate import errors raised on Linux to help troubleshoot missing Xlib module.

  • Declare python3-xlib as dependency on Linux for Python 3.

v1.0.6 (2016-04-19) - Universal wheel

  • Make sure to build a universal wheel for all python versions.

v1.0.5 (2016-04-11) - Fixes for dragging on OSX

  • Corrected dragging on OSX.

  • Added scroll speed constant for OSX to correct slow scroll speed.

v1.0.4 (2016-04-11) - Fixes for clicking and scrolling on Windows

  • Corrected name of mouse input field when sending click and scroll events.

v1.0.3 (2016-04-05) - Fixes for Python 3 on Windows

  • Corrected use of ctypes on Windows.

v1.0.2 (2016-04-03) - Fixes for thread identifiers

  • Use thread identifiers to identify threads, not Thread instances.

v1.0.1 (2016-04-03) - Fixes for Python 3

  • Corrected bugs which prevented the library from being used on Python 3.

v1.0 (2016-02-28) - Stable Release

  • Changed license to LGPL.

  • Corrected minor bugs and inconsistencies.

  • Corrected and extended documentation.

v0.6 (2016-02-08) - Keyboard Monitor

  • Added support for monitoring the keyboard.

  • Corrected wheel packaging.

  • Corrected deadlock when stopping a listener in some cases on X.

  • Corrected key code constants on Mac OSX.

  • Do not intercept events on Mac OSX.

v0.5.1 (2016-01-26) - Do not die on dead keys

  • Corrected handling of dead keys.

  • Corrected documentation.

v0.5 (2016-01-18) - Keyboard Modifiers

  • Added support for modifiers.

v0.4 (2015-12-22) - Keyboard Controller

  • Added keyboard controller.

v0.3 (2015-12-22) - Cleanup

  • Moved pynput.mouse.Controller.Button to top-level.

v0.2 (2015-10-28) - Initial Release

  • Support for controlling the mouse on Linux, Mac OSX and Windows.

  • Support for monitoring the mouse on Linux, Mac OSX and Windows.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pynput-robocorp-fork-2.0.0.tar.gz (70.4 kB view details)

Uploaded Source

Built Distributions

pynput_robocorp_fork-2.0.0-py3.7.egg (78.0 kB view details)

Uploaded Source

pynput_robocorp_fork-2.0.0-py2.py3-none-any.whl (94.0 kB view details)

Uploaded Python 2 Python 3

File details

Details for the file pynput-robocorp-fork-2.0.0.tar.gz.

File metadata

  • Download URL: pynput-robocorp-fork-2.0.0.tar.gz
  • Upload date:
  • Size: 70.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/1.13.0 pkginfo/1.5.0.1 requests/2.21.0 setuptools/45.2.0 requests-toolbelt/0.9.1 tqdm/4.30.0 CPython/3.7.5

File hashes

Hashes for pynput-robocorp-fork-2.0.0.tar.gz
Algorithm Hash digest
SHA256 3d748e8c049b647ca2b93841d835d3339e47dd9760eabacf0cf7f3d4a8effad2
MD5 1e8a2aec4d73c1fb0816077689ad284d
BLAKE2b-256 46531755f3d611e547fdaa9c27d85b040bb683a60c2db2df9f5293dcd63f4970

See more details on using hashes here.

File details

Details for the file pynput_robocorp_fork-2.0.0-py3.7.egg.

File metadata

  • Download URL: pynput_robocorp_fork-2.0.0-py3.7.egg
  • Upload date:
  • Size: 78.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/1.13.0 pkginfo/1.5.0.1 requests/2.21.0 setuptools/45.2.0 requests-toolbelt/0.9.1 tqdm/4.30.0 CPython/3.7.5

File hashes

Hashes for pynput_robocorp_fork-2.0.0-py3.7.egg
Algorithm Hash digest
SHA256 81f86ac6d743cc7345e8d287e88209ef767fafaa3015b69ac47f990263dc8f09
MD5 8f67a625fe2d714972f1b04657996132
BLAKE2b-256 77610491c4c3a8fe30474f185ba18b0dfc25258e66be8e4e109d4de146ae4307

See more details on using hashes here.

File details

Details for the file pynput_robocorp_fork-2.0.0-py2.py3-none-any.whl.

File metadata

  • Download URL: pynput_robocorp_fork-2.0.0-py2.py3-none-any.whl
  • Upload date:
  • Size: 94.0 kB
  • Tags: Python 2, Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/1.13.0 pkginfo/1.5.0.1 requests/2.21.0 setuptools/45.2.0 requests-toolbelt/0.9.1 tqdm/4.30.0 CPython/3.7.5

File hashes

Hashes for pynput_robocorp_fork-2.0.0-py2.py3-none-any.whl
Algorithm Hash digest
SHA256 f79b827c6835dddd42058c06392f0c520d5fdc95334b8c875dfc06ddd670ee8b
MD5 26265db67cfecb01832a42cc95734694
BLAKE2b-256 13ef8418a3a2ead1ac7bf6672b0c8fbc4aa3ebf1f91931303e86c38a854cf59a

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page