[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