[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