diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/evdev.c | 68 | ||||
-rw-r--r-- | src/evdev.h | 7 | ||||
-rw-r--r-- | src/libinput-private.h | 10 | ||||
-rw-r--r-- | src/libinput-util.h | 21 | ||||
-rw-r--r-- | src/libinput.c | 41 | ||||
-rw-r--r-- | src/libinput.h | 96 | ||||
-rw-r--r-- | src/libinput.sym | 7 |
7 files changed, 250 insertions, 0 deletions
diff --git a/src/evdev.c b/src/evdev.c index 7abd8953..38ac3aa7 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 2607fd85..8dafc2b4 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 b65ae93a..10522125 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 82ab2b1e..701fe078 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 bcd0dcd0..7a9199dd 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 a93676ec..d972dd82 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 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 ca1baba7..c6a0e4c9 100644 --- a/src/libinput.sym +++ b/src/libinput.sym @@ -252,3 +252,10 @@ LIBINPUT_1.3 { libinput_event_tablet_pad_get_time; libinput_event_tablet_pad_get_time_usec; } LIBINPUT_1.2; + +LIBINPUT_1.4 { + 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_1.3; |