tablet: hook up tip events

Behavior for axis events in the same event frame as the BTN_TOUCH is to
always send axis events before any tip state.
Behavior for button events in the same event frame as the BTN_TOUCH is to
order button events to happen when the tip is in proximity, i.e. after the tip
event on tip down and before the tip event on tip up.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
Reviewed-by: Hans de Goede <hdegoede@redhat.com>
This commit is contained in:
Peter Hutterer 2015-11-11 14:03:05 +10:00
parent 1318ffadb5
commit 6f5d9902c8
5 changed files with 422 additions and 10 deletions

View file

@ -425,6 +425,8 @@ tablet_update_button(struct tablet_dispatch *tablet,
uint32_t enable)
{
switch (evcode) {
case BTN_TOUCH:
return;
case BTN_LEFT:
case BTN_RIGHT:
case BTN_MIDDLE:
@ -433,7 +435,6 @@ tablet_update_button(struct tablet_dispatch *tablet,
case BTN_FORWARD:
case BTN_BACK:
case BTN_TASK:
case BTN_TOUCH:
case BTN_STYLUS:
case BTN_STYLUS2:
break;
@ -496,11 +497,10 @@ tablet_process_key(struct tablet_dispatch *tablet,
break;
case BTN_TOUCH:
if (e->value)
tablet_set_status(tablet, TABLET_TOOL_IN_CONTACT);
tablet_set_status(tablet, TABLET_TOOL_ENTERING_CONTACT);
else
tablet_unset_status(tablet, TABLET_TOOL_IN_CONTACT);
/* Fall through */
tablet_set_status(tablet, TABLET_TOOL_LEAVING_CONTACT);
break;
case BTN_LEFT:
case BTN_RIGHT:
case BTN_MIDDLE:
@ -622,7 +622,6 @@ tool_set_bits_from_libwacom(const struct tablet_dispatch *tablet,
copy_button_cap(tablet, tool, BTN_STYLUS2);
if (libwacom_stylus_get_num_buttons(s) >= 1)
copy_button_cap(tablet, tool, BTN_STYLUS);
copy_button_cap(tablet, tool, BTN_TOUCH);
}
if (libwacom_stylus_has_wheel(s))
@ -707,7 +706,6 @@ tool_set_bits(const struct tablet_dispatch *tablet,
case LIBINPUT_TOOL_TYPE_ERASER:
copy_button_cap(tablet, tool, BTN_STYLUS);
copy_button_cap(tablet, tool, BTN_STYLUS2);
copy_button_cap(tablet, tool, BTN_TOUCH);
break;
case LIBINPUT_TOOL_TYPE_MOUSE:
case LIBINPUT_TOOL_TYPE_LENS:
@ -843,7 +841,8 @@ sanitize_tablet_axes(struct tablet_dispatch *tablet)
clear_bit(tablet->changed_axes, LIBINPUT_TABLET_AXIS_DISTANCE);
tablet->axes[LIBINPUT_TABLET_AXIS_DISTANCE] = 0;
} else if (bit_is_set(tablet->changed_axes, LIBINPUT_TABLET_AXIS_PRESSURE) &&
!tablet_has_status(tablet, TABLET_TOOL_IN_CONTACT)) {
(!tablet_has_status(tablet, TABLET_TOOL_IN_CONTACT) &&
!tablet_has_status(tablet, TABLET_TOOL_ENTERING_CONTACT))) {
/* Make sure that the last axis value sent to the caller is a 0 */
if (tablet->axes[LIBINPUT_TABLET_AXIS_PRESSURE] == 0)
clear_bit(tablet->changed_axes,
@ -881,6 +880,8 @@ tablet_flush(struct tablet_dispatch *tablet,
0,
sizeof(tablet->button_state.stylus_buttons));
tablet_set_status(tablet, TABLET_BUTTONS_RELEASED);
if (tablet_has_status(tablet, TABLET_TOOL_IN_CONTACT))
tablet_set_status(tablet, TABLET_TOOL_LEAVING_CONTACT);
} else if (tablet_has_status(tablet, TABLET_AXES_UPDATED) ||
tablet_has_status(tablet, TABLET_TOOL_ENTERING_PROXIMITY)) {
sanitize_tablet_axes(tablet);
@ -890,6 +891,16 @@ tablet_flush(struct tablet_dispatch *tablet,
tablet_unset_status(tablet, TABLET_AXES_UPDATED);
}
if (tablet_has_status(tablet, TABLET_TOOL_ENTERING_CONTACT)) {
tablet_notify_tip(&device->base,
time,
tool,
LIBINPUT_TOOL_TIP_DOWN,
tablet->axes);
tablet_unset_status(tablet, TABLET_TOOL_ENTERING_CONTACT);
tablet_set_status(tablet, TABLET_TOOL_IN_CONTACT);
}
if (tablet_has_status(tablet, TABLET_BUTTONS_RELEASED)) {
tablet_notify_buttons(tablet,
device,
@ -908,6 +919,16 @@ tablet_flush(struct tablet_dispatch *tablet,
tablet_unset_status(tablet, TABLET_BUTTONS_PRESSED);
}
if (tablet_has_status(tablet, TABLET_TOOL_LEAVING_CONTACT)) {
tablet_notify_tip(&device->base,
time,
tool,
LIBINPUT_TOOL_TIP_UP,
tablet->axes);
tablet_unset_status(tablet, TABLET_TOOL_LEAVING_CONTACT);
tablet_unset_status(tablet, TABLET_TOOL_IN_CONTACT);
}
if (tablet_has_status(tablet, TABLET_TOOL_LEAVING_PROXIMITY)) {
memset(tablet->changed_axes, 0, sizeof(tablet->changed_axes));
tablet_notify_proximity(&device->base,

View file

@ -38,7 +38,9 @@ enum tablet_status {
TABLET_TOOL_IN_CONTACT = 1 << 3,
TABLET_TOOL_LEAVING_PROXIMITY = 1 << 4,
TABLET_TOOL_OUT_OF_PROXIMITY = 1 << 5,
TABLET_TOOL_ENTERING_PROXIMITY = 1 << 6
TABLET_TOOL_ENTERING_PROXIMITY = 1 << 6,
TABLET_TOOL_ENTERING_CONTACT = 1 << 7,
TABLET_TOOL_LEAVING_CONTACT = 1 << 8,
};
struct button_state {
@ -48,7 +50,7 @@ struct button_state {
struct tablet_dispatch {
struct evdev_dispatch base;
struct evdev_device *device;
unsigned char status;
unsigned int status;
unsigned char changed_axes[NCHARS(LIBINPUT_TABLET_AXIS_MAX + 1)];
double axes[LIBINPUT_TABLET_AXIS_MAX + 1];
double deltas[LIBINPUT_TABLET_AXIS_MAX + 1];

View file

@ -2330,6 +2330,21 @@ litest_is_gesture_event(struct libinput_event *event,
return gevent;
}
struct libinput_event_tablet * litest_is_tablet_event(
struct libinput_event *event,
enum libinput_event_type type)
{
struct libinput_event_tablet *tevent;
litest_assert(event != NULL);
litest_assert_int_eq(libinput_event_get_type(event), type);
tevent = libinput_event_get_tablet_event(event);
litest_assert(tevent != NULL);
return tevent;
}
void
litest_assert_tablet_button_event(struct libinput *li, unsigned int button,
enum libinput_button_state state)

View file

@ -402,6 +402,9 @@ struct libinput_event_gesture * litest_is_gesture_event(
struct libinput_event *event,
enum libinput_event_type type,
int nfingers);
struct libinput_event_tablet * litest_is_tablet_event(
struct libinput_event *event,
enum libinput_event_type type);
void litest_assert_button_event(struct libinput *li,
unsigned int button,

View file

@ -34,6 +34,370 @@
#include "evdev-tablet.h"
#include "litest.h"
START_TEST(tip_down_up)
{
struct litest_device *dev = litest_current_device();
struct libinput *li = dev->libinput;
struct libinput_event *event;
struct libinput_event_tablet *tablet_event;
struct axis_replacement axes[] = {
{ ABS_DISTANCE, 10 },
{ -1, -1 }
};
litest_tablet_proximity_in(dev, 10, 10, axes);
litest_drain_events(li);
litest_event(dev, EV_KEY, BTN_TOUCH, 1);
litest_event(dev, EV_SYN, SYN_REPORT, 0);
libinput_dispatch(li);
event = libinput_get_event(li);
tablet_event = litest_is_tablet_event(event,
LIBINPUT_EVENT_TABLET_TIP);
ck_assert_int_eq(libinput_event_tablet_get_tip_state(tablet_event),
LIBINPUT_TOOL_TIP_DOWN);
libinput_event_destroy(event);
litest_assert_empty_queue(li);
litest_event(dev, EV_KEY, BTN_TOUCH, 0);
litest_event(dev, EV_SYN, SYN_REPORT, 0);
libinput_dispatch(li);
event = libinput_get_event(li);
tablet_event = litest_is_tablet_event(event,
LIBINPUT_EVENT_TABLET_TIP);
ck_assert_int_eq(libinput_event_tablet_get_tip_state(tablet_event),
LIBINPUT_TOOL_TIP_UP);
libinput_event_destroy(event);
litest_assert_empty_queue(li);
litest_assert_empty_queue(li);
}
END_TEST
START_TEST(tip_down_prox_in)
{
struct litest_device *dev = litest_current_device();
struct libinput *li = dev->libinput;
struct libinput_event *event;
struct libinput_event_tablet *tablet_event;
struct axis_replacement axes[] = {
{ ABS_DISTANCE, 10 },
{ -1, -1 }
};
litest_drain_events(li);
litest_push_event_frame(dev);
litest_tablet_proximity_in(dev, 10, 10, axes);
litest_event(dev, EV_KEY, BTN_TOUCH, 1);
litest_pop_event_frame(dev);
libinput_dispatch(li);
event = libinput_get_event(li);
tablet_event = litest_is_tablet_event(event,
LIBINPUT_EVENT_TABLET_PROXIMITY);
ck_assert_int_eq(libinput_event_tablet_get_proximity_state(tablet_event),
LIBINPUT_TOOL_PROXIMITY_IN);
libinput_event_destroy(event);
libinput_dispatch(li);
event = libinput_get_event(li);
tablet_event = litest_is_tablet_event(event,
LIBINPUT_EVENT_TABLET_TIP);
ck_assert_int_eq(libinput_event_tablet_get_tip_state(tablet_event),
LIBINPUT_TOOL_TIP_DOWN);
libinput_event_destroy(event);
litest_assert_empty_queue(li);
}
END_TEST
START_TEST(tip_up_prox_out)
{
struct litest_device *dev = litest_current_device();
struct libinput *li = dev->libinput;
struct libinput_event *event;
struct libinput_event_tablet *tablet_event;
struct axis_replacement axes[] = {
{ ABS_DISTANCE, 10 },
{ -1, -1 }
};
litest_tablet_proximity_in(dev, 10, 10, axes);
litest_event(dev, EV_KEY, BTN_TOUCH, 1);
litest_event(dev, EV_SYN, SYN_REPORT, 0);
litest_drain_events(li);
litest_push_event_frame(dev);
litest_event(dev, EV_KEY, BTN_TOUCH, 0);
litest_tablet_proximity_out(dev);
litest_pop_event_frame(dev);
libinput_dispatch(li);
event = libinput_get_event(li);
tablet_event = litest_is_tablet_event(event,
LIBINPUT_EVENT_TABLET_TIP);
ck_assert_int_eq(libinput_event_tablet_get_tip_state(tablet_event),
LIBINPUT_TOOL_TIP_UP);
libinput_event_destroy(event);
libinput_dispatch(li);
event = libinput_get_event(li);
tablet_event = litest_is_tablet_event(event,
LIBINPUT_EVENT_TABLET_PROXIMITY);
ck_assert_int_eq(libinput_event_tablet_get_proximity_state(tablet_event),
LIBINPUT_TOOL_PROXIMITY_OUT);
libinput_event_destroy(event);
litest_assert_empty_queue(li);
}
END_TEST
START_TEST(tip_up_btn_change)
{
struct litest_device *dev = litest_current_device();
struct libinput *li = dev->libinput;
struct libinput_event *event;
struct libinput_event_tablet *tablet_event;
struct axis_replacement axes[] = {
{ ABS_DISTANCE, 10 },
{ -1, -1 }
};
litest_tablet_proximity_in(dev, 10, 10, axes);
litest_event(dev, EV_KEY, BTN_TOUCH, 1);
litest_event(dev, EV_SYN, SYN_REPORT, 0);
litest_drain_events(li);
litest_event(dev, EV_KEY, BTN_STYLUS, 1);
litest_event(dev, EV_KEY, BTN_TOUCH, 0);
litest_event(dev, EV_SYN, SYN_REPORT, 0);
libinput_dispatch(li);
event = libinput_get_event(li);
tablet_event = litest_is_tablet_event(event,
LIBINPUT_EVENT_TABLET_BUTTON);
ck_assert_int_eq(libinput_event_tablet_get_button(tablet_event),
BTN_STYLUS);
ck_assert_int_eq(libinput_event_tablet_get_button_state(tablet_event),
LIBINPUT_BUTTON_STATE_PRESSED);
libinput_event_destroy(event);
libinput_dispatch(li);
event = libinput_get_event(li);
tablet_event = litest_is_tablet_event(event,
LIBINPUT_EVENT_TABLET_TIP);
ck_assert_int_eq(libinput_event_tablet_get_tip_state(tablet_event),
LIBINPUT_TOOL_TIP_UP);
libinput_event_destroy(event);
litest_assert_empty_queue(li);
litest_event(dev, EV_KEY, BTN_TOUCH, 1);
litest_event(dev, EV_SYN, SYN_REPORT, 0);
litest_drain_events(li);
/* same thing with a release at tip-up */
litest_event(dev, EV_KEY, BTN_TOUCH, 0);
litest_event(dev, EV_KEY, BTN_STYLUS, 0);
litest_event(dev, EV_SYN, SYN_REPORT, 0);
libinput_dispatch(li);
event = libinput_get_event(li);
tablet_event = litest_is_tablet_event(event,
LIBINPUT_EVENT_TABLET_BUTTON);
ck_assert_int_eq(libinput_event_tablet_get_button(tablet_event),
BTN_STYLUS);
ck_assert_int_eq(libinput_event_tablet_get_button_state(tablet_event),
LIBINPUT_BUTTON_STATE_RELEASED);
libinput_event_destroy(event);
libinput_dispatch(li);
event = libinput_get_event(li);
tablet_event = litest_is_tablet_event(event,
LIBINPUT_EVENT_TABLET_TIP);
ck_assert_int_eq(libinput_event_tablet_get_tip_state(tablet_event),
LIBINPUT_TOOL_TIP_UP);
libinput_event_destroy(event);
litest_assert_empty_queue(li);
}
END_TEST
START_TEST(tip_down_btn_change)
{
struct litest_device *dev = litest_current_device();
struct libinput *li = dev->libinput;
struct libinput_event *event;
struct libinput_event_tablet *tablet_event;
struct axis_replacement axes[] = {
{ ABS_DISTANCE, 10 },
{ -1, -1 }
};
litest_tablet_proximity_in(dev, 10, 10, axes);
litest_drain_events(li);
litest_event(dev, EV_KEY, BTN_STYLUS, 1);
litest_event(dev, EV_KEY, BTN_TOUCH, 1);
litest_event(dev, EV_SYN, SYN_REPORT, 0);
libinput_dispatch(li);
event = libinput_get_event(li);
tablet_event = litest_is_tablet_event(event,
LIBINPUT_EVENT_TABLET_TIP);
ck_assert_int_eq(libinput_event_tablet_get_tip_state(tablet_event),
LIBINPUT_TOOL_TIP_DOWN);
libinput_event_destroy(event);
libinput_dispatch(li);
event = libinput_get_event(li);
tablet_event = litest_is_tablet_event(event,
LIBINPUT_EVENT_TABLET_BUTTON);
ck_assert_int_eq(libinput_event_tablet_get_button(tablet_event),
BTN_STYLUS);
ck_assert_int_eq(libinput_event_tablet_get_button_state(tablet_event),
LIBINPUT_BUTTON_STATE_PRESSED);
libinput_event_destroy(event);
litest_assert_empty_queue(li);
litest_event(dev, EV_KEY, BTN_TOUCH, 0);
litest_event(dev, EV_SYN, SYN_REPORT, 0);
litest_drain_events(li);
/* same thing with a release at tip-down */
litest_event(dev, EV_KEY, BTN_TOUCH, 1);
litest_event(dev, EV_KEY, BTN_STYLUS, 0);
litest_event(dev, EV_SYN, SYN_REPORT, 0);
libinput_dispatch(li);
event = libinput_get_event(li);
tablet_event = litest_is_tablet_event(event,
LIBINPUT_EVENT_TABLET_TIP);
ck_assert_int_eq(libinput_event_tablet_get_tip_state(tablet_event),
LIBINPUT_TOOL_TIP_DOWN);
libinput_event_destroy(event);
libinput_dispatch(li);
event = libinput_get_event(li);
tablet_event = litest_is_tablet_event(event,
LIBINPUT_EVENT_TABLET_BUTTON);
ck_assert_int_eq(libinput_event_tablet_get_button(tablet_event),
BTN_STYLUS);
ck_assert_int_eq(libinput_event_tablet_get_button_state(tablet_event),
LIBINPUT_BUTTON_STATE_RELEASED);
libinput_event_destroy(event);
litest_assert_empty_queue(li);
}
END_TEST
START_TEST(tip_down_motion)
{
struct litest_device *dev = litest_current_device();
struct libinput *li = dev->libinput;
struct libinput_event *event;
struct libinput_event_tablet *tablet_event;
struct axis_replacement axes[] = {
{ ABS_DISTANCE, 10 },
{ -1, -1 }
};
double x, y, last_x, last_y;
litest_tablet_proximity_in(dev, 10, 10, axes);
litest_drain_events(li);
litest_push_event_frame(dev);
litest_tablet_motion(dev, 70, 70, axes);
litest_event(dev, EV_KEY, BTN_TOUCH, 1);
litest_event(dev, EV_SYN, SYN_REPORT, 0);
litest_pop_event_frame(dev);
libinput_dispatch(li);
event = libinput_get_event(li);
tablet_event = litest_is_tablet_event(event,
LIBINPUT_EVENT_TABLET_AXIS);
last_x = libinput_event_tablet_get_axis_value(tablet_event,
LIBINPUT_TABLET_AXIS_X);
last_y = libinput_event_tablet_get_axis_value(tablet_event,
LIBINPUT_TABLET_AXIS_Y);
libinput_event_destroy(event);
libinput_dispatch(li);
event = libinput_get_event(li);
tablet_event = litest_is_tablet_event(event,
LIBINPUT_EVENT_TABLET_TIP);
ck_assert_int_eq(libinput_event_tablet_get_tip_state(tablet_event),
LIBINPUT_TOOL_TIP_DOWN);
x = libinput_event_tablet_get_axis_value(tablet_event,
LIBINPUT_TABLET_AXIS_X);
y = libinput_event_tablet_get_axis_value(tablet_event,
LIBINPUT_TABLET_AXIS_Y);
ck_assert_double_eq(last_x, x);
ck_assert_double_eq(last_y, y);
libinput_event_destroy(event);
litest_assert_empty_queue(li);
}
END_TEST
START_TEST(tip_up_motion)
{
struct litest_device *dev = litest_current_device();
struct libinput *li = dev->libinput;
struct libinput_event *event;
struct libinput_event_tablet *tablet_event;
struct axis_replacement axes[] = {
{ ABS_DISTANCE, 10 },
{ -1, -1 }
};
double x, y, last_x, last_y;
litest_tablet_proximity_in(dev, 10, 10, axes);
litest_event(dev, EV_KEY, BTN_TOUCH, 1);
litest_event(dev, EV_SYN, SYN_REPORT, 0);
litest_drain_events(li);
litest_push_event_frame(dev);
litest_tablet_motion(dev, 70, 70, axes);
litest_event(dev, EV_KEY, BTN_TOUCH, 0);
litest_event(dev, EV_SYN, SYN_REPORT, 0);
litest_pop_event_frame(dev);
libinput_dispatch(li);
event = libinput_get_event(li);
tablet_event = litest_is_tablet_event(event,
LIBINPUT_EVENT_TABLET_AXIS);
last_x = libinput_event_tablet_get_axis_value(tablet_event,
LIBINPUT_TABLET_AXIS_X);
last_y = libinput_event_tablet_get_axis_value(tablet_event,
LIBINPUT_TABLET_AXIS_Y);
libinput_event_destroy(event);
libinput_dispatch(li);
event = libinput_get_event(li);
tablet_event = litest_is_tablet_event(event,
LIBINPUT_EVENT_TABLET_TIP);
ck_assert_int_eq(libinput_event_tablet_get_tip_state(tablet_event),
LIBINPUT_TOOL_TIP_UP);
x = libinput_event_tablet_get_axis_value(tablet_event,
LIBINPUT_TABLET_AXIS_X);
y = libinput_event_tablet_get_axis_value(tablet_event,
LIBINPUT_TABLET_AXIS_Y);
ck_assert_double_eq(last_x, x);
ck_assert_double_eq(last_y, y);
libinput_event_destroy(event);
litest_assert_empty_queue(li);
}
END_TEST
START_TEST(proximity_in_out)
{
struct litest_device *dev = litest_current_device();
@ -1789,6 +2153,13 @@ litest_setup_tests(void)
litest_add("tablet:proximity", proximity_in_out, LITEST_TABLET, LITEST_ANY);
litest_add("tablet:proximity", proximity_has_axes, LITEST_TABLET, LITEST_ANY);
litest_add("tablet:proximity", bad_distance_events, LITEST_TABLET | LITEST_DISTANCE, LITEST_ANY);
litest_add("tablet:tip", tip_down_up, LITEST_TABLET, LITEST_ANY);
litest_add("tablet:tip", tip_down_prox_in, LITEST_TABLET, LITEST_ANY);
litest_add("tablet:tip", tip_up_prox_out, LITEST_TABLET, LITEST_ANY);
litest_add("tablet:tip", tip_down_btn_change, LITEST_TABLET, LITEST_ANY);
litest_add("tablet:tip", tip_up_btn_change, LITEST_TABLET, LITEST_ANY);
litest_add("tablet:tip", tip_down_motion, LITEST_TABLET, LITEST_ANY);
litest_add("tablet:tip", tip_up_motion, LITEST_TABLET, LITEST_ANY);
litest_add("tablet:motion", motion, LITEST_TABLET, LITEST_ANY);
litest_add("tablet:motion", motion_delta, LITEST_TABLET, LITEST_ANY);
litest_add("tablet:motion", motion_delta_partial, LITEST_TABLET, LITEST_ANY);