1/*
2 * Copyright © 2016 Red Hat, Inc.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 * DEALINGS IN THE SOFTWARE.
22 */
23
24#include <config.h>
25
26#include <check.h>
27#include <errno.h>
28#include <fcntl.h>
29#include <libinput.h>
30#include <unistd.h>
31
32#include "libinput-util.h"
33#include "litest.h"
34
35START_TEST(trackball_rotation_config_defaults)
36{
37	struct litest_device *dev = litest_current_device();
38	struct libinput_device *device = dev->libinput_device;
39	int angle;
40
41	ck_assert(libinput_device_config_rotation_is_available(device));
42
43	angle = libinput_device_config_rotation_get_angle(device);
44	ck_assert_int_eq(angle, 0);
45	angle = libinput_device_config_rotation_get_default_angle(device);
46	ck_assert_int_eq(angle, 0);
47}
48END_TEST
49
50START_TEST(trackball_rotation_config_invalid_range)
51{
52	struct litest_device *dev = litest_current_device();
53	struct libinput_device *device = dev->libinput_device;
54	enum libinput_config_status status;
55
56	status = libinput_device_config_rotation_set_angle(device, 360);
57	ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_INVALID);
58	status = libinput_device_config_rotation_set_angle(device, 361);
59	ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_INVALID);
60	status = libinput_device_config_rotation_set_angle(device, -1);
61	ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_INVALID);
62}
63END_TEST
64
65START_TEST(trackball_rotation_config_no_rotation)
66{
67	struct litest_device *dev = litest_current_device();
68	struct libinput_device *device = dev->libinput_device;
69	enum libinput_config_status status;
70	int angle;
71
72	ck_assert(!libinput_device_config_rotation_is_available(device));
73
74	angle = libinput_device_config_rotation_get_angle(device);
75	ck_assert_int_eq(angle, 0);
76	angle = libinput_device_config_rotation_get_default_angle(device);
77	ck_assert_int_eq(angle, 0);
78
79	/* 0 always succeeds */
80	status = libinput_device_config_rotation_set_angle(device, 0);
81	ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS);
82
83	for (angle = 1; angle < 360; angle++) {
84		status = libinput_device_config_rotation_set_angle(device,
85								   angle);
86		ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_UNSUPPORTED);
87	}
88}
89END_TEST
90
91START_TEST(trackball_rotation_config_right_angle)
92{
93	struct litest_device *dev = litest_current_device();
94	struct libinput_device *device = dev->libinput_device;
95	enum libinput_config_status status;
96	int angle;
97
98	ck_assert(libinput_device_config_rotation_is_available(device));
99
100	for (angle = 0; angle < 360; angle += 90) {
101		status = libinput_device_config_rotation_set_angle(device,
102								   angle);
103		ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS);
104	}
105}
106END_TEST
107
108START_TEST(trackball_rotation_config_odd_angle)
109{
110	struct litest_device *dev = litest_current_device();
111	struct libinput_device *device = dev->libinput_device;
112	enum libinput_config_status status;
113	int angle;
114
115	ck_assert(libinput_device_config_rotation_is_available(device));
116
117	for (angle = 0; angle < 360; angle++) {
118		status = libinput_device_config_rotation_set_angle(device,
119								   angle);
120		ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS);
121	}
122}
123END_TEST
124
125START_TEST(trackball_rotation_x)
126{
127	struct litest_device *dev = litest_current_device();
128	struct libinput *li = dev->libinput;
129	struct libinput_device *device = dev->libinput_device;
130	struct libinput_event *event;
131	struct libinput_event_pointer *ptrev;
132	int angle;
133	double dx, dy;
134
135	litest_drain_events(li);
136
137	for (angle = 0; angle < 360; angle++) {
138		libinput_device_config_rotation_set_angle(device, angle);
139
140		litest_event(dev, EV_REL, REL_X, 1);
141		litest_event(dev, EV_SYN, SYN_REPORT, 0);
142		libinput_dispatch(li);
143
144		event = libinput_get_event(li);
145		ptrev = litest_is_motion_event(event);
146
147		/* Test unaccelerated because pointer accel may mangle the
148		   other coords */
149		dx = libinput_event_pointer_get_dx_unaccelerated(ptrev);
150		dy = libinput_event_pointer_get_dy_unaccelerated(ptrev);
151
152		switch (angle) {
153		case 0:
154			ck_assert_double_eq(dx, 1.0);
155			ck_assert_double_eq(dy, 0.0);
156			break;
157		case 90:
158			ck_assert_double_eq(dx, 0.0);
159			ck_assert_double_eq(dy, 1.0);
160			break;
161		case 180:
162			ck_assert_double_eq(dx, -1.0);
163			ck_assert_double_eq(dy, 0.0);
164			break;
165		case 270:
166			ck_assert_double_eq(dx, 0.0);
167			ck_assert_double_eq(dy, -1.0);
168			break;
169		}
170		libinput_event_destroy(event);
171	}
172}
173END_TEST
174
175START_TEST(trackball_rotation_y)
176{
177	struct litest_device *dev = litest_current_device();
178	struct libinput *li = dev->libinput;
179	struct libinput_device *device = dev->libinput_device;
180	struct libinput_event *event;
181	struct libinput_event_pointer *ptrev;
182	int angle;
183	double dx, dy;
184
185	litest_drain_events(li);
186
187	for (angle = 0; angle < 360; angle++) {
188		libinput_device_config_rotation_set_angle(device, angle);
189
190		litest_event(dev, EV_REL, REL_Y, 1);
191		litest_event(dev, EV_SYN, SYN_REPORT, 0);
192		libinput_dispatch(li);
193
194		event = libinput_get_event(li);
195		ptrev = litest_is_motion_event(event);
196
197		/* Test unaccelerated because pointer accel may mangle the
198		   other coords */
199		dx = libinput_event_pointer_get_dx_unaccelerated(ptrev);
200		dy = libinput_event_pointer_get_dy_unaccelerated(ptrev);
201
202		switch (angle) {
203		case 0:
204			ck_assert_double_eq(dx, 0.0);
205			ck_assert_double_eq(dy, 1.0);
206			break;
207		case 90:
208			ck_assert_double_eq(dx, -1.0);
209			ck_assert_double_eq(dy, 0.0);
210			break;
211		case 180:
212			ck_assert_double_eq(dx, 0.0);
213			ck_assert_double_eq(dy, -1.0);
214			break;
215		case 270:
216			ck_assert_double_eq(dx, 1.0);
217			ck_assert_double_eq(dy, 0.0);
218			break;
219		}
220		libinput_event_destroy(event);
221	}
222}
223END_TEST
224
225START_TEST(trackball_rotation_accel)
226{
227	struct litest_device *dev = litest_current_device();
228	struct libinput *li = dev->libinput;
229	struct libinput_device *device = dev->libinput_device;
230	struct libinput_event *event;
231	struct libinput_event_pointer *ptrev;
232	double dx, dy;
233
234	litest_drain_events(li);
235
236	/* Pointer accel mangles the coordinates, so we only test one angle
237	 * and rely on the unaccelerated tests above to warn us when
238	 * something's off */
239	libinput_device_config_rotation_set_angle(device, 90);
240
241	litest_event(dev, EV_REL, REL_Y, 1);
242	litest_event(dev, EV_REL, REL_X, 1);
243	litest_event(dev, EV_SYN, SYN_REPORT, 0);
244	libinput_dispatch(li);
245
246	event = libinput_get_event(li);
247	ptrev = litest_is_motion_event(event);
248
249	dx = libinput_event_pointer_get_dx(ptrev);
250	dy = libinput_event_pointer_get_dy(ptrev);
251
252	ck_assert_double_lt(dx, 0.0);
253	ck_assert_double_gt(dy, 0.0);
254	libinput_event_destroy(event);
255}
256END_TEST
257
258TEST_COLLECTION(trackball)
259{
260	litest_add(trackball_rotation_config_defaults, LITEST_TRACKBALL, LITEST_ANY);
261	litest_add(trackball_rotation_config_invalid_range, LITEST_TRACKBALL, LITEST_ANY);
262	litest_add(trackball_rotation_config_no_rotation, LITEST_POINTINGSTICK, LITEST_ANY);
263	litest_add(trackball_rotation_config_right_angle, LITEST_TRACKBALL, LITEST_ANY);
264	litest_add(trackball_rotation_config_odd_angle, LITEST_TRACKBALL, LITEST_ANY);
265	litest_add(trackball_rotation_x, LITEST_TRACKBALL, LITEST_ANY);
266	litest_add(trackball_rotation_y, LITEST_TRACKBALL, LITEST_ANY);
267	litest_add(trackball_rotation_accel, LITEST_TRACKBALL, LITEST_ANY);
268}
269