[PATCH 7/8] evdev-touchpad: Use multitouch for Sony touchpads

Alexander E. Patrakov patrakov at gmail.com
Mon Aug 5 03:34:36 PDT 2013


From: "Alexander E. Patrakov" <patrakov at gmail.com>

Track finger poritions and virtual buttons
---
 src/evdev-touchpad.c | 168 +++++++++++++++++++++++++++++++++++++++++++++------
 1 file changed, 149 insertions(+), 19 deletions(-)

diff --git a/src/evdev-touchpad.c b/src/evdev-touchpad.c
index 01c52aa..53de1e7 100644
--- a/src/evdev-touchpad.c
+++ b/src/evdev-touchpad.c
@@ -76,9 +76,10 @@ struct touchpad_motion {
 };
 
 enum touchpad_fingers_state {
-	TOUCHPAD_FINGERS_ONE   = (1 << 0),
-	TOUCHPAD_FINGERS_TWO   = (1 << 1),
-	TOUCHPAD_FINGERS_THREE = (1 << 2)
+	TOUCHPAD_FINGERS_NONE_YET = 1,
+	TOUCHPAD_FINGERS_ONE   = (1 << 1),
+	TOUCHPAD_FINGERS_TWO   = (1 << 2),
+	TOUCHPAD_FINGERS_THREE = (1 << 3)
 };
 
 enum fsm_event {
@@ -106,6 +107,7 @@ struct touchpad_dispatch {
 	int last_finger_state;
 	int slot;
 	int relevant_touch;
+	int virtual_buttons;
 
 	double constant_accel_factor;
 	double min_accel_factor;
@@ -127,6 +129,7 @@ struct touchpad_dispatch {
 
 		bool is_moving;
 		bool is_pressed;
+		bool tracking_id_changed;
 	} hw_abs[MAX_SLOTS + 1];
 
 	bool has_moved;
@@ -145,6 +148,11 @@ struct touchpad_dispatch {
 		int32_t center_y;
 	} hysteresis;
 
+	struct {
+		int32_t center_x;
+		int32_t separator_y;
+	} boundaries;
+
 	struct touchpad_motion motion_history[TOUCHPAD_HISTORY_LENGTH];
 	int motion_index;
 	unsigned int motion_count;
@@ -441,7 +449,7 @@ fsm_timout_handler(void *data)
 }
 
 static bool
-is_valid_touch(struct touchpad_dispatch *touchpad, int slot)
+is_valid_touch(struct touchpad_dispatch *touchpad, int slot, bool for_buttons)
 {
 	if (!touchpad->hw_abs[slot].x_valid)
 		return false;
@@ -449,6 +457,14 @@ is_valid_touch(struct touchpad_dispatch *touchpad, int slot)
 		return false;
 	if (!touchpad->hw_abs[slot].is_pressed)
 		return false;
+	if (touchpad->interaction_model == INTERACTION_MODEL_SONY) {
+		if (for_buttons &&
+		    touchpad->hw_abs[slot].y < touchpad->boundaries.separator_y)
+			return false;
+		if (!for_buttons &&
+		    touchpad->hw_abs[slot].y >= touchpad->boundaries.separator_y)
+			return false;
+	}
 	return true;
 }
 
@@ -466,12 +482,24 @@ touchpad_update_state(struct touchpad_dispatch *touchpad, uint32_t time)
 	int last_valid_touch = -1;
 	int relevant_touch = touchpad->relevant_touch;
 	bool reset_motion = false;
+	int mt_finger_state = TOUCHPAD_FINGERS_NONE_YET;
 
-	for (i = 0; i < MAX_SLOTS; i++)
-		if (is_valid_touch(touchpad, i)) {
+	for (i = 0; i < MAX_SLOTS; i++) {
+		if (touchpad->hw_abs[i].tracking_id_changed)
+			touchpad->hw_abs[i].tracking_id_changed = false;
+		else if (is_valid_touch(touchpad, i, false)) {
 			touch_state |= 1 << i;
 			last_valid_touch = i;
+			if (mt_finger_state < TOUCHPAD_FINGERS_THREE)
+				mt_finger_state = mt_finger_state << 1;
 		}
+	}
+
+	if (touchpad->interaction_model == INTERACTION_MODEL_SONY) {
+		touchpad->finger_state = 0;
+		if (mt_finger_state != TOUCHPAD_FINGERS_NONE_YET)
+			touchpad->finger_state = mt_finger_state;
+	}
 
 	if (touch_state && !touchpad->touch_state) {
 		push_fsm_event(touchpad, FSM_EVENT_TOUCH);
@@ -634,13 +662,81 @@ process_absolute(struct touchpad_dispatch *touchpad,
 }
 
 static inline void
+process_absolute_sony(struct touchpad_dispatch *touchpad,
+		      struct evdev_device *device,
+		      struct input_event *e)
+{
+	int slot = touchpad->slot;
+	switch (e->code) {
+	case ABS_MT_SLOT:
+		slot = e->value;
+		if (slot < 0 || slot >= MAX_SLOTS)
+			slot = MAX_SLOTS;
+		touchpad->slot = slot;
+		break;
+	case ABS_MT_TRACKING_ID:
+		touchpad->hw_abs[slot].tracking_id_changed = true;
+		touchpad->hw_abs[slot].x_valid = false;
+		touchpad->hw_abs[slot].y_valid = false;
+		touchpad->hw_abs[slot].is_pressed = false;
+		touchpad->hw_abs[slot].is_moving = false;
+		break;
+	case ABS_MT_PRESSURE:
+		if (e->value > touchpad->pressure.touch_high &&
+		    !touchpad->hw_abs[slot].is_pressed)
+			on_touch(touchpad, slot);
+		else if (e->value < touchpad->pressure.touch_low &&
+			 touchpad->hw_abs[slot].is_pressed)
+			on_release(touchpad, slot);
+		break;
+	case ABS_MT_POSITION_X:
+		if (touchpad->hw_abs[slot].is_pressed) {
+			touchpad->hw_abs[slot].x = e->value;
+			touchpad->hw_abs[slot].x_valid = true;
+			touchpad->hw_abs[slot].is_moving = true;
+		}
+		break;
+	case ABS_MT_POSITION_Y:
+		if (touchpad->hw_abs[slot].is_pressed) {
+			touchpad->hw_abs[slot].y = e->value;
+			touchpad->hw_abs[slot].y_valid = true;
+			touchpad->hw_abs[slot].is_moving = true;
+		}
+		break;
+	}
+}
+
+static int
+get_virtual_buttons_pressed(struct touchpad_dispatch* touchpad)
+{
+	int slot;
+	int result = 0;
+
+	if (touchpad->interaction_model == INTERACTION_MODEL_SIMPLE)
+		return 1;
+
+	if (touchpad->interaction_model == INTERACTION_MODEL_APPLE)
+		return (touchpad->finger_state == TOUCHPAD_FINGERS_TWO) ? 2 : 1;
+
+	/* And the remaining part is for Sony */
+
+	for (slot = 0; slot < MAX_SLOTS; slot++) {
+		if (!is_valid_touch(touchpad, slot, true))
+			continue;
+		if (touchpad->hw_abs[slot].x < touchpad->boundaries.center_x)
+			result |= 1;
+		else
+			result |= 2;
+	}
+	return result;
+}
+
+static inline void
 process_key(struct touchpad_dispatch *touchpad,
 	    struct evdev_device *device,
 	    struct input_event *e,
 	    uint32_t time)
 {
-	uint32_t code;
-
 	switch (e->code) {
 	case BTN_TOUCH:
 		if (!touchpad->has_pressure) {
@@ -651,6 +747,24 @@ process_key(struct touchpad_dispatch *touchpad,
 		}
 		break;
 	case BTN_LEFT:
+		if (e->value) {
+			touchpad->virtual_buttons = get_virtual_buttons_pressed(touchpad);
+			if (touchpad->virtual_buttons & 1)
+				notify_button(device->seat, time, BTN_LEFT,
+					WL_POINTER_BUTTON_STATE_PRESSED);
+			if (touchpad->virtual_buttons & 2)
+				notify_button(device->seat, time, BTN_RIGHT,
+					WL_POINTER_BUTTON_STATE_PRESSED);
+		} else {
+			if (touchpad->virtual_buttons & 2)
+				notify_button(device->seat, time, BTN_RIGHT,
+					WL_POINTER_BUTTON_STATE_RELEASED);
+			if (touchpad->virtual_buttons & 1)
+				notify_button(device->seat, time, BTN_LEFT,
+					WL_POINTER_BUTTON_STATE_RELEASED);
+			touchpad->virtual_buttons = 0;
+		}
+		break;
 	case BTN_RIGHT:
 	case BTN_MIDDLE:
 	case BTN_SIDE:
@@ -658,15 +772,9 @@ process_key(struct touchpad_dispatch *touchpad,
 	case BTN_FORWARD:
 	case BTN_BACK:
 	case BTN_TASK:
-		if (touchpad->interaction_model == INTERACTION_MODEL_APPLE &&
-		    e->code == BTN_LEFT &&
-		    touchpad->finger_state == TOUCHPAD_FINGERS_TWO)
-			code = BTN_RIGHT;
-		else
-			code = e->code;
-		notify_button(device->seat, time, code,
-			      e->value ? WL_POINTER_BUTTON_STATE_PRESSED :
-			                 WL_POINTER_BUTTON_STATE_RELEASED);
+		notify_button(device->seat, time, e->code,
+			e->value ? WL_POINTER_BUTTON_STATE_PRESSED :
+				   WL_POINTER_BUTTON_STATE_PRESSED);
 		break;
 	case BTN_TOOL_PEN:
 	case BTN_TOOL_RUBBER:
@@ -685,18 +793,24 @@ process_key(struct touchpad_dispatch *touchpad,
 		}
 		break;
 	case BTN_TOOL_FINGER:
+		if (touchpad->interaction_model == INTERACTION_MODEL_SONY)
+			break;
 		if (e->value)
 			touchpad->finger_state |= TOUCHPAD_FINGERS_ONE;
 		else
 			touchpad->finger_state &= ~TOUCHPAD_FINGERS_ONE;
 		break;
 	case BTN_TOOL_DOUBLETAP:
+		if (touchpad->interaction_model == INTERACTION_MODEL_SONY)
+			break;
 		if (e->value)
 			touchpad->finger_state |= TOUCHPAD_FINGERS_TWO;
 		else
 			touchpad->finger_state &= ~TOUCHPAD_FINGERS_TWO;
 		break;
 	case BTN_TOOL_TRIPLETAP:
+		if (touchpad->interaction_model == INTERACTION_MODEL_SONY)
+			break;
 		if (e->value)
 			touchpad->finger_state |= TOUCHPAD_FINGERS_THREE;
 		else
@@ -720,7 +834,10 @@ touchpad_process(struct evdev_dispatch *dispatch,
 			touchpad_update_state(touchpad, time);
 		break;
 	case EV_ABS:
-		process_absolute(touchpad, device, e);
+		if (touchpad->interaction_model == INTERACTION_MODEL_SONY)
+			process_absolute_sony(touchpad, device, e);
+		else
+			process_absolute(touchpad, device, e);
 		break;
 	case EV_KEY:
 		process_key(touchpad, device, e, time);
@@ -765,6 +882,16 @@ touchpad_init(struct touchpad_dispatch *touchpad,
 	touchpad->model = get_touchpad_model(device);
 	configure_interaction_model(touchpad);
 
+	if (touchpad->interaction_model == INTERACTION_MODEL_SONY) {
+		ioctl(device->fd, EVIOCGABS(ABS_MT_SLOT), &absinfo);
+		touchpad->slot = absinfo.value;
+		if (touchpad->slot < 0 || touchpad->slot >= MAX_SLOTS)
+			touchpad->slot = MAX_SLOTS;
+	} else {
+		touchpad->slot = 0;
+	}
+	touchpad->virtual_buttons = 0;
+
 	/* Configure pressure */
 	ioctl(device->fd, EVIOCGBIT(EV_ABS, sizeof(abs_bits)), abs_bits);
 	if (TEST_BIT(abs_bits, ABS_PRESSURE)) {
@@ -792,6 +919,10 @@ touchpad_init(struct touchpad_dispatch *touchpad,
 	touchpad->hysteresis.center_x = 0;
 	touchpad->hysteresis.center_y = 0;
 
+	/* Relevant for Sony touchpads only */
+	touchpad->boundaries.center_x = device->abs.min_x + width / 2;
+	touchpad->boundaries.separator_y = device->abs.min_y + 3 * height / 5;
+
 	/* Configure acceleration profile */
 	accel = create_pointer_accelator_filter(touchpad_profile);
 	if (accel == NULL)
@@ -805,7 +936,6 @@ touchpad_init(struct touchpad_dispatch *touchpad,
 
 	memset(touchpad->hw_abs, 0, sizeof touchpad->hw_abs);
 
-	touchpad->slot = MAX_SLOTS;
 	touchpad->relevant_touch = -1;
 
 	touchpad->has_moved = false;
-- 
1.8.3.2



More information about the wayland-devel mailing list