Add support for Apple Magic Trackpad
Apple Magic Trackpad can track individual touch contact but
its driver follows MT-A protocol instead of MT-B protocol.
Specifically, the driver reports event ABS_MT_TRACKING_ID as
the indication of state machine change, instead of reporting
ABS_MT_SLOT event.
This CL makes mtplot work with Apple Magic Trackpad by:
1. Current slot is updated with new ABS_MT_TRACKING_ID.
2. 0 touch major value means current slot (touch contact) is
removed.
3. Use a touch_major value for drawing since the touchpad
does not report pressure value.
BUG=chromium-os:29435
TEST=Connect Stumpy with Apple Magic Trackpad and check that
mtplot works.
Change-Id: Iea827ff36590b7edf9602ca6a3db60c00f0efc66
diff --git a/mtplot.c b/mtplot.c
index d6c5174..9384337 100644
--- a/mtplot.c
+++ b/mtplot.c
@@ -461,8 +461,11 @@
static int y_max = 0;
static int pressure_min = 0;
static int pressure_max = 255;
+static int touch_major_min = 0;
+static int touch_major_max = 255;
static bool semi_mt_device = false;
+static bool has_mt_slot = false;
static unsigned int w_width;
static unsigned int w_height;
@@ -527,13 +530,21 @@
unsigned int width, height;
unsigned long forecolor;
- if ((s->track_id == -1) || (s->pressure == 0))
+ if (s->track_id == -1)
return;
- // TODO: Get really fancy and use touch_minor & orientation
- // TODO: Get really really fancy, and use 'width_*'
- width = 50 * (s->pressure - pressure_min) / (pressure_max - pressure_min);
- height = 50 * (s->pressure - pressure_min) / (pressure_max - pressure_min);
+ if (s->pressure) {
+ // TODO: Get really fancy and use touch_minor & orientation
+ // TODO: Get really really fancy, and use 'width_*'
+ width = 50 * (s->pressure - pressure_min) / (pressure_max - pressure_min);
+ height = 50 * (s->pressure - pressure_min) / (pressure_max - pressure_min);
+ } else {
+ // In case we don't have pressure reading, use touch_major instead.
+ width = 50 * (s->touch_major - touch_major_min) /
+ (touch_major_max - touch_major_min);
+ height = 50 * (s->touch_major - touch_major_min) /
+ (touch_major_max - touch_major_min);
+ }
// TODO: Update x/y_min/max on window resize
x = (s->x - x_min) * w_width / (x_max - x_min) - (width - 1) / 2;
@@ -584,6 +595,23 @@
}
}
+// Associate the track ID with slot number.
+static int track_id_to_slot(struct mt_state *s, int track_id) {
+ int i;
+ // For existing track ID, return its associated slot.
+ for (i = slot_min; i <= slot_max; i++)
+ if (s->slot[i].track_id == track_id)
+ return i;
+
+ // For new track ID, return a free slot.
+ for (i = slot_min; i <= slot_max; i++)
+ if (s->slot[i].track_id == -1)
+ return i;
+
+ perror("No free slot for for new track_id");
+ return slot_min;
+}
+
static void ProcessAbs(struct mt_state *s, struct input_event *e) {
struct mt_slot *slot = &s->slot[s->current];
@@ -592,6 +620,10 @@
s->current = e->value;
break;
case ABS_MT_TOUCH_MAJOR:
+ // If there is no ABS_MT_SLOT support, use a 0 touch major as
+ // the indication of removed touch contact.
+ if (!has_mt_slot && e->value == 0)
+ slot->track_id = -1;
slot->touch_major = e->value;
break;
case ABS_MT_TOUCH_MINOR:
@@ -618,6 +650,13 @@
case ABS_MT_BLOB_ID:
break;
case ABS_MT_TRACKING_ID:
+ // If there is no ABS_MT_SLOT support, use ABS_MT_TRACKING_ID as
+ // replacement. If new ABS_MT_TRACKING_ID is received, update the
+ // current slot to be the one associated with the new track ID.
+ if (!has_mt_slot && e->value >= 0) {
+ s->current = track_id_to_slot(s, e->value);
+ slot = &s->slot[s->current];
+ }
slot->track_id = e->value;
break;
case ABS_MT_PRESSURE:
@@ -723,6 +762,8 @@
pressure_min = abs[k];
else if (axis == ABS_PRESSURE)
pressure_min = abs[k];
+ else if (axis == ABS_MT_TOUCH_MAJOR)
+ touch_major_min = abs[k];
} else if (k == 2) {
if (axis == ABS_MT_SLOT)
slot_max = abs[k];
@@ -734,6 +775,8 @@
pressure_max = abs[k];
else if (axis == ABS_PRESSURE)
pressure_max = abs[k];
+ else if (axis == ABS_MT_TOUCH_MAJOR)
+ touch_major_max = abs[k];
}
}
}
@@ -794,8 +837,11 @@
if (test_bit(j, bit[i])) {
printf(" Event code %d (%s)\n", j,
names[i] ? (names[i][j] ? names[i][j] : "?") : "?");
- if (i == EV_ABS)
+ if (i == EV_ABS) {
PrintAbsData(fd, j);
+ if (j == ABS_MT_SLOT)
+ has_mt_slot = true;
+ }
}
}