Wednesday, June 30, 2010

XTS has a new home

Gather round children, for I shall bore you with a story. Back in the olden days, we had a X Test Suite (XTS). Amongst other things, it tried to verify certain behaviours in light of protocol requests. It's quite huge, covering pretty much all of the core protocol and a few extensions as well. That beast, and a beast it was, was maintained in CVS and mostly dead.

In March 2009 we started autotooling it, removing cruft, general weirdness and over time it became more useful. Many thanks here to Dan Nicholson, Aaron Plattner and Jon Turney. Now we've finally moved it from various $HOME directories to a git repo proper. The work is not completed yet though. The code does show its age and many a cleanup work is needed to drag XTS into the future. Kicking and screaming may be involved, swearing will definitely be part of that process.

To get the test suite, run

git clone git://

It is now at a stage where it pretty much runs with the usual autoreconf/configure/make steps and spits out results. The usefulness of those results is in debate, they all need auditing. You must run it against a plain X server, running a window manager will alter the results.

Note that XTS is a developer tool, be aware that it's inner workings and output may be confusing. If you look at it long enough, you may see the matrix.

Tuesday, June 22, 2010

xmodmap keyboard deconfiguration

Reading this post on last weekend made me cringe. Not because it is factually wrong (it isn't), but because what's described here is the reason for a great many bugreports and some rather uninformed hatemail. One thing that startled me in particular is the hint that "to really take charge, you need to dig into the X keyboard extension" when the rest of the article doesn't deal with XKB at all. This prompted me to write this blurb here.

The abstraction cardhouse

In X, keyboard input is abstracted. The keyboard sends a keycode to the client. The client then translates that keycode into a keysym (a glyph, in most cases, more or less), given a keycode-keysym table. Keycodes should be treated as arbitrary by the client. Keysyms on the other hand are constant, the keysym for "♥" is always the same (0x1002665). In the core protocol, that lookup table was reasonably straightforward (for some value of "straightforward"), with several modifiers providing access to different levels in the table. The table being based on the max number of modifiers. For 105 keys and two modifiers, the table was essentially 210 symbols wide (modifiers can be "shift", "alt", etc.).

That was deemed to be insufficient, causing the development of the X Keyboard Extension, lovingly referred to as "XKB" or "that bloody nail in my coffin". I won't go into details, but the lookup tables are a tad more complicated. XKB is integrated around core so that XKB and core applications can coexist nicely. Up to a point that for a long time we kept XKB state and core state separately inside the server instead of generating it on-the-fly. What's unfortunate though is that the XKB protocol spec describes how to get the core lookup table from the XKB data. It also describes how to extrapolate from core to XKB. It doesn't however cover the full circle. So if you go from XKB to core back to XKB, guesswork happens.

Anyway, what you need to take from this is that the general rule of thumb is - any commandline tool uses core, any tool that allows you to select a layout, variant or model uses XKB.
And core doesn't support device specifiers, so it can only ever work on the default device or core device, more on that below.

Pulling out the cards

All the above was mostly good until 2007. That's when input hotplug happened. And 2009, when MPX happened. Now none of the old tools work properly anymore. Not because we've broken them, they still do what they've always done. But the environment has changed and what they do isn't sufficient anymore. So before you think about writing an angry comment that we've broken your configuration: stop using input and output hotplugging, stop using suspend/resume, stop using a desktop environment that manages your keyboard configuration. Then you'll notice everything still works as before and you can xmodmap away.

So why did everything break since?
Back before input hotplug we had one device that was deemed the "core keyboard". Whenever anything configured the device it set the configuration on this core device. Since xset, xmodmap and friends work on core only, the XKB configuration was then modified from that core table. All that was fine, because the core keyboard was hardly ever changed. Now with input-hotplug and MPX, we have the physical devices, attached to what is now called "master devices" but still serve the same purpose as the old "core keyboard". However, we've greatly increased the flexibility of the devices and physical devices are more often than not configured directly now. What we then end up with is a master device that has multiple keyboards configured, all with possible different keyboard configurations. In fact, non-US layout users in Fedora 12 are practically guaranteed to have multiple keyboard configurations. We only apply the user-selected layout to actual keyboard devices, not to devices with keys (Power Button, Video Bus, etc.). These devices come up with the "US" default.

In the case of a user with two physical keyboards, one qwerty, one azerty, the matching master device needs to adjust the keyboard configuration of the device in use. This means that it will switch between the two configurations as the devices are used. That works fine too. But if you now use xmodmap to change the the keyboard config on the master device, this configuration only stays as long as the same physical keyboard device is being used.
Now, the simple fix for this is to apply the new configuration to all devices instead of just the master device. And that's exactly what we do. However, this doesn't work with hotplugging. Once a new device is plugged in, it comes up with the configuration configured in the xorg.conf again. And that config doesn't include whatever xmodmap settings were applied later. So once that device is used, the settings are lost again or at least lost on this device.
Now sprinkle into this the fact that core doesn't really support multiple groups (layouts) on the same keyboard, that keycodes may be different between devices, that with MPX a device that was a slave to an xmodmap configured master device may end up being attached to a master that has a different XKB configuration and you've got the start of an interesting career.

The fix for all this is simple: make the session handle all keyboards, existing and hotplugged ones, and let it update the config accordingly. Whenever you're using a tool like xmodmap it is your responsibility to reapply the config after changing keyboards. Which brings me back to the article above - it curiously didn't mention that. So I strongly recommend that instead of configuring your keyboard with xmodmap you spend your time helping your favourite desktop environment to provide tools to cover your use-case.

PS: surprisingly "deconfiguration" doesn't exist in the dictionary but it seems the best word to describe what xmodmap does.

Wednesday, June 16, 2010

An (incomplete) roundup of touchpad features

Every once in a while, I stumble across a blog post titled "Multitouch with the synaptics driver" or something similar. Usually I find out that these posts describe how to enable two-finger scrolling or something similar. So I figured, maybe it's time to have something like a roundup of the features of the synaptics driver. As I have posted not too long ago, we have a great many options not all of them as useful as they could be.

First of all - the name "synaptics" is historical and now woefully inadequate. On Linux, we now rely on the kernel to address device-specifics and simply use the event API. In fact, synaptics is just like evdev with different features. (Note to non-Linux users: we still have the backends for hardware communication in the driver as well)

So whenever we talk about "synaptics devices", the "synaptics driver", or "synaptics features" in X, we mean "touchpad". All of the features are described in the man page and can be set either as an xorg.conf option or at runtime by tweaking the properties (with xinput or synclient). I'll brush on the capabilities exposed by the GNOME tool, for the KDE tool check the comments, I'm sure Kevin Kofler will point to them as usual.

Furthermore, I won't list the various options required to configure all this - simply look it up in the man page and you may find some other gems in there too.

Edge scrolling

The most commonly used touchpad feature is likely edge scrolling. Four edges are defined on the touchpad and movement outside of these edges is interpreted as scrolling. By convention, scrolling in X is buttons 4,5 and 6,7 for vertical and horizontal scrolling, respectively. If movement in the scrolling areas is detected, the driver converts the motion into a number of button presses for these scroll buttons.

Vertical and horizontal edge scrolling is hardcoded to only work on the right and the bottom part of the touchpad. They can be enabled separately and independently, though the GNOME GUI we have for it ties the horizontal scroll method to the vertical scroll method.

Edge scrolling is quite configurable, allowing for minimum and maximum speed settings and even pressure-dependent scrolling. Of course, the distance required to emit one scrolling event is configurable as well. None of these tweaks are exposed in the GNOME GUI.

Two-finger scrolling

Two-finger scrolling is the basic multi-touch feature that the driver provides. If two fingers are detected on the touchpad (you will need the hardware capabilities to do so), vertical and horizontal two-finger movements are converted into scrolling events. Provided the scroll methods are activated of course. The GNOME GUI allows for either edge or two-finger scrolling, the driver could provide both simultaneously.

Now, the interesting thing about two-finger scrolling is that it is usable on touchpads that only support single-fingers as well - through the two-finger emulation. If enabled, the driver tries to guess based on the width of the finger whether it is a single or dual-finger input and then trigger the required bits.

Other than that, two-finger scrolling is rather unexciting, it just does what it says on the box. As with edge scrolling, the minimum distances for a scroll event to be generated is configurable (but not in the GUI).

Multi-finger tapping

Tapping is the action of quickly putting a finger down on the touchpad and lifting it again. Multi-finger tapping is the same action with more than one finger. Synaptics currently supports up to three-finger tapping plus corner tapping. Each multi-finger tap can be assigned a different button, the default the GNOME tool assigns if tapping is enabled is 1/2/3 finger tapping to left/right/middle. Again, multi-finger support relies on your hardware.
Tap-and-drag is automatically enabled, whereby tapping an object, then dragging it with one finger "locks" the mouse button on the object.

Corner tapping works similar, but instead activates hot-zones in the corners of the touchpad (defined by the edge settings). Each corner can also be assigned a different button action. Corner tapping is not exposed in the GUI at this point.

Click fingers

Click fingers are similar to tapping in configuration and effect, but the trigger is different. The ClickFinger actions are executed when the left button is pressed while fingers are down on the touchpad. So if you leave two fingers resting on the touchpad and press the physical button, the configured action is executed. This can be quite useful for those that cannot or do not want to use tapping but still require left/right mouse button presses from their touchpad.

Circular scrolling

Similar to the edge and two-finger scrolling but detects circular motions instead of up/down and left/right motions. This works quite similar to the iPod interface. Depending on the trigger, a circular motion started in that trigger area (e.g. top right corner) will initialize the scrolling behaviour. Note that the circular scrolling events are generated per angle motion, i.e. by changing the radius of the circle you can change the speed of the scrolling.


For scrolling, synaptics has coasting available as well. If enabled, scrolling continues even if the finger has lifted off the pad - provided enough force was to begin with. So if you quickly swipe two fingers up/down, scrolling will only stop once you tap the touchpad again. Coasting is disabled by default and judging by my computer, Firefox seems to be slow enough to give it a coasting feel anyway ;)
Also note that this isn't a physics model, it's a simple start/stop mechanism which arguably isn't quite as useful as a physics model may be.

Multi-touch gestures

We don't have any of the well-known pinch, rotate, swipe, etc. gestures yet. The main issue here is not the driver itself, it would be reasonably easy to add the bits to the driver but we can't do much with it. We have no meaningful way to transmit the gesture data to the client. So it's down to hacks like in the infamous elantech driver that shipped with the Dell Minis. Unfortunately, having the driver generate keystrokes like Ctrl+ to zoom in is hacky at best and nightmarish at worst.
We really need to update the middle-man here (the X server) to provide this information to the client so they can do the appropriate stuff with it. Alas, this work is taking a while.

SHM configuration

I just wanted to add this to have one more place to say it: SHM config doesn't exist anymore. You will need X server 1.6 or later to run the current versions of synaptics and if you see a message asking you to enable SHM configuration, your distribution may need updating or the program that pops up this message may need to be fixed.

Tuesday, June 15, 2010

driver configuration option madness

xf86-input-synaptics $> git grep "xf86Set.*Option" | wc -l

xf86SetIntOption, xf86SetBoolOption, etc. are the server's API to query configuration options. The touchpad driver has 71 one of them (rough count, one is counted twice but three are missing due to abstraction, so it's actually 73 then). I wonder how many of them are actually in use.

Carrying them around isn't really expensive. Good programming practice is to have all these set through variables or defines anyway so you might as well make those configurable. But still, over 70 options in a single driver?

At some point, we should start focusing on making the driver better by default instead of just throwing new configuration options at it. Any time the user has to change from the default configuration, we have failed.

Tuesday, June 1, 2010

New synaptics acceleration mechanism

In 2008, Simon Thum rewrote the X server pointer acceleration code into a complex mechanism that supported better tweaks for a variety of devices. However, a side-effect of this was that synaptics touchpads got accelerated twice, making pointer movement very fast and IMO quite imprecise.

A few months ago, Simon wrote a synaptics patch to pop a synaptics-specific acceleration mechanism into the driver to improve this situation. It's been delayed by me because although I loved it from the first minute onwards, I wanted to get an evaluation done to compare the before and after pointer behaviour in on some objective way (I did get as far as writing nearly all of the code required). Today I gave in and pushed the patch. This study isn't going to happen and I don't feel like holding back something that I believe is a real improvement to how touchpads feel in X.

Now, if you update to synaptics git the first thing you'll notice is that the pointer feels slower. After a few hours or a day you'll likely be used to it, so give yourself the time to get used to it. The new pointer accel code will be in the 1.3 release, which is due out soon (latest for X server 1.9). I'll try to find the time to add some knobs to the GNOME configuration tool by then too.

New evdev middle mouse button emulation defaults

As a heads-up, the next version of evdev (2.5) has a changed default for the middle mouse button emulation code. It is now off by default.

First of all - what is middle mouse button emulation?
Back in the olden days, when oil was cheap and mouse buttons were the peak of technology and thus expensive, mice only had two buttons. Possibly also to confuse user because two buttons for a (on average) five-finger hand seems just the right thing to do. Anyway, I digress.

One version of copy/paste in X relies on the middle mouse button, so a way to emulate that button was implemented in the driver. When this emulation was on, a left button was held back for a timeout and if during this timeout the right button was pressed, the driver would instead post a middle button event. If the right button didn't get pressed in time, the left button event was sent after the timeout expiry.

Coffee addicts could set this timeout to multiple minutes enough to have an excuse to fuel their addiction whenever they tried to do anything with the GUI. Now, two things have happened. The price of oil has surpassed the price of mouse buttons and on virtually all mice we have shiny things like scroll wheels, side buttons and whatnot. Also, computers have gotten a lot faster and people get annoyed about lag in the UI. Holding back a mouse button event by a few milliseconds seriously reduces the number of tweets one can write.

For the last couple of releases, we had the emulation on "auto" by default. It was on, until a physical middle mouse button click was detected. At this point the driver realised the emulation wasn't needed and turned it off. Which made for interesting side-effects: if you didn't know this feature, the GUI felt snappier after a middle mouse button press - for no obvious reason.
The "auto" option was a permanent false positive, there's no really reliable method to detect if a mouse has a middle mouse button.

So I've removed that "auto" feature and defaulted to off. Result - a slightly snappier feel of the UI for a quite underused feature. Of course, there are plenty of users of this feature, so it wasn't removed completely. If you need middle button emulation, please enable it with an xorg.conf snippet or ask your favourite desktop environment to provide a convenient checkbox.

Section "InputClass"
Identifier "middle button emulation class"
MatchIsPointer "on"
Option "Emulate3Buttons" "on"