# OpenSD User’s Manual

## Running OpenSD

OpenSD is intended to be run as a user-level service, but it can be run from a terminal like most other Linux programs. This can be useful for troubleshooting or debugging purposes since every message is logged to stdout.

OpenSD requires access to the uinput and hidraw subsystems. To enable this access, OpenSD provides a udev rule which will be installed when installing OpenSD. In this rule, access is allowed to both subsystem for members of the opensd group, which is also created on install. Any user that intends to run OpenSD must be a member of this group, or otherwise have R/W access to these device nodes. After installing for the first time it will be necessary to log out in order for the user’s group changes to take effect.

For more information see the Troubleshooting section.

Warning | Do NOT run the OpenSD daemon as root, either directly or as a system service.

### From a terminal

    $ opensdd

Will start an instance of the daemon and log all output to the terminal. The default log level is `WARN`.

Or to see debug messages run:

    $ opensdd -l debug

A full list of command line options can be shown using:

    $ opensdd --help

### As a User-Level Service

For systemd users, a service file is provided which can be run as a user-level service that will automatically start on log-in.

To run the OpenSD daemon as a service on user log-in:

    $ systemctl --user enable opensd
    $ systemctl --user start opensd

## Configuration

OpenSD uses two types of configuration files. The first type being the Daemon Configuration, and the second type are gamepad Profiles which are loaded by the daemon.

All files use an ini-style format and are easily created or modified with any text editor.

Since OpenSD is a userspace daemon, configuration files are stored in `$XDG_CONFIG_HOME/opensd/` which, on most systems, will be `~/.config/opensd/`. Gamepad profiles are stored in the `profile` subdirectory, (example: `~/.config/opensd/profiles/`). If the OpenSD user config directory does not exist, a new one will be created and populated with the default configuration files when the daemon is run.

Note | OpenSD follows the XDG specification, so environments which set / change `$XDG_HOME` or `$XDG_CONFIG_HOME` should behave correctly. For the purposes of this documentation we’ll refer to the default XDG paths for user configuration files (example: `~/.config/opensd/`).

Basic format rules:

- Parsing is line-based and space delimited.

- The files are broken into braced enclosed sections and keys.

- Names of sections and keys are not case-sensitive, but values can be, such as file names.

- Sections are enclosed in square brackets (example: `[SectionName]`)

- Keys must be contained within a section.

- Key assignment must be separated by whitespace. (example: `key = value1 value2 value3`)

- Comments are preceeded by a `#` or `;` at the beginning of the line.

- Placing a value in quotes `"` treats the value as a literal string which allows whitespace. (example: `key = "A string with spaces"`)

## Daemon Configuration File (config.ini)

This single file contains a small group of options that pertain to the daemon itself. The default configuration file for the daemon can be found at `~/.config/opensd/config.ini`. An unmodified copy of this file will be installed to `/usr/local/share/opensd/config/config.ini` or `/usr/share/opensd/config/config.ini`.

An example config.ini can be found in this documentation if you want to see what a complete file might look like.

### [Daemon] Section

Note | This section is required.

#### Profile

This tells the daemon which profile to load when it starts up. Profiles are only loaded from the `~./config/opensd/profiles/` directory, so only specify the filename here. OpenSD also has other methods for loading profiles once the daemon is running, this setting is only for the default profile you wish to use.

Format:

    Profile = <filename>

Example:

    [Daemon]
    Profile = default.profile

#### AllowClients

Note | This feature is not yet fully implemented.

This setting enables or disables the use of the CLI and GUI utilities which connect to the daemon. If set to false, the daemon will not listen for clients. This can be useful if you want to "lock down" a configuration so it cannot be changed while it is running. The default is `true`.

Format:

    AllowClients = <true | false>

Example:

    [Daemon]
    AllowClients = true

## Profile Configuration Files (*.profile)

These files are used to configure the gamepad driver features and bindings. A default profile is configured in the config.ini file to be loaded at startup, but you can also switch between them at any time while the daemon is running using any of several possible methods.

Gamepad profiles can be found in `~/.config/opensd/profiles/`. The file extension is `*.profile`.

An example profile can be found in this documentation if you want to see what a complete file might look like.

A default profile (cleverly named `default.profile`) is provided which includes documentation in the comments on how to configure it. It is not recommended to modify this file, instead you should make a copy of it, renaming it to `whatever_you_want.profile` and edit that file instead. If the default profile is deleted, it will be recreated when the daemon is run, so if you need a clean or updated copy of the `default.profile`, simply delete it and restart the OpenSD daemon.

An unmodified copy of this file will be installed to `/usr/local/share/opensd/profiles/default.profile` or `/usr/share/opensd/profiles/default.profile`.

### [Profile] Section

#### Name

The profile name as it will appear in the GUI and through the CLI query. Should be unique for each profile to avoid confusion.

Format:

    Name = <profile_name>

- `profile_name`: Any unique name. Should be enclosed in quotes "" to preserve spaces.

Example:

    [Profile]
    Name = "My favourite gamepad profile"

Note | Prior to version 0.47, quoted literal strings were not supported. It’s recommended, but not necessary to update old profiles to put this value in quotes.

#### Description

A breif description of the profile for use in the GUI and CLI query. Does not affect anything else, just intended as a hint for users.

Format:

    Description = <description>

- `description`: A brief, helpful description of what your profile does. Should be enclosed in quotes "" to preserve spaces.

Example:

    [Profile]
    Description = "Just a profile I use for most applications."

Note | Prior to version 0.47, quoted literal strings were not supported. It’s recommended, but not necessary to update old profiles to put this value in quotes.

### [Features] Section

#### ForceFeedback

Enable or disables haptic / force-feedback events for the gamepad device. It’s worth mentioning that only the `Gamepad` device can receive force-feedback events; the `Motion` or `Mouse` devices will not receive these events.

Format:

    ForceFeedback = <true | false>

Example:

    [Features]
    ForceFeedback = true

If unspecified, this value defaults to `false`.

Note | This feature is not yet fully implemented

#### MotionDevice

If this is set to `true`, an additional input device will be created which will report motion control data. Motion axes need to have thier ranges and bindings defined. If this is disabled, any `Motion` device bindings will be ignored.

Format:

    MotionDevice = <true | false>

Example:

    [Features]
    MotionDevice = true

If unspecified, this value defaults to `false`.

Note | While it’s possible to combine gamepad and motion input into a single input device, Linux kernel and uinput specifications state that motion control devices should be separate from other gamepad / joystick input. Not separating these can also make it difficult to configure controls in most applications.

#### MouseDevice

If this is set to `true`, an additional input device will be created which will be used to send mouse / trackpad events. Mouse events still need to have thier bindings defined. If this is disabled, any `Mouse` device bindings will be ignored.

Format:

    MouseDevice = <true | false>

Example:

    [Features]
    MouseDevice = true

If unspecified, this value defaults to `true`.

#### LizardMode

The Steam Controller and the Steam Deck both have a kind of fallback "BIOS" mode which emulates some keyboard and mouse input using the gamepad. Valve refers to this as "Lizard Mode". This mode cannot be redefined. It sends events IN ADDITION to the gamepad events created by the OpenSD driver, so it should always be disabled. If you would like mouse or keyboard emulation, they should be configured with bindings. When OpenSD exits, Lizard Mode is re-enabled.

If this is set to `false` "Lizard Mode" will be disabled (recommended).

Format:

    LizardMode = <true | false>

Example:

    [Features]
    LizardMode = false

If unspecified, this value defaults to `false`.

#### StickFiltering

The thumbsticks on the Steam Deck have a circular range but return square-ish data, which makes it feel odd and complicated to apply radial deadzones to. Because of this, OpenSD vectorizes the stick position and returns "cleaner", round stick ranges, as well as being able to create clean deadzone rescaling. If you disable this setting, axis ranges are still internally normalized and rescaled to the the uinput device, but no vectorization will be applied and any deadzones will be ignored.

If set to `true` thumbsticks will be filtered (recommended).

Format:

    StickFiltering  = <true | false>

Example:

    [Features]
    StickFiltering  = true

If unspecified this value defaults to `true`.

Note | This must be enabled for thumbstick deadzones to work.

#### TrackpadFiltering

Similar to StickFiltering, but matches the square shape of the trackpad. Filtering is only applied to absolute values. This setting must be enabled to apply deadzones to the trackpad absolute axes. Relative values (`*PadRelX` and `*PadRelY`) are unaffected, therefore deadzones do not affect mouse movement with the pads.

If set to `true` trackpads will be filtered (recommended).

Format:

    TrackpadFiltering  = <true | false>

Example:

    [Features]
    TrackpadFiltering  = true

If unspecified, this value defaults to `true`.

Note | This must be enabled for trackpad deadzones to work.

### [DeviceInfo] Section

This section is used to optionally configure the USB identification of each device OpenSD creates. While OpenSD has its own defaults, they can be overridden to make these devices appear as a different hardware. This can be useful when some very poorly written games only look for / support specific gamepads, rather than a universal API. Shame. Often, these games filter out all input devices which don’t match the device name string and/or the USB VID:PID. These settings enable the gamepad to mimic the appearance of a device which the software does recognise.

Format:

    <device>    = <vid> <pid> <ver> <name>

- `device`: Any OpenSD input device: `Gamepad`, `Motion`, or `Mouse`.

- `vid`: The USB device VendorID to use. Format must be in hexidecimal.

- `pid`: The USB device ProductID to use. Format must be in hexidecimal.

- `ver`: The USB device version to use. Format must be in hexidecimal.

- `name`: The USB device name string to use. Should be enclosed in quotes "" if it contains any whitespace characters.

Example:

    [DeviceInfo]
    Gamepad     = 0xDEAD 0xBEEF 0x0100 "OpenSD Gamepad Device"
    Motion      = 0xDEAD 0xD00D 0x0100 "OpenSD Motion Control Device"
    Mouse       = 0xDEAD 0xF00D 0x0100 "OpenSD Mouse / Trackpad Device"

Note | Some software may also perform gamepad detection based on button and axis configuration. Axis settings can also be configured in the [GamepadAxes] Section and [MotionAxes] Section for this very purpose.

### [Deadzones] Section

These values are double precision floating point and represent the percentage of the total axis range to ignore. A value of 0.05 would be a 5% deadzone. Deadzones are capped at 0.9 (90%). A value of 0 is considered disabled. If StickFiltering is disabled, `LStick` and `RStick` deadzones will be ignored. If TrackpadFiltering is disabled, `LPad` and `RPad` deadzones will be ignored.

Format:

    <axis>      = <value>

- `axis`: Any of the supported gamepad axes, which are: * `LStick`, `RStick`, `LPad`, `RPad`, `LTrigg` and `RTrigg`.

- `value`: A double-precision floating point value between 0 and 0.9.

Example:

    [Deadzones]
    LStick      = 0.1
    RStick      = 0.1
    LPad        = 0
    RPad        = 0
    LTrigg      = 0
    RTrigg      = 0

Any undefined axis deadzone will default to `0` (disabled).

Note | Because the Steam Deck thumbsticks tend not to return to center completely (at least on current revisions), a small deadzone of around 0.10 (10%) is generally recommended.

### [GamepadAxes] Section

Gamepad absolute axes must have a defined range or they will not be created. Any `Gamepad` `ABS_*` events which are configured in the Gamepad Bindings section must be defined here first, or they will be ignored.

Internally, the axis values are normalized and rescaled between the actual hardware and the value seen by applications, so no clipping or "dead extremes" will occur. There is no "right" or "wrong" value here that you need to know, but it may be useful to precisely emulate other hardware so it can be detected as such by certain applications which try to guess what kind of device you have.

The Steam Deck hardware uses signed 16-bit integers (-32767 to 32767) for its thumbstick, trackpad, trigger and motion axes, so there’s no reason to use a larger or smaller range for those inputs, unless you are trying to emulate a specific device.

Hat-type axes (`ABS_HAT*`) should typically use a range of `-1` to `1` because of thier historical purpose, but this is not strictly enforced.

Triggers should typically have minumum value of `0` so that they rest at zero when released.

Format:

    <abs_event>     = <min> <max> [fuzz] [res]

- `abs_event`: Any absolute axis event code you wish to bind. Absolute event codes begin with `ABS_`. A full list of input event codes can be found at linux/input-event-codes.h from the Linux kernel.

- `min`: A value representing the minimum range of the axis. This is a signed 32-bit integer.

- `max`: A value representing the maximum range of the axis. This is a signed 32-bit integer.

- `fuzz`: Optional value representing the fuzziness of the axis values. This is a signed 32-bit integer.

- `res`: Optional value representing the resolution of the axis in units/mm (units/radian for rotational axes). This is a signed 32-bit integer.

Example:

    [GamepadAxes]
    ABS_HAT0X       = -1        1
    ABS_HAT0Y       = -1        1
    ABS_X           = -32767    32767
    ABS_Y           = -32767    32767
    ABS_RX          = -32767    32767
    ABS_RY          = -32767    32767
    ABS_Z           = 0         32767
    ABS_RZ          = 0         32767

### [MotionAxes] Section

Motion control absolute axes, as with the gamepad device, must have a defined range or they will not be created. Any `Motion` `ABS_*` events which are configured in the Motion Bindings must be defined here first, or they will be ignored.

Internally, the axis values are normalized and rescaled between the actual hardware and the value seen by applications, so no clipping or "dead extremes" will occur. There is no "right" or "wrong" value here that you need to know, but it may be useful to precisely emulate other hardware so it can be detected as such by certain applications which try to guess what kind of device you have.

The Steam Deck hardware uses signed 16-bit integers (-32767 to 32767) for its thumbstick, trackpad, trigger and motion axes, so there’s no reason to use a larger or smaller range for those inputs, unless you are trying to emulate a specific device.

Format:

    <abs_event>     = <min>     <max>

- `abs_event`: Any absolute axis event code you wish to bind. Absolute event codes begin with `ABS_`. A full list of input event codes can be found at linux/input-event-codes.h from the Linux kernel.

- `min`: An integer representing the minimum range of the axis. This is a signed 32-bit integer.

- `max`: An integer representing the maximum range of the axis. This is a signed 32-bit integer.

Example:

    [MotionAxes]
    ABS_X           = -32767    32767
    ABS_Y           = -32767    32767
    ABS_Z           = -32767    32767
    ABS_RX          = -32767    32767
    ABS_RY          = -32767    32767
    ABS_RZ          = -32767    32767

Note | Motion controls are not yet fully implemented.

### [Touchpads] Section

#### Touchpad Sensitivity

When the touchpad is used for relative axes, the sensitivity of the X and Y axes can be adjusted for each pad. This axis movement is multiplied by the specified value, so values less than 1.0 will result in a slower rate of movement. A value of 1.0 represents 100% of default sensitvity. A value of 0.5 would be 50% slower than the default.

While it is possible to set the scale of individual relative axes for each binding, that method has low precision due to the nature of integer math. Adjusting the pad sensitivity here will probably give you much finer-grain control. The two methods can also be combined, with the REL_ axis scale being calulated after the pad sensitivity.

Format:

    pad_sens = <x_sens> <y_sens>

- `pad_sens`: Left or right pad sensitivity. Can be `LPadSensitivity` or `RPadSensitivity`.

- `x_sens`: A floating point value representing the sensitivity of the X axis.

- `y_sens`: A floating point value representing the sensitivity of the Y axis.

Example:

    [Touchpads]
    LPadSensitivity     = 1.0       1.0
    RPadSensitivity     = 1.0       1.0

#### Touchpad Inertia Decay

When used as relative axes, the touchpad motion vectors have intertia. This intertia decays each USB frame until it becomes zero. These settings allow you to configure the rate of inertial decay. The gamepad USB device polls at fixed(?) 250Hz so it can fall off rather quickly even with very small values.

A value of 0 means no decay (frictionless). A value of 1.0 will effectively disable inertia. When using a trackpad as a pointer device, a value of 0.05 (5% decay per frame) is recommended. Values are clamped from 0 to 1.0.

Format:

    pad_decay = <x_decay> <y_decay>

- `pad_decay`: Left or right pad inertia decay. Can be `LPadDecay` or `RPadDecay`.

- `x_decay`: A floating point value between 0 and 1.0 representing the inertial decay of the X axis.

- `y_decay`: A floating point value between 0 and 1.0 representing the inertial decay of the Y axis.

Example:

    [Touchpads]
    LPadDecay       = 0.05      0.05
    RPadDecay       = 0.05      0.05

### [Bindings] Section

This should be a list of all the physical gamepad buttons/sticks/pads/motion inputs you want to bind to a virtual input event or command. Anything not specified here will be considered "unbound" and not emit any event.

There are currently four basic binding types: device bindings, `Command` bindings, `Profile` bindings and `None`.

Device bindings

  Represent input events which are generated by pressing buttons, keys, moving the mouse, thumbsticks, motion control, etc. Event bindings are tied to specific input devices, which include `Gamepad`, `Motion` and `Mouse`. Applications read events from these different device types in different ways so they should generally be separated.

`Command` bindings

  Executes a given command inside a shell environment.

`Profile` bindings

  Used to switch to a different profile when triggered.

`None`

  This is used to indicate that a particular input has no binding. (default)

Input binding names which this document will refer to as `input` or <input>, are represent physical buttons, triggers, axes, etc. on the physical gamepad portion of the Steam Deck. They can be broken down into a several categories for simplicity:

Directional Pad

  `DPad{Up|Down|Left|Right}`

Buttons

  `A` `B` `X` `Y` `L1` `L2` `L3` `L4` `L5` `R1` `R2` `R3` `R4` `R5` `Menu` `Options` `Steam` `QuickAccess`

Triggers

  `{L|R}Trigg`

Thumbsticks

  `{L|R}Stick{Up|Down|Left|Right|Touch|Force}`

Trackpads

  `{L|R}Pad{Up|Down|Left|Right|RelX|RelY|Touch|Press|Force}`

Accelerometers

  `Accel{X|Y}{Plus|Minus}`

Attitude / gyros

  `{Roll|Pitch|Yaw}{Plus|Minus}`

Input names prefixed with `L` or `R` indicate left and right controls (example: `LStickLeft` vs `RStickLeft`)

Additionally, trackpads are mapped out into several button layouts simultaneously. This means that when pressed, specific areas of the trackpad behave like individual buttons. There are several "maps" which can be used non-exclusively. These are

Quadrant button maps

  `{L|R}PadPressQuad{Up|Down|Left|Right}`

Orthogonal button maps

  `{L|R}PadPressOrth{Up|Down|Left|Right}`

2x2 grid maps

  `{L|R}PadPressGrid2x2_{1|2|3|4}`

3x3 grid maps

  `{L|R}PadPressGrid3x3_{1|2|3|4|5|6|7|8|9}`

A full list of available input codes can be seen in the example profile section, as well as in `default.profile` file from your installation.

A detailed explanation of each of these inputs can be found in the Input Types section.

#### Gamepad Bindings

The `Gamepad` device binding is used to generate input events for a joystick / gamepad-type device. This generally means buttons (`BTN_*`) and absolute axis (`ABS_*`) events. `KEY_*` events are allowed, but many programs will not read `KEY_*` events from a joystick device, instead try binding key events to the `Mouse` device.

The syntax for bindings differs slightly depending on the event type. Absolute axis (`EV_ABS`) events are prefixed with `ABS_` and key / button events (`EV_KEY`) are prefixed with `KEY_` and `BTN_` respectively. OpenSD supports most event codes. For a full list of event codes, see linux/input-event-codes.h from the Linux kernel.

When bound to a button-type input (example: the `A` button), the bind is triggered when the button is pressed. When bound to an axis-type input (example: `LStickUp`), the event is emitted when the axis is in a non-zero position and leaves the deadzone (if any).

For KEY / BTN events:

Format:

    input = Gamepad <event_code>

- `input`: Any one of the input binding names.

- `event_code`: Any EV_KEY type event. These events are prefixed with `BTN_` or `KEY_`. (example: `BTN_START` or `KEY_ESCAPE`)

Example:

    [Bindings]
    Menu = Gamepad BTN_START

For ABS events:

Format:

    input = Gamepad <event_code> <direction>

- `input`: Any one of the input binding names.

- `event_code`: Any `EV_ABS` type event. These events are prefixed with `ABS_`. (example: `ABS_X`)

- `direction`: Indicates the direction that the axis is moved in. Values may be `+` or `-`. For centered axes, like thubsticks, `-` represents moving the axis up or left, and `+` represents moving the axis down or right. For ramped axes, like triggers and pressure sensors, `+` represents applying pressure.

When binding a button-type input like a DPad direction or, say, the `B` button to an ABS event, the button will push the axis to its maximum extent in the given direction. When binding an analog axis, like a thumbstick, to an ABS value, the range of motion is mapped to the axis value in the given direction.

Examples:

    [Bindings]
    # Button mapped to an axis
    DPadUp          = Gamepad   ABS_HAT0Y   -

    # Analogue stick mapped to an axis
    RStickUp        = Gamepad   ABS_Y       -
    RStickDown      = Gamepad   ABS_Y       +

    # Analogue trigger mapped to an axis
    LTrigg          = Gamepad   ABS_Z       +

A full list of gamepad input names can be seen in the example profile.

A detailed explanation of inputs can be found in the Input Types section of this documentation.

Note | ABS events must have a defined range in the [GamepadAxes] Section

#### Motion Bindings

The `Motion` device binding is used to generate input events for a motion control-type device. While OpenSD does not strictly enforce this, the Linux kernel and uinput specify that motion control events should be emitted by separate devices. Not doing so can create a lot of "noise", especially when configuring controls within another application. As per this spec, the `Motion` device only supports `EV_ABS` type events. These events are prefixed with `ABS_` (example: `ABS_Z`). For a full list of event codes, see linux/input-event-codes.h from the Linux kernel.

The syntax and behaviour for binding `Motion` device events is the same as binding ABS events with the `Gamepad` device in the previous section.

Also, the `Motion` device is a completely separate context and namespace from the `Gamepad` and `Mouse` devices, much in the same way that two players with identical controllers will have the same buttons, but very different meanings to the game. For example, pressing `A` on controller #1 does not affect player #2. Its up the the end-user’s software to decide the the context and meaning of the individual events.

Format:

    input = Motion <event_code> <direction>

- `input`: Any one of the input binding names.

- `event_code`: Any `EV_ABS` type event. These events are prefixed with `ABS_`. (example: `ABS_X`)

- `direction`: Indicates the direction that the axis is moved in. Values may be `+` or `-`.

Examples:

    [Bindings]
    # Bind roll attitude to Motion device
    RollPlus        = Motion    ABS_X       +
    RollMinus       = Motion    ABS_X       -

A full list of motion contol input names can be seen in the example profile.

A detailed explanation of motion input be found in the Input Types Section of this document.

Note | ABS events must have a defined range in the [MotionAxes] Section

Note | This feature is not yet fully implemented.

#### Mouse Bindings

The `Mouse` device binding is used to generate input events which will be interpreted as events coming from a pointer-type device such as a physical mouse. This binding type supports button / key and relative axis events. The `Mouse` device can also function a bit like a keyboard, so it’s advised to bind any key events to this device.

The syntax for bindings differs slightly depending on the event type. Relative axis (`EV_REL`) events are prefixed with `REL_` and key / button events (`EV_KEY`) are prefixed with `KEY_` and `BTN_` respectively. OpenSD supports most event codes. For a full list of event codes, see linux/input-event-codes.h from the Linux kernel.

For KEY / BTN events:

    input = Mouse <event_code>

- `input`: Any one of the input binding names.

- `event_code`: Any EV_KEY type event. These events are prefixed with `BTN_` or `KEY_`. (example: `BTN_LEFT` or `KEY_ESCAPE`)

Example:

    [Bindings]
    RPadPress       = Mouse BTN_LEFT
    QuickAccess     = Mouse BTN_RIGHT

For REL events:

    [Bindings]
    RPadRelX        = Mouse REL_X
    RPadRelY        = Mouse REL_Y

- `input`: Any one of the input binding names.

- `event_code`: Any `EV_REL` type event. These events are prefixed with `REL_`. (example: `REL_X`)

Please see the Trackpad input type section of this documentation for a better explanation of how `{L|R}PadRel{X|Y}` relative inputs work.

#### Command Bindings

The `Command` binding allows you to execute external programs or scripts by forking them off as a child process. These processes run concurrently, do not return any usable exit code, and will not interrupt the driver.

Format:

    input = Command <wait_for_exit> <repeat_delay_ms> <command_to_execute>

- `input`: Any one of the input binding names. Best suited to button-types.

- `wait_for_exit`: a `true` or `false` value which specifies if the command should complete before the binding can be triggered again.

- `repeat_delay_ms`: The amount of time in milliseconds that must elapse before the binding can be triggered again. The timer starts when the binding is successfully triggered.

- `command_to_execute`: The name of the command / script you want to run, same as you would from a terminal. The command executes normally inside a shell, so variable expansion should work. Arguments may be specfied by placing them after the command as usual.

Example:

    [Bindings]
    QuickAccess     = Command   true    0   rofi -show run

#### Profile Bindings

The `Profile` binding type allows you to switch to a different profile using just the gamepad input. Profiles are loaded from the user profile directory. There is a 2 second delay after profile switching before the profile can be changed again, to prevent undesirable rapid cycling. If a profile fails to load, the process will be aborted and the profile currently in use will remain so.

Format:

    input = Profile <profile_name>

- `input`: Any one of the input binding names. Best suited to button-types.

- `profile_name`: Filename of the profile ini you want to load. Path is fixed to the user profile directory, so only specify the filename itself.

Example:

    [Bindings]
    L5      = Profile   left_hand_mouse.profile

## Input Types

As briefly described in the Bindings section, the gamepad has multiple input components which can be categorized by their interface, but also by a primitive type. For example, the thumbsticks on the Steam Deck have a pair of X / Y axes (example: `LStickUp`, `LStickLeft`), which, as a primitive type are absolute, but the thumbsticks also have a touch sensor at the top which can be read as a binary button primitive (`LStickTouch`) as well as a pressure level (`LStickForce`) which is read as a single absolute axis like a trigger would be.

The intent is for each input name to be as simple and intuitive as possible, but that’s always going to be pretty subjective. This section intends to provide a painfully detailed explanation for every individual input that can have a binding ; )

### Directional Pad

The directional pad is just a set of four buttons which are diametrically exclusive — you can press up and left simultaneously but you cannot press left and right simultaneously.

Naming Convention

  - `DPad{Up|Down|Left|Right}`

Descriptions

  - `DPadUp`: The top button on the directional pad.

  - `DPadDown`: The botton button on the directional pad.

  - `DPadLeft`: The left button on the directional pad.

  - `DPadRight`: The right button on the directional pad.

Use

  While you can bind them to nearly anything, these buttons are usually bound to pair of Hat axes, which are typically axes with a range of -1 to 1 and 0 when resting / released.

  - Button bindings to `KEY_` and `BTN_` events work directly as you might expect.

  - Buttons bound to `ABS_` events emit the axis limit in the given direction.

A common configuration, as seen in the example profile, might look like this:

    [Bindings]
    DpadUp              = Gamepad   ABS_HAT0Y   -
    DpadDown            = Gamepad   ABS_HAT0Y   +
    DpadLeft            = Gamepad   ABS_HAT0X   -
    DpadRight           = Gamepad   ABS_HAT0X   +

### Buttons

These are pretty straightforward. As you probably expect, buttons have two states. They’re true when pressed and false when released. The Steam Deck borrows common names for most buttons, but also adds a few of it’s own. It’s debatable how to organize or classify these, so I’ll just sorta go by the legacy naming standards.

Naming conventions

  - `A` `B` `X` `Y` `{L|R}{1|2|3|4|5}` `Menu` `Options` `Steam` `QuickAccess`

Descriptions

  - `A`: Same as it appears on the front of the Steam Deck.

  - `B`: Same as it appears on the front of the Steam Deck.

  - `X`: Same as it appears on the front of the Steam Deck.

  - `Y`: Same as it appears on the front of the Steam Deck.

  - `L1`: The top left bumper / shoulder button.

  - `R1`: The top right bumper / shoulder button.

  - `L2`: Button nested inside the pressure sensor of the left trigger.

  - `R2`: Button nested inside the pressure sensor of the right trigger.

  - `L3`: Button nested at the bottom of the left stick. Activated by pressing down until it clicks.

  - `R3`: Button nested at the bottom of the right stick. Activated by pressing down until it clicks.

  - `L4`: Upper paddle button located on the back-left side of the Steam Deck.

  - `R4`: Upper paddle button located on the back-right side of the Steam Deck.

  - `L5`: Lower paddle button located on the back-left side of the Steam Deck.

  - `R5`: Lower paddle button located on the back-right side of the Steam Deck.

  - `Menu`: Raised hamburger button (☰) located above the *right *thumbstick.

  - `Options`: Raised overlapped rectangle button (⮻) located above the left thumbstick.

  - `Steam`: Flat button of the same name (STEAM), located below the left trackpad.

  - `QuickAccess`: Flat button with three interpuncts (···), located below the right trackpad.

Use

  Binding buttons is simple.

  - Button bindings to `KEY_` and `BTN_` events work directly.

  - Buttons bound to `ABS_` events emit the axis limit in the given direction. For example, if you create a binding like `A = ABS_X +`, then when you press the `A` button, it will emit an `ABS_X` event for whatever the maximum axis limit for `ABS_X` is, whereas `A = ABS_X -` will emit the minimum axis limit.

  - `A`/`B`/`X`/`Y` have respective input codes for `Gamepad` devices: `BTN_SOUTH`, `BTN_EAST`, `BTN_WEST` and `BTN_NORTH`.

  - `{L|R}{1|2}` have respective input codes for `Gamepad` devices: `BTN_TL` `BTN_TL2` `BTN_TR` and `BTN_TR2`.

  - `{L|R}3` have respective input codes for `Gamepad` devices: `BTN_THUMBL` and `BTN_THUMBR`

  - `Menu` has a respective (based on location and common use) input code for `Gamepad` devices: `BTN_START`.

  - `Options` has a respective (based on location and common use) input code for `Gamepad` devices: `BTN_SELECT`.

  - `Steam` is probably closest to a PS or HOME button on a `Gamepad` device; possibly use `BTN_MODE`.

### Thumbsticks

The thumbsticks on the Steam Deck are associated with six different inputs in OpenSD. As you would expect, there is an X/Y axis pair for each stick, but there are also touch and pressure (well, sorta) sensors located on the top of each one. The directional axes are broken into halves such that each direction can emit different events if desired.

Axis values from thumbsticks are normalized internally so they can be rescaled to the defined ABS event ranges. The hardware returns signed 16-bit integer values for axis values in the HID reports. The "pressure sensor" component has a very short numerical range, but is quite sensitive.

If Stick Filtering is enabled the full axis is internally normalized as a unit vector and a radial deadzone may be applied.

Naming convention

  - `{L|R}Stick{Up|Down|Left|Right|Touch|Force}`

Descriptions

  - `LStickUp`: Represents the top half of the Y-axis of the left thumbstick.

  - `LStickDown`: Represents the bottom half of the Y-axis of the left thumbstick.

  - `LStickLeft`: Represents the left half of the X-axis of the left thumbstick.

  - `LStickRight`: Represents the right half of the X-axis of the left thumbstick.

  - `LStickTouch`: This is a binary button that return true when the top of the left thumbstick is touched.

  - `LStickForce`: Capacitive touch sensor at the top of the left thumbstick. It is very sensitive and can register if your hand is near, without actually touching it. At a hardware level, the sensitivity ranges from 0 to ~112, which is an odd number. This value is returned as an normalized axis (0 to 1.0), just like a trigger.

  - `RStickUp`: Represents the top half of the Y axis of the right thumbstick.

  - `RStickDown`: Represents the bottom half of the Y axis of the right thumbstick.

  - `RStickLeft`: Represents the left half of the X axis of the right thumbstick.

  - `RStickRight`: Represents the right half of the X axis of the right thumbstick.

  - `RStickTouch`: This is a binary button that return true when the top of the right thumbstick is touched.

  - `RStickForce`: Capacitive touch sensor at the top of the right thumbstick. It is very sensitive and can register if your hand is near, without actually touching it. At a hardware level, the sensitivity ranges from 0 to ~112, which is an odd number. This value is returned as an normalized axis (0 to 1.0), just like a trigger.

Use

  Directional inputs are treated like axis halves. You typically want to map `Up` and `Down` onto the same ABS event code, but in opposite directions. Doing so will perfectly map the full range of motion to an event code. An example of this, as demonstrated in the [Bindings] section of the example profile:

    # Left Stick
    LStickUp            = Gamepad   ABS_Y       -
    LStickDown          = Gamepad   ABS_Y       +
    LStickLeft          = Gamepad   ABS_X       -
    LStickRight         = Gamepad   ABS_X       +
    # Right Stick
    RStickUp            = Gamepad   ABS_RY      -
    RStickDown          = Gamepad   ABS_RY      +
    RStickLeft          = Gamepad   ABS_RX      -
    RStickRight         = Gamepad   ABS_RX      +

You’re also able to treat each axis half like a button if you bind it to a key or button event code, in which case it will trigger the binding when the stick leaves the center / deadzone. You can use the deadzone in this case to determine how far the stick must be pushed from center before the binding is triggered.

- `LStickLeft` & `LStickRight` are typically bound to the `ABS_X` event code on `Gamepad` devices.

- `LStickUp` & `LStickDown` are typically bound to the `ABS_Y` event code on `Gamepad` devices.

- `RStickLeft` & `RStickRight` are typically bound to the `ABS_RX` event code on `Gamepad` devices.

- `RStickUp` & `RStickDown` are typically bound to the `ABS_RY` event code on `Gamepad` devices.

- Use `LStickTouch` / `RStickTouch` to detect if a players hands are on the controls.

- Use `LStickForce` / `RStickForce` if you want to write a tiny electric theremin simulator? If this sensor is bound to an absolute axis, a range of 0 to 100 is recommened.

### Triggers

Triggers are pressure sensors that are also treated a bit like a thumbstick’s half-axis, with the difference being there’s no complement half. Triggers have a resting position of the defined axis minimum limit and move toward the maximum limit when actuated. Typically the minimum limit is zero, so the axis does not return non-zero values when released / resting, but you can do any weird thing you want.

Axis values from triggers are normalized internally so they can be rescaled to the defined ABS event ranges. Internally, the HID reports return trigger values as unsigned 16-bit integers.

Triggers also have a binary button component: `L2` and `R2`. Information about these buttons can be found in the Buttons section.

Linear deadzones can be applied to triggers, if desired in the Deadzones Section of a profile.

Naming convention

  - `{L|R}Trigg`

Descriptions

  - `LTrigg`: Represents a pressure sensor value for the left trigger on the top-rear of the device.

  - `RTrigg`: Represents a pressure sensor value for the right trigger on the top-rear of the device.

Use

  These inputs are absolute axes and can be mapped to ABS event codes as well as KEY / BTN event codes. One possible reason to use the axis itself as a button-type binding would be to use `L2` / `R2` buttons on partial actuation, and use a deadzone to emit another event code on full actuation.

  - `LTrigg` is typically bound to `ABS_Z`.

  - `RTrigg` is typically bound to `ABS_RZ`.

### Trackpads

At the core, trackpads are absolute axis devices have with an X / Y pair, as well as a pressure sensor Z-axis and a slightly tactile button. A number of inputs can be extrapolated from the data those basic types provide. That includes touch sensors, press / button sensors, pressure / force sensors, absolute coordinates, relative movement tracking as well as the ability to map out regions of the pad and treat them as individual buttons. OpenSD trackpads have the most input bindings out of all the components.

As with the Thumbsticks, directional axes are broken into halves such that each direction can emit different events if desired. These halves can be mapped on to a whole ABS event code, or use separately.

Trackpads support radial deadzones for absolute axis inputs, and can be configured in the Deadzones Section of a profile.

Relative trackpad input, such as `LPadRelX` or `LPadRelY`, are not affected by deadzones and return data suitable for pointing devices like mice. These return the difference in positional movement calculated between HID frames. Some filtering is always applied to this process to reduce jitter and a small amount of intertia is also applied. The typical value range returned by these inputs is usually between -5 and +5. Binding `RelX` and `*RelY` inputs to anything other than `REL_` event codes on the `Mouse` device is probably not useful.

Touchpads are non-multitouch devices so they only relay a single X / Y coordinate pair. I’ve read that, at a hardware level, they are supposedly multi-touch capable, but I don’t have any information on reading that data yet. If true, it will probably be supported in a future version.

OpenSD provides multiple "button maps", any of which can be used non-exclusively with each other. These "button maps" break the full area of the trackpad into logical sections which, when pressed (as opposed to being merely touched) act as individual buttons. If so desired, trackpads can be used to create "button clusters", which can be used to emulate a Directional Pad, arrow keys, run scripts, launch applications, etc. For the sake of readability, button maps are described separately below the main input descriptions.

Naming convention

  - `{L|R}Pad{Up|Down|Left|Right|Touch|Press|Force|RelX|RelY}`

  - `{L|R}PadPressQuad{Up|Down|Left|Right}`

  - `{L|R}PadPressOrth{Up|Down|Left|Right}`

  - `{L|R}PadPressGrid2x2_{1|2|3|4}`

  - `{L|R}PadPressGrid3x3_{1|2|3|4|5|6|7|8|9}`

Descriptions

  - `LPadUp`: Represents the top half of the Y-axis of the left trackpad.

  - `LPadDown`: Represents the bottom half of the Y-axis of the left trackpad.

  - `LPadLeft`: Represents the left half of the X-axis of the left trackpad.

  - `LPadRight`: Represents the right half of the X-axis of the left trackpad.

  - `LPadTouch`: This is a button sensor which detects if the left pad is being touched. Quite sensitive.

  - `LPadPress`: This is also a button which detects if the left pad is being pressed down like a button. Actuation has a slight tactile bump.

  - `LPadForce`: This is a pressure sensor which returns a normalized value of how much force is being used to press down on the left trackpad. This is an absolute axis value and behaves the same as Triggers.

  - `LPadRelX`: This is a derived relative axis value that measures the amount of relative X-axis movement between update frames of the left trackpad. This represents the same kind of input data that mice use. This input is unaffected by deadzones. Typical values returned fall inside the range of -5 to +5.

  - `LPadRelY`: This is a derived relative axis value that measures the amount of relative Y-axis movement between update frames of the left trackpad. This represents the same kind of input data that mice use. This input is unaffected by deadzones. Typical values returned fall inside the range of -5 to +5.

  - `RPadUp`: Represents the top half of the Y-axis of the right trackpad.

  - `RPadDown`: Represents the bottom half of the Y-axis of the right trackpad.

  - `RPadLeft`: Represents the left half of the X-axis of the right trackpad.

  - `RPadRight`: Represents the right half of the X-axis of the right trackpad.

  - `RPadTouch`: This is a button sensor which detects if the right pad is being touched. Quite sensitive.

  - `RPadPress`: This is also a button which detects if the right pad is being pressed down like a button. Actuation has a slight tactile bump.

  - `RPadForce`: This is a pressure sensor which returns a normalized value of how much force is being used to press down on the right trackpad. This is an absolute axis value and behaves the same as Triggers.

  - `RPadRelX`: This is a derived relative axis value that measures the amount of relative X-axis movement between update frames of the right trackpad. This represents the same kind of input data that mice use. This input is unaffected by deadzones. Typical values returned fall inside the range of -5 to +5.

  - `RPadRelY`: This is a derived relative axis value that measures the amount of relative Y-axis movement between update frames of the right trackpad. This represents the same kind of input data that mice use. This input is unaffected by deadzones. Typical values returned fall inside the range of -5 to +5.

#### Quadrant Button Map

The quadrant map (`PadPressQuad*`) provides a way to treat each touchpad as being composed of four non-overlapping triagular quadrants, as depicted in the figure 1 below. Each button is inherently exclusive to the others in this map since the X / Y coordinate can only fall inside of one of these regions at a time. This means that this map will not detect any overlapping presses, like a and b when you press in the upper-left region.

Fig. 1

    ┌─────────────┐
    │ \         / │
    │  \   a   /  │
    │   \     /   │
    │    \   /    │
    │     \ /     │
    │ b    X    c │
    │     / \     │
    │    /   \    │
    │   /     \   │
    │  /   d   \  │
    │ /         \ │
    └─────────────┘

- `LPadPressQuadUp`: The logical button on the left trackpad corresponding to fig. 1, region "a".

- `LPadPressQuadDown`: The logical button on the left trackpad corresponding to fig. 1, region "d".

- `LPadPressQuadLeft`: The logical button on the left trackpad corresponding to fig. 1, region "b".

- `LPadPressQuadRight`: The logical button on the left trackpad corresponding to fig. 1, region "c".

- `RPadPressQuadUp`: The logical button on the right trackpad corresponding to fig. 1, region "a".

- `RPadPressQuadDown`: The logical button on the right trackpad corresponding to fig. 1, region "d".

- `RPadPressQuadLeft`: The logical button on the right trackpad corresponding to fig. 1, region "b".

- `RPadPressQuadRight`: The logical button on the right trackpad corresponding to fig. 1, region "c".

#### Orthogonal Button Map

The orthogonal map (`PadPressOrth*`) works similarly to a Directional Pad. As you can see below in figure 2, it demonstrates how the "a", "b", "c" and "d" regions represent orthogonal directions which are not strictly exclusive as they are with the Quadrant Button Map. If a diagonal corner is pressed, it triggers both orthogonally adjacent buttons. For example, pressing the upper-middle of the pad only triggers "a", but pressing the upper-left of the pad will trigger both "a" and "b".

Fig. 2

    ┌─────┬─────┬─────┐
    │     │     │     │
    │  ab │  a  │  ac │
    │     │     │     │
    ├─────┼─────┼─────┤
    │     │     │     │
    │  b  │     │  c  │
    │     │     │     │
    ├─────┼─────┼─────┤
    │     │     │     │
    │  db │  d  │  dc │
    │     │     │     │
    └─────┴─────┴─────┘

- `LPadPressOrthUp`: The logical button on the left trackpad corresponding to fig. 2 regions containing "a".

- `LPadPressOrthDown`: The logical button on the left trackpad corresponding to fig. 2 regions containing d".

- `LPadPressOrthLeft`: The logical button on the left trackpad corresponding to fig. 2 regions containing "b".

- `LPadPressOrthRight`: The logical button on the left trackpad corresponding to fig. 2 regions containing "c".

- `RPadPressOrthUp`: The logical button on the right trackpad corresponding to fig. 2 regions containing "a".

- `RPadPressOrthDown`: The logical button on the right trackpad corresponding to fig. 2 regions containing d".

- `RPadPressOrthLeft`: The logical button on the right trackpad corresponding to fig. 2 regions containing "b".

- `RPadPressOrthRight`: The logical button on the right trackpad corresponding to fig. 2 regions containing "c".

#### 2x2 Grid Button Map

This button map divides the pad into regions along the center axes, resulting in four square buttons in each corner, as depicted in figure 3. Buttons are naturally exclusive, so only one can be pressed at a time. Buttons are enumerated left-to-right, top-to-bottom.

Fig. 3

    ┌────────┬────────┐
    │        │        │
    │        │        │
    │   a    │    c   │
    │        │        │
    │        │        │
    ├────────┼────────┤
    │        │        │
    │        │        │
    │   c    │    d   │
    │        │        │
    │        │        │
    └────────┴────────┘

- `LPadPressGrid2x2_1`: The logical button on the left trackpad corresponding to fig. 3, region "a".

- `LPadPressGrid2x2_2`: The logical button on the left trackpad corresponding to fig. 3, region "b".

- `LPadPressGrid2x2_3`: The logical button on the left trackpad corresponding to fig. 3, region "c".

- `LPadPressGrid2x2_4`: The logical button on the left trackpad corresponding to fig. 3, region "d".

- `RPadPressGrid2x2_1`: The logical button on the right trackpad corresponding to fig. 3, region "a".

- `RPadPressGrid2x2_2`: The logical button on the right trackpad corresponding to fig. 3, region "b".

- `RPadPressGrid2x2_3`: The logical button on the right trackpad corresponding to fig. 3, region "c".

- `RPadPressGrid2x2_4`: The logical button on the right trackpad corresponding to fig. 3, region "d".

#### 3x3 Grid Button Map

This button map divides the pad into thirds along both axes, resulting in a 3x3 grid of nine square buttons, as depicted in figure 4. These buttons are naturally exclusive to one another, so only one can be pressed at a time. Buttons are enumerated left-to-right, top-to-bottom.

Note | The resulting size of each button will be fairly small, so it may require a little practice and small thumbs to manipulate them precisely.

Fig. 4

    ┌─────┬─────┬─────┐
    │     │     │     │
    │  a  │  b  │  c  │
    │     │     │     │
    ├─────┼─────┼─────┤
    │     │     │     │
    │  d  │  e  │  f  │
    │     │     │     │
    ├─────┼─────┼─────┤
    │     │     │     │
    │  g  │  h  │  i  │
    │     │     │     │
    └─────┴─────┴─────┘

- `LPadPressGrid3x3_1`: The logical button on the left trackpad corresponding to fig. 4, region "a".

- `LPadPressGrid3x3_2`: The logical button on the left trackpad corresponding to fig. 4, region "b".

- `LPadPressGrid3x3_3`: The logical button on the left trackpad corresponding to fig. 4, region "c".

- `LPadPressGrid3x3_4`: The logical button on the left trackpad corresponding to fig. 4, region "d".

- `LPadPressGrid3x3_5`: The logical button on the left trackpad corresponding to fig. 4, region "e".

- `LPadPressGrid3x3_6`: The logical button on the left trackpad corresponding to fig. 4, region "f".

- `LPadPressGrid3x3_7`: The logical button on the left trackpad corresponding to fig. 4, region "g".

- `LPadPressGrid3x3_8`: The logical button on the left trackpad corresponding to fig. 4, region "h".

- `LPadPressGrid3x3_9`: The logical button on the left trackpad corresponding to fig. 4, region "i".

- `RPadPressGrid3x3_1`: The logical button on the right trackpad corresponding to fig. 4, region "a".

- `RPadPressGrid3x3_2`: The logical button on the right trackpad corresponding to fig. 4, region "b".

- `RPadPressGrid3x3_3`: The logical button on the right trackpad corresponding to fig. 4, region "c".

- `RPadPressGrid3x3_4`: The logical button on the right trackpad corresponding to fig. 4, region "d".

- `RPadPressGrid3x3_5`: The logical button on the right trackpad corresponding to fig. 4, region "e".

- `RPadPressGrid3x3_6`: The logical button on the right trackpad corresponding to fig. 4, region "f".

- `RPadPressGrid3x3_7`: The logical button on the right trackpad corresponding to fig. 4, region "g".

- `RPadPressGrid3x3_8`: The logical button on the right trackpad corresponding to fig. 4, region "h".

- `RPadPressGrid3x3_9`: The logical button on the right trackpad corresponding to fig. 4, region "i".

## Troubleshooting

TODO: This section <<<

## Example config.ini

    [Daemon]
    # The gamepad profile to be loaded on startup
    Profile = default.profile

    # Allow client connections from CLI and GUI configuration tools
    AllowClients = true

## Example Profile

    [Profile]
    Name        = "Default OpenSD Profile"
    Description = "A basic configuration that should work for most games and provide a few extras."

    [Features]
    ForceFeedback       = true
    MotionDevice        = true
    MouseDevice         = true
    LizardMode          = false
    StickFiltering      = true
    TrackpadFiltering   = true

    [DeviceInfo]
    Gamepad     = 0xDEAD 0xBEEF 0x0100 "OpenSD Gamepad Device"
    Motion      = 0xDEAD 0xD00D 0x0100 "OpenSD Motion Control Device"
    Mouse       = 0xDEAD 0xF00D 0x0100 "OpenSD Mouse Device"

    [Deadzones]
    LStick      = 0.1
    RStick      = 0.1
    LPad        = 0
    RPad        = 0
    LTrigg      = 0
    RTrigg      = 0

    [GamepadAxes]
    #-----------------------------------------------------------
    # Axis            Min       Max         Fuzz    Resolution
    #-----------------------------------------------------------
    ABS_HAT0X       = -1        1
    ABS_HAT0Y       = -1        1
    ABS_X           = -32767    32767
    ABS_Y           = -32767    32767
    ABS_RX          = -32767    32767
    ABS_RY          = -32767    32767
    ABS_Z           = 0         32767
    ABS_RZ          = 0         32767

    [MotionAxes]
    #-----------------------------------------------------------
    # Axis            Min       Max         Fuzz    Resolution
    #-----------------------------------------------------------
    ABS_X           = -32767    32767
    ABS_Y           = -32767    32767
    ABS_Z           = -32767    32767
    ABS_RX          = -32767    32767
    ABS_RY          = -32767    32767
    ABS_RZ          = -32767    32767

    [Touchpads]
    #---------------------------------------
    # Axis                x         y
    #---------------------------------------
    LPadSensitivity     = 1.0       1.0
    RPadSensitivity     = 1.0       1.0
    LPadDecay           = 0.05      0.05
    RPadDecay           = 0.05      0.05

    [Bindings]
    #-----------------------------------------------------------
    # Input             BindType    Mapping     +/-/scale
    #-----------------------------------------------------------
    # Directional Pad
    DpadUp              = Gamepad   ABS_HAT0Y   -
    DpadDown            = Gamepad   ABS_HAT0Y   +
    DpadLeft            = Gamepad   ABS_HAT0X   -
    DpadRight           = Gamepad   ABS_HAT0X   +
    # Buttons
    A                   = Gamepad   BTN_SOUTH
    B                   = Gamepad   BTN_EAST
    X                   = Gamepad   BTN_WEST
    Y                   = Gamepad   BTN_NORTH
    L1                  = Gamepad   BTN_TL
    R1                  = Gamepad   BTN_TR
    L2                  = Gamepad   BTN_TL2
    R2                  = Gamepad   BTN_TR2
    L3                  = Gamepad   BTN_THUMBL
    R3                  = Gamepad   BTN_THUMBR
    L4                  = None
    R4                  = None
    L5                  = None
    R5                  = None
    Menu                = Gamepad   BTN_START
    Options             = Gamepad   BTN_SELECT
    Steam               = Gamepad   BTN_MODE
    QuickAccess         = Mouse     BTN_RIGHT
    # Triggers
    LTrigg              = Gamepad   ABS_Z       +
    RTrigg              = Gamepad   ABS_RZ      +
    # Left Stick
    LStickUp            = Gamepad   ABS_Y       -
    LStickDown          = Gamepad   ABS_Y       +
    LStickLeft          = Gamepad   ABS_X       -
    LStickRight         = Gamepad   ABS_X       +
    LStickTouch         = None
    LStickForce         = None
    # Right Stick
    RStickUp            = Gamepad   ABS_RY      -
    RStickDown          = Gamepad   ABS_RY      +
    RStickLeft          = Gamepad   ABS_RX      -
    RStickRight         = Gamepad   ABS_RX      +
    RStickTouch         = None
    RStickForce         = None
    # Left Trackpad
    LPadUp              = None
    LPadDown            = None
    LPadLeft            = None
    LPadRight           = None
    LPadTouch           = None
    LPadRelX            = None
    LPadRelY            = None
    LPadTouch           = None
    LPadPress           = None
    LPadForce           = None
    LPadPressQuadUp     = None
    LPadPressQuadDown   = None
    LPadPressQuadLeft   = None
    LPadPressQuadRight  = None
    LPadPressOrthUp     = None
    LPadPressOrthDown   = None
    LPadPressOrthLeft   = None
    LPadPressOrthRight  = None
    LPadPressGrid2x2_1  = None
    LPadPressGrid2x2_2  = None
    LPadPressGrid2x2_3  = None
    LPadPressGrid2x2_4  = None
    LPadPressGrid3x3_1  = None
    LPadPressGrid3x3_2  = None
    LPadPressGrid3x3_3  = None
    LPadPressGrid3x3_4  = None
    LPadPressGrid3x3_5  = None
    LPadPressGrid3x3_6  = None
    LPadPressGrid3x3_7  = None
    LPadPressGrid3x3_8  = None
    LPadPressGrid3x3_9  = None
    # Right Trackpad
    RPadUp              = None
    RPadDown            = None
    RPadLeft            = None
    RPadRight           = None
    RPadTouch           = None
    RPadRelX            = Mouse     REL_X
    RPadRelY            = Mouse     REL_Y
    RPadTouch           = None
    RPadPress           = Mouse     BTN_LEFT
    RPadForce           = None
    RPadPressQuadUp     = None
    RPadPressQuadDown   = None
    RPadPressQuadLeft   = None
    RPadPressQuadRight  = None
    RPadPressOrthUp     = None
    RPadPressOrthDown   = None
    RPadPressOrthLeft   = None
    RPadPressOrthRight  = None
    RPadPressGrid2x2_1  = None
    RPadPressGrid2x2_2  = None
    RPadPressGrid2x2_3  = None
    RPadPressGrid2x2_4  = None
    RPadPressGrid3x3_1  = None
    RPadPressGrid3x3_2  = None
    RPadPressGrid3x3_3  = None
    RPadPressGrid3x3_4  = None
    RPadPressGrid3x3_5  = None
    RPadPressGrid3x3_6  = None
    RPadPressGrid3x3_7  = None
    RPadPressGrid3x3_8  = None
    RPadPressGrid3x3_9  = None
    # Accelerometers
    AccelXPlus          = Motion    ABS_RX      +
    AccelXMinus         = Motion    ABS_RX      -
    AccelYPlus          = Motion    ABS_RY      +
    AccelYMinus         = Motion    ABS_RY      -
    AccelZPlus          = Motion    ABS_RZ      +
    AccelZMinus         = Motion    ABS_RZ      -
    # Gyro / Attitude
    RollPlus            = Motion    ABS_X       +
    RollMinus           = Motion    ABS_X       -
    PitchPlus           = Motion    ABS_Y       +
    PitchMinus          = Motion    ABS_Y       -
    YawPlus             = Motion    ABS_Z       +
    YawMinus            = Motion    ABS_Z       -