tablet: split out tip handling into a separate event

The tablet tip works like a button in the kernel but is otherwise not really
a button. Split it into an explicit tip up/down event instead.

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 13:39:43 +10:00
parent 30dbd6718a
commit 1318ffadb5
8 changed files with 154 additions and 1 deletions

View file

@ -476,6 +476,13 @@ tablet_notify_proximity(struct libinput_device *device,
unsigned char *changed_axes, unsigned char *changed_axes,
double *axes); double *axes);
void
tablet_notify_tip(struct libinput_device *device,
uint64_t time,
struct libinput_tool *tool,
enum libinput_tool_tip_state tip_state,
double *axes);
void void
tablet_notify_button(struct libinput_device *device, tablet_notify_button(struct libinput_device *device,
uint64_t time, uint64_t time,

View file

@ -137,6 +137,7 @@ struct libinput_event_tablet {
unsigned char changed_axes[NCHARS(LIBINPUT_TABLET_AXIS_MAX + 1)]; unsigned char changed_axes[NCHARS(LIBINPUT_TABLET_AXIS_MAX + 1)];
struct libinput_tool *tool; struct libinput_tool *tool;
enum libinput_tool_proximity_state proximity_state; enum libinput_tool_proximity_state proximity_state;
enum libinput_tool_tip_state tip_state;
}; };
static void static void
@ -313,6 +314,7 @@ libinput_event_get_tablet_event(struct libinput_event *event)
NULL, NULL,
LIBINPUT_EVENT_TABLET_AXIS, LIBINPUT_EVENT_TABLET_AXIS,
LIBINPUT_EVENT_TABLET_PROXIMITY, LIBINPUT_EVENT_TABLET_PROXIMITY,
LIBINPUT_EVENT_TABLET_TIP,
LIBINPUT_EVENT_TABLET_BUTTON); LIBINPUT_EVENT_TABLET_BUTTON);
return (struct libinput_event_tablet *) event; return (struct libinput_event_tablet *) event;
@ -918,6 +920,7 @@ libinput_event_tablet_axis_has_changed(struct libinput_event_tablet *event,
event->base.type, event->base.type,
0, 0,
LIBINPUT_EVENT_TABLET_AXIS, LIBINPUT_EVENT_TABLET_AXIS,
LIBINPUT_EVENT_TABLET_TIP,
LIBINPUT_EVENT_TABLET_PROXIMITY); LIBINPUT_EVENT_TABLET_PROXIMITY);
return (NCHARS(axis) <= sizeof(event->changed_axes)) ? return (NCHARS(axis) <= sizeof(event->changed_axes)) ?
@ -935,6 +938,7 @@ libinput_event_tablet_get_axis_value(struct libinput_event_tablet *event,
event->base.type, event->base.type,
0, 0,
LIBINPUT_EVENT_TABLET_AXIS, LIBINPUT_EVENT_TABLET_AXIS,
LIBINPUT_EVENT_TABLET_TIP,
LIBINPUT_EVENT_TABLET_PROXIMITY); LIBINPUT_EVENT_TABLET_PROXIMITY);
switch(axis) { switch(axis) {
@ -968,6 +972,7 @@ libinput_event_tablet_get_axis_delta(struct libinput_event_tablet *event,
event->base.type, event->base.type,
0, 0,
LIBINPUT_EVENT_TABLET_AXIS, LIBINPUT_EVENT_TABLET_AXIS,
LIBINPUT_EVENT_TABLET_TIP,
LIBINPUT_EVENT_TABLET_PROXIMITY); LIBINPUT_EVENT_TABLET_PROXIMITY);
switch(axis) { switch(axis) {
@ -999,6 +1004,7 @@ libinput_event_tablet_get_axis_delta_discrete(
event->base.type, event->base.type,
0, 0,
LIBINPUT_EVENT_TABLET_AXIS, LIBINPUT_EVENT_TABLET_AXIS,
LIBINPUT_EVENT_TABLET_TIP,
LIBINPUT_EVENT_TABLET_PROXIMITY); LIBINPUT_EVENT_TABLET_PROXIMITY);
switch(axis) { switch(axis) {
@ -1028,6 +1034,7 @@ libinput_event_tablet_get_x_transformed(struct libinput_event_tablet *event,
event->base.type, event->base.type,
0, 0,
LIBINPUT_EVENT_TABLET_AXIS, LIBINPUT_EVENT_TABLET_AXIS,
LIBINPUT_EVENT_TABLET_TIP,
LIBINPUT_EVENT_TABLET_PROXIMITY); LIBINPUT_EVENT_TABLET_PROXIMITY);
return evdev_device_transform_x(device, return evdev_device_transform_x(device,
@ -1046,6 +1053,7 @@ libinput_event_tablet_get_y_transformed(struct libinput_event_tablet *event,
event->base.type, event->base.type,
0, 0,
LIBINPUT_EVENT_TABLET_AXIS, LIBINPUT_EVENT_TABLET_AXIS,
LIBINPUT_EVENT_TABLET_TIP,
LIBINPUT_EVENT_TABLET_PROXIMITY); LIBINPUT_EVENT_TABLET_PROXIMITY);
return evdev_device_transform_y(device, return evdev_device_transform_y(device,
@ -1065,6 +1073,12 @@ libinput_event_tablet_get_proximity_state(struct libinput_event_tablet *event)
return event->proximity_state; return event->proximity_state;
} }
LIBINPUT_EXPORT enum libinput_tool_tip_state
libinput_event_tablet_get_tip_state(struct libinput_event_tablet *event)
{
return event->tip_state;
}
LIBINPUT_EXPORT uint32_t LIBINPUT_EXPORT uint32_t
libinput_event_tablet_get_time(struct libinput_event_tablet *event) libinput_event_tablet_get_time(struct libinput_event_tablet *event)
{ {
@ -1969,6 +1983,34 @@ tablet_notify_proximity(struct libinput_device *device,
&proximity_event->base); &proximity_event->base);
} }
void
tablet_notify_tip(struct libinput_device *device,
uint64_t time,
struct libinput_tool *tool,
enum libinput_tool_tip_state tip_state,
double *axes)
{
struct libinput_event_tablet *tip_event;
tip_event = zalloc(sizeof *tip_event);
if (!tip_event)
return;
*tip_event = (struct libinput_event_tablet) {
.time = time,
.tool = tool,
.tip_state = tip_state,
};
memcpy(tip_event->axes,
axes,
sizeof(tip_event->axes));
post_device_event(device,
time,
LIBINPUT_EVENT_TABLET_TIP,
&tip_event->base);
}
void void
tablet_notify_button(struct libinput_device *device, tablet_notify_button(struct libinput_device *device,
uint64_t time, uint64_t time,

View file

@ -216,6 +216,20 @@ enum libinput_tool_proximity_state {
LIBINPUT_TOOL_PROXIMITY_IN = 1, LIBINPUT_TOOL_PROXIMITY_IN = 1,
}; };
/**
* @ingroup device
*
* The tip contact state for a tool on a device. The device must have
* the @ref LIBINPUT_DEVICE_CAP_TABLET capability.
*
* The tip contact state of a tool is a binary state signalling whether the tool is
* touching the surface of the tablet device.
*/
enum libinput_tool_tip_state {
LIBINPUT_TOOL_TIP_UP = 0,
LIBINPUT_TOOL_TIP_DOWN = 1,
};
/** /**
* @ingroup base * @ingroup base
* *
@ -301,6 +315,19 @@ enum libinput_event_type {
* proximity out event. * proximity out event.
*/ */
LIBINPUT_EVENT_TABLET_PROXIMITY, LIBINPUT_EVENT_TABLET_PROXIMITY,
/**
* Signals that a tool has come in contact with the surface of a
* device with the @ref LIBINPUT_DEVICE_CAP_TABLET capability.
*
* On devices without distance proximity detection, the @ref
* LIBINPUT_EVENT_TABLET_TIP is sent immediately after @ref
* LIBINPUT_EVENT_TABLET_PROXIMITY for the tip down event, and
* immediately before for the tip up event.
*
* If a button and/or axis state change occurs at the same time as a
* tip state change, the order of events is device-dependent.
*/
LIBINPUT_EVENT_TABLET_TIP,
LIBINPUT_EVENT_TABLET_BUTTON, LIBINPUT_EVENT_TABLET_BUTTON,
LIBINPUT_EVENT_GESTURE_SWIPE_BEGIN = 800, LIBINPUT_EVENT_GESTURE_SWIPE_BEGIN = 800,
@ -1499,6 +1526,20 @@ libinput_event_tablet_get_tool(struct libinput_event_tablet *event);
enum libinput_tool_proximity_state enum libinput_tool_proximity_state
libinput_event_tablet_get_proximity_state(struct libinput_event_tablet *event); libinput_event_tablet_get_proximity_state(struct libinput_event_tablet *event);
/**
* @ingroup event_tablet
*
* Returns the new tip state of a tool from a tip event.
* Used to check whether or not a tool came in contact with the tablet
* surface or left contact with the tablet surface during an
* event of type @ref LIBINPUT_EVENT_TABLET_TIP.
*
* @param event The libinput tablet event
* @return The new tip state of the tool from the event.
*/
enum libinput_tool_tip_state
libinput_event_tablet_get_tip_state(struct libinput_event_tablet *event);
/** /**
* @ingroup event_tablet * @ingroup event_tablet
* *

View file

@ -195,6 +195,7 @@ LIBINPUT_TABLET_SUPPORT {
libinput_event_tablet_get_proximity_state; libinput_event_tablet_get_proximity_state;
libinput_event_tablet_get_seat_button_count; libinput_event_tablet_get_seat_button_count;
libinput_event_tablet_get_time; libinput_event_tablet_get_time;
libinput_event_tablet_get_tip_state;
libinput_event_tablet_get_tool; libinput_event_tablet_get_tool;
libinput_event_tablet_get_x_transformed; libinput_event_tablet_get_x_transformed;
libinput_event_tablet_get_y_transformed; libinput_event_tablet_get_y_transformed;

View file

@ -1887,6 +1887,9 @@ litest_event_type_str(struct libinput_event *event)
case LIBINPUT_EVENT_TABLET_PROXIMITY: case LIBINPUT_EVENT_TABLET_PROXIMITY:
str = "TABLET PROX"; str = "TABLET PROX";
break; break;
case LIBINPUT_EVENT_TABLET_TIP:
str = "TABLET TIP";
break;
case LIBINPUT_EVENT_TABLET_BUTTON: case LIBINPUT_EVENT_TABLET_BUTTON:
str = "TABLET BUTTON"; str = "TABLET BUTTON";
break; break;
@ -1949,6 +1952,11 @@ litest_print_event(struct libinput_event *event)
fprintf(stderr, "proximity %d\n", fprintf(stderr, "proximity %d\n",
libinput_event_tablet_get_proximity_state(t)); libinput_event_tablet_get_proximity_state(t));
break; break;
case LIBINPUT_EVENT_TABLET_TIP:
t = libinput_event_get_tablet_event(event);
fprintf(stderr, "tip %d\n",
libinput_event_tablet_get_tip_state(t));
break;
case LIBINPUT_EVENT_TABLET_BUTTON: case LIBINPUT_EVENT_TABLET_BUTTON:
t = libinput_event_get_tablet_event(event); t = libinput_event_get_tablet_event(event);
fprintf(stderr, "button %d state %d\n", fprintf(stderr, "button %d state %d\n",

View file

@ -118,7 +118,7 @@ START_TEST(proximity_out_clear_buttons)
/* Test that proximity out events send button releases for any currently /* Test that proximity out events send button releases for any currently
* pressed stylus buttons * pressed stylus buttons
*/ */
for (button = BTN_TOUCH; button <= BTN_STYLUS2; button++) { for (button = BTN_TOUCH + 1; button <= BTN_STYLUS2; button++) {
bool button_released = false; bool button_released = false;
uint32_t event_button; uint32_t event_button;
enum libinput_button_state state; enum libinput_button_state state;
@ -155,6 +155,8 @@ START_TEST(proximity_out_clear_buttons)
libevdev_event_code_get_name(EV_KEY, button), libevdev_event_code_get_name(EV_KEY, button),
event_button); event_button);
} }
litest_assert_empty_queue(li);
} }
END_TEST END_TEST

View file

@ -115,6 +115,9 @@ print_event_header(struct libinput_event *ev)
case LIBINPUT_EVENT_TABLET_PROXIMITY: case LIBINPUT_EVENT_TABLET_PROXIMITY:
type = "TABLET_PROXIMITY"; type = "TABLET_PROXIMITY";
break; break;
case LIBINPUT_EVENT_TABLET_TIP:
type = "TABLET_TIP";
break;
case LIBINPUT_EVENT_TABLET_BUTTON: case LIBINPUT_EVENT_TABLET_BUTTON:
type = "TABLET_BUTTON"; type = "TABLET_BUTTON";
break; break;
@ -278,6 +281,18 @@ print_pointer_button_event(struct libinput_event *ev)
libinput_event_pointer_get_seat_button_count(p)); libinput_event_pointer_get_seat_button_count(p));
} }
static void
print_tablet_tip_event(struct libinput_event *ev)
{
struct libinput_event_tablet *p = libinput_event_get_tablet_event(ev);
enum libinput_tool_tip_state state;
print_event_time(libinput_event_tablet_get_time(p));
state = libinput_event_tablet_get_tip_state(p);
printf("%s\n", state == LIBINPUT_TOOL_TIP_DOWN ? "down" : "up");
}
static void static void
print_tablet_button_event(struct libinput_event *ev) print_tablet_button_event(struct libinput_event *ev)
{ {
@ -667,6 +682,9 @@ handle_and_print_events(struct libinput *li)
case LIBINPUT_EVENT_TABLET_PROXIMITY: case LIBINPUT_EVENT_TABLET_PROXIMITY:
print_proximity_event(ev); print_proximity_event(ev);
break; break;
case LIBINPUT_EVENT_TABLET_TIP:
print_tablet_tip_event(ev);
break;
case LIBINPUT_EVENT_TABLET_BUTTON: case LIBINPUT_EVENT_TABLET_BUTTON:
print_tablet_button_event(ev); print_tablet_button_event(ev);
break; break;

View file

@ -88,6 +88,8 @@ struct window {
struct { struct {
double x, y; double x, y;
double x_in, y_in; double x_in, y_in;
double x_down, y_down;
double x_up, y_up;
double pressure; double pressure;
double distance; double distance;
double tilt_x, tilt_y; double tilt_x, tilt_y;
@ -234,6 +236,20 @@ draw(GtkWidget *widget, cairo_t *cr, gpointer data)
cairo_save(cr); cairo_save(cr);
} }
if (w->tool.x_down && w->tool.y_down) {
cairo_rectangle(cr, w->tool.x_down - 10, w->tool.y_down - 10, 20, 20);
cairo_stroke(cr);
cairo_restore(cr);
cairo_save(cr);
}
if (w->tool.x_up && w->tool.y_up) {
cairo_rectangle(cr, w->tool.x_up - 10, w->tool.y_up - 10, 20, 20);
cairo_stroke(cr);
cairo_restore(cr);
cairo_save(cr);
}
if (w->tool.pressure) if (w->tool.pressure)
cairo_set_source_rgb(cr, .8, .8, .2); cairo_set_source_rgb(cr, .8, .8, .2);
@ -584,6 +600,7 @@ static void
handle_event_tablet(struct libinput_event *ev, struct window *w) handle_event_tablet(struct libinput_event *ev, struct window *w)
{ {
struct libinput_event_tablet *t = libinput_event_get_tablet_event(ev); struct libinput_event_tablet *t = libinput_event_get_tablet_event(ev);
double x, y;
switch (libinput_event_get_type(ev)) { switch (libinput_event_get_type(ev)) {
case LIBINPUT_EVENT_TABLET_PROXIMITY: case LIBINPUT_EVENT_TABLET_PROXIMITY:
@ -591,6 +608,10 @@ handle_event_tablet(struct libinput_event *ev, struct window *w)
LIBINPUT_TOOL_PROXIMITY_OUT) { LIBINPUT_TOOL_PROXIMITY_OUT) {
w->tool.x_in = 0; w->tool.x_in = 0;
w->tool.y_in = 0; w->tool.y_in = 0;
w->tool.x_down = 0;
w->tool.y_down = 0;
w->tool.x_up = 0;
w->tool.y_up = 0;
} else { } else {
w->tool.x_in = libinput_event_tablet_get_x_transformed(t, w->tool.x_in = libinput_event_tablet_get_x_transformed(t,
w->width); w->width);
@ -612,6 +633,18 @@ handle_event_tablet(struct libinput_event *ev, struct window *w)
w->tool.tilt_y = libinput_event_tablet_get_axis_value(t, w->tool.tilt_y = libinput_event_tablet_get_axis_value(t,
LIBINPUT_TABLET_AXIS_TILT_Y); LIBINPUT_TABLET_AXIS_TILT_Y);
break; break;
case LIBINPUT_EVENT_TABLET_TIP:
x = libinput_event_tablet_get_x_transformed(t, w->width);
y = libinput_event_tablet_get_y_transformed(t, w->height);
if (libinput_event_tablet_get_tip_state(t) ==
LIBINPUT_TOOL_TIP_DOWN) {
w->tool.x_down = x;
w->tool.y_down = y;
} else {
w->tool.x_up = x;
w->tool.y_up = y;
}
break;
case LIBINPUT_EVENT_TABLET_BUTTON: case LIBINPUT_EVENT_TABLET_BUTTON:
break; break;
default: default:
@ -676,6 +709,7 @@ handle_event_libinput(GIOChannel *source, GIOCondition condition, gpointer data)
break; break;
case LIBINPUT_EVENT_TABLET_AXIS: case LIBINPUT_EVENT_TABLET_AXIS:
case LIBINPUT_EVENT_TABLET_PROXIMITY: case LIBINPUT_EVENT_TABLET_PROXIMITY:
case LIBINPUT_EVENT_TABLET_TIP:
case LIBINPUT_EVENT_TABLET_BUTTON: case LIBINPUT_EVENT_TABLET_BUTTON:
handle_event_tablet(ev, w); handle_event_tablet(ev, w);
break; break;