From: "Alexander E. Patrakov" <[email protected]>

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

_______________________________________________
wayland-devel mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/wayland-devel

Reply via email to