Add semi-mt support. Kernel drivers for 'semi-mt' devices, such as the Synaptics profile sensor, do not provide a pressure value with their semi-mt slots. Instead, they report a single pressure value via ABS_PRESSURE. So, if the device's INPUT_PROP_SEMI_MT bit is set we use the ABS_PRESSURE value to set the height/width of all plotted circles. BUG=chromium-os:24277 TEST=mtplot And see if the touch events could be drawn on Cr-48. Change-Id: I4c3d564fc7fd902b7cdae0ac5850730f07ffde86
diff --git a/mtplot.c b/mtplot.c index bc1ce9c..edb6479 100644 --- a/mtplot.c +++ b/mtplot.c
@@ -18,6 +18,7 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <stdbool.h> #include <X11/Xlib.h> #define BITS_PER_LONG (sizeof(long) * 8) @@ -27,6 +28,8 @@ #define LONG(x) ((x)/BITS_PER_LONG) #define test_bit(bit, array) ((array[LONG(bit)] >> OFF(bit)) & 1) #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) +#define LONG_BITS (sizeof(long) * 8) +#define NLONGS(x) (((x) + LONG_BITS - 1) / LONG_BITS) #define DEV_INPUT_EVENT "/dev/input" #define EVENT_DEV_NAME "event" @@ -448,6 +451,8 @@ static int pressure_min = 0; static int pressure_max = 255; +static bool semi_mt_device = false; + static unsigned int w_width; static unsigned int w_height; @@ -511,7 +516,7 @@ unsigned int width, height; unsigned long forecolor; - if (s->track_id == -1 || s->pressure == 0) + if ((s->track_id == -1) || (s->pressure == 0)) return; // TODO: Get really fancy and use touch_minor & orientation @@ -555,6 +560,17 @@ XClearWindow(dpy, w); } +// Update all active slots with the same ABS_PRESSURE value as it is a +// semi-mt device. +static void UpdateWithAbsPressure(struct mt_state *s, struct input_event *e) { + int i; + for (i = slot_min; i <= slot_max; i++) { + struct mt_slot *slt = &s->slot[i]; + if (slt->track_id != -1) + slt->pressure = e->value; + } +} + static void ProcessAbs(struct mt_state *s, struct input_event *e) { struct mt_slot *slot = &s->slot[s->current]; @@ -594,6 +610,10 @@ case ABS_MT_PRESSURE: slot->pressure = e->value; break; + case ABS_PRESSURE: + if (semi_mt_device) + UpdateWithAbsPressure(s, e); + break; default: break; } @@ -696,6 +716,8 @@ y_min = abs[k]; else if (axis == ABS_MT_PRESSURE) pressure_min = abs[k]; + else if (axis == ABS_PRESSURE) + pressure_min = abs[k]; } else if (k == 2) { if (axis == ABS_MT_SLOT) slot_max = abs[k]; @@ -705,10 +727,27 @@ y_max = abs[k]; else if (axis == ABS_MT_PRESSURE) pressure_max = abs[k]; + else if (axis == ABS_PRESSURE) + pressure_max = abs[k]; } } } +// Test if the INPUT_PROP_SEMI_MT bit is set. If so, we will retrieve the +// pressure value from the element ABS_PRESSURE instead. +// +// @param fd The file descriptor to the device. +// @return true if the bit INPUT_PROP_SEMI_MT is set, or zero otherwise. +static bool IsSemiMtDevice(int fd) { + unsigned long prop_bitmask[NLONGS(INPUT_PROP_CNT)]; + int len = ioctl(fd, EVIOCGPROP(sizeof(prop_bitmask)), prop_bitmask); + if (len < 0) { + printf("get properties error: %s\n", strerror(errno)); + return false; + } + return test_bit(INPUT_PROP_SEMI_MT, prop_bitmask); +} + // Print static device information (no events). This information includes // version numbers, device name and all bits supported by this device. // @@ -839,6 +878,9 @@ if (PrintDeviceInfo(fd)) return EXIT_FAILURE; + if (IsSemiMtDevice(fd)) + semi_mt_device = true; + printf("Testing ... (interrupt to exit)\n"); if (TestGrab(fd)) {