|
|
|
|
@@ -1,5 +1,5 @@
|
|
|
|
|
/*
|
|
|
|
|
* Copyright © 2013-2015 Red Hat, Inc.
|
|
|
|
|
* Copyright © 2013-2017 Red Hat, Inc.
|
|
|
|
|
*
|
|
|
|
|
* Permission to use, copy, modify, distribute, and sell this software
|
|
|
|
|
* and its documentation for any purpose is hereby granted without
|
|
|
|
|
@@ -65,6 +65,9 @@
|
|
|
|
|
#define TOUCH_MAX_SLOTS 15
|
|
|
|
|
#define XORG_KEYCODE_OFFSET 8
|
|
|
|
|
|
|
|
|
|
#define streq(a, b) (strcmp(a, b) == 0)
|
|
|
|
|
#define strneq(a, b, n) (strncmp(a, b, n) == 0)
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
libinput does not provide axis information for absolute devices, instead
|
|
|
|
|
it scales into the screen dimensions provided. So we set up the axes with
|
|
|
|
|
@@ -209,6 +212,10 @@ update_mode_prop(InputInfoPtr pInfo,
|
|
|
|
|
static enum event_handling
|
|
|
|
|
xf86libinput_handle_event(struct libinput_event *event);
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
xf86libinput_post_tablet_motion(InputInfoPtr pInfo,
|
|
|
|
|
struct libinput_event_tablet_tool *event);
|
|
|
|
|
|
|
|
|
|
static inline int
|
|
|
|
|
use_server_fd(const InputInfoPtr pInfo) {
|
|
|
|
|
return pInfo->fd > -1 && (pInfo->flags & XI86_SERVER_FD);
|
|
|
|
|
@@ -259,7 +266,7 @@ xf86libinput_is_subdevice(InputInfoPtr pInfo)
|
|
|
|
|
BOOL is_subdevice;
|
|
|
|
|
|
|
|
|
|
source = xf86SetStrOption(pInfo->options, "_source", "");
|
|
|
|
|
is_subdevice = strcmp(source, "_driver/libinput") == 0;
|
|
|
|
|
is_subdevice = streq(source, "_driver/libinput");
|
|
|
|
|
free(source);
|
|
|
|
|
|
|
|
|
|
return is_subdevice;
|
|
|
|
|
@@ -1213,7 +1220,7 @@ is_libinput_device(InputInfoPtr pInfo)
|
|
|
|
|
BOOL rc;
|
|
|
|
|
|
|
|
|
|
driver = xf86CheckStrOption(pInfo->options, "driver", "");
|
|
|
|
|
rc = strcmp(driver, "libinput") == 0;
|
|
|
|
|
rc = streq(driver, "libinput");
|
|
|
|
|
free(driver);
|
|
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
|
@@ -1713,12 +1720,15 @@ static enum event_handling
|
|
|
|
|
xf86libinput_handle_tablet_tip(InputInfoPtr pInfo,
|
|
|
|
|
struct libinput_event_tablet_tool *event)
|
|
|
|
|
{
|
|
|
|
|
DeviceIntPtr pDev = pInfo->dev;
|
|
|
|
|
enum libinput_tablet_tool_tip_state state;
|
|
|
|
|
const BOOL is_absolute = TRUE;
|
|
|
|
|
|
|
|
|
|
if (xf86libinput_tool_queue_event(event))
|
|
|
|
|
return EVENT_QUEUED;
|
|
|
|
|
|
|
|
|
|
xf86libinput_post_tablet_motion(pDev->public.devicePrivate, event);
|
|
|
|
|
|
|
|
|
|
state = libinput_event_tablet_tool_get_tip_state(event);
|
|
|
|
|
|
|
|
|
|
xf86PostButtonEventP(pInfo->dev,
|
|
|
|
|
@@ -1773,8 +1783,8 @@ xf86libinput_apply_area(InputInfoPtr pInfo, double *x, double *y)
|
|
|
|
|
*y = sy;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static enum event_handling
|
|
|
|
|
xf86libinput_handle_tablet_axis(InputInfoPtr pInfo,
|
|
|
|
|
static void
|
|
|
|
|
xf86libinput_post_tablet_motion(InputInfoPtr pInfo,
|
|
|
|
|
struct libinput_event_tablet_tool *event)
|
|
|
|
|
{
|
|
|
|
|
DeviceIntPtr dev = pInfo->dev;
|
|
|
|
|
@@ -1784,9 +1794,6 @@ xf86libinput_handle_tablet_axis(InputInfoPtr pInfo,
|
|
|
|
|
double value;
|
|
|
|
|
double x, y;
|
|
|
|
|
|
|
|
|
|
if (xf86libinput_tool_queue_event(event))
|
|
|
|
|
return EVENT_QUEUED;
|
|
|
|
|
|
|
|
|
|
x = libinput_event_tablet_tool_get_x_transformed(event,
|
|
|
|
|
TABLET_AXIS_MAX);
|
|
|
|
|
y = libinput_event_tablet_tool_get_y_transformed(event,
|
|
|
|
|
@@ -1836,13 +1843,23 @@ xf86libinput_handle_tablet_axis(InputInfoPtr pInfo,
|
|
|
|
|
default:
|
|
|
|
|
xf86IDrvMsg(pInfo, X_ERROR,
|
|
|
|
|
"Invalid rotation axis on tool\n");
|
|
|
|
|
return EVENT_HANDLED;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
valuator_mask_set_double(mask, valuator, value);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
xf86PostMotionEventM(dev, Absolute, mask);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static enum event_handling
|
|
|
|
|
xf86libinput_handle_tablet_axis(InputInfoPtr pInfo,
|
|
|
|
|
struct libinput_event_tablet_tool *event)
|
|
|
|
|
{
|
|
|
|
|
if (xf86libinput_tool_queue_event(event))
|
|
|
|
|
return EVENT_QUEUED;
|
|
|
|
|
|
|
|
|
|
xf86libinput_post_tablet_motion(pInfo, event);
|
|
|
|
|
|
|
|
|
|
return EVENT_HANDLED;
|
|
|
|
|
}
|
|
|
|
|
@@ -1974,6 +1991,13 @@ xf86libinput_handle_tablet_proximity(InputInfoPtr pInfo,
|
|
|
|
|
|
|
|
|
|
xf86PostProximityEventM(pDev, in_prox, mask);
|
|
|
|
|
|
|
|
|
|
/* We have to send an extra motion event after proximity to make
|
|
|
|
|
* sure the client got the updated x/y coordinates, especially if
|
|
|
|
|
* they don't handle proximity events (XI2).
|
|
|
|
|
*/
|
|
|
|
|
if (in_prox)
|
|
|
|
|
xf86libinput_post_tablet_motion(pDev->public.devicePrivate, event);
|
|
|
|
|
|
|
|
|
|
return EVENT_HANDLED;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -2184,10 +2208,16 @@ open_restricted(const char *path, int flags, void *data)
|
|
|
|
|
InputInfoPtr pInfo;
|
|
|
|
|
int fd = -1;
|
|
|
|
|
|
|
|
|
|
/* Special handling for sysfs files (used for pad LEDs) */
|
|
|
|
|
if (strneq(path, "/sys/", 5)) {
|
|
|
|
|
fd = open(path, flags);
|
|
|
|
|
return fd < 0 ? -errno : fd;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
nt_list_for_each_entry(pInfo, xf86FirstLocalDevice(), next) {
|
|
|
|
|
char *device = xf86CheckStrOption(pInfo->options, "Device", NULL);
|
|
|
|
|
|
|
|
|
|
if (device != NULL && strcmp(path, device) == 0) {
|
|
|
|
|
if (device != NULL && streq(path, device)) {
|
|
|
|
|
free(device);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
@@ -2353,9 +2383,9 @@ xf86libinput_parse_tap_buttonmap_option(InputInfoPtr pInfo,
|
|
|
|
|
"TappingButtonMap",
|
|
|
|
|
NULL);
|
|
|
|
|
if (str) {
|
|
|
|
|
if (strcmp(str, "lmr") == 0)
|
|
|
|
|
if (streq(str, "lmr"))
|
|
|
|
|
map = LIBINPUT_CONFIG_TAP_MAP_LMR;
|
|
|
|
|
else if (strcmp(str, "lrm") == 0)
|
|
|
|
|
else if (streq(str, "lrm"))
|
|
|
|
|
map = LIBINPUT_CONFIG_TAP_MAP_LRM;
|
|
|
|
|
else
|
|
|
|
|
xf86IDrvMsg(pInfo, X_ERROR,
|
|
|
|
|
@@ -2468,11 +2498,11 @@ xf86libinput_parse_sendevents_option(InputInfoPtr pInfo,
|
|
|
|
|
"SendEventsMode",
|
|
|
|
|
NULL);
|
|
|
|
|
if (modestr) {
|
|
|
|
|
if (strcmp(modestr, "enabled") == 0)
|
|
|
|
|
if (streq(modestr, "enabled"))
|
|
|
|
|
mode = LIBINPUT_CONFIG_SEND_EVENTS_ENABLED;
|
|
|
|
|
else if (strcmp(modestr, "disabled") == 0)
|
|
|
|
|
else if (streq(modestr, "disabled"))
|
|
|
|
|
mode = LIBINPUT_CONFIG_SEND_EVENTS_DISABLED;
|
|
|
|
|
else if (strcmp(modestr, "disabled-on-external-mouse") == 0)
|
|
|
|
|
else if (streq(modestr, "disabled-on-external-mouse"))
|
|
|
|
|
mode = LIBINPUT_CONFIG_SEND_EVENTS_DISABLED_ON_EXTERNAL_MOUSE;
|
|
|
|
|
else
|
|
|
|
|
xf86IDrvMsg(pInfo, X_ERROR,
|
|
|
|
|
@@ -2866,7 +2896,7 @@ xf86libinput_parse_tablet_area_option(InputInfoPtr pInfo,
|
|
|
|
|
str = xf86SetStrOption(pInfo->options,
|
|
|
|
|
"TabletToolAreaRatio",
|
|
|
|
|
NULL);
|
|
|
|
|
if (!str || strcmp(str, "default") == 0)
|
|
|
|
|
if (!str || streq(str, "default"))
|
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
|
|
rc = sscanf(str, "%d:%d", &area.x, &area.y);
|
|
|
|
|
@@ -3386,17 +3416,43 @@ static Atom prop_float;
|
|
|
|
|
static Atom prop_device;
|
|
|
|
|
static Atom prop_product_id;
|
|
|
|
|
|
|
|
|
|
static inline void
|
|
|
|
|
update_mode_prop(InputInfoPtr pInfo,
|
|
|
|
|
struct libinput_event_tablet_pad *event)
|
|
|
|
|
{
|
|
|
|
|
struct xf86libinput *driver_data = pInfo->private;
|
|
|
|
|
struct mode_prop_state {
|
|
|
|
|
int deviceid;
|
|
|
|
|
InputInfoPtr pInfo;
|
|
|
|
|
|
|
|
|
|
struct libinput_tablet_pad_mode_group *group;
|
|
|
|
|
unsigned int mode;
|
|
|
|
|
unsigned int idx;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static Bool
|
|
|
|
|
update_mode_prop_cb(ClientPtr client, pointer closure)
|
|
|
|
|
{
|
|
|
|
|
struct mode_prop_state *state = closure;
|
|
|
|
|
InputInfoPtr pInfo = state->pInfo, tmp;
|
|
|
|
|
struct xf86libinput *driver_data = pInfo->private;
|
|
|
|
|
BOOL found = FALSE;
|
|
|
|
|
XIPropertyValuePtr val;
|
|
|
|
|
int rc;
|
|
|
|
|
unsigned char groups[4] = {0};
|
|
|
|
|
struct libinput_tablet_pad_mode_group *group = state->group;
|
|
|
|
|
unsigned int mode = state->mode;
|
|
|
|
|
unsigned int idx = state->idx;
|
|
|
|
|
|
|
|
|
|
if (idx >= ARRAY_SIZE(groups))
|
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
|
|
/* The device may have gotten removed before the WorkProc was
|
|
|
|
|
* scheduled. X reuses deviceids, but if the pointer value and
|
|
|
|
|
* device ID are what we had before, we're good */
|
|
|
|
|
nt_list_for_each_entry(tmp, xf86FirstLocalDevice(), next) {
|
|
|
|
|
if (tmp->dev->id == state->deviceid && tmp == pInfo) {
|
|
|
|
|
found = TRUE;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (!found)
|
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
|
|
rc = XIGetDeviceProperty(pInfo->dev,
|
|
|
|
|
prop_mode_groups,
|
|
|
|
|
@@ -3404,18 +3460,12 @@ update_mode_prop(InputInfoPtr pInfo,
|
|
|
|
|
if (rc != Success ||
|
|
|
|
|
val->format != 8 ||
|
|
|
|
|
val->size <= 0)
|
|
|
|
|
return;
|
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
|
|
memcpy(groups, (unsigned char*)val->data, val->size);
|
|
|
|
|
|
|
|
|
|
group = libinput_event_tablet_pad_get_mode_group(event);
|
|
|
|
|
mode = libinput_event_tablet_pad_get_mode(event);
|
|
|
|
|
idx = libinput_tablet_pad_mode_group_get_index(group);
|
|
|
|
|
if (idx >= ARRAY_SIZE(groups))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (groups[idx] == mode)
|
|
|
|
|
return;
|
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
|
|
groups[idx] = mode;
|
|
|
|
|
|
|
|
|
|
@@ -3428,8 +3478,36 @@ update_mode_prop(InputInfoPtr pInfo,
|
|
|
|
|
groups,
|
|
|
|
|
TRUE);
|
|
|
|
|
driver_data->allow_mode_group_updates = false;
|
|
|
|
|
if (rc != Success)
|
|
|
|
|
|
|
|
|
|
out:
|
|
|
|
|
libinput_tablet_pad_mode_group_unref(group);
|
|
|
|
|
free(state);
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline void
|
|
|
|
|
update_mode_prop(InputInfoPtr pInfo,
|
|
|
|
|
struct libinput_event_tablet_pad *event)
|
|
|
|
|
{
|
|
|
|
|
struct libinput_tablet_pad_mode_group *group;
|
|
|
|
|
struct mode_prop_state *state;
|
|
|
|
|
|
|
|
|
|
state = calloc(1, sizeof(*state));
|
|
|
|
|
if (!state)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
state->deviceid = pInfo->dev->id;
|
|
|
|
|
state->pInfo = pInfo;
|
|
|
|
|
|
|
|
|
|
group = libinput_event_tablet_pad_get_mode_group(event);
|
|
|
|
|
|
|
|
|
|
state->group = libinput_tablet_pad_mode_group_ref(group);
|
|
|
|
|
state->mode = libinput_event_tablet_pad_get_mode(event);
|
|
|
|
|
state->idx = libinput_tablet_pad_mode_group_get_index(group);
|
|
|
|
|
|
|
|
|
|
/* Schedule a WorkProc so we don't update from within the input
|
|
|
|
|
thread */
|
|
|
|
|
QueueWorkProc(update_mode_prop_cb, serverClient, state);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline BOOL
|
|
|
|
|
@@ -5160,6 +5238,19 @@ LibinputInitTabletAreaRatioProperty(DeviceIntPtr dev,
|
|
|
|
|
2, data);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline bool
|
|
|
|
|
subdevice_filter_for_capabilities(DeviceIntPtr dev,
|
|
|
|
|
uint32_t capabilities)
|
|
|
|
|
{
|
|
|
|
|
InputInfoPtr pInfo = dev->public.devicePrivate;
|
|
|
|
|
struct xf86libinput *driver_data = pInfo->private;
|
|
|
|
|
|
|
|
|
|
if (!xf86libinput_is_subdevice(pInfo))
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
return !(driver_data->capabilities & capabilities);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
LibinputInitProperty(DeviceIntPtr dev)
|
|
|
|
|
{
|
|
|
|
|
@@ -5172,21 +5263,35 @@ LibinputInitProperty(DeviceIntPtr dev)
|
|
|
|
|
|
|
|
|
|
prop_float = XIGetKnownProperty("FLOAT");
|
|
|
|
|
|
|
|
|
|
LibinputInitTapProperty(dev, driver_data, device);
|
|
|
|
|
LibinputInitTapDragProperty(dev, driver_data, device);
|
|
|
|
|
LibinputInitTapDragLockProperty(dev, driver_data, device);
|
|
|
|
|
LibinputInitTapButtonmapProperty(dev, driver_data, device);
|
|
|
|
|
LibinputInitCalibrationProperty(dev, driver_data, device);
|
|
|
|
|
LibinputInitAccelProperty(dev, driver_data, device);
|
|
|
|
|
LibinputInitNaturalScrollProperty(dev, driver_data, device);
|
|
|
|
|
/* On a subdevice, we likely only have a keyboard, so filter out the
|
|
|
|
|
* properties for the capabilities we don't have */
|
|
|
|
|
if (!subdevice_filter_for_capabilities(dev, CAP_POINTER|CAP_TOUCH)) {
|
|
|
|
|
LibinputInitTapProperty(dev, driver_data, device);
|
|
|
|
|
LibinputInitTapDragProperty(dev, driver_data, device);
|
|
|
|
|
LibinputInitTapDragLockProperty(dev, driver_data, device);
|
|
|
|
|
LibinputInitTapButtonmapProperty(dev, driver_data, device);
|
|
|
|
|
LibinputInitNaturalScrollProperty(dev, driver_data, device);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!subdevice_filter_for_capabilities(dev, CAP_TOUCH|CAP_TABLET)) {
|
|
|
|
|
LibinputInitCalibrationProperty(dev, driver_data, device);
|
|
|
|
|
LibinputInitLeftHandedProperty(dev, driver_data, device);
|
|
|
|
|
LibinputInitAccelProperty(dev, driver_data, device);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!subdevice_filter_for_capabilities(dev, CAP_POINTER)) {
|
|
|
|
|
LibinputInitScrollMethodsProperty(dev, driver_data, device);
|
|
|
|
|
LibinputInitClickMethodsProperty(dev, driver_data, device);
|
|
|
|
|
LibinputInitMiddleEmulationProperty(dev, driver_data, device);
|
|
|
|
|
LibinputInitRotationAngleProperty(dev, driver_data, device);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!subdevice_filter_for_capabilities(dev, CAP_TABLET_PAD)) {
|
|
|
|
|
LibinputInitModeGroupProperties(dev, driver_data, device);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
LibinputInitSendEventsProperty(dev, driver_data, device);
|
|
|
|
|
LibinputInitLeftHandedProperty(dev, driver_data, device);
|
|
|
|
|
LibinputInitScrollMethodsProperty(dev, driver_data, device);
|
|
|
|
|
LibinputInitClickMethodsProperty(dev, driver_data, device);
|
|
|
|
|
LibinputInitMiddleEmulationProperty(dev, driver_data, device);
|
|
|
|
|
LibinputInitDisableWhileTypingProperty(dev, driver_data, device);
|
|
|
|
|
LibinputInitModeGroupProperties(dev, driver_data, device);
|
|
|
|
|
LibinputInitRotationAngleProperty(dev, driver_data, device);
|
|
|
|
|
|
|
|
|
|
/* Device node property, read-only */
|
|
|
|
|
device_node = driver_data->path;
|
|
|
|
|
|