[PATCH evdev 2/3] Add the new valuators for multitouch (rev2)

Benjamin Tissoires tissoire at cena.fr
Tue Jun 1 01:12:17 PDT 2010


Thanks Peter (I also cross send to the right mailing list address as I 
made a mistake the first time I send these patches)

Le 01/06/2010 03:35, Peter Hutterer a écrit :
> On Sun, May 30, 2010 at 03:08:58PM +0200, Benjamin Tissoires wrote:
>> The step one in implementing multitouch in evdev is to report all the
>> touches in different valuators.
>> This patch detects multitouch devices and creates the extra valuators
>> required for multitouch.
>>
>> Bonus point: this patch also sort the multitouch valuators to have
>> ABS_MT_POSISTION_X and ABS_MT_POSISTION_Y at their first position.
>              ^^ typos, but at least they're consistent ;)
>
>>
>> Note that I currently assume that all definitions above ABS_MT_TOUCH_MAJOR
>> and below ABS_MAX are MT-related.
>>
>> Signed-off-by: Benjamin Tissoires<tissoire at cena.fr>
>> ---
>>   src/evdev.c |  177 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
>>   src/evdev.h |    6 ++-
>>   2 files changed, 181 insertions(+), 2 deletions(-)
>>
>> diff --git a/src/evdev.c b/src/evdev.c
>> index 0cf1d3e..10fe81b 100644
>> --- a/src/evdev.c
>> +++ b/src/evdev.c
>> @@ -339,6 +339,8 @@ EvdevQueueButtonClicks(InputInfoPtr pInfo, int button, int count)
>>   #define ABS_X_VALUE 0x1
>>   #define ABS_Y_VALUE 0x2
>>   #define ABS_VALUE   0x4
>> +#define ABS_MT_X_VALUE   0x8
>> +#define ABS_MT_Y_VALUE   0x16
>>   /**
>>    * Take the valuators and process them accordingly.
>>    */
>> @@ -543,6 +545,10 @@ EvdevProcessAbsoluteMotionEvent(InputInfoPtr pInfo, struct input_event *ev)
>>           pEvdev->abs |= ABS_X_VALUE;
>>       else if (ev->code == ABS_Y)
>>           pEvdev->abs |= ABS_Y_VALUE;
>> +    else if (ev->code == ABS_MT_POSITION_X)
>> +        pEvdev->abs |= ABS_MT_X_VALUE;
>> +    else if (ev->code == ABS_MT_POSITION_Y)
>> +        pEvdev->abs |= ABS_MT_Y_VALUE;
>>       else
>>           pEvdev->abs |= ABS_VALUE;
>>   }
>> @@ -704,6 +710,8 @@ EvdevProcessEvent(InputInfoPtr pInfo, struct input_event *ev)
>>   #undef ABS_X_VALUE
>>   #undef ABS_Y_VALUE
>>   #undef ABS_VALUE
>> +#undef ABS_MT_X_VALUE
>> +#undef ABS_MT_Y_VALUE
>>
>>   /* just a magic number to reduce the number of reads */
>>   #define NUM_EVENTS 16
>> @@ -1132,6 +1140,154 @@ EvdevAddKeyClass(DeviceIntPtr device)
>>       return Success;
>>   }
>>
>> +/**
>> + * Count the number of mt-related valuators.
>> + * assume that mt values are in the range
>> + * ABS_MT_TOUCH_MAJOR..ABS_MAX
>> + */
>> +static int
>> +EvdevMTCountValuators(EvdevPtr pEvdev)
>> +{
>> +    int axis;
>> +
>> +    pEvdev->mt_num_valuators = 0;
>> +
>> +    if (!(pEvdev->flags&  EVDEV_MULTITOUCH))
>> +        return 0;
>> +
>> +    for (axis = ABS_MT_TOUCH_MAJOR; axis<= ABS_MAX; axis++) {
>
> As Henrik pointed out this is a problematic assumption. Any reason we can't
> just take the currently highest known MT define and use it? we'll simply
> update when a new kernel comes out with new defines.

You're right, as usual. As you mention after, I'll put 2 define 
EVDEV_FIRST_MT_AXIS and EVDEV_LAST_MT_AXIS. But when the patches Henrik 
send will be upstream, we will use them of course.

>
>> +        if (!TestBit(axis, pEvdev->abs_bitmask))
>> +            continue;
>> +        pEvdev->mt_num_valuators++;
>
> this is misusing continue, you might as well just do a if (TestBit))
> num_valuators++.
>
>> +    }
>> +
>> +    return pEvdev->mt_num_valuators;
>> +}
>> +
>> +/**
>> + * This function counts the number of valuators the device has.
>> + * In case of multitouch device, it adds to this number a set of
>> + * valuators to handle more than one touch.
>> + *
>> + * For instance, two touches can be received as:
>> + *
>> + * Valuator 0: x0
>> + * Valuator 1: y0
>> + * Valuator 2: pressure0
>> + * Valuator 3: x1
>> + * Valuator 4: y1
>> + * Valuator 5: pressure1
>
> I think it'd be good to use other numbers than starting with 0. we're pretty
> much guaranteed that the device has other axes as valuators 0, 1 ...

no problem

>> + */
>> +static int
>> +EvdevMTAddExtraValuators(EvdevPtr pEvdev, int total_num_axes)
>> +{
>> +    int num_axes = 0;
>> +    int mt_num_valuators = 0;
>> +
>> +    if (!(pEvdev->flags&  EVDEV_MULTITOUCH))
>> +        return total_num_axes;
>> +
>> +    mt_num_valuators = EvdevMTCountValuators(pEvdev);
>> +
>> +    /* substract the mt-valuators to total_num_axes
>> +     * to have only the non-mt valuators */
>> +    num_axes = total_num_axes - mt_num_valuators;
>> +
>> +    /* count the maximum number of touchpoints the device can support */
>> +    pEvdev->mt_max_touchpoints = (MAX_VALUATORS - num_axes)
>> +                                                / mt_num_valuators;
>> +
>> +    /* check if the device tells the number of touchpoints
>> +     * it can support. */
>> +    if (TestBit(ABS_MT_TRACKING_ID, pEvdev->abs_bitmask)) {
>> +        int max_id = pEvdev->absinfo[ABS_MT_TRACKING_ID].maximum;
>> +        if (max_id<  pEvdev->mt_max_touchpoints)
>> +            pEvdev->mt_max_touchpoints = max_id;
>> +    }
>> +
>> +    num_axes += pEvdev->mt_max_touchpoints * mt_num_valuators;
>> +
>> +    return num_axes;
>> +}
>> +
>> +/**
>> + * As the first declared mt valuator is ABS_MT_TOUCH_MAJOR, it is then
>                     ^^ this should be "defined", I think
>> + * the first mt-related valuator.
>> + * This function puts ABS_MT_POSITION_X and ABS_MT_POSITION_Y at places
>> + * 0 and 1 in the set of multitouch valuators.
>> + */
>> +static void
>> +EvdevMTSortValuators(EvdevPtr pEvdev)
>> +{
>> +    int axis, tmp_axis_value;
>> +    int first_axis = 0;
>> +    int second_axis = 0;
>> +
>> +    if (!(pEvdev->flags&  EVDEV_MULTITOUCH))
>> +        return;
>> +
>> +    /* find the first and second mt axes */
>> +    for (axis = ABS_MT_TOUCH_MAJOR; axis<= ABS_MAX; axis++) {
>
> same assumption here again, might be best to abstract this with an evdev
> specific define for highest ABS_MT supported.
>
>> +        if (pEvdev->axis_map[axis] == -1)
>> +            continue;
>> +
>> +        if (!first_axis)
>> +            first_axis = axis;
>> +        else if (!second_axis) {
>> +            second_axis = axis;
>> +            break;
>> +        }
>> +    }
>> +
>> +    /* do the actual swap */
>> +    tmp_axis_value = pEvdev->axis_map[first_axis];
>> +    pEvdev->axis_map[first_axis] = pEvdev->axis_map[ABS_MT_POSITION_X];
>> +    pEvdev->axis_map[ABS_MT_POSITION_X] = tmp_axis_value;
>> +
>> +    tmp_axis_value = pEvdev->axis_map[second_axis];
>> +    pEvdev->axis_map[second_axis] = pEvdev->axis_map[ABS_MT_POSITION_Y];
>> +    pEvdev->axis_map[ABS_MT_POSITION_Y] = tmp_axis_value;
>> +}
>> +
>> +/**
>> + * As multitouch devices contains extra axes to enable multitouch,
>> + * they are not initialized in the first init pass. This function
>> + * does the init for those extra valuators.
>> + */
>> +static void
>> +EvdevMTInitValuators(DeviceIntPtr device, Atom *atoms)
>> +{
>> +    InputInfoPtr pInfo;
>> +    EvdevPtr pEvdev;
>> +    int axis, j;
>> +
>> +    pInfo = device->public.devicePrivate;
>> +    pEvdev = pInfo->private;
>> +
>> +    if (!(pEvdev->flags&  EVDEV_MULTITOUCH))
>> +        return;
>> +
>> +    /* Here j starts at 1 as one set of mt-valuators has already been
>> +     * registered */
>> +    for (j = 1; j<  pEvdev->mt_max_touchpoints; j++) {
>> +        for (axis = ABS_MT_TOUCH_MAJOR; axis<= ABS_MAX; axis++) {
>> +            int axnum = pEvdev->axis_map[axis];
>> +            int real_axnum = axnum + j * pEvdev->mt_num_valuators;
>> +            if (axnum == -1)
>> +                continue;
>> +            xf86InitValuatorAxisStruct(device, real_axnum,
>> +    #if GET_ABI_MAJOR(ABI_XINPUT_VERSION)>= 7
>
> no indentation for #ifdef's please.
>
>> +                                       atoms[axnum],
>> +    #endif
>> +                                       pEvdev->absinfo[axis].minimum,
>> +                                       pEvdev->absinfo[axis].maximum,
>> +                                       10000, 0, 10000);
>
> use the kernel resolution here please (see 7bbbce9a834).

oops, that's due to my long time to answer...

Cheers,
Benjamin

>
>
>> +            xf86InitValuatorDefaults(device, real_axnum);
>> +            pEvdev->old_vals[real_axnum] = -1;
>> +        }
>> +    }
>> +}
>> +
>>   static int
>>   EvdevAddAbsClass(DeviceIntPtr device)
>>   {
>> @@ -1149,6 +1305,9 @@ EvdevAddAbsClass(DeviceIntPtr device)
>>       num_axes = CountBits(pEvdev->abs_bitmask, NLONGS(ABS_MAX));
>>       if (num_axes<  1)
>>           return !Success;
>> +
>> +    num_axes = EvdevMTAddExtraValuators(pEvdev, num_axes);
>> +
>>       pEvdev->num_vals = num_axes;
>>       memset(pEvdev->vals, 0, num_axes * sizeof(int));
>>       memset(pEvdev->old_vals, -1, num_axes * sizeof(int));
>> @@ -1162,6 +1321,8 @@ EvdevAddAbsClass(DeviceIntPtr device)
>>           i++;
>>       }
>>
>> +    EvdevMTSortValuators(pEvdev);
>> +
>>       EvdevInitAxesLabels(pEvdev, pEvdev->num_vals, atoms);
>>
>>       if (!InitValuatorClassDeviceStruct(device, num_axes,
>> @@ -1200,6 +1361,8 @@ EvdevAddAbsClass(DeviceIntPtr device)
>>
>>       free(atoms);
>>
>> +    EvdevMTInitValuators(device, atoms);
>> +
>>       if (!InitPtrFeedbackClassDeviceStruct(device, EvdevPtrCtrlProc))
>>           return !Success;
>>
>> @@ -1503,7 +1666,7 @@ EvdevInit(DeviceIntPtr device)
>>
>>       if (pEvdev->flags&  (EVDEV_UNIGNORE_RELATIVE | EVDEV_UNIGNORE_ABSOLUTE))
>>           EvdevInitAnyClass(device, pEvdev);
>> -    else if (pEvdev->flags&  (EVDEV_TOUCHPAD | EVDEV_TOUCHSCREEN | EVDEV_TABLET))
>> +    else if (pEvdev->flags&  (EVDEV_TOUCHPAD | EVDEV_TOUCHSCREEN | EVDEV_TABLET | EVDEV_MULTITOUCH))
>>           EvdevInitTouchDevice(device, pEvdev);
>>       else if (pEvdev->flags&  EVDEV_RELATIVE_EVENTS)
>>           EvdevInitRelClass(device, pEvdev);
>> @@ -1875,6 +2038,15 @@ EvdevProbe(InputInfoPtr pInfo)
>>           xf86Msg(X_PROBED, "%s: Found absolute axes\n", pInfo->name);
>>           pEvdev->flags |= EVDEV_ABSOLUTE_EVENTS;
>>
>> +        if ((TestBit(ABS_MT_POSITION_X, pEvdev->abs_bitmask)&&
>> +                        TestBit(ABS_MT_POSITION_Y, pEvdev->abs_bitmask))) {
>
> align the two TestBits please.
>
>> +            xf86Msg(X_INFO, "%s: Found absolute multitouch device.\n", pInfo->name);
>> +            pEvdev->flags |= EVDEV_MULTITOUCH;
>> +            if (!pEvdev->num_buttons) {
>> +                pEvdev->num_buttons = 7; /* LMR + scroll wheels */
>> +                pEvdev->flags |= EVDEV_BUTTON_EVENTS;
>> +            }
>> +        }
>>           if ((TestBit(ABS_X, pEvdev->abs_bitmask)&&
>>                TestBit(ABS_Y, pEvdev->abs_bitmask))) {
>>               xf86Msg(X_PROBED, "%s: Found x and y absolute axes\n", pInfo->name);
>> @@ -1947,6 +2119,9 @@ EvdevProbe(InputInfoPtr pInfo)
>>           } else if (pEvdev->flags&  EVDEV_TOUCHSCREEN) {
>>               xf86Msg(X_INFO, "%s: Configuring as touchscreen\n", pInfo->name);
>>               pInfo->type_name = XI_TOUCHSCREEN;
>> +	} else if (pEvdev->flags&  EVDEV_MULTITOUCH) {
>> +	    xf86Msg(X_INFO, "%s: Configuring as multitouch device\n", pInfo->name);
>> +	    pInfo->type_name = "MULTITOUCHDEVICE";
>
> this should probably be a define, so we can add it to XI in due time.
>
> Cheers,
>    Peter
>
>>   	} else {
>>   	    xf86Msg(X_INFO, "%s: Configuring as mouse\n", pInfo->name);
>>   	    pInfo->type_name = XI_MOUSE;
>> diff --git a/src/evdev.h b/src/evdev.h
>> index 8c89f83..852f06c 100644
>> --- a/src/evdev.h
>> +++ b/src/evdev.h
>> @@ -71,6 +71,7 @@
>>   #define EVDEV_UNIGNORE_ABSOLUTE (1<<  9) /* explicitly unignore abs axes */
>>   #define EVDEV_UNIGNORE_RELATIVE (1<<  10) /* explicitly unignore rel axes */
>>   #define EVDEV_RELATIVE_MODE	(1<<  11) /* Force relative events for devices with absolute axes */
>> +#define EVDEV_MULTITOUCH	(1<<  12) /* device looks like a multi-touch screen? */
>>
>>   #if GET_ABI_MAJOR(ABI_XINPUT_VERSION)>= 3
>>   #define HAVE_PROPERTIES 1
>> @@ -80,7 +81,6 @@
>>   #define MAX_VALUATORS 36
>>   #endif
>>
>> -
>>   #if GET_ABI_MAJOR(ABI_XINPUT_VERSION)<  5
>>   typedef struct {
>>       char *rules;
>> @@ -193,6 +193,10 @@ typedef struct {
>>       /* Event queue used to defer keyboard/button events until EV_SYN time. */
>>       int                     num_queue;
>>       EventQueueRec           queue[EVDEV_MAXQUEUE];
>> +
>> +    unsigned int mt_num_valuators;
>> +    unsigned int mt_max_touchpoints; /* the number of simultaneous touchpoints
>> +                                      * the device can support */
>>   } EvdevRec, *EvdevPtr;
>>
>>   /* Event posting functions */
>> --
>> 1.7.0.1
>>


More information about the xorg-devel mailing list