evdev: workaround for missing ABS_X/Y on multitouch devices (mostly Android)

Peter Hutterer peter.hutterer at who-t.net
Thu Jun 26 18:47:29 PDT 2014


On Thu, Jun 26, 2014 at 10:47:01PM +0100, Colin Macdonald wrote:
> On 25/06/14 02:39, Peter Hutterer wrote:
> > it's doable, and with libevdev fairly simple nowadays, we'd only
> > have to call libevdev_set_abs_info() and be done with it. Send a
> > patch and I'll merge this.
> 
> First attempt at a patch attached.  Works for me on an Android
> device but haven't yet tested on a normal bit of hardware.
> 
> I used libevdev_enable_event_code() to create ABS_X with a copy
> libevdev_get_abs_info() from ABS_MT_POSITION_X (etc, following the
> mt_axis_mapping table in the code).
> 
> Older applications (XFCE window manager for one) don't get drags but
> perhaps this is b/c they expect actual ABS_X,Y events.

evdev makes that transparent, so it shouldn't matter what events you get.
the client should always receive the same events regardless.
 
> I also get some pretty ominous warnings, but I'm not sure if they
> are related or not!
> 
> libevdev error in sanitize_event: BUG: Device "sec_touchscreen"
> received a double tracking ID 21 in slot 1.
> (EE) [dix] touchscreen: unable to find touch point 0
> (EE) [dix] touchscreen: unable to find touch point 1
> (EE) [dix] touchscreen: unable to find touch point 1
> (EE) [dix] touchscreen: unable to find touch point 1
> (EE) [dix] touchscreen: unable to find touch point 1
> (EE) [dix] touchscreen: unable to find touch point 1
> (EE) [dix] touchscreen: unable to find touch point 1
> libevdev error in sanitize_event: BUG: Device "sec_touchscreen"
> received a double tracking ID 22 in slot 0.
> (EE) [dix] touchscreen: unable to find touch point 0
> (EE) [dix] touchscreen: unable to find touch point 0
> (EE) [dix] touchscreen: unable to find touch point 0
> (EE) [dix] touchscreen: unable to find touch point 0
> (EE) [dix] touchscreen: unable to find touch point 0
> (EE) [dix] touchscreen: unable to find touch point 0
> libevdev error in sanitize_event: BUG: Device "sec_touchscreen"
> received a double tracking ID 24 in slot 3.
> (EE) [dix] touchscreen: unable to find touch point 3
> (EE) [dix] touchscreen: unable to find touch point 3
> (EE) [dix] touchscreen: unable to find touch point 3
> (EE) [dix] touchscreen: unable to find touch point 3
> [dix] EventToCore: Not implemented yet
> [dix] EventToCore: Not implemented yet

that doesn't look good. do you have an evemu recording for this device?

> In case you prefer not to apply this as is, I'm working in "noabsx"
> branch on https://github.com/cbm755/xf86-input-evdev/

tbh, I never prefer github over direct patches. too many clicks to reply
inline or apply patches, aside from anything I reply is stored on some misc
server somewhere that may or may not decide to purge the archives at some
point in the future. mailing lists are archived and mirrored (publicly and
on my box here), which makes it much more trustworthy than some web
interface somewhere.

github is great for a number of things, keeping repos for pulling, but patch
review is not one of those.

> From 9359d756b592ab02af501eac8a70f3826a74a7f0 Mon Sep 17 00:00:00 2001
> From: "Colin B. Macdonald" <macdonald at maths.ox.ac.uk>
> Date: Thu, 26 Jun 2014 21:51:45 +0100
> Subject: [PATCH] Work around devices lacking ABS_X, bug #80470
> 
> ---
>  src/evdev.c | 48 +++++++++++++++++++++++++++++++++++++++++++-----
>  1 file changed, 43 insertions(+), 5 deletions(-)
> 
> diff --git a/src/evdev.c b/src/evdev.c
> index 30f809b..89aae91 100644
> --- a/src/evdev.c
> +++ b/src/evdev.c
> @@ -1218,7 +1218,8 @@ EvdevAddAbsValuatorClass(DeviceIntPtr device, int want_scroll_axes)
>  {
>      InputInfoPtr pInfo;
>      EvdevPtr pEvdev;
> -    int num_axes = 0, axis, i = 0;
> +    int axis, i = 0;
> +    int num_axes = 0; /* number of non-MT axes */
>      int num_mt_axes = 0, /* number of MT-only axes */
>          num_mt_axes_total = 0; /* total number of MT axes, including
>                                    double-counted ones, excluding blacklisted */
> @@ -1231,6 +1232,8 @@ EvdevAddAbsValuatorClass(DeviceIntPtr device, int want_scroll_axes)
>      if (!libevdev_has_event_type(pEvdev->dev, EV_ABS))
>          goto out;
>  
> +    /* Find the number of absolute axis, including MT ones, will
> +       decrease this later. */
>      for (i = 0; i < ABS_MAX; i++)
>          if (libevdev_has_event_code(pEvdev->dev, EV_ABS, i))
>              num_axes++;
> @@ -1239,6 +1242,10 @@ EvdevAddAbsValuatorClass(DeviceIntPtr device, int want_scroll_axes)
>          goto out;
>  
>  #ifdef MULTITOUCH
> +    /* Loop over absolute multitouch axes.  Generate fake axes for
> +       ABS_X etc if kernel doesn't provide.  Adjust the mapping
> +       between for double-counting between ABS_X and ABS_MT_POSITION_X
> +       etc.  Adjust the axes counts. */

right idea, but I think this is too fancy for what we need. Something like
this before the loop should be enough:

/* curse you, android! */
if (libevdev_has_event_code(EV_ABS, ABS_MT_POSITION_X) &&
    !libevdev_has_event_code(EV_ABS, ABS_X))
{
    const struct input_absinfo* abs;
    abs = libevdev_get_abs_info(pEvdev->dev, axis);
    libevdev_enable_event_code(pEvdev->dev, EV_ABS, ABS_X, abs);
    num_axes++;
}

repeat for ABS_Y

That lets the rest of the code do what it already does for devices that
follow the spec, with little interference.

Cheers,
   Peter



>      for (axis = ABS_MT_SLOT; axis < ABS_MAX; axis++)
>      {
>          if (libevdev_has_event_code(pEvdev->dev, EV_ABS, axis))
> @@ -1246,11 +1253,39 @@ EvdevAddAbsValuatorClass(DeviceIntPtr device, int want_scroll_axes)
>              int j;
>              Bool skip = FALSE;
>  
> +            /* Loop over the MT->legacy axis mapping table:
> +               1. if find both ABS_X_POSITION_X and ABS_X: setup mapping
> +               2. if find ABS_X_POSITION_X but not ABS_X: the kernel
> +                  should give us ABS_X etc for backwards compat but
> +                  some devices don't have it.  Add a fake axis, then
> +                  setup mapping. */
>              for (j = 0; j < ArrayLength(mt_axis_mappings); j++)
>              {
> -                if (mt_axis_mappings[j].mt_code == axis &&
> -                    libevdev_has_event_code(pEvdev->dev, EV_ABS, mt_axis_mappings[j].code))
> +                if (mt_axis_mappings[j].mt_code == axis)
>                  {
> +                    /* Have ABS_MT_POSITION_X but not ABS_X: add fake
> +                       ABS_X axis using info from ABS_MT_POSITION_X. */
> +                    if (!libevdev_has_event_code(pEvdev->dev, EV_ABS,
> +                                                 mt_axis_mappings[j].code))
> +                    {
> +                        const struct input_absinfo* abs;
> +                        abs = libevdev_get_abs_info(pEvdev->dev, axis);
> +                        if (libevdev_enable_event_code(pEvdev->dev, EV_ABS,
> +                                                       mt_axis_mappings[j].code, abs))
> +                        {
> +                            xf86IDrvMsg(pInfo, X_ERROR,
> +                                        "Failed at faking axis %d as a copy of axis %d\n",
> +                                        mt_axis_mappings[j].code, axis);
> +                            goto out;
> +                        }
> +                        xf86IDrvMsg(pInfo, X_WARNING,
> +                                    "Faking '%s' (#%d) as a copy of axis '%s' (#%d)\n",
> +                                    abs_labels[mt_axis_mappings[j].code],
> +                                    mt_axis_mappings[j].code,
> +                                    abs_labels[axis], axis);
> +                        num_axes++;
> +                    }
> +                    /* (now) have ABS_MT_POSITION_X and ABS_X: setup the mapping */
>                      mt_axis_mappings[j].needs_mapping = TRUE;
>                      skip = TRUE;
>                  }
> @@ -1265,9 +1300,12 @@ EvdevAddAbsValuatorClass(DeviceIntPtr device, int want_scroll_axes)
>              num_axes--;
>          }
>      }
> +    xf86IDrvMsg(pInfo, X_INFO, "Have %d multitouch, %d non-multitouch axes\n", num_mt_axes, num_axes);
>  
> -    /* device only has mt-axes. the kernel should give us ABS_X etc for
> -       backwards compat but some devices don't have it. */
> +    /* Even after faking ABS_X etc, we still only have mt-axes!
> +       Shouldn't happen any more even if kernel doesn't give ABS_X.
> +       But leaving sanity check here: if triggered, it might indicate
> +       a problem with the mt_axis_apping. */
>      if (num_axes == 0 && num_mt_axes > 0) {
>          xf86IDrvMsg(pInfo, X_ERROR,
>                      "found only multitouch-axes. That shouldn't happen.\n");
> -- 
> 1.9.3
> 



More information about the xorg-devel mailing list