mirror of
https://gitlab.freedesktop.org/libinput/libinput.git
synced 2026-05-07 10:48:07 +02:00
touchpad: add touch-size-based palm detection
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
This commit is contained in:
parent
432fbc33cd
commit
ca4285de66
9 changed files with 152 additions and 20 deletions
|
|
@ -745,6 +745,30 @@ tp_palm_detect_multifinger(struct tp_dispatch *tp, struct tp_touch *t, uint64_t
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline bool
|
||||||
|
tp_palm_detect_touch_size_triggered(struct tp_dispatch *tp,
|
||||||
|
struct tp_touch *t,
|
||||||
|
uint64_t time)
|
||||||
|
{
|
||||||
|
if (!tp->palm.use_size)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* If a finger size is large enough for palm, we stick with that and
|
||||||
|
* force the user to release and reset the finger */
|
||||||
|
if (t->palm.state != PALM_NONE && t->palm.state != PALM_TOUCH_SIZE)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (t->major > tp->palm.size_threshold ||
|
||||||
|
t->minor > tp->palm.size_threshold) {
|
||||||
|
evdev_log_debug(tp->device,
|
||||||
|
"palm: touch size exceeded\n");
|
||||||
|
t->palm.state = PALM_TOUCH_SIZE;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
static inline bool
|
static inline bool
|
||||||
tp_palm_detect_edge(struct tp_dispatch *tp,
|
tp_palm_detect_edge(struct tp_dispatch *tp,
|
||||||
struct tp_touch *t,
|
struct tp_touch *t,
|
||||||
|
|
@ -828,6 +852,9 @@ tp_palm_detect(struct tp_dispatch *tp, struct tp_touch *t, uint64_t time)
|
||||||
if (tp_palm_detect_tool_triggered(tp, t, time))
|
if (tp_palm_detect_tool_triggered(tp, t, time))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
if (tp_palm_detect_touch_size_triggered(tp, t, time))
|
||||||
|
goto out;
|
||||||
|
|
||||||
if (tp_palm_detect_edge(tp, t, time))
|
if (tp_palm_detect_edge(tp, t, time))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
|
@ -862,6 +889,9 @@ out:
|
||||||
case PALM_PRESSURE:
|
case PALM_PRESSURE:
|
||||||
palm_state = "pressure";
|
palm_state = "pressure";
|
||||||
break;
|
break;
|
||||||
|
case PALM_TOUCH_SIZE:
|
||||||
|
palm_state = "touch size";
|
||||||
|
break;
|
||||||
case PALM_NONE:
|
case PALM_NONE:
|
||||||
default:
|
default:
|
||||||
abort();
|
abort();
|
||||||
|
|
@ -2415,10 +2445,14 @@ tp_init_palmdetect_edge(struct tp_dispatch *tp,
|
||||||
struct phys_coords mm = { 0.0, 0.0 };
|
struct phys_coords mm = { 0.0, 0.0 };
|
||||||
struct device_coords edges;
|
struct device_coords edges;
|
||||||
|
|
||||||
|
if (device->tags & EVDEV_TAG_EXTERNAL_TOUCHPAD &&
|
||||||
|
!tp_is_tpkb_combo_below(device))
|
||||||
|
return;
|
||||||
|
|
||||||
evdev_device_get_size(device, &width, &height);
|
evdev_device_get_size(device, &width, &height);
|
||||||
|
|
||||||
/* Enable palm detection on touchpads >= 70 mm. Anything smaller
|
/* Enable edge palm detection on touchpads >= 70 mm. Anything
|
||||||
probably won't need it, until we find out it does */
|
smaller probably won't need it, until we find out it does */
|
||||||
if (width < 70.0)
|
if (width < 70.0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
@ -2475,6 +2509,33 @@ tp_init_palmdetect_pressure(struct tp_dispatch *tp,
|
||||||
tp->palm.pressure_threshold);
|
tp->palm.pressure_threshold);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
tp_init_palmdetect_size(struct tp_dispatch *tp,
|
||||||
|
struct evdev_device *device)
|
||||||
|
{
|
||||||
|
const char *prop;
|
||||||
|
int threshold;
|
||||||
|
|
||||||
|
if (!tp->touch_size.use_touch_size)
|
||||||
|
return;
|
||||||
|
|
||||||
|
prop = udev_device_get_property_value(device->udev_device,
|
||||||
|
"LIBINPUT_ATTR_PALM_SIZE_THRESHOLD");
|
||||||
|
if (!prop)
|
||||||
|
return;
|
||||||
|
|
||||||
|
threshold = parse_palm_size_property(prop);
|
||||||
|
if (threshold == 0) {
|
||||||
|
evdev_log_bug_client(device,
|
||||||
|
"palm: ignoring invalid threshold %s\n",
|
||||||
|
prop);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
tp->palm.use_size = true;
|
||||||
|
tp->palm.size_threshold = threshold;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
tp_init_palmdetect(struct tp_dispatch *tp,
|
tp_init_palmdetect(struct tp_dispatch *tp,
|
||||||
struct evdev_device *device)
|
struct evdev_device *device)
|
||||||
|
|
@ -2497,6 +2558,7 @@ tp_init_palmdetect(struct tp_dispatch *tp,
|
||||||
|
|
||||||
tp_init_palmdetect_edge(tp, device);
|
tp_init_palmdetect_edge(tp, device);
|
||||||
tp_init_palmdetect_pressure(tp, device);
|
tp_init_palmdetect_pressure(tp, device);
|
||||||
|
tp_init_palmdetect_size(tp, device);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
|
||||||
|
|
@ -59,6 +59,7 @@ enum touch_palm_state {
|
||||||
PALM_TRACKPOINT,
|
PALM_TRACKPOINT,
|
||||||
PALM_TOOL_PALM,
|
PALM_TOOL_PALM,
|
||||||
PALM_PRESSURE,
|
PALM_PRESSURE,
|
||||||
|
PALM_TOUCH_SIZE,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum button_event {
|
enum button_event {
|
||||||
|
|
@ -360,6 +361,9 @@ struct tp_dispatch {
|
||||||
|
|
||||||
bool use_pressure;
|
bool use_pressure;
|
||||||
int pressure_threshold;
|
int pressure_threshold;
|
||||||
|
|
||||||
|
bool use_size;
|
||||||
|
int size_threshold;
|
||||||
} palm;
|
} palm;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
|
|
|
||||||
|
|
@ -431,6 +431,31 @@ parse_palm_pressure_property(const char *prop)
|
||||||
return threshold;
|
return threshold;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper function to parse the LIBINPUT_ATTR_PALM_SIZE_THRESHOLD property
|
||||||
|
* from udev. Property is of the form:
|
||||||
|
* LIBINPUT_ATTR_PALM_SIZE_THRESHOLD=<integer>
|
||||||
|
* Where the number indicates the minimum threshold to consider a touch to
|
||||||
|
* be a palm.
|
||||||
|
*
|
||||||
|
* @param prop The value of the udev property (without the
|
||||||
|
* LIBINPUT_ATTR_PALM_SIZE_THRESHOLD=)
|
||||||
|
* @return The pressure threshold or 0 on error
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
parse_palm_size_property(const char *prop)
|
||||||
|
{
|
||||||
|
int thr = 0;
|
||||||
|
|
||||||
|
if (!prop)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (!safe_atoi(prop, &thr) || thr < 0 || thr > 1024)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return thr;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the next word in a string pointed to by state before the first
|
* Return the next word in a string pointed to by state before the first
|
||||||
* separator character. Call repeatedly to tokenize a whole string.
|
* separator character. Call repeatedly to tokenize a whole string.
|
||||||
|
|
|
||||||
|
|
@ -390,6 +390,7 @@ bool parse_dimension_property(const char *prop, size_t *width, size_t *height);
|
||||||
bool parse_calibration_property(const char *prop, float calibration[6]);
|
bool parse_calibration_property(const char *prop, float calibration[6]);
|
||||||
bool parse_range_property(const char *prop, int *hi, int *lo);
|
bool parse_range_property(const char *prop, int *hi, int *lo);
|
||||||
int parse_palm_pressure_property(const char *prop);
|
int parse_palm_pressure_property(const char *prop);
|
||||||
|
int parse_palm_size_property(const char *prop);
|
||||||
|
|
||||||
enum tpkbcombo_layout {
|
enum tpkbcombo_layout {
|
||||||
TPKBCOMBO_LAYOUT_UNKNOWN,
|
TPKBCOMBO_LAYOUT_UNKNOWN,
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,8 @@
|
||||||
#include <libinput.h>
|
#include <libinput.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
|
||||||
|
#include "libinput-util.h"
|
||||||
|
|
||||||
extern void litest_setup_tests_udev(void);
|
extern void litest_setup_tests_udev(void);
|
||||||
extern void litest_setup_tests_path(void);
|
extern void litest_setup_tests_path(void);
|
||||||
extern void litest_setup_tests_pointer(void);
|
extern void litest_setup_tests_pointer(void);
|
||||||
|
|
@ -915,6 +917,22 @@ litest_disable_middleemu(struct litest_device *dev)
|
||||||
litest_assert_int_eq(status, expected);
|
litest_assert_int_eq(status, expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline bool
|
||||||
|
litest_touchpad_is_external(struct litest_device *dev)
|
||||||
|
{
|
||||||
|
struct udev_device *udev_device;
|
||||||
|
const char *prop;
|
||||||
|
bool is_external;
|
||||||
|
|
||||||
|
udev_device = libinput_device_get_udev_device(dev->libinput_device);
|
||||||
|
prop = udev_device_get_property_value(udev_device,
|
||||||
|
"ID_INPUT_TOUCHPAD_INTEGRATION");
|
||||||
|
is_external = prop && streq(prop, "external");
|
||||||
|
udev_device_unref(udev_device);
|
||||||
|
|
||||||
|
return is_external;
|
||||||
|
}
|
||||||
|
|
||||||
#undef ck_assert_double_eq
|
#undef ck_assert_double_eq
|
||||||
#undef ck_assert_double_ne
|
#undef ck_assert_double_ne
|
||||||
#undef ck_assert_double_lt
|
#undef ck_assert_double_lt
|
||||||
|
|
|
||||||
|
|
@ -61,22 +61,6 @@ START_TEST(device_sendevents_config_invalid)
|
||||||
}
|
}
|
||||||
END_TEST
|
END_TEST
|
||||||
|
|
||||||
static inline bool
|
|
||||||
touchpad_is_external(struct litest_device *dev)
|
|
||||||
{
|
|
||||||
struct udev_device *udev_device;
|
|
||||||
const char *prop;
|
|
||||||
bool is_external;
|
|
||||||
|
|
||||||
udev_device = libinput_device_get_udev_device(dev->libinput_device);
|
|
||||||
prop = udev_device_get_property_value(udev_device,
|
|
||||||
"ID_INPUT_TOUCHPAD_INTEGRATION");
|
|
||||||
is_external = prop && streq(prop, "external");
|
|
||||||
udev_device_unref(udev_device);
|
|
||||||
|
|
||||||
return is_external;
|
|
||||||
}
|
|
||||||
|
|
||||||
START_TEST(device_sendevents_config_touchpad)
|
START_TEST(device_sendevents_config_touchpad)
|
||||||
{
|
{
|
||||||
struct litest_device *dev = litest_current_device();
|
struct litest_device *dev = litest_current_device();
|
||||||
|
|
@ -87,7 +71,7 @@ START_TEST(device_sendevents_config_touchpad)
|
||||||
|
|
||||||
/* The wacom devices in the test suite are external */
|
/* The wacom devices in the test suite are external */
|
||||||
if (libevdev_get_id_vendor(dev->evdev) != VENDOR_ID_WACOM &&
|
if (libevdev_get_id_vendor(dev->evdev) != VENDOR_ID_WACOM &&
|
||||||
!touchpad_is_external(dev))
|
!litest_touchpad_is_external(dev))
|
||||||
expected |=
|
expected |=
|
||||||
LIBINPUT_CONFIG_SEND_EVENTS_DISABLED_ON_EXTERNAL_MOUSE;
|
LIBINPUT_CONFIG_SEND_EVENTS_DISABLED_ON_EXTERNAL_MOUSE;
|
||||||
|
|
||||||
|
|
@ -107,7 +91,7 @@ START_TEST(device_sendevents_config_touchpad_superset)
|
||||||
|
|
||||||
/* The wacom devices in the test suite are external */
|
/* The wacom devices in the test suite are external */
|
||||||
if (libevdev_get_id_vendor(dev->evdev) == VENDOR_ID_WACOM ||
|
if (libevdev_get_id_vendor(dev->evdev) == VENDOR_ID_WACOM ||
|
||||||
touchpad_is_external(dev))
|
litest_touchpad_is_external(dev))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
device = dev->libinput_device;
|
device = dev->libinput_device;
|
||||||
|
|
|
||||||
|
|
@ -5376,6 +5376,41 @@ START_TEST(touchpad_touch_size_2fg)
|
||||||
}
|
}
|
||||||
END_TEST
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST(touchpad_palm_detect_touch_size)
|
||||||
|
{
|
||||||
|
struct litest_device *dev = litest_current_device();
|
||||||
|
struct libinput *li = dev->libinput;
|
||||||
|
struct axis_replacement axes[] = {
|
||||||
|
{ ABS_MT_TOUCH_MAJOR, 0 },
|
||||||
|
{ ABS_MT_TOUCH_MINOR, 0 },
|
||||||
|
{ -1, 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!touchpad_has_touch_size(dev) ||
|
||||||
|
litest_touchpad_is_external(dev))
|
||||||
|
return;
|
||||||
|
|
||||||
|
litest_drain_events(li);
|
||||||
|
litest_axis_set_value(axes, ABS_MT_TOUCH_MAJOR, 30);
|
||||||
|
litest_axis_set_value(axes, ABS_MT_TOUCH_MINOR, 30);
|
||||||
|
litest_touch_down_extended(dev, 0, 50, 50, axes);
|
||||||
|
litest_touch_move_to_extended(dev, 0,
|
||||||
|
50, 50,
|
||||||
|
80, 80,
|
||||||
|
axes, 10, 1);
|
||||||
|
litest_assert_only_typed_events(li,
|
||||||
|
LIBINPUT_EVENT_POINTER_MOTION);
|
||||||
|
|
||||||
|
litest_axis_set_value_unchecked(axes, ABS_MT_TOUCH_MAJOR, 90);
|
||||||
|
litest_axis_set_value(axes, ABS_MT_TOUCH_MINOR, 90);
|
||||||
|
litest_touch_move_to_extended(dev, 0,
|
||||||
|
80, 80,
|
||||||
|
50, 50,
|
||||||
|
axes, 10, 1);
|
||||||
|
litest_assert_empty_queue(li);
|
||||||
|
}
|
||||||
|
END_TEST
|
||||||
|
|
||||||
void
|
void
|
||||||
litest_setup_tests_touchpad(void)
|
litest_setup_tests_touchpad(void)
|
||||||
{
|
{
|
||||||
|
|
@ -5430,6 +5465,7 @@ litest_setup_tests_touchpad(void)
|
||||||
litest_add("touchpad:palm", touchpad_palm_detect_tool_palm, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH);
|
litest_add("touchpad:palm", touchpad_palm_detect_tool_palm, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH);
|
||||||
litest_add("touchpad:palm", touchpad_palm_detect_tool_palm_on_off, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH);
|
litest_add("touchpad:palm", touchpad_palm_detect_tool_palm_on_off, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH);
|
||||||
litest_add("touchpad:palm", touchpad_palm_detect_tool_palm_tap, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH);
|
litest_add("touchpad:palm", touchpad_palm_detect_tool_palm_tap, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH);
|
||||||
|
litest_add("touchpad:palm", touchpad_palm_detect_touch_size, LITEST_APPLE_CLICKPAD, LITEST_ANY);
|
||||||
|
|
||||||
litest_add("touchpad:palm", touchpad_palm_detect_pressure, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH);
|
litest_add("touchpad:palm", touchpad_palm_detect_pressure, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH);
|
||||||
litest_add("touchpad:palm", touchpad_palm_detect_pressure_late, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH);
|
litest_add("touchpad:palm", touchpad_palm_detect_pressure_late, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH);
|
||||||
|
|
|
||||||
|
|
@ -51,6 +51,7 @@ libinput:touchpad:input:b0005v05ACp*
|
||||||
LIBINPUT_MODEL_APPLE_TOUCHPAD=1
|
LIBINPUT_MODEL_APPLE_TOUCHPAD=1
|
||||||
LIBINPUT_ATTR_SIZE_HINT=104x75
|
LIBINPUT_ATTR_SIZE_HINT=104x75
|
||||||
LIBINPUT_ATTR_TOUCH_SIZE_RANGE=150:130
|
LIBINPUT_ATTR_TOUCH_SIZE_RANGE=150:130
|
||||||
|
LIBINPUT_ATTR_PALM_SIZE_THRESHOLD=800
|
||||||
|
|
||||||
libinput:name:*Apple Inc. Apple Internal Keyboard*:dmi:*
|
libinput:name:*Apple Inc. Apple Internal Keyboard*:dmi:*
|
||||||
LIBINPUT_ATTR_KEYBOARD_INTEGRATION=internal
|
LIBINPUT_ATTR_KEYBOARD_INTEGRATION=internal
|
||||||
|
|
|
||||||
|
|
@ -119,6 +119,7 @@ def property_grammar():
|
||||||
|
|
||||||
tprops = (
|
tprops = (
|
||||||
('LIBINPUT_ATTR_PALM_PRESSURE_THRESHOLD', INTEGER('X')),
|
('LIBINPUT_ATTR_PALM_PRESSURE_THRESHOLD', INTEGER('X')),
|
||||||
|
('LIBINPUT_ATTR_PALM_SIZE_THRESHOLD', INTEGER('X')),
|
||||||
)
|
)
|
||||||
typed_props = [Literal(name)('NAME') - Suppress('=') - val
|
typed_props = [Literal(name)('NAME') - Suppress('=') - val
|
||||||
for name, val in tprops]
|
for name, val in tprops]
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue