Merge branch 'master' into tablet-support

Conflicts:
	test/litest.h
This commit is contained in:
Peter Hutterer 2015-01-20 15:24:34 +10:00
commit 35b3992792
17 changed files with 1631 additions and 260 deletions

View file

@ -66,6 +66,12 @@ The Xorg synaptics driver uses 30% of the touchpad dimensions as threshold,
libinput does not have this restriction. If two fingers are on the pad
while clicking, that is a two-finger click.
Clickfinger configuration can be enabled through the
libinput_device_config_click_set_method() call. If clickfingers are
enabled on a touchpad with top software buttons, the top area will keep
acting as softbuttons for use with the trackpoint. Clickfingers will be used
everywhere else on the touchpad.
@section special_clickpads Special Clickpads
The Lenovo *40 series laptops have a clickpad that provides two software button sections, one at

View file

@ -494,10 +494,9 @@ tp_release_all_buttons(struct tp_dispatch *tp,
}
}
void
static void
tp_init_softbuttons(struct tp_dispatch *tp,
struct evdev_device *device,
double topbutton_size_mult)
struct evdev_device *device)
{
int width, height;
const struct input_absinfo *absinfo_x, *absinfo_y;
@ -523,6 +522,26 @@ tp_init_softbuttons(struct tp_dispatch *tp,
}
tp->buttons.bottom_area.rightbutton_left_edge = width/2 + xoffset;
}
void
tp_init_top_softbuttons(struct tp_dispatch *tp,
struct evdev_device *device,
double topbutton_size_mult)
{
int width, height;
const struct input_absinfo *absinfo_x, *absinfo_y;
int xoffset, yoffset;
int yres;
absinfo_x = device->abs.absinfo_x;
absinfo_y = device->abs.absinfo_y;
xoffset = absinfo_x->minimum,
yoffset = absinfo_y->minimum;
yres = absinfo_y->resolution;
width = abs(absinfo_x->maximum - absinfo_x->minimum);
height = abs(absinfo_y->maximum - absinfo_y->minimum);
if (tp->buttons.has_topbuttons) {
/* T440s has the top button line 5mm from the top, event
@ -545,6 +564,89 @@ tp_init_softbuttons(struct tp_dispatch *tp,
}
}
static inline uint32_t
tp_button_config_click_get_methods(struct libinput_device *device)
{
struct evdev_device *evdev = (struct evdev_device*)device;
struct tp_dispatch *tp = (struct tp_dispatch*)evdev->dispatch;
uint32_t methods = LIBINPUT_CONFIG_CLICK_METHOD_NONE;
if (tp->buttons.is_clickpad) {
methods |= LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS;
if (tp->has_mt)
methods |= LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER;
}
return methods;
}
static void
tp_switch_click_method(struct tp_dispatch *tp)
{
/*
* All we need to do when switching click methods is to change the
* bottom_area.top_edge so that when in clickfinger mode the bottom
* touchpad area is not dead wrt finger movement starting there.
*
* We do not need to take any state into account, fingers which are
* already down will simply keep the state / area they have assigned
* until they are released, and the post_button_events path is state
* agnostic.
*/
switch (tp->buttons.click_method) {
case LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS:
tp_init_softbuttons(tp, tp->device);
break;
case LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER:
case LIBINPUT_CONFIG_CLICK_METHOD_NONE:
tp->buttons.bottom_area.top_edge = INT_MAX;
break;
}
}
static enum libinput_config_status
tp_button_config_click_set_method(struct libinput_device *device,
enum libinput_config_click_method method)
{
struct evdev_device *evdev = (struct evdev_device*)device;
struct tp_dispatch *tp = (struct tp_dispatch*)evdev->dispatch;
tp->buttons.click_method = method;
tp_switch_click_method(tp);
return LIBINPUT_CONFIG_STATUS_SUCCESS;
}
static enum libinput_config_click_method
tp_button_config_click_get_method(struct libinput_device *device)
{
struct evdev_device *evdev = (struct evdev_device*)device;
struct tp_dispatch *tp = (struct tp_dispatch*)evdev->dispatch;
return tp->buttons.click_method;
}
static enum libinput_config_click_method
tp_click_get_default_method(struct tp_dispatch *tp)
{
if (!tp->buttons.is_clickpad)
return LIBINPUT_CONFIG_CLICK_METHOD_NONE;
else if (libevdev_get_id_vendor(tp->device->evdev) == VENDOR_ID_APPLE)
return LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER;
else
return LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS;
}
static enum libinput_config_click_method
tp_button_config_click_get_default_method(struct libinput_device *device)
{
struct evdev_device *evdev = (struct evdev_device*)device;
struct tp_dispatch *tp = (struct tp_dispatch*)evdev->dispatch;
return tp_click_get_default_method(tp);
}
int
tp_init_buttons(struct tp_dispatch *tp,
struct evdev_device *device)
@ -582,15 +684,16 @@ tp_init_buttons(struct tp_dispatch *tp,
tp->buttons.motion_dist = diagonal * DEFAULT_BUTTON_MOTION_THRESHOLD;
if (libevdev_get_id_vendor(device->evdev) == VENDOR_ID_APPLE)
tp->buttons.use_clickfinger = true;
tp->buttons.config_method.get_methods = tp_button_config_click_get_methods;
tp->buttons.config_method.set_method = tp_button_config_click_set_method;
tp->buttons.config_method.get_method = tp_button_config_click_get_method;
tp->buttons.config_method.get_default_method = tp_button_config_click_get_default_method;
tp->device->base.config.click_method = &tp->buttons.config_method;
if (tp->buttons.is_clickpad && !tp->buttons.use_clickfinger) {
tp_init_softbuttons(tp, device, 1.0);
} else {
tp->buttons.bottom_area.top_edge = INT_MAX;
tp->buttons.top_area.bottom_edge = INT_MIN;
}
tp->buttons.click_method = tp_click_get_default_method(tp);
tp_switch_click_method(tp);
tp_init_top_softbuttons(tp, device, 1.0);
tp_for_each_touch(tp, t) {
t->button.state = BUTTON_STATE_NONE;
@ -611,43 +714,6 @@ tp_remove_buttons(struct tp_dispatch *tp)
libinput_timer_cancel(&t->button.timer);
}
static int
tp_post_clickfinger_buttons(struct tp_dispatch *tp, uint64_t time)
{
uint32_t current, old, button;
enum libinput_button_state state;
current = tp->buttons.state;
old = tp->buttons.old_state;
if (current == old)
return 0;
if (current) {
switch (tp->nfingers_down) {
case 1: button = BTN_LEFT; break;
case 2: button = BTN_RIGHT; break;
case 3: button = BTN_MIDDLE; break;
default:
return 0;
}
tp->buttons.active = button;
state = LIBINPUT_BUTTON_STATE_PRESSED;
} else {
button = tp->buttons.active;
tp->buttons.active = 0;
state = LIBINPUT_BUTTON_STATE_RELEASED;
}
if (button) {
evdev_pointer_notify_button(tp->device,
time,
button,
state);
}
return 1;
}
static int
tp_post_physical_buttons(struct tp_dispatch *tp, uint64_t time)
{
@ -683,12 +749,12 @@ tp_post_physical_buttons(struct tp_dispatch *tp, uint64_t time)
return 0;
}
static void
tp_notify_softbutton(struct tp_dispatch *tp,
uint64_t time,
uint32_t button,
uint32_t is_topbutton,
enum libinput_button_state state)
static int
tp_notify_clickpadbutton(struct tp_dispatch *tp,
uint64_t time,
uint32_t button,
uint32_t is_topbutton,
enum libinput_button_state state)
{
/* If we've a trackpoint, send top buttons through the trackpoint */
if (is_topbutton && tp->buttons.trackpoint) {
@ -702,18 +768,38 @@ tp_notify_softbutton(struct tp_dispatch *tp,
event.value = (state == LIBINPUT_BUTTON_STATE_PRESSED) ? 1 : 0;
dispatch->interface->process(dispatch, tp->buttons.trackpoint,
&event, time);
return;
return 1;
}
/* Ignore button events not for the trackpoint while suspended */
if (tp->device->suspended)
return;
return 0;
/*
* If the user has requested clickfinger replace the button chosen
* by the softbutton code with one based on the number of fingers.
*/
if (tp->buttons.click_method == LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER &&
state == LIBINPUT_BUTTON_STATE_PRESSED) {
switch (tp->nfingers_down) {
case 1: button = BTN_LEFT; break;
case 2: button = BTN_RIGHT; break;
case 3: button = BTN_MIDDLE; break;
default:
button = 0;
}
tp->buttons.active = button;
if (!button)
return 0;
}
evdev_pointer_notify_button(tp->device, time, button, state);
return 1;
}
static int
tp_post_softbutton_buttons(struct tp_dispatch *tp, uint64_t time)
tp_post_clickpadbutton_buttons(struct tp_dispatch *tp, uint64_t time)
{
uint32_t current, old, button, is_top;
enum libinput_button_state state;
@ -783,22 +869,18 @@ tp_post_softbutton_buttons(struct tp_dispatch *tp, uint64_t time)
tp->buttons.click_pending = false;
if (button)
tp_notify_softbutton(tp, time, button, is_top, state);
return tp_notify_clickpadbutton(tp, time, button, is_top, state);
return 1;
return 0;
}
int
tp_post_button_events(struct tp_dispatch *tp, uint64_t time)
{
if (tp->buttons.is_clickpad) {
if (tp->buttons.use_clickfinger)
return tp_post_clickfinger_buttons(tp, time);
else
return tp_post_softbutton_buttons(tp, time);
}
return tp_post_physical_buttons(tp, time);
if (tp->buttons.is_clickpad)
return tp_post_clickpadbutton_buttons(tp, time);
else
return tp_post_physical_buttons(tp, time);
}
int

View file

@ -294,6 +294,7 @@ tp_edge_scroll_handle_state(struct tp_dispatch *tp, uint64_t time)
switch (t->state) {
case TOUCH_NONE:
case TOUCH_HOVERING:
break;
case TOUCH_BEGIN:
tp_edge_scroll_handle_event(tp, t, SCROLL_EVENT_TOUCH);

View file

@ -135,27 +135,96 @@ tp_get_touch(struct tp_dispatch *tp, unsigned int slot)
return &tp->touches[slot];
}
static inline void
tp_begin_touch(struct tp_dispatch *tp, struct tp_touch *t, uint64_t time)
static inline unsigned int
tp_fake_finger_count(struct tp_dispatch *tp)
{
if (t->state == TOUCH_BEGIN || t->state == TOUCH_UPDATE)
/* don't count BTN_TOUCH */
return ffs(tp->fake_touches >> 1);
}
static inline bool
tp_fake_finger_is_touching(struct tp_dispatch *tp)
{
return tp->fake_touches & 0x1;
}
static inline void
tp_fake_finger_set(struct tp_dispatch *tp,
unsigned int code,
bool is_press)
{
unsigned int shift;
switch (code) {
case BTN_TOUCH:
shift = 0;
break;
case BTN_TOOL_FINGER:
shift = 1;
break;
case BTN_TOOL_DOUBLETAP:
case BTN_TOOL_TRIPLETAP:
case BTN_TOOL_QUADTAP:
shift = code - BTN_TOOL_DOUBLETAP + 2;
break;
default:
return;
}
if (is_press)
tp->fake_touches |= 1 << shift;
else
tp->fake_touches &= ~(0x1 << shift);
}
static inline void
tp_new_touch(struct tp_dispatch *tp, struct tp_touch *t, uint64_t time)
{
if (t->state == TOUCH_BEGIN ||
t->state == TOUCH_UPDATE ||
t->state == TOUCH_HOVERING)
return;
/* we begin the touch as hovering because until BTN_TOUCH happens we
* don't know if it's a touch down or not. And BTN_TOUCH may happen
* after ABS_MT_TRACKING_ID */
tp_motion_history_reset(t);
t->dirty = true;
t->state = TOUCH_BEGIN;
t->has_ended = false;
t->state = TOUCH_HOVERING;
t->pinned.is_pinned = false;
t->millis = time;
tp->nfingers_down++;
assert(tp->nfingers_down >= 1);
tp->queued |= TOUCHPAD_EVENT_MOTION;
}
static inline void
tp_begin_touch(struct tp_dispatch *tp, struct tp_touch *t, uint64_t time)
{
t->dirty = true;
t->state = TOUCH_BEGIN;
t->millis = time;
tp->nfingers_down++;
assert(tp->nfingers_down >= 1);
}
/**
* End a touch, even if the touch sequence is still active.
*/
static inline void
tp_end_touch(struct tp_dispatch *tp, struct tp_touch *t, uint64_t time)
{
if (t->state == TOUCH_END || t->state == TOUCH_NONE)
switch (t->state) {
case TOUCH_HOVERING:
t->state = TOUCH_NONE;
/* fallthough */
case TOUCH_NONE:
case TOUCH_END:
return;
case TOUCH_BEGIN:
case TOUCH_UPDATE:
break;
}
t->dirty = true;
t->is_pointer = false;
@ -168,6 +237,16 @@ tp_end_touch(struct tp_dispatch *tp, struct tp_touch *t, uint64_t time)
tp->queued |= TOUCHPAD_EVENT_MOTION;
}
/**
* End the touch sequence on ABS_MT_TRACKING_ID -1 or when the BTN_TOOL_* 0 is received.
*/
static inline void
tp_end_sequence(struct tp_dispatch *tp, struct tp_touch *t, uint64_t time)
{
t->has_ended = true;
tp_end_touch(tp, t, time);
}
static double
tp_estimate_delta(int x0, int x1, int x2, int x3)
{
@ -218,9 +297,9 @@ tp_process_absolute(struct tp_dispatch *tp,
break;
case ABS_MT_TRACKING_ID:
if (e->value != -1)
tp_begin_touch(tp, t, time);
tp_new_touch(tp, t, time);
else
tp_end_touch(tp, t, time);
tp_end_sequence(tp, t, time);
}
}
@ -253,41 +332,21 @@ tp_process_fake_touch(struct tp_dispatch *tp,
uint64_t time)
{
struct tp_touch *t;
unsigned int fake_touches;
unsigned int nfake_touches;
unsigned int i, start;
unsigned int shift;
if (e->code != BTN_TOUCH &&
(e->code < BTN_TOOL_DOUBLETAP || e->code > BTN_TOOL_QUADTAP))
return;
tp_fake_finger_set(tp, e->code, e->value != 0);
shift = e->code == BTN_TOUCH ? 0 : (e->code - BTN_TOOL_DOUBLETAP + 1);
nfake_touches = tp_fake_finger_count(tp);
if (e->value)
tp->fake_touches |= 1 << shift;
else
tp->fake_touches &= ~(0x1 << shift);
fake_touches = tp->fake_touches;
nfake_touches = 0;
while (fake_touches) {
nfake_touches++;
fake_touches >>= 1;
}
/* For single touch tps we use BTN_TOUCH for begin / end of touch 0 */
start = tp->has_mt ? tp->real_touches : 0;
for (i = start; i < tp->ntouches; i++) {
t = tp_get_touch(tp, i);
if (i < nfake_touches)
tp_begin_touch(tp, t, time);
tp_new_touch(tp, t, time);
else
tp_end_touch(tp, t, time);
tp_end_sequence(tp, t, time);
}
/* On mt the actual touch info may arrive after BTN_TOOL_FOO */
assert(tp->has_mt || tp->nfingers_down == nfake_touches);
}
static void
@ -302,6 +361,7 @@ tp_process_key(struct tp_dispatch *tp,
tp_process_button(tp, e, time);
break;
case BTN_TOUCH:
case BTN_TOOL_FINGER:
case BTN_TOOL_DOUBLETAP:
case BTN_TOOL_TRIPLETAP:
case BTN_TOOL_QUADTAP:
@ -325,7 +385,12 @@ tp_unpin_finger(struct tp_dispatch *tp, struct tp_touch *t)
tp->buttons.motion_dist * tp->buttons.motion_dist) {
t->pinned.is_pinned = false;
tp_set_pointer(tp, t);
return;
}
/* The finger may slowly drift, adjust the center */
t->pinned.center_x = t->x + t->pinned.center_x / 2;
t->pinned.center_y = t->y + t->pinned.center_y / 2;
}
static void
@ -554,6 +619,61 @@ tp_remove_scroll(struct tp_dispatch *tp)
tp_remove_edge_scroll(tp);
}
static void
tp_unhover_touches(struct tp_dispatch *tp, uint64_t time)
{
struct tp_touch *t;
unsigned int nfake_touches;
int i;
if (!tp->fake_touches && !tp->nfingers_down)
return;
nfake_touches = tp_fake_finger_count(tp);
if (tp->nfingers_down == nfake_touches &&
((tp->nfingers_down == 0 && !tp_fake_finger_is_touching(tp)) ||
(tp->nfingers_down > 0 && tp_fake_finger_is_touching(tp))))
return;
/* if BTN_TOUCH is set and we have less fingers down than fake
* touches, switch each hovering touch to BEGIN
* until nfingers_down matches nfake_touches
*/
if (tp_fake_finger_is_touching(tp) &&
tp->nfingers_down < nfake_touches) {
for (i = 0; i < (int)tp->ntouches; i++) {
t = tp_get_touch(tp, i);
if (t->state == TOUCH_HOVERING) {
tp_begin_touch(tp, t, time);
if (tp->nfingers_down >= nfake_touches)
break;
}
}
}
/* if BTN_TOUCH is unset end all touches, we're hovering now. If we
* have too many touches also end some of them. This is done in
* reverse order.
*/
if (tp->nfingers_down > nfake_touches ||
!tp_fake_finger_is_touching(tp)) {
for (i = tp->ntouches - 1; i >= 0; i--) {
t = tp_get_touch(tp, i);
if (t->state == TOUCH_HOVERING)
continue;
tp_end_touch(tp, t, time);
if (tp_fake_finger_is_touching(tp) &&
tp->nfingers_down == nfake_touches)
break;
}
}
}
static void
tp_process_state(struct tp_dispatch *tp, uint64_t time)
{
@ -561,6 +681,8 @@ tp_process_state(struct tp_dispatch *tp, uint64_t time)
struct tp_touch *first = tp_get_touch(tp, 0);
unsigned int i;
tp_unhover_touches(tp, time);
for (i = 0; i < tp->ntouches; i++) {
t = tp_get_touch(tp, i);
@ -606,13 +728,18 @@ tp_post_process_state(struct tp_dispatch *tp, uint64_t time)
struct tp_touch *t;
tp_for_each_touch(tp, t) {
if (!t->dirty)
continue;
if (t->state == TOUCH_END)
t->state = TOUCH_NONE;
else if (t->state == TOUCH_BEGIN)
if (t->state == TOUCH_END) {
if (t->has_ended)
t->state = TOUCH_NONE;
else
t->state = TOUCH_HOVERING;
} else if (t->state == TOUCH_BEGIN) {
t->state = TOUCH_UPDATE;
}
t->dirty = false;
}
@ -793,7 +920,7 @@ tp_clear_state(struct tp_dispatch *tp)
tp_release_all_taps(tp, now);
tp_for_each_touch(tp, t) {
tp_end_touch(tp, t, now);
tp_end_sequence(tp, t, now);
}
tp_handle_state(tp, now);
@ -811,7 +938,7 @@ tp_suspend(struct tp_dispatch *tp, struct evdev_device *device)
if (tp->buttons.has_topbuttons) {
evdev_notify_suspended_device(device);
/* Enlarge topbutton area while suspended */
tp_init_softbuttons(tp, device, 1.5);
tp_init_top_softbuttons(tp, device, 1.5);
} else {
evdev_device_suspend(device);
}
@ -824,7 +951,7 @@ tp_resume(struct tp_dispatch *tp, struct evdev_device *device)
/* tap state-machine is offline while suspended, reset state */
tp_clear_state(tp);
/* restore original topbutton area size */
tp_init_softbuttons(tp, device, 1.0);
tp_init_top_softbuttons(tp, device, 1.0);
evdev_notify_resumed_device(device);
} else {
evdev_device_resume(device);
@ -954,6 +1081,7 @@ tp_init_touch(struct tp_dispatch *tp,
struct tp_touch *t)
{
t->tp = tp;
t->has_ended = true;
}
static int

View file

@ -53,6 +53,7 @@ enum touchpad_model {
enum touch_state {
TOUCH_NONE = 0,
TOUCH_HOVERING,
TOUCH_BEGIN,
TOUCH_UPDATE,
TOUCH_END
@ -130,6 +131,7 @@ struct tp_motion {
struct tp_touch {
struct tp_dispatch *tp;
enum touch_state state;
bool has_ended; /* TRACKING_ID == -1 */
bool dirty;
bool is_pointer; /* the pointer-controlling touch */
int32_t x;
@ -197,7 +199,12 @@ struct tp_dispatch {
unsigned int real_touches; /* number of slots */
unsigned int ntouches; /* no slots inc. fakes */
struct tp_touch *touches; /* len == ntouches */
unsigned int fake_touches; /* fake touch mask */
/* bit 0: BTN_TOUCH
* bit 1: BTN_TOOL_FINGER
* bit 2: BTN_TOOL_DOUBLETAP
* ...
*/
unsigned int fake_touches;
struct {
int32_t margin_x;
@ -236,7 +243,10 @@ struct tp_dispatch {
} top_area;
struct evdev_device *trackpoint;
} buttons; /* physical buttons */
enum libinput_config_click_method click_method;
struct libinput_device_config_click_method config_method;
} buttons;
struct {
struct libinput_device_config_scroll_method config_method;
@ -299,9 +309,9 @@ int
tp_init_buttons(struct tp_dispatch *tp, struct evdev_device *device);
void
tp_init_softbuttons(struct tp_dispatch *tp,
struct evdev_device *device,
double topbutton_size_mult);
tp_init_top_softbuttons(struct tp_dispatch *tp,
struct evdev_device *device,
double topbutton_size_mult);
void
tp_remove_buttons(struct tp_dispatch *tp);

View file

@ -150,6 +150,14 @@ struct libinput_device_config_scroll_method {
uint32_t (*get_default_button)(struct libinput_device *device);
};
struct libinput_device_config_click_method {
uint32_t (*get_methods)(struct libinput_device *device);
enum libinput_config_status (*set_method)(struct libinput_device *device,
enum libinput_config_click_method method);
enum libinput_config_click_method (*get_method)(struct libinput_device *device);
enum libinput_config_click_method (*get_default_method)(struct libinput_device *device);
};
struct libinput_device_config {
struct libinput_device_config_tap *tap;
struct libinput_device_config_calibration *calibration;
@ -158,6 +166,7 @@ struct libinput_device_config {
struct libinput_device_config_natural_scroll *natural_scroll;
struct libinput_device_config_left_handed *left_handed;
struct libinput_device_config_scroll_method *scroll_method;
struct libinput_device_config_click_method *click_method;
};
struct libinput_device {

View file

@ -1961,6 +1961,56 @@ libinput_device_config_left_handed_get_default(struct libinput_device *device)
return device->config.left_handed->get_default(device);
}
LIBINPUT_EXPORT uint32_t
libinput_device_config_click_get_methods(struct libinput_device *device)
{
if (device->config.click_method)
return device->config.click_method->get_methods(device);
else
return 0;
}
LIBINPUT_EXPORT enum libinput_config_status
libinput_device_config_click_set_method(struct libinput_device *device,
enum libinput_config_click_method method)
{
if ((libinput_device_config_click_get_methods(device) & method) != method)
return LIBINPUT_CONFIG_STATUS_UNSUPPORTED;
/* Check method is a single valid method */
switch (method) {
case LIBINPUT_CONFIG_CLICK_METHOD_NONE:
case LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS:
case LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER:
break;
default:
return LIBINPUT_CONFIG_STATUS_INVALID;
}
if (device->config.click_method)
return device->config.click_method->set_method(device, method);
else /* method must be _NONE to get here */
return LIBINPUT_CONFIG_STATUS_SUCCESS;
}
LIBINPUT_EXPORT enum libinput_config_click_method
libinput_device_config_click_get_method(struct libinput_device *device)
{
if (device->config.click_method)
return device->config.click_method->get_method(device);
else
return LIBINPUT_CONFIG_CLICK_METHOD_NONE;
}
LIBINPUT_EXPORT enum libinput_config_click_method
libinput_device_config_click_get_default_method(struct libinput_device *device)
{
if (device->config.click_method)
return device->config.click_method->get_default_method(device);
else
return LIBINPUT_CONFIG_CLICK_METHOD_NONE;
}
LIBINPUT_EXPORT uint32_t
libinput_device_config_scroll_get_methods(struct libinput_device *device)
{

View file

@ -2498,6 +2498,108 @@ libinput_device_config_left_handed_get(struct libinput_device *device);
int
libinput_device_config_left_handed_get_default(struct libinput_device *device);
/**
* @ingroup config
*
* The click method defines when to generate software-emulated
* buttons, usually on a device that does not have a specific physical
* button available.
*/
enum libinput_config_click_method {
/**
* Do not send software-emulated button events. This has no effect
* on physical button generations.
*/
LIBINPUT_CONFIG_CLICK_METHOD_NONE = 0,
/**
* Use software-button areas (see @ref clickfinger) to generate
* button events.
*/
LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS = (1 << 0),
/**
* The number of fingers decides which button press to generate.
*/
LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER = (1 << 1),
};
/**
* @ingroup config
*
* Check which button click methods a device supports. The button click
* method defines when to generate software-emulated buttons, usually on a
* device that does not have a specific physical button available.
*
* @param device The device to configure
*
* @return A bitmask of possible methods.
*
* @see libinput_device_config_click_get_methods
* @see libinput_device_config_click_set_method
* @see libinput_device_config_click_get_method
*/
uint32_t
libinput_device_config_click_get_methods(struct libinput_device *device);
/**
* @ingroup config
*
* Set the button click method for this device. The button click
* method defines when to generate software-emulated buttons, usually on a
* device that does not have a specific physical button available.
*
* @note The selected click method may not take effect immediately. The
* device may require changing to a neutral state first before activating
* the new method.
*
* @param device The device to configure
* @param method The button click method
*
* @return A config status code
*
* @see libinput_device_config_click_get_methods
* @see libinput_device_config_click_get_method
* @see libinput_device_config_click_get_default_method
*/
enum libinput_config_status
libinput_device_config_click_set_method(struct libinput_device *device,
enum libinput_config_click_method method);
/**
* @ingroup config
*
* Get the button click method for this device. The button click
* method defines when to generate software-emulated buttons, usually on a
* device that does not have a specific physical button available.
*
* @param device The device to configure
*
* @return The current button click method for this device
*
* @see libinput_device_config_click_get_methods
* @see libinput_device_config_click_set_method
* @see libinput_device_config_click_get_default_method
*/
enum libinput_config_click_method
libinput_device_config_click_get_method(struct libinput_device *device);
/**
* @ingroup config
*
* Get the default button click method for this device. The button click
* method defines when to generate software-emulated buttons, usually on a
* device that does not have a specific physical button available.
*
* @param device The device to configure
*
* @return The default button click method for this device
*
* @see libinput_device_config_click_get_methods
* @see libinput_device_config_click_set_method
* @see libinput_device_config_click_get_method
*/
enum libinput_config_click_method
libinput_device_config_click_get_default_method(struct libinput_device *device);
/**
* @ingroup config
*

View file

@ -139,3 +139,11 @@ global:
local:
*;
};
LIBINPUT_0.9.0 {
global:
libinput_device_config_click_get_default_method;
libinput_device_config_click_get_method;
libinput_device_config_click_get_methods;
libinput_device_config_click_set_method;
} LIBINPUT_0.8.0;

View file

@ -21,6 +21,7 @@ liblitest_la_SOURCES = \
litest-ms-surface-cover.c \
litest-qemu-usb-tablet.c \
litest-synaptics.c \
litest-synaptics-hover.c \
litest-synaptics-st.c \
litest-synaptics-t440.c \
litest-trackpoint.c \

View file

@ -31,21 +31,6 @@
#include "litest.h"
#include "litest-int.h"
static int tracking_id;
/* this is a semi-mt device, so we keep track of the touches that the tests
* send and modify them so that the first touch is always slot 0 and sends
* the top-left of the bounding box, the second is always slot 1 and sends
* the bottom-right of the bounding box.
* Lifting any of two fingers terminates slot 1
*/
struct alps {
/* The actual touches requested by the test for the two slots
* in the 0..100 range used by litest */
struct {
double x, y;
} touches[2];
};
static void alps_create(struct litest_device *d);
@ -56,141 +41,28 @@ litest_alps_setup(void)
litest_set_current_device(d);
}
static void
send_abs_xy(struct litest_device *d, double x, double y)
{
struct input_event e;
int val;
e.type = EV_ABS;
e.code = ABS_X;
e.value = LITEST_AUTO_ASSIGN;
val = litest_auto_assign_value(d, &e, 0, x, y);
litest_event(d, EV_ABS, ABS_X, val);
e.code = ABS_Y;
val = litest_auto_assign_value(d, &e, 0, x, y);
litest_event(d, EV_ABS, ABS_Y, val);
}
static void
send_abs_mt_xy(struct litest_device *d, double x, double y)
{
struct input_event e;
int val;
e.type = EV_ABS;
e.code = ABS_MT_POSITION_X;
e.value = LITEST_AUTO_ASSIGN;
val = litest_auto_assign_value(d, &e, 0, x, y);
litest_event(d, EV_ABS, ABS_MT_POSITION_X, val);
e.code = ABS_MT_POSITION_Y;
e.value = LITEST_AUTO_ASSIGN;
val = litest_auto_assign_value(d, &e, 0, x, y);
litest_event(d, EV_ABS, ABS_MT_POSITION_Y, val);
}
static void
alps_touch_down(struct litest_device *d, unsigned int slot, double x, double y)
{
struct alps *alps = d->private;
double t, l, r = 0, b = 0; /* top, left, right, bottom */
struct litest_semi_mt *semi_mt = d->private;
if (d->ntouches_down > 2 || slot > 1)
return;
if (d->ntouches_down == 1) {
l = x;
t = y;
} else {
int other = (slot + 1) % 2;
l = min(x, alps->touches[other].x);
t = min(y, alps->touches[other].y);
r = max(x, alps->touches[other].x);
b = max(y, alps->touches[other].y);
}
send_abs_xy(d, l, t);
litest_event(d, EV_ABS, ABS_MT_SLOT, 0);
if (d->ntouches_down == 1)
litest_event(d, EV_ABS, ABS_MT_TRACKING_ID, ++tracking_id);
send_abs_mt_xy(d, l, t);
if (d->ntouches_down == 2) {
litest_event(d, EV_ABS, ABS_MT_SLOT, 1);
litest_event(d, EV_ABS, ABS_MT_TRACKING_ID, ++tracking_id);
send_abs_mt_xy(d, r, b);
}
litest_event(d, EV_SYN, SYN_REPORT, 0);
alps->touches[slot].x = x;
alps->touches[slot].y = y;
litest_semi_mt_touch_down(d, semi_mt, slot, x, y);
}
static void
alps_touch_move(struct litest_device *d, unsigned int slot, double x, double y)
{
struct alps *alps = d->private;
double t, l, r = 0, b = 0; /* top, left, right, bottom */
struct litest_semi_mt *semi_mt = d->private;
if (d->ntouches_down > 2 || slot > 1)
return;
if (d->ntouches_down == 1) {
l = x;
t = y;
} else {
int other = (slot + 1) % 2;
l = min(x, alps->touches[other].x);
t = min(y, alps->touches[other].y);
r = max(x, alps->touches[other].x);
b = max(y, alps->touches[other].y);
}
send_abs_xy(d, l, t);
litest_event(d, EV_ABS, ABS_MT_SLOT, 0);
send_abs_mt_xy(d, l, t);
if (d->ntouches_down == 2) {
litest_event(d, EV_ABS, ABS_MT_SLOT, 1);
send_abs_mt_xy(d, r, b);
}
litest_event(d, EV_SYN, SYN_REPORT, 0);
alps->touches[slot].x = x;
alps->touches[slot].y = y;
litest_semi_mt_touch_move(d, semi_mt, slot, x, y);
}
static void
alps_touch_up(struct litest_device *d, unsigned int slot)
{
struct alps *alps = d->private;
struct litest_semi_mt *semi_mt = d->private;
/* note: ntouches_down is decreased before we get here */
if (d->ntouches_down >= 2 || slot > 1)
return;
litest_event(d, EV_ABS, ABS_MT_SLOT, d->ntouches_down);
litest_event(d, EV_ABS, ABS_MT_TRACKING_ID, -1);
/* if we have one finger left, send x/y coords for that finger left.
this is likely to happen with a real touchpad */
if (d->ntouches_down == 1) {
int other = (slot + 1) % 2;
send_abs_xy(d, alps->touches[other].x, alps->touches[other].y);
litest_event(d, EV_ABS, ABS_MT_SLOT, 0);
send_abs_mt_xy(d, alps->touches[other].x, alps->touches[other].y);
}
litest_event(d, EV_SYN, SYN_REPORT, 0);
litest_semi_mt_touch_up(d, semi_mt, slot);
}
static struct litest_device_interface interface = {
@ -247,10 +119,10 @@ struct litest_test_device litest_alps_device = {
static void
alps_create(struct litest_device *d)
{
struct alps *alps = zalloc(sizeof(*alps));
assert(alps);
struct litest_semi_mt *semi_mt = zalloc(sizeof(*semi_mt));
assert(semi_mt);
d->private = alps;
d->private = semi_mt;
d->uinput = litest_create_uinput_device_from_description(litest_alps_device.name,
litest_alps_device.id,

View file

@ -0,0 +1,132 @@
/*
* Copyright © 2014 Red Hat, Inc.
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that copyright
* notice and this permission notice appear in supporting documentation, and
* that the name of the copyright holders not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. The copyright holders make no representations
* about the suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* OF THIS SOFTWARE.
*/
#if HAVE_CONFIG_H
#include "config.h"
#endif
#include <assert.h>
#include "libinput-util.h"
#include "litest.h"
#include "litest-int.h"
static void
synaptics_hover_create(struct litest_device *d);
static void
litest_synaptics_hover_setup(void)
{
struct litest_device *d = litest_create_device(LITEST_SYNAPTICS_HOVER_SEMI_MT);
litest_set_current_device(d);
}
static void
synaptics_hover_touch_down(struct litest_device *d, unsigned int slot, double x, double y)
{
struct litest_semi_mt *semi_mt = d->private;
litest_semi_mt_touch_down(d, semi_mt, slot, x, y);
}
static void
synaptics_hover_touch_move(struct litest_device *d, unsigned int slot, double x, double y)
{
struct litest_semi_mt *semi_mt = d->private;
litest_semi_mt_touch_move(d, semi_mt, slot, x, y);
}
static void
synaptics_hover_touch_up(struct litest_device *d, unsigned int slot)
{
struct litest_semi_mt *semi_mt = d->private;
litest_semi_mt_touch_up(d, semi_mt, slot);
}
static struct litest_device_interface interface = {
.touch_down = synaptics_hover_touch_down,
.touch_move = synaptics_hover_touch_move,
.touch_up = synaptics_hover_touch_up,
};
static struct input_id input_id = {
.bustype = 0x11,
.vendor = 0x2,
.product = 0x7,
};
static int events[] = {
EV_KEY, BTN_LEFT,
EV_KEY, BTN_RIGHT,
EV_KEY, BTN_TOOL_FINGER,
EV_KEY, BTN_TOUCH,
EV_KEY, BTN_TOOL_DOUBLETAP,
EV_KEY, BTN_TOOL_TRIPLETAP,
INPUT_PROP_MAX, INPUT_PROP_POINTER,
INPUT_PROP_MAX, INPUT_PROP_SEMI_MT,
-1, -1,
};
static struct input_absinfo absinfo[] = {
{ ABS_X, 1472, 5472, 0, 0, 60 },
{ ABS_Y, 1408, 4498, 0, 0, 85 },
{ ABS_PRESSURE, 0, 255, 0, 0, 0 },
{ ABS_TOOL_WIDTH, 0, 15, 0, 0, 0 },
{ ABS_MT_SLOT, 0, 1, 0, 0, 0 },
{ ABS_MT_POSITION_X, 1472, 5472, 0, 0, 60 },
{ ABS_MT_POSITION_Y, 1408, 4498, 0, 0, 85 },
{ ABS_MT_TRACKING_ID, 0, 65535, 0, 0, 0 },
{ .value = -1 }
};
struct litest_test_device litest_synaptics_hover_device = {
.type = LITEST_SYNAPTICS_HOVER_SEMI_MT,
.features = LITEST_TOUCHPAD | LITEST_SEMI_MT | LITEST_BUTTON,
.shortname = "synaptics hover",
.setup = litest_synaptics_hover_setup,
.interface = &interface,
.create = synaptics_hover_create,
.name = "SynPS/2 Synaptics TouchPad",
.id = &input_id,
.events = events,
.absinfo = absinfo,
};
static void
synaptics_hover_create(struct litest_device *d)
{
struct litest_semi_mt *semi_mt = zalloc(sizeof(*semi_mt));
assert(semi_mt);
d->private = semi_mt;
d->uinput = litest_create_uinput_device_from_description(
litest_synaptics_hover_device.name,
litest_synaptics_hover_device.id,
absinfo,
events);
d->interface = &interface;
}

View file

@ -94,6 +94,7 @@ extern struct litest_test_device litest_generic_singletouch_device;
extern struct litest_test_device litest_qemu_tablet_device;
extern struct litest_test_device litest_xen_virtual_pointer_device;
extern struct litest_test_device litest_vmware_virtmouse_device;
extern struct litest_test_device litest_synaptics_hover_device;
struct litest_test_device* devices[] = {
&litest_synaptics_clickpad_device,
@ -113,6 +114,7 @@ struct litest_test_device* devices[] = {
&litest_qemu_tablet_device,
&litest_xen_virtual_pointer_device,
&litest_vmware_virtmouse_device,
&litest_synaptics_hover_device,
NULL,
};
@ -1386,3 +1388,144 @@ litest_pop_event_frame(struct litest_device *dev)
dev->skip_ev_syn = false;
litest_event(dev, EV_SYN, SYN_REPORT, 0);
}
static void
send_abs_xy(struct litest_device *d, double x, double y)
{
struct input_event e;
int val;
e.type = EV_ABS;
e.code = ABS_X;
e.value = LITEST_AUTO_ASSIGN;
val = litest_auto_assign_value(d, &e, 0, x, y);
litest_event(d, EV_ABS, ABS_X, val);
e.code = ABS_Y;
val = litest_auto_assign_value(d, &e, 0, x, y);
litest_event(d, EV_ABS, ABS_Y, val);
}
static void
send_abs_mt_xy(struct litest_device *d, double x, double y)
{
struct input_event e;
int val;
e.type = EV_ABS;
e.code = ABS_MT_POSITION_X;
e.value = LITEST_AUTO_ASSIGN;
val = litest_auto_assign_value(d, &e, 0, x, y);
litest_event(d, EV_ABS, ABS_MT_POSITION_X, val);
e.code = ABS_MT_POSITION_Y;
e.value = LITEST_AUTO_ASSIGN;
val = litest_auto_assign_value(d, &e, 0, x, y);
litest_event(d, EV_ABS, ABS_MT_POSITION_Y, val);
}
void
litest_semi_mt_touch_down(struct litest_device *d,
struct litest_semi_mt *semi_mt,
unsigned int slot,
double x, double y)
{
double t, l, r = 0, b = 0; /* top, left, right, bottom */
if (d->ntouches_down > 2 || slot > 1)
return;
if (d->ntouches_down == 1) {
l = x;
t = y;
} else {
int other = (slot + 1) % 2;
l = min(x, semi_mt->touches[other].x);
t = min(y, semi_mt->touches[other].y);
r = max(x, semi_mt->touches[other].x);
b = max(y, semi_mt->touches[other].y);
}
send_abs_xy(d, l, t);
litest_event(d, EV_ABS, ABS_MT_SLOT, 0);
if (d->ntouches_down == 1)
litest_event(d, EV_ABS, ABS_MT_TRACKING_ID, ++semi_mt->tracking_id);
send_abs_mt_xy(d, l, t);
if (d->ntouches_down == 2) {
litest_event(d, EV_ABS, ABS_MT_SLOT, 1);
litest_event(d, EV_ABS, ABS_MT_TRACKING_ID, ++semi_mt->tracking_id);
send_abs_mt_xy(d, r, b);
}
litest_event(d, EV_SYN, SYN_REPORT, 0);
semi_mt->touches[slot].x = x;
semi_mt->touches[slot].y = y;
}
void
litest_semi_mt_touch_move(struct litest_device *d,
struct litest_semi_mt *semi_mt,
unsigned int slot,
double x, double y)
{
double t, l, r = 0, b = 0; /* top, left, right, bottom */
if (d->ntouches_down > 2 || slot > 1)
return;
if (d->ntouches_down == 1) {
l = x;
t = y;
} else {
int other = (slot + 1) % 2;
l = min(x, semi_mt->touches[other].x);
t = min(y, semi_mt->touches[other].y);
r = max(x, semi_mt->touches[other].x);
b = max(y, semi_mt->touches[other].y);
}
send_abs_xy(d, l, t);
litest_event(d, EV_ABS, ABS_MT_SLOT, 0);
send_abs_mt_xy(d, l, t);
if (d->ntouches_down == 2) {
litest_event(d, EV_ABS, ABS_MT_SLOT, 1);
send_abs_mt_xy(d, r, b);
}
litest_event(d, EV_SYN, SYN_REPORT, 0);
semi_mt->touches[slot].x = x;
semi_mt->touches[slot].y = y;
}
void
litest_semi_mt_touch_up(struct litest_device *d,
struct litest_semi_mt *semi_mt,
unsigned int slot)
{
/* note: ntouches_down is decreased before we get here */
if (d->ntouches_down >= 2 || slot > 1)
return;
litest_event(d, EV_ABS, ABS_MT_SLOT, d->ntouches_down);
litest_event(d, EV_ABS, ABS_MT_TRACKING_ID, -1);
/* if we have one finger left, send x/y coords for that finger left.
this is likely to happen with a real touchpad */
if (d->ntouches_down == 1) {
int other = (slot + 1) % 2;
send_abs_xy(d, semi_mt->touches[other].x, semi_mt->touches[other].y);
litest_event(d, EV_ABS, ABS_MT_SLOT, 0);
send_abs_mt_xy(d, semi_mt->touches[other].x, semi_mt->touches[other].y);
}
litest_event(d, EV_SYN, SYN_REPORT, 0);
}

View file

@ -49,10 +49,11 @@ enum litest_device_type {
LITEST_QEMU_TABLET = -13,
LITEST_XEN_VIRTUAL_POINTER = -14,
LITEST_VMWARE_VIRTMOUSE = -15,
LITEST_WACOM_BAMBOO = -16,
LITEST_WACOM_CINTIQ = -17,
LITEST_WACOM_INTUOS = -18,
LITEST_WACOM_ISDV4 = -19,
LITEST_SYNAPTICS_HOVER_SEMI_MT = -16,
LITEST_WACOM_BAMBOO = -17,
LITEST_WACOM_CINTIQ = -18,
LITEST_WACOM_INTUOS = -19,
LITEST_WACOM_ISDV4 = -20,
};
enum litest_device_feature {
@ -215,6 +216,33 @@ void litest_timeout_buttonscroll(void);
void litest_push_event_frame(struct litest_device *dev);
void litest_pop_event_frame(struct litest_device *dev);
/* this is a semi-mt device, so we keep track of the touches that the tests
* send and modify them so that the first touch is always slot 0 and sends
* the top-left of the bounding box, the second is always slot 1 and sends
* the bottom-right of the bounding box.
* Lifting any of two fingers terminates slot 1
*/
struct litest_semi_mt {
int tracking_id;
/* The actual touches requested by the test for the two slots
* in the 0..100 range used by litest */
struct {
double x, y;
} touches[2];
};
void litest_semi_mt_touch_down(struct litest_device *d,
struct litest_semi_mt *semi_mt,
unsigned int slot,
double x, double y);
void litest_semi_mt_touch_move(struct litest_device *d,
struct litest_semi_mt *semi_mt,
unsigned int slot,
double x, double y);
void litest_semi_mt_touch_up(struct litest_device *d,
struct litest_semi_mt *semi_mt,
unsigned int slot);
#ifndef ck_assert_notnull
#define ck_assert_notnull(ptr) ck_assert_ptr_ne(ptr, NULL)
#endif

View file

@ -711,10 +711,96 @@ START_TEST(touchpad_3fg_tap_btntool_inverted)
}
END_TEST
START_TEST(touchpad_click_defaults_clickfinger)
{
struct litest_device *dev = litest_current_device();
struct libinput_device *device = dev->libinput_device;
uint32_t methods, method;
enum libinput_config_status status;
/* call this test for apple touchpads */
methods = libinput_device_config_click_get_methods(device);
ck_assert(methods & LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS);
ck_assert(methods & LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER);
method = libinput_device_config_click_get_method(device);
ck_assert_int_eq(method, LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER);
method = libinput_device_config_click_get_default_method(device);
ck_assert_int_eq(method, LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER);
status = libinput_device_config_click_set_method(device,
LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS);
ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS);
status = libinput_device_config_click_set_method(device,
LIBINPUT_CONFIG_CLICK_METHOD_NONE);
ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS);
}
END_TEST
START_TEST(touchpad_click_defaults_btnarea)
{
struct litest_device *dev = litest_current_device();
struct libinput_device *device = dev->libinput_device;
uint32_t methods, method;
enum libinput_config_status status;
/* call this test for non-apple clickpads */
methods = libinput_device_config_click_get_methods(device);
ck_assert(methods & LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER);
ck_assert(methods & LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS);
method = libinput_device_config_click_get_method(device);
ck_assert_int_eq(method, LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS);
method = libinput_device_config_click_get_default_method(device);
ck_assert_int_eq(method, LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS);
status = libinput_device_config_click_set_method(device,
LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER);
ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS);
status = libinput_device_config_click_set_method(device,
LIBINPUT_CONFIG_CLICK_METHOD_NONE);
ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS);
}
END_TEST
START_TEST(touchpad_click_defaults_none)
{
struct litest_device *dev = litest_current_device();
struct libinput_device *device = dev->libinput_device;
uint32_t methods, method;
enum libinput_config_status status;
/* call this test for non-clickpads */
methods = libinput_device_config_click_get_methods(device);
ck_assert_int_eq(methods, 0);
method = libinput_device_config_click_get_method(device);
ck_assert_int_eq(method, LIBINPUT_CONFIG_CLICK_METHOD_NONE);
method = libinput_device_config_click_get_default_method(device);
ck_assert_int_eq(method, LIBINPUT_CONFIG_CLICK_METHOD_NONE);
status = libinput_device_config_click_set_method(device,
LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER);
ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_UNSUPPORTED);
status = libinput_device_config_click_set_method(device,
LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS);
ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_UNSUPPORTED);
}
END_TEST
START_TEST(touchpad_1fg_clickfinger)
{
struct litest_device *dev = litest_create_device(LITEST_BCM5974);
struct litest_device *dev = litest_current_device();
struct libinput *li = dev->libinput;
enum libinput_config_status status;
status = libinput_device_config_click_set_method(dev->libinput_device,
LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER);
ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS);
litest_drain_events(li);
@ -731,15 +817,18 @@ START_TEST(touchpad_1fg_clickfinger)
LIBINPUT_BUTTON_STATE_PRESSED);
litest_assert_button_event(li, BTN_LEFT,
LIBINPUT_BUTTON_STATE_RELEASED);
litest_delete_device(dev);
}
END_TEST
START_TEST(touchpad_2fg_clickfinger)
{
struct litest_device *dev = litest_create_device(LITEST_BCM5974);
struct litest_device *dev = litest_current_device();
struct libinput *li = dev->libinput;
enum libinput_config_status status;
status = libinput_device_config_click_set_method(dev->libinput_device,
LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER);
ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS);
litest_drain_events(li);
@ -754,12 +843,202 @@ START_TEST(touchpad_2fg_clickfinger)
libinput_dispatch(li);
litest_assert_button_event(li, BTN_RIGHT,
LIBINPUT_BUTTON_STATE_PRESSED);
litest_assert_button_event(li, BTN_RIGHT,
LIBINPUT_BUTTON_STATE_RELEASED);
}
END_TEST
START_TEST(touchpad_clickfinger_to_area_method)
{
struct litest_device *dev = litest_current_device();
enum libinput_config_status status;
struct libinput *li = dev->libinput;
litest_drain_events(li);
status = libinput_device_config_click_set_method(dev->libinput_device,
LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS);
ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS);
litest_touch_down(dev, 0, 90, 90);
litest_event(dev, EV_KEY, BTN_LEFT, 1);
litest_event(dev, EV_SYN, SYN_REPORT, 0);
litest_event(dev, EV_KEY, BTN_LEFT, 0);
litest_event(dev, EV_SYN, SYN_REPORT, 0);
litest_touch_up(dev, 0);
libinput_dispatch(li);
litest_assert_button_event(li, BTN_RIGHT,
LIBINPUT_BUTTON_STATE_PRESSED);
litest_assert_button_event(li, BTN_RIGHT,
LIBINPUT_BUTTON_STATE_RELEASED);
status = libinput_device_config_click_set_method(dev->libinput_device,
LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER);
ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS);
litest_drain_events(li);
/* use bottom right corner to catch accidental softbutton right */
litest_touch_down(dev, 0, 90, 90);
litest_event(dev, EV_KEY, BTN_LEFT, 1);
litest_event(dev, EV_SYN, SYN_REPORT, 0);
litest_event(dev, EV_KEY, BTN_LEFT, 0);
litest_event(dev, EV_SYN, SYN_REPORT, 0);
litest_touch_up(dev, 0);
libinput_dispatch(li);
litest_assert_button_event(li, BTN_LEFT,
LIBINPUT_BUTTON_STATE_PRESSED);
litest_assert_button_event(li, BTN_LEFT,
LIBINPUT_BUTTON_STATE_RELEASED);
}
END_TEST
START_TEST(touchpad_clickfinger_to_area_method_while_down)
{
struct litest_device *dev = litest_current_device();
enum libinput_config_status status;
struct libinput *li = dev->libinput;
litest_drain_events(li);
status = libinput_device_config_click_set_method(dev->libinput_device,
LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS);
ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS);
litest_touch_down(dev, 0, 90, 90);
litest_event(dev, EV_KEY, BTN_LEFT, 1);
litest_event(dev, EV_SYN, SYN_REPORT, 0);
libinput_dispatch(li);
litest_assert_button_event(li, BTN_RIGHT,
LIBINPUT_BUTTON_STATE_PRESSED);
status = libinput_device_config_click_set_method(dev->libinput_device,
LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER);
ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS);
litest_event(dev, EV_KEY, BTN_LEFT, 0);
litest_event(dev, EV_SYN, SYN_REPORT, 0);
litest_touch_up(dev, 0);
libinput_dispatch(li);
litest_assert_button_event(li, BTN_RIGHT,
LIBINPUT_BUTTON_STATE_RELEASED);
litest_drain_events(li);
/* use bottom right corner to catch accidental softbutton right */
litest_touch_down(dev, 0, 90, 90);
litest_event(dev, EV_KEY, BTN_LEFT, 1);
litest_event(dev, EV_SYN, SYN_REPORT, 0);
litest_event(dev, EV_KEY, BTN_LEFT, 0);
litest_event(dev, EV_SYN, SYN_REPORT, 0);
litest_touch_up(dev, 0);
libinput_dispatch(li);
litest_assert_button_event(li, BTN_LEFT,
LIBINPUT_BUTTON_STATE_PRESSED);
litest_assert_button_event(li, BTN_LEFT,
LIBINPUT_BUTTON_STATE_RELEASED);
}
END_TEST
START_TEST(touchpad_area_to_clickfinger_method)
{
struct litest_device *dev = litest_current_device();
enum libinput_config_status status;
struct libinput *li = dev->libinput;
status = libinput_device_config_click_set_method(dev->libinput_device,
LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER);
ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS);
litest_drain_events(li);
/* use bottom right corner to catch accidental softbutton right */
litest_touch_down(dev, 0, 90, 90);
litest_event(dev, EV_KEY, BTN_LEFT, 1);
litest_event(dev, EV_SYN, SYN_REPORT, 0);
litest_event(dev, EV_KEY, BTN_LEFT, 0);
litest_event(dev, EV_SYN, SYN_REPORT, 0);
litest_touch_up(dev, 0);
libinput_dispatch(li);
litest_assert_button_event(li, BTN_LEFT,
LIBINPUT_BUTTON_STATE_PRESSED);
litest_assert_button_event(li, BTN_LEFT,
LIBINPUT_BUTTON_STATE_RELEASED);
status = libinput_device_config_click_set_method(dev->libinput_device,
LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS);
ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS);
litest_touch_down(dev, 0, 90, 90);
litest_event(dev, EV_KEY, BTN_LEFT, 1);
litest_event(dev, EV_SYN, SYN_REPORT, 0);
litest_event(dev, EV_KEY, BTN_LEFT, 0);
litest_event(dev, EV_SYN, SYN_REPORT, 0);
litest_touch_up(dev, 0);
libinput_dispatch(li);
litest_assert_button_event(li, BTN_RIGHT,
LIBINPUT_BUTTON_STATE_PRESSED);
litest_assert_button_event(li, BTN_RIGHT,
LIBINPUT_BUTTON_STATE_RELEASED);
}
END_TEST
START_TEST(touchpad_area_to_clickfinger_method_while_down)
{
struct litest_device *dev = litest_current_device();
enum libinput_config_status status;
struct libinput *li = dev->libinput;
status = libinput_device_config_click_set_method(dev->libinput_device,
LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER);
ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS);
litest_drain_events(li);
/* use bottom right corner to catch accidental softbutton right */
litest_touch_down(dev, 0, 90, 90);
litest_event(dev, EV_KEY, BTN_LEFT, 1);
litest_event(dev, EV_SYN, SYN_REPORT, 0);
litest_assert_button_event(li, BTN_LEFT,
LIBINPUT_BUTTON_STATE_PRESSED);
status = libinput_device_config_click_set_method(dev->libinput_device,
LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS);
ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS);
litest_event(dev, EV_KEY, BTN_LEFT, 0);
litest_event(dev, EV_SYN, SYN_REPORT, 0);
litest_touch_up(dev, 0);
libinput_dispatch(li);
litest_assert_button_event(li, BTN_LEFT,
LIBINPUT_BUTTON_STATE_RELEASED);
litest_touch_down(dev, 0, 90, 90);
litest_event(dev, EV_KEY, BTN_LEFT, 1);
litest_event(dev, EV_SYN, SYN_REPORT, 0);
litest_event(dev, EV_KEY, BTN_LEFT, 0);
litest_event(dev, EV_SYN, SYN_REPORT, 0);
litest_touch_up(dev, 0);
libinput_dispatch(li);
litest_assert_button_event(li, BTN_RIGHT,
LIBINPUT_BUTTON_STATE_PRESSED);
litest_assert_button_event(li, BTN_RIGHT,
LIBINPUT_BUTTON_STATE_RELEASED);
litest_delete_device(dev);
}
END_TEST
@ -1371,6 +1650,99 @@ START_TEST(clickpad_topsoftbuttons_move_out_ignore)
}
END_TEST
START_TEST(clickpad_topsoftbuttons_clickfinger)
{
struct litest_device *dev = litest_current_device();
struct libinput *li = dev->libinput;
libinput_device_config_click_set_method(dev->libinput_device,
LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER);
litest_drain_events(li);
litest_touch_down(dev, 0, 90, 5);
litest_event(dev, EV_KEY, BTN_LEFT, 1);
litest_event(dev, EV_SYN, SYN_REPORT, 0);
litest_event(dev, EV_KEY, BTN_LEFT, 0);
litest_event(dev, EV_SYN, SYN_REPORT, 0);
litest_touch_up(dev, 0);
litest_assert_button_event(li,
BTN_LEFT,
LIBINPUT_BUTTON_STATE_PRESSED);
litest_assert_button_event(li,
BTN_LEFT,
LIBINPUT_BUTTON_STATE_RELEASED);
litest_assert_empty_queue(li);
litest_touch_down(dev, 0, 90, 5);
litest_touch_down(dev, 1, 10, 5);
litest_event(dev, EV_KEY, BTN_LEFT, 1);
litest_event(dev, EV_SYN, SYN_REPORT, 0);
litest_event(dev, EV_KEY, BTN_LEFT, 0);
litest_event(dev, EV_SYN, SYN_REPORT, 0);
litest_touch_up(dev, 0);
litest_touch_up(dev, 1);
litest_assert_button_event(li,
BTN_RIGHT,
LIBINPUT_BUTTON_STATE_PRESSED);
litest_assert_button_event(li,
BTN_RIGHT,
LIBINPUT_BUTTON_STATE_RELEASED);
}
END_TEST
START_TEST(clickpad_topsoftbuttons_clickfinger_dev_disabled)
{
struct litest_device *dev = litest_current_device();
struct libinput *li = dev->libinput;
struct litest_device *trackpoint = litest_add_device(li,
LITEST_TRACKPOINT);
libinput_device_config_click_set_method(dev->libinput_device,
LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER);
libinput_device_config_send_events_set_mode(dev->libinput_device,
LIBINPUT_CONFIG_SEND_EVENTS_DISABLED);
litest_drain_events(li);
litest_touch_down(dev, 0, 90, 5);
litest_event(dev, EV_KEY, BTN_LEFT, 1);
litest_event(dev, EV_SYN, SYN_REPORT, 0);
litest_event(dev, EV_KEY, BTN_LEFT, 0);
litest_event(dev, EV_SYN, SYN_REPORT, 0);
litest_touch_up(dev, 0);
litest_assert_button_event(li,
BTN_RIGHT,
LIBINPUT_BUTTON_STATE_PRESSED);
litest_assert_button_event(li,
BTN_RIGHT,
LIBINPUT_BUTTON_STATE_RELEASED);
litest_assert_empty_queue(li);
litest_touch_down(dev, 0, 90, 5);
litest_touch_down(dev, 1, 10, 5);
litest_event(dev, EV_KEY, BTN_LEFT, 1);
litest_event(dev, EV_SYN, SYN_REPORT, 0);
litest_event(dev, EV_KEY, BTN_LEFT, 0);
litest_event(dev, EV_SYN, SYN_REPORT, 0);
litest_touch_up(dev, 0);
litest_touch_up(dev, 1);
litest_assert_button_event(li,
BTN_MIDDLE,
LIBINPUT_BUTTON_STATE_PRESSED);
litest_assert_button_event(li,
BTN_MIDDLE,
LIBINPUT_BUTTON_STATE_RELEASED);
litest_delete_device(trackpoint);
}
END_TEST
static void
test_2fg_scroll(struct litest_device *dev, double dx, double dy, int want_sleep)
{
@ -2207,8 +2579,387 @@ START_TEST(touchpad_left_handed_clickpad_delayed)
}
END_TEST
int main(int argc, char **argv) {
static void
hover_continue(struct litest_device *dev, unsigned int slot,
int x, int y)
{
litest_event(dev, EV_ABS, ABS_MT_SLOT, slot);
litest_event(dev, EV_ABS, ABS_MT_POSITION_X, x);
litest_event(dev, EV_ABS, ABS_MT_POSITION_Y, y);
litest_event(dev, EV_ABS, ABS_X, x);
litest_event(dev, EV_ABS, ABS_Y, y);
litest_event(dev, EV_ABS, ABS_PRESSURE, 10);
litest_event(dev, EV_ABS, ABS_TOOL_WIDTH, 6);
/* WARNING: no SYN_REPORT! */
}
static void
hover_start(struct litest_device *dev, unsigned int slot,
int x, int y)
{
static unsigned int tracking_id;
litest_event(dev, EV_ABS, ABS_MT_SLOT, slot);
litest_event(dev, EV_ABS, ABS_MT_TRACKING_ID, ++tracking_id);
hover_continue(dev, slot, x, y);
/* WARNING: no SYN_REPORT! */
}
START_TEST(touchpad_hover_noevent)
{
struct litest_device *dev = litest_current_device();
struct libinput *li = dev->libinput;
int i;
int x = 2400,
y = 2400;
litest_drain_events(li);
hover_start(dev, 0, x, y);
litest_event(dev, EV_KEY, BTN_TOOL_FINGER, 1);
litest_event(dev, EV_SYN, SYN_REPORT, 0);
for (i = 0; i < 10; i++) {
x += 200;
y -= 200;
litest_event(dev, EV_ABS, ABS_MT_POSITION_X, x);
litest_event(dev, EV_ABS, ABS_MT_POSITION_Y, y);
litest_event(dev, EV_ABS, ABS_X, x);
litest_event(dev, EV_ABS, ABS_Y, y);
litest_event(dev, EV_SYN, SYN_REPORT, 0);
}
litest_event(dev, EV_KEY, BTN_TOOL_FINGER, 0);
litest_event(dev, EV_SYN, SYN_REPORT, 0);
litest_assert_empty_queue(li);
}
END_TEST
START_TEST(touchpad_hover_down)
{
struct litest_device *dev = litest_current_device();
struct libinput *li = dev->libinput;
struct libinput_event *event;
int i;
int x = 2400,
y = 2400;
litest_drain_events(li);
hover_start(dev, 0, x, y);
litest_event(dev, EV_KEY, BTN_TOOL_FINGER, 1);
litest_event(dev, EV_SYN, SYN_REPORT, 0);
for (i = 0; i < 10; i++) {
x += 200;
y -= 200;
litest_event(dev, EV_ABS, ABS_MT_POSITION_X, x);
litest_event(dev, EV_ABS, ABS_MT_POSITION_Y, y);
litest_event(dev, EV_ABS, ABS_X, x);
litest_event(dev, EV_ABS, ABS_Y, y);
litest_event(dev, EV_SYN, SYN_REPORT, 0);
}
litest_assert_empty_queue(li);
litest_event(dev, EV_ABS, ABS_X, x + 100);
litest_event(dev, EV_ABS, ABS_Y, y + 100);
litest_event(dev, EV_KEY, BTN_TOUCH, 1);
litest_event(dev, EV_SYN, SYN_REPORT, 0);
libinput_dispatch(li);
for (i = 0; i < 10; i++) {
x -= 200;
y += 200;
litest_event(dev, EV_ABS, ABS_MT_POSITION_X, x);
litest_event(dev, EV_ABS, ABS_MT_POSITION_Y, y);
litest_event(dev, EV_ABS, ABS_X, x);
litest_event(dev, EV_ABS, ABS_Y, y);
litest_event(dev, EV_SYN, SYN_REPORT, 0);
}
libinput_dispatch(li);
ck_assert_int_ne(libinput_next_event_type(li),
LIBINPUT_EVENT_NONE);
while ((event = libinput_get_event(li)) != NULL) {
ck_assert_int_eq(libinput_event_get_type(event),
LIBINPUT_EVENT_POINTER_MOTION);
libinput_event_destroy(event);
libinput_dispatch(li);
}
/* go back to hover */
hover_continue(dev, 0, x, y);
litest_event(dev, EV_KEY, BTN_TOUCH, 0);
litest_event(dev, EV_SYN, SYN_REPORT, 0);
for (i = 0; i < 10; i++) {
x += 200;
y -= 200;
litest_event(dev, EV_ABS, ABS_MT_POSITION_X, x);
litest_event(dev, EV_ABS, ABS_MT_POSITION_Y, y);
litest_event(dev, EV_ABS, ABS_X, x);
litest_event(dev, EV_ABS, ABS_Y, y);
litest_event(dev, EV_SYN, SYN_REPORT, 0);
}
litest_event(dev, EV_KEY, BTN_TOOL_FINGER, 0);
litest_event(dev, EV_SYN, SYN_REPORT, 0);
litest_assert_empty_queue(li);
}
END_TEST
START_TEST(touchpad_hover_down_hover_down)
{
struct litest_device *dev = litest_current_device();
struct libinput *li = dev->libinput;
struct libinput_event *event;
int i, j;
int x = 1400,
y = 1400;
litest_drain_events(li);
/* hover */
hover_start(dev, 0, x, y);
litest_event(dev, EV_KEY, BTN_TOOL_FINGER, 1);
litest_event(dev, EV_SYN, SYN_REPORT, 0);
litest_assert_empty_queue(li);
for (i = 0; i < 3; i++) {
/* touch */
litest_event(dev, EV_ABS, ABS_X, x + 100);
litest_event(dev, EV_ABS, ABS_Y, y + 100);
litest_event(dev, EV_KEY, BTN_TOUCH, 1);
litest_event(dev, EV_SYN, SYN_REPORT, 0);
libinput_dispatch(li);
for (j = 0; j < 5; j++) {
x += 200;
y += 200;
litest_event(dev, EV_ABS, ABS_MT_POSITION_X, x);
litest_event(dev, EV_ABS, ABS_MT_POSITION_Y, y);
litest_event(dev, EV_ABS, ABS_X, x);
litest_event(dev, EV_ABS, ABS_Y, y);
litest_event(dev, EV_SYN, SYN_REPORT, 0);
}
libinput_dispatch(li);
ck_assert_int_ne(libinput_next_event_type(li),
LIBINPUT_EVENT_NONE);
while ((event = libinput_get_event(li)) != NULL) {
ck_assert_int_eq(libinput_event_get_type(event),
LIBINPUT_EVENT_POINTER_MOTION);
libinput_event_destroy(event);
libinput_dispatch(li);
}
/* go back to hover */
hover_continue(dev, 0, x, y);
litest_event(dev, EV_KEY, BTN_TOUCH, 0);
litest_event(dev, EV_SYN, SYN_REPORT, 0);
for (j = 0; j < 5; j++) {
x += 200;
y += 200;
litest_event(dev, EV_ABS, ABS_MT_POSITION_X, x);
litest_event(dev, EV_ABS, ABS_MT_POSITION_Y, y);
litest_event(dev, EV_ABS, ABS_X, x);
litest_event(dev, EV_ABS, ABS_Y, y);
litest_event(dev, EV_SYN, SYN_REPORT, 0);
}
litest_assert_empty_queue(li);
}
/* touch */
litest_event(dev, EV_KEY, BTN_TOOL_FINGER, 0);
litest_event(dev, EV_SYN, SYN_REPORT, 0);
litest_assert_empty_queue(li);
/* start a new touch to be sure */
litest_touch_down(dev, 0, 50, 50);
litest_touch_move_to(dev, 0, 50, 50, 70, 70, 10, 10);
litest_touch_up(dev, 0);
libinput_dispatch(li);
ck_assert_int_ne(libinput_next_event_type(li),
LIBINPUT_EVENT_NONE);
while ((event = libinput_get_event(li)) != NULL) {
ck_assert_int_eq(libinput_event_get_type(event),
LIBINPUT_EVENT_POINTER_MOTION);
libinput_event_destroy(event);
libinput_dispatch(li);
}
}
END_TEST
START_TEST(touchpad_hover_down_up)
{
struct litest_device *dev = litest_current_device();
struct libinput *li = dev->libinput;
int i;
int x = 1400,
y = 1400;
litest_drain_events(li);
/* hover two fingers, then touch */
hover_start(dev, 0, x, y);
litest_event(dev, EV_KEY, BTN_TOOL_FINGER, 1);
litest_event(dev, EV_SYN, SYN_REPORT, 0);
litest_assert_empty_queue(li);
hover_start(dev, 1, x, y);
litest_event(dev, EV_KEY, BTN_TOOL_FINGER, 0);
litest_event(dev, EV_KEY, BTN_TOOL_DOUBLETAP, 1);
litest_event(dev, EV_SYN, SYN_REPORT, 0);
litest_assert_empty_queue(li);
litest_event(dev, EV_KEY, BTN_TOOL_DOUBLETAP, 0);
litest_event(dev, EV_KEY, BTN_TOOL_TRIPLETAP, 1);
litest_event(dev, EV_KEY, BTN_TOUCH, 1);
litest_event(dev, EV_SYN, SYN_REPORT, 0);
litest_assert_empty_queue(li);
/* hover first finger, end second in same frame */
litest_event(dev, EV_ABS, ABS_MT_SLOT, 1);
litest_event(dev, EV_ABS, ABS_MT_TRACKING_ID, -1);
litest_event(dev, EV_KEY, BTN_TOOL_TRIPLETAP, 0);
litest_event(dev, EV_KEY, BTN_TOOL_FINGER, 1);
litest_event(dev, EV_KEY, BTN_TOUCH, 0);
litest_event(dev, EV_SYN, SYN_REPORT, 0);
litest_assert_empty_queue(li);
litest_event(dev, EV_KEY, BTN_TOUCH, 1);
litest_event(dev, EV_SYN, SYN_REPORT, 0);
libinput_dispatch(li);
/* now move the finger */
for (i = 0; i < 10; i++) {
litest_event(dev, EV_ABS, ABS_MT_SLOT, 0);
litest_event(dev, EV_ABS, ABS_MT_POSITION_X, x);
litest_event(dev, EV_ABS, ABS_MT_POSITION_Y, y);
litest_event(dev, EV_ABS, ABS_X, x);
litest_event(dev, EV_ABS, ABS_Y, y);
litest_event(dev, EV_SYN, SYN_REPORT, 0);
x -= 100;
y -= 100;
}
litest_assert_only_typed_events(li,
LIBINPUT_EVENT_POINTER_MOTION);
litest_event(dev, EV_ABS, ABS_MT_SLOT, 0);
litest_event(dev, EV_ABS, ABS_MT_TRACKING_ID, -1);
litest_event(dev, EV_KEY, BTN_TOOL_FINGER, 0);
litest_event(dev, EV_KEY, BTN_TOUCH, 0);
litest_event(dev, EV_SYN, SYN_REPORT, 0);
libinput_dispatch(li);
}
END_TEST
START_TEST(touchpad_hover_2fg_noevent)
{
struct litest_device *dev = litest_current_device();
struct libinput *li = dev->libinput;
int i;
int x = 2400,
y = 2400;
litest_drain_events(li);
hover_start(dev, 0, x, y);
litest_event(dev, EV_KEY, BTN_TOOL_FINGER, 1);
litest_event(dev, EV_SYN, SYN_REPORT, 0);
hover_start(dev, 1, x + 500, y + 500);
litest_event(dev, EV_KEY, BTN_TOOL_FINGER, 0);
litest_event(dev, EV_KEY, BTN_TOOL_DOUBLETAP, 1);
litest_event(dev, EV_SYN, SYN_REPORT, 0);
for (i = 0; i < 10; i++) {
x += 200;
y -= 200;
litest_event(dev, EV_ABS, ABS_MT_SLOT, 0);
litest_event(dev, EV_ABS, ABS_MT_POSITION_X, x);
litest_event(dev, EV_ABS, ABS_MT_POSITION_Y, y);
litest_event(dev, EV_ABS, ABS_MT_SLOT, 1);
litest_event(dev, EV_ABS, ABS_MT_POSITION_X, x + 500);
litest_event(dev, EV_ABS, ABS_MT_POSITION_Y, y + 500);
litest_event(dev, EV_ABS, ABS_X, x);
litest_event(dev, EV_ABS, ABS_Y, y);
litest_event(dev, EV_SYN, SYN_REPORT, 0);
}
litest_event(dev, EV_KEY, BTN_TOOL_DOUBLETAP, 0);
litest_event(dev, EV_SYN, SYN_REPORT, 0);
litest_assert_empty_queue(li);
litest_event(dev, EV_KEY, BTN_TOOL_FINGER, 0);
litest_event(dev, EV_SYN, SYN_REPORT, 0);
litest_assert_empty_queue(li);
}
END_TEST
START_TEST(touchpad_hover_2fg_1fg_down)
{
struct litest_device *dev = litest_current_device();
struct libinput *li = dev->libinput;
struct libinput_event *event;
int i;
int x = 2400,
y = 2400;
litest_drain_events(li);
/* two slots active, but BTN_TOOL_FINGER only */
hover_start(dev, 0, x, y);
hover_start(dev, 1, x + 500, y + 500);
litest_event(dev, EV_KEY, BTN_TOUCH, 1);
litest_event(dev, EV_KEY, BTN_TOOL_FINGER, 1);
litest_event(dev, EV_SYN, SYN_REPORT, 0);
for (i = 0; i < 10; i++) {
x += 200;
y -= 200;
litest_event(dev, EV_ABS, ABS_MT_SLOT, 0);
litest_event(dev, EV_ABS, ABS_MT_POSITION_X, x);
litest_event(dev, EV_ABS, ABS_MT_POSITION_Y, y);
litest_event(dev, EV_ABS, ABS_MT_SLOT, 1);
litest_event(dev, EV_ABS, ABS_MT_POSITION_X, x + 500);
litest_event(dev, EV_ABS, ABS_MT_POSITION_Y, y + 500);
litest_event(dev, EV_ABS, ABS_X, x);
litest_event(dev, EV_ABS, ABS_Y, y);
litest_event(dev, EV_SYN, SYN_REPORT, 0);
}
litest_event(dev, EV_KEY, BTN_TOUCH, 0);
litest_event(dev, EV_KEY, BTN_TOOL_FINGER, 0);
litest_event(dev, EV_SYN, SYN_REPORT, 0);
libinput_dispatch(li);
ck_assert_int_ne(libinput_next_event_type(li),
LIBINPUT_EVENT_NONE);
while ((event = libinput_get_event(li)) != NULL) {
ck_assert_int_eq(libinput_event_get_type(event),
LIBINPUT_EVENT_POINTER_MOTION);
libinput_event_destroy(event);
libinput_dispatch(li);
}
}
END_TEST
int main(int argc, char **argv) {
litest_add("touchpad:motion", touchpad_1fg_motion, LITEST_TOUCHPAD, LITEST_ANY);
litest_add("touchpad:motion", touchpad_2fg_no_motion, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH);
@ -2246,8 +2997,18 @@ int main(int argc, char **argv) {
litest_add("touchpad:tap", clickpad_1fg_tap_click, LITEST_CLICKPAD, LITEST_ANY);
litest_add("touchpad:tap", clickpad_2fg_tap_click, LITEST_CLICKPAD, LITEST_SINGLE_TOUCH|LITEST_APPLE_CLICKPAD);
litest_add_no_device("touchpad:clickfinger", touchpad_1fg_clickfinger);
litest_add_no_device("touchpad:clickfinger", touchpad_2fg_clickfinger);
litest_add("touchpad:clickfinger", touchpad_1fg_clickfinger, LITEST_CLICKPAD, LITEST_ANY);
litest_add("touchpad:clickfinger", touchpad_2fg_clickfinger, LITEST_CLICKPAD, LITEST_ANY);
litest_add("touchpad:clickfinger", touchpad_clickfinger_to_area_method, LITEST_CLICKPAD, LITEST_ANY);
litest_add("touchpad:clickfinger",
touchpad_clickfinger_to_area_method_while_down, LITEST_CLICKPAD, LITEST_ANY);
litest_add("touchpad:clickfinger", touchpad_area_to_clickfinger_method, LITEST_CLICKPAD, LITEST_ANY);
litest_add("touchpad:clickfinger",
touchpad_area_to_clickfinger_method_while_down, LITEST_CLICKPAD, LITEST_ANY);
litest_add("touchpad:click", touchpad_click_defaults_clickfinger, LITEST_APPLE_CLICKPAD, LITEST_ANY);
litest_add("touchpad:click", touchpad_click_defaults_btnarea, LITEST_CLICKPAD, LITEST_APPLE_CLICKPAD);
litest_add("touchpad:click", touchpad_click_defaults_none, LITEST_TOUCHPAD, LITEST_CLICKPAD);
litest_add("touchpad:click", touchpad_btn_left, LITEST_TOUCHPAD, LITEST_CLICKPAD);
litest_add("touchpad:click", clickpad_btn_left, LITEST_CLICKPAD, LITEST_ANY);
@ -2266,6 +3027,8 @@ int main(int argc, char **argv) {
litest_add("touchpad:topsoftbuttons", clickpad_topsoftbuttons_right, LITEST_TOPBUTTONPAD, LITEST_ANY);
litest_add("touchpad:topsoftbuttons", clickpad_topsoftbuttons_middle, LITEST_TOPBUTTONPAD, LITEST_ANY);
litest_add("touchpad:topsoftbuttons", clickpad_topsoftbuttons_move_out_ignore, LITEST_TOPBUTTONPAD, LITEST_ANY);
litest_add("touchpad:topsoftbuttons", clickpad_topsoftbuttons_clickfinger, LITEST_TOPBUTTONPAD, LITEST_ANY);
litest_add("touchpad:topsoftbuttons", clickpad_topsoftbuttons_clickfinger_dev_disabled, LITEST_TOPBUTTONPAD, LITEST_ANY);
litest_add("touchpad:scroll", touchpad_2fg_scroll, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH);
litest_add("touchpad:scroll", touchpad_2fg_scroll_slow_distance, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH);
@ -2295,5 +3058,14 @@ int main(int argc, char **argv) {
litest_add("touchpad:left-handed", touchpad_left_handed_delayed, LITEST_TOUCHPAD, LITEST_CLICKPAD);
litest_add("touchpad:left-handed", touchpad_left_handed_clickpad_delayed, LITEST_CLICKPAD, LITEST_APPLE_CLICKPAD);
/* Hover tests aren't generic, they only work on this device and
* ignore the semi-mt capability (it doesn't matter for the tests */
litest_add_for_device("touchpad:hover", touchpad_hover_noevent, LITEST_SYNAPTICS_HOVER_SEMI_MT);
litest_add_for_device("touchpad:hover", touchpad_hover_down, LITEST_SYNAPTICS_HOVER_SEMI_MT);
litest_add_for_device("touchpad:hover", touchpad_hover_down_up, LITEST_SYNAPTICS_HOVER_SEMI_MT);
litest_add_for_device("touchpad:hover", touchpad_hover_down_hover_down, LITEST_SYNAPTICS_HOVER_SEMI_MT);
litest_add_for_device("touchpad:hover", touchpad_hover_2fg_noevent, LITEST_SYNAPTICS_HOVER_SEMI_MT);
litest_add_for_device("touchpad:hover", touchpad_hover_2fg_1fg_down, LITEST_SYNAPTICS_HOVER_SEMI_MT);
return litest_run(argc, argv);
}

View file

@ -43,6 +43,7 @@ enum options {
OPT_NATURAL_SCROLL_DISABLE,
OPT_LEFT_HANDED_ENABLE,
OPT_LEFT_HANDED_DISABLE,
OPT_CLICK_METHOD,
};
static void
@ -69,6 +70,7 @@ tools_usage()
"--disable-natural-scrolling.... enable/disable natural scrolling\n"
"--enable-left-handed\n"
"--disable-left-handed.... enable/disable left-handed button configuration\n"
"--set-click-method=[none|clickfinger|buttonareas] .... set the desired click method\n"
"\n"
"These options apply to all applicable devices, if a feature\n"
"is not explicitly specified it is left at each device's default.\n"
@ -86,6 +88,7 @@ tools_init_options(struct tools_options *options)
options->tapping = -1;
options->natural_scroll = -1;
options->left_handed = -1;
options->click_method = -1;
options->backend = BACKEND_UDEV;
options->seat = "seat0";
}
@ -107,6 +110,7 @@ tools_parse_args(int argc, char **argv, struct tools_options *options)
{ "disable-natural-scrolling", 0, 0, OPT_NATURAL_SCROLL_DISABLE },
{ "enable-left-handed", 0, 0, OPT_LEFT_HANDED_ENABLE },
{ "disable-left-handed", 0, 0, OPT_LEFT_HANDED_DISABLE },
{ "set-click-method", 1, 0, OPT_CLICK_METHOD },
{ 0, 0, 0, 0}
};
@ -153,6 +157,25 @@ tools_parse_args(int argc, char **argv, struct tools_options *options)
case OPT_LEFT_HANDED_DISABLE:
options->left_handed = 0;
break;
case OPT_CLICK_METHOD:
if (!optarg) {
tools_usage();
return 1;
}
if (strcmp(optarg, "none") == 0) {
options->click_method =
LIBINPUT_CONFIG_CLICK_METHOD_NONE;
} else if (strcmp(optarg, "clickfinger") == 0) {
options->click_method =
LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER;
} else if (strcmp(optarg, "buttonareas") == 0) {
options->click_method =
LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS;
} else {
tools_usage();
return 1;
}
break;
default:
tools_usage();
return 1;
@ -263,4 +286,7 @@ tools_device_apply_config(struct libinput_device *device,
options->natural_scroll);
if (options->left_handed != -1)
libinput_device_config_left_handed_set(device, options->left_handed);
if (options->click_method != -1)
libinput_device_config_click_set_method(device, options->click_method);
}

View file

@ -39,6 +39,7 @@ struct tools_options {
int tapping;
int natural_scroll;
int left_handed;
enum libinput_config_click_method click_method;
};
void tools_init_options(struct tools_options *options);