Dear All,
this is the patch I submitted to Petter a few weeks ago. I post it on
the mailing list to show you my work, but I will send a second mail for
the explanations and discussions.
Cheers,
Benjamin
>From cf15aa4dd7e2f685f783f5fb6a9a72c2bc1d32d9 Mon Sep 17 00:00:00 2001
From: Benjamin Tissoires <[email protected]>
Date: Sat, 19 Dec 2009 10:27:27 +0100
Subject: [PATCH evdev 1/7] modifying evdev.h to be ready for multitouch : adding a struct to store the mt events
Signed-off-by: Benjamin Tissoires <[email protected]>
---
src/evdev.h | 37 +++++++++++++++++++++++++++++++++++++
1 files changed, 37 insertions(+), 0 deletions(-)
diff --git a/src/evdev.h b/src/evdev.h
index 95d00db..54cd74b 100644
--- a/src/evdev.h
+++ b/src/evdev.h
@@ -65,6 +65,11 @@
#define MAX_VALUATORS 36
#endif
+/* MT related */
+#define MAX_VALUATORS_MT 5 //currently if MAXDEVICES == 40
+#define DEFAULT_MT_TIMEOUT 100
+#define EVDEV_PROP_TRACKING_ID "Evdev Tracking ID"
+#define EVDEV_PROP_MULTITOUCH_SUBDEVICES "Evdev MultiTouch"
#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) < 5
typedef struct {
@@ -89,6 +94,15 @@ typedef struct {
int traveled_distance;
} WheelAxis, *WheelAxisPtr;
+/* struct used to store MT events until the EV_SYNC. */
+typedef struct _EvdevDataMTRec{
+ int id;
+ BOOL containsValues;
+ Time expires;
+ int vals[MAX_VALUATORS];
+ InputInfoPtr pInfo;
+} EvdevDataMTRec, *EvdevDataMTPtr;
+
/* Event queue used to defer keyboard/button events until EV_SYN time. */
typedef struct {
enum {
@@ -178,6 +192,29 @@ typedef struct {
/* Event queue used to defer keyboard/button events until EV_SYN time. */
int num_queue;
EventQueueRec queue[EVDEV_MAXQUEUE];
+
+ /* mt related */
+ /* used to store MT events until the EV_SYNC. */
+ EvdevDataMTRec vals_mt[MAX_VALUATORS_MT];
+ /* flag that tells whether mt was send during the sequence. */
+ unsigned int mt;
+ /* the number of subdevice we have for mt. */
+ unsigned int num_multitouch;
+ /* the maximum time between two events to consider a mt event as released. */
+ Time timeout;
+
+ OsTimerPtr subdevice_timer;
+
+ /* to store the trackID. */
+ int current_id;
+
+ /* as the N-Trig does not track the touches, we need to reconstruct a trckingID. */
+ int id;
+ int num_mt;
+
+ /* the reference of the main mt device. */
+ InputInfoPtr core_device;
+
} EvdevRec, *EvdevPtr;
/* Event posting functions */
--
1.6.5.2
>From a8f68e23efa79c785c48c1b25ad90e911bff4bcd Mon Sep 17 00:00:00 2001
From: Benjamin Tissoires <[email protected]>
Date: Sat, 19 Dec 2009 11:04:24 +0100
Subject: [PATCH evdev 2/7] detection of multitouch devices and adding the "Evdev Tracking ID" property
Signed-off-by: Benjamin Tissoires <[email protected]>
---
src/evdev.c | 51 ++++++++++++++++++++++++++++++++++++++++++++++-----
1 files changed, 46 insertions(+), 5 deletions(-)
diff --git a/src/evdev.c b/src/evdev.c
index 7e65c69..470a3f7 100644
--- a/src/evdev.c
+++ b/src/evdev.c
@@ -92,6 +92,7 @@
#define EVDEV_TABLET (1 << 8) /* device looks like a tablet? */
#define EVDEV_UNIGNORE_ABSOLUTE (1 << 9) /* explicitly unignore abs axes */
#define EVDEV_UNIGNORE_RELATIVE (1 << 10) /* explicitly unignore rel axes */
+#define EVDEV_MULTITOUCH (1 << 11) /* device looks like a multi-touch screen? */
#define MIN_KEYCODE 8
#define GLYPHS_PER_KEY 2
@@ -129,6 +130,7 @@ static Atom prop_calibration = 0;
static Atom prop_swap = 0;
static Atom prop_axis_label = 0;
static Atom prop_btn_label = 0;
+static Atom prop_tracking_id = 0;
#endif
/* All devices the evdev driver has allocated and knows about.
@@ -328,6 +330,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.
*/
@@ -533,6 +537,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;
}
@@ -1464,7 +1472,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);
@@ -1855,6 +1863,15 @@ EvdevProbe(InputInfoPtr pInfo)
pEvdev->num_buttons = 7; /* LMR + scroll wheels */
pEvdev->flags |= EVDEV_BUTTON_EVENTS;
}
+ } else if ((TestBit(ABS_MT_POSITION_X, pEvdev->abs_bitmask) &&
+ TestBit(ABS_MT_POSITION_Y, pEvdev->abs_bitmask))) {
+ xf86Msg(X_INFO, "%s: Found absolute multitouch tablet.\n", pInfo->name);
+ pEvdev->flags |= EVDEV_MULTITOUCH;
+ if (!pEvdev->num_buttons)
+ {
+ pEvdev->num_buttons = 7; /* LMR + scroll wheels */
+ pEvdev->flags |= EVDEV_BUTTON_EVENTS;
+ }
} else if (TestBit(ABS_PRESSURE, pEvdev->abs_bitmask) ||
TestBit(BTN_TOUCH, pEvdev->key_bitmask)) {
if (num_buttons || TestBit(BTN_TOOL_FINGER, pEvdev->key_bitmask)) {
@@ -1891,10 +1908,13 @@ 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 {
- xf86Msg(X_INFO, "%s: Configuring as mouse\n", pInfo->name);
- pInfo->type_name = XI_MOUSE;
- }
+ } else if (pEvdev->flags & EVDEV_MULTITOUCH) {
+ xf86Msg(X_INFO, "%s: Configuring as multitouch screen\n", pInfo->name);
+ pInfo->type_name = "MULTITOUCHSCREEN";
+ } else {
+ xf86Msg(X_INFO, "%s: Configuring as mouse\n", pInfo->name);
+ pInfo->type_name = XI_MOUSE;
+ }
}
if (has_keys) {
@@ -2454,6 +2474,19 @@ EvdevInitProperty(DeviceIntPtr dev)
return;
XISetDevicePropertyDeletable(dev, prop_swap, FALSE);
+
+ if (pEvdev->flags & EVDEV_MULTITOUCH)
+ {
+ /* tracking ids for mt */
+ prop_tracking_id = MakeAtom(EVDEV_PROP_TRACKING_ID,
+ strlen(EVDEV_PROP_TRACKING_ID), TRUE);
+ rc = XIChangeDeviceProperty(dev, prop_tracking_id, XA_INTEGER, 32,
+ PropModeReplace, 1, &pEvdev->id, FALSE);
+ if (rc != Success)
+ return;
+
+ XISetDevicePropertyDeletable(dev, prop_tracking_id, FALSE);
+ }
#ifdef HAVE_LABELS
/* Axis labelling */
@@ -2516,6 +2549,14 @@ EvdevSetProperty(DeviceIntPtr dev, Atom atom, XIPropertyValuePtr val,
pEvdev->swap_axes = *((BOOL*)val->data);
} else if (atom == prop_axis_label || atom == prop_btn_label)
return BadAccess; /* Axis/Button labels can't be changed */
+ else if (atom == prop_tracking_id)
+ {
+ if (val->format != 32 || val->type != XA_INTEGER || val->size != 1)
+ return BadMatch;
+
+ if (!checkonly)
+ pEvdev->id = *((int*)val->data);
+ }
return Success;
}
--
1.6.5.2
>From 6f9ccd2075fb8e047c5109982e7b1c2fa6345c82 Mon Sep 17 00:00:00 2001
From: Benjamin Tissoires <[email protected]>
Date: Sat, 19 Dec 2009 11:17:36 +0100
Subject: [PATCH evdev 3/7] take the tracking ID event into account
Signed-off-by: Benjamin Tissoires <[email protected]>
---
src/evdev.c | 18 +++++++++++++++++-
1 files changed, 17 insertions(+), 1 deletions(-)
diff --git a/src/evdev.c b/src/evdev.c
index 470a3f7..bf0b792 100644
--- a/src/evdev.c
+++ b/src/evdev.c
@@ -677,6 +677,18 @@ EvdevProcessSyncEvent(InputInfoPtr pInfo, struct input_event *ev)
}
/**
+ * Take the trackingID input event and process it accordingly.
+ */
+static void
+EvdevProcessTrackingIDEvent(InputInfoPtr pInfo, struct input_event *ev)
+{
+ // begining of a new touch
+ EvdevPtr pEvdev = pInfo->private;
+
+ pEvdev->current_id = ev->value;
+}
+
+/**
* Process the events from the device; nothing is actually posted to the server
* until an EV_SYN event is received.
*/
@@ -688,7 +700,11 @@ EvdevProcessEvent(InputInfoPtr pInfo, struct input_event *ev)
EvdevProcessRelativeMotionEvent(pInfo, ev);
break;
case EV_ABS:
- EvdevProcessAbsoluteMotionEvent(pInfo, ev);
+ if (ev->code == ABS_MT_TRACKING_ID){
+ EvdevProcessTrackingIDEvent(pInfo, ev);
+ } else {
+ EvdevProcessAbsoluteMotionEvent(pInfo, ev);
+ }
break;
case EV_KEY:
EvdevProcessKeyEvent(pInfo, ev);
--
1.6.5.2
>From c9b3256c060cdb825f04ba19f8ef5823e3de94c8 Mon Sep 17 00:00:00 2001
From: Benjamin Tissoires <[email protected]>
Date: Sat, 19 Dec 2009 12:20:50 +0100
Subject: [PATCH evdev 4/7] adding to evdev the virtual subdevices that manage the multitouch part
Signed-off-by: Benjamin Tissoires <[email protected]>
---
src/evdev.c | 138 +++++++++++++++++++++++++++++++++++++++++++++++++++++++---
1 files changed, 130 insertions(+), 8 deletions(-)
diff --git a/src/evdev.c b/src/evdev.c
index bf0b792..fb5c5c9 100644
--- a/src/evdev.c
+++ b/src/evdev.c
@@ -170,6 +170,12 @@ EvdevGetMajorMinor(InputInfoPtr pInfo)
return st.st_rdev;
}
+static BOOL
+EvdevIsCoreDevice(InputInfoPtr pInfo) {
+ EvdevPtr pEvdev = pInfo->private;
+ return pEvdev->core_device == pInfo;
+}
+
/**
* Return TRUE if one of the devices we know about has the same min/maj
* number.
@@ -722,6 +728,14 @@ EvdevProcessEvent(InputInfoPtr pInfo, struct input_event *ev)
/* just a magic number to reduce the number of reads */
#define NUM_EVENTS 16
+/**
+ * Empty callback for subdevice.
+ */
+static void
+EvdevSubdevReadInput(InputInfoPtr pInfo) {
+ return;
+}
+
static void
EvdevReadInput(InputInfoPtr pInfo)
{
@@ -1510,6 +1524,27 @@ EvdevInit(DeviceIntPtr device)
}
/**
+ * For the subdev: Init all extras (wheel emulation, etc.) and grab the device.
+ */
+static int
+EvdevSubdevOn(DeviceIntPtr device)
+{
+ InputInfoPtr pInfo;
+ EvdevPtr pEvdev;
+
+ pInfo = device->public.devicePrivate;
+ pEvdev = pInfo->private;
+
+ xf86AddEnabledDevice(pInfo);
+ EvdevMBEmuOn(pInfo);
+ pEvdev->flags |= EVDEV_INITIALIZED;
+ device->public.on = TRUE;
+
+ return Success;
+}
+
+
+/**
* Init all extras (wheel emulation, etc.) and grab the device.
*/
static int
@@ -1572,19 +1607,41 @@ EvdevProc(DeviceIntPtr device, int what)
return EvdevInit(device);
case DEVICE_ON:
- return EvdevOn(device);
+ if (EvdevIsCoreDevice(pInfo))
+ return EvdevOn(device);
+ else
+ return EvdevSubdevOn(device);
case DEVICE_OFF:
if (pEvdev->flags & EVDEV_INITIALIZED)
EvdevMBEmuFinalize(pInfo);
- if (pInfo->fd != -1)
- {
- if (pEvdev->grabDevice && ioctl(pInfo->fd, EVIOCGRAB, (void *)0))
- xf86Msg(X_WARNING, "%s: Release failed (%s)\n", pInfo->name,
- strerror(errno));
+ if (EvdevIsCoreDevice(pInfo)){
+ if (pInfo->fd != -1)
+ {
+ if (pEvdev->grabDevice && ioctl(pInfo->fd, EVIOCGRAB, (void *)0))
+ xf86Msg(X_WARNING, "%s: Release failed (%s)\n", pInfo->name,
+ strerror(errno));
+ xf86RemoveEnabledDevice(pInfo);
+ close(pInfo->fd);
+ pInfo->fd = -1;
+ }
+ if (pEvdev->subdevice_timer)
+ {
+ TimerFree(pEvdev->subdevice_timer);
+ pEvdev->subdevice_timer = NULL;
+ }
+ } else {
+ /* subdevice: removing it in the list of the core device */
+ EvdevPtr g_pEvdev;
+ int i;
+ g_pEvdev = pEvdev->core_device->private;
+ for (i=0; i<MAX_VALUATORS_MT; ++i) {
+ if (g_pEvdev->vals_mt[i].pInfo == pInfo) {
+ g_pEvdev->vals_mt[i].pInfo = NULL;
+ break;
+ }
+ }
xf86RemoveEnabledDevice(pInfo);
- close(pInfo->fd);
- pInfo->fd = -1;
}
pEvdev->min_maj = 0;
pEvdev->flags &= ~EVDEV_INITIALIZED;
@@ -1593,11 +1650,13 @@ EvdevProc(DeviceIntPtr device, int what)
case DEVICE_CLOSE:
xf86Msg(X_INFO, "%s: Close\n", pInfo->name);
+ if (EvdevIsCoreDevice(pInfo)) { // core mt only
if (pInfo->fd != -1) {
close(pInfo->fd);
pInfo->fd = -1;
}
EvdevRemoveDevice(pInfo);
+ }
pEvdev->min_maj = 0;
break;
}
@@ -1983,16 +2042,66 @@ EvdevSetCalibration(InputInfoPtr pInfo, int num_calibration, int calibration[4])
}
static InputInfoPtr
+EvdevSubdevPreInit(InputInfoPtr pInfo, InputDriverPtr drv, IDevPtr dev, int flags)
+{
+ EvdevPtr pEvdev;
+
+ /* Initialise the InputInfoRec. */
+ pInfo->name = dev->identifier;
+ pInfo->flags = 0;
+ pInfo->type_name = "UNKNOWN";
+ pInfo->device_control = EvdevProc;
+ pInfo->history_size = 0;
+ pInfo->control_proc = NULL;
+ pInfo->close_proc = NULL;
+ pInfo->read_input = EvdevSubdevReadInput;
+ pInfo->switch_mode = NULL;
+ pInfo->conversion_proc = NULL;
+ pInfo->reverse_conversion_proc = NULL;
+ pInfo->dev = NULL;
+ pInfo->private_flags = 0;
+ pInfo->always_core_feedback = NULL;
+ pInfo->conf_idev = dev;
+
+ if (!(pEvdev = xcalloc(sizeof(EvdevRec), 1)))
+ return pInfo;
+
+ pInfo->private = pEvdev;
+
+ xf86CollectInputOptions(pInfo, evdevDefaults, NULL);
+ xf86ProcessCommonOptions(pInfo, pInfo->options);
+ pEvdev->id = -1;
+
+ xf86Msg(X_INFO, "%s: Evdev subdevice found\n", dev->identifier);
+ // FIXME: need to duplicate the parent device
+
+ pInfo->flags |= XI86_CONFIGURED;
+ pEvdev->num_multitouch = 1;
+
+ return pInfo;
+}
+
+static InputInfoPtr
EvdevPreInit(InputDriverPtr drv, IDevPtr dev, int flags)
{
InputInfoPtr pInfo;
const char *device, *str;
int num_calibration = 0, calibration[4] = { 0, 0, 0, 0 };
EvdevPtr pEvdev;
+ char *type;
if (!(pInfo = xf86AllocateInput(drv, 0)))
return NULL;
+ /* If Type == Object, this is a subdevice for an object to use */
+ type = xf86CheckStrOption(dev->commonOptions, "Type", NULL);
+
+ xf86Msg(X_INFO, "%s: Evdev Type %s found\n", dev->identifier,type);
+
+ if (type != NULL && strcmp(type, "Object") == 0) {
+ return EvdevSubdevPreInit(pInfo, drv, dev, flags);
+ }
+
/* Initialise the InputInfoRec. */
pInfo->name = dev->identifier;
pInfo->flags = 0;
@@ -2017,6 +2126,10 @@ EvdevPreInit(InputDriverPtr drv, IDevPtr dev, int flags)
xf86CollectInputOptions(pInfo, evdevDefaults, NULL);
xf86ProcessCommonOptions(pInfo, pInfo->options);
+
+ /* mt initializations. */
+ pEvdev->id = -1;
+ pEvdev->core_device = pInfo;
/*
* We initialize pEvdev->tool to 1 so that device that doesn't use
@@ -2077,6 +2190,15 @@ EvdevPreInit(InputDriverPtr drv, IDevPtr dev, int flags)
Note that this needs a server that sets the console to RAW mode. */
pEvdev->grabDevice = xf86CheckBoolOption(dev->commonOptions, "GrabDevice", 0);
+ /* Get setting for checking wether a touch is still alive */
+ pEvdev->timeout = xf86CheckIntOption(dev->commonOptions,
+ "SubdevTimeout", DEFAULT_MT_TIMEOUT);
+ if (pEvdev->timeout < 1) {
+ pEvdev->timeout = 1;
+ }
+ xf86Msg(X_INFO, "%s: SubdevTimeout set to %d\n",
+ dev->identifier, (int)pEvdev->timeout);
+
EvdevInitButtonMapping(pInfo);
if (EvdevCacheCompare(pInfo, FALSE) ||
--
1.6.5.2
>From 92a60fc6f9b1a872a0b028f80e496d850ffaa1e0 Mon Sep 17 00:00:00 2001
From: Benjamin Tissoires <[email protected]>
Date: Sat, 19 Dec 2009 12:34:48 +0100
Subject: [PATCH evdev 5/7] Handling the creation / destruction of mt subdevices by the property "Evdev MultiTouch"
Signed-off-by: Benjamin Tissoires <[email protected]>
---
src/evdev.c | 169 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 files changed, 167 insertions(+), 2 deletions(-)
diff --git a/src/evdev.c b/src/evdev.c
index fb5c5c9..3722a1c 100644
--- a/src/evdev.c
+++ b/src/evdev.c
@@ -118,6 +118,7 @@ static const char *evdevDefaults[] = {
static int EvdevOn(DeviceIntPtr);
static int EvdevCacheCompare(InputInfoPtr pInfo, BOOL compare);
static void EvdevKbdCtrl(DeviceIntPtr device, KeybdCtrl *ctrl);
+static void EvdevSetMultitouch(InputInfoPtr pInfo, int num_multitouch);
#ifdef HAVE_PROPERTIES
static void EvdevInitAxesLabels(EvdevPtr pEvdev, int natoms, Atom *atoms);
@@ -131,8 +132,11 @@ static Atom prop_swap = 0;
static Atom prop_axis_label = 0;
static Atom prop_btn_label = 0;
static Atom prop_tracking_id = 0;
+static Atom prop_multitouch = 0;
#endif
+static InputInfoPtr pCreatorInfo = NULL;
+
/* All devices the evdev driver has allocated and knows about.
* MAXDEVICES is safe as null-terminated array, as two devices (VCP and VCK)
* cannot be used by evdev, leaving us with a space of 2 at the end. */
@@ -1583,6 +1587,7 @@ EvdevOn(DeviceIntPtr device)
}
xf86FlushInput(pInfo->fd);
+ EvdevSetMultitouch(pInfo, pEvdev->num_multitouch);
xf86AddEnabledDevice(pInfo);
EvdevMBEmuOn(pInfo);
pEvdev->flags |= EVDEV_INITIALIZED;
@@ -1616,6 +1621,7 @@ EvdevProc(DeviceIntPtr device, int what)
if (pEvdev->flags & EVDEV_INITIALIZED)
EvdevMBEmuFinalize(pInfo);
if (EvdevIsCoreDevice(pInfo)){
+ EvdevSetMultitouch(pInfo, 0);
if (pInfo->fd != -1)
{
if (pEvdev->grabDevice && ioctl(pInfo->fd, EVIOCGRAB, (void *)0))
@@ -2045,6 +2051,7 @@ static InputInfoPtr
EvdevSubdevPreInit(InputInfoPtr pInfo, InputDriverPtr drv, IDevPtr dev, int flags)
{
EvdevPtr pEvdev;
+ EvdevPtr pCreatorEvdev;
/* Initialise the InputInfoRec. */
pInfo->name = dev->identifier;
@@ -2072,9 +2079,14 @@ EvdevSubdevPreInit(InputInfoPtr pInfo, InputDriverPtr drv, IDevPtr dev, int flag
xf86ProcessCommonOptions(pInfo, pInfo->options);
pEvdev->id = -1;
+ if (!pCreatorInfo){
+ return pInfo;
+ }
+ pCreatorEvdev = pCreatorInfo->private;
+ memcpy(pEvdev, pCreatorEvdev, sizeof(EvdevRec));
+ pInfo->type_name = pCreatorInfo->type_name;
xf86Msg(X_INFO, "%s: Evdev subdevice found\n", dev->identifier);
- // FIXME: need to duplicate the parent device
-
+
pInfo->flags |= XI86_CONFIGURED;
pEvdev->num_multitouch = 1;
@@ -2624,6 +2636,17 @@ EvdevInitProperty(DeviceIntPtr dev)
return;
XISetDevicePropertyDeletable(dev, prop_tracking_id, FALSE);
+
+ /* The number of multitouch subdevices.
+ * If 0, we emulate a touchscreen. */
+ prop_multitouch = MakeAtom(EVDEV_PROP_MULTITOUCH_SUBDEVICES,
+ strlen(EVDEV_PROP_MULTITOUCH_SUBDEVICES), TRUE);
+ rc = XIChangeDeviceProperty(dev, prop_multitouch, XA_INTEGER, 8,
+ PropModeReplace, 1, &pEvdev->num_multitouch, FALSE);
+ if (rc != Success)
+ return;
+
+ XISetDevicePropertyDeletable(dev, prop_multitouch, FALSE);
}
#ifdef HAVE_LABELS
@@ -2694,8 +2717,150 @@ EvdevSetProperty(DeviceIntPtr dev, Atom atom, XIPropertyValuePtr val,
if (!checkonly)
pEvdev->id = *((int*)val->data);
+ } else if (atom == prop_multitouch)
+ {
+ BOOL data;
+ if (val->format != 8 || val->type != XA_INTEGER || val->size != 1)
+ return BadMatch;
+ if (!checkonly) {
+ data = *((BOOL*)val->data);
+ if (pEvdev->num_multitouch != data)
+ EvdevSetMultitouch(pInfo,data);
+ }
}
return Success;
}
#endif
+
+/* Duplicate xf86 options and convert them to InputOption */
+static InputOption *EvdevOptionDupConvert(pointer original)
+{
+ InputOption *iopts = NULL, *new;
+ InputInfoRec dummy;
+
+
+ memset(&dummy, 0, sizeof(dummy));
+ xf86CollectInputOptions(&dummy, NULL, original);
+
+ while(dummy.options)
+ {
+ new = xcalloc(1, sizeof(InputOption));
+
+ new->key = xf86OptionName(dummy.options);
+ new->value = xf86OptionValue(dummy.options);
+
+ new->next = iopts;
+ iopts = new;
+ dummy.options = xf86NextOption(dummy.options);
+ }
+ return iopts;
+}
+static void EvdevFreeInputOpts(InputOption* opts)
+{
+ InputOption *tmp = opts;
+
+ while(opts)
+ {
+ tmp = opts->next;
+ xfree(opts->key);
+ xfree(opts->value);
+ xfree(opts);
+ opts = tmp;
+ }
+}
+static void EvdevReplaceOption(InputOption *opts,const char* key, char * value)
+{
+
+ while(opts)
+ {
+ if (xf86NameCmp(opts->key, key) == 0)
+ {
+
+ xfree(opts->value);
+ opts->value = strdup(value);
+ }
+ opts = opts->next;
+ }
+}
+
+/**
+ * New device creation through xorg/input
+ *
+ * @return 0 if successful, 1 if failure
+ */
+static InputInfoPtr
+EvdevCreateSubDevice(InputInfoPtr pInfo, int id) {
+ InputInfoPtr pSubdev;
+
+ DeviceIntPtr dev; /* dummy */
+ InputOption *input_options = NULL;
+ char* name;
+
+
+ pInfo->options = xf86AddNewOption(pInfo->options, "Type", "core");
+ pInfo->options = xf86AddNewOption(pInfo->options, "SendCoreEvents", "on");
+
+ /* Create new device */
+
+ input_options = EvdevOptionDupConvert(pInfo->options);
+
+ EvdevReplaceOption(input_options, "type","Object");
+
+ //EvdevReplaceOption(input_options, "SendCoreEvents","off"); //FIXME: bug in xserver
+ name = xalloc( (strlen(pInfo->name) + strlen(" subdev ") + 20 )*sizeof(char)); // 20 for adding the id
+ sprintf(name, "%s subdev %i", pInfo->name, id);
+ EvdevReplaceOption(input_options, "name",name);
+
+ pCreatorInfo = pInfo;
+ NewInputDeviceRequest(input_options, &dev);
+ pSubdev = dev->public.devicePrivate;
+ pCreatorInfo = NULL;
+
+ EvdevFreeInputOpts(input_options);
+
+ xfree(name);
+ return pSubdev;
+}
+static void
+EvdevDeleteSubDevice(InputInfoPtr pInfo, InputInfoPtr subdev) {
+ /* We need to explicitely flush the events so as not deleting
+ * a device that still has events in queue
+ */
+ ProcessInputEvents();
+ xf86Msg(X_INFO, "%s: Removing subdevice %s\n", pInfo->name,subdev->name);
+ DeleteInputDeviceRequest(subdev->dev);
+}
+
+/*
+ * Handle the creation/destruction of subdevices
+ * according to pEvdev->num_multitouch.
+ */
+static void
+EvdevSetMultitouch(InputInfoPtr pInfo, int num_multitouch) {
+ EvdevPtr pEvdev = pInfo->private;
+ int i;
+
+ if (num_multitouch > MAX_VALUATORS_MT)
+ num_multitouch = MAX_VALUATORS_MT;
+ if (num_multitouch < 0)
+ num_multitouch = 0;
+
+ for (i=0;i<num_multitouch;++i) {
+ if (pEvdev->vals_mt[i].pInfo == NULL){
+ pEvdev->vals_mt[i].containsValues = FALSE;
+ pEvdev->vals_mt[i].id = -1;
+ pEvdev->vals_mt[i].pInfo = EvdevCreateSubDevice(pInfo, i);
+ }
+ }
+ for (i=num_multitouch;i<MAX_VALUATORS_MT;++i) {
+ pEvdev->vals_mt[i].containsValues = FALSE;
+ pEvdev->vals_mt[i].id = -1;
+ if (pEvdev->vals_mt[i].pInfo) {
+ EvdevDeleteSubDevice(pInfo, pEvdev->vals_mt[i].pInfo);
+ pEvdev->vals_mt[i].pInfo = NULL;
+ }
+ }
+
+ pEvdev->num_multitouch = num_multitouch;
+}
--
1.6.5.2
>From 2253d6e23e642ae3e93b1ea09b118955033b6800 Mon Sep 17 00:00:00 2001
From: Benjamin Tissoires <[email protected]>
Date: Sat, 19 Dec 2009 12:59:45 +0100
Subject: [PATCH evdev 6/7] Process of MT events:
* at each MTSyncReport, copy the valuators into the EvdevDataMT (in pEvdev->vals_mt) tha has the same trackingID.
* when receiving the EV_SYNC, if there were some multitouch events and the multitouch is activated, the driver generates all the known touches through their own subdevices by duplicating their valuators into the main one and by calling again "EvdevProcessSyncEvent" without the mutlitouch flag
Signed-off-by: Benjamin Tissoires <[email protected]>
---
src/evdev.c | 221 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
1 files changed, 210 insertions(+), 11 deletions(-)
diff --git a/src/evdev.c b/src/evdev.c
index 3722a1c..befb1d4 100644
--- a/src/evdev.c
+++ b/src/evdev.c
@@ -118,6 +118,10 @@ static const char *evdevDefaults[] = {
static int EvdevOn(DeviceIntPtr);
static int EvdevCacheCompare(InputInfoPtr pInfo, BOOL compare);
static void EvdevKbdCtrl(DeviceIntPtr device, KeybdCtrl *ctrl);
+static void EvdevProcessSyncEvent(InputInfoPtr pInfo, struct input_event *ev);
+static void EvdevCopyFromData(InputInfoPtr pInfo, EvdevDataMTPtr pData);
+static void EvdevProcessEvent(InputInfoPtr pInfo, struct input_event *ev);
+static void EvdevEndOfMultiTouch(InputInfoPtr pInfo,EvdevDataMTPtr pData);
static void EvdevSetMultitouch(InputInfoPtr pInfo, int num_multitouch);
#ifdef HAVE_PROPERTIES
@@ -337,6 +341,26 @@ EvdevQueueButtonClicks(InputInfoPtr pInfo, int button, int count)
}
}
+/**
+ * Timer called to know whether a touch is still alive.
+ */
+static CARD32
+EvdevSubdevTimer(OsTimerPtr timer, CARD32 time, pointer arg)
+{
+ InputInfoPtr pInfo = (InputInfoPtr)arg;
+ EvdevPtr pEvdev = pInfo->private;
+ int i;
+
+ for (i=0;i<pEvdev->num_multitouch;i++) {
+ if (pEvdev->vals_mt[i].containsValues) {
+ EvdevEndOfMultiTouch(pInfo, &(pEvdev->vals_mt[i]));
+ }
+ }
+
+ return 0;
+ //return pEvdev->timeout; /* come back in 100 ms */
+}
+
#define ABS_X_VALUE 0x1
#define ABS_Y_VALUE 0x2
#define ABS_VALUE 0x4
@@ -466,6 +490,10 @@ EvdevProcessButtonEvent(InputInfoPtr pInfo, struct input_event *ev)
if (EvdevWheelEmuFilterButton(pInfo, button, value))
return;
+ /* if multitouch enabled, drop Buttons as they are treated by the tracking ID. */
+ if (pEvdev->num_multitouch)
+ return;
+
if (EvdevMBEmuFilterEvent(pInfo, button, value))
return;
@@ -586,7 +614,7 @@ EvdevProcessKeyEvent(InputInfoPtr pInfo, struct input_event *ev)
case BTN_TOUCH:
pEvdev->tool = value ? ev->code : 0;
- if (!(pEvdev->flags & (EVDEV_TOUCHSCREEN | EVDEV_TABLET)))
+ if (!(pEvdev->flags & (EVDEV_TOUCHSCREEN | EVDEV_TABLET | EVDEV_MULTITOUCH)))
break;
/* Treat BTN_TOUCH from devices that only have BTN_TOUCH as
* BTN_LEFT. */
@@ -599,6 +627,67 @@ EvdevProcessKeyEvent(InputInfoPtr pInfo, struct input_event *ev)
}
}
+static void
+EvdevEndOfMultiTouch(InputInfoPtr pInfo,EvdevDataMTPtr pData)
+{
+ InputInfoPtr pSubdev = pData->pInfo;
+ EvdevPtr pEvdevSubdev = pSubdev->private;
+ pEvdevSubdev->id = -1;
+ XIChangeDeviceProperty(pSubdev->dev, prop_tracking_id, XA_INTEGER, 32,
+ PropModeReplace, 1, &(pEvdevSubdev->id), TRUE);
+
+ pData->containsValues = FALSE;
+ pData->id = -1;
+}
+
+/**
+ * Post the multitouch motion events.
+ */
+static void
+EvdevPostMTMotionEvents(InputInfoPtr pInfo,struct input_event *ev)
+{
+ EvdevPtr pEvdev = pInfo->private, pEvdevSubdev;
+ EvdevDataMTPtr pData;
+ InputInfoPtr pSubdev;
+ Time currentTime = GetTimeInMillis();
+ int i;
+
+ for (i=0;i<pEvdev->num_multitouch;++i) {
+ pData = &(pEvdev->vals_mt[i]);
+ if (!pData->containsValues) {
+ continue;
+ }
+ pSubdev = pData->pInfo;
+ if (!pSubdev)
+ continue;
+
+
+ if (currentTime > pData->expires) {
+ /* the MT-touch has ended, destroy the subdevice. */
+ EvdevEndOfMultiTouch(pInfo, pData);
+ continue;
+ }
+
+ EvdevCopyFromData(pSubdev, pData);
+ pEvdevSubdev = pSubdev->private;
+ if (pEvdevSubdev->id != pData->id) {
+ pEvdevSubdev->id = pData->id;
+ XIChangeDeviceProperty(pSubdev->dev, prop_tracking_id, XA_INTEGER, 32,
+ PropModeReplace, 1, &(pEvdevSubdev->id), TRUE);
+ }
+ pEvdevSubdev->mt = 0;
+ pEvdevSubdev->abs = 1;
+ pEvdevSubdev->rel = 0;
+ pEvdevSubdev->tool = 1;
+ /* droping of the pressed/released events */
+ memset(pEvdevSubdev->queue, 0, sizeof(pEvdevSubdev->queue));
+ pEvdevSubdev->num_queue = 0;
+ EvdevProcessSyncEvent(pSubdev, ev);
+
+ }
+ pEvdev->subdevice_timer = TimerSet(pEvdev->subdevice_timer, 0, pEvdev->timeout, EvdevSubdevTimer, pInfo);
+}
+
/**
* Post the relative motion events.
*/
@@ -661,6 +750,109 @@ static void EvdevPostQueuedEvents(InputInfoPtr pInfo, int *num_v, int *first_v,
}
}
}
+static void
+EvdevCopyFromData(InputInfoPtr pInfo, EvdevDataMTPtr pData)
+{
+ EvdevPtr pEvdev = pInfo->private;
+ memcpy(pEvdev->vals, pData->vals, MAX_VALUATORS * sizeof(int));
+ /* we drop the buttons/key events */
+}
+
+static void
+EvdevStoreMTData(InputInfoPtr pInfo, EvdevDataMTPtr pData)
+{
+ EvdevPtr pEvdev = pInfo->private;
+ int id,x,y;
+ Time currentTime = GetTimeInMillis();
+
+ id = pEvdev->current_id;
+ x = pEvdev->vals[pEvdev->axis_map[ABS_MT_POSITION_X]];
+ y = pEvdev->vals[pEvdev->axis_map[ABS_MT_POSITION_Y]];
+
+
+
+ pData->id = id;
+ memcpy(pData->vals, pEvdev->vals, MAX_VALUATORS * sizeof(int));
+ pData->vals[pEvdev->axis_map[ABS_X]] = x;
+ pData->vals[pEvdev->axis_map[ABS_Y]] = y;
+ pData->containsValues = TRUE;
+ pData->expires = currentTime + pEvdev->timeout;
+}
+
+/**
+ * Reset the pEvdev with all values at 0.
+ */
+static void
+EvdevReinitPEvdev(InputInfoPtr pInfo)
+{
+ EvdevPtr pEvdev = pInfo->private;
+ memset(pEvdev->delta, 0, sizeof(pEvdev->delta));
+ memset(pEvdev->queue, 0, sizeof(pEvdev->queue));
+ pEvdev->num_queue = 0;
+ pEvdev->abs = 0;
+ pEvdev->rel = 0;
+ pEvdev->mt = 0;
+ pEvdev->num_mt = 0;
+ pEvdev->current_id = -1;
+}
+
+/**
+ * Take the mt-synchronization input event and process it accordingly.
+ */
+static void
+EvdevProcessMTSyncReport(InputInfoPtr pInfo, struct input_event *ev)
+{
+ EvdevPtr pEvdev = pInfo->private;
+ BOOL found = FALSE;
+ int id;
+ int i;
+
+ if (!pEvdev->num_multitouch)
+ return;
+
+
+ id = pEvdev->current_id;
+
+ // ntrig doesn't gives the trackID, generating one
+ if (id < 0) {
+ id = pEvdev->num_mt++;
+ pEvdev->current_id = id;
+ }
+
+ if (id >= 0) { // the trackID is given by the device
+ /* find the previously associated pData */
+ i = 0;
+ while (i < pEvdev->num_multitouch && pEvdev->vals_mt[i].id != id) {
+
+ ++i;
+ }
+ if (i < pEvdev->num_multitouch) {
+
+ found = TRUE;
+ }
+ }
+
+ if (!found) {
+ /* not found : find the first available pData */
+ i = 0;
+ while (i < pEvdev->num_multitouch && pEvdev->vals_mt[i].containsValues ) {
+ ++i;
+ }
+ if (i < pEvdev->num_multitouch) {
+
+ found = TRUE;
+ }
+ }
+
+ if (found) {
+ EvdevStoreMTData(pInfo, &(pEvdev->vals_mt[i]));
+ /* commented out to avoid a lot of log. */
+ //} else {
+ // xf86Msg(X_WARNING, "%s: ignoring event {id=%d} : not enough space to store it. %s:%d\n", pInfo->name,id,__FILE__,__LINE__);
+ }
+ EvdevReinitPEvdev(pInfo);
+ pEvdev->mt = 1;
+}
/**
* Take the synchronization input event and process it accordingly; the motion
@@ -672,18 +864,24 @@ EvdevProcessSyncEvent(InputInfoPtr pInfo, struct input_event *ev)
int num_v = 0, first_v = 0;
int v[MAX_VALUATORS];
EvdevPtr pEvdev = pInfo->private;
+
+ if (ev->code == SYN_MT_REPORT) {
+ EvdevProcessMTSyncReport(pInfo, ev);
+ return;
+ }
+
- EvdevProcessValuators(pInfo, v, &num_v, &first_v);
-
- EvdevPostRelativeMotionEvents(pInfo, &num_v, &first_v, v);
- EvdevPostAbsoluteMotionEvents(pInfo, &num_v, &first_v, v);
- EvdevPostQueuedEvents(pInfo, &num_v, &first_v, v);
+ if (pEvdev->mt) {
+ EvdevPostMTMotionEvents(pInfo, ev);
+ } else {
+ EvdevProcessValuators(pInfo, v, &num_v, &first_v);
- memset(pEvdev->delta, 0, sizeof(pEvdev->delta));
- memset(pEvdev->queue, 0, sizeof(pEvdev->queue));
- pEvdev->num_queue = 0;
- pEvdev->abs = 0;
- pEvdev->rel = 0;
+ EvdevPostRelativeMotionEvents(pInfo, &num_v, &first_v, v);
+ EvdevPostAbsoluteMotionEvents(pInfo, &num_v, &first_v, v);
+ EvdevPostQueuedEvents(pInfo, &num_v, &first_v, v);
+ }
+
+ EvdevReinitPEvdev(pInfo);
}
/**
@@ -2142,6 +2340,7 @@ EvdevPreInit(InputDriverPtr drv, IDevPtr dev, int flags)
/* mt initializations. */
pEvdev->id = -1;
pEvdev->core_device = pInfo;
+ pEvdev->num_multitouch = 0;
/*
* We initialize pEvdev->tool to 1 so that device that doesn't use
--
1.6.5.2
_______________________________________________
xorg-devel mailing list
[email protected]
http://lists.x.org/mailman/listinfo/xorg-devel