diff options
-rw-r--r-- | doc/clickpad-softbuttons.dox | 6 | ||||
-rw-r--r-- | src/evdev-mt-touchpad-buttons.c | 216 | ||||
-rw-r--r-- | src/evdev-mt-touchpad.c | 4 | ||||
-rw-r--r-- | 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 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); |