return true;
}
+static bool
+tp_palm_detect_pressure_triggered(struct tp_dispatch *tp,
+ struct tp_touch *t,
+ uint64_t time)
+{
+ if (!tp->palm.use_pressure)
+ return false;
+
+ if (t->palm.state != PALM_NONE &&
+ t->palm.state != PALM_PRESSURE)
+ return false;
+
+ if (t->pressure > tp->palm.pressure_threshold)
+ t->palm.state = PALM_PRESSURE;
+
+ return t->palm.state == PALM_PRESSURE;
+}
+
static void
tp_palm_detect(struct tp_dispatch *tp, struct tp_touch *t, uint64_t time)
{
const char *palm_state;
enum touch_palm_state oldstate = t->palm.state;
+ if (tp_palm_detect_pressure_triggered(tp, t, time))
+ goto out;
+
if (tp_palm_detect_dwt_triggered(tp, t, time))
goto out;
if (tp_palm_detect_edge(tp, t, time))
goto out;
+ /* Pressure is highest priority because it cannot be released and
+ * overrides all other checks. So we check once before anything else
+ * in case pressure triggers on a non-palm touch. And again after
+ * everything in case one of the others released but we have a
+ * pressure trigger now.
+ */
+ if (tp_palm_detect_pressure_triggered(tp, t, time))
+ goto out;
+
return;
out:
+
if (oldstate == t->palm.state)
return;
case PALM_TOOL_PALM:
palm_state = "tool-palm";
break;
+ case PALM_PRESSURE:
+ palm_state = "pressure";
+ break;
case PALM_NONE:
default:
abort();
tp->palm.right_edge = edges.x;
}
+static int
+tp_read_palm_pressure_prop(struct tp_dispatch *tp,
+ const struct evdev_device *device)
+{
+ struct udev_device *udev_device = device->udev_device;
+ const char *prop;
+ int threshold;
+ const int default_palm_threshold = 130;
+
+ prop = udev_device_get_property_value(udev_device,
+ "LIBINPUT_ATTR_PALM_PRESSURE_THRESHOLD");
+ if (!prop)
+ return default_palm_threshold;
+
+ threshold = parse_palm_pressure_property(prop);
+
+ return threshold > 0 ? threshold : default_palm_threshold;
+}
+
+static inline void
+tp_init_palmdetect_pressure(struct tp_dispatch *tp,
+ struct evdev_device *device)
+{
+ if (!libevdev_has_event_code(device->evdev, EV_ABS, ABS_MT_PRESSURE)) {
+ tp->palm.use_pressure = false;
+ return;
+ }
+
+ tp->palm.pressure_threshold = tp_read_palm_pressure_prop(tp, device);
+ tp->palm.use_pressure = true;
+
+ evdev_log_debug(device,
+ "palm: pressure threshold is %d\n",
+ tp->palm.pressure_threshold);
+}
+
static void
tp_init_palmdetect(struct tp_dispatch *tp,
struct evdev_device *device)
tp->palm.use_mt_tool = true;
tp_init_palmdetect_edge(tp, device);
+ tp_init_palmdetect_pressure(tp, device);
}
static void
#include "libinput-util.h"
#include "litest.h"
+static inline bool
+has_disable_while_typing(struct litest_device *device)
+{
+ return libinput_device_config_dwt_is_available(device->libinput_device);
+}
+
+static inline struct litest_device *
+dwt_init_paired_keyboard(struct libinput *li,
+ struct litest_device *touchpad)
+{
+ enum litest_device_type which = LITEST_KEYBOARD;
+
+ if (libevdev_get_id_vendor(touchpad->evdev) == VENDOR_ID_APPLE)
+ which = LITEST_APPLE_KEYBOARD;
+
+ if (libevdev_get_id_vendor(touchpad->evdev) == VENDOR_ID_CHICONY)
+ which = LITEST_ACER_HAWAII_KEYBOARD;
+
+ return litest_add_device(li, which);
+}
+
START_TEST(touchpad_1fg_motion)
{
struct litest_device *dev = litest_current_device();
}
END_TEST
+static inline bool
+touchpad_has_palm_pressure(struct litest_device *dev)
+{
+ struct libevdev *evdev = dev->evdev;
+
+ if (libevdev_has_event_code(evdev, EV_ABS, ABS_MT_PRESSURE))
+ return true;
+
+ return false;
+}
+
+START_TEST(touchpad_palm_detect_pressure)
+{
+ struct litest_device *dev = litest_current_device();
+ struct libinput *li = dev->libinput;
+ struct axis_replacement axes[] = {
+ { ABS_MT_PRESSURE, 75 },
+ { -1, 0 }
+ };
+
+ if (!touchpad_has_palm_pressure(dev))
+ return;
+
+ litest_disable_tap(dev->libinput_device);
+ litest_drain_events(li);
+
+ litest_touch_down_extended(dev, 0, 50, 99, axes);
+ litest_touch_move_to(dev, 0, 50, 50, 80, 99, 10, 0);
+ litest_touch_up(dev, 0);
+
+ litest_assert_empty_queue(li);
+}
+END_TEST
+
+START_TEST(touchpad_palm_detect_pressure_late)
+{
+ struct litest_device *dev = litest_current_device();
+ struct libinput *li = dev->libinput;
+ struct axis_replacement axes[] = {
+ { ABS_MT_PRESSURE, 75 },
+ { -1, 0 }
+ };
+
+ if (!touchpad_has_palm_pressure(dev))
+ return;
+
+ litest_disable_tap(dev->libinput_device);
+ litest_drain_events(li);
+
+ litest_touch_down(dev, 0, 50, 50);
+ litest_touch_move_to(dev, 0, 50, 70, 80, 90, 10, 0);
+ litest_drain_events(li);
+ libinput_dispatch(li);
+ litest_touch_move_to_extended(dev, 0, 80, 90, 50, 20,
+ axes, 10, 0);
+ litest_touch_up(dev, 0);
+
+ litest_assert_empty_queue(li);
+}
+END_TEST
+
+START_TEST(touchpad_palm_detect_pressure_keep_palm)
+{
+ struct litest_device *dev = litest_current_device();
+ struct libinput *li = dev->libinput;
+ struct axis_replacement axes[] = {
+ { ABS_MT_PRESSURE, 75 },
+ { -1, 0 }
+ };
+
+ if (!touchpad_has_palm_pressure(dev))
+ return;
+
+ litest_disable_tap(dev->libinput_device);
+ litest_drain_events(li);
+
+ litest_touch_down(dev, 0, 80, 90);
+ litest_touch_move_to_extended(dev, 0, 80, 90, 50, 20,
+ axes, 10, 0);
+ litest_touch_move_to(dev, 0, 50, 20, 80, 90, 10, 0);
+ litest_touch_up(dev, 0);
+
+ litest_assert_empty_queue(li);
+}
+END_TEST
+
+START_TEST(touchpad_palm_detect_pressure_after_edge)
+{
+ struct litest_device *dev = litest_current_device();
+ struct libinput *li = dev->libinput;
+ struct axis_replacement axes[] = {
+ { ABS_MT_PRESSURE, 75 },
+ { -1, 0 }
+ };
+
+ if (!touchpad_has_palm_pressure(dev) ||
+ !touchpad_has_palm_detect_size(dev) ||
+ !litest_has_2fg_scroll(dev))
+ return;
+
+ litest_enable_2fg_scroll(dev);
+ litest_disable_tap(dev->libinput_device);
+ litest_drain_events(li);
+
+ litest_touch_down(dev, 0, 99, 50);
+ litest_touch_move_to_extended(dev, 0, 99, 50, 20, 50, axes, 20, 0);
+ litest_touch_up(dev, 0);
+ libinput_dispatch(li);
+
+ litest_assert_empty_queue(li);
+}
+END_TEST
+
+START_TEST(touchpad_palm_detect_pressure_after_dwt)
+{
+ struct litest_device *touchpad = litest_current_device();
+ struct litest_device *keyboard;
+ struct libinput *li = touchpad->libinput;
+ struct axis_replacement axes[] = {
+ { ABS_MT_PRESSURE, 75 },
+ { -1, 0 }
+ };
+
+ if (!touchpad_has_palm_pressure(touchpad))
+ return;
+
+ keyboard = dwt_init_paired_keyboard(li, touchpad);
+ litest_disable_tap(touchpad->libinput_device);
+ litest_drain_events(li);
+
+ litest_keyboard_key(keyboard, KEY_A, true);
+ litest_keyboard_key(keyboard, KEY_A, false);
+ litest_drain_events(li);
+
+ /* within dwt timeout, dwt blocks events */
+ litest_touch_down(touchpad, 0, 50, 50);
+ litest_touch_move_to_extended(touchpad, 0, 50, 50, 20, 50, axes, 20, 0);
+ litest_assert_empty_queue(li);
+
+ litest_timeout_dwt_short();
+ libinput_dispatch(li);
+ litest_assert_empty_queue(li);
+
+ /* after dwt timeout, pressure blocks events */
+ litest_touch_move_to_extended(touchpad, 0, 20, 50, 50, 50, axes, 20, 0);
+ litest_touch_up(touchpad, 0);
+
+ litest_assert_empty_queue(li);
+
+ litest_delete_device(keyboard);
+}
+END_TEST
+
START_TEST(touchpad_left_handed)
{
struct litest_device *dev = litest_current_device();
}
END_TEST
-static inline bool
-has_disable_while_typing(struct litest_device *device)
-{
- return libinput_device_config_dwt_is_available(device->libinput_device);
-}
-
-static inline struct litest_device *
-dwt_init_paired_keyboard(struct libinput *li,
- struct litest_device *touchpad)
-{
- enum litest_device_type which = LITEST_KEYBOARD;
-
- if (libevdev_get_id_vendor(touchpad->evdev) == VENDOR_ID_APPLE)
- which = LITEST_APPLE_KEYBOARD;
-
- if (libevdev_get_id_vendor(touchpad->evdev) == VENDOR_ID_CHICONY)
- which = LITEST_ACER_HAWAII_KEYBOARD;
-
- return litest_add_device(li, which);
-}
-
START_TEST(touchpad_dwt)
{
struct litest_device *touchpad = litest_current_device();
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_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_keep_palm, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH);
+ litest_add("touchpad:palm", touchpad_palm_detect_pressure_after_edge, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH);
+ litest_add("touchpad:palm", touchpad_palm_detect_pressure_after_dwt, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH);
+
litest_add("touchpad:left-handed", touchpad_left_handed, LITEST_TOUCHPAD|LITEST_BUTTON, LITEST_CLICKPAD);
litest_add_for_device("touchpad:left-handed", touchpad_left_handed_appletouch, LITEST_APPLETOUCH);
litest_add("touchpad:left-handed", touchpad_left_handed_clickpad, LITEST_CLICKPAD, LITEST_APPLE_CLICKPAD);