input-evdev patch adding option to override XDevice type Atom, option to force EV_REL events being treated as absolute values.

Wolfgang Draxinger 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
> already.
>
> 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 
corrently:

* 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
     neutral position

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 
see..?
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.

cheers

Wolfgang Draxinger

*) P.S.: Here's some quick and dirty introduction into the basic math 
of 3D applications, for those not intimate with 3D graphics 
(programming):

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...
Name: signature.asc
Type: application/pgp-signature
Size: 189 bytes
Desc: This is a digitally signed message part.
URL: <http://lists.x.org/archives/xorg/attachments/20080314/eb755d6e/attachment.pgp>


More information about the xorg mailing list