tablet: Handle button-events

Signed-off-by: Stephen Chandler Paul <thatslyude@gmail.com>
Reviewed-by: Peter Hutterer <peter.hutterer@who-t.net>
Reviewed-by: Hans de Goede <hdegoede@redhat.com>
This commit is contained in:
Stephen Chandler Paul 2014-06-10 23:14:41 -04:00
parent e5f7ec9d53
commit 5561e4502d
5 changed files with 233 additions and 3 deletions

View file

@ -31,6 +31,11 @@
#define tablet_unset_status(tablet_,s_) ((tablet_)->status &= ~(s_))
#define tablet_has_status(tablet_,s_) (!!((tablet_)->status & (s_)))
#define tablet_get_pressed_buttons(tablet_,field_) \
((tablet_)->button_state.field_ & ~((tablet_)->prev_button_state.field_))
#define tablet_get_released_buttons(tablet_,field_) \
((tablet_)->prev_button_state.field_ & ~((tablet_)->button_state.field_))
static void
tablet_process_absolute(struct tablet_dispatch *tablet,
struct evdev_device *device,
@ -110,6 +115,37 @@ tablet_check_notify_axes(struct tablet_dispatch *tablet,
}
}
static void
tablet_update_button(struct tablet_dispatch *tablet,
uint32_t evcode,
uint32_t enable)
{
uint32_t button, *flags;
/* XXX: This really depends on the expected buttons fitting in the mask */
if (evcode >= BTN_MISC && evcode <= BTN_TASK) {
flags = &tablet->button_state.pad_buttons;
button = evcode - BTN_MISC;
} else if (evcode >= BTN_TOUCH && evcode <= BTN_STYLUS2) {
flags = &tablet->button_state.stylus_buttons;
button = evcode - BTN_TOUCH;
} else {
log_info("Unhandled button %s (%#x)\n",
libevdev_event_code_get_name(EV_KEY, evcode), evcode);
return;
}
if (enable) {
(*flags) |= 1 << button;
tablet_set_status(tablet, TABLET_BUTTONS_PRESSED);
} else {
(*flags) &= ~(1 << button);
tablet_set_status(tablet, TABLET_BUTTONS_RELEASED);
}
assert(button < 32);
}
static void
tablet_process_key(struct tablet_dispatch *tablet,
struct evdev_device *device,
@ -128,7 +164,11 @@ tablet_process_key(struct tablet_dispatch *tablet,
/* These codes have an equivalent libinput_tool value */
tablet_update_tool(tablet, e->code, e->value);
break;
case BTN_TOUCH:
case BTN_STYLUS:
case BTN_STYLUS2:
default:
tablet_update_button(tablet, e->code, e->value);
break;
}
}
@ -186,12 +226,68 @@ tablet_notify_tool(struct tablet_dispatch *tablet,
tablet_notify_tool_update(base, time, new_tool);
}
static void
tablet_notify_button_mask(struct tablet_dispatch *tablet,
struct evdev_device *device,
uint32_t time,
uint32_t buttons,
uint32_t button_base,
enum libinput_button_state state)
{
struct libinput_device *base = &device->base;
int32_t num_button = 0;
while (buttons) {
int enabled;
num_button++;
enabled = (buttons & 1);
buttons >>= 1;
if (!enabled)
continue;
tablet_notify_button(base,
time,
num_button + button_base - 1,
state);
}
}
static void
tablet_notify_buttons(struct tablet_dispatch *tablet,
struct evdev_device *device,
uint32_t time,
enum libinput_button_state state)
{
uint32_t pad_buttons, stylus_buttons;
if (state == LIBINPUT_BUTTON_STATE_PRESSED) {
pad_buttons = tablet_get_pressed_buttons(tablet, pad_buttons);
stylus_buttons =
tablet_get_pressed_buttons(tablet, stylus_buttons);
} else {
pad_buttons = tablet_get_released_buttons(tablet, pad_buttons);
stylus_buttons =
tablet_get_released_buttons(tablet, stylus_buttons);
}
tablet_notify_button_mask(tablet, device, time,
pad_buttons, BTN_MISC, state);
tablet_notify_button_mask(tablet, device, time,
stylus_buttons, BTN_TOUCH, state);
}
static void
tablet_flush(struct tablet_dispatch *tablet,
struct evdev_device *device,
uint32_t time)
{
if (tablet_has_status(tablet, TABLET_TOOL_LEAVING_PROXIMITY)) {
/* Release all stylus buttons */
tablet->button_state.stylus_buttons = 0;
tablet_set_status(tablet, TABLET_BUTTONS_RELEASED);
/* FIXME: This behavior is not ideal and this memset should be
* removed */
memset(&tablet->changed_axes, 0, sizeof(tablet->changed_axes));
@ -210,10 +306,27 @@ tablet_flush(struct tablet_dispatch *tablet,
}
}
if (tablet_has_status(tablet, TABLET_BUTTONS_RELEASED)) {
tablet_notify_buttons(tablet, device, time,
LIBINPUT_BUTTON_STATE_RELEASED);
tablet_unset_status(tablet, TABLET_BUTTONS_RELEASED);
}
if (tablet_has_status(tablet, TABLET_BUTTONS_PRESSED)) {
tablet_notify_buttons(tablet, device, time,
LIBINPUT_BUTTON_STATE_PRESSED);
tablet_unset_status(tablet, TABLET_BUTTONS_PRESSED);
}
if (tablet_has_status(tablet, TABLET_TOOL_LEAVING_PROXIMITY)) {
tablet_notify_proximity_out(&device->base, time);
tablet_unset_status(tablet, TABLET_TOOL_LEAVING_PROXIMITY);
}
/* Update state */
memcpy(&tablet->prev_button_state,
&tablet->button_state,
sizeof(tablet->button_state));
}
static void

View file

@ -31,7 +31,14 @@ enum tablet_status {
TABLET_NONE = 0,
TABLET_AXES_UPDATED = 1 << 0,
TABLET_TOOL_UPDATED = 1 << 1,
TABLET_TOOL_LEAVING_PROXIMITY = 1 << 2
TABLET_TOOL_LEAVING_PROXIMITY = 1 << 2,
TABLET_BUTTONS_PRESSED = 1 << 3,
TABLET_BUTTONS_RELEASED = 1 << 4
};
struct button_state {
uint32_t pad_buttons; /* bitmask of evcode - BTN_MISC */
uint32_t stylus_buttons; /* bitmask of evcode - BTN_TOUCH */
};
struct tablet_dispatch {
@ -41,6 +48,9 @@ struct tablet_dispatch {
unsigned char changed_axes[NCHARS(LIBINPUT_TABLET_AXIS_CNT)];
double axes[LIBINPUT_TABLET_AXIS_CNT];
struct button_state button_state;
struct button_state prev_button_state;
enum libinput_tool_type current_tool_type;
uint32_t current_tool_serial;
};

View file

@ -219,6 +219,11 @@ tablet_notify_proximity_out(struct libinput_device *device,
uint32_t time);
void
tablet_notify_button(struct libinput_device *device,
uint32_t time,
int32_t button,
enum libinput_button_state state);
void
touch_notify_frame(struct libinput_device *device,
uint32_t time);
#endif /* LIBINPUT_PRIVATE_H */

View file

@ -82,6 +82,9 @@ struct libinput_event_touch {
struct libinput_event_tablet {
struct libinput_event base;
uint32_t button;
enum libinput_button_state state;
uint32_t seat_button_count;
uint32_t time;
double *axes;
unsigned char changed_axes[NCHARS(LIBINPUT_TABLET_AXIS_CNT)];
@ -202,6 +205,7 @@ libinput_event_get_pointer_event(struct libinput_event *event)
case LIBINPUT_EVENT_TABLET_AXIS:
case LIBINPUT_EVENT_TABLET_TOOL_UPDATE:
case LIBINPUT_EVENT_TABLET_PROXIMITY_OUT:
case LIBINPUT_EVENT_TABLET_BUTTON:
break;
}
@ -231,6 +235,7 @@ libinput_event_get_keyboard_event(struct libinput_event *event)
case LIBINPUT_EVENT_TABLET_AXIS:
case LIBINPUT_EVENT_TABLET_TOOL_UPDATE:
case LIBINPUT_EVENT_TABLET_PROXIMITY_OUT:
case LIBINPUT_EVENT_TABLET_BUTTON:
break;
}
@ -260,6 +265,7 @@ libinput_event_get_touch_event(struct libinput_event *event)
case LIBINPUT_EVENT_TABLET_AXIS:
case LIBINPUT_EVENT_TABLET_TOOL_UPDATE:
case LIBINPUT_EVENT_TABLET_PROXIMITY_OUT:
case LIBINPUT_EVENT_TABLET_BUTTON:
break;
}
@ -288,6 +294,7 @@ libinput_event_get_tablet_event(struct libinput_event *event)
case LIBINPUT_EVENT_TABLET_AXIS:
case LIBINPUT_EVENT_TABLET_TOOL_UPDATE:
case LIBINPUT_EVENT_TABLET_PROXIMITY_OUT:
case LIBINPUT_EVENT_TABLET_BUTTON:
return (struct libinput_event_tablet *) event;
}
@ -316,6 +323,7 @@ libinput_event_get_device_notify_event(struct libinput_event *event)
case LIBINPUT_EVENT_TABLET_AXIS:
case LIBINPUT_EVENT_TABLET_TOOL_UPDATE:
case LIBINPUT_EVENT_TABLET_PROXIMITY_OUT:
case LIBINPUT_EVENT_TABLET_BUTTON:
break;
}
@ -532,6 +540,24 @@ libinput_event_tablet_get_time(struct libinput_event_tablet *event)
return event->time;
}
LIBINPUT_EXPORT uint32_t
libinput_event_tablet_get_button(struct libinput_event_tablet *event)
{
return event->button;
}
LIBINPUT_EXPORT enum libinput_button_state
libinput_event_tablet_get_button_state(struct libinput_event_tablet *event)
{
return event->state;
}
LIBINPUT_EXPORT uint32_t
libinput_event_tablet_get_seat_button_count(struct libinput_event_tablet *event)
{
return event->seat_button_count;
}
LIBINPUT_EXPORT enum libinput_tool_type
libinput_tool_get_type(struct libinput_tool *tool)
{
@ -1223,6 +1249,35 @@ tablet_notify_proximity_out(struct libinput_device *device,
&proximity_out_update_event->base);
}
void
tablet_notify_button(struct libinput_device *device,
uint32_t time,
int32_t button,
enum libinput_button_state state)
{
struct libinput_event_tablet *button_event;
int32_t seat_button_count;
button_event = zalloc(sizeof *button_event);
if (!button_event)
return;
seat_button_count = update_seat_button_count(device->seat,
button,
state);
*button_event = (struct libinput_event_tablet) {
.time = time,
.button = button,
.state = state,
.seat_button_count = seat_button_count,
};
post_device_event(device,
LIBINPUT_EVENT_TABLET_BUTTON,
&button_event->base);
}
static void
libinput_post_event(struct libinput *libinput,
struct libinput_event *event)

View file

@ -269,7 +269,8 @@ enum libinput_event_type {
* was held down on the stylus are sent before the initial proximity out
* event.
*/
LIBINPUT_EVENT_TABLET_PROXIMITY_OUT
LIBINPUT_EVENT_TABLET_PROXIMITY_OUT,
LIBINPUT_EVENT_TABLET_BUTTON
};
struct libinput;
@ -299,7 +300,8 @@ struct libinput_event_touch;
*
* Tablet event representing an axis update, button press, or tool update. Valid
* event types for this event are @ref LIBINPUT_EVENT_TABLET_AXIS, @ref
* LIBINPUT_EVENT_TABLET_TOOL_UPDATE and @ref LIBINPUT_EVENT_TABLET_TOOL_UPDATE.
* LIBINPUT_EVENT_TABLET_TOOL_UPDATE, @ref LIBINPUT_EVENT_TABLET_TOOL_UPDATE and
* @ref LIBINPUT_EVENT_TABLET_BUTTON.
*/
struct libinput_event_tablet;
@ -932,6 +934,51 @@ libinput_event_tablet_get_y_transformed(struct libinput_event_tablet *event,
struct libinput_tool *
libinput_event_tablet_get_tool(struct libinput_event_tablet *event);
/**
* @ingroup event_tablet
*
* Return the button that triggered this event.
* For tablet events that are not of type LIBINPUT_EVENT_TABLET_BUTTON, this
* function returns 0.
*
* @note It is an application bug to call this function for events other than
* LIBINPUT_EVENT_TABLET_BUTTON.
*
* @param event The libinput tablet event
* @return the button triggering this event
*/
uint32_t
libinput_event_tablet_get_button(struct libinput_event_tablet *event);
/**
* @ingroup event_tablet
*
* Return the button state of the event.
*
* @note It is an application bug to call this function for events other than
* LIBINPUT_EVENT_TABLET_BUTTON.
*
* @param event The libinput tablet event
* @return the button state triggering this event
*/
enum libinput_button_state
libinput_event_tablet_get_button_state(struct libinput_event_tablet *event);
/**
* @ingroup event_tablet
*
* For the button of a LIBINPUT_EVENT_TABLET_BUTTON event, return the total
* number of buttons pressed on all devices on the associated seat after the
* the event was triggered.
*
" @note It is an application bug to call this function for events other than
* LIBINPUT_EVENT_TABLET_BUTTON. For other events, this function returns 0.
*
* @return the seat wide pressed button count for the key of this event
*/
uint32_t
libinput_event_tablet_get_seat_button_count(struct libinput_event_tablet *event);
/**
* @ingroup event_tablet
*