mirror of
https://gitlab.freedesktop.org/libinput/libinput.git
synced 2025-12-26 12:10:06 +01:00
Having a motion event that's sent right after the original proximity event just to give the values of each axis is somewhat redundant. Since we already include the values of each axis with each type of event, we may as well use the proximity event to give the client the starting values for each axis on the tablet. Signed-off-by: Stephen Chandler Paul <thatslyude@gmail.com> Reviewed-by: Peter Hutterer <peter.hutterer@who-t.net> Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
630 lines
17 KiB
C
630 lines
17 KiB
C
/*
|
|
* Copyright © 2014 Red Hat, Inc.
|
|
* Copyright © 2014 Stephen Chandler "Lyude" Paul
|
|
*
|
|
* Permission to use, copy, modify, distribute, and sell this software and
|
|
* its documentation for any purpose is hereby granted without fee, provided
|
|
* that the above copyright notice appear in all copies and that both that
|
|
* copyright notice and this permission notice appear in supporting
|
|
* documentation, and that the name of the copyright holders not be used in
|
|
* advertising or publicity pertaining to distribution of the software
|
|
* without specific, written prior permission. The copyright holders make
|
|
* no representations about the suitability of this software for any
|
|
* purpose. It is provided "as is" without express or implied warranty.
|
|
*
|
|
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
|
|
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
|
* FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
|
* SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
|
|
* RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
|
|
* CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
|
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
*/
|
|
#include "config.h"
|
|
#include "evdev-tablet.h"
|
|
|
|
#include <assert.h>
|
|
#include <stdbool.h>
|
|
#include <string.h>
|
|
|
|
#define tablet_set_status(tablet_,s_) (tablet_)->status |= (s_)
|
|
#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,
|
|
struct input_event *e,
|
|
uint32_t time)
|
|
{
|
|
enum libinput_tablet_axis axis;
|
|
|
|
switch (e->code) {
|
|
case ABS_X:
|
|
case ABS_Y:
|
|
case ABS_PRESSURE:
|
|
case ABS_TILT_X:
|
|
case ABS_TILT_Y:
|
|
case ABS_DISTANCE:
|
|
axis = evcode_to_axis(e->code);
|
|
if (axis == LIBINPUT_TABLET_AXIS_NONE) {
|
|
log_bug_libinput(device->base.seat->libinput,
|
|
"Invalid ABS event code %#x\n",
|
|
e->code);
|
|
break;
|
|
}
|
|
|
|
set_bit(tablet->changed_axes, axis);
|
|
tablet_set_status(tablet, TABLET_AXES_UPDATED);
|
|
break;
|
|
default:
|
|
log_info(device->base.seat->libinput,
|
|
"Unhandled ABS event code %#x\n", e->code);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void
|
|
tablet_mark_all_axes_changed(struct tablet_dispatch *tablet,
|
|
struct evdev_device *device)
|
|
{
|
|
enum libinput_tablet_axis a;
|
|
|
|
for (a = 0; a < LIBINPUT_TABLET_AXIS_CNT; a++) {
|
|
if (libevdev_has_event_code(device->evdev,
|
|
EV_ABS,
|
|
axis_to_evcode(a)))
|
|
set_bit(tablet->changed_axes, a);
|
|
}
|
|
|
|
tablet_set_status(tablet, TABLET_AXES_UPDATED);
|
|
}
|
|
|
|
static void
|
|
tablet_change_to_left_handed(struct evdev_device *device)
|
|
{
|
|
struct tablet_dispatch *tablet =
|
|
(struct tablet_dispatch*)device->dispatch;
|
|
|
|
if (device->left_handed.enabled == device->left_handed.want_enabled)
|
|
return;
|
|
|
|
if (!tablet_has_status(tablet, TABLET_TOOL_OUT_OF_PROXIMITY))
|
|
return;
|
|
|
|
device->left_handed.enabled = device->left_handed.want_enabled;
|
|
}
|
|
|
|
static void
|
|
tablet_update_tool(struct tablet_dispatch *tablet,
|
|
struct evdev_device *device,
|
|
enum libinput_tool_type tool,
|
|
bool enabled)
|
|
{
|
|
assert(tool != LIBINPUT_TOOL_NONE);
|
|
|
|
if (enabled) {
|
|
tablet->current_tool_type = tool;
|
|
tablet_mark_all_axes_changed(tablet, device);
|
|
tablet_set_status(tablet, TABLET_TOOL_ENTERING_PROXIMITY);
|
|
tablet_unset_status(tablet, TABLET_TOOL_OUT_OF_PROXIMITY);
|
|
}
|
|
else
|
|
tablet_set_status(tablet, TABLET_TOOL_LEAVING_PROXIMITY);
|
|
}
|
|
|
|
static inline double
|
|
normalize_pressure_or_dist(const struct input_absinfo * absinfo) {
|
|
double range = absinfo->maximum - absinfo->minimum;
|
|
double value = (absinfo->value - absinfo->minimum) / range;
|
|
|
|
return value;
|
|
}
|
|
|
|
static inline double
|
|
normalize_tilt(const struct input_absinfo * absinfo) {
|
|
double range = absinfo->maximum - absinfo->minimum;
|
|
double value = (absinfo->value - absinfo->minimum) / range;
|
|
|
|
/* Map to the (-1, 1) range */
|
|
return (value * 2) - 1;
|
|
}
|
|
|
|
static inline int32_t
|
|
invert_axis(const struct input_absinfo *absinfo)
|
|
{
|
|
return absinfo->maximum - (absinfo->value - absinfo->minimum);
|
|
}
|
|
|
|
static void
|
|
tablet_check_notify_axes(struct tablet_dispatch *tablet,
|
|
struct evdev_device *device,
|
|
uint32_t time,
|
|
struct libinput_tool *tool)
|
|
{
|
|
struct libinput_device *base = &device->base;
|
|
bool axis_update_needed = false;
|
|
int a;
|
|
|
|
for (a = 0; a < LIBINPUT_TABLET_AXIS_CNT; a++) {
|
|
const struct input_absinfo *absinfo;
|
|
|
|
if (!bit_is_set(tablet->changed_axes, a))
|
|
continue;
|
|
|
|
absinfo = libevdev_get_abs_info(device->evdev,
|
|
axis_to_evcode(a));
|
|
|
|
switch (a) {
|
|
case LIBINPUT_TABLET_AXIS_X:
|
|
case LIBINPUT_TABLET_AXIS_Y:
|
|
if (device->left_handed.enabled)
|
|
tablet->axes[a] = invert_axis(absinfo);
|
|
else
|
|
tablet->axes[a] = absinfo->value;
|
|
break;
|
|
case LIBINPUT_TABLET_AXIS_DISTANCE:
|
|
case LIBINPUT_TABLET_AXIS_PRESSURE:
|
|
tablet->axes[a] = normalize_pressure_or_dist(absinfo);
|
|
break;
|
|
case LIBINPUT_TABLET_AXIS_TILT_X:
|
|
case LIBINPUT_TABLET_AXIS_TILT_Y:
|
|
tablet->axes[a] = normalize_tilt(absinfo);
|
|
break;
|
|
default:
|
|
log_bug_libinput(device->base.seat->libinput,
|
|
"Invalid axis update: %d\n", a);
|
|
break;
|
|
}
|
|
|
|
axis_update_needed = true;
|
|
}
|
|
|
|
/* We need to make sure that we check that the tool is not out of
|
|
* proximity before we send any axis updates. This is because many
|
|
* tablets will send axis events with incorrect values if the tablet
|
|
* tool is close enough so that the tablet can partially detect that
|
|
* it's there, but can't properly receive any data from the tool. */
|
|
if (axis_update_needed &&
|
|
!tablet_has_status(tablet, TABLET_TOOL_OUT_OF_PROXIMITY) &&
|
|
!tablet_has_status(tablet, TABLET_TOOL_LEAVING_PROXIMITY)) {
|
|
if (tablet_has_status(tablet, TABLET_TOOL_ENTERING_PROXIMITY))
|
|
tablet_notify_proximity(&device->base,
|
|
time,
|
|
tool,
|
|
LIBINPUT_TOOL_PROXIMITY_IN,
|
|
tablet->changed_axes,
|
|
tablet->axes);
|
|
else
|
|
tablet_notify_axis(base,
|
|
time,
|
|
tool,
|
|
tablet->changed_axes,
|
|
tablet->axes);
|
|
}
|
|
|
|
memset(tablet->changed_axes, 0, sizeof(tablet->changed_axes));
|
|
}
|
|
|
|
static void
|
|
tablet_update_button(struct tablet_dispatch *tablet,
|
|
uint32_t evcode,
|
|
uint32_t enable)
|
|
{
|
|
uint32_t button, *mask;
|
|
|
|
/* XXX: This really depends on the expected buttons fitting in the mask */
|
|
if (evcode >= BTN_MISC && evcode <= BTN_TASK) {
|
|
return;
|
|
} else if (evcode >= BTN_TOUCH && evcode <= BTN_STYLUS2) {
|
|
mask = &tablet->button_state.stylus_buttons;
|
|
button = evcode - BTN_TOUCH;
|
|
} else {
|
|
log_info(tablet->device->base.seat->libinput,
|
|
"Unhandled button %s (%#x)\n",
|
|
libevdev_event_code_get_name(EV_KEY, evcode), evcode);
|
|
return;
|
|
}
|
|
|
|
assert(button < 32);
|
|
|
|
if (enable) {
|
|
(*mask) |= 1 << button;
|
|
tablet_set_status(tablet, TABLET_BUTTONS_PRESSED);
|
|
} else {
|
|
(*mask) &= ~(1 << button);
|
|
tablet_set_status(tablet, TABLET_BUTTONS_RELEASED);
|
|
}
|
|
}
|
|
|
|
static void
|
|
tablet_process_key(struct tablet_dispatch *tablet,
|
|
struct evdev_device *device,
|
|
struct input_event *e,
|
|
uint32_t time)
|
|
{
|
|
switch (e->code) {
|
|
case BTN_TOOL_PEN:
|
|
case BTN_TOOL_RUBBER:
|
|
case BTN_TOOL_BRUSH:
|
|
case BTN_TOOL_PENCIL:
|
|
case BTN_TOOL_AIRBRUSH:
|
|
case BTN_TOOL_FINGER:
|
|
case BTN_TOOL_MOUSE:
|
|
case BTN_TOOL_LENS:
|
|
/* These codes have an equivalent libinput_tool value */
|
|
tablet_update_tool(tablet, device, e->code, e->value);
|
|
break;
|
|
case BTN_TOUCH:
|
|
if (e->value)
|
|
tablet_set_status(tablet, TABLET_STYLUS_IN_CONTACT);
|
|
else
|
|
tablet_unset_status(tablet, TABLET_STYLUS_IN_CONTACT);
|
|
|
|
/* Fall through */
|
|
case BTN_STYLUS:
|
|
case BTN_STYLUS2:
|
|
default:
|
|
tablet_update_button(tablet, e->code, e->value);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void
|
|
tablet_process_misc(struct tablet_dispatch *tablet,
|
|
struct evdev_device *device,
|
|
struct input_event *e,
|
|
uint32_t time)
|
|
{
|
|
switch (e->code) {
|
|
case MSC_SERIAL:
|
|
if (e->value != -1)
|
|
tablet->current_tool_serial = e->value;
|
|
|
|
break;
|
|
default:
|
|
log_info(device->base.seat->libinput,
|
|
"Unhandled MSC event code %s (%#x)\n",
|
|
libevdev_event_code_get_name(EV_MSC, e->code),
|
|
e->code);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static struct libinput_tool *
|
|
tablet_get_tool(struct tablet_dispatch *tablet,
|
|
enum libinput_tool_type type,
|
|
uint32_t serial)
|
|
{
|
|
struct libinput_tool *tool = NULL, *t;
|
|
struct list *tool_list;
|
|
|
|
if (serial) {
|
|
tool_list = &tablet->device->base.seat->libinput->tool_list;
|
|
|
|
/* Check if we already have the tool in our list of tools */
|
|
list_for_each(t, tool_list, link) {
|
|
if (type == t->type && serial == t->serial) {
|
|
tool = t;
|
|
break;
|
|
}
|
|
}
|
|
} else {
|
|
/* We can't guarantee that tools without serial numbers are
|
|
* unique, so we keep them local to the tablet that they come
|
|
* into proximity of instead of storing them in the global tool
|
|
* list */
|
|
tool_list = &tablet->tool_list;
|
|
|
|
/* Same as above, but don't bother checking the serial number */
|
|
list_for_each(t, tool_list, link) {
|
|
if (type == t->type) {
|
|
tool = t;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* If we didn't already have the new_tool in our list of tools,
|
|
* add it */
|
|
if (!tool) {
|
|
tool = zalloc(sizeof *tool);
|
|
*tool = (struct libinput_tool) {
|
|
.type = type,
|
|
.serial = serial,
|
|
.refcount = 1,
|
|
};
|
|
|
|
/* Determine the axis capabilities of the tool. Here's a break
|
|
* down of the heuristics used here:
|
|
* - The Wacom art pen supports all of the extra axes, along
|
|
* with rotation
|
|
* - All of normal pens and the airbrush support all of the
|
|
* extra axes if the tablet can report them
|
|
* - All of the mouse like devices don't really report any of
|
|
* the extra axes except for rotation.
|
|
* (as of writing this comment, rotation isn't supported, so you
|
|
* won't see the mouse or art pen here)
|
|
*/
|
|
switch (type) {
|
|
case LIBINPUT_TOOL_PEN:
|
|
case LIBINPUT_TOOL_ERASER:
|
|
case LIBINPUT_TOOL_PENCIL:
|
|
case LIBINPUT_TOOL_BRUSH:
|
|
case LIBINPUT_TOOL_AIRBRUSH:
|
|
if (bit_is_set(tablet->axis_caps,
|
|
LIBINPUT_TABLET_AXIS_PRESSURE))
|
|
set_bit(tool->axis_caps,
|
|
LIBINPUT_TABLET_AXIS_PRESSURE);
|
|
if (bit_is_set(tablet->axis_caps,
|
|
LIBINPUT_TABLET_AXIS_DISTANCE))
|
|
set_bit(tool->axis_caps,
|
|
LIBINPUT_TABLET_AXIS_DISTANCE);
|
|
if (bit_is_set(tablet->axis_caps,
|
|
LIBINPUT_TABLET_AXIS_TILT_X))
|
|
set_bit(tool->axis_caps,
|
|
LIBINPUT_TABLET_AXIS_TILT_X);
|
|
if (bit_is_set(tablet->axis_caps,
|
|
LIBINPUT_TABLET_AXIS_TILT_Y))
|
|
set_bit(tool->axis_caps,
|
|
LIBINPUT_TABLET_AXIS_TILT_Y);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
list_insert(tool_list, &tool->link);
|
|
}
|
|
|
|
return tool;
|
|
}
|
|
|
|
static void
|
|
tablet_notify_button_mask(struct tablet_dispatch *tablet,
|
|
struct evdev_device *device,
|
|
uint32_t time,
|
|
struct libinput_tool *tool,
|
|
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,
|
|
tool,
|
|
tablet->axes,
|
|
num_button + button_base - 1,
|
|
state);
|
|
}
|
|
}
|
|
|
|
static void
|
|
tablet_notify_buttons(struct tablet_dispatch *tablet,
|
|
struct evdev_device *device,
|
|
uint32_t time,
|
|
struct libinput_tool *tool,
|
|
enum libinput_button_state state)
|
|
{
|
|
uint32_t stylus_buttons;
|
|
|
|
if (state == LIBINPUT_BUTTON_STATE_PRESSED)
|
|
stylus_buttons =
|
|
tablet_get_pressed_buttons(tablet, stylus_buttons);
|
|
else
|
|
stylus_buttons =
|
|
tablet_get_released_buttons(tablet, stylus_buttons);
|
|
|
|
tablet_notify_button_mask(tablet,
|
|
device,
|
|
time,
|
|
tool,
|
|
stylus_buttons,
|
|
BTN_TOUCH,
|
|
state);
|
|
}
|
|
|
|
static void
|
|
sanitize_tablet_axes(struct tablet_dispatch *tablet)
|
|
{
|
|
const struct input_absinfo *distance,
|
|
*pressure;
|
|
|
|
distance = libevdev_get_abs_info(tablet->device->evdev, ABS_DISTANCE);
|
|
pressure = libevdev_get_abs_info(tablet->device->evdev, ABS_PRESSURE);
|
|
|
|
/* Keep distance and pressure mutually exclusive */
|
|
if (bit_is_set(tablet->changed_axes, LIBINPUT_TABLET_AXIS_DISTANCE) &&
|
|
distance->value > distance->minimum &&
|
|
pressure->value > pressure->minimum) {
|
|
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_STYLUS_IN_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,
|
|
LIBINPUT_TABLET_AXIS_PRESSURE);
|
|
else
|
|
tablet->axes[LIBINPUT_TABLET_AXIS_PRESSURE] = 0;
|
|
}
|
|
}
|
|
|
|
static void
|
|
tablet_flush(struct tablet_dispatch *tablet,
|
|
struct evdev_device *device,
|
|
uint32_t time)
|
|
{
|
|
struct libinput_tool *tool =
|
|
tablet_get_tool(tablet,
|
|
tablet->current_tool_type,
|
|
tablet->current_tool_serial);
|
|
|
|
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);
|
|
} else if (tablet_has_status(tablet, TABLET_AXES_UPDATED) ||
|
|
tablet_has_status(tablet, TABLET_TOOL_ENTERING_PROXIMITY)) {
|
|
sanitize_tablet_axes(tablet);
|
|
tablet_check_notify_axes(tablet, device, time, tool);
|
|
|
|
tablet_unset_status(tablet, TABLET_TOOL_ENTERING_PROXIMITY);
|
|
tablet_unset_status(tablet, TABLET_AXES_UPDATED);
|
|
}
|
|
|
|
if (tablet_has_status(tablet, TABLET_BUTTONS_RELEASED)) {
|
|
tablet_notify_buttons(tablet,
|
|
device,
|
|
time,
|
|
tool,
|
|
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,
|
|
tool,
|
|
LIBINPUT_BUTTON_STATE_PRESSED);
|
|
tablet_unset_status(tablet, TABLET_BUTTONS_PRESSED);
|
|
}
|
|
|
|
if (tablet_has_status(tablet, TABLET_TOOL_LEAVING_PROXIMITY)) {
|
|
tablet_notify_proximity(&device->base,
|
|
time,
|
|
tool,
|
|
LIBINPUT_TOOL_PROXIMITY_OUT,
|
|
tablet->changed_axes,
|
|
tablet->axes);
|
|
|
|
tablet_set_status(tablet, TABLET_TOOL_OUT_OF_PROXIMITY);
|
|
tablet_unset_status(tablet, TABLET_TOOL_LEAVING_PROXIMITY);
|
|
memset(tablet->changed_axes, 0, sizeof(tablet->changed_axes));
|
|
|
|
tablet_change_to_left_handed(device);
|
|
}
|
|
|
|
/* Update state */
|
|
memcpy(&tablet->prev_button_state,
|
|
&tablet->button_state,
|
|
sizeof(tablet->button_state));
|
|
}
|
|
|
|
static void
|
|
tablet_process(struct evdev_dispatch *dispatch,
|
|
struct evdev_device *device,
|
|
struct input_event *e,
|
|
uint64_t time)
|
|
{
|
|
struct tablet_dispatch *tablet =
|
|
(struct tablet_dispatch *)dispatch;
|
|
|
|
switch (e->type) {
|
|
case EV_ABS:
|
|
tablet_process_absolute(tablet, device, e, time);
|
|
break;
|
|
case EV_KEY:
|
|
tablet_process_key(tablet, device, e, time);
|
|
break;
|
|
case EV_MSC:
|
|
tablet_process_misc(tablet, device, e, time);
|
|
break;
|
|
case EV_SYN:
|
|
tablet_flush(tablet, device, time);
|
|
break;
|
|
default:
|
|
log_error(device->base.seat->libinput,
|
|
"Unexpected event type %s (%#x)\n",
|
|
libevdev_event_type_get_name(e->type),
|
|
e->type);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void
|
|
tablet_destroy(struct evdev_dispatch *dispatch)
|
|
{
|
|
struct tablet_dispatch *tablet =
|
|
(struct tablet_dispatch*)dispatch;
|
|
struct libinput_tool *tool, *tmp;
|
|
|
|
list_for_each_safe(tool, tmp, &tablet->tool_list, link) {
|
|
libinput_tool_unref(tool);
|
|
}
|
|
|
|
free(tablet);
|
|
}
|
|
|
|
static struct evdev_dispatch_interface tablet_interface = {
|
|
tablet_process,
|
|
NULL, /* remove */
|
|
tablet_destroy,
|
|
NULL, /* device_added */
|
|
NULL, /* device_removed */
|
|
NULL, /* device_suspended */
|
|
NULL, /* device_resumed */
|
|
NULL, /* tag_device */
|
|
};
|
|
|
|
static int
|
|
tablet_init(struct tablet_dispatch *tablet,
|
|
struct evdev_device *device)
|
|
{
|
|
enum libinput_tablet_axis axis;
|
|
|
|
tablet->base.interface = &tablet_interface;
|
|
tablet->device = device;
|
|
tablet->status = TABLET_NONE;
|
|
tablet->current_tool_type = LIBINPUT_TOOL_NONE;
|
|
list_init(&tablet->tool_list);
|
|
|
|
for (axis = 0; axis < LIBINPUT_TABLET_AXIS_CNT; axis++) {
|
|
if (libevdev_has_event_code(device->evdev,
|
|
EV_ABS,
|
|
axis_to_evcode(axis)))
|
|
set_bit(tablet->axis_caps, axis);
|
|
}
|
|
|
|
tablet_mark_all_axes_changed(tablet, device);
|
|
|
|
tablet_set_status(tablet, TABLET_TOOL_OUT_OF_PROXIMITY);
|
|
|
|
return 0;
|
|
}
|
|
|
|
struct evdev_dispatch *
|
|
evdev_tablet_create(struct evdev_device *device)
|
|
{
|
|
struct tablet_dispatch *tablet;
|
|
|
|
tablet = zalloc(sizeof *tablet);
|
|
if (!tablet)
|
|
return NULL;
|
|
|
|
if (tablet_init(tablet, device) != 0) {
|
|
tablet_destroy(&tablet->base);
|
|
return NULL;
|
|
}
|
|
|
|
evdev_init_left_handed(device, tablet_change_to_left_handed);
|
|
|
|
return &tablet->base;
|
|
}
|