Showing posts with label input device properties. Show all posts
Showing posts with label input device properties. Show all posts

Thursday, July 14, 2016

xinput resolves device names and property names

xinput is a commandline tool to change X device properties. Specifically, it's a generic interface to change X input driver configuration at run-time, used primarily in the absence of a desktop environment or just for testing things. But there's a feature of xinput that many don't appear to know: it resolves device and property names correctly. So plenty of times you see advice to run a command like this:

xinput set-prop 15 281 1
This is bad advice, it's almost impossible to figure out what this is supposed to do, it depends on the device ID never changing (spoiler: it will) and the property number never changing (spoiler: it will). Worst case, you may suddenly end up setting a different property on a different device and you won't even notice. Instead, just use the built-in name resolution features of xinput:
xinput set-prop "SynPS/2 Synaptics TouchPad" "libinput Tapping Enabled" 1
This command will work regardless of the device ID for the touchpad and regardless of the property number. Plus it's self-documenting. This has been possible for many many years, so please stop using the number-only approach.

Friday, June 3, 2011

Linking kernel and X devices

XI2 has made it possible to access any device the X server knows about and get events from those devices. Alas, one piece was missing: short of parsing the Xorg.log file it was so far impossible to link the system devices with kernel device. You had to guess that /dev/input/event3 was your "AT Translated Set 2 keyboard" with the X device ID of 6.

Why would one need this? Some properties of a device are not exported in X. These included for example anything in sysfs.

I've now pushed patches to evdev, synaptics and the wacom driver to export the device node as a simple string property. From this device node, a client can navigate to the matching sysfs dir, get other events out of the kernel or do whatever they like to do.

The property name is "Device Node" and it is a standard char* that contains the device path. The path is set by the driver, so even if you use e.g. auto-dev on synaptics, the value will be filled in correctly. On the downside, if the driver doesn't support it, the property will not be available on a device. If you write clients that require this information, ensure that you can cope with a missing property and remember that several X devices may share the same device node (e.g. wacom).

These patches do not require a new server, though we have added a #define XI_PROP_DEVICE_NODE to the server to make it easier for others to use this property without misspelling it.

Another property that was pushed in the same series was the "Device Product ID" property (#define XI_PROP_PRODUCT_ID once the new server is out). This property contains two unsigned 32-bit values: vendor ID and product ID. Having this information available makes it simpler for X clients to apply configuration based on specific devices. This can come in handy if you e.g. need different acceleration for a set of mice or you simply want to remap buttons on a specific device.
Again, the two values are set by the driver and all the above rules apply.

I may end up writing those patches for mouse and keyboard too but feel free to help me out with it.

The obligatory not-quite-a screenshot:

:: whot@barra:~> xinput list-props "SynPS/2 Synaptics TouchPad"
Device 'SynPS/2 Synaptics TouchPad':
[...]
Device Product ID (252): 2, 7
Device Node (253): "/dev/input/event4"



Update June 7 2011: As Peter pointed out in the comments, the device node is always local to the host the server runs on. It is up to the client to figure out if it runs on the same host.

Tuesday, February 17, 2009

Generic axis support in evdev

After the groundwork by Matt Helsley we now have generic axis support in evdev. So evdev finally sets the device up according to what the kernel reports rather than limiting itself to x/y and potentially pressure.

A truly generic driver. Rejoice.

And because we can, it does axis labeling too (if you have xserver git master, that is).
No more guessing what axis 7 actually is.

The obligatory "screenshot":


whot@roo:~> xinput --list-props "PIXART USB OPTICAL MOUSE" | grep "Axis Labels"
Axis Labels (242): "Rel X", "Rel Y", "Rel Vert Wheel"
whot@roo:~> xinput --list-props "Wacom Intuos3 4x6" | grep "Axis Labels"
Axis Labels (242): "Abs X", "Abs Y", "Abs Z", "Abs Rotary X", "Abs Rotary Z", "Abs
Throttle", "Abs Wheel", "Abs Pressure", "Abs Distance", "Abs Tilt X", "Abs Tilt Y", "Abs Misc"


Expect this to be in evdev 2.2, once it has matured and potential glitches are ironed out.

Friday, October 3, 2008

Device properties have landed

After a few more patches, the property support has now landed in what I'd like to call the final version. Unless there's any more changes in the next few weeks, this will be added as the main component of the X Input Extension v1.5.

So here's a short description of what they are, the protocol additions and the driver-side API.

What are device properties?



Input device properties (IDP) are basically the same as Window Properties (Atoms) in the core X protocol, or RandR output properties. They are numerical identifiers with arbitrary names that can be assigned arbitrary values. The big thing about IDP is that we can now add options to drivers that can be triggered at modified by clients without having to bump the protocol or even the server. Likewise, we can add options to the server easier too.

One of the server's weakest parts was run-time configuration of input devices. Options in the xorg.conf (or nowadays in the HAL fdi file) were easy enough, but once the server was running it was difficult to do anything. Synaptics even exposes shared memory to enable run-time configuration for lack of a better mechanism. IDP should fix this lack of a decent method and hopefully unify the configuration mechanisms. In fact, synaptics, evdev and joystick already provide property support.

Your server already uses a lot of properties for various stuff. The "xlsatoms" command lists all properties currently defined and their names. The "xprop" command lists all window properties and their current value(s).

Driver API


The code to use device properties from a driver (or the server) is basically always the same:

#include<X11/Xatom.h>
#define MYPROP_NAME "Example property"

char prop_value = 8;
/* create atom (if it doesn't exist already anyway) */
Atom prop = MakeAtom(MYPROP_NAME, strlen(MYPROP_NAME), TRUE);
rc = XIChangeDeviceProperty(device, prop,
XA_INTEGER /* type */,
8 /* format */,
PropModeReplace,
1 /* no of items */,
&prop_value /* data */,
TRUE /* send event */):

/* don't allow clients to delete our prop */
XISetDevicePropertyDeletable(device, prop, FALSE);
XIRegisterPropertyHandler(device, SetPropertyHandler,
GetPropertyHandler,
DeletePropertyHandler);


SetPropertyHandler is called whenever a client changes the property. GetPropertyHandler is called whenever a client retrieves the property value, if you have to get data off the device - do it here. Finally DeletePropertyHandler is called when the property is about to be deleted. Note that if you set the property to be non-deletable, the DeletePropertyHandler can only called if a driver or the server wants to delete the property.

In all cases, do stuff, return Success or an error code otherwise. A NULL handler is allowed. Errors are returned immediately to the client, so make sure your property is properly documented that developers can figure out why a BadValue, BadMatch, etc. error occurs.

Here's some example code for a SetPropertyHandler

int SetPropertyHandler(DeviceIntPtr dev, Atom atom,
XIPropertyValuePtr value, BOOL checkonly)
{
if (atom == myprop)
{
if (val->format != 8 || val->type != XA_INTEGER || ...)
return BadMatch;

if (*((char*)val->data) > 10)
return BadValue;

if (!checkonly) /* do something with the value */
{ ...
}
}
return Success; /* You MUST return Success, even if you didn't handle it */
}


Important here: if checkonly is TRUE, you must not change any state. Check only for validity of the atom and the given value. Each SetPropertyHandler is called twice, once to check the value, then again to actually apply the data. The assumption is that if the checkonly run succeeds, the state change cannot fail. If you return an error in the checkonly run, this error is returned to the client and the second run is never executed.

A few rules: keep the handler simple. You cannot assume that you're called in any particular order. You cannot assume that the second run is ever executed. Keep the handler as local as possible, instead of having one big handler it may be better having two separate ones (e.g. one in the DIX, one in the DDX).

That's basically it. A call to XIChangeDeviceProperty() causes an event to be sent to the clients, so this is the API that should be used if the property needs changing from within the server/driver.

Protocol requests and events


As just mentioned above, there's one event DevicePropertyNotify which lists the state (NewValue or Deleted), the property affected and of course the device id. This event is sent whenever a property is changed by a client and whenever a driver/the server changes a property with XIChangeDeviceProperty(..., TRUE).

The four new requests are:

ListDeviceProperties
ChangeDeviceProperty
DeleteDeviceProperty
GetDeviceProperty

All four requests are virtually identical to the ListProperties, ChangeProperty, DeleteProperty, and GetProperty requests of the core protocol - except they allow the specification of a device ID instead of a window ID. Just look up the man page for the core protocol requests for more information.

The xinput tool has all the basic code to list, view and delete properties.

As a final gimmick, evdev, synaptics and the xserver each have a name-properties.h file, (e.g. evdev-properties.h gives you all the defines for the property names) and the command "
pkg-config --cflags xorg-evdev" gives you the necessary include paths.

Thursday, July 10, 2008

Input Device Properties

Another big feature was just pushed to git - input device properties.

You may know about window properties, you may know about RandR output properties. Now we have input device properties too, which are little more than a copy of the above two.

IDP allow you to attach properties to a device. These properties can be of arbitrary type and can be changed without the server having to know their details.
So who uses IDP?
- Drivers: the evdev driver now attaches two properties to enable middle mouse button support at runtime, and to change the middle button timeout. When a client changes such a property, the driver is notified and adjusts accordingly.
- The server: Simon Thum has been working on improved mouse pointer acceleration for a while now [1]. With IDP, the server can attach parameters to the device and use them for smoother acceleration.
- Clients: A client may label the device that is controlled by the dominant hand accordingly, and other clients can utilise this for their interaction methods.

And here's the mandatory "screenshots":

Changing the MB timeout from the default to 500ms.

whot@emu:~$ xinput --list-props "USB Optical Mouse"
Device 'USB Optical Mouse':
Middle Button Emulation: 2
valid values: 0 1 2
Middle Button Timeout: 50
whot@emu:~$ xinput --set-int-prop "USB Optical Mouse" "Middle Button Timeout" 16 500
whot@emu:~$ xinput --list-props "USB Optical Mouse"
Device 'USB Optical Mouse':
Middle Button Emulation: 2
valid values: 0 1 2
Middle Button Timeout: 500


Creating a client-defined property

whot@emu:~$ xinput --set-int-prop "USB Optical Mouse" "foobar" 8 2
whot@emu:~$ xinput --list-props "USB Optical Mouse"
Device 'USB Optical Mouse':
Middle Button Emulation: 2
valid values: 0 1 2
Middle Button Timeout: 500
foobar: 2
[client]

Note the [client] marks this property as created by a client, so you know that changing this property probably won't change anything in the driver/server.

Disclaimer: IDP weren't actually my idea, daniels has been talking about them for a while and I've seen them pop up elsewhere. I merely found the time to implement them.

[1] http://bugs.freedesktop.org/show_bug.cgi?id=8583