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 <peter.hutterer@who-t.net>
This commit is contained in:
Peter Hutterer 2018-09-19 12:02:51 +10:00
parent 72560e031b
commit f325ca921d
7 changed files with 126 additions and 21 deletions

View file

@ -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,
};

View file

@ -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;
};

View file

@ -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,
};

View file

@ -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,
};

View file

@ -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,
};

View file

@ -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)
{

View file

@ -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 */