mirror of
https://gitlab.freedesktop.org/libinput/libinput.git
synced 2026-02-03 20:30:27 +01:00
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>
This commit is contained in:
parent
c8ec33e72a
commit
0c50e186a0
4 changed files with 164 additions and 73 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
@ -611,43 +714,6 @@ tp_remove_buttons(struct tp_dispatch *tp)
|
|||
libinput_timer_cancel(&t->button.timer);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue