use wlr_keyboard_group to manage all keyboards
This commit is contained in:
parent
fa660fb61e
commit
023efce6eb
145
dwl.c
145
dwl.c
@ -28,6 +28,7 @@
|
|||||||
#include <wlr/types/wlr_idle_notify_v1.h>
|
#include <wlr/types/wlr_idle_notify_v1.h>
|
||||||
#include <wlr/types/wlr_input_device.h>
|
#include <wlr/types/wlr_input_device.h>
|
||||||
#include <wlr/types/wlr_keyboard.h>
|
#include <wlr/types/wlr_keyboard.h>
|
||||||
|
#include <wlr/types/wlr_keyboard_group.h>
|
||||||
#include <wlr/types/wlr_layer_shell_v1.h>
|
#include <wlr/types/wlr_layer_shell_v1.h>
|
||||||
#include <wlr/types/wlr_linux_dmabuf_v1.h>
|
#include <wlr/types/wlr_linux_dmabuf_v1.h>
|
||||||
#include <wlr/types/wlr_output.h>
|
#include <wlr/types/wlr_output.h>
|
||||||
@ -141,7 +142,7 @@ typedef struct {
|
|||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
struct wl_list link;
|
struct wl_list link;
|
||||||
struct wlr_keyboard *wlr_keyboard;
|
struct wlr_keyboard_group *wlr_group;
|
||||||
|
|
||||||
int nsyms;
|
int nsyms;
|
||||||
const xkb_keysym_t *keysyms; /* invalid if nsyms == 0 */
|
const xkb_keysym_t *keysyms; /* invalid if nsyms == 0 */
|
||||||
@ -150,8 +151,7 @@ typedef struct {
|
|||||||
|
|
||||||
struct wl_listener modifiers;
|
struct wl_listener modifiers;
|
||||||
struct wl_listener key;
|
struct wl_listener key;
|
||||||
struct wl_listener destroy;
|
} KeyboardGroup;
|
||||||
} Keyboard;
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
/* Must keep these three elements in this order */
|
/* Must keep these three elements in this order */
|
||||||
@ -238,7 +238,6 @@ static void buttonpress(struct wl_listener *listener, void *data);
|
|||||||
static void chvt(const Arg *arg);
|
static void chvt(const Arg *arg);
|
||||||
static void checkidleinhibitor(struct wlr_surface *exclude);
|
static void checkidleinhibitor(struct wlr_surface *exclude);
|
||||||
static void cleanup(void);
|
static void cleanup(void);
|
||||||
static void cleanupkeyboard(struct wl_listener *listener, void *data);
|
|
||||||
static void cleanupmon(struct wl_listener *listener, void *data);
|
static void cleanupmon(struct wl_listener *listener, void *data);
|
||||||
static void closemon(Monitor *m);
|
static void closemon(Monitor *m);
|
||||||
static void commitlayersurfacenotify(struct wl_listener *listener, void *data);
|
static void commitlayersurfacenotify(struct wl_listener *listener, void *data);
|
||||||
@ -368,7 +367,7 @@ static struct wlr_session_lock_v1 *cur_lock;
|
|||||||
static struct wl_listener lock_listener = {.notify = locksession};
|
static struct wl_listener lock_listener = {.notify = locksession};
|
||||||
|
|
||||||
static struct wlr_seat *seat;
|
static struct wlr_seat *seat;
|
||||||
static struct wl_list keyboards;
|
static KeyboardGroup kb_group;
|
||||||
static struct wlr_surface *held_grab;
|
static struct wlr_surface *held_grab;
|
||||||
static unsigned int cursor_mode;
|
static unsigned int cursor_mode;
|
||||||
static Client *grabc;
|
static Client *grabc;
|
||||||
@ -636,25 +635,16 @@ cleanup(void)
|
|||||||
}
|
}
|
||||||
wlr_xcursor_manager_destroy(cursor_mgr);
|
wlr_xcursor_manager_destroy(cursor_mgr);
|
||||||
wlr_output_layout_destroy(output_layout);
|
wlr_output_layout_destroy(output_layout);
|
||||||
|
|
||||||
|
/* Remove event source that use the dpy event loop before destroying dpy */
|
||||||
|
wl_event_source_remove(kb_group.key_repeat_source);
|
||||||
|
|
||||||
wl_display_destroy(dpy);
|
wl_display_destroy(dpy);
|
||||||
/* Destroy after the wayland display (when the monitors are already destroyed)
|
/* Destroy after the wayland display (when the monitors are already destroyed)
|
||||||
to avoid destroying them with an invalid scene output. */
|
to avoid destroying them with an invalid scene output. */
|
||||||
wlr_scene_node_destroy(&scene->tree.node);
|
wlr_scene_node_destroy(&scene->tree.node);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
cleanupkeyboard(struct wl_listener *listener, void *data)
|
|
||||||
{
|
|
||||||
Keyboard *kb = wl_container_of(listener, kb, destroy);
|
|
||||||
|
|
||||||
wl_event_source_remove(kb->key_repeat_source);
|
|
||||||
wl_list_remove(&kb->link);
|
|
||||||
wl_list_remove(&kb->modifiers.link);
|
|
||||||
wl_list_remove(&kb->key.link);
|
|
||||||
wl_list_remove(&kb->destroy.link);
|
|
||||||
free(kb);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
cleanupmon(struct wl_listener *listener, void *data)
|
cleanupmon(struct wl_listener *listener, void *data)
|
||||||
{
|
{
|
||||||
@ -761,35 +751,12 @@ createidleinhibitor(struct wl_listener *listener, void *data)
|
|||||||
void
|
void
|
||||||
createkeyboard(struct wlr_keyboard *keyboard)
|
createkeyboard(struct wlr_keyboard *keyboard)
|
||||||
{
|
{
|
||||||
struct xkb_context *context;
|
/* Set the keymap to match the group keymap */
|
||||||
struct xkb_keymap *keymap;
|
wlr_keyboard_set_keymap(keyboard, kb_group.wlr_group->keyboard.keymap);
|
||||||
Keyboard *kb = keyboard->data = ecalloc(1, sizeof(*kb));
|
|
||||||
kb->wlr_keyboard = keyboard;
|
|
||||||
|
|
||||||
/* Prepare an XKB keymap and assign it to the keyboard. */
|
|
||||||
context = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
|
|
||||||
keymap = xkb_keymap_new_from_names(context, &xkb_rules,
|
|
||||||
XKB_KEYMAP_COMPILE_NO_FLAGS);
|
|
||||||
if (!keymap)
|
|
||||||
die("createkeyboard: failed to compile keymap");
|
|
||||||
|
|
||||||
wlr_keyboard_set_keymap(keyboard, keymap);
|
|
||||||
xkb_keymap_unref(keymap);
|
|
||||||
xkb_context_unref(context);
|
|
||||||
wlr_keyboard_set_repeat_info(keyboard, repeat_rate, repeat_delay);
|
wlr_keyboard_set_repeat_info(keyboard, repeat_rate, repeat_delay);
|
||||||
|
|
||||||
/* Here we set up listeners for keyboard events. */
|
/* Add the new keyboard to the group */
|
||||||
LISTEN(&keyboard->events.modifiers, &kb->modifiers, keypressmod);
|
wlr_keyboard_group_add_keyboard(kb_group.wlr_group, keyboard);
|
||||||
LISTEN(&keyboard->events.key, &kb->key, keypress);
|
|
||||||
LISTEN(&keyboard->base.events.destroy, &kb->destroy, cleanupkeyboard);
|
|
||||||
|
|
||||||
wlr_seat_set_keyboard(seat, keyboard);
|
|
||||||
|
|
||||||
kb->key_repeat_source = wl_event_loop_add_timer(
|
|
||||||
wl_display_get_event_loop(dpy), keyrepeat, kb);
|
|
||||||
|
|
||||||
/* And add the keyboard to our list of keyboards */
|
|
||||||
wl_list_insert(&keyboards, &kb->link);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -1353,7 +1320,7 @@ inputdevice(struct wl_listener *listener, void *data)
|
|||||||
* there are no pointer devices, so we always include that capability. */
|
* there are no pointer devices, so we always include that capability. */
|
||||||
/* TODO do we actually require a cursor? */
|
/* TODO do we actually require a cursor? */
|
||||||
caps = WL_SEAT_CAPABILITY_POINTER;
|
caps = WL_SEAT_CAPABILITY_POINTER;
|
||||||
if (!wl_list_empty(&keyboards))
|
if (!wl_list_empty(&kb_group.wlr_group->devices))
|
||||||
caps |= WL_SEAT_CAPABILITY_KEYBOARD;
|
caps |= WL_SEAT_CAPABILITY_KEYBOARD;
|
||||||
wlr_seat_set_capabilities(seat, caps);
|
wlr_seat_set_capabilities(seat, caps);
|
||||||
}
|
}
|
||||||
@ -1383,7 +1350,7 @@ keypress(struct wl_listener *listener, void *data)
|
|||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
/* This event is raised when a key is pressed or released. */
|
/* This event is raised when a key is pressed or released. */
|
||||||
Keyboard *kb = wl_container_of(listener, kb, key);
|
KeyboardGroup *group = wl_container_of(listener, group, key);
|
||||||
struct wlr_keyboard_key_event *event = data;
|
struct wlr_keyboard_key_event *event = data;
|
||||||
|
|
||||||
/* Translate libinput keycode -> xkbcommon */
|
/* Translate libinput keycode -> xkbcommon */
|
||||||
@ -1391,10 +1358,10 @@ keypress(struct wl_listener *listener, void *data)
|
|||||||
/* Get a list of keysyms based on the keymap for this keyboard */
|
/* Get a list of keysyms based on the keymap for this keyboard */
|
||||||
const xkb_keysym_t *syms;
|
const xkb_keysym_t *syms;
|
||||||
int nsyms = xkb_state_key_get_syms(
|
int nsyms = xkb_state_key_get_syms(
|
||||||
kb->wlr_keyboard->xkb_state, keycode, &syms);
|
group->wlr_group->keyboard.xkb_state, keycode, &syms);
|
||||||
|
|
||||||
int handled = 0;
|
int handled = 0;
|
||||||
uint32_t mods = wlr_keyboard_get_modifiers(kb->wlr_keyboard);
|
uint32_t mods = wlr_keyboard_get_modifiers(&group->wlr_group->keyboard);
|
||||||
|
|
||||||
wlr_idle_notifier_v1_notify_activity(idle_notifier, seat);
|
wlr_idle_notifier_v1_notify_activity(idle_notifier, seat);
|
||||||
|
|
||||||
@ -1404,22 +1371,21 @@ keypress(struct wl_listener *listener, void *data)
|
|||||||
for (i = 0; i < nsyms; i++)
|
for (i = 0; i < nsyms; i++)
|
||||||
handled = keybinding(mods, syms[i]) || handled;
|
handled = keybinding(mods, syms[i]) || handled;
|
||||||
|
|
||||||
if (handled && kb->wlr_keyboard->repeat_info.delay > 0) {
|
if (handled && group->wlr_group->keyboard.repeat_info.delay > 0) {
|
||||||
kb->mods = mods;
|
group->mods = mods;
|
||||||
kb->keysyms = syms;
|
group->keysyms = syms;
|
||||||
kb->nsyms = nsyms;
|
group->nsyms = nsyms;
|
||||||
wl_event_source_timer_update(kb->key_repeat_source,
|
wl_event_source_timer_update(group->key_repeat_source,
|
||||||
kb->wlr_keyboard->repeat_info.delay);
|
group->wlr_group->keyboard.repeat_info.delay);
|
||||||
} else {
|
} else {
|
||||||
kb->nsyms = 0;
|
group->nsyms = 0;
|
||||||
wl_event_source_timer_update(kb->key_repeat_source, 0);
|
wl_event_source_timer_update(group->key_repeat_source, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (handled)
|
if (handled)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* Pass unhandled keycodes along to the client. */
|
/* Pass unhandled keycodes along to the client. */
|
||||||
wlr_seat_set_keyboard(seat, kb->wlr_keyboard);
|
|
||||||
wlr_seat_keyboard_notify_key(seat, event->time_msec,
|
wlr_seat_keyboard_notify_key(seat, event->time_msec,
|
||||||
event->keycode, event->state);
|
event->keycode, event->state);
|
||||||
}
|
}
|
||||||
@ -1429,32 +1395,26 @@ keypressmod(struct wl_listener *listener, void *data)
|
|||||||
{
|
{
|
||||||
/* This event is raised when a modifier key, such as shift or alt, is
|
/* This event is raised when a modifier key, such as shift or alt, is
|
||||||
* pressed. We simply communicate this to the client. */
|
* pressed. We simply communicate this to the client. */
|
||||||
Keyboard *kb = wl_container_of(listener, kb, modifiers);
|
KeyboardGroup *group = wl_container_of(listener, group, modifiers);
|
||||||
/*
|
|
||||||
* A seat can only have one keyboard, but this is a limitation of the
|
|
||||||
* Wayland protocol - not wlroots. We assign all connected keyboards to the
|
|
||||||
* same seat. You can swap out the underlying wlr_keyboard like this and
|
|
||||||
* wlr_seat handles this transparently.
|
|
||||||
*/
|
|
||||||
wlr_seat_set_keyboard(seat, kb->wlr_keyboard);
|
|
||||||
/* Send modifiers to the client. */
|
/* Send modifiers to the client. */
|
||||||
wlr_seat_keyboard_notify_modifiers(seat,
|
wlr_seat_keyboard_notify_modifiers(seat,
|
||||||
&kb->wlr_keyboard->modifiers);
|
&group->wlr_group->keyboard.modifiers);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
keyrepeat(void *data)
|
keyrepeat(void *data)
|
||||||
{
|
{
|
||||||
Keyboard *kb = data;
|
KeyboardGroup *group = data;
|
||||||
int i;
|
int i;
|
||||||
if (!kb->nsyms || kb->wlr_keyboard->repeat_info.rate <= 0)
|
if (!group->nsyms || group->wlr_group->keyboard.repeat_info.rate <= 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
wl_event_source_timer_update(kb->key_repeat_source,
|
wl_event_source_timer_update(group->key_repeat_source,
|
||||||
1000 / kb->wlr_keyboard->repeat_info.rate);
|
1000 / group->wlr_group->keyboard.repeat_info.rate);
|
||||||
|
|
||||||
for (i = 0; i < kb->nsyms; i++)
|
for (i = 0; i < group->nsyms; i++)
|
||||||
keybinding(kb->mods, kb->keysyms[i]);
|
keybinding(group->mods, group->keysyms[i]);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -2160,6 +2120,9 @@ setsel(struct wl_listener *listener, void *data)
|
|||||||
void
|
void
|
||||||
setup(void)
|
setup(void)
|
||||||
{
|
{
|
||||||
|
struct xkb_context *context;
|
||||||
|
struct xkb_keymap *keymap;
|
||||||
|
|
||||||
int i, sig[] = {SIGCHLD, SIGINT, SIGTERM, SIGPIPE};
|
int i, sig[] = {SIGCHLD, SIGINT, SIGTERM, SIGPIPE};
|
||||||
struct sigaction sa = {.sa_flags = SA_RESTART, .sa_handler = handlesig};
|
struct sigaction sa = {.sa_flags = SA_RESTART, .sa_handler = handlesig};
|
||||||
sigemptyset(&sa.sa_mask);
|
sigemptyset(&sa.sa_mask);
|
||||||
@ -2323,7 +2286,6 @@ setup(void)
|
|||||||
* pointer, touch, and drawing tablet device. We also rig up a listener to
|
* pointer, touch, and drawing tablet device. We also rig up a listener to
|
||||||
* let us know when new input devices are available on the backend.
|
* let us know when new input devices are available on the backend.
|
||||||
*/
|
*/
|
||||||
wl_list_init(&keyboards);
|
|
||||||
LISTEN_STATIC(&backend->events.new_input, inputdevice);
|
LISTEN_STATIC(&backend->events.new_input, inputdevice);
|
||||||
virtual_keyboard_mgr = wlr_virtual_keyboard_manager_v1_create(dpy);
|
virtual_keyboard_mgr = wlr_virtual_keyboard_manager_v1_create(dpy);
|
||||||
LISTEN_STATIC(&virtual_keyboard_mgr->events.new_virtual_keyboard, virtualkeyboard);
|
LISTEN_STATIC(&virtual_keyboard_mgr->events.new_virtual_keyboard, virtualkeyboard);
|
||||||
@ -2334,6 +2296,41 @@ setup(void)
|
|||||||
LISTEN_STATIC(&seat->events.request_start_drag, requeststartdrag);
|
LISTEN_STATIC(&seat->events.request_start_drag, requeststartdrag);
|
||||||
LISTEN_STATIC(&seat->events.start_drag, startdrag);
|
LISTEN_STATIC(&seat->events.start_drag, startdrag);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Configures a keyboard group, which will keep track of all connected
|
||||||
|
* keyboards, keep their modifier and LED states in sync, and handle
|
||||||
|
* keypresses
|
||||||
|
*/
|
||||||
|
kb_group.wlr_group = wlr_keyboard_group_create();
|
||||||
|
kb_group.wlr_group->data = &kb_group;
|
||||||
|
|
||||||
|
/* Prepare an XKB keymap and assign it to the keyboard group. */
|
||||||
|
context = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
|
||||||
|
keymap = xkb_keymap_new_from_names(context, &xkb_rules,
|
||||||
|
XKB_KEYMAP_COMPILE_NO_FLAGS);
|
||||||
|
if (!keymap)
|
||||||
|
die("failed to compile keymap");
|
||||||
|
|
||||||
|
wlr_keyboard_set_keymap(&kb_group.wlr_group->keyboard, keymap);
|
||||||
|
xkb_keymap_unref(keymap);
|
||||||
|
xkb_context_unref(context);
|
||||||
|
|
||||||
|
wlr_keyboard_set_repeat_info(&kb_group.wlr_group->keyboard, repeat_rate, repeat_delay);
|
||||||
|
|
||||||
|
/* Set up listeners for keyboard events */
|
||||||
|
LISTEN(&kb_group.wlr_group->keyboard.events.key, &kb_group.key, keypress);
|
||||||
|
LISTEN(&kb_group.wlr_group->keyboard.events.modifiers, &kb_group.modifiers, keypressmod);
|
||||||
|
|
||||||
|
kb_group.key_repeat_source = wl_event_loop_add_timer(
|
||||||
|
wl_display_get_event_loop(dpy), keyrepeat, &kb_group);
|
||||||
|
|
||||||
|
/* A seat can only have one keyboard, but this is a limitation of the
|
||||||
|
* Wayland protocol - not wlroots. We assign all connected keyboards to the
|
||||||
|
* same wlr_keyboard_group, which provides a single wlr_keyboard interface for
|
||||||
|
* all of them. Set this combined wlr_keyboard as the seat keyboard.
|
||||||
|
*/
|
||||||
|
wlr_seat_set_keyboard(seat, &kb_group.wlr_group->keyboard);
|
||||||
|
|
||||||
output_mgr = wlr_output_manager_v1_create(dpy);
|
output_mgr = wlr_output_manager_v1_create(dpy);
|
||||||
LISTEN_STATIC(&output_mgr->events.apply, outputmgrapply);
|
LISTEN_STATIC(&output_mgr->events.apply, outputmgrapply);
|
||||||
LISTEN_STATIC(&output_mgr->events.test, outputmgrtest);
|
LISTEN_STATIC(&output_mgr->events.test, outputmgrtest);
|
||||||
|
Loading…
Reference in New Issue
Block a user