summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/evdev.c68
-rw-r--r--src/evdev.h7
-rw-r--r--src/libinput-private.h10
-rw-r--r--src/libinput-util.h21
-rw-r--r--src/libinput.c41
-rw-r--r--src/libinput.h96
-rw-r--r--src/libinput.sym7
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;