summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Hutterer <peter.hutterer@who-t.net>2015-01-14 14:54:43 +0100
committerPeter Hutterer <peter.hutterer@who-t.net>2015-01-16 10:34:24 +1000
commit0c50e186a05e831e1baaefa3889ef17b940504a8 (patch)
tree90d015d0cbae2daee0d676a01c8380e7dd3634cc
parentc8ec33e72a5146b60485e72264d496aba3299752 (diff)
touchpad: hook up click method configuration
Allow switching between softbuttons and clickfinger on any mt-capable clickpad. Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net> [hdegoede@redhat.com] Keep top softbuttons working when enabling clickfinger [hdegoede@redhat.com] Simply touchpad click method switching Signed-off-by: Hans de Goede <hdegoede@redhat.com>
-rw-r--r--doc/clickpad-softbuttons.dox6
-rw-r--r--src/evdev-mt-touchpad-buttons.c216
-rw-r--r--src/evdev-mt-touchpad.c4
-rw-r--r--src/evdev-mt-touchpad.h11
4 files changed, 164 insertions, 73 deletions
diff --git a/doc/clickpad-softbuttons.dox b/doc/clickpad-softbuttons.dox
index 2653c3b7..d9ebfbbc 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 6af3fcf1..ca7495f8 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 53a0bf21..5221be60 100644
--- a/src/evdev-mt-touchpad.c
+++ b/src/evdev-mt-touchpad.c
@@ -938,7 +938,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);
}
@@ -951,7 +951,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 7fe152a3..3479e5ea 100644
--- a/src/evdev-mt-touchpad.h
+++ b/src/evdev-mt-touchpad.h
@@ -243,7 +243,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;
@@ -306,9 +309,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);