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.
Attachment:
signature.asc
Description: This is a digitally signed message part.