Python library for the Linux input subsystem
Python Racket
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Failed to load latest commit information.


PyInput is an API that abstracts away some of the low-level details of the Linux input subsystem. It allows read/write access to the devices /dev/input/event* and the uninput device through object streams.

An object stream is like a normal stream, except it produces objects instead of bytes or strings. This means that many of the usual Python interfaces are modified to take the type that is supposed to be read from the stream. They must implement my struct interface (see The struct Interface).

Also provided is the pile of constants, structures, and macros defined in the headers linux/input.h and linux/uinput.h. This is generated by SWIG, so it should be complete.

WARNING: There are several major bugs and lapses in functionality that currently make this module less than usable. See `issues <>`_ for a list of issues.

The struct Interface

The struct interface is implemented on all structures defined in this module and is used by the object streams.

The initializer takes the initial properties as arguments.
Returns a binary string containing the the data packed for the input subsystem. This is just a copy of the C struct as in memory.
A class method. Reverses pack(). Takes the packed C struct as a string and returns an instance.
Returns the size of the struct, or the size of the string of the string returned by pack(), or the size of the string expected by unpack(). (These are all the same value.)


This is where everything is (not just stuff related to uinput). In addition to the macros, structures, and constants, the following is available. See pydoc for full information.

Attempts to find the uinput device by checking a pre-defined list of options. You can pass in more options in others.

The object stream for reading from /dev/input/event*. It defines both stream reading methods and convenience methods for getting information about the device.

The stream interface is:

  • write(obj)
  • read(type)
  • ioctl(op, ...)
  • close()
  • flush()
  • iter(type) (Read the docs on this; the iterator has extra options)
  • The context manager interface

These are the convenience methods. Most of them use ioctl() for their data.

  • dev_id() -- Returns the input_id structure for the device
  • dev_version() -- Returns the device version as an integer
  • dev_name() -- Returns the device name as a string
  • dev_bits() -- Returns what events the device will create, as a dictionary of lists
  • dev_ranges() -- Returns the ranges of the absolute axis, as a dict

Inherits from EvdevStream, but most of the methods will probably fail. It also keeps track of the state of the device (namely if it's created).

The context manager interface is implemented somewhat unusually. It is meant to be nested. To demonstrate:

with UinputStream() as us: # Open the file, make sure it gets closed = ... # Declare the events you're using
    with us.create(): # Create the device and make sure it gets destroyed.
                      # The return value of create() isn't meant to be used outside of this.
        us.event(t, c, v) # Actually feed an event

The first with is the one for the file, managing the open/close life cycle. The inner with is for the virtual device, managing the create/destroy life cycle.

Note that UinputStream doesn't abstract away anything to do with the events themselves or the declarations. It just makes interfacing with the input subsystem easier. You still need to pass a reset event and declare the events you'll be creating.

  • create() -- Creates the device, ie call the UI_DEV_CREATE ioctl, and returns a context manager to destroy it
  • destroy() -- Destroys the device, ie call the UI_DEV_DESTROY ioctl
  • event(type, code, value) -- Creates and feeds an input_event