mirror of
https://gitlab.freedesktop.org/libinput/libinput.git
synced 2026-01-06 15:20:27 +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>
(cherry picked from commit 6229df184e)
This commit is contained in:
parent
9c781d07c3
commit
a7736c03f0
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