diff --git a/src/evdev-tablet.c b/src/evdev-tablet.c index 8439cffe..4012b154 100644 --- a/src/evdev-tablet.c +++ b/src/evdev-tablet.c @@ -33,6 +33,11 @@ #include #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 diff --git a/src/evdev-tablet.h b/src/evdev-tablet.h index de930aaa..e19b62ca 100644 --- a/src/evdev-tablet.h +++ b/src/evdev-tablet.h @@ -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; diff --git a/src/evdev.h b/src/evdev.h index 729eccf6..1ebd04f7 100644 --- a/src/evdev.h +++ b/src/evdev.h @@ -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 {