From f325ca921dede43b87286b2fff510c5dfacb3c93 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Wed, 19 Sep 2018 12:02:51 +1000 Subject: [PATCH] evdev: add a rectangle to the touch arbitration This enables us to specify the location that needs to be arbitrated, rather than just disabling the whole device altogether. This patch just adds the hooks, no implementation. This is internal API only, one backend can specify an area in mm which gets converted to device coordinates in the target device and arbitrated there. Right now, everything simply passes NULL. Signed-off-by: Peter Hutterer --- src/evdev-fallback.c | 48 +++++++++++++++++++++++++++++++++------- src/evdev-fallback.h | 1 + src/evdev-mt-touchpad.c | 5 ++++- src/evdev-tablet-pad.c | 3 ++- src/evdev-tablet.c | 14 +++++++----- src/evdev.h | 49 ++++++++++++++++++++++++++++++++++++----- src/libinput-private.h | 27 +++++++++++++++++++++++ 7 files changed, 126 insertions(+), 21 deletions(-) diff --git a/src/evdev-fallback.c b/src/evdev-fallback.c index 64007720..50c4afd1 100644 --- a/src/evdev-fallback.c +++ b/src/evdev-fallback.c @@ -871,6 +871,21 @@ fallback_any_button_down(struct fallback_dispatch *dispatch, return false; } +static inline bool +fallback_arbitrate_touch(struct fallback_dispatch *dispatch, + struct mt_slot *slot) +{ + bool discard = false; + + if (dispatch->arbitration.state == ARBITRATION_IGNORE_RECT && + point_in_rect(&slot->point, &dispatch->arbitration.rect)) { + slot->palm_state = PALM_IS_PALM; + discard = true; + } + + return discard; +} + static inline bool fallback_flush_mt_events(struct fallback_dispatch *dispatch, struct evdev_device *device, @@ -900,10 +915,13 @@ fallback_flush_mt_events(struct fallback_dispatch *dispatch, } else if (slot->palm_state == PALM_NONE) { switch (slot->state) { case SLOT_STATE_BEGIN: - sent = fallback_flush_mt_down(dispatch, - device, - i, - time); + if (!fallback_arbitrate_touch(dispatch, + slot)) { + sent = fallback_flush_mt_down(dispatch, + device, + i, + time); + } break; case SLOT_STATE_UPDATE: sent = fallback_flush_mt_motion(dispatch, @@ -1044,12 +1062,16 @@ fallback_interface_process(struct evdev_dispatch *evdev_dispatch, static void cancel_touches(struct fallback_dispatch *dispatch, struct evdev_device *device, + const struct device_coord_rect *rect, uint64_t time) { unsigned int idx; bool need_frame = false; - need_frame = fallback_flush_st_cancel(dispatch, device, time); + if (!rect || point_in_rect(&dispatch->abs.point, rect)) + need_frame = fallback_flush_st_cancel(dispatch, + device, + time); for (idx = 0; idx < dispatch->mt.slots_len; idx++) { struct mt_slot *slot = &dispatch->mt.slots[idx]; @@ -1057,7 +1079,8 @@ cancel_touches(struct fallback_dispatch *dispatch, if (slot->seat_slot == -1) continue; - if (fallback_flush_mt_cancel(dispatch, device, idx, time)) + if ((!rect || point_in_rect(&slot->point, rect)) && + fallback_flush_mt_cancel(dispatch, device, idx, time)) need_frame = true; } @@ -1125,7 +1148,7 @@ fallback_return_to_neutral_state(struct fallback_dispatch *dispatch, if ((time = libinput_now(libinput)) == 0) return; - cancel_touches(dispatch, device, time); + cancel_touches(dispatch, device, NULL, time); release_pressed_keys(dispatch, device, time); memset(dispatch->hw_key_mask, 0, sizeof(dispatch->hw_key_mask)); memset(dispatch->hw_key_mask, 0, sizeof(dispatch->last_hw_key_mask)); @@ -1199,9 +1222,11 @@ static void fallback_interface_toggle_touch(struct evdev_dispatch *evdev_dispatch, struct evdev_device *device, enum evdev_arbitration_state which, + const struct phys_rect *phys_rect, uint64_t time) { struct fallback_dispatch *dispatch = fallback_dispatch(evdev_dispatch); + struct device_coord_rect rect = {0}; if (which == dispatch->arbitration.state) return; @@ -1218,6 +1243,12 @@ fallback_interface_toggle_touch(struct evdev_dispatch *evdev_dispatch, libinput_timer_set(&dispatch->arbitration.arbitration_timer, time + ms2us(90)); break; + case ARBITRATION_IGNORE_RECT: + assert(phys_rect); + rect = evdev_phys_rect_to_units(device, phys_rect); + cancel_touches(dispatch, device, &rect, time); + dispatch->arbitration.rect = rect; + break; case ARBITRATION_IGNORE_ALL: libinput_timer_cancel(&dispatch->arbitration.arbitration_timer); fallback_return_to_neutral_state(dispatch, device); @@ -1421,7 +1452,8 @@ struct evdev_dispatch_interface fallback_interface = { .device_suspended = fallback_interface_device_removed, /* treat as remove */ .device_resumed = fallback_interface_device_added, /* treat as add */ .post_added = fallback_interface_sync_initial_state, - .toggle_touch = fallback_interface_toggle_touch, + .touch_arbitration_toggle = fallback_interface_toggle_touch, + .touch_arbitration_update_rect = NULL, .get_switch_state = fallback_interface_get_switch_state, }; diff --git a/src/evdev-fallback.h b/src/evdev-fallback.h index 58694dcc..f57c4af2 100644 --- a/src/evdev-fallback.h +++ b/src/evdev-fallback.h @@ -147,6 +147,7 @@ struct fallback_dispatch { struct { enum evdev_arbitration_state state; bool in_arbitration; + struct device_coord_rect rect; struct libinput_timer arbitration_timer; } arbitration; }; diff --git a/src/evdev-mt-touchpad.c b/src/evdev-mt-touchpad.c index 7385ab57..4798111a 100644 --- a/src/evdev-mt-touchpad.c +++ b/src/evdev-mt-touchpad.c @@ -2693,6 +2693,7 @@ static void tp_interface_toggle_touch(struct evdev_dispatch *dispatch, struct evdev_device *device, enum evdev_arbitration_state which, + const struct phys_rect *rect, uint64_t time) { struct tp_dispatch *tp = tp_dispatch(dispatch); @@ -2702,6 +2703,7 @@ tp_interface_toggle_touch(struct evdev_dispatch *dispatch, switch (which) { case ARBITRATION_IGNORE_ALL: + case ARBITRATION_IGNORE_RECT: libinput_timer_cancel(&tp->arbitration.arbitration_timer); tp_clear_state(tp); tp->arbitration.state = which; @@ -2730,7 +2732,8 @@ static struct evdev_dispatch_interface tp_interface = { .device_suspended = tp_interface_device_removed, /* treat as remove */ .device_resumed = tp_interface_device_added, /* treat as add */ .post_added = NULL, - .toggle_touch = tp_interface_toggle_touch, + .touch_arbitration_toggle = tp_interface_toggle_touch, + .touch_arbitration_update_rect = NULL, .get_switch_state = NULL, }; diff --git a/src/evdev-tablet-pad.c b/src/evdev-tablet-pad.c index b3b374dc..f1cbc4a4 100644 --- a/src/evdev-tablet-pad.c +++ b/src/evdev-tablet-pad.c @@ -518,7 +518,8 @@ static struct evdev_dispatch_interface pad_interface = { .device_suspended = NULL, .device_resumed = NULL, .post_added = NULL, - .toggle_touch = NULL, + .touch_arbitration_toggle = NULL, + .touch_arbitration_update_rect = NULL, .get_switch_state = NULL, }; diff --git a/src/evdev-tablet.c b/src/evdev-tablet.c index 6d177e18..e94fad53 100644 --- a/src/evdev-tablet.c +++ b/src/evdev-tablet.c @@ -1634,11 +1634,12 @@ tablet_set_touch_device_enabled(struct evdev_device *touch_device, which = ARBITRATION_IGNORE_ALL; dispatch = touch_device->dispatch; - if (dispatch->interface->toggle_touch) - dispatch->interface->toggle_touch(dispatch, - touch_device, - which, - time); + if (dispatch->interface->touch_arbitration_toggle) + dispatch->interface->touch_arbitration_toggle(dispatch, + touch_device, + which, + NULL, + time); } static inline void @@ -1941,7 +1942,8 @@ static struct evdev_dispatch_interface tablet_interface = { .device_suspended = NULL, .device_resumed = NULL, .post_added = tablet_check_initial_proximity, - .toggle_touch = NULL, + .touch_arbitration_toggle = NULL, + .touch_arbitration_update_rect = NULL, .get_switch_state = NULL, }; diff --git a/src/evdev.h b/src/evdev.h index e983fb1d..34ee64de 100644 --- a/src/evdev.h +++ b/src/evdev.h @@ -147,6 +147,7 @@ enum evdev_debounce_state { enum evdev_arbitration_state { ARBITRATION_NOT_ACTIVE, ARBITRATION_IGNORE_ALL, + ARBITRATION_IGNORE_RECT, }; struct evdev_device { @@ -303,11 +304,22 @@ struct evdev_dispatch_interface { struct evdev_dispatch *dispatch); /* For touch arbitration, called on the device that should - * enable/disable touch capabilities */ - void (*toggle_touch)(struct evdev_dispatch *dispatch, - struct evdev_device *device, - enum evdev_arbitration_state which, - uint64_t now); + * enable/disable touch capabilities. + */ + void (*touch_arbitration_toggle)(struct evdev_dispatch *dispatch, + struct evdev_device *device, + enum evdev_arbitration_state which, + const struct phys_rect *rect, /* may be NULL */ + uint64_t now); + + /* Called when touch arbitration is on, updates the area where touch + * arbitration should apply. + */ + void (*touch_arbitration_update_rect)(struct evdev_dispatch *dispatch, + struct evdev_device *device, + const struct phys_rect *rect, + uint64_t now); + /* Return the state of the given switch */ enum libinput_switch_state @@ -880,6 +892,33 @@ evdev_device_mm_to_units(const struct evdev_device *device, return units; } +static inline struct device_coord_rect +evdev_phys_rect_to_units(const struct evdev_device *device, + const struct phys_rect *mm) +{ + struct device_coord_rect units = {0}; + const struct input_absinfo *absx, *absy; + + if (device->abs.absinfo_x == NULL || + device->abs.absinfo_y == NULL) { + log_bug_libinput(evdev_libinput_context(device), + "%s: is not an abs device\n", + device->devname); + return units; + } + + absx = device->abs.absinfo_x; + absy = device->abs.absinfo_y; + + units.x = mm->x * absx->resolution + absx->minimum; + units.y = mm->y * absy->resolution + absy->minimum; + units.w = mm->w * absx->resolution; + units.h = mm->h * absy->resolution; + + return units; +} + + static inline void evdev_device_init_abs_range_warnings(struct evdev_device *device) { diff --git a/src/libinput-private.h b/src/libinput-private.h index ad92cde8..c0234a5b 100644 --- a/src/libinput-private.h +++ b/src/libinput-private.h @@ -95,6 +95,18 @@ struct phys_coords { double y; }; +/* A rectangle in mm, x/y is the top-left corner */ +struct phys_rect { + double x, y; + double w, h; +}; + +/* A rectangle in device coordinates, x/y is the top-left corner */ +struct device_coord_rect { + int x, y; + int w, h; +}; + /* A pair of tilt flags */ struct wheel_tilt_flags { bool vertical, horizontal; @@ -810,4 +822,19 @@ device_float_get_direction(const struct device_float_coords coords) { return xy_get_direction(coords.x, coords.y); } + +/** + * Returns true if the point is within the given rectangle, including the + * left edge but excluding the right edge. + */ +static inline bool +point_in_rect(const struct device_coords *point, + const struct device_coord_rect *rect) +{ + return (point->x >= rect->x && + point->x < rect->x + rect->w && + point->y >= rect->y && + point->y < rect->y + rect->h); +} + #endif /* LIBINPUT_PRIVATE_H */