touchpad: add clickfinger button map

Part-of: <https://gitlab.freedesktop.org/libinput/libinput/-/merge_requests/988>
This commit is contained in:
Tarcísio Eduardo Moreira Crocomo 2024-04-09 18:46:42 -03:00
parent 1d5d45a251
commit 46d1fff0b0
16 changed files with 385 additions and 34 deletions

View file

@ -50,6 +50,10 @@ __all_seats()
'--apply-to=[Apply configuration options where the device name matches the pattern]:pattern' \ '--apply-to=[Apply configuration options where the device name matches the pattern]:pattern' \
'--disable-sendevents=[Disable send-events option for the devices matching the pattern]:pattern' \ '--disable-sendevents=[Disable send-events option for the devices matching the pattern]:pattern' \
'--set-click-method=[Set the desired click method]:click-method:(none clickfinger buttonareas)' \ '--set-click-method=[Set the desired click method]:click-method:(none clickfinger buttonareas)' \
'--set-clickfinger-map=[Set button mapping for clickfinger]:tap-map:(( \
lrm\:2-fingers\ right-click\ /\ 3-fingers\ middle-click \
lmr\:2-fingers\ middle-click\ /\ 3-fingers\ right-click \
))' \
'--set-scroll-method=[Set the desired scroll method]:scroll-method:(none twofinger edge button)' \ '--set-scroll-method=[Set the desired scroll method]:scroll-method:(none twofinger edge button)' \
'--set-scroll-button=[Set the button to the given button code]' \ '--set-scroll-button=[Set the button to the given button code]' \
'--set-profile=[Set pointer acceleration profile]:accel-profile:(adaptive flat)' \ '--set-profile=[Set pointer acceleration profile]:accel-profile:(adaptive flat)' \

View file

@ -102,11 +102,12 @@ ignores such button clicks, this behavior is intentional.
Clickfinger behavior Clickfinger behavior
------------------------------------------------------------------------------ ------------------------------------------------------------------------------
This is the default behavior on Apple touchpads. This is the default behavior on Apple touchpads. Here, a left, right, middle
Here, a left, right, middle button event is generated when one, two, or button event is generated when one, two, or three fingers are held down on the
three fingers are held down on the touchpad when a physical click is touchpad when a physical click is generated, given the default mapping. The
generated. The location of the fingers does not matter and there are no location of the fingers does not matter and there are no software-defined
software-defined button areas. button areas. It is possible to swap right and middle buttons, the same way as
with :ref:`tapping <tapping>`.
.. figure:: clickfinger.svg .. figure:: clickfinger.svg
:align: center :align: center

View file

@ -8,12 +8,13 @@ Tap-to-click behaviour
finger touch down/up sequence maps into a button click. This is most finger touch down/up sequence maps into a button click. This is most
commonly used on touchpads, but may be available on other devices. commonly used on touchpads, but may be available on other devices.
libinput implements tapping for one, two, and three fingers, where supported libinput implements tapping for one, two, and three fingers, where supported by
by the hardware, and maps those taps into a left, right, and middle button the hardware, and maps those taps into a left, right, and middle button click,
click, respectively. Not all devices support three fingers, libinput will respectively. This mapping can be switched to left, middle and right through
support tapping up to whatever is supported by the hardware. libinput does configuration. Not all devices support three fingers, libinput will support
not support four-finger taps or any tapping with more than four fingers, tapping up to whatever is supported by the hardware. libinput does not support
even though some hardware can distinguish between that many fingers. four-finger taps or any tapping with more than four fingers, even though some
hardware can distinguish between that many fingers.
.. _tapping_default: .. _tapping_default:

View file

@ -958,6 +958,51 @@ tp_guess_clickpad(const struct tp_dispatch *tp, struct evdev_device *device)
return is_clickpad; return is_clickpad;
} }
static inline void
tp_button_update_clickfinger_map(struct tp_dispatch *tp)
{
if (tp->buttons.state != BUTTON_STATE_NONE)
return;
if (tp->buttons.map != tp->buttons.want_map)
tp->buttons.map = tp->buttons.want_map;
}
void
tp_button_post_process_state(struct tp_dispatch *tp)
{
tp_button_update_clickfinger_map(tp);
}
static enum libinput_config_status
tp_button_config_set_clickfinger_map(struct libinput_device *device,
enum libinput_config_clickfinger_button_map map)
{
struct evdev_dispatch *dispatch = evdev_device(device)->dispatch;
struct tp_dispatch *tp = tp_dispatch(dispatch);
tp->buttons.want_map = map;
tp_button_update_clickfinger_map(tp);
return LIBINPUT_CONFIG_STATUS_SUCCESS;
}
static enum libinput_config_clickfinger_button_map
tp_button_config_get_clickfinger_map(struct libinput_device *device)
{
struct evdev_dispatch *dispatch = evdev_device(device)->dispatch;
struct tp_dispatch *tp = tp_dispatch(dispatch);
return tp->buttons.want_map;
}
static enum libinput_config_clickfinger_button_map
tp_button_config_get_default_clickfinger_map(struct libinput_device *device)
{
return LIBINPUT_CONFIG_CLICKFINGER_MAP_LRM;
}
void void
tp_init_buttons(struct tp_dispatch *tp, tp_init_buttons(struct tp_dispatch *tp,
struct evdev_device *device) struct evdev_device *device)
@ -982,8 +1027,15 @@ tp_init_buttons(struct tp_dispatch *tp,
tp->buttons.config_method.set_method = tp_button_config_click_set_method; 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_method = tp_button_config_click_get_method;
tp->buttons.config_method.get_default_method = tp_button_config_click_get_default_method; tp->buttons.config_method.get_default_method = tp_button_config_click_get_default_method;
tp->buttons.config_method.set_clickfinger_map = tp_button_config_set_clickfinger_map;
tp->buttons.config_method.get_clickfinger_map = tp_button_config_get_clickfinger_map;
tp->buttons.config_method.get_default_clickfinger_map = tp_button_config_get_default_clickfinger_map;
tp->device->base.config.click_method = &tp->buttons.config_method; tp->device->base.config.click_method = &tp->buttons.config_method;
tp->buttons.map = LIBINPUT_CONFIG_CLICKFINGER_MAP_LRM;
tp->buttons.want_map = tp->buttons.map;
tp->buttons.click_method = tp_click_get_default_method(tp); tp->buttons.click_method = tp_click_get_default_method(tp);
tp_switch_click_method(tp); tp_switch_click_method(tp);
@ -1118,6 +1170,10 @@ tp_clickfinger_set_button(struct tp_dispatch *tp)
struct tp_touch *t; struct tp_touch *t;
struct tp_touch *first = NULL, struct tp_touch *first = NULL,
*second = NULL; *second = NULL;
int32_t button_map[2][3] = {
{ BTN_LEFT, BTN_RIGHT, BTN_MIDDLE },
{ BTN_LEFT, BTN_MIDDLE, BTN_RIGHT },
};
tp_for_each_touch(tp, t) { tp_for_each_touch(tp, t) {
if (t->state != TOUCH_BEGIN && t->state != TOUCH_UPDATE) if (t->state != TOUCH_BEGIN && t->state != TOUCH_UPDATE)
@ -1148,11 +1204,12 @@ tp_clickfinger_set_button(struct tp_dispatch *tp)
nfingers = 1; nfingers = 1;
out: out:
nfingers = max(1, nfingers);
switch (nfingers) { switch (nfingers) {
case 0: case 1:
case 1: button = BTN_LEFT; break; case 2:
case 2: button = BTN_RIGHT; break; case 3: button = button_map[tp->buttons.map][nfingers-1]; break;
case 3: button = BTN_MIDDLE; break;
default: default:
button = 0; button = 0;
break; break;
@ -1326,8 +1383,9 @@ int
tp_post_button_events(struct tp_dispatch *tp, uint64_t time) tp_post_button_events(struct tp_dispatch *tp, uint64_t time)
{ {
if (tp->buttons.is_clickpad || if (tp->buttons.is_clickpad ||
tp->device->model_flags & EVDEV_MODEL_APPLE_TOUCHPAD_ONEBUTTON) tp->device->model_flags & EVDEV_MODEL_APPLE_TOUCHPAD_ONEBUTTON) {
return tp_post_clickpadbutton_buttons(tp, time); return tp_post_clickpadbutton_buttons(tp, time);
}
return tp_post_physical_buttons(tp, time); return tp_post_physical_buttons(tp, time);
} }

View file

@ -1846,6 +1846,7 @@ tp_post_process_state(struct tp_dispatch *tp, uint64_t time)
tp_thumb_reset(tp); tp_thumb_reset(tp);
tp_tap_post_process_state(tp); tp_tap_post_process_state(tp);
tp_button_post_process_state(tp);
} }
static void static void

View file

@ -399,6 +399,9 @@ struct tp_dispatch {
enum libinput_config_click_method click_method; enum libinput_config_click_method click_method;
struct libinput_device_config_click_method config_method; struct libinput_device_config_click_method config_method;
enum libinput_config_clickfinger_button_map map;
enum libinput_config_clickfinger_button_map want_map;
} buttons; } buttons;
struct { struct {
@ -625,6 +628,9 @@ tp_tap_handle_state(struct tp_dispatch *tp, uint64_t time);
void void
tp_tap_post_process_state(struct tp_dispatch *tp); tp_tap_post_process_state(struct tp_dispatch *tp);
void
tp_button_post_process_state(struct tp_dispatch *tp);
void void
tp_init_tap(struct tp_dispatch *tp); tp_init_tap(struct tp_dispatch *tp);

View file

@ -333,6 +333,10 @@ struct libinput_device_config_click_method {
enum libinput_config_click_method method); enum libinput_config_click_method method);
enum libinput_config_click_method (*get_method)(struct libinput_device *device); enum libinput_config_click_method (*get_method)(struct libinput_device *device);
enum libinput_config_click_method (*get_default_method)(struct libinput_device *device); enum libinput_config_click_method (*get_default_method)(struct libinput_device *device);
enum libinput_config_status (*set_clickfinger_map)(struct libinput_device *device,
enum libinput_config_clickfinger_button_map map);
enum libinput_config_clickfinger_button_map (*get_clickfinger_map)(struct libinput_device *device);
enum libinput_config_clickfinger_button_map (*get_default_clickfinger_map)(struct libinput_device *device);
}; };
struct libinput_device_config_middle_emulation { struct libinput_device_config_middle_emulation {

View file

@ -72,6 +72,7 @@ ASSERT_INT_SIZE(enum libinput_config_drag_lock_state);
ASSERT_INT_SIZE(enum libinput_config_send_events_mode); ASSERT_INT_SIZE(enum libinput_config_send_events_mode);
ASSERT_INT_SIZE(enum libinput_config_accel_profile); ASSERT_INT_SIZE(enum libinput_config_accel_profile);
ASSERT_INT_SIZE(enum libinput_config_click_method); ASSERT_INT_SIZE(enum libinput_config_click_method);
ASSERT_INT_SIZE(enum libinput_config_clickfinger_button_map);
ASSERT_INT_SIZE(enum libinput_config_middle_emulation_state); ASSERT_INT_SIZE(enum libinput_config_middle_emulation_state);
ASSERT_INT_SIZE(enum libinput_config_scroll_method); ASSERT_INT_SIZE(enum libinput_config_scroll_method);
ASSERT_INT_SIZE(enum libinput_config_dwt_state); ASSERT_INT_SIZE(enum libinput_config_dwt_state);
@ -4509,6 +4510,45 @@ libinput_device_config_click_get_default_method(struct libinput_device *device)
return LIBINPUT_CONFIG_CLICK_METHOD_NONE; return LIBINPUT_CONFIG_CLICK_METHOD_NONE;
} }
LIBINPUT_EXPORT enum libinput_config_status
libinput_device_config_click_set_clickfinger_button_map(struct libinput_device *device,
enum libinput_config_clickfinger_button_map map)
{
switch (map) {
case LIBINPUT_CONFIG_CLICKFINGER_MAP_LRM:
case LIBINPUT_CONFIG_CLICKFINGER_MAP_LMR:
break;
default:
return LIBINPUT_CONFIG_STATUS_INVALID;
}
if ((libinput_device_config_click_get_methods(device) &
LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER) != LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER)
return LIBINPUT_CONFIG_STATUS_UNSUPPORTED;
return device->config.click_method->set_clickfinger_map(device, map);
}
LIBINPUT_EXPORT enum libinput_config_clickfinger_button_map
libinput_device_config_click_get_clickfinger_button_map(struct libinput_device *device)
{
if ((libinput_device_config_click_get_methods(device) &
LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER) != LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER)
return LIBINPUT_CONFIG_CLICKFINGER_MAP_LRM;
return device->config.click_method->get_clickfinger_map(device);
}
LIBINPUT_EXPORT enum libinput_config_clickfinger_button_map
libinput_device_config_click_get_default_clickfinger_button_map(struct libinput_device *device)
{
if ((libinput_device_config_click_get_methods(device) &
LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER) != LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER)
return LIBINPUT_CONFIG_CLICKFINGER_MAP_LRM;
return device->config.click_method->get_default_clickfinger_map(device);
}
LIBINPUT_EXPORT int LIBINPUT_EXPORT int
libinput_device_config_middle_emulation_is_available( libinput_device_config_middle_emulation_is_available(
struct libinput_device *device) struct libinput_device *device)

View file

@ -4608,6 +4608,7 @@ libinput_device_group_get_user_data(struct libinput_device_group *group);
* - libinput_device_config_tap_set_drag_enabled() * - libinput_device_config_tap_set_drag_enabled()
* - libinput_device_config_tap_set_drag_lock_enabled() * - libinput_device_config_tap_set_drag_lock_enabled()
* - libinput_device_config_click_set_method() * - libinput_device_config_click_set_method()
* - libinput_device_config_click_set_clickfinger_button_map()
* - libinput_device_config_scroll_set_method() * - libinput_device_config_scroll_set_method()
* - libinput_device_config_dwt_set_enabled() * - libinput_device_config_dwt_set_enabled()
* - Touchscreens: * - Touchscreens:
@ -4747,6 +4748,16 @@ enum libinput_config_tap_button_map {
LIBINPUT_CONFIG_TAP_MAP_LMR, LIBINPUT_CONFIG_TAP_MAP_LMR,
}; };
/**
* @ingroup config
*/
enum libinput_config_clickfinger_button_map {
/** 1/2/3 finger click maps to left/right/middle */
LIBINPUT_CONFIG_CLICKFINGER_MAP_LRM,
/** 1/2/3 finger click maps to left/middle/right*/
LIBINPUT_CONFIG_CLICKFINGER_MAP_LMR,
};
/** /**
* @ingroup config * @ingroup config
* *
@ -5816,6 +5827,68 @@ libinput_device_config_click_get_method(struct libinput_device *device);
enum libinput_config_click_method enum libinput_config_click_method
libinput_device_config_click_get_default_method(struct libinput_device *device); libinput_device_config_click_get_default_method(struct libinput_device *device);
/**
* @ingroup config
*
* Set the finger number to button number mapping for clickfinger. The
* default mapping on most devices is to have a 1, 2 and 3 finger tap to map
* to the left, right and middle button, respectively.
* A device may permit changing the button mapping but disallow specific
* maps. In this case @ref LIBINPUT_CONFIG_STATUS_UNSUPPORTED is returned,
* the caller is expected to handle this case correctly.
*
* Changing the button mapping may not take effect immediately,
* the device may wait until it is in a neutral state before applying any
* changes.
*
* @param device The device to configure
* @param map The new finger-to-button number mapping
*
* @return A config status code. Changing the order on a device that does not
* support the clickfinger method always fails with @ref
* LIBINPUT_CONFIG_STATUS_UNSUPPORTED.
*
* @see libinput_device_config_click_get_clickfinger_button_map
* @see libinput_device_config_click_get_default_clickfinger_button_map
*/
enum libinput_config_status
libinput_device_config_click_set_clickfinger_button_map(struct libinput_device *device,
enum libinput_config_clickfinger_button_map map);
/**
* @ingroup config
*
* Get the finger number to button number mapping for clickfinger.
*
* The return value for a device that does not support tapping is always
* @ref LIBINPUT_CONFIG_CLICKFINGER_MAP_LRM.
*
* @param device The device to configure
* @return The current finger-to-button number mapping
*
* @see libinput_device_config_click_set_clickfinger_button_map
* @see libinput_device_config_click_get_default_clickfinger_button_map
*/
enum libinput_config_clickfinger_button_map
libinput_device_config_click_get_clickfinger_button_map(struct libinput_device *device);
/**
* @ingroup config
*
* Get the default finger number to button number mapping for clickfinger.
*
* The return value for a device that does not support clickfinger is always
* @ref LIBINPUT_CONFIG_CLICKFINGER_MAP_LRM.
*
* @param device The device to configure
* @return The default finger-to-button number mapping
*
* @see libinput_device_config_click_set_clickfinger_button_map
* @see libinput_device_config_click_get_clickfinger_button_map
*/
enum libinput_config_clickfinger_button_map
libinput_device_config_click_get_default_clickfinger_button_map(struct libinput_device *device);
/** /**
* @ingroup config * @ingroup config
*/ */

View file

@ -335,6 +335,9 @@ LIBINPUT_1.23 {
} LIBINPUT_1.21; } LIBINPUT_1.21;
LIBINPUT_1.26 { LIBINPUT_1.26 {
libinput_device_config_click_set_clickfinger_button_map;
libinput_device_config_click_get_default_clickfinger_button_map;
libinput_device_config_click_get_clickfinger_button_map;
libinput_device_get_id_bustype; libinput_device_get_id_bustype;
libinput_device_tablet_pad_get_num_dials; libinput_device_tablet_pad_get_num_dials;
libinput_event_tablet_pad_get_dial_delta_v120; libinput_event_tablet_pad_get_dial_delta_v120;

View file

@ -1155,6 +1155,18 @@ litest_enable_clickfinger(struct litest_device *dev)
litest_assert_int_eq(status, expected); litest_assert_int_eq(status, expected);
} }
static inline void
litest_set_clickfinger_map(struct litest_device *dev,
enum libinput_config_clickfinger_button_map map)
{
enum libinput_config_status status, expected;
struct libinput_device *device = dev->libinput_device;
expected = LIBINPUT_CONFIG_STATUS_SUCCESS;
status = libinput_device_config_click_set_clickfinger_button_map(device, map);
litest_assert_int_eq(status, expected);
}
static inline void static inline void
litest_enable_buttonareas(struct litest_device *dev) litest_enable_buttonareas(struct litest_device *dev)
{ {

View file

@ -82,6 +82,48 @@ START_TEST(touchpad_click_defaults_clickfinger)
} }
END_TEST END_TEST
START_TEST(touchpad_click_default_clickfinger_map)
{
struct litest_device *dev = litest_current_device();
struct libinput_device *device = dev->libinput_device;
enum libinput_config_clickfinger_button_map map;
map = libinput_device_config_click_get_clickfinger_button_map(device);
ck_assert_int_eq(map, LIBINPUT_CONFIG_CLICKFINGER_MAP_LRM);
map = libinput_device_config_click_get_default_clickfinger_button_map(device);
ck_assert_int_eq(map, LIBINPUT_CONFIG_CLICKFINGER_MAP_LRM);
}
END_TEST
START_TEST(touchpad_click_set_clickfinger_map)
{
struct litest_device *dev = litest_current_device();
struct libinput_device *device = dev->libinput_device;
enum libinput_config_clickfinger_button_map map;
enum libinput_config_status status;
map = LIBINPUT_CONFIG_CLICKFINGER_MAP_LRM;
status = libinput_device_config_click_set_clickfinger_button_map(device, map);
ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS);
map = libinput_device_config_click_get_clickfinger_button_map(dev->libinput_device);
ck_assert_int_eq(map, LIBINPUT_CONFIG_TAP_MAP_LRM);
map = LIBINPUT_CONFIG_CLICKFINGER_MAP_LMR;
status = libinput_device_config_click_set_clickfinger_button_map(device, map);
ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS);
map = libinput_device_config_click_get_clickfinger_button_map(dev->libinput_device);
ck_assert_int_eq(map, LIBINPUT_CONFIG_TAP_MAP_LMR);
map = LIBINPUT_CONFIG_CLICKFINGER_MAP_LRM - 1;
status = libinput_device_config_click_set_clickfinger_button_map(device, map);
ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_INVALID);
map = LIBINPUT_CONFIG_CLICKFINGER_MAP_LMR + 1;
status = libinput_device_config_click_set_clickfinger_button_map(device, map);
ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_INVALID);
}
END_TEST
START_TEST(touchpad_click_defaults_btnarea) START_TEST(touchpad_click_defaults_btnarea)
{ {
struct litest_device *dev = litest_current_device(); struct litest_device *dev = litest_current_device();
@ -217,8 +259,22 @@ START_TEST(touchpad_2fg_clickfinger)
{ {
struct litest_device *dev = litest_current_device(); struct litest_device *dev = litest_current_device();
struct libinput *li = dev->libinput; struct libinput *li = dev->libinput;
enum libinput_config_clickfinger_button_map map = _i; /* ranged test */
unsigned int button = 0;
litest_enable_clickfinger(dev); litest_enable_clickfinger(dev);
litest_set_clickfinger_map(dev, map);
switch (map) {
case LIBINPUT_CONFIG_CLICKFINGER_MAP_LRM:
button = BTN_RIGHT;
break;
case LIBINPUT_CONFIG_CLICKFINGER_MAP_LMR:
button = BTN_MIDDLE;
break;
default:
litest_abort_msg("Invalid map range %d", map);
}
litest_drain_events(li); litest_drain_events(li);
@ -233,9 +289,9 @@ START_TEST(touchpad_2fg_clickfinger)
libinput_dispatch(li); libinput_dispatch(li);
litest_assert_button_event(li, BTN_RIGHT, litest_assert_button_event(li, button,
LIBINPUT_BUTTON_STATE_PRESSED); LIBINPUT_BUTTON_STATE_PRESSED);
litest_assert_button_event(li, BTN_RIGHT, litest_assert_button_event(li, button,
LIBINPUT_BUTTON_STATE_RELEASED); LIBINPUT_BUTTON_STATE_RELEASED);
} }
END_TEST END_TEST
@ -244,11 +300,25 @@ START_TEST(touchpad_3fg_clickfinger)
{ {
struct litest_device *dev = litest_current_device(); struct litest_device *dev = litest_current_device();
struct libinput *li = dev->libinput; struct libinput *li = dev->libinput;
enum libinput_config_clickfinger_button_map map = _i; /* ranged test */
unsigned int button = 0;
if (litest_slot_count(dev) < 3) if (litest_slot_count(dev) < 3)
return; return;
litest_enable_clickfinger(dev); litest_enable_clickfinger(dev);
litest_set_clickfinger_map(dev, map);
switch (map) {
case LIBINPUT_CONFIG_CLICKFINGER_MAP_LRM:
button = BTN_MIDDLE;
break;
case LIBINPUT_CONFIG_CLICKFINGER_MAP_LMR:
button = BTN_RIGHT;
break;
default:
litest_abort_msg("Invalid map range %d", map);
}
litest_drain_events(li); litest_drain_events(li);
@ -266,10 +336,10 @@ START_TEST(touchpad_3fg_clickfinger)
libinput_dispatch(li); libinput_dispatch(li);
litest_assert_button_event(li, litest_assert_button_event(li,
BTN_MIDDLE, button,
LIBINPUT_BUTTON_STATE_PRESSED); LIBINPUT_BUTTON_STATE_PRESSED);
litest_assert_button_event(li, litest_assert_button_event(li,
BTN_MIDDLE, button,
LIBINPUT_BUTTON_STATE_RELEASED); LIBINPUT_BUTTON_STATE_RELEASED);
} }
END_TEST END_TEST
@ -278,12 +348,26 @@ START_TEST(touchpad_3fg_clickfinger_btntool)
{ {
struct litest_device *dev = litest_current_device(); struct litest_device *dev = litest_current_device();
struct libinput *li = dev->libinput; struct libinput *li = dev->libinput;
enum libinput_config_clickfinger_button_map map = _i; /* ranged test */
unsigned int button = 0;
if (litest_slot_count(dev) >= 3 || if (litest_slot_count(dev) >= 3 ||
!libevdev_has_event_code(dev->evdev, EV_KEY, BTN_TOOL_TRIPLETAP)) !libevdev_has_event_code(dev->evdev, EV_KEY, BTN_TOOL_TRIPLETAP))
return; return;
litest_enable_clickfinger(dev); litest_enable_clickfinger(dev);
litest_set_clickfinger_map(dev, map);
switch (map) {
case LIBINPUT_CONFIG_CLICKFINGER_MAP_LRM:
button = BTN_MIDDLE;
break;
case LIBINPUT_CONFIG_CLICKFINGER_MAP_LMR:
button = BTN_RIGHT;
break;
default:
litest_abort_msg("Invalid map range %d", map);
}
litest_drain_events(li); litest_drain_events(li);
@ -305,10 +389,10 @@ START_TEST(touchpad_3fg_clickfinger_btntool)
libinput_dispatch(li); libinput_dispatch(li);
litest_assert_button_event(li, litest_assert_button_event(li,
BTN_MIDDLE, button,
LIBINPUT_BUTTON_STATE_PRESSED); LIBINPUT_BUTTON_STATE_PRESSED);
litest_assert_button_event(li, litest_assert_button_event(li,
BTN_MIDDLE, button,
LIBINPUT_BUTTON_STATE_RELEASED); LIBINPUT_BUTTON_STATE_RELEASED);
} }
END_TEST END_TEST
@ -418,13 +502,15 @@ START_TEST(touchpad_2fg_clickfinger_distance)
struct libinput *li = dev->libinput; struct libinput *li = dev->libinput;
double w, h; double w, h;
bool small_touchpad = false; bool small_touchpad = false;
unsigned int expected_button; unsigned int expected_button = 0;
enum libinput_config_clickfinger_button_map map = _i; /* ranged test */
if (libinput_device_get_size(dev->libinput_device, &w, &h) == 0 && if (libinput_device_get_size(dev->libinput_device, &w, &h) == 0 &&
h < 50.0) h < 50.0)
small_touchpad = true; small_touchpad = true;
litest_enable_clickfinger(dev); litest_enable_clickfinger(dev);
litest_set_clickfinger_map(dev, map);
litest_drain_events(li); litest_drain_events(li);
@ -458,7 +544,14 @@ START_TEST(touchpad_2fg_clickfinger_distance)
/* if the touchpad is small enough, we expect all fingers to count /* if the touchpad is small enough, we expect all fingers to count
* for clickfinger */ * for clickfinger */
if (small_touchpad) if (small_touchpad)
switch (map) {
case LIBINPUT_CONFIG_CLICKFINGER_MAP_LRM:
expected_button = BTN_RIGHT; expected_button = BTN_RIGHT;
break;
case LIBINPUT_CONFIG_CLICKFINGER_MAP_LMR:
expected_button = BTN_MIDDLE;
break;
}
else else
expected_button = BTN_LEFT; expected_button = BTN_LEFT;
@ -475,11 +568,25 @@ START_TEST(touchpad_3fg_clickfinger_distance)
{ {
struct litest_device *dev = litest_current_device(); struct litest_device *dev = litest_current_device();
struct libinput *li = dev->libinput; struct libinput *li = dev->libinput;
enum libinput_config_clickfinger_button_map map = _i; /* ranged test */
unsigned int button = 0;
if (litest_slot_count(dev) < 3) if (litest_slot_count(dev) < 3)
return; return;
litest_enable_clickfinger(dev); litest_enable_clickfinger(dev);
litest_set_clickfinger_map(dev, map);
switch (map) {
case LIBINPUT_CONFIG_CLICKFINGER_MAP_LRM:
button = BTN_MIDDLE;
break;
case LIBINPUT_CONFIG_CLICKFINGER_MAP_LMR:
button = BTN_RIGHT;
break;
default:
litest_abort_msg("Invalid map range %d", map);
}
litest_drain_events(li); litest_drain_events(li);
@ -496,10 +603,10 @@ START_TEST(touchpad_3fg_clickfinger_distance)
litest_touch_up(dev, 2); litest_touch_up(dev, 2);
litest_assert_button_event(li, litest_assert_button_event(li,
BTN_MIDDLE, button,
LIBINPUT_BUTTON_STATE_PRESSED); LIBINPUT_BUTTON_STATE_PRESSED);
litest_assert_button_event(li, litest_assert_button_event(li,
BTN_MIDDLE, button,
LIBINPUT_BUTTON_STATE_RELEASED); LIBINPUT_BUTTON_STATE_RELEASED);
} }
END_TEST END_TEST
@ -508,11 +615,25 @@ START_TEST(touchpad_3fg_clickfinger_distance_btntool)
{ {
struct litest_device *dev = litest_current_device(); struct litest_device *dev = litest_current_device();
struct libinput *li = dev->libinput; struct libinput *li = dev->libinput;
enum libinput_config_clickfinger_button_map map = _i; /* ranged test */
unsigned int button = 0;
if (litest_slot_count(dev) > 2) if (litest_slot_count(dev) > 2)
return; return;
litest_enable_clickfinger(dev); litest_enable_clickfinger(dev);
litest_set_clickfinger_map(dev, map);
switch (map) {
case LIBINPUT_CONFIG_CLICKFINGER_MAP_LRM:
button = BTN_MIDDLE;
break;
case LIBINPUT_CONFIG_CLICKFINGER_MAP_LMR:
button = BTN_RIGHT;
break;
default:
litest_abort_msg("Invalid map range %d", map);
}
litest_drain_events(li); litest_drain_events(li);
@ -534,10 +655,10 @@ START_TEST(touchpad_3fg_clickfinger_distance_btntool)
litest_touch_up(dev, 1); litest_touch_up(dev, 1);
litest_assert_button_event(li, litest_assert_button_event(li,
BTN_MIDDLE, button,
LIBINPUT_BUTTON_STATE_PRESSED); LIBINPUT_BUTTON_STATE_PRESSED);
litest_assert_button_event(li, litest_assert_button_event(li,
BTN_MIDDLE, button,
LIBINPUT_BUTTON_STATE_RELEASED); LIBINPUT_BUTTON_STATE_RELEASED);
} }
END_TEST END_TEST
@ -2127,20 +2248,22 @@ END_TEST
TEST_COLLECTION(touchpad_buttons) TEST_COLLECTION(touchpad_buttons)
{ {
struct range finger_count = {1, 4}; struct range finger_count = {1, 4};
struct range clickfinger_map_range = { LIBINPUT_CONFIG_CLICKFINGER_MAP_LRM,
LIBINPUT_CONFIG_CLICKFINGER_MAP_LMR + 1 };
litest_add(touchpad_button, LITEST_TOUCHPAD, LITEST_CLICKPAD); litest_add(touchpad_button, LITEST_TOUCHPAD, LITEST_CLICKPAD);
litest_add(touchpad_1fg_clickfinger, LITEST_CLICKPAD, LITEST_ANY); litest_add(touchpad_1fg_clickfinger, LITEST_CLICKPAD, LITEST_ANY);
litest_add(touchpad_1fg_clickfinger_no_touch, LITEST_CLICKPAD, LITEST_ANY); litest_add(touchpad_1fg_clickfinger_no_touch, LITEST_CLICKPAD, LITEST_ANY);
litest_add(touchpad_2fg_clickfinger, LITEST_CLICKPAD, LITEST_ANY); litest_add_ranged(touchpad_2fg_clickfinger, LITEST_CLICKPAD, LITEST_ANY, &clickfinger_map_range);
litest_add(touchpad_3fg_clickfinger, LITEST_CLICKPAD, LITEST_ANY); litest_add_ranged(touchpad_3fg_clickfinger, LITEST_CLICKPAD, LITEST_ANY, &clickfinger_map_range);
litest_add(touchpad_3fg_clickfinger_btntool, LITEST_CLICKPAD, LITEST_ANY); litest_add_ranged(touchpad_3fg_clickfinger_btntool, LITEST_CLICKPAD, LITEST_ANY, &clickfinger_map_range);
litest_add(touchpad_4fg_clickfinger, LITEST_CLICKPAD, LITEST_ANY); litest_add(touchpad_4fg_clickfinger, LITEST_CLICKPAD, LITEST_ANY);
litest_add(touchpad_4fg_clickfinger_btntool_2slots, LITEST_CLICKPAD, LITEST_ANY); litest_add(touchpad_4fg_clickfinger_btntool_2slots, LITEST_CLICKPAD, LITEST_ANY);
litest_add(touchpad_4fg_clickfinger_btntool_3slots, LITEST_CLICKPAD, LITEST_ANY); litest_add(touchpad_4fg_clickfinger_btntool_3slots, LITEST_CLICKPAD, LITEST_ANY);
litest_add(touchpad_2fg_clickfinger_distance, LITEST_CLICKPAD, LITEST_ANY); litest_add_ranged(touchpad_2fg_clickfinger_distance, LITEST_CLICKPAD, LITEST_ANY, &clickfinger_map_range);
litest_add(touchpad_3fg_clickfinger_distance, LITEST_CLICKPAD, LITEST_ANY); litest_add_ranged(touchpad_3fg_clickfinger_distance, LITEST_CLICKPAD, LITEST_ANY, &clickfinger_map_range);
litest_add(touchpad_3fg_clickfinger_distance_btntool, LITEST_CLICKPAD, LITEST_ANY); litest_add_ranged(touchpad_3fg_clickfinger_distance_btntool, LITEST_CLICKPAD, LITEST_ANY, &clickfinger_map_range);
litest_add_for_device(touchpad_2fg_clickfinger_bottom, LITEST_SYNAPTICS_TOPBUTTONPAD); litest_add_for_device(touchpad_2fg_clickfinger_bottom, LITEST_SYNAPTICS_TOPBUTTONPAD);
litest_add(touchpad_clickfinger_to_area_method, LITEST_CLICKPAD, LITEST_ANY); litest_add(touchpad_clickfinger_to_area_method, LITEST_CLICKPAD, LITEST_ANY);
litest_add(touchpad_clickfinger_to_area_method_while_down, LITEST_CLICKPAD, LITEST_ANY); litest_add(touchpad_clickfinger_to_area_method_while_down, LITEST_CLICKPAD, LITEST_ANY);
@ -2161,6 +2284,8 @@ TEST_COLLECTION(touchpad_buttons)
litest_add_ranged(touchpad_clickfinger_click_drag, LITEST_CLICKPAD, LITEST_ANY, &finger_count); litest_add_ranged(touchpad_clickfinger_click_drag, LITEST_CLICKPAD, LITEST_ANY, &finger_count);
litest_add(touchpad_click_defaults_clickfinger, LITEST_APPLE_CLICKPAD, LITEST_ANY); litest_add(touchpad_click_defaults_clickfinger, LITEST_APPLE_CLICKPAD, LITEST_ANY);
litest_add(touchpad_click_default_clickfinger_map, LITEST_APPLE_CLICKPAD, LITEST_ANY);
litest_add(touchpad_click_set_clickfinger_map, LITEST_APPLE_CLICKPAD, LITEST_ANY);
litest_add(touchpad_click_defaults_btnarea, LITEST_CLICKPAD, LITEST_APPLE_CLICKPAD); litest_add(touchpad_click_defaults_btnarea, LITEST_CLICKPAD, LITEST_APPLE_CLICKPAD);
litest_add(touchpad_click_defaults_none, LITEST_TOUCHPAD, LITEST_CLICKPAD); litest_add(touchpad_click_defaults_none, LITEST_TOUCHPAD, LITEST_CLICKPAD);
litest_add(touchpad_click_defaults_none, LITEST_ANY, LITEST_TOUCHPAD); litest_add(touchpad_click_defaults_none, LITEST_ANY, LITEST_TOUCHPAD);

View file

@ -88,6 +88,9 @@ Enable or disable the scroll button lock
.B \-\-set\-click\-method=[none|clickfinger|buttonareas] .B \-\-set\-click\-method=[none|clickfinger|buttonareas]
Set the desired click method Set the desired click method
.TP 8 .TP 8
.B \-\-set\-clickfinger\-map=[lrm|lmr]
Set button mapping for clickfinger
.TP 8
.B \-\-set\-scroll\-method=[none|twofinger|edge|button] .B \-\-set\-scroll\-method=[none|twofinger|edge|button]
Set the desired scroll method Set the desired scroll method
.TP 8 .TP 8

View file

@ -205,6 +205,18 @@ tools_parse_option(int option,
return 1; return 1;
} }
break; break;
case OPT_CLICKFINGER_MAP:
if (!optarg)
return 1;
if (streq(optarg, "lrm")) {
options->clickfinger_map = LIBINPUT_CONFIG_CLICKFINGER_MAP_LRM;
} else if (streq(optarg, "lmr")) {
options->clickfinger_map = LIBINPUT_CONFIG_CLICKFINGER_MAP_LMR;
} else {
return 1;
}
break;
case OPT_SCROLL_METHOD: case OPT_SCROLL_METHOD:
if (!optarg) if (!optarg)
return 1; return 1;
@ -499,6 +511,10 @@ tools_device_apply_config(struct libinput_device *device,
if (options->click_method != (enum libinput_config_click_method)-1) if (options->click_method != (enum libinput_config_click_method)-1)
libinput_device_config_click_set_method(device, options->click_method); libinput_device_config_click_set_method(device, options->click_method);
if (options->clickfinger_map != (enum libinput_config_clickfinger_button_map)-1)
libinput_device_config_click_set_clickfinger_button_map(device,
options->clickfinger_map);
if (options->scroll_method != (enum libinput_config_scroll_method)-1) if (options->scroll_method != (enum libinput_config_scroll_method)-1)
libinput_device_config_scroll_set_method(device, libinput_device_config_scroll_set_method(device,
options->scroll_method); options->scroll_method);

View file

@ -51,6 +51,7 @@ enum configuration_options {
OPT_DWTP_ENABLE, OPT_DWTP_ENABLE,
OPT_DWTP_DISABLE, OPT_DWTP_DISABLE,
OPT_CLICK_METHOD, OPT_CLICK_METHOD,
OPT_CLICKFINGER_MAP,
OPT_SCROLL_METHOD, OPT_SCROLL_METHOD,
OPT_SCROLL_BUTTON, OPT_SCROLL_BUTTON,
OPT_SCROLL_BUTTON_LOCK_ENABLE, OPT_SCROLL_BUTTON_LOCK_ENABLE,
@ -86,6 +87,7 @@ enum configuration_options {
{ "enable-scroll-button-lock", no_argument, 0, OPT_SCROLL_BUTTON_LOCK_ENABLE }, \ { "enable-scroll-button-lock", no_argument, 0, OPT_SCROLL_BUTTON_LOCK_ENABLE }, \
{ "disable-scroll-button-lock",no_argument, 0, OPT_SCROLL_BUTTON_LOCK_DISABLE }, \ { "disable-scroll-button-lock",no_argument, 0, OPT_SCROLL_BUTTON_LOCK_DISABLE }, \
{ "set-click-method", required_argument, 0, OPT_CLICK_METHOD }, \ { "set-click-method", required_argument, 0, OPT_CLICK_METHOD }, \
{ "set-clickfinger-map", required_argument, 0, OPT_CLICKFINGER_MAP }, \
{ "set-scroll-method", required_argument, 0, OPT_SCROLL_METHOD }, \ { "set-scroll-method", required_argument, 0, OPT_SCROLL_METHOD }, \
{ "set-scroll-button", required_argument, 0, OPT_SCROLL_BUTTON }, \ { "set-scroll-button", required_argument, 0, OPT_SCROLL_BUTTON }, \
{ "set-profile", required_argument, 0, OPT_PROFILE }, \ { "set-profile", required_argument, 0, OPT_PROFILE }, \
@ -113,6 +115,7 @@ struct tools_options {
int left_handed; int left_handed;
int middlebutton; int middlebutton;
enum libinput_config_click_method click_method; enum libinput_config_click_method click_method;
enum libinput_config_clickfinger_button_map clickfinger_map;
enum libinput_config_scroll_method scroll_method; enum libinput_config_scroll_method scroll_method;
enum libinput_config_tap_button_map tap_map; enum libinput_config_tap_button_map tap_map;
int scroll_button; int scroll_button;

View file

@ -218,6 +218,7 @@ options = {
"set-scroll-method": ["none", "twofinger", "edge", "button"], "set-scroll-method": ["none", "twofinger", "edge", "button"],
"set-profile": ["adaptive", "flat"], "set-profile": ["adaptive", "flat"],
"set-tap-map": ["lrm", "lmr"], "set-tap-map": ["lrm", "lmr"],
"set-clickfinger-map": ["lrm", "lmr"],
}, },
# options with a range (and increment) # options with a range (and increment)
"ranges": { "ranges": {