input-evdev patch adding option to override XDevice type Atom, option to force EV_REL events being treated as absolute values.
wdraxinger at darkstargames.de
Fri Mar 14 07:36:35 PDT 2008
Am Freitag, 14. März 2008 schrieb Jiri Kosina:
> Exactly, I fully agree with Dmitry here.
> We can easily fix up the device report descriptor in the kernel
> code, so that it would send EV_ABS instead of EV_REL events. We do
> similar fixups (not this particular one) for quite a few devices
> The real question here is whether it is really buggy device, or
> just EV_REL interpretation makes more sense so X input driver, but
> the device itself doesn't send buggy data. Could you please
> elaborate a little bit more?
The device I'm refering to is a 3Dconnexion SpaceNavigator i.e. a
Spaceball used to input 3D transformation data*; technically this
means it is a 6DOF 'joystick'. 3 axes of translation, 3 axes of
rotation (some people/applications treat them as Euler angles, but
there's a different method, which suits Spaceballs better).
The values it reports are the translation and rotation of the handle
knob, which are by nature absolute values (the device has a neutral
position and mechanical limits).
XInput already defines a device type SPACEBALL, which is mostly used
as an absolute valuator. A application using it would use the values
the device sends, and integrates them using a timer.
Now the SpaceNavigator has some very unusual behaviour: If it's _not_
in neutral position it repeatedly sends EV_REL movements, the
repeated sending at constant time intervalls causing the valuator in
the X server to integrate the values, which are then reported as axis
values (just like how a mouse is treated). This is "fine" if you set
the device as "SendCoreEvents" to control the pointer with it. But to
use it that way in a 3D application (Blender, CADs, whatever) this is
definitely the wrong behaviour. I'd even assume, that some 3D apps
with spaceball support don't even check, it the device is reported as
relative valuator and just assume the motion event axes values as
absolute --- checking on the valuator mode, one could differentiate
and reintegrate the values, thus removing any offset, but it still
requires some extra handling: If the device is (back) in neutral
position it doesn't send any events at all. When I first wrote my
patch I've overseen this. It has the nasty side effect, that if the
device has gone into neutral there's still the very last non-0-value
in the application's driver's state machine. The solution is simple:
Have a timeout that get's released with each EV_SYN and when it
signals send a 0-vector.
So here are the quirks needed to make the SpaceNavigator behave sanely
against end user applications --- which might be written naively with
the assumption all devices implement the (de facto) standards
* Values the device report are absolute:
=> Replace EV_REL with EV_ABS.
* Repeatedly sent absolute events of the same value
don't hurt, but cause some overhead/eat bandwidth
if X is networked:
=> Only pass on the event if a value changed
* Some devices, like spaceballs, rely on events that
contain the values of all non-commutative valuators
(for a spaceball this is rotation):
=> In such case only send full events
* If the device reports absolute values in relative events
it's likely, that 0-vectors (i.e. device is in neutral
position) are not reported in form of a event:
=> Add a timeout that triggers a synthetic 0-vector absolute
event to inform the application of the device being in
Finally, and completely outside any wrong/kludgy behaviour of the
device: Spaceballs should be listed a XDevice with the type
atom "SPACEBALL". IMHO an option to override the atom should become a
InputSection option, rather than a xf86-input-evdev option: There are
a few other drivers that report non-standard atoms. linuxwacom, e.g.
set's the atom to "Wacom Stylus" or "Wacom Eraser" whereas there's a
proper standard XDevice type atom "TABLET". Anyway xf86-input-evdev
needs a option (or some device database) to set the atom to anything
else than "KEYBOARD" or "MOUSE", which are the only types it can
determine from what the kernel tells. Technically such an option is
implemented by replacing just two lines in the current code, like I
did in the patch I posted.
And last but not least I noticed (I also reported in my very first
post about this) that xf86-input-evdev has a element 'sync' in it's
state struct that is nowhere explicitly initialzed. However evdev
events are immediately xf86PostMotionEvent-ed if this flag is not set
(which it not is, as the compiler silently initialzes it to 0). As
long as the axis vectos can be concatenated commutatively (ordinary
translation i.e. vector addition) this doesn't hurt. However
rotations --- and a spaceball reports rotations --- are not
commutative. You can easyly try it out with some cardboard box of
some of your computer equipment: First rotate it around the global
(i.e. the coordinate system of your desk) X axis (tilt) and then
around the Z axis (roll). Memorize the new position. Now bring it
back to the original position, then rotate around Z and then X. You
The correct behaviour (just as it is correctly implemented, and only
overriden by the sync flag in xf86-input-evdev) is to wait for EV_SYN
to post a complete MotionEvent, especially with spaceballs, since the
spaceball sends a rotation, for which the values are needed as a
bunch. My suggestion: Just drop the sync flag, it's not properly used
anyway. I did so in my demonstration patch.
*) P.S.: Here's some quick and dirty introduction into the basic math
of 3D applications, for those not intimate with 3D graphics
Usually 3D transformations are stored using a 4x4 matrix in homogenous
coordinates: The general structure is:
| R T |
M = | 0 1 |
where R is a 3x3 rotation matrix (usually being orthonormal), but also
determines the scale though the reciprocal normalisation factor (if R
is just orthogonal), T is (x, y, z, 1)^t (^t means transposed). The
nice things about homogenous transformation matrices is, that any
transformations can be concatenated by simple matrix multiplication.
To save space and computation cycles R can be represented in form of a
quaternion (a 4 vector, something like a complex number on
steroids :-) ), with the first element denoting the angle of rotation
and the 3 last elements (which are imaginary numbers) denoting the
axis. Determining the equivalent quaternion from a rotation matrix is
a eigenvalue problem.
The nice this about quaternions is, that concatenating them requires
just 16 scalar multiplications, whereas matrix multiplication
requires 64 scalar multiplications.
-------------- next part --------------
A non-text attachment was scrubbed...
Size: 189 bytes
Desc: This is a digitally signed message part.
More information about the xorg