From: Peter Hutterer <peter.hutte...@who-t.net>

Allow switching between softbuttons and clickfinger on any mt-capable
clickpad.

Signed-off-by: Peter Hutterer <peter.hutte...@who-t.net>
[hdego...@redhat.com] Keep top softbuttons working when enabling clickfinger
[hdego...@redhat.com] Simply touchpad click method switching
Signed-off-by: Hans de Goede <hdego...@redhat.com>
---
 doc/clickpad-softbuttons.dox    |   6 ++
 src/evdev-mt-touchpad-buttons.c | 216 +++++++++++++++++++++++++++-------------
 src/evdev-mt-touchpad.c         |   4 +-
 src/evdev-mt-touchpad.h         |  11 +-
 4 files changed, 164 insertions(+), 73 deletions(-)

diff --git a/doc/clickpad-softbuttons.dox b/doc/clickpad-softbuttons.dox
index 2653c3b..d9ebfbb 100644
--- a/doc/clickpad-softbuttons.dox
+++ b/doc/clickpad-softbuttons.dox
@@ -66,6 +66,12 @@ The Xorg synaptics driver uses 30% of the touchpad 
dimensions as threshold,
 libinput does not have this restriction. If two fingers are on the pad
 while clicking, that is a two-finger click.
 
+Clickfinger configuration can be enabled through the
+libinput_device_config_click_set_method() call. If clickfingers are
+enabled on a touchpad with top software buttons, the top area will keep
+acting as softbuttons for use with the trackpoint. Clickfingers will be used
+everywhere else on the touchpad.
+
 @section special_clickpads Special Clickpads
 
 The Lenovo *40 series laptops have a clickpad that provides two software 
button sections, one at
diff --git a/src/evdev-mt-touchpad-buttons.c b/src/evdev-mt-touchpad-buttons.c
index 6af3fcf..ca7495f 100644
--- a/src/evdev-mt-touchpad-buttons.c
+++ b/src/evdev-mt-touchpad-buttons.c
@@ -494,10 +494,9 @@ tp_release_all_buttons(struct tp_dispatch *tp,
        }
 }
 
-void
+static void
 tp_init_softbuttons(struct tp_dispatch *tp,
-                   struct evdev_device *device,
-                   double topbutton_size_mult)
+                   struct evdev_device *device)
 {
        int width, height;
        const struct input_absinfo *absinfo_x, *absinfo_y;
@@ -523,6 +522,26 @@ tp_init_softbuttons(struct tp_dispatch *tp,
        }
 
        tp->buttons.bottom_area.rightbutton_left_edge = width/2 + xoffset;
+}
+
+void
+tp_init_top_softbuttons(struct tp_dispatch *tp,
+                       struct evdev_device *device,
+                       double topbutton_size_mult)
+{
+       int width, height;
+       const struct input_absinfo *absinfo_x, *absinfo_y;
+       int xoffset, yoffset;
+       int yres;
+
+       absinfo_x = device->abs.absinfo_x;
+       absinfo_y = device->abs.absinfo_y;
+
+       xoffset = absinfo_x->minimum,
+       yoffset = absinfo_y->minimum;
+       yres = absinfo_y->resolution;
+       width = abs(absinfo_x->maximum - absinfo_x->minimum);
+       height = abs(absinfo_y->maximum - absinfo_y->minimum);
 
        if (tp->buttons.has_topbuttons) {
                /* T440s has the top button line 5mm from the top, event
@@ -545,6 +564,89 @@ tp_init_softbuttons(struct tp_dispatch *tp,
        }
 }
 
+static inline uint32_t
+tp_button_config_click_get_methods(struct libinput_device *device)
+{
+       struct evdev_device *evdev = (struct evdev_device*)device;
+       struct tp_dispatch *tp = (struct tp_dispatch*)evdev->dispatch;
+       uint32_t methods = LIBINPUT_CONFIG_CLICK_METHOD_NONE;
+
+       if (tp->buttons.is_clickpad) {
+               methods |= LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS;
+               if (tp->has_mt)
+                       methods |= LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER;
+       }
+
+       return methods;
+}
+
+static void
+tp_switch_click_method(struct tp_dispatch *tp)
+{
+       /*
+        * All we need to do when switching click methods is to change the
+        * bottom_area.top_edge so that when in clickfinger mode the bottom
+        * touchpad area is not dead wrt finger movement starting there.
+        *
+        * We do not need to take any state into account, fingers which are
+        * already down will simply keep the state / area they have assigned
+        * until they are released, and the post_button_events path is state
+        * agnostic.
+        */
+
+       switch (tp->buttons.click_method) {
+       case LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS:
+               tp_init_softbuttons(tp, tp->device);
+               break;
+       case LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER:
+       case LIBINPUT_CONFIG_CLICK_METHOD_NONE:
+               tp->buttons.bottom_area.top_edge = INT_MAX;
+               break;
+       }
+}
+
+static enum libinput_config_status
+tp_button_config_click_set_method(struct libinput_device *device,
+                                 enum libinput_config_click_method method)
+{
+       struct evdev_device *evdev = (struct evdev_device*)device;
+       struct tp_dispatch *tp = (struct tp_dispatch*)evdev->dispatch;
+
+       tp->buttons.click_method = method;
+       tp_switch_click_method(tp);
+
+       return LIBINPUT_CONFIG_STATUS_SUCCESS;
+}
+
+static enum libinput_config_click_method
+tp_button_config_click_get_method(struct libinput_device *device)
+{
+       struct evdev_device *evdev = (struct evdev_device*)device;
+       struct tp_dispatch *tp = (struct tp_dispatch*)evdev->dispatch;
+
+       return tp->buttons.click_method;
+}
+
+static enum libinput_config_click_method
+tp_click_get_default_method(struct tp_dispatch *tp)
+{
+       if (!tp->buttons.is_clickpad)
+               return LIBINPUT_CONFIG_CLICK_METHOD_NONE;
+       else if (libevdev_get_id_vendor(tp->device->evdev) == VENDOR_ID_APPLE)
+               return LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER;
+       else
+               return LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS;
+}
+
+static enum libinput_config_click_method
+tp_button_config_click_get_default_method(struct libinput_device *device)
+{
+       struct evdev_device *evdev = (struct evdev_device*)device;
+       struct tp_dispatch *tp = (struct tp_dispatch*)evdev->dispatch;
+
+       return tp_click_get_default_method(tp);
+}
+
 int
 tp_init_buttons(struct tp_dispatch *tp,
                struct evdev_device *device)
@@ -582,15 +684,16 @@ tp_init_buttons(struct tp_dispatch *tp,
 
        tp->buttons.motion_dist = diagonal * DEFAULT_BUTTON_MOTION_THRESHOLD;
 
-       if (libevdev_get_id_vendor(device->evdev) == VENDOR_ID_APPLE)
-               tp->buttons.use_clickfinger = true;
+       tp->buttons.config_method.get_methods = 
tp_button_config_click_get_methods;
+       tp->buttons.config_method.set_method = 
tp_button_config_click_set_method;
+       tp->buttons.config_method.get_method = 
tp_button_config_click_get_method;
+       tp->buttons.config_method.get_default_method = 
tp_button_config_click_get_default_method;
+       tp->device->base.config.click_method = &tp->buttons.config_method;
 
-       if (tp->buttons.is_clickpad && !tp->buttons.use_clickfinger) {
-               tp_init_softbuttons(tp, device, 1.0);
-       } else {
-               tp->buttons.bottom_area.top_edge = INT_MAX;
-               tp->buttons.top_area.bottom_edge = INT_MIN;
-       }
+       tp->buttons.click_method = tp_click_get_default_method(tp);
+       tp_switch_click_method(tp);
+
+       tp_init_top_softbuttons(tp, device, 1.0);
 
        tp_for_each_touch(tp, t) {
                t->button.state = BUTTON_STATE_NONE;
@@ -612,43 +715,6 @@ tp_remove_buttons(struct tp_dispatch *tp)
 }
 
 static int
-tp_post_clickfinger_buttons(struct tp_dispatch *tp, uint64_t time)
-{
-       uint32_t current, old, button;
-       enum libinput_button_state state;
-
-       current = tp->buttons.state;
-       old = tp->buttons.old_state;
-
-       if (current == old)
-               return 0;
-
-       if (current) {
-               switch (tp->nfingers_down) {
-               case 1: button = BTN_LEFT; break;
-               case 2: button = BTN_RIGHT; break;
-               case 3: button = BTN_MIDDLE; break;
-               default:
-                       return 0;
-               }
-               tp->buttons.active = button;
-               state = LIBINPUT_BUTTON_STATE_PRESSED;
-       } else {
-               button = tp->buttons.active;
-               tp->buttons.active = 0;
-               state = LIBINPUT_BUTTON_STATE_RELEASED;
-       }
-
-       if (button) {
-               evdev_pointer_notify_button(tp->device,
-                                           time,
-                                           button,
-                                           state);
-       }
-       return 1;
-}
-
-static int
 tp_post_physical_buttons(struct tp_dispatch *tp, uint64_t time)
 {
        uint32_t current, old, button;
@@ -683,12 +749,12 @@ tp_post_physical_buttons(struct tp_dispatch *tp, uint64_t 
time)
        return 0;
 }
 
-static void
-tp_notify_softbutton(struct tp_dispatch *tp,
-                    uint64_t time,
-                    uint32_t button,
-                    uint32_t is_topbutton,
-                    enum libinput_button_state state)
+static int
+tp_notify_clickpadbutton(struct tp_dispatch *tp,
+                        uint64_t time,
+                        uint32_t button,
+                        uint32_t is_topbutton,
+                        enum libinput_button_state state)
 {
        /* If we've a trackpoint, send top buttons through the trackpoint */
        if (is_topbutton && tp->buttons.trackpoint) {
@@ -702,18 +768,38 @@ tp_notify_softbutton(struct tp_dispatch *tp,
                event.value = (state == LIBINPUT_BUTTON_STATE_PRESSED) ? 1 : 0;
                dispatch->interface->process(dispatch, tp->buttons.trackpoint,
                                             &event, time);
-               return;
+               return 1;
        }
 
        /* Ignore button events not for the trackpoint while suspended */
        if (tp->device->suspended)
-               return;
+               return 0;
+
+       /*
+        * If the user has requested clickfinger replace the button chosen
+        * by the softbutton code with one based on the number of fingers.
+        */
+       if (tp->buttons.click_method == 
LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER &&
+                       state == LIBINPUT_BUTTON_STATE_PRESSED) {
+               switch (tp->nfingers_down) {
+               case 1: button = BTN_LEFT; break;
+               case 2: button = BTN_RIGHT; break;
+               case 3: button = BTN_MIDDLE; break;
+               default:
+                       button = 0;
+               }
+               tp->buttons.active = button;
+
+               if (!button)
+                       return 0;
+       }
 
        evdev_pointer_notify_button(tp->device, time, button, state);
+       return 1;
 }
 
 static int
-tp_post_softbutton_buttons(struct tp_dispatch *tp, uint64_t time)
+tp_post_clickpadbutton_buttons(struct tp_dispatch *tp, uint64_t time)
 {
        uint32_t current, old, button, is_top;
        enum libinput_button_state state;
@@ -783,22 +869,18 @@ tp_post_softbutton_buttons(struct tp_dispatch *tp, 
uint64_t time)
        tp->buttons.click_pending = false;
 
        if (button)
-               tp_notify_softbutton(tp, time, button, is_top, state);
+               return tp_notify_clickpadbutton(tp, time, button, is_top, 
state);
 
-       return 1;
+       return 0;
 }
 
 int
 tp_post_button_events(struct tp_dispatch *tp, uint64_t time)
 {
-       if (tp->buttons.is_clickpad) {
-               if (tp->buttons.use_clickfinger)
-                       return tp_post_clickfinger_buttons(tp, time);
-               else
-                       return tp_post_softbutton_buttons(tp, time);
-       }
-
-       return tp_post_physical_buttons(tp, time);
+       if (tp->buttons.is_clickpad)
+               return tp_post_clickpadbutton_buttons(tp, time);
+       else
+               return tp_post_physical_buttons(tp, time);
 }
 
 int
diff --git a/src/evdev-mt-touchpad.c b/src/evdev-mt-touchpad.c
index e778b06..ebbebb4 100644
--- a/src/evdev-mt-touchpad.c
+++ b/src/evdev-mt-touchpad.c
@@ -816,7 +816,7 @@ tp_suspend(struct tp_dispatch *tp, struct evdev_device 
*device)
        if (tp->buttons.has_topbuttons) {
                evdev_notify_suspended_device(device);
                /* Enlarge topbutton area while suspended */
-               tp_init_softbuttons(tp, device, 1.5);
+               tp_init_top_softbuttons(tp, device, 1.5);
        } else {
                evdev_device_suspend(device);
        }
@@ -829,7 +829,7 @@ tp_resume(struct tp_dispatch *tp, struct evdev_device 
*device)
                /* tap state-machine is offline while suspended, reset state */
                tp_clear_state(tp);
                /* restore original topbutton area size */
-               tp_init_softbuttons(tp, device, 1.0);
+               tp_init_top_softbuttons(tp, device, 1.0);
                evdev_notify_resumed_device(device);
        } else {
                evdev_device_resume(device);
diff --git a/src/evdev-mt-touchpad.h b/src/evdev-mt-touchpad.h
index 5807f08..10225ec 100644
--- a/src/evdev-mt-touchpad.h
+++ b/src/evdev-mt-touchpad.h
@@ -236,7 +236,10 @@ struct tp_dispatch {
                } top_area;
 
                struct evdev_device *trackpoint;
-       } buttons;                              /* physical buttons */
+
+               enum libinput_config_click_method click_method;
+               struct libinput_device_config_click_method config_method;
+       } buttons;
 
        struct {
                struct libinput_device_config_scroll_method config_method;
@@ -299,9 +302,9 @@ int
 tp_init_buttons(struct tp_dispatch *tp, struct evdev_device *device);
 
 void
-tp_init_softbuttons(struct tp_dispatch *tp,
-                   struct evdev_device *device,
-                   double topbutton_size_mult);
+tp_init_top_softbuttons(struct tp_dispatch *tp,
+                       struct evdev_device *device,
+                       double topbutton_size_mult);
 
 void
 tp_remove_buttons(struct tp_dispatch *tp);
-- 
2.1.0

_______________________________________________
wayland-devel mailing list
wayland-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/wayland-devel

Reply via email to