On May 3, 2016, at 4:13 PM, Peter Hutterer <peter.hutte...@who-t.net> wrote: > > Trackballs are effectively stationary devices and can be positioned at any > rotation. They are also employed by users with impaired dexterity which > sometimes implies that they are positioned at an non-default angle to make the > buttons easier to reach. > > Add a config option for rotation for trackball devices. Currently only > supported for 90-degree angles, if there is a need we can add more angles > later. > > Signed-off-by: Peter Hutterer <peter.hutte...@who-t.net>
Hi, The first paragraph of the comment for libinput_device_config_rotation_set_angle is a bit confusing, marked inline below. yong > --- > I'm not 100% sure yet that this is the feature we should have. Rotation > itself is important for trackpoints, no doubt, but I'm contemplating whether > to make this a more generic form like a matrix. It makes decisions of > precedence a lot easier, especially if we need to add other options later > that may overlap or conflict with rotation (admittedly, it just shifts that > decision to the caller). but a matrix can also be misused easier and makes > it harder for libinput to detect what the caller wants to do. while this > doesn't have a use-case yet for this feature, sometimes knowing what the > caller wants to do allows us to modify other features. > > src/evdev.c | 68 ++++++++++++ > src/evdev.h | 7 ++ > src/libinput-private.h | 10 ++ > src/libinput-util.h | 21 ++++ > src/libinput.c | 41 ++++++++ > src/libinput.h | 96 +++++++++++++++++ > src/libinput.sym | 4 + > test/Makefile.am | 5 + > test/trackball.c | 273 +++++++++++++++++++++++++++++++++++++++++++++++++ > 9 files changed, 525 insertions(+) > create mode 100644 test/trackball.c > > diff --git a/src/evdev.c b/src/evdev.c > index 7abd895..38ac3aa 100644 > --- a/src/evdev.c > +++ b/src/evdev.c > @@ -370,6 +370,22 @@ evdev_filter_defuzz_touch(struct evdev_device *device, > struct mt_slot *slot) > return false; > } > > +static inline void > +evdev_rotate_relative(struct evdev_device *device) > +{ > + struct evdev_dispatch *dispatch = device->dispatch; > + struct device_coords rel = device->rel; > + > + if (!device->base.config.rotation) > + return; > + > + /* loss of precision for non-90 degrees, but we only support 90 deg > + * right now anyway */ > + matrix_mult_vec(&dispatch->rotation.matrix, &rel.x, &rel.y); > + > + device->rel = rel; > +} > + > static void > evdev_flush_pending_event(struct evdev_device *device, uint64_t time) > { > @@ -394,6 +410,8 @@ evdev_flush_pending_event(struct evdev_device *device, > uint64_t time) > if (!(device->seat_caps & EVDEV_DEVICE_POINTER)) > break; > > + evdev_rotate_relative(device); > + > normalize_delta(device, &device->rel, &unaccel); > raw.x = device->rel.x; > raw.y = device->rel.y; > @@ -1326,6 +1344,55 @@ evdev_init_natural_scroll(struct evdev_device *device) > device->base.config.natural_scroll = &device->scroll.config_natural; > } > > +static int > +evdev_rotation_config_is_available(struct libinput_device *device) > +{ > + /* This function only gets called when we support rotation */ > + return 1; > +} > + > +static enum libinput_config_status > +evdev_rotation_config_set_angle(struct libinput_device *device, > + unsigned int degrees_cw) > +{ > + struct evdev_dispatch *dispatch = ((struct > evdev_device*)device)->dispatch; > + > + dispatch->rotation.angle = degrees_cw; > + matrix_init_rotate(&dispatch->rotation.matrix, degrees_cw); > + > + return LIBINPUT_CONFIG_STATUS_SUCCESS; > +} > + > +static unsigned int > +evdev_rotation_config_get_angle(struct libinput_device *device) > +{ > + struct evdev_dispatch *dispatch = ((struct > evdev_device*)device)->dispatch; > + > + return dispatch->rotation.angle; > +} > + > +static unsigned int > +evdev_rotation_config_get_default_angle(struct libinput_device *device) > +{ > + return 0; > +} > + > +static void > +evdev_init_rotation(struct evdev_device *device, > + struct evdev_dispatch *dispatch) > +{ > + if ((device->model_flags & EVDEV_MODEL_TRACKBALL) == 0) > + return; > + > + dispatch->rotation.config.is_available = > evdev_rotation_config_is_available; > + dispatch->rotation.config.set_angle = evdev_rotation_config_set_angle; > + dispatch->rotation.config.get_angle = evdev_rotation_config_get_angle; > + dispatch->rotation.config.get_default_angle = > evdev_rotation_config_get_default_angle; > + dispatch->rotation.is_enabled = false; > + matrix_init_identity(&dispatch->rotation.matrix); > + device->base.config.rotation = &dispatch->rotation.config; > +} > + > static struct evdev_dispatch * > fallback_dispatch_create(struct libinput_device *device) > { > @@ -1356,6 +1423,7 @@ fallback_dispatch_create(struct libinput_device *device) > > evdev_init_calibration(evdev_device, dispatch); > evdev_init_sendevents(evdev_device, dispatch); > + evdev_init_rotation(evdev_device, dispatch); > > /* BTN_MIDDLE is set on mice even when it's not present. So > * we can only use the absence of BTN_MIDDLE to mean something, i.e. > diff --git a/src/evdev.h b/src/evdev.h > index 2607fd8..8dafc2b 100644 > --- a/src/evdev.h > +++ b/src/evdev.h > @@ -290,6 +290,13 @@ struct evdev_dispatch { > struct libinput_device_config_calibration calibration; > > struct { > + bool is_enabled; > + int angle; > + struct matrix matrix; > + struct libinput_device_config_rotation config; > + } rotation; > + > + struct { > struct libinput_device_config_send_events config; > enum libinput_config_send_events_mode current_mode; > } sendevents; > diff --git a/src/libinput-private.h b/src/libinput-private.h > index b65ae93..1052212 100644 > --- a/src/libinput-private.h > +++ b/src/libinput-private.h > @@ -258,6 +258,15 @@ struct libinput_device_config_dwt { > struct libinput_device *device); > }; > > +struct libinput_device_config_rotation { > + int (*is_available)(struct libinput_device *device); > + enum libinput_config_status (*set_angle)( > + struct libinput_device *device, > + unsigned int degrees_cw); > + unsigned int (*get_angle)(struct libinput_device *device); > + unsigned int (*get_default_angle)(struct libinput_device *device); > +}; > + > struct libinput_device_config { > struct libinput_device_config_tap *tap; > struct libinput_device_config_calibration *calibration; > @@ -269,6 +278,7 @@ struct libinput_device_config { > struct libinput_device_config_click_method *click_method; > struct libinput_device_config_middle_emulation *middle_emulation; > struct libinput_device_config_dwt *dwt; > + struct libinput_device_config_rotation *rotation; > }; > > struct libinput_device_group { > diff --git a/src/libinput-util.h b/src/libinput-util.h > index 82ab2b1..701fe07 100644 > --- a/src/libinput-util.h > +++ b/src/libinput-util.h > @@ -186,6 +186,12 @@ long_any_bit_set(unsigned long *array, size_t size) > return 0; > } > > +static inline double > +deg2rad(int degree) > +{ > + return M_PI * degree / 180.0; > +} > + > struct matrix { > float val[3][3]; /* [row][col] */ > }; > @@ -227,6 +233,21 @@ matrix_init_translate(struct matrix *m, float x, float y) > m->val[1][2] = y; > } > > +static inline void > +matrix_init_rotate(struct matrix *m, int degrees) > +{ > + double s, c; > + > + s = sin(deg2rad(degrees)); > + c = cos(deg2rad(degrees)); > + > + matrix_init_identity(m); > + m->val[0][0] = c; > + m->val[0][1] = -s; > + m->val[1][0] = s; > + m->val[1][1] = c; > +} > + > static inline int > matrix_is_identity(const struct matrix *m) > { > diff --git a/src/libinput.c b/src/libinput.c > index bcd0dcd..7a9199d 100644 > --- a/src/libinput.c > +++ b/src/libinput.c > @@ -3688,3 +3688,44 @@ libinput_device_config_dwt_get_default_enabled(struct > libinput_device *device) > > return device->config.dwt->get_default_enabled(device); > } > + > +LIBINPUT_EXPORT int > +libinput_device_config_rotation_is_available(struct libinput_device *device) > +{ > + if (!device->config.rotation) > + return 0; > + > + return device->config.rotation->is_available(device); > +} > + > +LIBINPUT_EXPORT enum libinput_config_status > +libinput_device_config_rotation_set_angle(struct libinput_device *device, > + unsigned int degrees_cw) > +{ > + if (!libinput_device_config_rotation_is_available(device)) > + return degrees_cw ? LIBINPUT_CONFIG_STATUS_UNSUPPORTED : > + LIBINPUT_CONFIG_STATUS_SUCCESS; > + > + if (degrees_cw >= 360 || degrees_cw % 90) > + return LIBINPUT_CONFIG_STATUS_INVALID; > + > + return device->config.rotation->set_angle(device, degrees_cw); > +} > + > +LIBINPUT_EXPORT unsigned int > +libinput_device_config_rotation_get_angle(struct libinput_device *device) > +{ > + if (!libinput_device_config_rotation_is_available(device)) > + return 0; > + > + return device->config.rotation->get_angle(device); > +} > + > +LIBINPUT_EXPORT unsigned int > +libinput_device_config_rotation_get_default_angle(struct libinput_device > *device) > +{ > + if (!libinput_device_config_rotation_is_available(device)) > + return 0; > + > + return device->config.rotation->get_default_angle(device); > +} > diff --git a/src/libinput.h b/src/libinput.h > index a93676e..b880810 100644 > --- a/src/libinput.h > +++ b/src/libinput.h > @@ -809,6 +809,9 @@ libinput_event_pointer_get_dy(struct > libinput_event_pointer *event); > * X resolution of the touchpad. See @ref motion_normalization for more > * details. > * > + * Any rotation applied to the device also applies to unaccelerated motion > + * (see libinput_device_config_rotation_set_angle()). > + * > * @note It is an application bug to call this function for events other than > * @ref LIBINPUT_EVENT_POINTER_MOTION. > * > @@ -831,6 +834,9 @@ libinput_event_pointer_get_dx_unaccelerated( > * X resolution of the touchpad. See @ref motion_normalization for more > * details. > * > + * Any rotation applied to the device also applies to unaccelerated motion > + * (see libinput_device_config_rotation_set_angle()). > + * > * @note It is an application bug to call this function for events other than > * @ref LIBINPUT_EVENT_POINTER_MOTION. > * > @@ -1356,6 +1362,9 @@ libinput_event_gesture_get_dy(struct > libinput_event_gesture *event); > * details. Note that unaccelerated events are not equivalent to 'raw' events > * as read from the device. > * > + * Any rotation applied to the device also applies to gesture motion > + * (see libinput_device_config_rotation_set_angle()). > + * > * @return the unaccelerated relative x movement since the last event > */ > double > @@ -1375,6 +1384,9 @@ libinput_event_gesture_get_dx_unaccelerated( > * details. Note that unaccelerated events are not equivalent to 'raw' events > * as read from the device. > * > + * Any rotation applied to the device also applies to gesture motion > + * (see libinput_device_config_rotation_set_angle()). > + * > * @return the unaccelerated relative y movement since the last event > */ > double > @@ -3337,6 +3349,7 @@ libinput_device_group_get_user_data(struct > libinput_device_group *group); > * - libinput_device_config_scroll_set_natural_scroll_enabled() > * - libinput_device_config_left_handed_set() > * - libinput_device_config_middle_emulation_set_enabled() > + * - libinput_device_config_rotation_set_angle() > * - All devices: > * - libinput_device_config_send_events_set_mode() > */ > @@ -4649,6 +4662,89 @@ libinput_device_config_dwt_get_enabled(struct > libinput_device *device); > enum libinput_config_dwt_state > libinput_device_config_dwt_get_default_enabled(struct libinput_device > *device); > > +/** > + * @ingroup config > + * > + * Check whether a device can have a custom rotation applied. > + * > + * @param device The device to configure > + * @return Non-zero if a device can be rotated, zero otherwise. > + * > + * @see libinput_device_config_rotation_set_angle > + * @see libinput_device_config_rotation_get_angle > + * @see libinput_device_config_rotation_get_default_angle > + */ > +int > +libinput_device_config_rotation_is_available(struct libinput_device *device); > + > +/** > + * @ingroup config > + * > + * Set the rotation of a device in degrees clockwise off the logical neutral > + * position. Any subsequent motion events are adjusted according to the > + * given provided. The last sentence here is confusing. Did you mean according to the angle? > + * > + * The angle has to be in the range of [0, 360[ degrees, otherwise this > + * function returns LIBINPUT_CONFIG_STATUS_INVALID. If the angle is a > + * multiple of 360 or negative, the caller must ensure the correct ranging > + * before calling this function. > + * > + * libinput guarantees that this function accepts multiples of 90 degrees. > + * If a value is within the [0, 360[ range but not a multiple of 90 degrees, > + * this function may return LIBINPUT_CONFIG_STATUS_INVALID if the underlying > + * device or implementation does not support finer-grained rotation angles. > + * > + * The rotation angle is applied to all motion events emitted by the device. > + * Thus, rotating the device also changes the angle required or presented by > + * scrolling, gestures, etc. > + * > + * @param device The device to configure > + * @param degrees_cw The angle in degrees clockwise > + * @return A config status code. Setting a rotation of 0 degrees on a > + * device that does not support rotation always succeeds. > + * > + * @see libinput_device_config_rotation_is_available > + * @see libinput_device_config_rotation_get_angle > + * @see libinput_device_config_rotation_get_default_angle > + */ > +enum libinput_config_status > +libinput_device_config_rotation_set_angle(struct libinput_device *device, > + unsigned int degrees_cw); > + > +/** > + * @ingroup config > + * > + * Get the current rotation of a device in degrees clockwise off the logical > + * neutral position. If this device does not support rotation, the return > + * value is always 0. > + * > + * @param device The device to configure > + * @return The angle in degrees clockwise > + * > + * @see libinput_device_config_rotation_is_available > + * @see libinput_device_config_rotation_set_angle > + * @see libinput_device_config_rotation_get_default_angle > + */ > +unsigned int > +libinput_device_config_rotation_get_angle(struct libinput_device *device); > + > +/** > + * @ingroup config > + * > + * Get the default rotation of a device in degrees clockwise off the logical > + * neutral position. If this device does not support rotation, the return > + * value is always 0. > + * > + * @param device The device to configure > + * @return The default angle in degrees clockwise > + * > + * @see libinput_device_config_rotation_is_available > + * @see libinput_device_config_rotation_set_angle > + * @see libinput_device_config_rotation_get_angle > + */ > +unsigned int > +libinput_device_config_rotation_get_default_angle(struct libinput_device > *device); > + > #ifdef __cplusplus > } > #endif > diff --git a/src/libinput.sym b/src/libinput.sym > index ca1baba..a373c8f 100644 > --- a/src/libinput.sym > +++ b/src/libinput.sym > @@ -236,6 +236,10 @@ LIBINPUT_1.2 { > } LIBINPUT_1.1; > > LIBINPUT_1.3 { > + libinput_device_config_rotation_get_angle; > + libinput_device_config_rotation_get_default_angle; > + libinput_device_config_rotation_is_available; > + libinput_device_config_rotation_set_angle; > libinput_device_tablet_pad_get_num_buttons; > libinput_device_tablet_pad_get_num_rings; > libinput_device_tablet_pad_get_num_strips; > diff --git a/test/Makefile.am b/test/Makefile.am > index 9b67818..f0ac855 100644 > --- a/test/Makefile.am > +++ b/test/Makefile.am > @@ -80,6 +80,7 @@ run_tests = \ > test-gestures \ > test-pointer \ > test-touch \ > + test-trackball \ > test-trackpoint \ > test-udev \ > test-path \ > @@ -144,6 +145,10 @@ test_trackpoint_SOURCES = trackpoint.c > test_trackpoint_LDADD = $(TEST_LIBS) > test_trackpoint_LDFLAGS = -no-install > > +test_trackball_SOURCES = trackball.c > +test_trackball_LDADD = $(TEST_LIBS) > +test_trackball_LDFLAGS = -no-install > + > test_misc_SOURCES = misc.c > test_misc_CFLAGS= $(AM_CFLAGS) > -DLIBINPUT_LT_VERSION="\"$(LIBINPUT_LT_VERSION)\"" > test_misc_LDADD = $(TEST_LIBS) > diff --git a/test/trackball.c b/test/trackball.c > new file mode 100644 > index 0000000..d3238cf > --- /dev/null > +++ b/test/trackball.c > @@ -0,0 +1,273 @@ > +/* > + * Copyright © 2016 Red Hat, Inc. > + * > + * Permission is hereby granted, free of charge, to any person obtaining a > + * copy of this software and associated documentation files (the "Software"), > + * to deal in the Software without restriction, including without limitation > + * the rights to use, copy, modify, merge, publish, distribute, sublicense, > + * and/or sell copies of the Software, and to permit persons to whom the > + * Software is furnished to do so, subject to the following conditions: > + * > + * The above copyright notice and this permission notice (including the next > + * paragraph) shall be included in all copies or substantial portions of the > + * Software. > + * > + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR > + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, > + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL > + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER > + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING > + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER > + * DEALINGS IN THE SOFTWARE. > + */ > + > +#include <config.h> > + > +#include <check.h> > +#include <errno.h> > +#include <fcntl.h> > +#include <libinput.h> > +#include <unistd.h> > + > +#include "libinput-util.h" > +#include "litest.h" > + > +START_TEST(trackball_rotation_config_defaults) > +{ > + struct litest_device *dev = litest_current_device(); > + struct libinput_device *device = dev->libinput_device; > + int angle; > + > + ck_assert(libinput_device_config_rotation_is_available(device)); > + > + angle = libinput_device_config_rotation_get_angle(device); > + ck_assert_int_eq(angle, 0); > + angle = libinput_device_config_rotation_get_default_angle(device); > + ck_assert_int_eq(angle, 0); > +} > +END_TEST > + > +START_TEST(trackball_rotation_config_invalid_range) > +{ > + struct litest_device *dev = litest_current_device(); > + struct libinput_device *device = dev->libinput_device; > + enum libinput_config_status status; > + > + status = libinput_device_config_rotation_set_angle(device, 360); > + ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_INVALID); > + status = libinput_device_config_rotation_set_angle(device, 361); > + ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_INVALID); > + status = libinput_device_config_rotation_set_angle(device, -1); > + ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_INVALID); > +} > +END_TEST > + > +START_TEST(trackball_rotation_config_no_rotation) > +{ > + struct litest_device *dev = litest_current_device(); > + struct libinput_device *device = dev->libinput_device; > + enum libinput_config_status status; > + int angle; > + > + ck_assert(!libinput_device_config_rotation_is_available(device)); > + > + angle = libinput_device_config_rotation_get_angle(device); > + ck_assert_int_eq(angle, 0); > + angle = libinput_device_config_rotation_get_default_angle(device); > + ck_assert_int_eq(angle, 0); > + > + /* 0 always succeeds */ > + status = libinput_device_config_rotation_set_angle(device, 0); > + ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS); > + > + for (angle = 1; angle < 360; angle++) { > + if (angle % 90 == 0) > + continue; > + status = libinput_device_config_rotation_set_angle(device, > + angle); > + ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_UNSUPPORTED); > + } > +} > +END_TEST > + > +START_TEST(trackball_rotation_config_right_angle) > +{ > + struct litest_device *dev = litest_current_device(); > + struct libinput_device *device = dev->libinput_device; > + enum libinput_config_status status; > + int angle; > + > + ck_assert(libinput_device_config_rotation_is_available(device)); > + > + for (angle = 0; angle < 360; angle += 90) { > + status = libinput_device_config_rotation_set_angle(device, > + angle); > + ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS); > + } > +} > +END_TEST > + > +START_TEST(trackball_rotation_config_odd_angle) > +{ > + struct litest_device *dev = litest_current_device(); > + struct libinput_device *device = dev->libinput_device; > + enum libinput_config_status status; > + int angle; > + > + ck_assert(libinput_device_config_rotation_is_available(device)); > + > + for (angle = 0; angle < 360; angle++) { > + if (angle % 90 == 0) > + continue; > + status = libinput_device_config_rotation_set_angle(device, > + angle); > + ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_INVALID); > + } > +} > +END_TEST > + > +START_TEST(trackball_rotation_x) > +{ > + struct litest_device *dev = litest_current_device(); > + struct libinput *li = dev->libinput; > + struct libinput_device *device = dev->libinput_device; > + struct libinput_event *event; > + struct libinput_event_pointer *ptrev; > + int angle; > + double dx, dy; > + > + litest_drain_events(li); > + > + for (angle = 0; angle < 360; angle++) { > + libinput_device_config_rotation_set_angle(device, angle); > + > + litest_event(dev, EV_REL, REL_X, 1); > + litest_event(dev, EV_SYN, SYN_REPORT, 0); > + libinput_dispatch(li); > + > + event = libinput_get_event(li); > + ptrev = litest_is_motion_event(event); > + > + /* Test unaccelerated because pointer accel may mangle the > + other coords */ > + dx = libinput_event_pointer_get_dx_unaccelerated(ptrev); > + dy = libinput_event_pointer_get_dy_unaccelerated(ptrev); > + > + switch (angle) { > + case 0: > + ck_assert_double_eq(dx, 1.0); > + ck_assert_double_eq(dy, 0.0); > + break; > + case 90: > + ck_assert_double_eq(dx, 0.0); > + ck_assert_double_eq(dy, 1.0); > + break; > + case 180: > + ck_assert_double_eq(dx, -1.0); > + ck_assert_double_eq(dy, 0.0); > + break; > + case 270: > + ck_assert_double_eq(dx, 0.0); > + ck_assert_double_eq(dy, -1.0); > + break; > + } > + libinput_event_destroy(event); > + } > +} > +END_TEST > + > +START_TEST(trackball_rotation_y) > +{ > + struct litest_device *dev = litest_current_device(); > + struct libinput *li = dev->libinput; > + struct libinput_device *device = dev->libinput_device; > + struct libinput_event *event; > + struct libinput_event_pointer *ptrev; > + int angle; > + double dx, dy; > + > + litest_drain_events(li); > + > + for (angle = 0; angle < 360; angle++) { > + libinput_device_config_rotation_set_angle(device, angle); > + > + litest_event(dev, EV_REL, REL_Y, 1); > + litest_event(dev, EV_SYN, SYN_REPORT, 0); > + libinput_dispatch(li); > + > + event = libinput_get_event(li); > + ptrev = litest_is_motion_event(event); > + > + /* Test unaccelerated because pointer accel may mangle the > + other coords */ > + dx = libinput_event_pointer_get_dx_unaccelerated(ptrev); > + dy = libinput_event_pointer_get_dy_unaccelerated(ptrev); > + > + switch (angle) { > + case 0: > + ck_assert_double_eq(dx, 0.0); > + ck_assert_double_eq(dy, 1.0); > + break; > + case 90: > + ck_assert_double_eq(dx, -1.0); > + ck_assert_double_eq(dy, 0.0); > + break; > + case 180: > + ck_assert_double_eq(dx, 0.0); > + ck_assert_double_eq(dy, -1.0); > + break; > + case 270: > + ck_assert_double_eq(dx, 1.0); > + ck_assert_double_eq(dy, 0.0); > + break; > + } > + libinput_event_destroy(event); > + } > +} > +END_TEST > + > +START_TEST(trackball_rotation_accel) > +{ > + struct litest_device *dev = litest_current_device(); > + struct libinput *li = dev->libinput; > + struct libinput_device *device = dev->libinput_device; > + struct libinput_event *event; > + struct libinput_event_pointer *ptrev; > + double dx, dy; > + > + litest_drain_events(li); > + > + /* Pointer accel mangles the coordinates, so we only test one angle > + * and rely on the unaccelerated tests above to warn us when > + * something's off */ > + libinput_device_config_rotation_set_angle(device, 90); > + > + litest_event(dev, EV_REL, REL_Y, 1); > + litest_event(dev, EV_REL, REL_X, 1); > + litest_event(dev, EV_SYN, SYN_REPORT, 0); > + libinput_dispatch(li); > + > + event = libinput_get_event(li); > + ptrev = litest_is_motion_event(event); > + > + dx = libinput_event_pointer_get_dx(ptrev); > + dy = libinput_event_pointer_get_dy(ptrev); > + > + ck_assert_double_lt(dx, 0.0); > + ck_assert_double_gt(dy, 0.0); > + libinput_event_destroy(event); > +} > +END_TEST > + > +void > +litest_setup_tests(void) > +{ > + litest_add("trackball:rotation", trackball_rotation_config_defaults, > LITEST_TRACKBALL, LITEST_ANY); > + litest_add("trackball:rotation", > trackball_rotation_config_invalid_range, LITEST_TRACKBALL, LITEST_ANY); > + litest_add("trackball:rotation", trackball_rotation_config_no_rotation, > LITEST_ANY, LITEST_TRACKBALL); > + litest_add("trackball:rotation", trackball_rotation_config_right_angle, > LITEST_TRACKBALL, LITEST_ANY); > + litest_add("trackball:rotation", trackball_rotation_config_odd_angle, > LITEST_TRACKBALL, LITEST_ANY); > + litest_add("trackball:rotation", trackball_rotation_x, > LITEST_TRACKBALL, LITEST_ANY); > + litest_add("trackball:rotation", trackball_rotation_y, > LITEST_TRACKBALL, LITEST_ANY); > + litest_add("trackball:rotation", trackball_rotation_accel, > LITEST_TRACKBALL, LITEST_ANY); > +} > -- > 2.7.4 > > _______________________________________________ > wayland-devel mailing list > wayland-devel@lists.freedesktop.org > https://lists.freedesktop.org/mailman/listinfo/wayland-devel _______________________________________________ wayland-devel mailing list wayland-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/wayland-devel