[PATCH evdev 2/3] Add the new valuators for multitouch (rev2)
Peter Hutterer
peter.hutterer at who-t.net
Mon May 31 18:35:30 PDT 2010
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.
> + 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 ...
> + */
> +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).
> + 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