mirror of
https://gitlab.freedesktop.org/libinput/libinput.git
synced 2025-12-29 19:30:09 +01:00
touchpad: rotate the touch part of tablets
Tablets in left-handed mode are rotated, so we need to rotate the touchpad part of them too. This doesn't affect all tablets though, some of them are symmetrical and the left-handed mode merely changes the button order around (some of the earlier Bamboos). So we rely on libwacom to tell us which device must be rotated. The rotation itself is done on the input coordinate itself as we get it. This way any software buttons, palm zones, etc. are automatically handled by rest of the code. Fixes #274 Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
This commit is contained in:
parent
3542855902
commit
6229df184e
3 changed files with 168 additions and 9 deletions
|
|
@ -28,6 +28,10 @@
|
|||
#include <stdbool.h>
|
||||
#include <limits.h>
|
||||
|
||||
#if HAVE_LIBWACOM
|
||||
#include <libwacom/libwacom.h>
|
||||
#endif
|
||||
|
||||
#include "quirks.h"
|
||||
#include "evdev-mt-touchpad.h"
|
||||
|
||||
|
|
@ -464,6 +468,30 @@ tp_get_delta(struct tp_touch *t)
|
|||
return delta;
|
||||
}
|
||||
|
||||
static inline int32_t
|
||||
rotated(struct tp_dispatch *tp, unsigned int code, int value)
|
||||
{
|
||||
const struct input_absinfo *absinfo;
|
||||
|
||||
if (!tp->device->left_handed.enabled ||
|
||||
!tp->left_handed.rotate)
|
||||
return value;
|
||||
|
||||
switch (code) {
|
||||
case ABS_X:
|
||||
case ABS_MT_POSITION_X:
|
||||
absinfo = tp->device->abs.absinfo_x;
|
||||
break;
|
||||
case ABS_Y:
|
||||
case ABS_MT_POSITION_Y:
|
||||
absinfo = tp->device->abs.absinfo_y;
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
return absinfo->maximum - (value - absinfo->minimum);
|
||||
}
|
||||
|
||||
static void
|
||||
tp_process_absolute(struct tp_dispatch *tp,
|
||||
const struct input_event *e,
|
||||
|
|
@ -476,7 +504,7 @@ tp_process_absolute(struct tp_dispatch *tp,
|
|||
evdev_device_check_abs_axis_range(tp->device,
|
||||
e->code,
|
||||
e->value);
|
||||
t->point.x = e->value;
|
||||
t->point.x = rotated(tp, e->code, e->value);
|
||||
t->time = time;
|
||||
t->dirty = true;
|
||||
tp->queued |= TOUCHPAD_EVENT_MOTION;
|
||||
|
|
@ -485,7 +513,7 @@ tp_process_absolute(struct tp_dispatch *tp,
|
|||
evdev_device_check_abs_axis_range(tp->device,
|
||||
e->code,
|
||||
e->value);
|
||||
t->point.y = e->value;
|
||||
t->point.y = rotated(tp, e->code, e->value);
|
||||
t->time = time;
|
||||
t->dirty = true;
|
||||
tp->queued |= TOUCHPAD_EVENT_MOTION;
|
||||
|
|
@ -536,7 +564,7 @@ tp_process_absolute_st(struct tp_dispatch *tp,
|
|||
evdev_device_check_abs_axis_range(tp->device,
|
||||
e->code,
|
||||
e->value);
|
||||
t->point.x = e->value;
|
||||
t->point.x = rotated(tp, e->code, e->value);
|
||||
t->time = time;
|
||||
t->dirty = true;
|
||||
tp->queued |= TOUCHPAD_EVENT_MOTION;
|
||||
|
|
@ -545,7 +573,7 @@ tp_process_absolute_st(struct tp_dispatch *tp,
|
|||
evdev_device_check_abs_axis_range(tp->device,
|
||||
e->code,
|
||||
e->value);
|
||||
t->point.y = e->value;
|
||||
t->point.y = rotated(tp, e->code, e->value);
|
||||
t->time = time;
|
||||
t->dirty = true;
|
||||
tp->queued |= TOUCHPAD_EVENT_MOTION;
|
||||
|
|
@ -3700,11 +3728,80 @@ tp_change_to_left_handed(struct evdev_device *device)
|
|||
device->left_handed.enabled = device->left_handed.want_enabled;
|
||||
}
|
||||
|
||||
static bool
|
||||
tp_init_left_handed_rotation(struct tp_dispatch *tp,
|
||||
struct evdev_device *device)
|
||||
{
|
||||
bool rotate = false;
|
||||
#if HAVE_LIBWACOM
|
||||
WacomDeviceDatabase *db;
|
||||
WacomDevice **devices = NULL,
|
||||
**d;
|
||||
WacomDevice *dev;
|
||||
uint32_t vid = evdev_device_get_id_vendor(device),
|
||||
pid = evdev_device_get_id_product(device);
|
||||
|
||||
db = libwacom_database_new();
|
||||
if (!db) {
|
||||
evdev_log_info(device,
|
||||
"Failed to initialize libwacom context.\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Check if we have a device with the same vid/pid. If not,
|
||||
we need to loop through all devices and check their paired
|
||||
device. */
|
||||
dev = libwacom_new_from_usbid(db, vid, pid, NULL);
|
||||
if (dev) {
|
||||
rotate = libwacom_is_reversible(dev);
|
||||
libwacom_destroy(dev);
|
||||
goto out;
|
||||
}
|
||||
|
||||
devices = libwacom_list_devices_from_database(db, NULL);
|
||||
if (!devices)
|
||||
goto out;
|
||||
d = devices;
|
||||
while(*d) {
|
||||
const WacomMatch *paired;
|
||||
|
||||
paired = libwacom_get_paired_device(*d);
|
||||
if (paired &&
|
||||
libwacom_match_get_vendor_id(paired) == vid &&
|
||||
libwacom_match_get_product_id(paired) == pid) {
|
||||
rotate = libwacom_is_reversible(dev);
|
||||
break;
|
||||
}
|
||||
d++;
|
||||
}
|
||||
|
||||
free(devices);
|
||||
out:
|
||||
if (db)
|
||||
libwacom_database_destroy(db);
|
||||
#endif
|
||||
|
||||
return rotate;
|
||||
}
|
||||
|
||||
static void
|
||||
tp_init_left_handed(struct tp_dispatch *tp,
|
||||
struct evdev_device *device)
|
||||
{
|
||||
bool want_left_handed = true;
|
||||
|
||||
if (device->model_flags & EVDEV_MODEL_APPLE_TOUCHPAD_ONEBUTTON)
|
||||
want_left_handed = false;
|
||||
if (want_left_handed)
|
||||
evdev_init_left_handed(device, tp_change_to_left_handed);
|
||||
|
||||
tp->left_handed.rotate = tp_init_left_handed_rotation(tp, device);
|
||||
}
|
||||
|
||||
struct evdev_dispatch *
|
||||
evdev_mt_touchpad_create(struct evdev_device *device)
|
||||
{
|
||||
struct tp_dispatch *tp;
|
||||
bool want_left_handed = true;
|
||||
|
||||
evdev_tag_touchpad(device, device->udev_device);
|
||||
|
||||
|
|
@ -3723,10 +3820,7 @@ evdev_mt_touchpad_create(struct evdev_device *device)
|
|||
tp->sendevents.config.get_mode = tp_sendevents_get_mode;
|
||||
tp->sendevents.config.get_default_mode = tp_sendevents_get_default_mode;
|
||||
|
||||
if (device->model_flags & EVDEV_MODEL_APPLE_TOUCHPAD_ONEBUTTON)
|
||||
want_left_handed = false;
|
||||
if (want_left_handed)
|
||||
evdev_init_left_handed(device, tp_change_to_left_handed);
|
||||
tp_init_left_handed(tp, device);
|
||||
|
||||
return &tp->base;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -485,6 +485,11 @@ struct tp_dispatch {
|
|||
struct libinput_event_listener listener;
|
||||
struct evdev_device *tablet_mode_switch;
|
||||
} tablet_mode_switch;
|
||||
|
||||
struct {
|
||||
/* true if the axes need rotation when left-handed is on*/
|
||||
bool rotate;
|
||||
} left_handed;
|
||||
};
|
||||
|
||||
static inline struct tp_dispatch*
|
||||
|
|
|
|||
|
|
@ -2096,6 +2096,7 @@ START_TEST(touchpad_palm_clickfinger_size_2fg)
|
|||
litest_assert_empty_queue(li);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(touchpad_left_handed)
|
||||
{
|
||||
struct litest_device *dev = litest_current_device();
|
||||
|
|
@ -2430,6 +2431,64 @@ START_TEST(touchpad_left_handed_clickpad_delayed)
|
|||
}
|
||||
END_TEST
|
||||
|
||||
static inline bool
|
||||
touchpad_has_rotation(struct libevdev *evdev)
|
||||
{
|
||||
return libevdev_get_id_vendor(evdev) == VENDOR_ID_WACOM;
|
||||
}
|
||||
|
||||
START_TEST(touchpad_left_handed_rotation)
|
||||
{
|
||||
struct litest_device *dev = litest_current_device();
|
||||
struct libinput_device *d = dev->libinput_device;
|
||||
struct libinput *li = dev->libinput;
|
||||
enum libinput_config_status status;
|
||||
struct libinput_event *event;
|
||||
struct libinput_event_pointer *p;
|
||||
bool rotate = touchpad_has_rotation(dev->evdev);
|
||||
|
||||
if (!libinput_device_config_left_handed_is_available(d))
|
||||
return;
|
||||
|
||||
status = libinput_device_config_left_handed_set(d, 1);
|
||||
ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS);
|
||||
|
||||
litest_drain_events(li);
|
||||
|
||||
litest_touch_down(dev, 0, 20, 80);
|
||||
litest_touch_move_to(dev, 0, 20, 80, 80, 20, 20);
|
||||
litest_touch_up(dev, 0);
|
||||
libinput_dispatch(li);
|
||||
|
||||
event = libinput_get_event(li);
|
||||
ck_assert_notnull(event);
|
||||
do {
|
||||
double x, y, ux, uy;
|
||||
|
||||
p = litest_is_motion_event(event);
|
||||
|
||||
x = libinput_event_pointer_get_dx(p);
|
||||
y = libinput_event_pointer_get_dy(p);
|
||||
ux = libinput_event_pointer_get_dx_unaccelerated(p);
|
||||
uy = libinput_event_pointer_get_dy_unaccelerated(p);
|
||||
|
||||
if (rotate) {
|
||||
ck_assert_double_lt(x, 0);
|
||||
ck_assert_double_gt(y, 0);
|
||||
ck_assert_double_lt(ux, 0);
|
||||
ck_assert_double_gt(uy, 0);
|
||||
} else {
|
||||
ck_assert_double_gt(x, 0);
|
||||
ck_assert_double_lt(y, 0);
|
||||
ck_assert_double_gt(ux, 0);
|
||||
ck_assert_double_lt(uy, 0);
|
||||
}
|
||||
|
||||
libinput_event_destroy(event);
|
||||
} while ((event = libinput_get_event(li)));
|
||||
}
|
||||
END_TEST
|
||||
|
||||
static void
|
||||
hover_continue(struct litest_device *dev, unsigned int slot,
|
||||
int x, int y)
|
||||
|
|
@ -7010,6 +7069,7 @@ TEST_COLLECTION(touchpad)
|
|||
litest_add("touchpad:left-handed", touchpad_left_handed_tapping_2fg, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH);
|
||||
litest_add("touchpad:left-handed", touchpad_left_handed_delayed, LITEST_TOUCHPAD|LITEST_BUTTON, LITEST_CLICKPAD);
|
||||
litest_add("touchpad:left-handed", touchpad_left_handed_clickpad_delayed, LITEST_CLICKPAD, LITEST_APPLE_CLICKPAD);
|
||||
litest_add("touchpad:left-handed", touchpad_left_handed_rotation, LITEST_TOUCHPAD, LITEST_ANY);
|
||||
|
||||
/* Semi-MT hover tests aren't generic, they only work on this device and
|
||||
* ignore the semi-mt capability (it doesn't matter for the tests) */
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue