tablet: lock the tablet rotation to the touchpad rotation

Follow-up to 6229df184e
We must not rely on the caller to toggle the left-handed bits correctly since
they may not know which devices belong together (despite device groups). Let's
do the right thing here, if the touchpad is set to left-handed, rotate the
tablet accordingly.

Note that the left-handed setting of the touchpad is left as-is
(right-handed). Until we have notifications about configuration changes, this
is the best we can do.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
This commit is contained in:
Peter Hutterer 2019-05-03 15:56:54 +10:00
parent 829673901c
commit 7f4eb8ada1
3 changed files with 114 additions and 7 deletions

View file

@ -33,6 +33,11 @@
#include <libwacom/libwacom.h>
#endif
enum notify {
DONT_NOTIFY,
DO_NOTIFY,
};
/* The tablet sends events every ~2ms , 50ms should be plenty enough to
detect out-of-range.
This value is higher during test suite runs */
@ -256,17 +261,57 @@ tablet_process_absolute(struct tablet_dispatch *tablet,
}
static void
tablet_change_to_left_handed(struct evdev_device *device)
tablet_apply_rotation(struct evdev_device *device)
{
struct tablet_dispatch *tablet = tablet_dispatch(device->dispatch);
if (device->left_handed.enabled == device->left_handed.want_enabled)
if (tablet->rotation.rotate == tablet->rotation.want_rotate)
return;
if (!tablet_has_status(tablet, TABLET_TOOL_OUT_OF_PROXIMITY))
return;
tablet->rotation.rotate = tablet->rotation.want_rotate;
evdev_log_debug(device,
"tablet-rotation: rotation is %s\n",
tablet->rotation.rotate ? "on" : "off");
}
static void
tablet_change_rotation(struct evdev_device *device, enum notify notify)
{
struct tablet_dispatch *tablet = tablet_dispatch(device->dispatch);
struct evdev_device *touch_device = tablet->touch_device;
struct evdev_dispatch *dispatch;
bool tablet_is_left, touchpad_is_left;
tablet_is_left = tablet->device->left_handed.enabled;
touchpad_is_left = tablet->rotation.touch_device_left_handed_state;
tablet->rotation.want_rotate = tablet_is_left || touchpad_is_left;
tablet_apply_rotation(device);
if (notify == DO_NOTIFY && touch_device) {
bool enable = device->left_handed.want_enabled;
dispatch = touch_device->dispatch;
if (dispatch->interface->left_handed_toggle)
dispatch->interface->left_handed_toggle(dispatch,
touch_device,
enable);
}
}
static void
tablet_change_to_left_handed(struct evdev_device *device)
{
if (device->left_handed.enabled == device->left_handed.want_enabled)
return;
device->left_handed.enabled = device->left_handed.want_enabled;
tablet_change_rotation(device, DO_NOTIFY);
}
static void
@ -405,7 +450,7 @@ tablet_update_xy(struct tablet_dispatch *tablet,
bit_is_set(tablet->changed_axes, LIBINPUT_TABLET_TOOL_AXIS_Y)) {
absinfo = libevdev_get_abs_info(device->evdev, ABS_X);
if (device->left_handed.enabled)
if (tablet->rotation.rotate)
value = invert_axis(absinfo);
else
value = absinfo->value;
@ -414,7 +459,7 @@ tablet_update_xy(struct tablet_dispatch *tablet,
absinfo = libevdev_get_abs_info(device->evdev, ABS_Y);
if (device->left_handed.enabled)
if (tablet->rotation.rotate)
value = invert_axis(absinfo);
else
value = absinfo->value;
@ -1633,6 +1678,7 @@ tablet_send_events(struct tablet_dispatch *tablet,
if (tablet_send_proximity_out(tablet, tool, device, &axes, time)) {
tablet_change_to_left_handed(device);
tablet_apply_rotation(device);
tablet_history_reset(tablet);
}
}
@ -1960,15 +2006,19 @@ tablet_device_added(struct evdev_device *device,
struct evdev_device *added_device)
{
struct tablet_dispatch *tablet = tablet_dispatch(device->dispatch);
bool is_touchscreen, is_ext_touchpad;
if (libinput_device_get_device_group(&device->base) !=
libinput_device_get_device_group(&added_device->base))
return;
is_touchscreen = evdev_device_has_capability(added_device,
LIBINPUT_DEVICE_CAP_TOUCH);
is_ext_touchpad = evdev_device_has_capability(added_device,
LIBINPUT_DEVICE_CAP_POINTER) &&
(added_device->tags & EVDEV_TAG_EXTERNAL_TOUCHPAD);
/* Touch screens or external touchpads only */
if (evdev_device_has_capability(added_device, LIBINPUT_DEVICE_CAP_TOUCH) ||
(evdev_device_has_capability(added_device, LIBINPUT_DEVICE_CAP_POINTER) &&
(added_device->tags & EVDEV_TAG_EXTERNAL_TOUCHPAD))) {
if (is_touchscreen || is_ext_touchpad) {
evdev_log_debug(device,
"touch-arbitration: activated for %s<->%s\n",
device->devname,
@ -1976,6 +2026,19 @@ tablet_device_added(struct evdev_device *device,
tablet->touch_device = added_device;
}
if (is_ext_touchpad) {
evdev_log_debug(device,
"tablet-rotation: %s will rotate %s\n",
device->devname,
added_device->devname);
tablet->rotation.touch_device = added_device;
if (libinput_device_config_left_handed_get(&added_device->base)) {
tablet->rotation.touch_device_left_handed_state = true;
tablet_change_rotation(device, DO_NOTIFY);
}
}
}
static void
@ -1986,6 +2049,12 @@ tablet_device_removed(struct evdev_device *device,
if (tablet->touch_device == removed_device)
tablet->touch_device = NULL;
if (tablet->rotation.touch_device == removed_device) {
tablet->rotation.touch_device = NULL;
tablet->rotation.touch_device_left_handed_state = false;
tablet_change_rotation(device, DO_NOTIFY);
}
}
static void
@ -2031,6 +2100,30 @@ tablet_check_initial_proximity(struct evdev_device *device,
tablet->current_tool.serial = 0;
}
/* Called when the touchpad toggles to left-handed */
static void
tablet_left_handed_toggled(struct evdev_dispatch *dispatch,
struct evdev_device *device,
bool left_handed_enabled)
{
struct tablet_dispatch *tablet = tablet_dispatch(dispatch);
if (!tablet->rotation.touch_device)
return;
evdev_log_debug(device,
"tablet-rotation: touchpad is %s\n",
left_handed_enabled ? "left-handed" : "right-handed");
/* Our left-handed config is independent even though rotation is
* locked. So we rotate when either device is left-handed. But it
* can only be actually changed when the device is in a neutral
* state, hence the want_rotate.
*/
tablet->rotation.touch_device_left_handed_state = left_handed_enabled;
tablet_change_rotation(device, DONT_NOTIFY);
}
static struct evdev_dispatch_interface tablet_interface = {
.process = tablet_process,
.suspend = tablet_suspend,
@ -2044,6 +2137,7 @@ static struct evdev_dispatch_interface tablet_interface = {
.touch_arbitration_toggle = NULL,
.touch_arbitration_update_rect = NULL,
.get_switch_state = NULL,
.left_handed_toggle = tablet_left_handed_toggled,
};
static void

View file

@ -91,6 +91,15 @@ struct tablet_dispatch {
struct evdev_device *touch_device;
enum evdev_arbitration_state arbitration;
struct {
/* The device locked for rotation */
struct evdev_device *touch_device;
/* Last known left-handed state of the touchpad */
bool touch_device_left_handed_state;
bool rotate;
bool want_rotate;
} rotation;
struct {
struct libinput_timer prox_out_timer;
bool proximity_out_forced;

View file

@ -325,6 +325,10 @@ struct evdev_dispatch_interface {
enum libinput_switch_state
(*get_switch_state)(struct evdev_dispatch *dispatch,
enum libinput_switch which);
void (*left_handed_toggle)(struct evdev_dispatch *dispatch,
struct evdev_device *device,
bool left_handed_enabled);
};
enum evdev_dispatch_type {