diff options
Diffstat (limited to 'rootston/keyboard.c')
-rw-r--r-- | rootston/keyboard.c | 349 |
1 files changed, 0 insertions, 349 deletions
diff --git a/rootston/keyboard.c b/rootston/keyboard.c deleted file mode 100644 index da88e914..00000000 --- a/rootston/keyboard.c +++ /dev/null @@ -1,349 +0,0 @@ -#include <assert.h> -#include <stdbool.h> -#include <stdint.h> -#include <stdlib.h> -#include <wayland-server-core.h> -#include <wlr/backend/session.h> -#include <wlr/types/wlr_input_device.h> -#include <wlr/types/wlr_pointer_constraints_v1.h> -#include <wlr/types/wlr_pointer.h> -#include <wlr/util/log.h> -#include <xkbcommon/xkbcommon.h> -#include "rootston/bindings.h" -#include "rootston/input.h" -#include "rootston/keyboard.h" -#include "rootston/seat.h" - -static ssize_t pressed_keysyms_index(xkb_keysym_t *pressed_keysyms, - xkb_keysym_t keysym) { - for (size_t i = 0; i < ROOTS_KEYBOARD_PRESSED_KEYSYMS_CAP; ++i) { - if (pressed_keysyms[i] == keysym) { - return i; - } - } - return -1; -} - -static size_t pressed_keysyms_length(xkb_keysym_t *pressed_keysyms) { - size_t n = 0; - for (size_t i = 0; i < ROOTS_KEYBOARD_PRESSED_KEYSYMS_CAP; ++i) { - if (pressed_keysyms[i] != XKB_KEY_NoSymbol) { - ++n; - } - } - return n; -} - -static void pressed_keysyms_add(xkb_keysym_t *pressed_keysyms, - xkb_keysym_t keysym) { - ssize_t i = pressed_keysyms_index(pressed_keysyms, keysym); - if (i < 0) { - i = pressed_keysyms_index(pressed_keysyms, XKB_KEY_NoSymbol); - if (i >= 0) { - pressed_keysyms[i] = keysym; - } - } -} - -static void pressed_keysyms_remove(xkb_keysym_t *pressed_keysyms, - xkb_keysym_t keysym) { - ssize_t i = pressed_keysyms_index(pressed_keysyms, keysym); - if (i >= 0) { - pressed_keysyms[i] = XKB_KEY_NoSymbol; - } -} - -static bool keysym_is_modifier(xkb_keysym_t keysym) { - switch (keysym) { - case XKB_KEY_Shift_L: case XKB_KEY_Shift_R: - case XKB_KEY_Control_L: case XKB_KEY_Control_R: - case XKB_KEY_Caps_Lock: - case XKB_KEY_Shift_Lock: - case XKB_KEY_Meta_L: case XKB_KEY_Meta_R: - case XKB_KEY_Alt_L: case XKB_KEY_Alt_R: - case XKB_KEY_Super_L: case XKB_KEY_Super_R: - case XKB_KEY_Hyper_L: case XKB_KEY_Hyper_R: - return true; - default: - return false; - } -} - -static void pressed_keysyms_update(xkb_keysym_t *pressed_keysyms, - const xkb_keysym_t *keysyms, size_t keysyms_len, - enum wlr_key_state state) { - for (size_t i = 0; i < keysyms_len; ++i) { - if (keysym_is_modifier(keysyms[i])) { - continue; - } - if (state == WLR_KEY_PRESSED) { - pressed_keysyms_add(pressed_keysyms, keysyms[i]); - } else { // WLR_KEY_RELEASED - pressed_keysyms_remove(pressed_keysyms, keysyms[i]); - } - } -} - -static void keyboard_binding_execute(struct roots_keyboard *keyboard, - const char *command) { - execute_binding_command(keyboard->seat, keyboard->input, command); -} - -/** - * Execute a built-in, hardcoded compositor binding. These are triggered from a - * single keysym. - * - * Returns true if the keysym was handled by a binding and false if the event - * should be propagated to clients. - */ -static bool keyboard_execute_compositor_binding(struct roots_keyboard *keyboard, - xkb_keysym_t keysym) { - if (keysym >= XKB_KEY_XF86Switch_VT_1 && - keysym <= XKB_KEY_XF86Switch_VT_12) { - struct roots_server *server = keyboard->input->server; - - struct wlr_session *session = wlr_backend_get_session(server->backend); - if (session) { - unsigned vt = keysym - XKB_KEY_XF86Switch_VT_1 + 1; - wlr_session_change_vt(session, vt); - } - - return true; - } - - if (keysym == XKB_KEY_Escape) { - wlr_seat_pointer_end_grab(keyboard->seat->seat); - wlr_seat_keyboard_end_grab(keyboard->seat->seat); - roots_seat_end_compositor_grab(keyboard->seat); - } - - return false; -} - -/** - * Execute keyboard bindings. These include compositor bindings and user-defined - * bindings. - * - * Returns true if the keysym was handled by a binding and false if the event - * should be propagated to clients. - */ -static bool keyboard_execute_binding(struct roots_keyboard *keyboard, - xkb_keysym_t *pressed_keysyms, uint32_t modifiers, - const xkb_keysym_t *keysyms, size_t keysyms_len) { - for (size_t i = 0; i < keysyms_len; ++i) { - if (keyboard_execute_compositor_binding(keyboard, keysyms[i])) { - return true; - } - } - - // User-defined bindings - size_t n = pressed_keysyms_length(pressed_keysyms); - struct wl_list *bindings = &keyboard->input->server->config->bindings; - struct roots_binding_config *bc; - wl_list_for_each(bc, bindings, link) { - if (modifiers ^ bc->modifiers || n != bc->keysyms_len) { - continue; - } - - bool ok = true; - for (size_t i = 0; i < bc->keysyms_len; i++) { - ssize_t j = pressed_keysyms_index(pressed_keysyms, bc->keysyms[i]); - if (j < 0) { - ok = false; - break; - } - } - - if (ok) { - keyboard_binding_execute(keyboard, bc->command); - return true; - } - } - - return false; -} - -/* - * Get keysyms and modifiers from the keyboard as xkb sees them. - * - * This uses the xkb keysyms translation based on pressed modifiers and clears - * the consumed modifiers from the list of modifiers passed to keybind - * detection. - * - * On US layout, pressing Alt+Shift+2 will trigger Alt+@. - */ -static size_t keyboard_keysyms_translated(struct roots_keyboard *keyboard, - xkb_keycode_t keycode, const xkb_keysym_t **keysyms, - uint32_t *modifiers) { - *modifiers = wlr_keyboard_get_modifiers(keyboard->device->keyboard); - xkb_mod_mask_t consumed = xkb_state_key_get_consumed_mods2( - keyboard->device->keyboard->xkb_state, keycode, XKB_CONSUMED_MODE_XKB); - *modifiers = *modifiers & ~consumed; - - return xkb_state_key_get_syms(keyboard->device->keyboard->xkb_state, - keycode, keysyms); -} - -/* - * Get keysyms and modifiers from the keyboard as if modifiers didn't change - * keysyms. - * - * This avoids the xkb keysym translation based on modifiers considered pressed - * in the state. - * - * This will trigger keybinds such as Alt+Shift+2. - */ -static size_t keyboard_keysyms_raw(struct roots_keyboard *keyboard, - xkb_keycode_t keycode, const xkb_keysym_t **keysyms, - uint32_t *modifiers) { - *modifiers = wlr_keyboard_get_modifiers(keyboard->device->keyboard); - - xkb_layout_index_t layout_index = xkb_state_key_get_layout( - keyboard->device->keyboard->xkb_state, keycode); - return xkb_keymap_key_get_syms_by_level(keyboard->device->keyboard->keymap, - keycode, layout_index, 0, keysyms); -} - -void roots_keyboard_handle_key(struct roots_keyboard *keyboard, - struct wlr_event_keyboard_key *event) { - xkb_keycode_t keycode = event->keycode + 8; - - bool handled = false; - uint32_t modifiers; - const xkb_keysym_t *keysyms; - size_t keysyms_len; - - // Handle translated keysyms - - keysyms_len = keyboard_keysyms_translated(keyboard, keycode, &keysyms, - &modifiers); - pressed_keysyms_update(keyboard->pressed_keysyms_translated, keysyms, - keysyms_len, event->state); - if (event->state == WLR_KEY_PRESSED) { - handled = keyboard_execute_binding(keyboard, - keyboard->pressed_keysyms_translated, modifiers, keysyms, - keysyms_len); - } - - // Handle raw keysyms - keysyms_len = keyboard_keysyms_raw(keyboard, keycode, &keysyms, &modifiers); - pressed_keysyms_update(keyboard->pressed_keysyms_raw, keysyms, keysyms_len, - event->state); - if (event->state == WLR_KEY_PRESSED && !handled) { - handled = keyboard_execute_binding(keyboard, - keyboard->pressed_keysyms_raw, modifiers, keysyms, keysyms_len); - } - - if (!handled) { - wlr_seat_set_keyboard(keyboard->seat->seat, keyboard->device); - wlr_seat_keyboard_notify_key(keyboard->seat->seat, event->time_msec, - event->keycode, event->state); - } -} - -void roots_keyboard_handle_modifiers(struct roots_keyboard *r_keyboard) { - struct wlr_seat *seat = r_keyboard->seat->seat; - wlr_seat_set_keyboard(seat, r_keyboard->device); - wlr_seat_keyboard_notify_modifiers(seat, - &r_keyboard->device->keyboard->modifiers); -} - -static void keyboard_config_merge(struct roots_keyboard_config *config, - struct roots_keyboard_config *fallback) { - if (fallback == NULL) { - return; - } - if (config->rules == NULL) { - config->rules = fallback->rules; - } - if (config->model == NULL) { - config->model = fallback->model; - } - if (config->layout == NULL) { - config->layout = fallback->layout; - } - if (config->variant == NULL) { - config->variant = fallback->variant; - } - if (config->options == NULL) { - config->options = fallback->options; - } - if (config->meta_key == 0) { - config->meta_key = fallback->meta_key; - } - if (config->name == NULL) { - config->name = fallback->name; - } - if (config->repeat_rate <= 0) { - config->repeat_rate = fallback->repeat_rate; - } - if (config->repeat_delay <= 0) { - config->repeat_delay = fallback->repeat_delay; - } -} - -struct roots_keyboard *roots_keyboard_create(struct wlr_input_device *device, - struct roots_input *input) { - struct roots_keyboard *keyboard = calloc(sizeof(struct roots_keyboard), 1); - if (keyboard == NULL) { - return NULL; - } - device->data = keyboard; - keyboard->device = device; - keyboard->input = input; - - struct roots_keyboard_config *config = - calloc(1, sizeof(struct roots_keyboard_config)); - if (config == NULL) { - free(keyboard); - return NULL; - } - keyboard_config_merge(config, roots_config_get_keyboard(input->config, device)); - keyboard_config_merge(config, roots_config_get_keyboard(input->config, NULL)); - - struct roots_keyboard_config env_config = { - .rules = getenv("XKB_DEFAULT_RULES"), - .model = getenv("XKB_DEFAULT_MODEL"), - .layout = getenv("XKB_DEFAULT_LAYOUT"), - .variant = getenv("XKB_DEFAULT_VARIANT"), - .options = getenv("XKB_DEFAULT_OPTIONS"), - }; - keyboard_config_merge(config, &env_config); - keyboard->config = config; - - struct xkb_rule_names rules = { 0 }; - rules.rules = config->rules; - rules.model = config->model; - rules.layout = config->layout; - rules.variant = config->variant; - rules.options = config->options; - struct xkb_context *context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); - if (context == NULL) { - wlr_log(WLR_ERROR, "Cannot create XKB context"); - return NULL; - } - - struct xkb_keymap *keymap = xkb_map_new_from_names(context, &rules, - XKB_KEYMAP_COMPILE_NO_FLAGS); - if (keymap == NULL) { - xkb_context_unref(context); - wlr_log(WLR_ERROR, "Cannot create XKB keymap"); - return NULL; - } - - wlr_keyboard_set_keymap(device->keyboard, keymap); - xkb_keymap_unref(keymap); - xkb_context_unref(context); - - int repeat_rate = (config->repeat_rate > 0) ? config->repeat_rate : 25; - int repeat_delay = (config->repeat_delay > 0) ? config->repeat_delay : 600; - wlr_keyboard_set_repeat_info(device->keyboard, repeat_rate, repeat_delay); - - return keyboard; -} - -void roots_keyboard_destroy(struct roots_keyboard *keyboard) { - wl_list_remove(&keyboard->link); - free(keyboard->config); - free(keyboard); -} |