[PATCH libinput 3/3] touchpad: add support for per-finger hovering information

Peter Hutterer peter.hutterer at who-t.net
Tue May 5 22:08:09 PDT 2015


On Thu, Apr 30, 2015 at 04:30:25PM -0400, Benjamin Tissoires wrote:
> From: Benjamin Tissoires <benjamin.tissoires at redhat.com>
> 
> When the device supports true hovering, it reports this
> information through ABS_MT_DISTANCE.
> When this axis is available, we should rely on it to
> (un)hover the touches as BTN_TOUCH is most of the time
> unreliable (generated by the mouse emulation in the kernel).
> 
> Signed-off-by: Benjamin Tissoires <benjamin.tissoires at gmail.com>
> ---
>  src/evdev-mt-touchpad.c   |   40 +++++++++++-
>  src/evdev-mt-touchpad.h   |    2 +
>  test/Makefile.am          |    1 +
>  test/litest-atmel-hover.c |  149 ++++++++++++++++++++++++++++++++++++++++
>  test/litest.c             |  153 +++++++++++++++++++++++++++++++++++++-----
>  test/litest.h             |   26 +++++++-
>  test/touchpad.c           |  166 +++++++++++++++++++++++++++++++++++++++++++++
>  7 files changed, 519 insertions(+), 18 deletions(-)
>  create mode 100644 test/litest-atmel-hover.c
> 
> diff --git a/src/evdev-mt-touchpad.c b/src/evdev-mt-touchpad.c
> index d5ce880..5b7f291 100644
> --- a/src/evdev-mt-touchpad.c
> +++ b/src/evdev-mt-touchpad.c
> @@ -300,6 +300,9 @@ tp_process_absolute(struct tp_dispatch *tp,
>  	case ABS_MT_SLOT:
>  		tp->slot = e->value;
>  		break;
> +	case ABS_MT_DISTANCE:
> +		t->distance = e->value;
> +		break;
>  	case ABS_MT_TRACKING_ID:
>  		if (e->value != -1)
>  			tp_new_touch(tp, t, time);
> @@ -520,7 +523,29 @@ tp_palm_detect(struct tp_dispatch *tp, struct tp_touch *t, uint64_t time)
>  }
>  
>  static void
> -tp_unhover_touches(struct tp_dispatch *tp, uint64_t time)
> +tp_unhover_abs_distance(struct tp_dispatch *tp, uint64_t time)
> +{
> +	struct tp_touch *t;
> +	int i;
> +
> +	for (i = 0; i < (int)tp->ntouches; i++) {
> +		t = tp_get_touch(tp, i);

maybe a leftover, but can't we make i an unsigned int to save the cast?

> +
> +		if (t->state == TOUCH_HOVERING) {
> +			if (t->distance == 0) {
> +				/* avoid jumps when landing a finger */
> +				tp_motion_history_reset(t);
> +				tp_begin_touch(tp, t, time);
> +			}
> +		} else {
> +			if (t->distance > 0)
> +				tp_end_touch(tp, t, time);
> +		}
> +	}
> +}
> +
> +static void
> +tp_unhover_fake_touches(struct tp_dispatch *tp, uint64_t time)
>  {
>  	struct tp_touch *t;
>  	unsigned int nfake_touches;
> @@ -579,6 +604,16 @@ tp_unhover_touches(struct tp_dispatch *tp, uint64_t time)
>  }
>  
>  static void
> +tp_unhover_touches(struct tp_dispatch *tp, uint64_t time)
> +{
> +	if (tp->reports_distance)
> +		tp_unhover_abs_distance(tp, time);
> +	else
> +		tp_unhover_fake_touches(tp, time);
> +
> +}
> +
> +static void
>  tp_process_state(struct tp_dispatch *tp, uint64_t time)
>  {
>  	struct tp_touch *t;
> @@ -1184,6 +1219,9 @@ tp_init(struct tp_dispatch *tp,
>  		     device->abs.absinfo_y->minimum);
>  	diagonal = sqrt(width*width + height*height);
>  
> +	tp->reports_distance = libevdev_has_event_code(device->evdev, EV_ABS,
> +						       ABS_MT_DISTANCE);

nitpick: if the line break is needed, one arg per line (i.e. EV_ABS goes on
its own line)

> +
>  	tp->hysteresis_margin.x =
>  		diagonal / DEFAULT_HYSTERESIS_MARGIN_DENOMINATOR;
>  	tp->hysteresis_margin.y =
> diff --git a/src/evdev-mt-touchpad.h b/src/evdev-mt-touchpad.h
> index 97b17cd..ebba9df 100644
> --- a/src/evdev-mt-touchpad.h
> +++ b/src/evdev-mt-touchpad.h
> @@ -129,6 +129,7 @@ struct tp_touch {
>  	bool dirty;
>  	struct device_coords point;
>  	uint64_t millis;
> +	int distance;				/* distance == 0 means touch */
>  
>  	struct {
>  		struct device_coords samples[TOUCHPAD_HISTORY_LENGTH];
> @@ -183,6 +184,7 @@ struct tp_dispatch {
>  	unsigned int slot;			/* current slot */
>  	bool has_mt;
>  	bool semi_mt;
> +	bool reports_distance;			/* does the device supports true hovering */
>  	enum touchpad_model model;
>  
>  	unsigned int num_slots;			/* number of slots */
> diff --git a/test/Makefile.am b/test/Makefile.am
> index be0c5d9..a90fa78 100644
> --- a/test/Makefile.am
> +++ b/test/Makefile.am
> @@ -14,6 +14,7 @@ liblitest_la_SOURCES = \
>  	litest.h \
>  	litest-int.h \
>  	litest-alps-semi-mt.c \
> +	litest-atmel-hover.c \
>  	litest-bcm5974.c \
>  	litest-generic-singletouch.c \
>  	litest-keyboard.c \
> diff --git a/test/litest-atmel-hover.c b/test/litest-atmel-hover.c
> new file mode 100644
> index 0000000..7da0901
> --- /dev/null
> +++ b/test/litest-atmel-hover.c
> @@ -0,0 +1,149 @@
> +/*
> + * Copyright ?? 2015 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
> +atmel_hover_create(struct litest_device *d);
> +
> +static void
> +litest_atmel_hover_setup(void)
> +{
> +	struct litest_device *d = litest_create_device(LITEST_ATMEL_HOVER);
> +	litest_set_current_device(d);
> +}
> +
> +static struct input_event down[] = {
> +	{ .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_PRESSURE, .value = LITEST_AUTO_ASSIGN  },
> +	{ .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_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_DISTANCE, .value = LITEST_AUTO_ASSIGN },
> +	{ .type = EV_ABS, .code = ABS_MT_PRESSURE, .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_PRESSURE, .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_DISTANCE, .value = LITEST_AUTO_ASSIGN },
> +	{ .type = EV_ABS, .code = ABS_MT_PRESSURE, .value = LITEST_AUTO_ASSIGN  },
> +	{ .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 = LITEST_AUTO_ASSIGN },
> +	{ .type = EV_ABS, .code = ABS_MT_TRACKING_ID, .value = -1 },
> +	{ .type = EV_ABS, .code = ABS_MT_DISTANCE, .value = 1 },
> +	{ .type = EV_ABS, .code = ABS_MT_PRESSURE, .value = 0  },
> +	{ .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,
> +	.touch_up_events = up,
> +};
> +
> +static struct input_id input_id = {
> +	.bustype = 0x18,
> +	.vendor = 0x0,
> +	.product = 0x0,
> +};
> +
> +static int events[] = {
> +	EV_KEY, BTN_LEFT,
> +	EV_KEY, BTN_TOOL_FINGER,
> +	EV_KEY, BTN_TOUCH,
> +	EV_KEY, BTN_TOOL_DOUBLETAP,
> +	EV_KEY, BTN_TOOL_TRIPLETAP,
> +	EV_KEY, BTN_TOOL_QUADTAP,
> +	EV_KEY, BTN_TOOL_QUINTTAP,
> +	INPUT_PROP_MAX, INPUT_PROP_POINTER,
> +	INPUT_PROP_MAX, INPUT_PROP_BUTTONPAD,
> +	-1, -1,
> +};
> +
> +static struct input_absinfo absinfo[] = {
> +	{ ABS_X, 0, 960, 0, 0, 10 },
> +	{ ABS_Y, 0, 540, 0, 0, 10 },
> +	{ ABS_PRESSURE, 0, 255, 0, 0, 0 },
> +	{ ABS_MT_SLOT, 0, 9, 0, 0, 0 },
> +	{ ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0, 0 },
> +	{ ABS_MT_ORIENTATION, 0, 255, 0, 0, 0 },
> +	{ ABS_MT_POSITION_X, 0, 960, 0, 0, 10 },
> +	{ ABS_MT_POSITION_Y, 0, 540, 0, 0, 10 },
> +	{ ABS_MT_TOOL_TYPE, 0, 2, 0, 0, 0 },
> +	{ ABS_MT_TRACKING_ID, 0, 65535, 0, 0, 0 },
> +	{ ABS_MT_PRESSURE, 0, 255, 0, 0, 0 },
> +	{ ABS_MT_DISTANCE, 0, 1, 0, 0, 0 },
> +	{ .value = -1 }
> +};
> +
> +struct litest_test_device litest_atmel_hover_device = {
> +	.type = LITEST_ATMEL_HOVER,
> +	.features = LITEST_TOUCHPAD | LITEST_BUTTON | LITEST_CLICKPAD | LITEST_HOVER,
> +	.shortname = "atmel hover",
> +	.setup = litest_atmel_hover_setup,
> +	.interface = &interface,
> +	.create = atmel_hover_create,
> +
> +	.name = "Atmel maXTouch Touchpad",
> +	.id = &input_id,
> +	.events = events,
> +	.absinfo = absinfo,
> +};
> +
> +static void
> +atmel_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_atmel_hover_device.name,
> +			litest_atmel_hover_device.id,
> +			absinfo,
> +			events);
> +	d->interface = &interface;
> +}
> diff --git a/test/litest.c b/test/litest.c
> index 15fc87e..fa5095b 100644
> --- a/test/litest.c
> +++ b/test/litest.c
> @@ -103,6 +103,7 @@ extern struct litest_test_device litest_wheel_only_device;
>  extern struct litest_test_device litest_mouse_roccat_device;
>  extern struct litest_test_device litest_ms_surface_cover_device;
>  extern struct litest_test_device litest_logitech_trackball_device;
> +extern struct litest_test_device litest_atmel_hover_device;
>  
>  struct litest_test_device* devices[] = {
>  	&litest_synaptics_clickpad_device,
> @@ -127,6 +128,7 @@ struct litest_test_device* devices[] = {
>  	&litest_mouse_roccat_device,
>  	&litest_ms_surface_cover_device,
>  	&litest_logitech_trackball_device,
> +	&litest_atmel_hover_device,
>  	NULL,
>  };
>  
> @@ -794,7 +796,8 @@ litest_event(struct litest_device *d, unsigned int type,
>  int
>  litest_auto_assign_value(struct litest_device *d,
>  			 const struct input_event *ev,
> -			 int slot, double x, double y)
> +			 int slot, double x, double y,
> +			 int touching)
>  {
>  	static int tracking_id;
>  	int value = ev->value;
> @@ -817,6 +820,9 @@ litest_auto_assign_value(struct litest_device *d,
>  	case ABS_MT_SLOT:
>  		value = slot;
>  		break;
> +	case ABS_MT_DISTANCE:
> +		value = touching ? 0 : 1;
> +		break;
>  	}
>  
>  	return value;
> @@ -833,9 +839,17 @@ send_btntool(struct litest_device *d)
>  	litest_event(d, EV_KEY, BTN_TOOL_QUINTTAP, d->ntouches_down == 5);
>  }
>  
> -void
> -litest_touch_down(struct litest_device *d, unsigned int slot,
> -		  double x, double y)
> +static inline int
> +litest_validate_event(struct input_event *ev, int send_ev_syn)
> +{
> +	return !((int16_t)ev->type == EV_SYN &&
> +		(int16_t)ev->code == SYN_REPORT &&

are those casts needed?

also, this function is a bit awkwardly named: it doesn't validate as such,
it just tells us when to filter syn events.

and that brings us to the next bit: I think you can use
litest_push_event_frame()/litest_pop_event_frame() instead of passing a
parameter around. more on that in the tests below.


> +		!send_ev_syn);
> +}


> +
> +static void
> +litest_slot_start(struct litest_device *d, unsigned int slot,
> +		   double x, double y, int touching, int sync)
>  {
>  	struct input_event *ev;
>  
> @@ -851,13 +865,22 @@ litest_touch_down(struct litest_device *d, unsigned int slot,
>  
>  	ev = d->interface->touch_down_events;
>  	while (ev && (int16_t)ev->type != -1 && (int16_t)ev->code != -1) {
> -		int value = litest_auto_assign_value(d, ev, slot, x, y);
> -		litest_event(d, ev->type, ev->code, value);
> +		int value = litest_auto_assign_value(d, ev, slot, x, y, touching);
> +
> +		if (litest_validate_event(ev, sync))
> +			litest_event(d, ev->type, ev->code, value);
>  		ev++;
>  	}
>  }
>  
>  void
> +litest_touch_down(struct litest_device *d, unsigned int slot,
> +		  double x, double y)
> +{
> +	litest_slot_start(d, slot, x, y, 1, 1);
> +}
> +
> +void
>  litest_touch_up(struct litest_device *d, unsigned int slot)
>  {
>  	struct input_event *ev;
> @@ -882,15 +905,15 @@ litest_touch_up(struct litest_device *d, unsigned int slot)
>  		ev = up;
>  
>  	while (ev && (int16_t)ev->type != -1 && (int16_t)ev->code != -1) {
> -		int value = litest_auto_assign_value(d, ev, slot, 0, 0);
> +		int value = litest_auto_assign_value(d, ev, slot, 0, 0, 0);
>  		litest_event(d, ev->type, ev->code, value);
>  		ev++;
>  	}
>  }
>  
> -void
> -litest_touch_move(struct litest_device *d, unsigned int slot,
> -		  double x, double y)
> +static void
> +litest_slot_move(struct litest_device *d, unsigned int slot,
> +		   double x, double y, int touching, int sync)
>  {
>  	struct input_event *ev;
>  
> @@ -901,13 +924,21 @@ litest_touch_move(struct litest_device *d, unsigned int slot,
>  
>  	ev = d->interface->touch_move_events;
>  	while (ev && (int16_t)ev->type != -1 && (int16_t)ev->code != -1) {
> -		int value = litest_auto_assign_value(d, ev, slot, x, y);
> -		litest_event(d, ev->type, ev->code, value);
> +		int value = litest_auto_assign_value(d, ev, slot, x, y, touching);
> +		if (litest_validate_event(ev, sync))
> +			litest_event(d, ev->type, ev->code, value);
>  		ev++;
>  	}
>  }
>  
>  void
> +litest_touch_move(struct litest_device *d, unsigned int slot,
> +		  double x, double y)
> +{
> +	litest_slot_move(d, slot, x, y, 1, 1);
> +}
> +
> +void
>  litest_touch_move_to(struct litest_device *d,
>  		     unsigned int slot,
>  		     double x_from, double y_from,
> @@ -950,6 +981,96 @@ litest_touch_move_two_touches(struct litest_device *d,
>  }
>  
>  void
> +litest_hover_start(struct litest_device *d, unsigned int slot,
> +		   double x, double y, int sync)
> +{
> +	litest_slot_start(d, slot, x, y, 0, sync);
> +}
> +
> +void
> +litest_hover_end(struct litest_device *d, unsigned int slot, int sync)
> +{
> +	struct input_event *ev;
> +	struct input_event up[] = {
> +		{ .type = EV_ABS, .code = ABS_MT_SLOT, .value = LITEST_AUTO_ASSIGN },
> +		{ .type = EV_ABS, .code = ABS_MT_DISTANCE, .value = 1 },
> +		{ .type = EV_ABS, .code = ABS_MT_TRACKING_ID, .value = -1 },
> +		{ .type = EV_SYN, .code = SYN_REPORT, .value = 0 },
> +		{ .type = -1, .code = -1 }
> +	};
> +
> +	assert(d->ntouches_down > 0);
> +	d->ntouches_down--;
> +
> +	send_btntool(d);
> +
> +	if (d->interface->touch_up) {
> +		d->interface->touch_up(d, slot);
> +		return;
> +	} else if (d->interface->touch_up_events) {
> +		ev = d->interface->touch_up_events;
> +	} else
> +		ev = up;
> +
> +	while (ev && (int16_t)ev->type != -1 && (int16_t)ev->code != -1) {
> +		int value = litest_auto_assign_value(d, ev, slot, 0, 0, 0);
> +		if (litest_validate_event(ev, sync))
> +			litest_event(d, ev->type, ev->code, value);
> +		ev++;
> +	}
> +}
> +
> +void
> +litest_hover_move(struct litest_device *d, unsigned int slot,
> +		  double x, double y, int sync)
> +{
> +	litest_slot_move(d, slot, x, y, 0, sync);
> +}
> +
> +void
> +litest_hover_move_to(struct litest_device *d,
> +		     unsigned int slot,
> +		     double x_from, double y_from,
> +		     double x_to, double y_to,
> +		     int steps, int sleep_ms, int sync)
> +{
> +	for (int i = 0; i < steps - 1; i++) {
> +		litest_hover_move(d, slot,
> +				  x_from + (x_to - x_from)/steps * i,
> +				  y_from + (y_to - y_from)/steps * i,
> +				  sync);
> +		if (sleep_ms) {
> +			libinput_dispatch(d->libinput);
> +			msleep(sleep_ms);
> +			libinput_dispatch(d->libinput);
> +		}
> +	}
> +	litest_hover_move(d, slot, x_to, y_to, sync);
> +}
> +
> +void
> +litest_hover_move_two_touches(struct litest_device *d,
> +			      double x0, double y0,
> +			      double x1, double y1,
> +			      double dx, double dy,
> +			      int steps, int sleep_ms)
> +{
> +	for (int i = 0; i < steps - 1; i++) {
> +		litest_hover_move(d, 0, x0 + dx / steps * i,
> +					y0 + dy / steps * i, 0);
> +		litest_hover_move(d, 1, x1 + dx / steps * i,
> +					y1 + dy / steps * i, 1);
> +		if (sleep_ms) {
> +			libinput_dispatch(d->libinput);
> +			msleep(sleep_ms);
> +			libinput_dispatch(d->libinput);
> +		}
> +	}
> +	litest_hover_move(d, 0, x0 + dx, y0 + dy, 0);
> +	litest_hover_move(d, 1, x1 + dx, y1 + dy, 1);
> +}
> +
> +void
>  litest_button_click(struct litest_device *d, unsigned int button, bool is_press)
>  {
>  
> @@ -1484,11 +1605,11 @@ send_abs_xy(struct litest_device *d, double x, double y)
>  	e.type = EV_ABS;
>  	e.code = ABS_X;
>  	e.value = LITEST_AUTO_ASSIGN;
> -	val = litest_auto_assign_value(d, &e, 0, x, y);
> +	val = litest_auto_assign_value(d, &e, 0, x, y, 1);
>  	litest_event(d, EV_ABS, ABS_X, val);
>  
>  	e.code = ABS_Y;
> -	val = litest_auto_assign_value(d, &e, 0, x, y);
> +	val = litest_auto_assign_value(d, &e, 0, x, y, 1);
>  	litest_event(d, EV_ABS, ABS_Y, val);
>  }
>  
> @@ -1501,12 +1622,12 @@ send_abs_mt_xy(struct litest_device *d, double x, double y)
>  	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);
> +	val = litest_auto_assign_value(d, &e, 0, x, y, 1);
>  	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);
> +	val = litest_auto_assign_value(d, &e, 0, x, y, 1);
>  	litest_event(d, EV_ABS, ABS_MT_POSITION_Y, val);
>  }
>  
> diff --git a/test/litest.h b/test/litest.h
> index 611cdf7..bb9ba03 100644
> --- a/test/litest.h
> +++ b/test/litest.h
> @@ -57,6 +57,7 @@ enum litest_device_type {
>  	LITEST_WHEEL_ONLY = -21,
>  	LITEST_MOUSE_ROCCAT = -22,
>  	LITEST_LOGITECH_TRACKBALL = -23,
> +	LITEST_ATMEL_HOVER = -24,
>  };
>  
>  enum litest_device_feature {
> @@ -77,6 +78,7 @@ enum litest_device_feature {
>  	LITEST_FAKE_MT = 1 << 12,
>  	LITEST_ABSOLUTE = 1 << 13,
>  	LITEST_PROTOCOL_A = 1 << 14,
> +	LITEST_HOVER = 1 << 15,
>  };
>  
>  struct litest_device {
> @@ -141,7 +143,8 @@ void litest_event(struct litest_device *t,
>  		  int value);
>  int litest_auto_assign_value(struct litest_device *d,
>  			     const struct input_event *ev,
> -			     int slot, double x, double y);
> +			     int slot, double x, double y,
> +			     int touching);
>  void litest_touch_up(struct litest_device *d, unsigned int slot);
>  void litest_touch_move(struct litest_device *d,
>  		       unsigned int slot,
> @@ -161,6 +164,27 @@ void litest_touch_move_two_touches(struct litest_device *d,
>  				   double x1, double y1,
>  				   double dx, double dy,
>  				   int steps, int sleep_ms);
> +void litest_hover_start(struct litest_device *d,
> +			unsigned int slot,
> +			double x,
> +			double y,
> +			int sync);
> +void litest_hover_end(struct litest_device *d, unsigned int slot, int sync);
> +void litest_hover_move(struct litest_device *d,
> +		       unsigned int slot,
> +		       double x,
> +		       double y,
> +		       int sync);
> +void litest_hover_move_to(struct litest_device *d,
> +			  unsigned int slot,
> +			  double x_from, double y_from,
> +			  double x_to, double y_to,
> +			  int steps, int sleep_ms, int sync);
> +void litest_hover_move_two_touches(struct litest_device *d,
> +				   double x0, double y0,
> +				   double x1, double y1,
> +				   double dx, double dy,
> +				   int steps, int sleep_ms);
>  void litest_button_click(struct litest_device *d,
>  			 unsigned int button,
>  			 bool is_press);
> diff --git a/test/touchpad.c b/test/touchpad.c
> index 49f5023..f0be6d9 100644
> --- a/test/touchpad.c
> +++ b/test/touchpad.c
> @@ -3834,6 +3834,165 @@ START_TEST(touchpad_semi_mt_hover_2fg_1fg_down)
>  }
>  END_TEST
>  
> +START_TEST(touchpad_hover_noevent)
> +{
> +	struct litest_device *dev = litest_current_device();
> +	struct libinput *li = dev->libinput;
> +
> +	litest_drain_events(li);
> +
> +	litest_hover_start(dev, 0, 50, 50, 1);
> +	litest_hover_move_to(dev, 0, 50, 50, 70, 70, 10, 10, 1);
> +	litest_hover_end(dev, 0, 1);
> +
> +	litest_assert_empty_queue(li);
> +}
> +END_TEST
> +
> +START_TEST(touchpad_hover_down)
> +{
> +	struct litest_device *dev = litest_current_device();
> +	struct libinput *li = dev->libinput;
> +
> +	litest_drain_events(li);
> +
> +	/* hover the finger */
> +	litest_hover_start(dev, 0, 50, 50, 1);
> +
> +	litest_hover_move_to(dev, 0, 50, 50, 70, 70, 10, 10, 1);
> +
> +	litest_assert_empty_queue(li);
> +
> +	/* touch the finger on the sensor */
> +	litest_touch_move_to(dev, 0, 70, 70, 50, 50, 10, 10);
> +
> +	libinput_dispatch(li);
> +
> +	litest_assert_only_typed_events(li,
> +					LIBINPUT_EVENT_POINTER_MOTION);
> +
> +	/* go back to hover */
> +	litest_hover_move_to(dev, 0, 50, 50, 70, 70, 10, 10, 1);
> +	litest_hover_end(dev, 0, 1);
> +
> +	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;
> +	int i;
> +
> +	litest_drain_events(li);
> +
> +	litest_hover_start(dev, 0, 50, 50, 1);
> +
> +	for (i = 0; i < 3; i++) {
> +
> +		/* hover the finger */
> +		litest_hover_move_to(dev, 0, 50, 50, 70, 70, 10, 10, 1);
> +
> +		litest_assert_empty_queue(li);
> +
> +		/* touch the finger */
> +		litest_touch_move_to(dev, 0, 70, 70, 50, 50, 10, 10);

pls add a touch_down() call before each touch_move_to, it makes it a lot
more obvious that the finger is down now (goes for all tests).

> +
> +		libinput_dispatch(li);
> +
> +		litest_assert_only_typed_events(li,
> +						LIBINPUT_EVENT_POINTER_MOTION);
> +	}
> +
> +	litest_hover_end(dev, 0, 1);
> +
> +	/* 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);
> +
> +	litest_assert_only_typed_events(li,
> +					LIBINPUT_EVENT_POINTER_MOTION);
> +}
> +END_TEST
> +
> +START_TEST(touchpad_hover_down_up)
> +{
> +	struct litest_device *dev = litest_current_device();
> +	struct libinput *li = dev->libinput;
> +
> +	litest_drain_events(li);
> +
> +	/* hover two fingers, and a touch */

ok, here's where I think using the push/pop pairs will do the same job but
be slightly nicer in terms of API.

litest_push_event_frame();

> +	litest_hover_start(dev, 0, 50, 50, 0);
> +	litest_hover_start(dev, 1, 50, 50, 0);
> +	litest_touch_down(dev, 2, 50, 50);

litest_pop_event_frame();

> +
> +	litest_assert_empty_queue(li);
> +
> +	/* hover first finger, end second and third in same frame */

litest_push_event_frame();

> +	litest_hover_move(dev, 0, 70, 70, 0);
> +	litest_hover_end(dev, 1, 0);
> +	litest_touch_up(dev, 2);

litest_push_event_frame();
> +
> +	litest_assert_empty_queue(li);
> +
> +	/* now move the finger */
> +	litest_touch_move_to(dev, 0, 50, 50, 70, 70, 10, 10);
> +
> +	litest_touch_up(dev, 0);
> +
> +	litest_assert_only_typed_events(li,
> +					LIBINPUT_EVENT_POINTER_MOTION);
> +}
> +END_TEST
> +
> +START_TEST(touchpad_hover_2fg_noevent)
> +{
> +	struct litest_device *dev = litest_current_device();
> +	struct libinput *li = dev->libinput;
> +
> +	litest_drain_events(li);
> +
> +	/* hover two fingers */

litest_push_event_frame();

> +	litest_hover_start(dev, 0, 25, 25, 0);
> +	litest_hover_start(dev, 1, 50, 50, 1);
> +
litest_pop_event_frame();

> +	litest_hover_move_two_touches(dev, 25, 25, 50, 50, 50, 50, 10, 0);
> +

litest_push_event_frame();

> +	litest_hover_end(dev, 0, 0);
> +	litest_hover_end(dev, 1, 1);

litest_pop_event_frame();
> +
> +	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;
> +	int i;
> +
> +	litest_drain_events(li);
> +
> +	/* hover two fingers */

litest_push_event_frame();

> +	litest_hover_start(dev, 0, 25, 25, 0);
> +	litest_touch_down(dev, 1, 50, 50);

litest_pop_event_frame();
> +
> +	for (i = 0; i < 10; i++) {
litest_push_event_frame();
> +		litest_hover_move(dev, 0, 25 + 5 * i, 25 + 5 * i, 0);
> +		litest_touch_move(dev, 1, 50 + 5 * i, 50 - 5 * i);

litest_pop_event_frame();

> +	}
> +
litest_push_event_frame();
> +	litest_hover_end(dev, 0, 0);
> +	litest_touch_up(dev, 1);

litest_pop_event_frame();

right, so after adding these I think this should work. you can drop the
extra parameter and just use the push/pop instead.

Cheers,
   Peter

> +
> +	litest_assert_only_typed_events(li,
> +					LIBINPUT_EVENT_POINTER_MOTION);
> +}
> +END_TEST
> +
>  static void
>  assert_btnevent_from_device(struct litest_device *device,
>  			    unsigned int button,
> @@ -4241,6 +4400,13 @@ int main(int argc, char **argv) {
>  	litest_add_for_device("touchpad:semi-mt-hover", touchpad_semi_mt_hover_2fg_noevent, LITEST_SYNAPTICS_HOVER_SEMI_MT);
>  	litest_add_for_device("touchpad:semi-mt-hover", touchpad_semi_mt_hover_2fg_1fg_down, LITEST_SYNAPTICS_HOVER_SEMI_MT);
>  
> +	litest_add("touchpad:hover", touchpad_hover_noevent, LITEST_TOUCHPAD|LITEST_HOVER, LITEST_ANY);
> +	litest_add("touchpad:hover", touchpad_hover_down, LITEST_TOUCHPAD|LITEST_HOVER, LITEST_ANY);
> +	litest_add("touchpad:hover", touchpad_hover_down_up, LITEST_TOUCHPAD|LITEST_HOVER, LITEST_ANY);
> +	litest_add("touchpad:hover", touchpad_hover_down_hover_down, LITEST_TOUCHPAD|LITEST_HOVER, LITEST_ANY);
> +	litest_add("touchpad:hover", touchpad_hover_2fg_noevent, LITEST_TOUCHPAD|LITEST_HOVER, LITEST_ANY);
> +	litest_add("touchpad:hover", touchpad_hover_2fg_1fg_down, LITEST_TOUCHPAD|LITEST_HOVER, LITEST_ANY);
> +
>  	litest_add_for_device("touchpad:trackpoint", touchpad_trackpoint_buttons, LITEST_SYNAPTICS_TRACKPOINT_BUTTONS);
>  	litest_add_for_device("touchpad:trackpoint", touchpad_trackpoint_mb_scroll, LITEST_SYNAPTICS_TRACKPOINT_BUTTONS);
>  	litest_add_for_device("touchpad:trackpoint", touchpad_trackpoint_mb_click, LITEST_SYNAPTICS_TRACKPOINT_BUTTONS);
> -- 
> 1.7.1
> 

> _______________________________________________
> wayland-devel mailing list
> wayland-devel at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/wayland-devel



More information about the wayland-devel mailing list