The drivers using the type B protocol all report tracking information
the same way. The contact id is semantically equivalent to
ABS_MT_SLOT, and the handling of ABS_MT_TRACKING_ID only complicates
the driver. The situation can be improved upon by providing a common
pointer emulation code, thereby removing the need for the tracking id
in the driver. This patch moves all tracking event handling over to
the input core, simplifying both the existing drivers and the ones
currently in preparation.
Signed-off-by: Henrik Rydberg <[email protected]>
---
Hi Dmitry,
This is revision two of this patch, fixing the compilation problem and
adding the pointer emulation comment. In addition, the fourth patch
has been folded into this one, and touchpad finger count emulation has
been added. The original idea was to add this later, but since the
wacom driver is already touched in this patch, it makes sense to
switch to pointer emulation here and now.
Cheers,
Henrik
drivers/hid/hid-3m-pct.c | 30 +----------
drivers/input/input-mt.c | 91 +++++++++++++++++++++++++++++--
drivers/input/tablet/wacom_wac.c | 19 +------
drivers/input/tablet/wacom_wac.h | 4 --
drivers/input/touchscreen/wacom_w8001.c | 13 +----
include/linux/input-mt.h | 11 ++++
include/linux/input.h | 1 +
7 files changed, 105 insertions(+), 64 deletions(-)
diff --git a/drivers/hid/hid-3m-pct.c b/drivers/hid/hid-3m-pct.c
index e3711c5..a9fc2c1 100644
--- a/drivers/hid/hid-3m-pct.c
+++ b/drivers/hid/hid-3m-pct.c
@@ -28,7 +28,6 @@ MODULE_LICENSE("GPL");
#include "hid-ids.h"
#define MAX_SLOTS 60
-#define MAX_TRKID USHRT_MAX
/* estimated signal-to-noise ratios */
#define SN_MOVE 2048
@@ -36,14 +35,11 @@ MODULE_LICENSE("GPL");etter t
struct mmm_finger {
__s32 x, y, w, h;
- __u16 id;
- bool prev_touch;
bool touch, valid;
};
struct mmm_data {
struct mmm_finger f[MAX_SLOTS];
- __u16 id;
__u8 curid;
__u8 nexp, nreal;
bool touch, valid;
@@ -117,11 +113,6 @@ static int mmm_input_mapping(struct hid_device *hdev, struct hid_input *hi,
0, 1, 0, 0);
return 1;
case HID_DG_CONTACTID:
- field->logical_maximum = MAX_TRKID;
- hid_map_usage(hi, usage, bit, max,
- EV_ABS, ABS_MT_TRACKING_ID);
- input_set_abs_params(hi->input, ABS_MT_TRACKING_ID,
- 0, MAX_TRKID, 0, 0);
input_mt_init_slots(hi->input, MAX_SLOTS);
return 1;
}
@@ -152,7 +143,6 @@ static int mmm_input_mapped(struct hid_device *hdev, struct hid_input *hi,
*/
static void mmm_filter_event(struct mmm_data *md, struct input_dev *input)
{
- struct mmm_finger *oldest = 0;
int i;
for (i = 0; i < MAX_SLOTS; ++i) {
struct mmm_finger *f = &md->f[i];
@@ -161,6 +151,7 @@ static void mmm_filter_event(struct mmm_data *md, struct input_dev *input)
continue;
}
input_mt_slot(input, i);
+ input_mt_report_slot_state(input, f->touch);
if (f->touch) {
/* this finger is on the screen */
int wide = (f->w > f->h);
@@ -168,33 +159,16 @@ static void mmm_filter_event(struct mmm_data *md, struct input_dev *input)
int major = max(f->w, f->h) >> 1;
int minor = min(f->w, f->h) >> 1;
- if (!f->prev_touch)
- f->id = md->id++;
- input_event(input, EV_ABS, ABS_MT_TRACKING_ID, f->id);
input_event(input, EV_ABS, ABS_MT_POSITION_X, f->x);
input_event(input, EV_ABS, ABS_MT_POSITION_Y, f->y);
input_event(input, EV_ABS, ABS_MT_ORIENTATION, wide);
input_event(input, EV_ABS, ABS_MT_TOUCH_MAJOR, major);
input_event(input, EV_ABS, ABS_MT_TOUCH_MINOR, minor);
- /* touchscreen emulation: pick the oldest contact */
- if (!oldest || ((f->id - oldest->id) & (SHRT_MAX + 1)))
- oldest = f;
- } else {
- /* this finger took off the screen */
- input_event(input, EV_ABS, ABS_MT_TRACKING_ID, -1);
}
- f->prev_touch = f->touch;
f->valid = 0;
}
- /* touchscreen emulation */
- if (oldest) {
- input_event(input, EV_KEY, BTN_TOUCH, 1);
- input_event(input, EV_ABS, ABS_X, oldest->x);
- input_event(input, EV_ABS, ABS_Y, oldest->y);
- } else {
- input_event(input, EV_KEY, BTN_TOUCH, 0);
- }
+ input_mt_report_pointer_emulation(input);
input_sync(input);
}
diff --git a/drivers/input/input-mt.c b/drivers/input/input-mt.c
index c4a9784..be7264d 100644
--- a/drivers/input/input-mt.c
+++ b/drivers/input/input-mt.c
@@ -11,17 +11,18 @@
#include <linux/input-mt.h>
#include <linux/slab.h>
+#define TRKID_SGN ((TRKID_MAX + 1) >> 1)
+
/**
* input_mt_init_slots() - initialize MT input slots
* @dev: input device supporting MT events and finger tracking
* @num_slots: number of slots used by the device
*
* This function allocates all necessary memory for MT slot handling
- * in the input device, adds ABS_MT_SLOT to the device capabilities
- * and sets up appropriate event buffers. All slots are initially
- * marked as unused by setting ABS_MT_TRACKING_ID to -1. May be called
- * repeatedly. Returns -EINVAL if attempting to reinitialize with a
- * different number of slots.
+ * in the input device, prepares the ABS_MT_SLOT and
+ * ABS_MT_TRACKING_ID events for use and sets up appropriate buffers.
+ * May be called repeatedly. Returns -EINVAL if attempting to
+ * reinitialize with a different number of slots.
*/
int input_mt_init_slots(struct input_dev *dev, unsigned int num_slots)
{
@@ -38,6 +39,7 @@ int input_mt_init_slots(struct input_dev *dev, unsigned int num_slots)
dev->mtsize = num_slots;
input_set_abs_params(dev, ABS_MT_SLOT, 0, num_slots - 1, 0, 0);
+ input_set_abs_params(dev, ABS_MT_TRACKING_ID, 0, TRKID_MAX, 0, 0);
input_set_events_per_packet(dev, 6 * num_slots);
/* Mark slots as 'unused' */
@@ -61,5 +63,84 @@ void input_mt_destroy_slots(struct input_dev *dev)
dev->mt = NULL;
dev->mtsize = 0;
dev->slot = 0;
+ dev->trkid = 0;
}
EXPORT_SYMBOL(input_mt_destroy_slots);
+
+/**
+ * input_mt_report_state() - report contact state
+ * @dev: input device with allocated MT slots
+ * @active: true if contact is active, false otherwise
+ *
+ * Reports an active touch via ABS_MT_TRACKING_ID. If active is
+ * true and the slot is currently inactive, a new tracking id is
+ * assigned to the slot.
+ */
+void input_mt_report_slot_state(struct input_dev *dev, bool active)
+{
+ struct input_mt_slot *mt = dev->mt;
+ int id;
+
+ if (!mt || !active) {
+ input_event(dev, EV_ABS, ABS_MT_TRACKING_ID, -1);
+ return;
+ }
+
+ id = input_mt_get_value(&mt[dev->slot], ABS_MT_TRACKING_ID);
+ if (id < 0)
+ id = input_mt_new_trkid(dev);
+ input_event(dev, EV_ABS, ABS_MT_TRACKING_ID, id);
+}
+EXPORT_SYMBOL(input_mt_report_slot_state);
+
+/**
+ * input_mt_report_pointer_emulation() - common pointer emulation
+ * @dev: input device with allocated MT slots
+ *
+ * Performs legacy pointer emulation via BTN_TOUCH, ABS_X, ABS_Y and
+ * ABS_PRESSURE. Touchpad finger count is emulated using
+ * BTN_TOOL_FINGER, BTN_TOOL_DOUBLETAP, BTN_TOOL_TRIPLETAP and
+ * BTN_TOOL_QUADTAP.
+ *
+ * The input core ensures only the KEY and ABS axes already setup for
+ * this device will produce output.
+ */
+void input_mt_report_pointer_emulation(struct input_dev *dev)
+{
+ struct input_mt_slot *oldest = 0;
+ int oldid = dev->trkid;
+ int count = 0;
+ int i;
+
+ for (i = 0; i < dev->mtsize; ++i) {
+ struct input_mt_slot *ps = &dev->mt[i];
+ int id = input_mt_get_value(ps, ABS_MT_TRACKING_ID);
+
+ if (id < 0)
+ continue;
+ if ((id - oldid) & TRKID_SGN) {
+ oldest = ps;
+ oldid = id;
+ }
+ count++;
+ }
+
+ input_event(dev, EV_KEY, BTN_TOUCH, count > 0);
+ input_event(dev, EV_KEY, BTN_TOOL_FINGER, count == 1);
+ input_event(dev, EV_KEY, BTN_TOOL_DOUBLETAP, count == 2);
+ input_event(dev, EV_KEY, BTN_TOOL_TRIPLETAP, count == 3);
+ input_event(dev, EV_KEY, BTN_TOOL_QUADTAP, count == 4);
+
+ if (oldest) {
+ int x = input_mt_get_value(oldest, ABS_MT_POSITION_X);
+ int y = input_mt_get_value(oldest, ABS_MT_POSITION_Y);
+ int p = input_mt_get_value(oldest, ABS_MT_PRESSURE);
+
+ input_event(dev, EV_ABS, ABS_X, x);
+ input_event(dev, EV_ABS, ABS_Y, y);
+ input_event(dev, EV_ABS, ABS_PRESSURE, p);
+ } else {
+ input_event(dev, EV_ABS, ABS_PRESSURE, 0);
+ }
+}
+EXPORT_SYMBOL(input_mt_report_pointer_emulation);
diff --git a/drivers/input/tablet/wacom_wac.c b/drivers/input/tablet/wacom_wac.c
index 3f9e280..86d0be3 100644
--- a/drivers/input/tablet/wacom_wac.c
+++ b/drivers/input/tablet/wacom_wac.c
@@ -863,7 +863,6 @@ static int wacom_bpt_touch(struct wacom_wac *wacom)
struct wacom_features *features = &wacom->features;
struct input_dev *input = wacom->input;
unsigned char *data = wacom->data;
- int sp = 0, sx = 0, sy = 0, count = 0;
int i;
for (i = 0; i < 2; i++) {
@@ -885,23 +884,13 @@ static int wacom_bpt_touch(struct wacom_wac *wacom)
input_report_abs(input, ABS_MT_PRESSURE, p);
input_report_abs(input, ABS_MT_POSITION_X, x);
input_report_abs(input, ABS_MT_POSITION_Y, y);
- if (wacom->id[i] < 0)
- wacom->id[i] = wacom->trk_id++ & MAX_TRACKING_ID;
- if (!count++)
- sp = p, sx = x, sy = y;
+ input_mt_report_slot_state(input, true);
} else {
- wacom->id[i] = -1;
+ input_mt_report_slot_state(input, false);
}
- input_report_abs(input, ABS_MT_TRACKING_ID, wacom->id[i]);
}
- input_report_key(input, BTN_TOUCH, count > 0);
- input_report_key(input, BTN_TOOL_FINGER, count == 1);
- input_report_key(input, BTN_TOOL_DOUBLETAP, count == 2);
-
- input_report_abs(input, ABS_PRESSURE, sp);
- input_report_abs(input, ABS_X, sx);
- input_report_abs(input, ABS_Y, sy);
+ input_mt_report_pointer_emulation(input);
input_report_key(input, BTN_LEFT, (data[1] & 0x08) != 0);
input_report_key(input, BTN_FORWARD, (data[1] & 0x04) != 0);
@@ -1283,8 +1272,6 @@ void wacom_setup_input_capabilities(struct input_dev *input_dev,
input_set_abs_params(input_dev, ABS_MT_PRESSURE,
0, features->pressure_max,
features->pressure_fuzz, 0);
- input_set_abs_params(input_dev, ABS_MT_TRACKING_ID, 0,
- MAX_TRACKING_ID, 0, 0);
} else if (features->device_type == BTN_TOOL_PEN) {
__set_bit(BTN_TOOL_RUBBER, input_dev->keybit);
__set_bit(BTN_TOOL_PEN, input_dev->keybit);
diff --git a/drivers/input/tablet/wacom_wac.h b/drivers/input/tablet/wacom_wac.h
index 00ca015..b1310ec 100644
--- a/drivers/input/tablet/wacom_wac.h
+++ b/drivers/input/tablet/wacom_wac.h
@@ -42,9 +42,6 @@
#define WACOM_QUIRK_MULTI_INPUT 0x0001
#define WACOM_QUIRK_BBTOUCH_LOWRES 0x0002
-/* largest reported tracking id */
-#define MAX_TRACKING_ID 0xfff
-
enum {
PENPARTNER = 0,
GRAPHIRE,
@@ -100,7 +97,6 @@ struct wacom_wac {
int id[3];
__u32 serial[2];
int last_finger;
- int trk_id;
struct wacom_features features;
struct wacom_shared *shared;
struct input_dev *input;
diff --git a/drivers/input/touchscreen/wacom_w8001.c b/drivers/input/touchscreen/wacom_w8001.c
index b706cd5..abf4c6e 100644
--- a/drivers/input/touchscreen/wacom_w8001.c
+++ b/drivers/input/touchscreen/wacom_w8001.c
@@ -48,8 +48,6 @@ MODULE_LICENSE("GPL");
#define W8001_PKTLEN_TPCCTL 11 /* control packet */
#define W8001_PKTLEN_TOUCH2FG 13
-#define MAX_TRACKING_ID 0xFF /* arbitrarily chosen */
-
struct w8001_coord {
u8 rdy;
u8 tsw;
@@ -87,7 +85,6 @@ struct w8001 {
char phys[32];
int type;
unsigned int pktlen;
- int trkid[2];
};
static void parse_data(u8 *data, struct w8001_coord *coord)
@@ -116,7 +113,6 @@ static void parse_data(u8 *data, struct w8001_coord *coord)
static void parse_touch(struct w8001 *w8001)
{
- static int trkid;
struct input_dev *dev = w8001->dev;
unsigned char *data = w8001->data;
int i;
@@ -132,12 +128,10 @@ static void parse_touch(struct w8001 *w8001)
input_report_abs(dev, ABS_MT_POSITION_X, x);
input_report_abs(dev, ABS_MT_POSITION_Y, y);
input_report_abs(dev, ABS_MT_TOOL_TYPE, MT_TOOL_FINGER);
- if (w8001->trkid[i] < 0)
- w8001->trkid[i] = trkid++ & MAX_TRACKING_ID;
+ input_mt_report_slot_state(dev, true);
} else {
- w8001->trkid[i] = -1;
+ input_mt_report_slot_state(dev, false);
}
- input_report_abs(dev, ABS_MT_TRACKING_ID, w8001->trkid[i]);
}
input_sync(dev);
@@ -319,8 +313,6 @@ static int w8001_setup(struct w8001 *w8001)
w8001->pktlen = W8001_PKTLEN_TOUCH2FG;
input_mt_init_slots(dev, 2);
- input_set_abs_params(dev, ABS_MT_TRACKING_ID,
- 0, MAX_TRACKING_ID, 0, 0);
input_set_abs_params(dev, ABS_MT_POSITION_X,
0, touch.x, 0, 0);
input_set_abs_params(dev, ABS_MT_POSITION_Y,
@@ -372,7 +364,6 @@ static int w8001_connect(struct serio *serio, struct serio_driver *drv)
w8001->serio = serio;
w8001->id = serio->id.id;
w8001->dev = input_dev;
- w8001->trkid[0] = w8001->trkid[1] = -1;
init_completion(&w8001->cmd_done);
snprintf(w8001->phys, sizeof(w8001->phys), "%s/input0", serio->phys);
diff --git a/include/linux/input-mt.h b/include/linux/input-mt.h
index d7f6518..1a44567 100644
--- a/include/linux/input-mt.h
+++ b/include/linux/input-mt.h
@@ -13,6 +13,8 @@
#include <linux/input.h>
+#define TRKID_MAX 0xffff
+
/**
* struct input_mt_slot - represents the state of an input MT slot
* @abs: holds current values of ABS_MT axes for this slot
@@ -36,9 +38,18 @@ static inline int input_mt_get_value(const struct input_mt_slot *slot,
int input_mt_init_slots(struct input_dev *dev, unsigned int num_slots);
void input_mt_destroy_slots(struct input_dev *dev);
+static inline int input_mt_new_trkid(struct input_dev *dev)
+{
+ return dev->trkid++ & TRKID_MAX;
+}
+
static inline void input_mt_slot(struct input_dev *dev, int slot)
{
input_event(dev, EV_ABS, ABS_MT_SLOT, slot);
}
+void input_mt_report_slot_state(struct input_dev *dev, bool active);
+
+void input_mt_report_pointer_emulation(struct input_dev *dev);
+
#endif
diff --git a/include/linux/input.h b/include/linux/input.h
index dd7c0fc..3b856d6 100644
--- a/include/linux/input.h
+++ b/include/linux/input.h
@@ -1206,6 +1206,7 @@ struct input_dev {
struct input_mt_slot *mt;
int mtsize;
int slot;
+ int trkid;
struct input_absinfo *absinfo;
--
1.7.1
On Wed, Dec 1, 2010 at 9:21 AM, Henrik Rydberg <[email protected]> wrote:
> The drivers using the type B protocol all report tracking information
> the same way. The contact id is semantically equivalent to
> ABS_MT_SLOT, and the handling of ABS_MT_TRACKING_ID only complicates
> the driver. The situation can be improved upon by providing a common
> pointer emulation code, thereby removing the need for the tracking id
> in the driver. ?This patch moves all tracking event handling over to
> the input core, simplifying both the existing drivers and the ones
> currently in preparation.
>
> Signed-off-by: Henrik Rydberg <[email protected]>
Acked-by: Ping Cheng <[email protected]>
The changes that are related to Wacom driver look sane to me.
Dmitry,
Please ignore "[PATCH v2] Input: wacom - allow both MT and pen data to
be reported". I'll make a new one based on Henrik's patch.
Ping
> ---
> Hi Dmitry,
>
> This is revision two of this patch, fixing the compilation problem and
> adding the pointer emulation comment. In addition, the fourth patch
> has been folded into this one, and touchpad finger count emulation has
> been added. The original idea was to add this later, but since the
> wacom driver is already touched in this patch, it makes sense to
> switch to pointer emulation here and now.
>
> Cheers,
> Henrik
>
> ?drivers/hid/hid-3m-pct.c ? ? ? ? ? ? ? ?| ? 30 +----------
> ?drivers/input/input-mt.c ? ? ? ? ? ? ? ?| ? 91 +++++++++++++++++++++++++++++--
> ?drivers/input/tablet/wacom_wac.c ? ? ? ?| ? 19 +------
> ?drivers/input/tablet/wacom_wac.h ? ? ? ?| ? ?4 --
> ?drivers/input/touchscreen/wacom_w8001.c | ? 13 +----
> ?include/linux/input-mt.h ? ? ? ? ? ? ? ?| ? 11 ++++
> ?include/linux/input.h ? ? ? ? ? ? ? ? ? | ? ?1 +
> ?7 files changed, 105 insertions(+), 64 deletions(-)
>
> diff --git a/drivers/hid/hid-3m-pct.c b/drivers/hid/hid-3m-pct.c
> index e3711c5..a9fc2c1 100644
> --- a/drivers/hid/hid-3m-pct.c
> +++ b/drivers/hid/hid-3m-pct.c
> @@ -28,7 +28,6 @@ MODULE_LICENSE("GPL");
> ?#include "hid-ids.h"
>
> ?#define MAX_SLOTS ? ? ? ? ? ? ?60
> -#define MAX_TRKID ? ? ? ? ? ? ?USHRT_MAX
>
> ?/* estimated signal-to-noise ratios */
> ?#define SN_MOVE ? ? ? ? ? ? ? ? ? ? ? ?2048
> @@ -36,14 +35,11 @@ MODULE_LICENSE("GPL");etter t
>
> ?struct mmm_finger {
> ? ? ? ?__s32 x, y, w, h;
> - ? ? ? __u16 id;
> - ? ? ? bool prev_touch;
> ? ? ? ?bool touch, valid;
> ?};
>
> ?struct mmm_data {
> ? ? ? ?struct mmm_finger f[MAX_SLOTS];
> - ? ? ? __u16 id;
> ? ? ? ?__u8 curid;
> ? ? ? ?__u8 nexp, nreal;
> ? ? ? ?bool touch, valid;
> @@ -117,11 +113,6 @@ static int mmm_input_mapping(struct hid_device *hdev, struct hid_input *hi,
> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?0, 1, 0, 0);
> ? ? ? ? ? ? ? ? ? ? ? ?return 1;
> ? ? ? ? ? ? ? ?case HID_DG_CONTACTID:
> - ? ? ? ? ? ? ? ? ? ? ? field->logical_maximum = MAX_TRKID;
> - ? ? ? ? ? ? ? ? ? ? ? hid_map_usage(hi, usage, bit, max,
> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? EV_ABS, ABS_MT_TRACKING_ID);
> - ? ? ? ? ? ? ? ? ? ? ? input_set_abs_params(hi->input, ABS_MT_TRACKING_ID,
> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?0, MAX_TRKID, 0, 0);
> ? ? ? ? ? ? ? ? ? ? ? ?input_mt_init_slots(hi->input, MAX_SLOTS);
> ? ? ? ? ? ? ? ? ? ? ? ?return 1;
> ? ? ? ? ? ? ? ?}
> @@ -152,7 +143,6 @@ static int mmm_input_mapped(struct hid_device *hdev, struct hid_input *hi,
> ?*/
> ?static void mmm_filter_event(struct mmm_data *md, struct input_dev *input)
> ?{
> - ? ? ? struct mmm_finger *oldest = 0;
> ? ? ? ?int i;
> ? ? ? ?for (i = 0; i < MAX_SLOTS; ++i) {
> ? ? ? ? ? ? ? ?struct mmm_finger *f = &md->f[i];
> @@ -161,6 +151,7 @@ static void mmm_filter_event(struct mmm_data *md, struct input_dev *input)
> ? ? ? ? ? ? ? ? ? ? ? ?continue;
> ? ? ? ? ? ? ? ?}
> ? ? ? ? ? ? ? ?input_mt_slot(input, i);
> + ? ? ? ? ? ? ? input_mt_report_slot_state(input, f->touch);
> ? ? ? ? ? ? ? ?if (f->touch) {
> ? ? ? ? ? ? ? ? ? ? ? ?/* this finger is on the screen */
> ? ? ? ? ? ? ? ? ? ? ? ?int wide = (f->w > f->h);
> @@ -168,33 +159,16 @@ static void mmm_filter_event(struct mmm_data *md, struct input_dev *input)
> ? ? ? ? ? ? ? ? ? ? ? ?int major = max(f->w, f->h) >> 1;
> ? ? ? ? ? ? ? ? ? ? ? ?int minor = min(f->w, f->h) >> 1;
>
> - ? ? ? ? ? ? ? ? ? ? ? if (!f->prev_touch)
> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? f->id = md->id++;
> - ? ? ? ? ? ? ? ? ? ? ? input_event(input, EV_ABS, ABS_MT_TRACKING_ID, f->id);
> ? ? ? ? ? ? ? ? ? ? ? ?input_event(input, EV_ABS, ABS_MT_POSITION_X, f->x);
> ? ? ? ? ? ? ? ? ? ? ? ?input_event(input, EV_ABS, ABS_MT_POSITION_Y, f->y);
> ? ? ? ? ? ? ? ? ? ? ? ?input_event(input, EV_ABS, ABS_MT_ORIENTATION, wide);
> ? ? ? ? ? ? ? ? ? ? ? ?input_event(input, EV_ABS, ABS_MT_TOUCH_MAJOR, major);
> ? ? ? ? ? ? ? ? ? ? ? ?input_event(input, EV_ABS, ABS_MT_TOUCH_MINOR, minor);
> - ? ? ? ? ? ? ? ? ? ? ? /* touchscreen emulation: pick the oldest contact */
> - ? ? ? ? ? ? ? ? ? ? ? if (!oldest || ((f->id - oldest->id) & (SHRT_MAX + 1)))
> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? oldest = f;
> - ? ? ? ? ? ? ? } else {
> - ? ? ? ? ? ? ? ? ? ? ? /* this finger took off the screen */
> - ? ? ? ? ? ? ? ? ? ? ? input_event(input, EV_ABS, ABS_MT_TRACKING_ID, -1);
> ? ? ? ? ? ? ? ?}
> - ? ? ? ? ? ? ? f->prev_touch = f->touch;
> ? ? ? ? ? ? ? ?f->valid = 0;
> ? ? ? ?}
>
> - ? ? ? /* touchscreen emulation */
> - ? ? ? if (oldest) {
> - ? ? ? ? ? ? ? input_event(input, EV_KEY, BTN_TOUCH, 1);
> - ? ? ? ? ? ? ? input_event(input, EV_ABS, ABS_X, oldest->x);
> - ? ? ? ? ? ? ? input_event(input, EV_ABS, ABS_Y, oldest->y);
> - ? ? ? } else {
> - ? ? ? ? ? ? ? input_event(input, EV_KEY, BTN_TOUCH, 0);
> - ? ? ? }
> + ? ? ? input_mt_report_pointer_emulation(input);
> ? ? ? ?input_sync(input);
> ?}
>
> diff --git a/drivers/input/input-mt.c b/drivers/input/input-mt.c
> index c4a9784..be7264d 100644
> --- a/drivers/input/input-mt.c
> +++ b/drivers/input/input-mt.c
> @@ -11,17 +11,18 @@
> ?#include <linux/input-mt.h>
> ?#include <linux/slab.h>
>
> +#define TRKID_SGN ? ? ?((TRKID_MAX + 1) >> 1)
> +
> ?/**
> ?* input_mt_init_slots() - initialize MT input slots
> ?* @dev: input device supporting MT events and finger tracking
> ?* @num_slots: number of slots used by the device
> ?*
> ?* This function allocates all necessary memory for MT slot handling
> - * in the input device, adds ABS_MT_SLOT to the device capabilities
> - * and sets up appropriate event buffers. All slots are initially
> - * marked as unused by setting ABS_MT_TRACKING_ID to -1. May be called
> - * repeatedly. Returns -EINVAL if attempting to reinitialize with a
> - * different number of slots.
> + * in the input device, prepares the ABS_MT_SLOT and
> + * ABS_MT_TRACKING_ID events for use and sets up appropriate buffers.
> + * May be called repeatedly. Returns -EINVAL if attempting to
> + * reinitialize with a different number of slots.
> ?*/
> ?int input_mt_init_slots(struct input_dev *dev, unsigned int num_slots)
> ?{
> @@ -38,6 +39,7 @@ int input_mt_init_slots(struct input_dev *dev, unsigned int num_slots)
>
> ? ? ? ?dev->mtsize = num_slots;
> ? ? ? ?input_set_abs_params(dev, ABS_MT_SLOT, 0, num_slots - 1, 0, 0);
> + ? ? ? input_set_abs_params(dev, ABS_MT_TRACKING_ID, 0, TRKID_MAX, 0, 0);
> ? ? ? ?input_set_events_per_packet(dev, 6 * num_slots);
>
> ? ? ? ?/* Mark slots as 'unused' */
> @@ -61,5 +63,84 @@ void input_mt_destroy_slots(struct input_dev *dev)
> ? ? ? ?dev->mt = NULL;
> ? ? ? ?dev->mtsize = 0;
> ? ? ? ?dev->slot = 0;
> + ? ? ? dev->trkid = 0;
> ?}
> ?EXPORT_SYMBOL(input_mt_destroy_slots);
> +
> +/**
> + * input_mt_report_state() - report contact state
> + * @dev: input device with allocated MT slots
> + * @active: true if contact is active, false otherwise
> + *
> + * Reports an active touch via ABS_MT_TRACKING_ID. If active is
> + * true and the slot is currently inactive, a new tracking id is
> + * assigned to the slot.
> + */
> +void input_mt_report_slot_state(struct input_dev *dev, bool active)
> +{
> + ? ? ? struct input_mt_slot *mt = dev->mt;
> + ? ? ? int id;
> +
> + ? ? ? if (!mt || !active) {
> + ? ? ? ? ? ? ? input_event(dev, EV_ABS, ABS_MT_TRACKING_ID, -1);
> + ? ? ? ? ? ? ? return;
> + ? ? ? }
> +
> + ? ? ? id = input_mt_get_value(&mt[dev->slot], ABS_MT_TRACKING_ID);
> + ? ? ? if (id < 0)
> + ? ? ? ? ? ? ? id = input_mt_new_trkid(dev);
> + ? ? ? input_event(dev, EV_ABS, ABS_MT_TRACKING_ID, id);
> +}
> +EXPORT_SYMBOL(input_mt_report_slot_state);
> +
> +/**
> + * input_mt_report_pointer_emulation() - common pointer emulation
> + * @dev: input device with allocated MT slots
> + *
> + * Performs legacy pointer emulation via BTN_TOUCH, ABS_X, ABS_Y and
> + * ABS_PRESSURE. Touchpad finger count is emulated using
> + * BTN_TOOL_FINGER, BTN_TOOL_DOUBLETAP, BTN_TOOL_TRIPLETAP and
> + * BTN_TOOL_QUADTAP.
> + *
> + * The input core ensures only the KEY and ABS axes already setup for
> + * this device will produce output.
> + */
> +void input_mt_report_pointer_emulation(struct input_dev *dev)
> +{
> + ? ? ? struct input_mt_slot *oldest = 0;
> + ? ? ? int oldid = dev->trkid;
> + ? ? ? int count = 0;
> + ? ? ? int i;
> +
> + ? ? ? for (i = 0; i < dev->mtsize; ++i) {
> + ? ? ? ? ? ? ? struct input_mt_slot *ps = &dev->mt[i];
> + ? ? ? ? ? ? ? int id = input_mt_get_value(ps, ABS_MT_TRACKING_ID);
> +
> + ? ? ? ? ? ? ? if (id < 0)
> + ? ? ? ? ? ? ? ? ? ? ? continue;
> + ? ? ? ? ? ? ? if ((id - oldid) & TRKID_SGN) {
> + ? ? ? ? ? ? ? ? ? ? ? oldest = ps;
> + ? ? ? ? ? ? ? ? ? ? ? oldid = id;
> + ? ? ? ? ? ? ? }
> + ? ? ? ? ? ? ? count++;
> + ? ? ? }
> +
> + ? ? ? input_event(dev, EV_KEY, BTN_TOUCH, count > 0);
> + ? ? ? input_event(dev, EV_KEY, BTN_TOOL_FINGER, count == 1);
> + ? ? ? input_event(dev, EV_KEY, BTN_TOOL_DOUBLETAP, count == 2);
> + ? ? ? input_event(dev, EV_KEY, BTN_TOOL_TRIPLETAP, count == 3);
> + ? ? ? input_event(dev, EV_KEY, BTN_TOOL_QUADTAP, count == 4);
> +
> + ? ? ? if (oldest) {
> + ? ? ? ? ? ? ? int x = input_mt_get_value(oldest, ABS_MT_POSITION_X);
> + ? ? ? ? ? ? ? int y = input_mt_get_value(oldest, ABS_MT_POSITION_Y);
> + ? ? ? ? ? ? ? int p = input_mt_get_value(oldest, ABS_MT_PRESSURE);
> +
> + ? ? ? ? ? ? ? input_event(dev, EV_ABS, ABS_X, x);
> + ? ? ? ? ? ? ? input_event(dev, EV_ABS, ABS_Y, y);
> + ? ? ? ? ? ? ? input_event(dev, EV_ABS, ABS_PRESSURE, p);
> + ? ? ? } else {
> + ? ? ? ? ? ? ? input_event(dev, EV_ABS, ABS_PRESSURE, 0);
> + ? ? ? }
> +}
> +EXPORT_SYMBOL(input_mt_report_pointer_emulation);
> diff --git a/drivers/input/tablet/wacom_wac.c b/drivers/input/tablet/wacom_wac.c
> index 3f9e280..86d0be3 100644
> --- a/drivers/input/tablet/wacom_wac.c
> +++ b/drivers/input/tablet/wacom_wac.c
> @@ -863,7 +863,6 @@ static int wacom_bpt_touch(struct wacom_wac *wacom)
> ? ? ? ?struct wacom_features *features = &wacom->features;
> ? ? ? ?struct input_dev *input = wacom->input;
> ? ? ? ?unsigned char *data = wacom->data;
> - ? ? ? int sp = 0, sx = 0, sy = 0, count = 0;
> ? ? ? ?int i;
>
> ? ? ? ?for (i = 0; i < 2; i++) {
> @@ -885,23 +884,13 @@ static int wacom_bpt_touch(struct wacom_wac *wacom)
> ? ? ? ? ? ? ? ? ? ? ? ?input_report_abs(input, ABS_MT_PRESSURE, p);
> ? ? ? ? ? ? ? ? ? ? ? ?input_report_abs(input, ABS_MT_POSITION_X, x);
> ? ? ? ? ? ? ? ? ? ? ? ?input_report_abs(input, ABS_MT_POSITION_Y, y);
> - ? ? ? ? ? ? ? ? ? ? ? if (wacom->id[i] < 0)
> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? wacom->id[i] = wacom->trk_id++ & MAX_TRACKING_ID;
> - ? ? ? ? ? ? ? ? ? ? ? if (!count++)
> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? sp = p, sx = x, sy = y;
> + ? ? ? ? ? ? ? ? ? ? ? input_mt_report_slot_state(input, true);
> ? ? ? ? ? ? ? ?} else {
> - ? ? ? ? ? ? ? ? ? ? ? wacom->id[i] = -1;
> + ? ? ? ? ? ? ? ? ? ? ? input_mt_report_slot_state(input, false);
> ? ? ? ? ? ? ? ?}
> - ? ? ? ? ? ? ? input_report_abs(input, ABS_MT_TRACKING_ID, wacom->id[i]);
> ? ? ? ?}
>
> - ? ? ? input_report_key(input, BTN_TOUCH, count > 0);
> - ? ? ? input_report_key(input, BTN_TOOL_FINGER, count == 1);
> - ? ? ? input_report_key(input, BTN_TOOL_DOUBLETAP, count == 2);
> -
> - ? ? ? input_report_abs(input, ABS_PRESSURE, sp);
> - ? ? ? input_report_abs(input, ABS_X, sx);
> - ? ? ? input_report_abs(input, ABS_Y, sy);
> + ? ? ? input_mt_report_pointer_emulation(input);
>
> ? ? ? ?input_report_key(input, BTN_LEFT, (data[1] & 0x08) != 0);
> ? ? ? ?input_report_key(input, BTN_FORWARD, (data[1] & 0x04) != 0);
> @@ -1283,8 +1272,6 @@ void wacom_setup_input_capabilities(struct input_dev *input_dev,
> ? ? ? ? ? ? ? ? ? ? ? ?input_set_abs_params(input_dev, ABS_MT_PRESSURE,
> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 0, features->pressure_max,
> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? features->pressure_fuzz, 0);
> - ? ? ? ? ? ? ? ? ? ? ? input_set_abs_params(input_dev, ABS_MT_TRACKING_ID, 0,
> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?MAX_TRACKING_ID, 0, 0);
> ? ? ? ? ? ? ? ?} else if (features->device_type == BTN_TOOL_PEN) {
> ? ? ? ? ? ? ? ? ? ? ? ?__set_bit(BTN_TOOL_RUBBER, input_dev->keybit);
> ? ? ? ? ? ? ? ? ? ? ? ?__set_bit(BTN_TOOL_PEN, input_dev->keybit);
> diff --git a/drivers/input/tablet/wacom_wac.h b/drivers/input/tablet/wacom_wac.h
> index 00ca015..b1310ec 100644
> --- a/drivers/input/tablet/wacom_wac.h
> +++ b/drivers/input/tablet/wacom_wac.h
> @@ -42,9 +42,6 @@
> ?#define WACOM_QUIRK_MULTI_INPUT ? ? ? ? ? ? ? ?0x0001
> ?#define WACOM_QUIRK_BBTOUCH_LOWRES ? ? 0x0002
>
> -/* largest reported tracking id */
> -#define MAX_TRACKING_ID ? ? ? ? ? ? ? ? ? ? ? ?0xfff
> -
> ?enum {
> ? ? ? ?PENPARTNER = 0,
> ? ? ? ?GRAPHIRE,
> @@ -100,7 +97,6 @@ struct wacom_wac {
> ? ? ? ?int id[3];
> ? ? ? ?__u32 serial[2];
> ? ? ? ?int last_finger;
> - ? ? ? int trk_id;
> ? ? ? ?struct wacom_features features;
> ? ? ? ?struct wacom_shared *shared;
> ? ? ? ?struct input_dev *input;
> diff --git a/drivers/input/touchscreen/wacom_w8001.c b/drivers/input/touchscreen/wacom_w8001.c
> index b706cd5..abf4c6e 100644
> --- a/drivers/input/touchscreen/wacom_w8001.c
> +++ b/drivers/input/touchscreen/wacom_w8001.c
> @@ -48,8 +48,6 @@ MODULE_LICENSE("GPL");
> ?#define W8001_PKTLEN_TPCCTL ? ?11 ? ? ?/* control packet */
> ?#define W8001_PKTLEN_TOUCH2FG ?13
>
> -#define MAX_TRACKING_ID ? ? ? ? ? ? ? ?0xFF ? ?/* arbitrarily chosen */
> -
> ?struct w8001_coord {
> ? ? ? ?u8 rdy;
> ? ? ? ?u8 tsw;
> @@ -87,7 +85,6 @@ struct w8001 {
> ? ? ? ?char phys[32];
> ? ? ? ?int type;
> ? ? ? ?unsigned int pktlen;
> - ? ? ? int trkid[2];
> ?};
>
> ?static void parse_data(u8 *data, struct w8001_coord *coord)
> @@ -116,7 +113,6 @@ static void parse_data(u8 *data, struct w8001_coord *coord)
>
> ?static void parse_touch(struct w8001 *w8001)
> ?{
> - ? ? ? static int trkid;
> ? ? ? ?struct input_dev *dev = w8001->dev;
> ? ? ? ?unsigned char *data = w8001->data;
> ? ? ? ?int i;
> @@ -132,12 +128,10 @@ static void parse_touch(struct w8001 *w8001)
> ? ? ? ? ? ? ? ? ? ? ? ?input_report_abs(dev, ABS_MT_POSITION_X, x);
> ? ? ? ? ? ? ? ? ? ? ? ?input_report_abs(dev, ABS_MT_POSITION_Y, y);
> ? ? ? ? ? ? ? ? ? ? ? ?input_report_abs(dev, ABS_MT_TOOL_TYPE, MT_TOOL_FINGER);
> - ? ? ? ? ? ? ? ? ? ? ? if (w8001->trkid[i] < 0)
> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? w8001->trkid[i] = trkid++ & MAX_TRACKING_ID;
> + ? ? ? ? ? ? ? ? ? ? ? input_mt_report_slot_state(dev, true);
> ? ? ? ? ? ? ? ?} else {
> - ? ? ? ? ? ? ? ? ? ? ? w8001->trkid[i] = -1;
> + ? ? ? ? ? ? ? ? ? ? ? input_mt_report_slot_state(dev, false);
> ? ? ? ? ? ? ? ?}
> - ? ? ? ? ? ? ? input_report_abs(dev, ABS_MT_TRACKING_ID, w8001->trkid[i]);
> ? ? ? ?}
>
> ? ? ? ?input_sync(dev);
> @@ -319,8 +313,6 @@ static int w8001_setup(struct w8001 *w8001)
> ? ? ? ? ? ? ? ? ? ? ? ?w8001->pktlen = W8001_PKTLEN_TOUCH2FG;
>
> ? ? ? ? ? ? ? ? ? ? ? ?input_mt_init_slots(dev, 2);
> - ? ? ? ? ? ? ? ? ? ? ? input_set_abs_params(dev, ABS_MT_TRACKING_ID,
> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 0, MAX_TRACKING_ID, 0, 0);
> ? ? ? ? ? ? ? ? ? ? ? ?input_set_abs_params(dev, ABS_MT_POSITION_X,
> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?0, touch.x, 0, 0);
> ? ? ? ? ? ? ? ? ? ? ? ?input_set_abs_params(dev, ABS_MT_POSITION_Y,
> @@ -372,7 +364,6 @@ static int w8001_connect(struct serio *serio, struct serio_driver *drv)
> ? ? ? ?w8001->serio = serio;
> ? ? ? ?w8001->id = serio->id.id;
> ? ? ? ?w8001->dev = input_dev;
> - ? ? ? w8001->trkid[0] = w8001->trkid[1] = -1;
> ? ? ? ?init_completion(&w8001->cmd_done);
> ? ? ? ?snprintf(w8001->phys, sizeof(w8001->phys), "%s/input0", serio->phys);
>
> diff --git a/include/linux/input-mt.h b/include/linux/input-mt.h
> index d7f6518..1a44567 100644
> --- a/include/linux/input-mt.h
> +++ b/include/linux/input-mt.h
> @@ -13,6 +13,8 @@
>
> ?#include <linux/input.h>
>
> +#define TRKID_MAX ? ? ?0xffff
> +
> ?/**
> ?* struct input_mt_slot - represents the state of an input MT slot
> ?* @abs: holds current values of ABS_MT axes for this slot
> @@ -36,9 +38,18 @@ static inline int input_mt_get_value(const struct input_mt_slot *slot,
> ?int input_mt_init_slots(struct input_dev *dev, unsigned int num_slots);
> ?void input_mt_destroy_slots(struct input_dev *dev);
>
> +static inline int input_mt_new_trkid(struct input_dev *dev)
> +{
> + ? ? ? return dev->trkid++ & TRKID_MAX;
> +}
> +
> ?static inline void input_mt_slot(struct input_dev *dev, int slot)
> ?{
> ? ? ? ?input_event(dev, EV_ABS, ABS_MT_SLOT, slot);
> ?}
>
> +void input_mt_report_slot_state(struct input_dev *dev, bool active);
> +
> +void input_mt_report_pointer_emulation(struct input_dev *dev);
> +
> ?#endif
> diff --git a/include/linux/input.h b/include/linux/input.h
> index dd7c0fc..3b856d6 100644
> --- a/include/linux/input.h
> +++ b/include/linux/input.h
> @@ -1206,6 +1206,7 @@ struct input_dev {
> ? ? ? ?struct input_mt_slot *mt;
> ? ? ? ?int mtsize;
> ? ? ? ?int slot;
> + ? ? ? int trkid;
>
> ? ? ? ?struct input_absinfo *absinfo;
>
> --
> 1.7.1
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-input" in
> the body of a message to [email protected]
> More majordomo info at ?http://vger.kernel.org/majordomo-info.html
>
On 12/01/2010 09:21 AM, Henrik Rydberg wrote:
> The drivers using the type B protocol all report tracking information
> the same way. The contact id is semantically equivalent to
> ABS_MT_SLOT, and the handling of ABS_MT_TRACKING_ID only complicates
> the driver. The situation can be improved upon by providing a common
> pointer emulation code, thereby removing the need for the tracking id
> in the driver. This patch moves all tracking event handling over to
> the input core, simplifying both the existing drivers and the ones
> currently in preparation.
When two or more fingers are down, one of the fingers controls
ABS_{X,Y}. I think the aim is to emulate current behavior for
synaptics-style touchpads, which average the position in firmware. Thus,
we should be averaging the touch positions to generate the ABS_{X,Y} values.
-- Chase
On Mon, Dec 6, 2010 at 12:40 PM, Chase Douglas
<[email protected]> wrote:
> On 12/01/2010 09:21 AM, Henrik Rydberg wrote:
>> The drivers using the type B protocol all report tracking information
>> the same way. The contact id is semantically equivalent to
>> ABS_MT_SLOT, and the handling of ABS_MT_TRACKING_ID only complicates
>> the driver. The situation can be improved upon by providing a common
>> pointer emulation code, thereby removing the need for the tracking id
>> in the driver. ?This patch moves all tracking event handling over to
>> the input core, simplifying both the existing drivers and the ones
>> currently in preparation.
>
> When two or more fingers are down, one of the fingers controls
> ABS_{X,Y}. I think the aim is to emulate current behavior for
> synaptics-style touchpads, which average the position in firmware. Thus,
> we should be averaging the touch positions to generate the ABS_{X,Y} values.
>
At least for modern synaptics hardware, it does track to first touch
like this patch does.
It is maybe a weighted average were its 90% first finger and 10%
second finger. Just moving second finger gives slight movement.
I can't really speak for other touchpad behavior.
Chris
On 12/06/2010 11:52 AM, Chris Bagwell wrote:
> On Mon, Dec 6, 2010 at 12:40 PM, Chase Douglas
> <[email protected]> wrote:
>> On 12/01/2010 09:21 AM, Henrik Rydberg wrote:
>>> The drivers using the type B protocol all report tracking information
>>> the same way. The contact id is semantically equivalent to
>>> ABS_MT_SLOT, and the handling of ABS_MT_TRACKING_ID only complicates
>>> the driver. The situation can be improved upon by providing a common
>>> pointer emulation code, thereby removing the need for the tracking id
>>> in the driver. This patch moves all tracking event handling over to
>>> the input core, simplifying both the existing drivers and the ones
>>> currently in preparation.
>>
>> When two or more fingers are down, one of the fingers controls
>> ABS_{X,Y}. I think the aim is to emulate current behavior for
>> synaptics-style touchpads, which average the position in firmware. Thus,
>> we should be averaging the touch positions to generate the ABS_{X,Y} values.
>>
>
> At least for modern synaptics hardware, it does track to first touch
> like this patch does.
>
> It is maybe a weighted average were its 90% first finger and 10%
> second finger. Just moving second finger gives slight movement.
Ok. Does this present any usability issues, or does it seem to work fine
in your opinion? If it works ok in normal use cases then I'm fine with
how this is implemented.
-- Chase
On Mon, Dec 6, 2010 at 2:00 PM, Chase Douglas
<[email protected]> wrote:
> On 12/06/2010 11:52 AM, Chris Bagwell wrote:
>> On Mon, Dec 6, 2010 at 12:40 PM, Chase Douglas
>> <[email protected]> wrote:
>>> On 12/01/2010 09:21 AM, Henrik Rydberg wrote:
>>>> The drivers using the type B protocol all report tracking information
>>>> the same way. The contact id is semantically equivalent to
>>>> ABS_MT_SLOT, and the handling of ABS_MT_TRACKING_ID only complicates
>>>> the driver. The situation can be improved upon by providing a common
>>>> pointer emulation code, thereby removing the need for the tracking id
>>>> in the driver. ?This patch moves all tracking event handling over to
>>>> the input core, simplifying both the existing drivers and the ones
>>>> currently in preparation.
>>>
>>> When two or more fingers are down, one of the fingers controls
>>> ABS_{X,Y}. I think the aim is to emulate current behavior for
>>> synaptics-style touchpads, which average the position in firmware. Thus,
>>> we should be averaging the touch positions to generate the ABS_{X,Y} values.
>>>
>>
>> At least for modern synaptics hardware, it does track to first touch
>> like this patch does.
>>
>> It is maybe a weighted average were its 90% first finger and 10%
>> second finger. ?Just moving second finger gives slight movement.
>
> Ok. Does this present any usability issues, or does it seem to work fine
> in your opinion? If it works ok in normal use cases then I'm fine with
> how this is implemented.
Not averaging works fine in normal cases I've come up with. It works
best with dumbest of apps (those that don't even want to process
DOUBLETAP) as they will not see cursor jumps. It works fine for apps
that process DOUBLETAP and TRIPLETAP and specifically for tap and
swipe gestures where fingers are moving together anyways. We can't
reliably detect pinch or rotate motions without exact second fingers
data so not much reason to show 2nd finger movement there.
Click-and-drag on those click-pads are their own topic though. For
that case, I've tried to come up with something (show 2nd finger
movement by averaging or switch tracking) but either we will get a
cursor jump or else we will be confusing user land by sending a
DOUBLETAP when logically we want them to act as if 1 is touching. I
think MT is best solution for those.
Chris