2021-09-24 21:45:48 +01:00
|
|
|
// SPDX-License-Identifier: GPL-2.0-only
|
2020-10-05 20:27:52 +01:00
|
|
|
#include <assert.h>
|
2022-03-19 11:34:11 +00:00
|
|
|
#include <stdbool.h>
|
2021-10-15 10:26:00 -04:00
|
|
|
#include <strings.h>
|
2020-12-30 11:09:36 +00:00
|
|
|
#include <wlr/backend/libinput.h>
|
2022-03-19 11:34:11 +00:00
|
|
|
#include <wlr/types/wlr_input_device.h>
|
2022-06-25 15:57:04 +02:00
|
|
|
#include <wlr/types/wlr_keyboard.h>
|
|
|
|
|
#include <wlr/types/wlr_pointer.h>
|
|
|
|
|
#include <wlr/types/wlr_touch.h>
|
2020-10-02 21:19:56 +01:00
|
|
|
#include <wlr/util/log.h>
|
2022-09-16 18:41:02 -04:00
|
|
|
#include "common/mem.h"
|
2023-12-29 10:10:41 +01:00
|
|
|
#include "input/tablet.h"
|
2024-01-02 18:26:25 +01:00
|
|
|
#include "input/tablet_pad.h"
|
2023-09-03 19:21:16 +02:00
|
|
|
#include "input/input.h"
|
2023-09-03 19:15:50 +02:00
|
|
|
#include "input/keyboard.h"
|
2023-09-03 17:39:48 +02:00
|
|
|
#include "input/key-state.h"
|
2020-09-04 20:25:20 +01:00
|
|
|
#include "labwc.h"
|
2023-09-27 18:24:35 -04:00
|
|
|
#include "view.h"
|
2020-09-04 20:25:20 +01:00
|
|
|
|
2020-10-02 21:19:56 +01:00
|
|
|
static void
|
|
|
|
|
input_device_destroy(struct wl_listener *listener, void *data)
|
|
|
|
|
{
|
|
|
|
|
struct input *input = wl_container_of(listener, input, destroy);
|
|
|
|
|
wl_list_remove(&input->link);
|
2021-12-27 09:44:03 -05:00
|
|
|
wl_list_remove(&input->destroy.link);
|
2022-09-26 07:17:19 +01:00
|
|
|
|
|
|
|
|
/* `struct keyboard` is derived and has some extra clean up to do */
|
|
|
|
|
if (input->wlr_input_device->type == WLR_INPUT_DEVICE_KEYBOARD) {
|
|
|
|
|
struct keyboard *keyboard = (struct keyboard *)input;
|
|
|
|
|
wl_list_remove(&keyboard->key.link);
|
|
|
|
|
wl_list_remove(&keyboard->modifier.link);
|
2022-11-02 16:37:24 -04:00
|
|
|
keyboard_cancel_keybind_repeat(keyboard);
|
2022-09-26 07:17:19 +01:00
|
|
|
}
|
2020-10-02 21:19:56 +01:00
|
|
|
free(input);
|
|
|
|
|
}
|
|
|
|
|
|
2024-01-01 19:15:16 +00:00
|
|
|
static enum lab_libinput_device_type
|
2023-12-15 07:36:29 -08:00
|
|
|
device_type_from_wlr_device(struct wlr_input_device *wlr_input_device)
|
2022-03-19 11:34:11 +00:00
|
|
|
{
|
|
|
|
|
switch (wlr_input_device->type) {
|
|
|
|
|
case WLR_INPUT_DEVICE_TOUCH:
|
|
|
|
|
case WLR_INPUT_DEVICE_TABLET_TOOL:
|
2024-01-01 19:14:08 +00:00
|
|
|
return LAB_LIBINPUT_DEVICE_TOUCH;
|
2022-03-19 11:34:11 +00:00
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
2023-12-15 07:36:29 -08:00
|
|
|
|
|
|
|
|
if (wlr_input_device->type == WLR_INPUT_DEVICE_POINTER &&
|
|
|
|
|
wlr_input_device_is_libinput(wlr_input_device)) {
|
|
|
|
|
struct libinput_device *libinput_device =
|
|
|
|
|
wlr_libinput_get_device_handle(wlr_input_device);
|
|
|
|
|
|
|
|
|
|
if (libinput_device_config_tap_get_finger_count(libinput_device) > 0) {
|
2024-01-01 19:14:08 +00:00
|
|
|
return LAB_LIBINPUT_DEVICE_TOUCHPAD;
|
2023-12-15 07:36:29 -08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-01-01 19:14:08 +00:00
|
|
|
return LAB_LIBINPUT_DEVICE_NON_TOUCH;
|
2022-03-19 11:34:11 +00:00
|
|
|
}
|
|
|
|
|
|
2024-01-01 17:46:30 +00:00
|
|
|
/*
|
|
|
|
|
* Get applicable profile (category) by matching first by name and secondly be
|
|
|
|
|
* type (e.g. 'touch' and 'non-touch'). If not suitable match is found based on
|
|
|
|
|
* those two criteria we fallback on 'default'.
|
|
|
|
|
*/
|
|
|
|
|
static struct libinput_category *
|
|
|
|
|
get_category(struct wlr_input_device *device)
|
|
|
|
|
{
|
|
|
|
|
/* By name */
|
|
|
|
|
struct libinput_category *category;
|
|
|
|
|
wl_list_for_each_reverse(category, &rc.libinput_categories, link) {
|
|
|
|
|
if (category->name) {
|
|
|
|
|
if (!strcasecmp(device->name, category->name)) {
|
|
|
|
|
return category;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* By type */
|
2024-01-01 19:15:16 +00:00
|
|
|
enum lab_libinput_device_type type = device_type_from_wlr_device(device);
|
2024-01-01 17:46:30 +00:00
|
|
|
wl_list_for_each_reverse(category, &rc.libinput_categories, link) {
|
|
|
|
|
if (category->type == type) {
|
|
|
|
|
return category;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Use default profile as a fallback */
|
|
|
|
|
return libinput_category_get_default();
|
|
|
|
|
}
|
|
|
|
|
|
2021-02-06 15:47:51 +00:00
|
|
|
static void
|
|
|
|
|
configure_libinput(struct wlr_input_device *wlr_input_device)
|
2020-10-02 21:19:56 +01:00
|
|
|
{
|
2021-02-06 15:47:51 +00:00
|
|
|
if (!wlr_input_device) {
|
2021-07-23 21:15:55 +01:00
|
|
|
wlr_log(WLR_ERROR, "no wlr_input_device");
|
2021-02-06 15:47:51 +00:00
|
|
|
return;
|
|
|
|
|
}
|
2022-12-21 18:19:07 +00:00
|
|
|
if (!wlr_input_device_is_libinput(wlr_input_device)) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-30 11:09:36 +00:00
|
|
|
struct libinput_device *libinput_dev =
|
2021-02-06 15:47:51 +00:00
|
|
|
wlr_libinput_get_device_handle(wlr_input_device);
|
|
|
|
|
if (!libinput_dev) {
|
2021-07-23 21:15:55 +01:00
|
|
|
wlr_log(WLR_ERROR, "no libinput_dev");
|
2021-02-06 15:47:51 +00:00
|
|
|
return;
|
|
|
|
|
}
|
2021-10-09 09:10:26 -04:00
|
|
|
|
2024-01-01 17:46:30 +00:00
|
|
|
struct libinput_category *dc = get_category(wlr_input_device);
|
2021-10-15 10:26:00 -04:00
|
|
|
|
2022-12-22 16:44:08 -05:00
|
|
|
/*
|
|
|
|
|
* The above logic should have always matched SOME category
|
|
|
|
|
* (the default category if none other took precedence)
|
|
|
|
|
*/
|
|
|
|
|
assert(dc);
|
2021-10-15 10:26:00 -04:00
|
|
|
|
2021-02-06 15:47:51 +00:00
|
|
|
if (libinput_device_config_tap_get_finger_count(libinput_dev) <= 0) {
|
2021-10-09 09:10:26 -04:00
|
|
|
wlr_log(WLR_INFO, "tap unavailable");
|
|
|
|
|
} else {
|
|
|
|
|
wlr_log(WLR_INFO, "tap configured");
|
2021-10-15 10:26:00 -04:00
|
|
|
libinput_device_config_tap_set_enabled(libinput_dev, dc->tap);
|
2022-04-04 20:53:36 +01:00
|
|
|
libinput_device_config_tap_set_button_map(libinput_dev,
|
|
|
|
|
dc->tap_button_map);
|
2021-10-09 09:10:26 -04:00
|
|
|
}
|
|
|
|
|
|
2023-09-02 17:32:48 +09:00
|
|
|
if (libinput_device_config_tap_get_finger_count(libinput_dev) <= 0
|
|
|
|
|
|| dc->tap_and_drag < 0) {
|
|
|
|
|
wlr_log(WLR_INFO, "tap-and-drag not configured");
|
|
|
|
|
} else {
|
|
|
|
|
wlr_log(WLR_INFO, "tap-and-drag configured");
|
|
|
|
|
libinput_device_config_tap_set_drag_enabled(
|
|
|
|
|
libinput_dev, dc->tap_and_drag);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (libinput_device_config_tap_get_finger_count(libinput_dev) <= 0
|
|
|
|
|
|| dc->drag_lock < 0) {
|
|
|
|
|
wlr_log(WLR_INFO, "drag lock not configured");
|
|
|
|
|
} else {
|
|
|
|
|
wlr_log(WLR_INFO, "drag lock configured");
|
|
|
|
|
libinput_device_config_tap_set_drag_lock_enabled(
|
|
|
|
|
libinput_dev, dc->drag_lock);
|
|
|
|
|
}
|
|
|
|
|
|
2021-10-09 09:10:26 -04:00
|
|
|
if (libinput_device_config_scroll_has_natural_scroll(libinput_dev) <= 0
|
2023-09-02 17:32:29 +09:00
|
|
|
|| dc->natural_scroll < 0) {
|
2021-10-09 09:10:26 -04:00
|
|
|
wlr_log(WLR_INFO, "natural scroll not configured");
|
|
|
|
|
} else {
|
|
|
|
|
wlr_log(WLR_INFO, "natural scroll configured");
|
|
|
|
|
libinput_device_config_scroll_set_natural_scroll_enabled(
|
2021-10-15 10:26:00 -04:00
|
|
|
libinput_dev, dc->natural_scroll);
|
2021-10-09 09:10:26 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (libinput_device_config_left_handed_is_available(libinput_dev) <= 0
|
2023-09-02 17:32:29 +09:00
|
|
|
|| dc->left_handed < 0) {
|
2021-10-09 09:10:26 -04:00
|
|
|
wlr_log(WLR_INFO, "left-handed mode not configured");
|
|
|
|
|
} else {
|
|
|
|
|
wlr_log(WLR_INFO, "left-handed mode configured");
|
|
|
|
|
libinput_device_config_left_handed_set(libinput_dev,
|
2021-10-15 10:26:00 -04:00
|
|
|
dc->left_handed);
|
2021-10-09 09:10:26 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (libinput_device_config_accel_is_available(libinput_dev) == 0) {
|
|
|
|
|
wlr_log(WLR_INFO, "pointer acceleration unavailable");
|
|
|
|
|
} else {
|
|
|
|
|
wlr_log(WLR_INFO, "pointer acceleration configured");
|
2021-10-15 10:26:00 -04:00
|
|
|
if (dc->pointer_speed > -1) {
|
2021-10-15 20:52:36 +01:00
|
|
|
libinput_device_config_accel_set_speed(libinput_dev,
|
2021-10-15 10:26:00 -04:00
|
|
|
dc->pointer_speed);
|
2021-10-09 09:10:26 -04:00
|
|
|
}
|
2021-10-15 10:26:00 -04:00
|
|
|
if (dc->accel_profile > 0) {
|
2021-10-09 09:10:26 -04:00
|
|
|
libinput_device_config_accel_set_profile(libinput_dev,
|
2021-10-15 10:26:00 -04:00
|
|
|
dc->accel_profile);
|
2021-10-09 09:10:26 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (libinput_device_config_middle_emulation_is_available(libinput_dev)
|
2021-10-15 10:26:00 -04:00
|
|
|
== 0 || dc->middle_emu < 0) {
|
2021-10-09 09:10:26 -04:00
|
|
|
wlr_log(WLR_INFO, "middle emulation not configured");
|
|
|
|
|
} else {
|
|
|
|
|
wlr_log(WLR_INFO, "middle emulation configured");
|
|
|
|
|
libinput_device_config_middle_emulation_set_enabled(
|
2021-10-15 10:26:00 -04:00
|
|
|
libinput_dev, dc->middle_emu);
|
2021-10-09 09:10:26 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (libinput_device_config_dwt_is_available(libinput_dev) == 0
|
2023-09-02 17:32:29 +09:00
|
|
|
|| dc->dwt < 0) {
|
2021-10-09 09:10:26 -04:00
|
|
|
wlr_log(WLR_INFO, "dwt not configured");
|
|
|
|
|
} else {
|
|
|
|
|
wlr_log(WLR_INFO, "dwt configured");
|
2021-10-15 10:26:00 -04:00
|
|
|
libinput_device_config_dwt_set_enabled(libinput_dev, dc->dwt);
|
2021-02-06 15:47:51 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-01-06 21:40:10 +00:00
|
|
|
static struct wlr_output *
|
|
|
|
|
output_by_name(struct server *server, const char *name)
|
|
|
|
|
{
|
2022-04-04 20:53:36 +01:00
|
|
|
assert(name);
|
2022-01-06 21:40:10 +00:00
|
|
|
struct output *output;
|
|
|
|
|
wl_list_for_each(output, &server->outputs, link) {
|
|
|
|
|
if (!strcasecmp(output->wlr_output->name, name)) {
|
|
|
|
|
return output->wlr_output;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2024-01-07 22:22:06 +01:00
|
|
|
static void
|
|
|
|
|
map_input_to_output(struct seat *seat, struct wlr_input_device *dev, char *output_name)
|
|
|
|
|
{
|
|
|
|
|
struct wlr_output *output = NULL;
|
|
|
|
|
if (output_name) {
|
|
|
|
|
output = output_by_name(seat->server, output_name);
|
|
|
|
|
}
|
|
|
|
|
wlr_cursor_map_input_to_output(seat->cursor, dev, output);
|
|
|
|
|
wlr_cursor_map_input_to_region(seat->cursor, dev, NULL);
|
|
|
|
|
}
|
|
|
|
|
|
2022-09-26 07:17:19 +01:00
|
|
|
static struct input *
|
|
|
|
|
new_pointer(struct seat *seat, struct wlr_input_device *dev)
|
2021-02-06 15:47:51 +00:00
|
|
|
{
|
2022-09-26 07:17:19 +01:00
|
|
|
struct input *input = znew(*input);
|
|
|
|
|
input->wlr_input_device = dev;
|
2022-12-21 18:19:07 +00:00
|
|
|
configure_libinput(dev);
|
2022-01-06 21:40:10 +00:00
|
|
|
wlr_cursor_attach_input_device(seat->cursor, dev);
|
|
|
|
|
|
|
|
|
|
/* In support of running with WLR_WL_OUTPUTS set to >=2 */
|
2022-03-19 11:34:11 +00:00
|
|
|
if (dev->type == WLR_INPUT_DEVICE_POINTER) {
|
2022-06-25 15:57:04 +02:00
|
|
|
struct wlr_pointer *pointer = wlr_pointer_from_input_device(dev);
|
|
|
|
|
wlr_log(WLR_INFO, "map pointer to output %s\n", pointer->output_name);
|
2024-01-07 22:22:06 +01:00
|
|
|
map_input_to_output(seat, dev, pointer->output_name);
|
2022-01-17 23:02:59 +01:00
|
|
|
}
|
2022-09-26 07:17:19 +01:00
|
|
|
return input;
|
2020-10-02 21:19:56 +01:00
|
|
|
}
|
|
|
|
|
|
2022-09-26 07:17:19 +01:00
|
|
|
static struct input *
|
|
|
|
|
new_keyboard(struct seat *seat, struct wlr_input_device *device, bool virtual)
|
2020-10-02 21:19:56 +01:00
|
|
|
{
|
2022-09-26 07:17:19 +01:00
|
|
|
struct wlr_keyboard *kb = wlr_keyboard_from_input_device(device);
|
|
|
|
|
|
|
|
|
|
struct keyboard *keyboard = znew(*keyboard);
|
|
|
|
|
keyboard->base.wlr_input_device = device;
|
|
|
|
|
keyboard->wlr_keyboard = kb;
|
|
|
|
|
keyboard->is_virtual = virtual;
|
|
|
|
|
|
2020-10-02 21:19:56 +01:00
|
|
|
wlr_keyboard_set_keymap(kb, seat->keyboard_group->keyboard.keymap);
|
2022-09-26 07:17:19 +01:00
|
|
|
|
2023-10-08 22:26:26 -04:00
|
|
|
/*
|
|
|
|
|
* This needs to be before wlr_keyboard_group_add_keyboard().
|
|
|
|
|
* For some reason, wlroots takes the modifier state from the
|
|
|
|
|
* new keyboard and syncs it to the others in the group, rather
|
|
|
|
|
* than the other way around.
|
|
|
|
|
*/
|
|
|
|
|
keyboard_set_numlock(kb);
|
|
|
|
|
|
2022-09-26 07:17:19 +01:00
|
|
|
if (!virtual) {
|
|
|
|
|
wlr_keyboard_group_add_keyboard(seat->keyboard_group, kb);
|
|
|
|
|
}
|
|
|
|
|
|
2023-09-03 19:15:50 +02:00
|
|
|
keyboard_setup_handlers(keyboard);
|
2022-09-26 07:17:19 +01:00
|
|
|
|
2022-03-28 20:41:53 +01:00
|
|
|
wlr_seat_set_keyboard(seat->seat, kb);
|
2022-09-26 07:17:19 +01:00
|
|
|
|
|
|
|
|
return (struct input *)keyboard;
|
2020-10-02 21:19:56 +01:00
|
|
|
}
|
|
|
|
|
|
2024-01-13 00:25:08 +01:00
|
|
|
static void
|
|
|
|
|
map_touch_to_output(struct seat *seat, struct wlr_input_device *dev)
|
|
|
|
|
{
|
|
|
|
|
struct wlr_touch *touch = wlr_touch_from_input_device(dev);
|
|
|
|
|
char *output_name = touch->output_name ? touch->output_name : rc.touch.output_name;
|
|
|
|
|
wlr_log(WLR_INFO, "map touch to output %s\n", output_name);
|
|
|
|
|
map_input_to_output(seat, dev, output_name);
|
|
|
|
|
}
|
|
|
|
|
|
2022-09-26 07:17:19 +01:00
|
|
|
static struct input *
|
|
|
|
|
new_touch(struct seat *seat, struct wlr_input_device *dev)
|
2021-12-31 23:50:31 +00:00
|
|
|
{
|
2022-09-26 07:17:19 +01:00
|
|
|
struct input *input = znew(*input);
|
|
|
|
|
input->wlr_input_device = dev;
|
2022-12-21 18:19:07 +00:00
|
|
|
configure_libinput(dev);
|
2021-12-31 23:50:31 +00:00
|
|
|
wlr_cursor_attach_input_device(seat->cursor, dev);
|
|
|
|
|
|
|
|
|
|
/* In support of running with WLR_WL_OUTPUTS set to >=2 */
|
|
|
|
|
if (dev->type == WLR_INPUT_DEVICE_TOUCH) {
|
2024-01-13 00:25:08 +01:00
|
|
|
map_touch_to_output(seat, dev);
|
2021-12-31 23:50:31 +00:00
|
|
|
}
|
2022-09-26 07:17:19 +01:00
|
|
|
return input;
|
2021-12-31 23:50:31 +00:00
|
|
|
}
|
|
|
|
|
|
2023-12-01 22:13:07 +01:00
|
|
|
static struct input *
|
|
|
|
|
new_tablet(struct seat *seat, struct wlr_input_device *dev)
|
|
|
|
|
{
|
|
|
|
|
struct input *input = znew(*input);
|
|
|
|
|
input->wlr_input_device = dev;
|
2024-01-02 18:26:25 +01:00
|
|
|
tablet_init(seat, dev);
|
2024-01-07 22:24:16 +01:00
|
|
|
wlr_cursor_attach_input_device(seat->cursor, dev);
|
|
|
|
|
wlr_log(WLR_INFO, "map tablet to output %s\n", rc.tablet.output_name);
|
|
|
|
|
map_input_to_output(seat, dev, rc.tablet.output_name);
|
2024-01-02 18:26:25 +01:00
|
|
|
|
|
|
|
|
return input;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static struct input *
|
|
|
|
|
new_tablet_pad(struct seat *seat, struct wlr_input_device *dev)
|
|
|
|
|
{
|
|
|
|
|
struct input *input = znew(*input);
|
|
|
|
|
input->wlr_input_device = dev;
|
|
|
|
|
tablet_pad_init(seat, dev);
|
2023-12-01 22:13:07 +01:00
|
|
|
|
|
|
|
|
return input;
|
|
|
|
|
}
|
|
|
|
|
|
2022-08-17 18:12:24 +00:00
|
|
|
static void
|
|
|
|
|
seat_update_capabilities(struct seat *seat)
|
|
|
|
|
{
|
|
|
|
|
struct input *input = NULL;
|
|
|
|
|
uint32_t caps = 0;
|
2022-09-26 07:17:19 +01:00
|
|
|
|
2022-08-17 18:12:24 +00:00
|
|
|
wl_list_for_each(input, &seat->inputs, link) {
|
|
|
|
|
switch (input->wlr_input_device->type) {
|
|
|
|
|
case WLR_INPUT_DEVICE_KEYBOARD:
|
|
|
|
|
caps |= WL_SEAT_CAPABILITY_KEYBOARD;
|
|
|
|
|
break;
|
|
|
|
|
case WLR_INPUT_DEVICE_POINTER:
|
|
|
|
|
caps |= WL_SEAT_CAPABILITY_POINTER;
|
|
|
|
|
break;
|
|
|
|
|
case WLR_INPUT_DEVICE_TOUCH:
|
|
|
|
|
caps |= WL_SEAT_CAPABILITY_TOUCH;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
wlr_seat_set_capabilities(seat->seat, caps);
|
|
|
|
|
}
|
|
|
|
|
|
2022-08-17 18:16:16 +00:00
|
|
|
static void
|
|
|
|
|
seat_add_device(struct seat *seat, struct input *input)
|
|
|
|
|
{
|
|
|
|
|
input->seat = seat;
|
|
|
|
|
input->destroy.notify = input_device_destroy;
|
|
|
|
|
wl_signal_add(&input->wlr_input_device->events.destroy, &input->destroy);
|
|
|
|
|
wl_list_insert(&seat->inputs, &input->link);
|
|
|
|
|
|
|
|
|
|
seat_update_capabilities(seat);
|
|
|
|
|
}
|
|
|
|
|
|
2020-10-02 21:19:56 +01:00
|
|
|
static void
|
|
|
|
|
new_input_notify(struct wl_listener *listener, void *data)
|
|
|
|
|
{
|
|
|
|
|
struct seat *seat = wl_container_of(listener, seat, new_input);
|
|
|
|
|
struct wlr_input_device *device = data;
|
2022-09-26 07:17:19 +01:00
|
|
|
struct input *input = NULL;
|
2020-10-02 21:19:56 +01:00
|
|
|
|
|
|
|
|
switch (device->type) {
|
|
|
|
|
case WLR_INPUT_DEVICE_KEYBOARD:
|
2022-09-26 07:17:19 +01:00
|
|
|
input = new_keyboard(seat, device, false);
|
2020-10-02 21:19:56 +01:00
|
|
|
break;
|
|
|
|
|
case WLR_INPUT_DEVICE_POINTER:
|
2022-09-26 07:17:19 +01:00
|
|
|
input = new_pointer(seat, device);
|
2020-10-02 21:19:56 +01:00
|
|
|
break;
|
2021-12-31 23:50:31 +00:00
|
|
|
case WLR_INPUT_DEVICE_TOUCH:
|
2022-09-26 07:17:19 +01:00
|
|
|
input = new_touch(seat, device);
|
2021-12-31 23:50:31 +00:00
|
|
|
break;
|
2023-12-01 22:13:07 +01:00
|
|
|
case WLR_INPUT_DEVICE_TABLET_TOOL:
|
|
|
|
|
input = new_tablet(seat, device);
|
|
|
|
|
break;
|
2024-01-07 22:20:38 +01:00
|
|
|
case WLR_INPUT_DEVICE_TABLET_PAD:
|
|
|
|
|
input = new_tablet_pad(seat, device);
|
|
|
|
|
break;
|
2020-10-02 21:19:56 +01:00
|
|
|
default:
|
|
|
|
|
wlr_log(WLR_INFO, "unsupported input device");
|
2022-09-26 07:17:19 +01:00
|
|
|
return;
|
2020-10-02 21:19:56 +01:00
|
|
|
}
|
|
|
|
|
|
2022-08-17 18:16:16 +00:00
|
|
|
seat_add_device(seat, input);
|
2020-10-02 21:19:56 +01:00
|
|
|
}
|
|
|
|
|
|
2022-08-17 18:17:21 +00:00
|
|
|
static void
|
|
|
|
|
new_virtual_pointer(struct wl_listener *listener, void *data)
|
|
|
|
|
{
|
|
|
|
|
struct seat *seat = wl_container_of(listener, seat, virtual_pointer_new);
|
|
|
|
|
struct wlr_virtual_pointer_v1_new_pointer_event *event = data;
|
|
|
|
|
struct wlr_virtual_pointer_v1 *pointer = event->new_pointer;
|
|
|
|
|
struct wlr_input_device *device = &pointer->pointer.base;
|
|
|
|
|
|
2022-09-26 07:17:19 +01:00
|
|
|
struct input *input = new_pointer(seat, device);
|
2022-08-17 18:17:21 +00:00
|
|
|
device->data = input;
|
|
|
|
|
seat_add_device(seat, input);
|
|
|
|
|
if (event->suggested_output) {
|
|
|
|
|
wlr_cursor_map_input_to_output(seat->cursor, device,
|
|
|
|
|
event->suggested_output);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-08-17 18:23:06 +00:00
|
|
|
static void
|
|
|
|
|
new_virtual_keyboard(struct wl_listener *listener, void *data)
|
|
|
|
|
{
|
|
|
|
|
struct seat *seat = wl_container_of(listener, seat, virtual_keyboard_new);
|
2022-09-26 07:17:19 +01:00
|
|
|
struct wlr_virtual_keyboard_v1 *virtual_keyboard = data;
|
|
|
|
|
struct wlr_input_device *device = &virtual_keyboard->keyboard.base;
|
2022-08-17 18:23:06 +00:00
|
|
|
|
2022-09-26 07:17:19 +01:00
|
|
|
struct input *input = new_keyboard(seat, device, true);
|
2022-08-17 18:23:06 +00:00
|
|
|
device->data = input;
|
|
|
|
|
seat_add_device(seat, input);
|
|
|
|
|
}
|
|
|
|
|
|
2023-09-27 18:24:35 -04:00
|
|
|
static void
|
|
|
|
|
focus_change_notify(struct wl_listener *listener, void *data)
|
|
|
|
|
{
|
|
|
|
|
struct seat *seat = wl_container_of(listener, seat, focus_change);
|
|
|
|
|
struct wlr_seat_keyboard_focus_change_event *event = data;
|
|
|
|
|
struct server *server = seat->server;
|
2023-12-19 17:45:43 +00:00
|
|
|
struct wlr_surface *surface = event->new_surface;
|
|
|
|
|
struct view *view = surface ? view_from_wlr_surface(surface) : NULL;
|
|
|
|
|
|
|
|
|
|
/* Prevent focus switch to layershell client from updating view state */
|
|
|
|
|
if (surface && wlr_layer_surface_v1_try_from_wlr_surface(surface)) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2023-09-27 18:24:35 -04:00
|
|
|
|
2023-10-14 12:41:31 -04:00
|
|
|
/*
|
|
|
|
|
* If an xwayland-unmanaged surface was focused belonging to the
|
|
|
|
|
* same application as the focused view, allow the view to remain
|
|
|
|
|
* active. This fixes an issue with menus immediately closing in
|
|
|
|
|
* some X11 apps (try LibreOffice with SAL_USE_VCLPLUGIN=gen).
|
|
|
|
|
*/
|
2023-12-19 17:45:11 +00:00
|
|
|
if (!view && server->active_view && event->new_surface
|
|
|
|
|
&& view_is_related(server->active_view,
|
2023-10-15 00:15:16 -04:00
|
|
|
event->new_surface)) {
|
|
|
|
|
return;
|
2023-10-14 12:41:31 -04:00
|
|
|
}
|
|
|
|
|
|
2023-12-19 17:45:11 +00:00
|
|
|
if (view != server->active_view) {
|
|
|
|
|
if (server->active_view) {
|
|
|
|
|
view_set_activated(server->active_view, false);
|
2023-09-27 18:24:35 -04:00
|
|
|
}
|
|
|
|
|
if (view) {
|
|
|
|
|
view_set_activated(view, true);
|
|
|
|
|
}
|
2023-12-19 17:45:11 +00:00
|
|
|
server->active_view = view;
|
2023-09-27 18:24:35 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-10-02 21:19:56 +01:00
|
|
|
void
|
|
|
|
|
seat_init(struct server *server)
|
|
|
|
|
{
|
|
|
|
|
struct seat *seat = &server->seat;
|
|
|
|
|
seat->server = server;
|
|
|
|
|
|
|
|
|
|
seat->seat = wlr_seat_create(server->wl_display, "seat0");
|
|
|
|
|
if (!seat->seat) {
|
|
|
|
|
wlr_log(WLR_ERROR, "cannot allocate seat");
|
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
|
}
|
|
|
|
|
|
2023-08-26 17:01:42 +00:00
|
|
|
wl_list_init(&seat->touch_points);
|
2021-10-17 16:54:35 -04:00
|
|
|
wl_list_init(&seat->constraint_commit.link);
|
2020-10-02 21:19:56 +01:00
|
|
|
wl_list_init(&seat->inputs);
|
|
|
|
|
seat->new_input.notify = new_input_notify;
|
|
|
|
|
wl_signal_add(&server->backend->events.new_input, &seat->new_input);
|
|
|
|
|
|
2023-09-27 18:24:35 -04:00
|
|
|
seat->focus_change.notify = focus_change_notify;
|
|
|
|
|
wl_signal_add(&seat->seat->keyboard_state.events.focus_change,
|
|
|
|
|
&seat->focus_change);
|
|
|
|
|
|
2022-08-17 18:17:21 +00:00
|
|
|
seat->virtual_pointer = wlr_virtual_pointer_manager_v1_create(
|
|
|
|
|
server->wl_display);
|
|
|
|
|
wl_signal_add(&seat->virtual_pointer->events.new_virtual_pointer,
|
|
|
|
|
&seat->virtual_pointer_new);
|
|
|
|
|
seat->virtual_pointer_new.notify = new_virtual_pointer;
|
|
|
|
|
|
2022-08-17 18:23:06 +00:00
|
|
|
seat->virtual_keyboard = wlr_virtual_keyboard_manager_v1_create(
|
|
|
|
|
server->wl_display);
|
|
|
|
|
wl_signal_add(&seat->virtual_keyboard->events.new_virtual_keyboard,
|
|
|
|
|
&seat->virtual_keyboard_new);
|
|
|
|
|
seat->virtual_keyboard_new.notify = new_virtual_keyboard;
|
|
|
|
|
|
2020-10-02 21:19:56 +01:00
|
|
|
seat->cursor = wlr_cursor_create();
|
|
|
|
|
if (!seat->cursor) {
|
|
|
|
|
wlr_log(WLR_ERROR, "unable to create cursor");
|
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
|
}
|
|
|
|
|
wlr_cursor_attach_output_layout(seat->cursor, server->output_layout);
|
|
|
|
|
|
2023-09-03 19:21:16 +02:00
|
|
|
input_handlers_init(seat);
|
2020-10-02 21:19:56 +01:00
|
|
|
}
|
|
|
|
|
|
2020-09-28 20:41:41 +01:00
|
|
|
void
|
2020-10-02 21:19:56 +01:00
|
|
|
seat_finish(struct server *server)
|
2020-09-08 20:18:12 +01:00
|
|
|
{
|
2020-10-02 21:19:56 +01:00
|
|
|
struct seat *seat = &server->seat;
|
|
|
|
|
wl_list_remove(&seat->new_input.link);
|
2023-09-27 18:24:35 -04:00
|
|
|
wl_list_remove(&seat->focus_change.link);
|
2022-09-26 07:17:19 +01:00
|
|
|
|
|
|
|
|
struct input *input, *next;
|
|
|
|
|
wl_list_for_each_safe(input, next, &seat->inputs, link) {
|
|
|
|
|
input_device_destroy(&input->destroy, NULL);
|
|
|
|
|
}
|
|
|
|
|
|
2023-09-03 19:21:16 +02:00
|
|
|
input_handlers_finish(seat);
|
2020-09-08 20:18:12 +01:00
|
|
|
}
|
|
|
|
|
|
2022-12-21 18:19:07 +00:00
|
|
|
static void
|
|
|
|
|
configure_keyboard(struct wlr_input_device *device)
|
|
|
|
|
{
|
|
|
|
|
assert(device->type == WLR_INPUT_DEVICE_KEYBOARD);
|
|
|
|
|
struct wlr_keyboard *kb = wlr_keyboard_from_input_device(device);
|
|
|
|
|
wlr_keyboard_set_repeat_info(kb, rc.repeat_rate, rc.repeat_delay);
|
|
|
|
|
}
|
|
|
|
|
|
2021-10-10 12:03:18 -04:00
|
|
|
void
|
|
|
|
|
seat_reconfigure(struct server *server)
|
|
|
|
|
{
|
|
|
|
|
struct seat *seat = &server->seat;
|
|
|
|
|
struct input *input;
|
|
|
|
|
wl_list_for_each(input, &seat->inputs, link) {
|
2022-12-21 18:19:07 +00:00
|
|
|
switch (input->wlr_input_device->type) {
|
|
|
|
|
case WLR_INPUT_DEVICE_KEYBOARD:
|
|
|
|
|
configure_keyboard(input->wlr_input_device);
|
|
|
|
|
break;
|
|
|
|
|
case WLR_INPUT_DEVICE_POINTER:
|
2021-10-10 12:03:18 -04:00
|
|
|
configure_libinput(input->wlr_input_device);
|
2022-12-21 18:19:07 +00:00
|
|
|
break;
|
2024-01-13 00:25:19 +01:00
|
|
|
case WLR_INPUT_DEVICE_TOUCH:
|
|
|
|
|
map_touch_to_output(seat, input->wlr_input_device);
|
|
|
|
|
break;
|
2024-01-08 18:45:49 +01:00
|
|
|
case WLR_INPUT_DEVICE_TABLET_TOOL:
|
|
|
|
|
map_input_to_output(seat, input->wlr_input_device, rc.tablet.output_name);
|
|
|
|
|
break;
|
2022-12-21 18:19:07 +00:00
|
|
|
default:
|
|
|
|
|
break;
|
2021-10-10 12:03:18 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-28 22:34:27 +00:00
|
|
|
static void
|
2023-10-15 02:59:58 -04:00
|
|
|
seat_focus(struct seat *seat, struct wlr_surface *surface, bool is_lock_surface)
|
2020-09-04 20:25:20 +01:00
|
|
|
{
|
2023-10-15 02:59:58 -04:00
|
|
|
/*
|
|
|
|
|
* Respect session lock. This check is critical, DO NOT REMOVE.
|
|
|
|
|
* It should also come before the !surface condition, or the
|
|
|
|
|
* lock screen may lose focus and become impossible to unlock.
|
|
|
|
|
*/
|
|
|
|
|
struct server *server = seat->server;
|
|
|
|
|
if (server->session_lock && !is_lock_surface) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2020-09-04 20:25:20 +01:00
|
|
|
if (!surface) {
|
2020-10-08 20:22:52 +01:00
|
|
|
wlr_seat_keyboard_notify_clear_focus(seat->seat);
|
2020-09-04 20:25:20 +01:00
|
|
|
return;
|
|
|
|
|
}
|
2023-10-15 02:59:58 -04:00
|
|
|
|
|
|
|
|
/* Respect input inhibit (also used by some lock screens) */
|
|
|
|
|
if (input_inhibit_blocks_surface(seat, surface->resource)) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2022-09-20 20:46:39 +01:00
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Key events associated with keybindings (both pressed and released)
|
|
|
|
|
* are not sent to clients. When changing surface-focus it is therefore
|
|
|
|
|
* important not to send the keycodes of _all_ pressed keys, but only
|
|
|
|
|
* those that were actually _sent_ to clients (that is, those that were
|
|
|
|
|
* not bound).
|
|
|
|
|
*/
|
|
|
|
|
uint32_t *pressed_sent_keycodes = key_state_pressed_sent_keycodes();
|
|
|
|
|
int nr_pressed_sent_keycodes = key_state_nr_pressed_sent_keycodes();
|
|
|
|
|
|
2023-10-15 02:59:58 -04:00
|
|
|
struct wlr_keyboard *kb = &seat->keyboard_group->keyboard;
|
2022-09-20 20:46:39 +01:00
|
|
|
wlr_seat_keyboard_notify_enter(seat->seat, surface,
|
|
|
|
|
pressed_sent_keycodes, nr_pressed_sent_keycodes, &kb->modifiers);
|
2021-10-17 16:54:35 -04:00
|
|
|
|
|
|
|
|
struct wlr_pointer_constraint_v1 *constraint =
|
|
|
|
|
wlr_pointer_constraints_v1_constraint_for_surface(server->constraints,
|
|
|
|
|
surface, seat->seat);
|
|
|
|
|
constrain_cursor(server, constraint);
|
2020-09-08 20:18:12 +01:00
|
|
|
}
|
2020-10-31 15:09:13 +00:00
|
|
|
|
2023-01-28 22:34:27 +00:00
|
|
|
void
|
|
|
|
|
seat_focus_surface(struct seat *seat, struct wlr_surface *surface)
|
|
|
|
|
{
|
2023-10-15 02:59:58 -04:00
|
|
|
/* Respect layer-shell exclusive keyboard-interactivity. */
|
2023-01-28 22:34:27 +00:00
|
|
|
if (seat->focused_layer && seat->focused_layer->current.keyboard_interactive
|
|
|
|
|
== ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2023-10-15 02:59:58 -04:00
|
|
|
seat_focus(seat, surface, /*is_lock_surface*/ false);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
seat_focus_lock_surface(struct seat *seat, struct wlr_surface *surface)
|
|
|
|
|
{
|
|
|
|
|
seat_focus(seat, surface, /*is_lock_surface*/ true);
|
2023-01-28 22:34:27 +00:00
|
|
|
}
|
|
|
|
|
|
2020-10-31 15:09:13 +00:00
|
|
|
void
|
|
|
|
|
seat_set_focus_layer(struct seat *seat, struct wlr_layer_surface_v1 *layer)
|
|
|
|
|
{
|
|
|
|
|
if (!layer) {
|
|
|
|
|
seat->focused_layer = NULL;
|
2023-09-23 11:51:47 -04:00
|
|
|
desktop_focus_topmost_view(seat->server);
|
2020-10-31 15:09:13 +00:00
|
|
|
return;
|
|
|
|
|
}
|
2023-10-15 02:59:58 -04:00
|
|
|
seat_focus(seat, layer->surface, /*is_lock_surface*/ false);
|
2020-10-31 15:09:13 +00:00
|
|
|
if (layer->current.layer >= ZWLR_LAYER_SHELL_V1_LAYER_TOP) {
|
|
|
|
|
seat->focused_layer = layer;
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-09-01 17:50:28 -04:00
|
|
|
|
2022-09-13 10:55:59 -04:00
|
|
|
static void
|
|
|
|
|
pressed_surface_destroy(struct wl_listener *listener, void *data)
|
|
|
|
|
{
|
|
|
|
|
struct wlr_surface *surface = data;
|
|
|
|
|
struct seat *seat = wl_container_of(listener, seat,
|
|
|
|
|
pressed_surface_destroy);
|
|
|
|
|
|
|
|
|
|
assert(surface == seat->pressed.surface);
|
|
|
|
|
seat_reset_pressed(seat);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
seat_set_pressed(struct seat *seat, struct view *view,
|
2022-09-10 01:57:39 -04:00
|
|
|
struct wlr_scene_node *node, struct wlr_surface *surface,
|
2022-09-14 23:09:36 -04:00
|
|
|
struct wlr_surface *toplevel, uint32_t resize_edges)
|
2022-09-13 10:55:59 -04:00
|
|
|
{
|
2022-09-14 23:09:36 -04:00
|
|
|
assert(view || surface);
|
2022-09-13 10:55:59 -04:00
|
|
|
seat_reset_pressed(seat);
|
|
|
|
|
|
|
|
|
|
seat->pressed.view = view;
|
|
|
|
|
seat->pressed.node = node;
|
|
|
|
|
seat->pressed.surface = surface;
|
2022-09-10 01:57:39 -04:00
|
|
|
seat->pressed.toplevel = toplevel;
|
2022-09-14 23:09:36 -04:00
|
|
|
seat->pressed.resize_edges = resize_edges;
|
|
|
|
|
|
|
|
|
|
if (surface) {
|
|
|
|
|
seat->pressed_surface_destroy.notify = pressed_surface_destroy;
|
|
|
|
|
wl_signal_add(&surface->events.destroy,
|
|
|
|
|
&seat->pressed_surface_destroy);
|
|
|
|
|
}
|
2022-09-13 10:55:59 -04:00
|
|
|
}
|
|
|
|
|
|
2022-09-01 17:50:28 -04:00
|
|
|
void
|
|
|
|
|
seat_reset_pressed(struct seat *seat)
|
|
|
|
|
{
|
2022-09-13 10:55:59 -04:00
|
|
|
if (seat->pressed.surface) {
|
|
|
|
|
wl_list_remove(&seat->pressed_surface_destroy.link);
|
|
|
|
|
}
|
2022-09-14 23:09:36 -04:00
|
|
|
|
|
|
|
|
seat->pressed.view = NULL;
|
|
|
|
|
seat->pressed.node = NULL;
|
|
|
|
|
seat->pressed.surface = NULL;
|
|
|
|
|
seat->pressed.toplevel = NULL;
|
|
|
|
|
seat->pressed.resize_edges = 0;
|
2022-09-01 17:50:28 -04:00
|
|
|
}
|
2024-01-09 06:58:35 +01:00
|
|
|
|
|
|
|
|
void
|
|
|
|
|
seat_output_layout_changed(struct seat *seat)
|
|
|
|
|
{
|
|
|
|
|
struct input *input = NULL;
|
|
|
|
|
wl_list_for_each(input, &seat->inputs, link) {
|
|
|
|
|
switch (input->wlr_input_device->type) {
|
2024-01-13 00:25:45 +01:00
|
|
|
case WLR_INPUT_DEVICE_TOUCH:
|
|
|
|
|
map_touch_to_output(seat, input->wlr_input_device);
|
|
|
|
|
break;
|
2024-01-09 06:58:35 +01:00
|
|
|
case WLR_INPUT_DEVICE_TABLET_TOOL:
|
|
|
|
|
map_input_to_output(seat, input->wlr_input_device, rc.tablet.output_name);
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|