mirror of
https://gitlab.freedesktop.org/libinput/libinput.git
synced 2026-01-06 20:00:13 +01:00
Add a new dispatch interface for the Dell Canvas Totem
This device looks similar to a MT device on the kernel side, but it's not a MT device and it's not quite a tablet either. It uses slots to track up to 4 totems off the same device and the only hint that it's not a MT device is that it sends ABS_MT_TOOL_TYPE / MT_TOOL_DIAL. udev thinks it's a touchscreen and a tablet but we currently init those devices as touchscreen (because all wacom tablet touch devices are udev tablets+tochscreens). So we need a quirk to hook onto this device. And we use a completely separate dispatch implementation, because adding the behavior to the tablet interface requires so many exceptions that it's easier to just add a separate dispatch interface. Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
This commit is contained in:
parent
17d792445e
commit
bf4277623f
14 changed files with 1798 additions and 56 deletions
|
|
@ -307,6 +307,7 @@ src_libinput = src_libfilter + [
|
|||
'src/evdev-debounce.c',
|
||||
'src/evdev-fallback.c',
|
||||
'src/evdev-fallback.h',
|
||||
'src/evdev-totem.c',
|
||||
'src/evdev-middle-button.c',
|
||||
'src/evdev-mt-touchpad.c',
|
||||
'src/evdev-mt-touchpad.h',
|
||||
|
|
@ -709,6 +710,8 @@ if get_option('tests')
|
|||
'test/litest-device-bcm5974.c',
|
||||
'test/litest-device-calibrated-touchscreen.c',
|
||||
'test/litest-device-cyborg-rat-5.c',
|
||||
'test/litest-device-dell-canvas-totem.c',
|
||||
'test/litest-device-dell-canvas-totem-touch.c',
|
||||
'test/litest-device-elantech-touchpad.c',
|
||||
'test/litest-device-generic-singletouch.c',
|
||||
'test/litest-device-gpio-keys.c',
|
||||
|
|
@ -851,6 +854,7 @@ if get_option('tests')
|
|||
'test/test-touch.c',
|
||||
'test/test-log.c',
|
||||
'test/test-tablet.c',
|
||||
'test/test-totem.c',
|
||||
'test/test-pad.c',
|
||||
'test/test-touchpad.c',
|
||||
'test/test-touchpad-tap.c',
|
||||
|
|
|
|||
|
|
@ -52,3 +52,12 @@ AttrTrackpointMultiplier=1.5
|
|||
MatchName=*DualPoint Stick
|
||||
MatchDMIModalias=dmi:*svnDellInc.:pnLatitudeE7470*
|
||||
AttrTrackpointMultiplier=0.125
|
||||
|
||||
# The touch device has the same vid/pid as the totem, the MatchName
|
||||
# directive is required here
|
||||
[Canvas Totem]
|
||||
MatchName=*System Multi Axis
|
||||
MatchBus=usb
|
||||
MatchVendor=0x2575
|
||||
MatchProduct=0x0204
|
||||
ModelDellCanvasTotem=1
|
||||
|
|
|
|||
829
src/evdev-totem.c
Normal file
829
src/evdev-totem.c
Normal file
|
|
@ -0,0 +1,829 @@
|
|||
/*
|
||||
* Copyright © 2018 Red Hat, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "evdev.h"
|
||||
|
||||
enum totem_slot_state {
|
||||
SLOT_STATE_NONE,
|
||||
SLOT_STATE_BEGIN,
|
||||
SLOT_STATE_UPDATE,
|
||||
SLOT_STATE_END,
|
||||
};
|
||||
|
||||
struct totem_slot {
|
||||
bool dirty;
|
||||
unsigned int index;
|
||||
enum totem_slot_state state;
|
||||
struct libinput_tablet_tool *tool;
|
||||
struct tablet_axes axes;
|
||||
unsigned char changed_axes[NCHARS(LIBINPUT_TABLET_TOOL_AXIS_MAX + 1)];
|
||||
|
||||
struct device_coords last_point;
|
||||
};
|
||||
|
||||
struct totem_dispatch {
|
||||
struct evdev_dispatch base;
|
||||
struct evdev_device *device;
|
||||
|
||||
int slot; /* current slot */
|
||||
struct totem_slot *slots;
|
||||
size_t nslots;
|
||||
|
||||
struct evdev_device *touch_device;
|
||||
|
||||
/* We only have one button */
|
||||
bool button_state_now;
|
||||
bool button_state_previous;
|
||||
|
||||
enum evdev_arbitration_state arbitration_state;
|
||||
};
|
||||
|
||||
static inline struct totem_dispatch*
|
||||
totem_dispatch(struct evdev_dispatch *totem)
|
||||
{
|
||||
evdev_verify_dispatch_type(totem, DISPATCH_TOTEM);
|
||||
|
||||
return container_of(totem, struct totem_dispatch, base);
|
||||
}
|
||||
|
||||
static inline struct libinput *
|
||||
totem_libinput_context(const struct totem_dispatch *totem)
|
||||
{
|
||||
return evdev_libinput_context(totem->device);
|
||||
}
|
||||
|
||||
static struct libinput_tablet_tool *
|
||||
totem_new_tool(struct totem_dispatch *totem)
|
||||
{
|
||||
struct libinput *libinput = totem_libinput_context(totem);
|
||||
struct libinput_tablet_tool *tool;
|
||||
|
||||
tool = zalloc(sizeof *tool);
|
||||
|
||||
*tool = (struct libinput_tablet_tool) {
|
||||
.type = LIBINPUT_TABLET_TOOL_TYPE_TOTEM,
|
||||
.serial = 0,
|
||||
.tool_id = 0,
|
||||
.refcount = 1,
|
||||
};
|
||||
|
||||
tool->pressure_offset = 0;
|
||||
tool->has_pressure_offset = false;
|
||||
tool->pressure_threshold.lower = 0;
|
||||
tool->pressure_threshold.upper = 1;
|
||||
|
||||
set_bit(tool->axis_caps, LIBINPUT_TABLET_TOOL_AXIS_X);
|
||||
set_bit(tool->axis_caps, LIBINPUT_TABLET_TOOL_AXIS_Y);
|
||||
set_bit(tool->axis_caps, LIBINPUT_TABLET_TOOL_AXIS_ROTATION_Z);
|
||||
set_bit(tool->axis_caps, LIBINPUT_TABLET_TOOL_AXIS_SIZE_MAJOR);
|
||||
set_bit(tool->axis_caps, LIBINPUT_TABLET_TOOL_AXIS_SIZE_MINOR);
|
||||
set_bit(tool->buttons, BTN_0);
|
||||
|
||||
list_insert(&libinput->tool_list, &tool->link);
|
||||
|
||||
return tool;
|
||||
}
|
||||
|
||||
static inline void
|
||||
totem_set_touch_device_enabled(struct totem_dispatch *totem,
|
||||
bool enable_touch_device,
|
||||
uint64_t time)
|
||||
{
|
||||
struct evdev_device *touch_device = totem->touch_device;
|
||||
struct evdev_dispatch *dispatch;
|
||||
struct phys_rect r, *rect = NULL;
|
||||
enum evdev_arbitration_state state = ARBITRATION_NOT_ACTIVE;
|
||||
|
||||
if (touch_device == NULL)
|
||||
return;
|
||||
|
||||
/* We just pick the coordinates of the first touch we find. The
|
||||
* totem only does one tool right now despite being nominally an MT
|
||||
* device, so let's not go too hard on ourselves*/
|
||||
for (size_t i = 0; !enable_touch_device && i < totem->nslots; i++) {
|
||||
struct totem_slot *slot = &totem->slots[i];
|
||||
struct phys_coords mm;
|
||||
|
||||
if (slot->state == SLOT_STATE_NONE)
|
||||
continue;
|
||||
|
||||
/* Totem size is ~70mm. We could calculate the real size but
|
||||
until we need that, hardcoding it is enough */
|
||||
mm = evdev_device_units_to_mm(totem->device, &slot->axes.point);
|
||||
r.x = mm.x - 30;
|
||||
r.y = mm.y - 30;
|
||||
r.w = 100;
|
||||
r.h = 100;
|
||||
|
||||
rect = &r;
|
||||
|
||||
state = ARBITRATION_IGNORE_RECT;
|
||||
break;
|
||||
}
|
||||
|
||||
dispatch = touch_device->dispatch;
|
||||
|
||||
if (enable_touch_device) {
|
||||
if (dispatch->interface->touch_arbitration_toggle)
|
||||
dispatch->interface->touch_arbitration_toggle(dispatch,
|
||||
touch_device,
|
||||
state,
|
||||
rect,
|
||||
time);
|
||||
} else {
|
||||
switch (totem->arbitration_state) {
|
||||
case ARBITRATION_IGNORE_ALL:
|
||||
abort();
|
||||
case ARBITRATION_NOT_ACTIVE:
|
||||
if (dispatch->interface->touch_arbitration_toggle)
|
||||
dispatch->interface->touch_arbitration_toggle(dispatch,
|
||||
touch_device,
|
||||
state,
|
||||
rect,
|
||||
time);
|
||||
break;
|
||||
case ARBITRATION_IGNORE_RECT:
|
||||
if (dispatch->interface->touch_arbitration_update_rect)
|
||||
dispatch->interface->touch_arbitration_update_rect(dispatch,
|
||||
touch_device,
|
||||
rect,
|
||||
time);
|
||||
break;
|
||||
}
|
||||
}
|
||||
totem->arbitration_state = state;
|
||||
}
|
||||
|
||||
static void
|
||||
totem_process_key(struct totem_dispatch *totem,
|
||||
struct evdev_device *device,
|
||||
struct input_event *e,
|
||||
uint64_t time)
|
||||
{
|
||||
switch(e->code) {
|
||||
case BTN_0:
|
||||
totem->button_state_now = !!e->value;
|
||||
break;
|
||||
default:
|
||||
evdev_log_info(device,
|
||||
"Unhandled KEY event code %#x\n",
|
||||
e->code);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
totem_process_abs(struct totem_dispatch *totem,
|
||||
struct evdev_device *device,
|
||||
struct input_event *e,
|
||||
uint64_t time)
|
||||
{
|
||||
struct totem_slot *slot = &totem->slots[totem->slot];
|
||||
|
||||
switch(e->code) {
|
||||
case ABS_MT_SLOT:
|
||||
if ((size_t)e->value >= totem->nslots) {
|
||||
evdev_log_bug_libinput(device,
|
||||
"exceeded slot count (%d of max %zd)\n",
|
||||
e->value,
|
||||
totem->nslots);
|
||||
e->value = totem->nslots - 1;
|
||||
}
|
||||
totem->slot = e->value;
|
||||
return;
|
||||
case ABS_MT_TRACKING_ID:
|
||||
/* If the totem is already down on init, we currently
|
||||
ignore it */
|
||||
if (e->value >= 0)
|
||||
slot->state = SLOT_STATE_BEGIN;
|
||||
else if (slot->state != SLOT_STATE_NONE)
|
||||
slot->state = SLOT_STATE_END;
|
||||
break;
|
||||
case ABS_MT_POSITION_X:
|
||||
set_bit(slot->changed_axes, LIBINPUT_TABLET_TOOL_AXIS_X);
|
||||
break;
|
||||
case ABS_MT_POSITION_Y:
|
||||
set_bit(slot->changed_axes, LIBINPUT_TABLET_TOOL_AXIS_Y);
|
||||
break;
|
||||
case ABS_MT_TOUCH_MAJOR:
|
||||
set_bit(slot->changed_axes,
|
||||
LIBINPUT_TABLET_TOOL_AXIS_SIZE_MAJOR);
|
||||
break;
|
||||
case ABS_MT_TOUCH_MINOR:
|
||||
set_bit(slot->changed_axes,
|
||||
LIBINPUT_TABLET_TOOL_AXIS_SIZE_MINOR);
|
||||
break;
|
||||
case ABS_MT_ORIENTATION:
|
||||
set_bit(slot->changed_axes,
|
||||
LIBINPUT_TABLET_TOOL_AXIS_ROTATION_Z);
|
||||
break;
|
||||
case ABS_MT_TOOL_TYPE:
|
||||
if (e->value != MT_TOOL_DIAL) {
|
||||
evdev_log_info(device,
|
||||
"Unexpected tool type %#x, changing to dial\n",
|
||||
e->code);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
evdev_log_info(device,
|
||||
"Unhandled ABS event code %#x\n",
|
||||
e->code);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static bool
|
||||
totem_slot_fetch_axes(struct totem_dispatch *totem,
|
||||
struct totem_slot *slot,
|
||||
struct libinput_tablet_tool *tool,
|
||||
struct tablet_axes *axes_out,
|
||||
uint64_t time)
|
||||
{
|
||||
struct evdev_device *device = totem->device;
|
||||
const char tmp[sizeof(slot->changed_axes)] = {0};
|
||||
struct tablet_axes axes = {0};
|
||||
struct device_float_coords delta;
|
||||
bool rc = false;
|
||||
|
||||
if (memcmp(tmp, slot->changed_axes, sizeof(tmp)) == 0) {
|
||||
axes = slot->axes;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (bit_is_set(slot->changed_axes, LIBINPUT_TABLET_TOOL_AXIS_X) ||
|
||||
bit_is_set(slot->changed_axes, LIBINPUT_TABLET_TOOL_AXIS_Y)) {
|
||||
slot->axes.point.x = libevdev_get_slot_value(device->evdev,
|
||||
slot->index,
|
||||
ABS_MT_POSITION_X);
|
||||
slot->axes.point.y = libevdev_get_slot_value(device->evdev,
|
||||
slot->index,
|
||||
ABS_MT_POSITION_Y);
|
||||
}
|
||||
|
||||
if (bit_is_set(slot->changed_axes,
|
||||
LIBINPUT_TABLET_TOOL_AXIS_ROTATION_Z)) {
|
||||
int angle = libevdev_get_slot_value(device->evdev,
|
||||
slot->index,
|
||||
ABS_MT_ORIENTATION);
|
||||
/* The kernel gives us ±90 degrees off neutral */
|
||||
slot->axes.rotation = (360 - angle) % 360;
|
||||
}
|
||||
|
||||
if (bit_is_set(slot->changed_axes,
|
||||
LIBINPUT_TABLET_TOOL_AXIS_SIZE_MAJOR) ||
|
||||
bit_is_set(slot->changed_axes,
|
||||
LIBINPUT_TABLET_TOOL_AXIS_SIZE_MINOR)) {
|
||||
int major, minor;
|
||||
unsigned int rmajor, rminor;
|
||||
|
||||
major = libevdev_get_slot_value(device->evdev,
|
||||
slot->index,
|
||||
ABS_MT_TOUCH_MAJOR);
|
||||
minor = libevdev_get_slot_value(device->evdev,
|
||||
slot->index,
|
||||
ABS_MT_TOUCH_MINOR);
|
||||
rmajor = libevdev_get_abs_resolution(device->evdev, ABS_MT_TOUCH_MAJOR);
|
||||
rminor = libevdev_get_abs_resolution(device->evdev, ABS_MT_TOUCH_MINOR);
|
||||
slot->axes.size.major = (double)major/rmajor;
|
||||
slot->axes.size.minor = (double)minor/rminor;
|
||||
}
|
||||
|
||||
axes.point = slot->axes.point;
|
||||
axes.rotation = slot->axes.rotation;
|
||||
axes.size = slot->axes.size;
|
||||
|
||||
delta.x = slot->axes.point.x - slot->last_point.x;
|
||||
delta.y = slot->axes.point.y - slot->last_point.y;
|
||||
axes.delta = filter_dispatch(device->pointer.filter, &delta, tool, time);
|
||||
|
||||
rc = true;
|
||||
out:
|
||||
*axes_out = axes;
|
||||
return rc;
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
totem_slot_mark_all_axes_changed(struct totem_dispatch *totem,
|
||||
struct totem_slot *slot,
|
||||
struct libinput_tablet_tool *tool)
|
||||
{
|
||||
static_assert(sizeof(slot->changed_axes) ==
|
||||
sizeof(tool->axis_caps),
|
||||
"Mismatching array sizes");
|
||||
|
||||
memcpy(slot->changed_axes,
|
||||
tool->axis_caps,
|
||||
sizeof(slot->changed_axes));
|
||||
}
|
||||
|
||||
static inline void
|
||||
totem_slot_reset_changed_axes(struct totem_dispatch *totem,
|
||||
struct totem_slot *slot)
|
||||
{
|
||||
memset(slot->changed_axes, 0, sizeof(slot->changed_axes));
|
||||
}
|
||||
|
||||
static inline void
|
||||
slot_axes_initialize(struct totem_dispatch *totem,
|
||||
struct totem_slot *slot)
|
||||
{
|
||||
struct evdev_device *device = totem->device;
|
||||
|
||||
slot->axes.point.x = libevdev_get_slot_value(device->evdev,
|
||||
slot->index,
|
||||
ABS_MT_POSITION_X);
|
||||
slot->axes.point.y = libevdev_get_slot_value(device->evdev,
|
||||
slot->index,
|
||||
ABS_MT_POSITION_Y);
|
||||
slot->last_point.x = slot->axes.point.x;
|
||||
slot->last_point.y = slot->axes.point.y;
|
||||
}
|
||||
|
||||
static enum totem_slot_state
|
||||
totem_handle_slot_state(struct totem_dispatch *totem,
|
||||
struct totem_slot *slot,
|
||||
uint64_t time)
|
||||
{
|
||||
struct evdev_device *device = totem->device;
|
||||
struct tablet_axes axes;
|
||||
enum libinput_tablet_tool_tip_state tip_state;
|
||||
bool updated;
|
||||
|
||||
switch (slot->state) {
|
||||
case SLOT_STATE_BEGIN:
|
||||
if (!slot->tool)
|
||||
slot->tool = totem_new_tool(totem);
|
||||
slot_axes_initialize(totem, slot);
|
||||
totem_slot_mark_all_axes_changed(totem, slot, slot->tool);
|
||||
break;
|
||||
case SLOT_STATE_UPDATE:
|
||||
case SLOT_STATE_END:
|
||||
assert(slot->tool);
|
||||
break;
|
||||
case SLOT_STATE_NONE:
|
||||
return SLOT_STATE_NONE;
|
||||
}
|
||||
|
||||
tip_state = LIBINPUT_TABLET_TOOL_TIP_UP;
|
||||
updated = totem_slot_fetch_axes(totem, slot, slot->tool, &axes, time);
|
||||
|
||||
switch (slot->state) {
|
||||
case SLOT_STATE_BEGIN:
|
||||
tip_state = LIBINPUT_TABLET_TOOL_TIP_DOWN;
|
||||
tablet_notify_proximity(&device->base,
|
||||
time,
|
||||
slot->tool,
|
||||
LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_IN,
|
||||
slot->changed_axes,
|
||||
&axes);
|
||||
totem_slot_reset_changed_axes(totem, slot);
|
||||
tablet_notify_tip(&device->base,
|
||||
time,
|
||||
slot->tool,
|
||||
tip_state,
|
||||
slot->changed_axes,
|
||||
&axes);
|
||||
slot->state = SLOT_STATE_UPDATE;
|
||||
break;
|
||||
case SLOT_STATE_UPDATE:
|
||||
tip_state = LIBINPUT_TABLET_TOOL_TIP_DOWN;
|
||||
if (updated) {
|
||||
tablet_notify_axis(&device->base,
|
||||
time,
|
||||
slot->tool,
|
||||
tip_state,
|
||||
slot->changed_axes,
|
||||
&axes);
|
||||
}
|
||||
break;
|
||||
case SLOT_STATE_END:
|
||||
/* prox out is handled after button events */
|
||||
break;
|
||||
case SLOT_STATE_NONE:
|
||||
abort();
|
||||
break;
|
||||
}
|
||||
|
||||
/* We only have one button but possibly multiple totems. It's not
|
||||
* clear how the firmware will work, so for now we just handle the
|
||||
* button state in the first slot.
|
||||
*
|
||||
* Due to the design of the totem we're also less fancy about
|
||||
* button handling than the tablet code. Worst case, you might get
|
||||
* tip up before button up but meh.
|
||||
*/
|
||||
if (totem->button_state_now != totem->button_state_previous) {
|
||||
enum libinput_button_state btn_state;
|
||||
|
||||
if (totem->button_state_now)
|
||||
btn_state = LIBINPUT_BUTTON_STATE_PRESSED;
|
||||
else
|
||||
btn_state = LIBINPUT_BUTTON_STATE_RELEASED;
|
||||
|
||||
tablet_notify_button(&device->base,
|
||||
time,
|
||||
slot->tool,
|
||||
tip_state,
|
||||
&axes,
|
||||
BTN_0,
|
||||
btn_state);
|
||||
|
||||
totem->button_state_previous = totem->button_state_now;
|
||||
}
|
||||
|
||||
switch(slot->state) {
|
||||
case SLOT_STATE_BEGIN:
|
||||
case SLOT_STATE_UPDATE:
|
||||
break;
|
||||
case SLOT_STATE_END:
|
||||
tip_state = LIBINPUT_TABLET_TOOL_TIP_UP;
|
||||
tablet_notify_tip(&device->base,
|
||||
time,
|
||||
slot->tool,
|
||||
tip_state,
|
||||
slot->changed_axes,
|
||||
&axes);
|
||||
totem_slot_reset_changed_axes(totem, slot);
|
||||
tablet_notify_proximity(&device->base,
|
||||
time,
|
||||
slot->tool,
|
||||
LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_OUT,
|
||||
slot->changed_axes,
|
||||
&axes);
|
||||
slot->state = SLOT_STATE_NONE;
|
||||
break;
|
||||
case SLOT_STATE_NONE:
|
||||
abort();
|
||||
break;
|
||||
}
|
||||
|
||||
slot->last_point = slot->axes.point;
|
||||
totem_slot_reset_changed_axes(totem, slot);
|
||||
|
||||
return slot->state;
|
||||
}
|
||||
|
||||
static enum totem_slot_state
|
||||
totem_handle_state(struct totem_dispatch *totem,
|
||||
uint64_t time)
|
||||
{
|
||||
enum totem_slot_state global_state = SLOT_STATE_NONE;
|
||||
|
||||
for (size_t i = 0; i < totem->nslots; i++) {
|
||||
enum totem_slot_state s;
|
||||
|
||||
s = totem_handle_slot_state(totem,
|
||||
&totem->slots[i],
|
||||
time);
|
||||
|
||||
/* If one slot is active, the totem is active */
|
||||
if (s != SLOT_STATE_NONE)
|
||||
global_state = SLOT_STATE_UPDATE;
|
||||
}
|
||||
|
||||
return global_state;
|
||||
}
|
||||
|
||||
static void
|
||||
totem_interface_process(struct evdev_dispatch *dispatch,
|
||||
struct evdev_device *device,
|
||||
struct input_event *e,
|
||||
uint64_t time)
|
||||
{
|
||||
struct totem_dispatch *totem = totem_dispatch(dispatch);
|
||||
enum totem_slot_state global_state;
|
||||
bool enable_touch;
|
||||
|
||||
switch(e->type) {
|
||||
case EV_ABS:
|
||||
totem_process_abs(totem, device, e, time);
|
||||
break;
|
||||
case EV_KEY:
|
||||
totem_process_key(totem, device, e, time);
|
||||
break;
|
||||
case EV_MSC:
|
||||
/* timestamp, ignore */
|
||||
break;
|
||||
case EV_SYN:
|
||||
global_state = totem_handle_state(totem, time);
|
||||
enable_touch = (global_state == SLOT_STATE_NONE);
|
||||
totem_set_touch_device_enabled(totem,
|
||||
enable_touch,
|
||||
time);
|
||||
break;
|
||||
default:
|
||||
evdev_log_error(device,
|
||||
"Unexpected event type %s (%#x)\n",
|
||||
libevdev_event_type_get_name(e->type),
|
||||
e->type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
totem_interface_suspend(struct evdev_dispatch *dispatch,
|
||||
struct evdev_device *device)
|
||||
{
|
||||
struct totem_dispatch *totem = totem_dispatch(dispatch);
|
||||
uint64_t now = libinput_now(evdev_libinput_context(device));
|
||||
|
||||
for (size_t i = 0; i < totem->nslots; i++) {
|
||||
struct totem_slot *slot = &totem->slots[i];
|
||||
struct tablet_axes axes;
|
||||
enum libinput_tablet_tool_tip_state tip_state;
|
||||
|
||||
/* If we never initialized a tool, we can skip everything */
|
||||
if (!slot->tool)
|
||||
continue;
|
||||
|
||||
totem_slot_fetch_axes(totem, slot, slot->tool, &axes, now);
|
||||
totem_slot_reset_changed_axes(totem, slot);
|
||||
|
||||
if (slot->state == SLOT_STATE_NONE)
|
||||
tip_state = LIBINPUT_TABLET_TOOL_TIP_UP;
|
||||
else
|
||||
tip_state = LIBINPUT_TABLET_TOOL_TIP_DOWN;
|
||||
|
||||
if (totem->button_state_now) {
|
||||
tablet_notify_button(&device->base,
|
||||
now,
|
||||
slot->tool,
|
||||
tip_state,
|
||||
&axes,
|
||||
BTN_0,
|
||||
LIBINPUT_BUTTON_STATE_RELEASED);
|
||||
|
||||
totem->button_state_now = false;
|
||||
totem->button_state_previous = false;
|
||||
}
|
||||
|
||||
if (slot->state != SLOT_STATE_NONE) {
|
||||
tablet_notify_tip(&device->base,
|
||||
now,
|
||||
slot->tool,
|
||||
LIBINPUT_TABLET_TOOL_TIP_UP,
|
||||
slot->changed_axes,
|
||||
&axes);
|
||||
}
|
||||
tablet_notify_proximity(&device->base,
|
||||
now,
|
||||
slot->tool,
|
||||
LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_OUT,
|
||||
slot->changed_axes,
|
||||
&axes);
|
||||
}
|
||||
totem_set_touch_device_enabled(totem, true, now);
|
||||
}
|
||||
|
||||
static void
|
||||
totem_interface_destroy(struct evdev_dispatch *dispatch)
|
||||
{
|
||||
struct totem_dispatch *totem = totem_dispatch(dispatch);
|
||||
|
||||
free(totem->slots);
|
||||
free(totem);
|
||||
}
|
||||
|
||||
static void
|
||||
totem_interface_device_added(struct evdev_device *device,
|
||||
struct evdev_device *added_device)
|
||||
{
|
||||
struct totem_dispatch *totem = totem_dispatch(device->dispatch);
|
||||
struct libinput_device_group *g1, *g2;
|
||||
|
||||
if ((evdev_device_get_id_vendor(added_device) !=
|
||||
evdev_device_get_id_vendor(device)) ||
|
||||
(evdev_device_get_id_product(added_device) !=
|
||||
evdev_device_get_id_product(device)))
|
||||
return;
|
||||
|
||||
/* virtual devices don't have device groups, so check for that
|
||||
libinput replay */
|
||||
g1 = libinput_device_get_device_group(&device->base);
|
||||
g2 = libinput_device_get_device_group(&added_device->base);
|
||||
if (g1 && g2 && g1->identifier != g2->identifier)
|
||||
return;
|
||||
|
||||
if (totem->touch_device != NULL) {
|
||||
evdev_log_bug_libinput(device,
|
||||
"already has a paired touch device, ignoring (%s)\n",
|
||||
added_device->devname);
|
||||
return;
|
||||
}
|
||||
|
||||
totem->touch_device = added_device;
|
||||
evdev_log_info(device, "%s: is the totem touch device\n", added_device->devname);
|
||||
}
|
||||
|
||||
static void
|
||||
totem_interface_device_removed(struct evdev_device *device,
|
||||
struct evdev_device *removed_device)
|
||||
{
|
||||
struct totem_dispatch *totem = totem_dispatch(device->dispatch);
|
||||
|
||||
if (totem->touch_device != removed_device)
|
||||
return;
|
||||
|
||||
totem_set_touch_device_enabled(totem, true,
|
||||
libinput_now(evdev_libinput_context(device)));
|
||||
totem->touch_device = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
totem_interface_initial_proximity(struct evdev_device *device,
|
||||
struct evdev_dispatch *dispatch)
|
||||
{
|
||||
struct totem_dispatch *totem = totem_dispatch(dispatch);
|
||||
uint64_t now = libinput_now(evdev_libinput_context(device));
|
||||
bool enable_touch = true;
|
||||
|
||||
for (size_t i = 0; i < totem->nslots; i++) {
|
||||
struct totem_slot *slot = &totem->slots[i];
|
||||
struct tablet_axes axes;
|
||||
int tracking_id;
|
||||
|
||||
tracking_id = libevdev_get_slot_value(device->evdev,
|
||||
i,
|
||||
ABS_MT_TRACKING_ID);
|
||||
if (tracking_id == -1)
|
||||
continue;
|
||||
|
||||
slot->tool = totem_new_tool(totem);
|
||||
slot_axes_initialize(totem, slot);
|
||||
totem_slot_mark_all_axes_changed(totem, slot, slot->tool);
|
||||
totem_slot_fetch_axes(totem, slot, slot->tool, &axes, now);
|
||||
tablet_notify_proximity(&device->base,
|
||||
now,
|
||||
slot->tool,
|
||||
LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_IN,
|
||||
slot->changed_axes,
|
||||
&axes);
|
||||
totem_slot_reset_changed_axes(totem, slot);
|
||||
tablet_notify_tip(&device->base,
|
||||
now,
|
||||
slot->tool,
|
||||
LIBINPUT_TABLET_TOOL_TIP_DOWN,
|
||||
slot->changed_axes,
|
||||
&axes);
|
||||
slot->state = SLOT_STATE_UPDATE;
|
||||
enable_touch = false;
|
||||
}
|
||||
|
||||
totem_set_touch_device_enabled(totem, enable_touch, now);
|
||||
}
|
||||
|
||||
struct evdev_dispatch_interface totem_interface = {
|
||||
.process = totem_interface_process,
|
||||
.suspend = totem_interface_suspend,
|
||||
.remove = NULL,
|
||||
.destroy = totem_interface_destroy,
|
||||
.device_added = totem_interface_device_added,
|
||||
.device_removed = totem_interface_device_removed,
|
||||
.device_suspended = totem_interface_device_added, /* treat as remove */
|
||||
.device_resumed = totem_interface_device_removed, /* treat as add */
|
||||
.post_added = totem_interface_initial_proximity,
|
||||
.touch_arbitration_toggle = NULL,
|
||||
.touch_arbitration_update_rect = NULL,
|
||||
.get_switch_state = NULL,
|
||||
};
|
||||
|
||||
static bool
|
||||
totem_reject_device(struct evdev_device *device)
|
||||
{
|
||||
struct libevdev *evdev = device->evdev;
|
||||
bool has_xy, has_slot, has_tool_dial, has_size;
|
||||
double w, h;
|
||||
|
||||
has_xy = libevdev_has_event_code(evdev, EV_ABS, ABS_MT_POSITION_X) &&
|
||||
libevdev_has_event_code(evdev, EV_ABS, ABS_MT_POSITION_Y);
|
||||
has_slot = libevdev_has_event_code(evdev, EV_ABS, ABS_MT_SLOT);
|
||||
has_tool_dial = libevdev_has_event_code(evdev, EV_ABS, ABS_MT_TOOL_TYPE) &&
|
||||
libevdev_get_abs_maximum(evdev, ABS_MT_TOOL_TYPE) >= MT_TOOL_DIAL;
|
||||
has_size = evdev_device_get_size(device, &w, &h) == 0;
|
||||
has_size |= libevdev_get_abs_resolution(device->evdev, ABS_MT_TOUCH_MAJOR) > 0;
|
||||
has_size |= libevdev_get_abs_resolution(device->evdev, ABS_MT_TOUCH_MINOR) > 0;
|
||||
|
||||
if (has_xy && has_slot && has_tool_dial && has_size)
|
||||
return false;
|
||||
|
||||
evdev_log_bug_libinput(device,
|
||||
"missing totem capabilities:%s%s%s%s. "
|
||||
"Ignoring this device.\n",
|
||||
has_xy ? "" : " xy",
|
||||
has_slot ? "" : " slot",
|
||||
has_tool_dial ? "" : " dial",
|
||||
has_size ? "" : " resolutions");
|
||||
return true;
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
totem_accel_config_get_profiles(struct libinput_device *libinput_device)
|
||||
{
|
||||
return LIBINPUT_CONFIG_ACCEL_PROFILE_NONE;
|
||||
}
|
||||
|
||||
static enum libinput_config_status
|
||||
totem_accel_config_set_profile(struct libinput_device *libinput_device,
|
||||
enum libinput_config_accel_profile profile)
|
||||
{
|
||||
return LIBINPUT_CONFIG_STATUS_UNSUPPORTED;
|
||||
}
|
||||
|
||||
static enum libinput_config_accel_profile
|
||||
totem_accel_config_get_profile(struct libinput_device *libinput_device)
|
||||
{
|
||||
return LIBINPUT_CONFIG_ACCEL_PROFILE_NONE;
|
||||
}
|
||||
|
||||
static enum libinput_config_accel_profile
|
||||
totem_accel_config_get_default_profile(struct libinput_device *libinput_device)
|
||||
{
|
||||
return LIBINPUT_CONFIG_ACCEL_PROFILE_NONE;
|
||||
}
|
||||
|
||||
static int
|
||||
totem_init_accel(struct totem_dispatch *totem, struct evdev_device *device)
|
||||
{
|
||||
const struct input_absinfo *x, *y;
|
||||
struct motion_filter *filter;
|
||||
|
||||
x = device->abs.absinfo_x;
|
||||
y = device->abs.absinfo_y;
|
||||
|
||||
/* same filter as the tablet */
|
||||
filter = create_pointer_accelerator_filter_tablet(x->resolution,
|
||||
y->resolution);
|
||||
if (!filter)
|
||||
return -1;
|
||||
|
||||
evdev_device_init_pointer_acceleration(device, filter);
|
||||
|
||||
/* we override the profile hooks for accel configuration with hooks
|
||||
* that don't allow selection of profiles */
|
||||
device->pointer.config.get_profiles = totem_accel_config_get_profiles;
|
||||
device->pointer.config.set_profile = totem_accel_config_set_profile;
|
||||
device->pointer.config.get_profile = totem_accel_config_get_profile;
|
||||
device->pointer.config.get_default_profile = totem_accel_config_get_default_profile;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct evdev_dispatch *
|
||||
evdev_totem_create(struct evdev_device *device)
|
||||
{
|
||||
struct totem_dispatch *totem;
|
||||
struct totem_slot *slots;
|
||||
int num_slots;
|
||||
|
||||
if (totem_reject_device(device))
|
||||
return NULL;
|
||||
|
||||
totem = zalloc(sizeof *totem);
|
||||
totem->device = device;
|
||||
totem->base.dispatch_type = DISPATCH_TOTEM;
|
||||
totem->base.interface = &totem_interface;
|
||||
|
||||
num_slots = libevdev_get_num_slots(device->evdev);
|
||||
if (num_slots <= 0)
|
||||
goto error;
|
||||
|
||||
totem->slot = libevdev_get_current_slot(device->evdev);
|
||||
slots = zalloc(num_slots * sizeof(*totem->slots));
|
||||
|
||||
for (int slot = 0; slot < num_slots; ++slot) {
|
||||
slots[slot].index = slot;
|
||||
}
|
||||
|
||||
totem->slots = slots;
|
||||
totem->nslots = num_slots;
|
||||
|
||||
evdev_init_sendevents(device, &totem->base);
|
||||
totem_init_accel(totem, device);
|
||||
|
||||
return &totem->base;
|
||||
error:
|
||||
totem_interface_destroy(&totem->base);
|
||||
return NULL;
|
||||
}
|
||||
|
|
@ -1728,6 +1728,14 @@ evdev_configure_device(struct evdev_device *device)
|
|||
udev_tags &= ~EVDEV_UDEV_TAG_TOUCHSCREEN;
|
||||
}
|
||||
|
||||
if (evdev_device_has_model_quirk(device,
|
||||
QUIRK_MODEL_DELL_CANVAS_TOTEM)) {
|
||||
dispatch = evdev_totem_create(device);
|
||||
device->seat_caps |= EVDEV_DEVICE_TABLET;
|
||||
evdev_log_info(device, "device is a totem\n");
|
||||
return dispatch;
|
||||
}
|
||||
|
||||
/* libwacom assigns touchpad (or touchscreen) _and_ tablet to the
|
||||
tablet touch bits, so make sure we don't initialize the tablet
|
||||
interface for the touch device */
|
||||
|
|
|
|||
|
|
@ -336,6 +336,7 @@ enum evdev_dispatch_type {
|
|||
DISPATCH_TOUCHPAD,
|
||||
DISPATCH_TABLET,
|
||||
DISPATCH_TABLET_PAD,
|
||||
DISPATCH_TOTEM,
|
||||
};
|
||||
|
||||
struct evdev_dispatch {
|
||||
|
|
@ -431,6 +432,9 @@ evdev_lid_switch_dispatch_create(struct evdev_device *device);
|
|||
struct evdev_dispatch *
|
||||
fallback_dispatch_create(struct libinput_device *libinput_device);
|
||||
|
||||
struct evdev_dispatch *
|
||||
evdev_totem_create(struct evdev_device *device);
|
||||
|
||||
bool
|
||||
evdev_is_fake_mt_device(struct evdev_device *device);
|
||||
|
||||
|
|
@ -922,7 +926,6 @@ evdev_phys_rect_to_units(const struct evdev_device *device,
|
|||
return units;
|
||||
}
|
||||
|
||||
|
||||
static inline void
|
||||
evdev_device_init_abs_range_warnings(struct evdev_device *device)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -254,6 +254,7 @@ quirk_get_name(enum quirk q)
|
|||
case QUIRK_MODEL_TOUCHPAD_VISIBLE_MARKER: return "ModelTouchpadVisibleMarker";
|
||||
case QUIRK_MODEL_TRACKBALL: return "ModelTrackball";
|
||||
case QUIRK_MODEL_WACOM_TOUCHPAD: return "ModelWacomTouchpad";
|
||||
case QUIRK_MODEL_DELL_CANVAS_TOTEM: return "ModelDellCanvasTotem";
|
||||
|
||||
case QUIRK_ATTR_SIZE_HINT: return "AttrSizeHint";
|
||||
case QUIRK_ATTR_TOUCH_SIZE_RANGE: return "AttrTouchSizeRange";
|
||||
|
|
|
|||
|
|
@ -86,6 +86,7 @@ enum quirk {
|
|||
QUIRK_MODEL_TOUCHPAD_VISIBLE_MARKER,
|
||||
QUIRK_MODEL_TRACKBALL,
|
||||
QUIRK_MODEL_WACOM_TOUCHPAD,
|
||||
QUIRK_MODEL_DELL_CANVAS_TOTEM,
|
||||
|
||||
_QUIRK_LAST_MODEL_QUIRK_, /* Guard: do not modify */
|
||||
|
||||
|
|
|
|||
98
test/litest-device-dell-canvas-totem-touch.c
Normal file
98
test/litest-device-dell-canvas-totem-touch.c
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
/*
|
||||
* Copyright © 2019 Red Hat, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "litest.h"
|
||||
#include "litest-int.h"
|
||||
|
||||
static struct input_event down[] = {
|
||||
{ .type = EV_ABS, .code = ABS_MT_SLOT, .value = LITEST_AUTO_ASSIGN },
|
||||
{ .type = EV_ABS, .code = ABS_MT_TRACKING_ID, .value = LITEST_AUTO_ASSIGN },
|
||||
{ .type = EV_ABS, .code = ABS_X, .value = LITEST_AUTO_ASSIGN },
|
||||
{ .type = EV_ABS, .code = ABS_Y, .value = LITEST_AUTO_ASSIGN },
|
||||
{ .type = EV_ABS, .code = ABS_MT_POSITION_X, .value = LITEST_AUTO_ASSIGN },
|
||||
{ .type = EV_ABS, .code = ABS_MT_POSITION_Y, .value = LITEST_AUTO_ASSIGN },
|
||||
{ .type = EV_SYN, .code = SYN_REPORT, .value = 0 },
|
||||
{ .type = -1, .code = -1 },
|
||||
};
|
||||
|
||||
static struct input_event move[] = {
|
||||
{ .type = EV_ABS, .code = ABS_MT_SLOT, .value = LITEST_AUTO_ASSIGN },
|
||||
{ .type = EV_ABS, .code = ABS_X, .value = LITEST_AUTO_ASSIGN },
|
||||
{ .type = EV_ABS, .code = ABS_Y, .value = LITEST_AUTO_ASSIGN },
|
||||
{ .type = EV_ABS, .code = ABS_MT_POSITION_X, .value = LITEST_AUTO_ASSIGN },
|
||||
{ .type = EV_ABS, .code = ABS_MT_POSITION_Y, .value = LITEST_AUTO_ASSIGN },
|
||||
{ .type = EV_SYN, .code = SYN_REPORT, .value = 0 },
|
||||
{ .type = -1, .code = -1 },
|
||||
};
|
||||
|
||||
static struct litest_device_interface interface = {
|
||||
.touch_down_events = down,
|
||||
.touch_move_events = move,
|
||||
};
|
||||
|
||||
static struct input_absinfo absinfo[] = {
|
||||
{ ABS_MT_SLOT, 0, 4, 0, 0, 0 },
|
||||
{ ABS_X, 0, 32767, 0, 0, 55 },
|
||||
{ ABS_Y, 0, 32767, 0, 0, 98 },
|
||||
{ ABS_MT_POSITION_X, 0, 32767, 0, 0, 55 },
|
||||
{ ABS_MT_POSITION_Y, 0, 32767, 0, 0, 98 },
|
||||
{ ABS_MT_TRACKING_ID, 0, 65535, 0, 0, 0 },
|
||||
{ .value = -1 },
|
||||
};
|
||||
|
||||
static struct input_id input_id = {
|
||||
.bustype = 0x3,
|
||||
.vendor = 0x2575,
|
||||
.product = 0x0204,
|
||||
.version = 0x111,
|
||||
};
|
||||
|
||||
static int events[] = {
|
||||
EV_KEY, BTN_TOUCH,
|
||||
EV_MSC, MSC_TIMESTAMP,
|
||||
INPUT_PROP_MAX, INPUT_PROP_DIRECT,
|
||||
-1, -1,
|
||||
};
|
||||
|
||||
static const char udev_rule[] =
|
||||
"ACTION==\"remove\", GOTO=\"totem_end\"\n"
|
||||
"KERNEL!=\"event*\", GOTO=\"totem_end\"\n"
|
||||
"\n"
|
||||
"ATTRS{name}==\"litest Advanced Silicon S.A. CoolTouch® System*\",\\\n"
|
||||
" ENV{LIBINPUT_DEVICE_GROUP}=\"dell-canvas-totem-group\"\n"
|
||||
"\n"
|
||||
"LABEL=\"totem_end\"";
|
||||
|
||||
TEST_DEVICE("dell-canvas-totem-touch",
|
||||
.type = LITEST_DELL_CANVAS_TOTEM_TOUCH,
|
||||
.features = LITEST_TOUCH,
|
||||
.interface = &interface,
|
||||
|
||||
.name = "Advanced Silicon S.A. CoolTouch® System",
|
||||
.id = &input_id,
|
||||
.events = events,
|
||||
.absinfo = absinfo,
|
||||
.udev_rule = udev_rule,
|
||||
)
|
||||
129
test/litest-device-dell-canvas-totem.c
Normal file
129
test/litest-device-dell-canvas-totem.c
Normal file
|
|
@ -0,0 +1,129 @@
|
|||
/*
|
||||
* Copyright © 2018 Red Hat, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "litest.h"
|
||||
#include "litest-int.h"
|
||||
|
||||
/* We don't expect anything but slot 0 to be used, ever */
|
||||
#define TOTEM_SLOT 0
|
||||
|
||||
static struct input_event down[] = {
|
||||
{ .type = EV_ABS, .code = ABS_MT_SLOT, .value = TOTEM_SLOT },
|
||||
{ .type = EV_ABS, .code = ABS_MT_TOOL_TYPE, .value = MT_TOOL_DIAL }, /* fixed value in device */
|
||||
{ .type = EV_ABS, .code = ABS_MT_TRACKING_ID, .value = LITEST_AUTO_ASSIGN },
|
||||
{ .type = EV_ABS, .code = ABS_MT_POSITION_X, .value = LITEST_AUTO_ASSIGN },
|
||||
{ .type = EV_ABS, .code = ABS_MT_POSITION_Y, .value = LITEST_AUTO_ASSIGN },
|
||||
{ .type = EV_ABS, .code = ABS_MT_ORIENTATION, .value = LITEST_AUTO_ASSIGN },
|
||||
{ .type = EV_ABS, .code = ABS_MT_TOUCH_MAJOR, .value = 718 }, /* fixed value in device */
|
||||
{ .type = EV_ABS, .code = ABS_MT_TOUCH_MINOR, .value = 718 },
|
||||
{ .type = EV_SYN, .code = SYN_REPORT, .value = 0 },
|
||||
{ .type = -1, .code = -1 },
|
||||
};
|
||||
|
||||
static struct input_event move[] = {
|
||||
{ .type = EV_ABS, .code = ABS_MT_SLOT, .value = TOTEM_SLOT },
|
||||
{ .type = EV_ABS, .code = ABS_MT_POSITION_X, .value = LITEST_AUTO_ASSIGN },
|
||||
{ .type = EV_ABS, .code = ABS_MT_POSITION_Y, .value = LITEST_AUTO_ASSIGN },
|
||||
{ .type = EV_ABS, .code = ABS_MT_ORIENTATION, .value = LITEST_AUTO_ASSIGN },
|
||||
{ .type = EV_ABS, .code = ABS_MT_TOUCH_MAJOR, .value = 718 }, /* fixed value in device */
|
||||
{ .type = EV_ABS, .code = ABS_MT_TOUCH_MINOR, .value = 718 },
|
||||
{ .type = EV_SYN, .code = SYN_REPORT, .value = 0 },
|
||||
{ .type = -1, .code = -1 },
|
||||
};
|
||||
|
||||
static struct input_event up[] = {
|
||||
{ .type = EV_ABS, .code = ABS_MT_SLOT, .value = TOTEM_SLOT },
|
||||
{ .type = EV_ABS, .code = ABS_MT_TRACKING_ID, .value = -1 },
|
||||
{ .type = EV_SYN, .code = SYN_REPORT, .value = 0 },
|
||||
{ .type = -1, .code = -1 },
|
||||
};
|
||||
|
||||
static int
|
||||
get_axis_default(struct litest_device *d, unsigned int evcode, int32_t *value)
|
||||
{
|
||||
switch (evcode) {
|
||||
case ABS_MT_ORIENTATION:
|
||||
*value = 0;
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static struct litest_device_interface interface = {
|
||||
.tablet_proximity_in_events = down,
|
||||
.tablet_proximity_out_events = up,
|
||||
.tablet_motion_events = move,
|
||||
|
||||
.get_axis_default = get_axis_default,
|
||||
};
|
||||
|
||||
static struct input_absinfo absinfo[] = {
|
||||
{ ABS_MT_SLOT, 0, 4, 0, 0, 0 },
|
||||
{ ABS_MT_TOUCH_MAJOR, 0, 32767, 0, 0, 10 },
|
||||
{ ABS_MT_TOUCH_MINOR, 0, 32767, 0, 0, 10 },
|
||||
{ ABS_MT_ORIENTATION, -89, 89, 0, 0, 0 },
|
||||
{ ABS_MT_POSITION_X, 0, 32767, 0, 0, 55 },
|
||||
{ ABS_MT_POSITION_Y, 0, 32767, 0, 0, 98 },
|
||||
/* The real device has a min/max of 10/10 but uinput didn't allow
|
||||
* this */
|
||||
{ ABS_MT_TOOL_TYPE, 9, 10, 0, 0, 0 },
|
||||
{ ABS_MT_TRACKING_ID, 0, 65535, 0, 0, 0 },
|
||||
{ .value = -1 },
|
||||
};
|
||||
|
||||
static struct input_id input_id = {
|
||||
.bustype = 0x3,
|
||||
.vendor = 0x2575,
|
||||
.product = 0x0204,
|
||||
.version = 0x111,
|
||||
};
|
||||
|
||||
static int events[] = {
|
||||
EV_KEY, BTN_0,
|
||||
EV_MSC, MSC_TIMESTAMP,
|
||||
INPUT_PROP_MAX, INPUT_PROP_DIRECT,
|
||||
-1, -1,
|
||||
};
|
||||
|
||||
static const char udev_rule[] =
|
||||
"ACTION==\"remove\", GOTO=\"totem_end\"\n"
|
||||
"KERNEL!=\"event*\", GOTO=\"totem_end\"\n"
|
||||
"\n"
|
||||
"ATTRS{name}==\"litest Advanced Silicon S.A. CoolTouch® System System Multi Axis*\",\\\n"
|
||||
" ENV{LIBINPUT_DEVICE_GROUP}=\"dell-canvas-totem-group\"\n"
|
||||
"\n"
|
||||
"LABEL=\"totem_end\"";
|
||||
|
||||
TEST_DEVICE("dell-canvas-totem",
|
||||
.type = LITEST_DELL_CANVAS_TOTEM,
|
||||
.features = LITEST_TOTEM | LITEST_TABLET,
|
||||
.interface = &interface,
|
||||
|
||||
.name = "Advanced Silicon S.A. CoolTouch® System System Multi Axis",
|
||||
.id = &input_id,
|
||||
.events = events,
|
||||
.absinfo = absinfo,
|
||||
.udev_rule = udev_rule,
|
||||
)
|
||||
|
|
@ -2164,16 +2164,22 @@ auto_assign_tablet_value(struct litest_device *d,
|
|||
int x, int y,
|
||||
struct axis_replacement *axes)
|
||||
{
|
||||
static int tracking_id;
|
||||
int value = ev->value;
|
||||
|
||||
if (value != LITEST_AUTO_ASSIGN || ev->type != EV_ABS)
|
||||
return value;
|
||||
|
||||
switch (ev->code) {
|
||||
case ABS_MT_TRACKING_ID:
|
||||
value = ++tracking_id;
|
||||
break;
|
||||
case ABS_X:
|
||||
case ABS_MT_POSITION_X:
|
||||
value = litest_scale(d, ABS_X, x);
|
||||
break;
|
||||
case ABS_Y:
|
||||
case ABS_MT_POSITION_Y:
|
||||
value = litest_scale(d, ABS_Y, y);
|
||||
break;
|
||||
default:
|
||||
|
|
@ -3376,6 +3382,24 @@ void litest_assert_tablet_proximity_event(struct libinput *li,
|
|||
libinput_event_destroy(event);
|
||||
}
|
||||
|
||||
void litest_assert_tablet_tip_event(struct libinput *li,
|
||||
enum libinput_tablet_tool_tip_state state)
|
||||
{
|
||||
struct libinput_event *event;
|
||||
struct libinput_event_tablet_tool *tev;
|
||||
enum libinput_event_type type = LIBINPUT_EVENT_TABLET_TOOL_TIP;
|
||||
|
||||
litest_wait_for_event(li);
|
||||
event = libinput_get_event(li);
|
||||
|
||||
litest_assert_notnull(event);
|
||||
litest_assert_event_type(event, type);
|
||||
tev = libinput_event_get_tablet_tool_event(event);
|
||||
litest_assert_int_eq(libinput_event_tablet_tool_get_tip_state(tev),
|
||||
state);
|
||||
libinput_event_destroy(event);
|
||||
}
|
||||
|
||||
struct libinput_event_tablet_pad *
|
||||
litest_is_pad_button_event(struct libinput_event *event,
|
||||
unsigned int button,
|
||||
|
|
|
|||
|
|
@ -277,6 +277,8 @@ enum litest_device_type {
|
|||
LITEST_AIPTEK,
|
||||
LITEST_TOUCHSCREEN_INVALID_RANGE,
|
||||
LITEST_TOUCHSCREEN_MT_TOOL_TYPE,
|
||||
LITEST_DELL_CANVAS_TOTEM,
|
||||
LITEST_DELL_CANVAS_TOTEM_TOUCH,
|
||||
};
|
||||
|
||||
enum litest_device_feature {
|
||||
|
|
@ -314,6 +316,7 @@ enum litest_device_feature {
|
|||
LITEST_NO_DEBOUNCE = bit(28),
|
||||
LITEST_TOOL_MOUSE = bit(29),
|
||||
LITEST_DIRECT = bit(30),
|
||||
LITEST_TOTEM = bit(31),
|
||||
|
||||
_LITEST_DEVICE_FEATURE__FORCE_SIZE = LONG_MAX,
|
||||
};
|
||||
|
|
@ -762,6 +765,10 @@ void
|
|||
litest_assert_tablet_proximity_event(struct libinput *li,
|
||||
enum libinput_tablet_tool_proximity_state state);
|
||||
|
||||
void
|
||||
litest_assert_tablet_tip_event(struct libinput *li,
|
||||
enum libinput_tablet_tool_tip_state state);
|
||||
|
||||
void
|
||||
litest_assert_pad_button_event(struct libinput *li,
|
||||
unsigned int button,
|
||||
|
|
|
|||
|
|
@ -1612,7 +1612,7 @@ TEST_COLLECTION(device)
|
|||
litest_add("device:wheel", device_wheel_only, LITEST_WHEEL, LITEST_RELATIVE|LITEST_ABSOLUTE|LITEST_TABLET);
|
||||
litest_add_no_device("device:accelerometer", device_accelerometer);
|
||||
|
||||
litest_add("device:udev tags", device_udev_tag_wacom_tablet, LITEST_TABLET, LITEST_ANY);
|
||||
litest_add("device:udev tags", device_udev_tag_wacom_tablet, LITEST_TABLET, LITEST_TOTEM);
|
||||
|
||||
litest_add_no_device("device:invalid rel events", device_nonpointer_rel);
|
||||
litest_add_no_device("device:invalid rel events", device_touchpad_rel);
|
||||
|
|
@ -1630,7 +1630,7 @@ TEST_COLLECTION(device)
|
|||
litest_add("device:size", device_has_size, LITEST_TOUCHPAD, LITEST_ANY);
|
||||
litest_add("device:size", device_has_size, LITEST_TABLET, LITEST_ANY);
|
||||
litest_add("device:size", device_has_no_size, LITEST_ANY,
|
||||
LITEST_TOUCHPAD|LITEST_TABLET|LITEST_TOUCH|LITEST_ABSOLUTE|LITEST_SINGLE_TOUCH);
|
||||
LITEST_TOUCHPAD|LITEST_TABLET|LITEST_TOUCH|LITEST_ABSOLUTE|LITEST_SINGLE_TOUCH|LITEST_TOTEM);
|
||||
|
||||
litest_add_for_device("device:output", device_get_output, LITEST_CALIBRATED_TOUCHSCREEN);
|
||||
litest_add("device:output", device_no_output, LITEST_RELATIVE, LITEST_ANY);
|
||||
|
|
|
|||
|
|
@ -36,6 +36,18 @@
|
|||
#include "evdev-tablet.h"
|
||||
#include "litest.h"
|
||||
|
||||
static inline unsigned int
|
||||
pick_stylus_or_btn0(struct litest_device *dev)
|
||||
{
|
||||
if (libevdev_has_event_code(dev->evdev, EV_KEY, BTN_STYLUS))
|
||||
return BTN_STYLUS;
|
||||
|
||||
if (libevdev_has_event_code(dev->evdev, EV_KEY, BTN_0))
|
||||
return BTN_0; /* totem */
|
||||
|
||||
abort();
|
||||
}
|
||||
|
||||
START_TEST(button_down_up)
|
||||
{
|
||||
struct litest_device *dev = litest_current_device();
|
||||
|
|
@ -47,39 +59,34 @@ START_TEST(button_down_up)
|
|||
{ ABS_PRESSURE, 0 },
|
||||
{ -1, -1 }
|
||||
};
|
||||
|
||||
if (!libevdev_has_event_code(dev->evdev, EV_KEY, BTN_STYLUS))
|
||||
return;
|
||||
unsigned int button = pick_stylus_or_btn0(dev);
|
||||
|
||||
litest_tablet_proximity_in(dev, 10, 10, axes);
|
||||
litest_drain_events(li);
|
||||
|
||||
litest_event(dev, EV_KEY, BTN_STYLUS, 1);
|
||||
litest_event(dev, EV_SYN, SYN_REPORT, 0);
|
||||
litest_button_click(dev, button, true);
|
||||
libinput_dispatch(li);
|
||||
|
||||
event = libinput_get_event(li);
|
||||
tev = litest_is_tablet_event(event, LIBINPUT_EVENT_TABLET_TOOL_BUTTON);
|
||||
ck_assert_int_eq(libinput_event_tablet_tool_get_button(tev),
|
||||
BTN_STYLUS);
|
||||
button);
|
||||
ck_assert_int_eq(libinput_event_tablet_tool_get_button_state(tev),
|
||||
LIBINPUT_BUTTON_STATE_PRESSED);
|
||||
libinput_event_destroy(event);
|
||||
litest_assert_empty_queue(li);
|
||||
|
||||
litest_event(dev, EV_KEY, BTN_STYLUS, 0);
|
||||
litest_event(dev, EV_SYN, SYN_REPORT, 0);
|
||||
litest_button_click(dev, button, false);
|
||||
libinput_dispatch(li);
|
||||
|
||||
event = libinput_get_event(li);
|
||||
tev = litest_is_tablet_event(event, LIBINPUT_EVENT_TABLET_TOOL_BUTTON);
|
||||
ck_assert_int_eq(libinput_event_tablet_tool_get_button(tev),
|
||||
BTN_STYLUS);
|
||||
button);
|
||||
ck_assert_int_eq(libinput_event_tablet_tool_get_button_state(tev),
|
||||
LIBINPUT_BUTTON_STATE_RELEASED);
|
||||
libinput_event_destroy(event);
|
||||
litest_assert_empty_queue(li);
|
||||
|
||||
}
|
||||
END_TEST
|
||||
|
||||
|
|
@ -95,25 +102,28 @@ START_TEST(button_seat_count)
|
|||
{ ABS_PRESSURE, 0 },
|
||||
{ -1, -1 }
|
||||
};
|
||||
unsigned int button = pick_stylus_or_btn0(dev);
|
||||
|
||||
if (!libevdev_has_event_code(dev->evdev, EV_KEY, BTN_STYLUS))
|
||||
return;
|
||||
switch (button) {
|
||||
case BTN_STYLUS:
|
||||
dev2 = litest_add_device(li, LITEST_WACOM_CINTIQ_13HDT_PEN);
|
||||
break;
|
||||
case BTN_0:
|
||||
dev2 = litest_add_device(li, LITEST_DELL_CANVAS_TOTEM);
|
||||
break;
|
||||
}
|
||||
|
||||
dev2 = litest_add_device(li, LITEST_WACOM_CINTIQ_13HDT_PEN);
|
||||
litest_tablet_proximity_in(dev, 10, 10, axes);
|
||||
litest_tablet_proximity_in(dev2, 10, 10, axes);
|
||||
litest_drain_events(li);
|
||||
|
||||
litest_event(dev, EV_KEY, BTN_STYLUS, 1);
|
||||
litest_event(dev, EV_SYN, SYN_REPORT, 0);
|
||||
litest_event(dev2, EV_KEY, BTN_STYLUS, 1);
|
||||
litest_event(dev2, EV_SYN, SYN_REPORT, 0);
|
||||
litest_button_click(dev, button, true);
|
||||
litest_button_click(dev2, button, true);
|
||||
libinput_dispatch(li);
|
||||
|
||||
event = libinput_get_event(li);
|
||||
tev = litest_is_tablet_event(event, LIBINPUT_EVENT_TABLET_TOOL_BUTTON);
|
||||
ck_assert_int_eq(libinput_event_tablet_tool_get_button(tev),
|
||||
BTN_STYLUS);
|
||||
ck_assert_int_eq(libinput_event_tablet_tool_get_button(tev), button);
|
||||
ck_assert_int_eq(libinput_event_tablet_tool_get_button_state(tev),
|
||||
LIBINPUT_BUTTON_STATE_PRESSED);
|
||||
ck_assert_int_eq(libinput_event_tablet_tool_get_seat_button_count(tev), 1);
|
||||
|
|
@ -121,8 +131,7 @@ START_TEST(button_seat_count)
|
|||
|
||||
event = libinput_get_event(li);
|
||||
tev = litest_is_tablet_event(event, LIBINPUT_EVENT_TABLET_TOOL_BUTTON);
|
||||
ck_assert_int_eq(libinput_event_tablet_tool_get_button(tev),
|
||||
BTN_STYLUS);
|
||||
ck_assert_int_eq(libinput_event_tablet_tool_get_button(tev), button);
|
||||
ck_assert_int_eq(libinput_event_tablet_tool_get_button_state(tev),
|
||||
LIBINPUT_BUTTON_STATE_PRESSED);
|
||||
ck_assert_int_eq(libinput_event_tablet_tool_get_seat_button_count(tev), 2);
|
||||
|
|
@ -130,18 +139,15 @@ START_TEST(button_seat_count)
|
|||
|
||||
litest_assert_empty_queue(li);
|
||||
|
||||
litest_event(dev2, EV_KEY, BTN_STYLUS, 0);
|
||||
litest_event(dev2, EV_SYN, SYN_REPORT, 0);
|
||||
litest_event(dev, EV_KEY, BTN_STYLUS, 0);
|
||||
litest_event(dev, EV_SYN, SYN_REPORT, 0);
|
||||
litest_button_click(dev2, button, false);
|
||||
litest_button_click(dev, button, false);
|
||||
libinput_dispatch(li);
|
||||
|
||||
event = libinput_get_event(li);
|
||||
tev = litest_is_tablet_event(event, LIBINPUT_EVENT_TABLET_TOOL_BUTTON);
|
||||
ck_assert_int_eq(libinput_event_tablet_tool_get_button_state(tev),
|
||||
LIBINPUT_BUTTON_STATE_RELEASED);
|
||||
ck_assert_int_eq(libinput_event_tablet_tool_get_button(tev),
|
||||
BTN_STYLUS);
|
||||
ck_assert_int_eq(libinput_event_tablet_tool_get_button(tev), button);
|
||||
ck_assert_int_eq(libinput_event_tablet_tool_get_seat_button_count(tev), 1);
|
||||
libinput_event_destroy(event);
|
||||
|
||||
|
|
@ -149,8 +155,7 @@ START_TEST(button_seat_count)
|
|||
tev = litest_is_tablet_event(event, LIBINPUT_EVENT_TABLET_TOOL_BUTTON);
|
||||
ck_assert_int_eq(libinput_event_tablet_tool_get_button_state(tev),
|
||||
LIBINPUT_BUTTON_STATE_RELEASED);
|
||||
ck_assert_int_eq(libinput_event_tablet_tool_get_button(tev),
|
||||
BTN_STYLUS);
|
||||
ck_assert_int_eq(libinput_event_tablet_tool_get_button(tev), button);
|
||||
ck_assert_int_eq(libinput_event_tablet_tool_get_seat_button_count(tev), 0);
|
||||
libinput_event_destroy(event);
|
||||
litest_assert_empty_queue(li);
|
||||
|
|
@ -818,12 +823,12 @@ START_TEST(tip_state_button)
|
|||
{ ABS_PRESSURE, 0 },
|
||||
{ -1, -1 }
|
||||
};
|
||||
unsigned int button = pick_stylus_or_btn0(dev);
|
||||
|
||||
litest_tablet_proximity_in(dev, 10, 10, axes);
|
||||
litest_drain_events(li);
|
||||
|
||||
litest_event(dev, EV_KEY, BTN_STYLUS, 1);
|
||||
litest_event(dev, EV_SYN, SYN_REPORT, 0);
|
||||
litest_button_click(dev, button, true);
|
||||
libinput_dispatch(li);
|
||||
|
||||
event = libinput_get_event(li);
|
||||
|
|
@ -841,8 +846,7 @@ START_TEST(tip_state_button)
|
|||
litest_pop_event_frame(dev);
|
||||
litest_drain_events(li);
|
||||
|
||||
litest_event(dev, EV_KEY, BTN_STYLUS, 0);
|
||||
litest_event(dev, EV_SYN, SYN_REPORT, 0);
|
||||
litest_button_click(dev, button, false);
|
||||
libinput_dispatch(li);
|
||||
|
||||
event = libinput_get_event(li);
|
||||
|
|
@ -860,8 +864,7 @@ START_TEST(tip_state_button)
|
|||
litest_pop_event_frame(dev);
|
||||
litest_drain_events(li);
|
||||
|
||||
litest_event(dev, EV_KEY, BTN_STYLUS, 1);
|
||||
litest_event(dev, EV_SYN, SYN_REPORT, 0);
|
||||
litest_button_click(dev, button, true);
|
||||
libinput_dispatch(li);
|
||||
|
||||
event = libinput_get_event(li);
|
||||
|
|
@ -871,8 +874,7 @@ START_TEST(tip_state_button)
|
|||
LIBINPUT_TABLET_TOOL_TIP_UP);
|
||||
libinput_event_destroy(event);
|
||||
|
||||
litest_event(dev, EV_KEY, BTN_STYLUS, 0);
|
||||
litest_event(dev, EV_SYN, SYN_REPORT, 0);
|
||||
litest_button_click(dev, button, false);
|
||||
libinput_dispatch(li);
|
||||
|
||||
event = libinput_get_event(li);
|
||||
|
|
@ -929,6 +931,7 @@ START_TEST(proximity_in_out)
|
|||
struct libinput *li = dev->libinput;
|
||||
struct libinput_event_tablet_tool *tablet_event;
|
||||
struct libinput_event *event;
|
||||
enum libinput_tablet_tool_type type;
|
||||
bool have_tool_update = false,
|
||||
have_proximity_out = false;
|
||||
|
||||
|
|
@ -940,6 +943,15 @@ START_TEST(proximity_in_out)
|
|||
|
||||
litest_drain_events(li);
|
||||
|
||||
switch (dev->which) {
|
||||
case LITEST_DELL_CANVAS_TOTEM:
|
||||
type = LIBINPUT_TABLET_TOOL_TYPE_TOTEM;
|
||||
break;
|
||||
default:
|
||||
type = LIBINPUT_TABLET_TOOL_TYPE_PEN;
|
||||
break;
|
||||
}
|
||||
|
||||
litest_tablet_proximity_in(dev, 10, 10, axes);
|
||||
libinput_dispatch(li);
|
||||
|
||||
|
|
@ -952,8 +964,7 @@ START_TEST(proximity_in_out)
|
|||
have_tool_update = true;
|
||||
tablet_event = libinput_event_get_tablet_tool_event(event);
|
||||
tool = libinput_event_tablet_tool_get_tool(tablet_event);
|
||||
ck_assert_int_eq(libinput_tablet_tool_get_type(tool),
|
||||
LIBINPUT_TABLET_TOOL_TYPE_PEN);
|
||||
ck_assert_int_eq(libinput_tablet_tool_get_type(tool), type);
|
||||
}
|
||||
libinput_event_destroy(event);
|
||||
}
|
||||
|
|
@ -994,19 +1005,21 @@ START_TEST(proximity_in_button_down)
|
|||
{ ABS_PRESSURE, 0 },
|
||||
{ -1, -1 }
|
||||
};
|
||||
unsigned int button = pick_stylus_or_btn0(dev);
|
||||
|
||||
litest_drain_events(li);
|
||||
|
||||
litest_push_event_frame(dev);
|
||||
litest_tablet_proximity_in(dev, 10, 10, axes);
|
||||
litest_event(dev, EV_KEY, BTN_STYLUS, 1);
|
||||
litest_event(dev, EV_KEY, button, 1);
|
||||
litest_pop_event_frame(dev);
|
||||
libinput_dispatch(li);
|
||||
|
||||
litest_assert_tablet_proximity_event(li,
|
||||
LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_IN);
|
||||
litest_drain_events_of_type(li, LIBINPUT_EVENT_TABLET_TOOL_TIP, -1);
|
||||
litest_assert_tablet_button_event(li,
|
||||
BTN_STYLUS,
|
||||
button,
|
||||
LIBINPUT_BUTTON_STATE_PRESSED);
|
||||
litest_assert_empty_queue(li);
|
||||
}
|
||||
|
|
@ -1021,16 +1034,16 @@ START_TEST(proximity_out_button_up)
|
|||
{ ABS_PRESSURE, 0 },
|
||||
{ -1, -1 }
|
||||
};
|
||||
unsigned int button = pick_stylus_or_btn0(dev);
|
||||
|
||||
litest_tablet_proximity_in(dev, 10, 10, axes);
|
||||
|
||||
litest_event(dev, EV_KEY, BTN_STYLUS, 1);
|
||||
litest_event(dev, EV_SYN, SYN_REPORT, 0);
|
||||
litest_button_click(dev, button, true);
|
||||
litest_drain_events(li);
|
||||
|
||||
litest_push_event_frame(dev);
|
||||
litest_tablet_proximity_out(dev);
|
||||
litest_event(dev, EV_KEY, BTN_STYLUS, 0);
|
||||
litest_event(dev, EV_KEY, button, 0);
|
||||
litest_pop_event_frame(dev);
|
||||
libinput_dispatch(li);
|
||||
|
||||
|
|
@ -1038,8 +1051,9 @@ START_TEST(proximity_out_button_up)
|
|||
libinput_dispatch(li);
|
||||
|
||||
litest_assert_tablet_button_event(li,
|
||||
BTN_STYLUS,
|
||||
button,
|
||||
LIBINPUT_BUTTON_STATE_RELEASED);
|
||||
litest_drain_events_of_type(li, LIBINPUT_EVENT_TABLET_TOOL_TIP, -1);
|
||||
litest_assert_tablet_proximity_event(li,
|
||||
LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_OUT);
|
||||
litest_assert_empty_queue(li);
|
||||
|
|
@ -1182,6 +1196,8 @@ START_TEST(proximity_has_axes)
|
|||
litest_assert_double_ne(y, 0);
|
||||
}
|
||||
|
||||
litest_drain_events_of_type(li, LIBINPUT_EVENT_TABLET_TOOL_TIP, -1);
|
||||
|
||||
litest_assert_empty_queue(li);
|
||||
libinput_event_destroy(event);
|
||||
|
||||
|
|
@ -1219,6 +1235,8 @@ START_TEST(proximity_has_axes)
|
|||
litest_timeout_tablet_proxout();
|
||||
libinput_dispatch(li);
|
||||
|
||||
litest_drain_events_of_type(li, LIBINPUT_EVENT_TABLET_TOOL_TIP, -1);
|
||||
|
||||
event = libinput_get_event(li);
|
||||
tablet_event = litest_is_tablet_event(event,
|
||||
LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY);
|
||||
|
|
@ -1917,12 +1935,12 @@ START_TEST(motion_event_state)
|
|||
struct libinput_event_tablet_tool *tablet_event;
|
||||
int test_x, test_y;
|
||||
double last_x, last_y;
|
||||
|
||||
struct axis_replacement axes[] = {
|
||||
{ ABS_DISTANCE, 10 },
|
||||
{ ABS_PRESSURE, 0 },
|
||||
{ -1, -1 }
|
||||
};
|
||||
unsigned int button = pick_stylus_or_btn0(dev);
|
||||
|
||||
litest_drain_events(li);
|
||||
litest_tablet_proximity_in(dev, 5, 100, axes);
|
||||
|
|
@ -1941,8 +1959,7 @@ START_TEST(motion_event_state)
|
|||
last_y = libinput_event_tablet_tool_get_y(tablet_event);
|
||||
|
||||
/* mark with a button event, then go back to bottom/left */
|
||||
litest_event(dev, EV_KEY, BTN_STYLUS, 1);
|
||||
litest_event(dev, EV_SYN, SYN_REPORT, 0);
|
||||
litest_button_click(dev, button, true);
|
||||
|
||||
for (test_x = 100, test_y = 0; test_x > 0; test_x -= 10, test_y += 10)
|
||||
litest_tablet_motion(dev, test_x, test_y, axes);
|
||||
|
|
@ -2692,6 +2709,8 @@ START_TEST(tool_in_prox_before_start)
|
|||
serial = libinput_tablet_tool_get_serial(tool);
|
||||
libinput_event_destroy(event);
|
||||
|
||||
litest_drain_events_of_type(li, LIBINPUT_EVENT_TABLET_TOOL_TIP, -1);
|
||||
|
||||
litest_tablet_motion(dev, 30, 40, axes);
|
||||
libinput_dispatch(li);
|
||||
event = libinput_get_event(li);
|
||||
|
|
@ -5606,9 +5625,13 @@ TEST_COLLECTION(tablet)
|
|||
litest_add("tablet:tool", tool_capability, LITEST_TABLET, LITEST_ANY);
|
||||
litest_add_no_device("tablet:tool", tool_capabilities);
|
||||
litest_add("tablet:tool", tool_type, LITEST_TABLET, LITEST_ANY);
|
||||
litest_add("tablet:tool", tool_in_prox_before_start, LITEST_TABLET, LITEST_ANY);
|
||||
litest_add("tablet:tool", tool_in_prox_before_start, LITEST_TABLET, LITEST_TOTEM);
|
||||
litest_add("tablet:tool", tool_direct_switch_warning, LITEST_TABLET, LITEST_ANY);
|
||||
litest_add("tablet:tool", tool_direct_switch_skip_tool_update, LITEST_TABLET, LITEST_ANY);
|
||||
|
||||
/* Tablets hold back the proximity until the first event from the
|
||||
* kernel, the totem sends it immediately */
|
||||
litest_add("tablet:tool", tool_in_prox_before_start, LITEST_TABLET, LITEST_TOTEM);
|
||||
litest_add("tablet:tool_serial", tool_unique, LITEST_TABLET | LITEST_TOOL_SERIAL, LITEST_ANY);
|
||||
litest_add("tablet:tool_serial", tool_serial, LITEST_TABLET | LITEST_TOOL_SERIAL, LITEST_ANY);
|
||||
litest_add("tablet:tool_serial", tool_id, LITEST_TABLET | LITEST_TOOL_SERIAL, LITEST_ANY);
|
||||
|
|
@ -5656,7 +5679,7 @@ TEST_COLLECTION(tablet)
|
|||
litest_add_for_device("tablet:left_handed", left_handed_mouse_rotation, LITEST_WACOM_INTUOS);
|
||||
litest_add_for_device("tablet:left_handed", left_handed_artpen_rotation, LITEST_WACOM_INTUOS);
|
||||
litest_add_for_device("tablet:left_handed", no_left_handed, LITEST_WACOM_CINTIQ);
|
||||
litest_add("tablet:pad", pad_buttons_ignored, LITEST_TABLET, LITEST_ANY);
|
||||
litest_add("tablet:pad", pad_buttons_ignored, LITEST_TABLET, LITEST_TOTEM);
|
||||
litest_add("tablet:mouse", mouse_tool, LITEST_TABLET | LITEST_TOOL_MOUSE, LITEST_ANY);
|
||||
litest_add("tablet:mouse", mouse_buttons, LITEST_TABLET | LITEST_TOOL_MOUSE, LITEST_ANY);
|
||||
litest_add("tablet:mouse", mouse_rotation, LITEST_TABLET | LITEST_TOOL_MOUSE, LITEST_ANY);
|
||||
|
|
@ -5669,9 +5692,10 @@ TEST_COLLECTION(tablet)
|
|||
litest_add("tablet:time", tablet_time_usec, LITEST_TABLET, LITEST_ANY);
|
||||
litest_add("tablet:pressure", tablet_pressure_distance_exclusive, LITEST_TABLET | LITEST_DISTANCE, LITEST_ANY);
|
||||
|
||||
litest_add("tablet:calibration", tablet_calibration_has_matrix, LITEST_TABLET, LITEST_ANY);
|
||||
litest_add("tablet:calibration", tablet_calibration_set_matrix, LITEST_TABLET, LITEST_ANY);
|
||||
litest_add("tablet:calibration", tablet_calibration_set_matrix_delta, LITEST_TABLET, LITEST_ANY);
|
||||
/* The totem doesn't need calibration */
|
||||
litest_add("tablet:calibration", tablet_calibration_has_matrix, LITEST_TABLET, LITEST_TOTEM);
|
||||
litest_add("tablet:calibration", tablet_calibration_set_matrix, LITEST_TABLET, LITEST_TOTEM);
|
||||
litest_add("tablet:calibration", tablet_calibration_set_matrix_delta, LITEST_TABLET, LITEST_TOTEM);
|
||||
|
||||
litest_add("tablet:pressure", tablet_pressure_min_max, LITEST_TABLET, LITEST_ANY);
|
||||
litest_add_for_device("tablet:pressure", tablet_pressure_range, LITEST_WACOM_INTUOS);
|
||||
|
|
|
|||
605
test/test-totem.c
Normal file
605
test/test-totem.c
Normal file
|
|
@ -0,0 +1,605 @@
|
|||
/*
|
||||
* Copyright © 2018 Red Hat, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <check.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <libinput.h>
|
||||
#include <unistd.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "libinput-util.h"
|
||||
#include "evdev-tablet.h"
|
||||
#include "litest.h"
|
||||
|
||||
START_TEST(totem_type)
|
||||
{
|
||||
struct litest_device *dev = litest_current_device();
|
||||
struct libinput *li = dev->libinput;
|
||||
struct libinput_event *event;
|
||||
struct libinput_event_tablet_tool *t;
|
||||
struct libinput_tablet_tool *tool;
|
||||
|
||||
litest_drain_events(li);
|
||||
|
||||
litest_tablet_proximity_in(dev, 50, 50, NULL);
|
||||
libinput_dispatch(li);
|
||||
|
||||
event = libinput_get_event(li);
|
||||
t = litest_is_tablet_event(event,
|
||||
LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY);
|
||||
tool = libinput_event_tablet_tool_get_tool(t);
|
||||
|
||||
ck_assert_int_eq(libinput_tablet_tool_get_type(tool),
|
||||
LIBINPUT_TABLET_TOOL_TYPE_TOTEM);
|
||||
libinput_event_destroy(event);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(totem_axes)
|
||||
{
|
||||
struct litest_device *dev = litest_current_device();
|
||||
struct libinput *li = dev->libinput;
|
||||
struct libinput_event *event;
|
||||
struct libinput_event_tablet_tool *t;
|
||||
struct libinput_tablet_tool *tool;
|
||||
|
||||
litest_drain_events(li);
|
||||
|
||||
litest_tablet_proximity_in(dev, 50, 50, NULL);
|
||||
libinput_dispatch(li);
|
||||
|
||||
event = libinput_get_event(li);
|
||||
t = litest_is_tablet_event(event,
|
||||
LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY);
|
||||
tool = libinput_event_tablet_tool_get_tool(t);
|
||||
|
||||
ck_assert(libinput_tablet_tool_has_rotation(tool));
|
||||
ck_assert(libinput_tablet_tool_has_size(tool));
|
||||
ck_assert(libinput_tablet_tool_has_button(tool, BTN_0));
|
||||
|
||||
libinput_event_destroy(event);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(totem_proximity_in_out)
|
||||
{
|
||||
struct litest_device *dev = litest_current_device();
|
||||
struct libinput *li = dev->libinput;
|
||||
struct libinput_event *event;
|
||||
struct libinput_event_tablet_tool *t;
|
||||
|
||||
litest_drain_events(li);
|
||||
|
||||
litest_tablet_proximity_in(dev, 50, 50, NULL);
|
||||
libinput_dispatch(li);
|
||||
|
||||
event = libinput_get_event(li);
|
||||
t = litest_is_tablet_event(event,
|
||||
LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY);
|
||||
ck_assert_int_eq(libinput_event_tablet_tool_get_proximity_state(t),
|
||||
LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_IN);
|
||||
libinput_event_destroy(event);
|
||||
|
||||
event = libinput_get_event(li);
|
||||
t = litest_is_tablet_event(event,
|
||||
LIBINPUT_EVENT_TABLET_TOOL_TIP);
|
||||
ck_assert_int_eq(libinput_event_tablet_tool_get_tip_state(t),
|
||||
LIBINPUT_TABLET_TOOL_TIP_DOWN);
|
||||
libinput_event_destroy(event);
|
||||
|
||||
litest_assert_empty_queue(li);
|
||||
litest_tablet_proximity_out(dev);
|
||||
libinput_dispatch(li);
|
||||
|
||||
event = libinput_get_event(li);
|
||||
t = litest_is_tablet_event(event,
|
||||
LIBINPUT_EVENT_TABLET_TOOL_TIP);
|
||||
ck_assert_int_eq(libinput_event_tablet_tool_get_tip_state(t),
|
||||
LIBINPUT_TABLET_TOOL_TIP_UP);
|
||||
libinput_event_destroy(event);
|
||||
|
||||
event = libinput_get_event(li);
|
||||
t = litest_is_tablet_event(event,
|
||||
LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY);
|
||||
ck_assert_int_eq(libinput_event_tablet_tool_get_proximity_state(t),
|
||||
LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_OUT);
|
||||
libinput_event_destroy(event);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(totem_proximity_in_on_init)
|
||||
{
|
||||
struct litest_device *dev = litest_current_device();
|
||||
struct libinput *li;
|
||||
struct libinput_event *event;
|
||||
struct libinput_event_tablet_tool *t;
|
||||
const char *devnode;
|
||||
double x, y;
|
||||
double w, h;
|
||||
const struct input_absinfo *abs;
|
||||
|
||||
abs = libevdev_get_abs_info(dev->evdev, ABS_MT_POSITION_X);
|
||||
w = (abs->maximum - abs->minimum + 1)/abs->resolution;
|
||||
abs = libevdev_get_abs_info(dev->evdev, ABS_MT_POSITION_Y);
|
||||
h = (abs->maximum - abs->minimum + 1)/abs->resolution;
|
||||
|
||||
litest_tablet_proximity_in(dev, 50, 50, NULL);
|
||||
|
||||
/* for simplicity, we create a new litest context */
|
||||
devnode = libevdev_uinput_get_devnode(dev->uinput);
|
||||
li = litest_create_context();
|
||||
libinput_path_add_device(li, devnode);
|
||||
libinput_dispatch(li);
|
||||
|
||||
litest_wait_for_event_of_type(li,
|
||||
LIBINPUT_EVENT_DEVICE_ADDED,
|
||||
-1);
|
||||
event = libinput_get_event(li);
|
||||
libinput_event_destroy(event);
|
||||
|
||||
event = libinput_get_event(li);
|
||||
t = litest_is_tablet_event(event,
|
||||
LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY);
|
||||
ck_assert_int_eq(libinput_event_tablet_tool_get_proximity_state(t),
|
||||
LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_IN);
|
||||
x = libinput_event_tablet_tool_get_x(t);
|
||||
y = libinput_event_tablet_tool_get_y(t);
|
||||
|
||||
ck_assert_double_gt(x, w/2 - 1);
|
||||
ck_assert_double_lt(x, w/2 + 1);
|
||||
ck_assert_double_gt(y, h/2 - 1);
|
||||
ck_assert_double_lt(y, h/2 + 1);
|
||||
|
||||
libinput_event_destroy(event);
|
||||
|
||||
event = libinput_get_event(li);
|
||||
t = litest_is_tablet_event(event,
|
||||
LIBINPUT_EVENT_TABLET_TOOL_TIP);
|
||||
ck_assert_int_eq(libinput_event_tablet_tool_get_tip_state(t),
|
||||
LIBINPUT_TABLET_TOOL_TIP_DOWN);
|
||||
x = libinput_event_tablet_tool_get_x(t);
|
||||
y = libinput_event_tablet_tool_get_y(t);
|
||||
|
||||
ck_assert_double_gt(x, w/2 - 1);
|
||||
ck_assert_double_lt(x, w/2 + 1);
|
||||
ck_assert_double_gt(y, h/2 - 1);
|
||||
ck_assert_double_lt(y, h/2 + 1);
|
||||
|
||||
libinput_event_destroy(event);
|
||||
|
||||
litest_assert_empty_queue(li);
|
||||
|
||||
libinput_unref(li);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(totem_proximity_out_on_suspend)
|
||||
{
|
||||
struct litest_device *dev = litest_current_device();
|
||||
struct libinput *li;
|
||||
struct libinput_event *event;
|
||||
struct libinput_event_tablet_tool *t;
|
||||
const char *devnode;
|
||||
|
||||
/* for simplicity, we create a new litest context */
|
||||
devnode = libevdev_uinput_get_devnode(dev->uinput);
|
||||
li = litest_create_context();
|
||||
libinput_path_add_device(li, devnode);
|
||||
|
||||
litest_tablet_proximity_in(dev, 50, 50, NULL);
|
||||
litest_drain_events(li);
|
||||
|
||||
libinput_suspend(li);
|
||||
|
||||
libinput_dispatch(li);
|
||||
event = libinput_get_event(li);
|
||||
t = litest_is_tablet_event(event,
|
||||
LIBINPUT_EVENT_TABLET_TOOL_TIP);
|
||||
ck_assert_int_eq(libinput_event_tablet_tool_get_tip_state(t),
|
||||
LIBINPUT_TABLET_TOOL_TIP_UP);
|
||||
libinput_event_destroy(event);
|
||||
|
||||
event = libinput_get_event(li);
|
||||
t = litest_is_tablet_event(event,
|
||||
LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY);
|
||||
ck_assert_int_eq(libinput_event_tablet_tool_get_proximity_state(t),
|
||||
LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_OUT);
|
||||
libinput_event_destroy(event);
|
||||
|
||||
litest_assert_only_typed_events(li, LIBINPUT_EVENT_DEVICE_REMOVED);
|
||||
libinput_unref(li);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(totem_motion)
|
||||
{
|
||||
struct litest_device *dev = litest_current_device();
|
||||
struct libinput *li = dev->libinput;
|
||||
struct libinput_event *event;
|
||||
double x = 50, y = 50;
|
||||
double current_x, current_y, old_x, old_y;
|
||||
|
||||
litest_tablet_proximity_in(dev, x, y, NULL);
|
||||
litest_drain_events(li);
|
||||
|
||||
for (int i = 0; i < 30; i++, x++, y--) {
|
||||
struct libinput_event_tablet_tool *t;
|
||||
|
||||
litest_tablet_motion(dev, x + 1, y + 1, NULL);
|
||||
libinput_dispatch(li);
|
||||
|
||||
event = libinput_get_event(li);
|
||||
t = litest_is_tablet_event(event, LIBINPUT_EVENT_TABLET_TOOL_AXIS);
|
||||
|
||||
ck_assert(libinput_event_tablet_tool_x_has_changed(t));
|
||||
ck_assert(libinput_event_tablet_tool_y_has_changed(t));
|
||||
|
||||
current_x = libinput_event_tablet_tool_get_x(t);
|
||||
current_y = libinput_event_tablet_tool_get_y(t);
|
||||
if (i != 0) {
|
||||
ck_assert_double_gt(current_x, old_x);
|
||||
ck_assert_double_lt(current_y, old_y);
|
||||
}
|
||||
old_x = current_x;
|
||||
old_y = current_y;
|
||||
|
||||
libinput_event_destroy(event);
|
||||
}
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(totem_rotation)
|
||||
{
|
||||
struct litest_device *dev = litest_current_device();
|
||||
struct libinput *li = dev->libinput;
|
||||
struct libinput_event *event;
|
||||
double r, old_r;
|
||||
struct axis_replacement axes[] = {
|
||||
{ ABS_MT_ORIENTATION, 50 }, /* mid-point is 0 */
|
||||
{ -1, -1 }
|
||||
};
|
||||
|
||||
litest_tablet_proximity_in(dev, 50, 50, axes);
|
||||
litest_drain_events(li);
|
||||
|
||||
old_r = 360;
|
||||
|
||||
for (int i = 1; i < 30; i++) {
|
||||
struct libinput_event_tablet_tool *t;
|
||||
|
||||
|
||||
litest_axis_set_value(axes, ABS_MT_ORIENTATION, 50 + i);
|
||||
litest_tablet_motion(dev, 50, 50, axes);
|
||||
libinput_dispatch(li);
|
||||
|
||||
event = libinput_get_event(li);
|
||||
t = litest_is_tablet_event(event, LIBINPUT_EVENT_TABLET_TOOL_AXIS);
|
||||
|
||||
ck_assert(!libinput_event_tablet_tool_x_has_changed(t));
|
||||
ck_assert(!libinput_event_tablet_tool_y_has_changed(t));
|
||||
ck_assert(libinput_event_tablet_tool_rotation_has_changed(t));
|
||||
|
||||
r = libinput_event_tablet_tool_get_rotation(t);
|
||||
ck_assert_double_lt(r, old_r);
|
||||
old_r = r;
|
||||
|
||||
libinput_event_destroy(event);
|
||||
}
|
||||
|
||||
old_r = 0;
|
||||
|
||||
for (int i = 1; i < 30; i++) {
|
||||
struct libinput_event_tablet_tool *t;
|
||||
|
||||
|
||||
litest_axis_set_value(axes, ABS_MT_ORIENTATION, 50 - i);
|
||||
litest_tablet_motion(dev, 50, 50, axes);
|
||||
libinput_dispatch(li);
|
||||
|
||||
event = libinput_get_event(li);
|
||||
t = litest_is_tablet_event(event, LIBINPUT_EVENT_TABLET_TOOL_AXIS);
|
||||
|
||||
ck_assert(!libinput_event_tablet_tool_x_has_changed(t));
|
||||
ck_assert(!libinput_event_tablet_tool_y_has_changed(t));
|
||||
ck_assert(libinput_event_tablet_tool_rotation_has_changed(t));
|
||||
|
||||
r = libinput_event_tablet_tool_get_rotation(t);
|
||||
ck_assert_double_gt(r, old_r);
|
||||
old_r = r;
|
||||
|
||||
libinput_event_destroy(event);
|
||||
}
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(totem_size)
|
||||
{
|
||||
struct litest_device *dev = litest_current_device();
|
||||
struct libinput *li = dev->libinput;
|
||||
struct libinput_event *event;
|
||||
struct libinput_event_tablet_tool *t;
|
||||
double smin, smaj;
|
||||
|
||||
litest_drain_events(li);
|
||||
|
||||
litest_tablet_proximity_in(dev, 50, 50, NULL);
|
||||
libinput_dispatch(li);
|
||||
|
||||
event = libinput_get_event(li);
|
||||
t = litest_is_tablet_event(event, LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY);
|
||||
ck_assert(libinput_event_tablet_tool_size_major_has_changed(t));
|
||||
ck_assert(libinput_event_tablet_tool_size_minor_has_changed(t));
|
||||
smaj = libinput_event_tablet_tool_get_size_major(t);
|
||||
smin = libinput_event_tablet_tool_get_size_minor(t);
|
||||
libinput_event_destroy(event);
|
||||
|
||||
ck_assert_double_eq(smaj, 71.8);
|
||||
ck_assert_double_eq(smin, 71.8);
|
||||
|
||||
litest_drain_events(li);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(totem_button)
|
||||
{
|
||||
struct litest_device *dev = litest_current_device();
|
||||
struct libinput *li = dev->libinput;
|
||||
struct libinput_event *event;
|
||||
struct libinput_event_tablet_tool *t;
|
||||
|
||||
litest_tablet_proximity_in(dev, 30, 40, NULL);
|
||||
litest_drain_events(li);
|
||||
|
||||
litest_button_click(dev, BTN_0, true);
|
||||
libinput_dispatch(li);
|
||||
event = libinput_get_event(li);
|
||||
t = litest_is_tablet_event(event, LIBINPUT_EVENT_TABLET_TOOL_BUTTON);
|
||||
ck_assert_int_eq(libinput_event_tablet_tool_get_button(t), BTN_0);
|
||||
ck_assert_int_eq(libinput_event_tablet_tool_get_button_state(t),
|
||||
LIBINPUT_BUTTON_STATE_PRESSED);
|
||||
ck_assert_int_eq(libinput_event_tablet_tool_get_tip_state(t),
|
||||
LIBINPUT_TABLET_TOOL_TIP_DOWN);
|
||||
libinput_event_destroy(event);
|
||||
|
||||
litest_button_click(dev, BTN_0, false);
|
||||
libinput_dispatch(li);
|
||||
|
||||
event = libinput_get_event(li);
|
||||
t = litest_is_tablet_event(event, LIBINPUT_EVENT_TABLET_TOOL_BUTTON);
|
||||
ck_assert_int_eq(libinput_event_tablet_tool_get_button(t), BTN_0);
|
||||
ck_assert_int_eq(libinput_event_tablet_tool_get_button_state(t),
|
||||
LIBINPUT_BUTTON_STATE_RELEASED);
|
||||
ck_assert_int_eq(libinput_event_tablet_tool_get_tip_state(t),
|
||||
LIBINPUT_TABLET_TOOL_TIP_DOWN);
|
||||
libinput_event_destroy(event);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(totem_button_down_on_init)
|
||||
{
|
||||
struct litest_device *dev = litest_current_device();
|
||||
struct libinput *li;
|
||||
struct libinput_event *event;
|
||||
struct libinput_event_tablet_tool *t;
|
||||
const char *devnode;
|
||||
|
||||
litest_tablet_proximity_in(dev, 50, 50, NULL);
|
||||
litest_button_click(dev, BTN_0, true);
|
||||
|
||||
/* for simplicity, we create a new litest context */
|
||||
devnode = libevdev_uinput_get_devnode(dev->uinput);
|
||||
li = litest_create_context();
|
||||
libinput_path_add_device(li, devnode);
|
||||
libinput_dispatch(li);
|
||||
|
||||
litest_wait_for_event_of_type(li,
|
||||
LIBINPUT_EVENT_DEVICE_ADDED,
|
||||
-1);
|
||||
event = libinput_get_event(li);
|
||||
libinput_event_destroy(event);
|
||||
|
||||
event = libinput_get_event(li);
|
||||
t = litest_is_tablet_event(event,
|
||||
LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY);
|
||||
ck_assert_int_eq(libinput_event_tablet_tool_get_proximity_state(t),
|
||||
LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_IN);
|
||||
|
||||
libinput_event_destroy(event);
|
||||
|
||||
event = libinput_get_event(li);
|
||||
t = litest_is_tablet_event(event,
|
||||
LIBINPUT_EVENT_TABLET_TOOL_TIP);
|
||||
ck_assert_int_eq(libinput_event_tablet_tool_get_tip_state(t),
|
||||
LIBINPUT_TABLET_TOOL_TIP_DOWN);
|
||||
|
||||
libinput_event_destroy(event);
|
||||
|
||||
/* The button is down on init but we don't expect an event */
|
||||
litest_assert_empty_queue(li);
|
||||
|
||||
litest_button_click(dev, BTN_0, false);
|
||||
libinput_dispatch(li);
|
||||
litest_assert_empty_queue(li);
|
||||
|
||||
/* but buttons after this should be sent */
|
||||
litest_button_click(dev, BTN_0, true);
|
||||
libinput_dispatch(li);
|
||||
litest_assert_tablet_button_event(li, BTN_0, LIBINPUT_BUTTON_STATE_PRESSED);
|
||||
litest_button_click(dev, BTN_0, false);
|
||||
libinput_dispatch(li);
|
||||
litest_assert_tablet_button_event(li, BTN_0, LIBINPUT_BUTTON_STATE_RELEASED);
|
||||
|
||||
libinput_unref(li);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(totem_button_up_on_delete)
|
||||
{
|
||||
struct libinput *li = litest_create_context();
|
||||
struct litest_device *dev = litest_add_device(li, LITEST_DELL_CANVAS_TOTEM);
|
||||
struct libevdev *evdev = libevdev_new();
|
||||
|
||||
litest_tablet_proximity_in(dev, 10, 10, NULL);
|
||||
litest_drain_events(li);
|
||||
|
||||
litest_button_click(dev, BTN_0, true);
|
||||
litest_drain_events(li);
|
||||
|
||||
litest_delete_device(dev);
|
||||
libinput_dispatch(li);
|
||||
|
||||
litest_assert_tablet_button_event(li,
|
||||
BTN_0,
|
||||
LIBINPUT_BUTTON_STATE_RELEASED);
|
||||
|
||||
litest_assert_tablet_tip_event(li, LIBINPUT_TABLET_TOOL_TIP_UP);
|
||||
litest_assert_tablet_proximity_event(li,
|
||||
LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_OUT);
|
||||
libevdev_free(evdev);
|
||||
libinput_unref(li);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(totem_arbitration_below)
|
||||
{
|
||||
struct litest_device *totem = litest_current_device();
|
||||
struct litest_device *touch;
|
||||
struct libinput *li = totem->libinput;
|
||||
|
||||
touch = litest_add_device(li, LITEST_DELL_CANVAS_TOTEM_TOUCH);
|
||||
litest_drain_events(li);
|
||||
|
||||
/* touches below the totem, cancelled once the totem is down */
|
||||
litest_touch_down(touch, 0, 50, 50);
|
||||
libinput_dispatch(li);
|
||||
litest_assert_touch_down_frame(li);
|
||||
litest_touch_move_to(touch, 0, 50, 50, 50, 70, 10);
|
||||
libinput_dispatch(li);
|
||||
while (libinput_next_event_type(li)) {
|
||||
litest_assert_touch_motion_frame(li);
|
||||
}
|
||||
|
||||
litest_tablet_proximity_in(totem, 50, 70, NULL);
|
||||
libinput_dispatch(li);
|
||||
|
||||
litest_assert_tablet_proximity_event(li, LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_IN);
|
||||
litest_assert_tablet_tip_event(li, LIBINPUT_TABLET_TOOL_TIP_DOWN);
|
||||
litest_assert_touch_cancel(li);
|
||||
|
||||
litest_touch_move_to(touch, 0, 50, 70, 20, 50, 10);
|
||||
litest_assert_empty_queue(li);
|
||||
|
||||
litest_tablet_motion(totem, 20, 50, NULL);
|
||||
litest_assert_only_typed_events(li, LIBINPUT_EVENT_TABLET_TOOL_AXIS);
|
||||
|
||||
litest_touch_up(touch, 0);
|
||||
litest_assert_empty_queue(li);
|
||||
|
||||
litest_delete_device(touch);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(totem_arbitration_during)
|
||||
{
|
||||
struct litest_device *totem = litest_current_device();
|
||||
struct litest_device *touch;
|
||||
struct libinput *li = totem->libinput;
|
||||
|
||||
touch = litest_add_device(li, LITEST_DELL_CANVAS_TOTEM_TOUCH);
|
||||
litest_drain_events(li);
|
||||
|
||||
litest_tablet_proximity_in(totem, 50, 50, NULL);
|
||||
libinput_dispatch(li);
|
||||
|
||||
litest_drain_events(li);
|
||||
|
||||
for (int i = 0; i < 3; i++) {
|
||||
litest_touch_down(touch, 0, 51, 51);
|
||||
litest_touch_move_to(touch, 0, 51, 50, 90, 80, 10);
|
||||
litest_touch_up(touch, 0);
|
||||
|
||||
litest_assert_empty_queue(li);
|
||||
}
|
||||
|
||||
litest_delete_device(touch);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(totem_arbitration_outside_rect)
|
||||
{
|
||||
struct litest_device *totem = litest_current_device();
|
||||
struct litest_device *touch;
|
||||
struct libinput *li = totem->libinput;
|
||||
|
||||
touch = litest_add_device(li, LITEST_DELL_CANVAS_TOTEM_TOUCH);
|
||||
litest_drain_events(li);
|
||||
|
||||
litest_tablet_proximity_in(totem, 50, 50, NULL);
|
||||
libinput_dispatch(li);
|
||||
|
||||
litest_drain_events(li);
|
||||
|
||||
for (int i = 0; i < 3; i++) {
|
||||
litest_touch_down(touch, 0, 81, 51);
|
||||
litest_touch_move_to(touch, 0, 81, 50, 90, 80, 10);
|
||||
litest_touch_up(touch, 0);
|
||||
libinput_dispatch(li);
|
||||
|
||||
litest_assert_touch_sequence(li);
|
||||
}
|
||||
|
||||
/* moving onto the totem is fine */
|
||||
litest_touch_down(touch, 0, 81, 51);
|
||||
litest_touch_move_to(touch, 0, 81, 50, 50, 50, 10);
|
||||
litest_touch_up(touch, 0);
|
||||
libinput_dispatch(li);
|
||||
|
||||
litest_assert_touch_sequence(li);
|
||||
|
||||
litest_delete_device(touch);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
TEST_COLLECTION(totem)
|
||||
{
|
||||
litest_add("totem:tool", totem_type, LITEST_TOTEM, LITEST_ANY);
|
||||
litest_add("totem:tool", totem_axes, LITEST_TOTEM, LITEST_ANY);
|
||||
litest_add("totem:proximity", totem_proximity_in_out, LITEST_TOTEM, LITEST_ANY);
|
||||
litest_add("totem:proximity", totem_proximity_in_on_init, LITEST_TOTEM, LITEST_ANY);
|
||||
litest_add("totem:proximity", totem_proximity_out_on_suspend, LITEST_TOTEM, LITEST_ANY);
|
||||
|
||||
litest_add("totem:axes", totem_motion, LITEST_TOTEM, LITEST_ANY);
|
||||
litest_add("totem:axes", totem_rotation, LITEST_TOTEM, LITEST_ANY);
|
||||
litest_add("totem:axes", totem_size, LITEST_TOTEM, LITEST_ANY);
|
||||
litest_add("totem:button", totem_button, LITEST_TOTEM, LITEST_ANY);
|
||||
litest_add("totem:button", totem_button_down_on_init, LITEST_TOTEM, LITEST_ANY);
|
||||
litest_add_no_device("totem:button", totem_button_up_on_delete);
|
||||
|
||||
litest_add("totem:arbitration", totem_arbitration_below, LITEST_TOTEM, LITEST_ANY);
|
||||
litest_add("totem:arbitration", totem_arbitration_during, LITEST_TOTEM, LITEST_ANY);
|
||||
litest_add("totem:arbitration", totem_arbitration_outside_rect, LITEST_TOTEM, LITEST_ANY);
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue