From 754372c3de1f5b357850cb58cc8ddc1aee596bd6 Mon Sep 17 00:00:00 2001 From: frsfnrrg Date: Tue, 17 Jul 2018 22:01:06 -0400 Subject: Parse mouse binding options First, the existing sway_binding structure is given an enumerated type code. As all flags to bindsym/bindcode are boolean, a single uint32 is used to hold all flags. The _BORDER, _CONTENTS, _TITLEBAR flags, when active, indicate in which part of a container the binding can trigger; to localize complexity, they do not overlap with the command line arguments, which center around _TITLEBAR being set by default. The keyboard handling code is adjusted for this change, as is binding_key_compare; note that BINDING_LOCKED is *not* part of the key portion of the binding. Next, list of mouse bindings is introduced and cleaned up. Finally, the binding command parsing code is extended to handle the case where bindsym is used to describe a mouse binding rather than a keysym binding; the difference between the two may be detected as late as when the first key/button is parsed, or as early as the first flag. As bindings can have multiple keycodes/keysyms/buttons, mixed keysym/button sequences are prohibited. --- sway/input/keyboard.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'sway/input/keyboard.c') diff --git a/sway/input/keyboard.c b/sway/input/keyboard.c index ede38519..e6c5c335 100644 --- a/sway/input/keyboard.c +++ b/sway/input/keyboard.c @@ -88,11 +88,13 @@ static void get_active_binding(const struct sway_shortcut_state *state, uint32_t modifiers, bool release, bool locked) { for (int i = 0; i < bindings->length; ++i) { struct sway_binding *binding = bindings->items[i]; + bool binding_locked = binding->flags | BINDING_LOCKED; + bool binding_release = binding->flags | BINDING_RELEASE; if (modifiers ^ binding->modifiers || state->npressed != (size_t)binding->keys->length || - locked > binding->locked || - release != binding->release) { + release != binding_release || + locked > binding_locked) { continue; } -- cgit v1.2.3 From 94dd8823a0081f7983dce368d5d093d1d3eeaefe Mon Sep 17 00:00:00 2001 From: frsfnrrg Date: Mon, 23 Jul 2018 21:38:29 -0400 Subject: Invoke mouse bindings The mouse binding logic is inspired/copied from the keyboard binding logic; we store a sorted list of the currently pressed buttons, and trigger a binding when the currently pressed (or just recently pressed, in the case of a release binding) buttons, as well as modifiers/container region, match those of a given binding. As the code to execute a binding is not very keyboard specific, keyboard_execute_command is renamed to seat_execute_command and moved to where the other binding handling functions are. The call to transaction_commit_dirty has been lifted out. --- sway/input/keyboard.c | 40 +++++++++++++--------------------------- 1 file changed, 13 insertions(+), 27 deletions(-) (limited to 'sway/input/keyboard.c') diff --git a/sway/input/keyboard.c b/sway/input/keyboard.c index e6c5c335..49241db8 100644 --- a/sway/input/keyboard.c +++ b/sway/input/keyboard.c @@ -3,11 +3,11 @@ #include #include #include +#include "sway/commands.h" #include "sway/desktop/transaction.h" -#include "sway/input/seat.h" -#include "sway/input/keyboard.h" #include "sway/input/input-manager.h" -#include "sway/commands.h" +#include "sway/input/keyboard.h" +#include "sway/input/seat.h" #include "log.h" /** @@ -88,8 +88,8 @@ static void get_active_binding(const struct sway_shortcut_state *state, uint32_t modifiers, bool release, bool locked) { for (int i = 0; i < bindings->length; ++i) { struct sway_binding *binding = bindings->items[i]; - bool binding_locked = binding->flags | BINDING_LOCKED; - bool binding_release = binding->flags | BINDING_RELEASE; + bool binding_locked = binding->flags & BINDING_LOCKED; + bool binding_release = binding->flags & BINDING_RELEASE; if (modifiers ^ binding->modifiers || state->npressed != (size_t)binding->keys->length || @@ -120,23 +120,6 @@ static void get_active_binding(const struct sway_shortcut_state *state, } } -/** - * Execute the command associated to a binding - */ -static void keyboard_execute_command(struct sway_keyboard *keyboard, - struct sway_binding *binding) { - wlr_log(WLR_DEBUG, "running command for binding: %s", - binding->command); - config->handler_context.seat = keyboard->seat_device->sway_seat; - struct cmd_results *results = execute_command(binding->command, NULL); - transaction_commit_dirty(); - if (results->status != CMD_SUCCESS) { - wlr_log(WLR_DEBUG, "could not run command for binding: %s (%s)", - binding->command, results->error); - } - free_cmd_results(results); -} - /** * Execute a built-in, hardcoded compositor binding. These are triggered from a * single keysym. @@ -213,12 +196,13 @@ static size_t keyboard_keysyms_raw(struct sway_keyboard *keyboard, static void handle_keyboard_key(struct wl_listener *listener, void *data) { struct sway_keyboard *keyboard = wl_container_of(listener, keyboard, keyboard_key); - struct wlr_seat *wlr_seat = keyboard->seat_device->sway_seat->wlr_seat; + struct sway_seat* seat = keyboard->seat_device->sway_seat; + struct wlr_seat *wlr_seat = seat->wlr_seat; struct wlr_input_device *wlr_device = keyboard->seat_device->input_device->wlr_device; - wlr_idle_notify_activity(keyboard->seat_device->sway_seat->input->server->idle, wlr_seat); + wlr_idle_notify_activity(seat->input->server->idle, wlr_seat); struct wlr_event_keyboard_key *event = data; - bool input_inhibited = keyboard->seat_device->sway_seat->exclusive_client != NULL; + bool input_inhibited = seat->exclusive_client != NULL; // Identify new keycode, raw keysym(s), and translated keysym(s) xkb_keycode_t keycode = event->keycode + 8; @@ -268,7 +252,7 @@ static void handle_keyboard_key(struct wl_listener *listener, void *data) { // Execute stored release binding once no longer active if (keyboard->held_binding && binding_released != keyboard->held_binding && event->state == WLR_KEY_RELEASED) { - keyboard_execute_command(keyboard, keyboard->held_binding); + seat_execute_command(seat, keyboard->held_binding); handled = true; } if (binding_released != keyboard->held_binding) { @@ -292,7 +276,7 @@ static void handle_keyboard_key(struct wl_listener *listener, void *data) { raw_modifiers, false, input_inhibited); if (binding_pressed) { - keyboard_execute_command(keyboard, binding_pressed); + seat_execute_command(seat, binding_pressed); handled = true; } } @@ -314,6 +298,8 @@ static void handle_keyboard_key(struct wl_listener *listener, void *data) { wlr_seat_keyboard_notify_key(wlr_seat, event->time_msec, event->keycode, event->state); } + + transaction_commit_dirty(); } static void handle_keyboard_modifiers(struct wl_listener *listener, -- cgit v1.2.3 From 2166dbe2e49fc5eeb345d744424db360ee63f508 Mon Sep 17 00:00:00 2001 From: ProgAndy Date: Sun, 22 Jul 2018 21:16:19 +0200 Subject: Implement setting NumLock and CapsLock status After setting the keymap, try to enable NumLock and disable CapsLock. This only works if sway has the xkb master state and controls the keyboard. Prepare configuration settings for later use as well. --- sway/input/keyboard.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'sway/input/keyboard.c') diff --git a/sway/input/keyboard.c b/sway/input/keyboard.c index 49241db8..36c5a064 100644 --- a/sway/input/keyboard.c +++ b/sway/input/keyboard.c @@ -3,6 +3,7 @@ #include #include #include +#include #include "sway/commands.h" #include "sway/desktop/transaction.h" #include "sway/input/input-manager.h" @@ -385,6 +386,23 @@ void sway_keyboard_configure(struct sway_keyboard *keyboard) { keyboard->keymap = keymap; wlr_keyboard_set_keymap(wlr_device->keyboard, keyboard->keymap); + xkb_mod_mask_t locked_mods = 0; + if (!input_config || input_config->xkb_numlock != 0) { + xkb_mod_index_t mod_index = xkb_map_mod_get_index(keymap, XKB_MOD_NAME_NUM); + if (mod_index != XKB_MOD_INVALID) { + locked_mods |= (uint32_t)1 << mod_index; + } + } + if (input_config && input_config->xkb_capslock > 0) { + xkb_mod_index_t mod_index = xkb_map_mod_get_index(keymap, XKB_MOD_NAME_CAPS); + if (mod_index != XKB_MOD_INVALID) { + locked_mods |= (uint32_t)1 << mod_index; + } + } + if (locked_mods) { + wlr_keyboard_notify_modifiers(wlr_device->keyboard, 0, 0, locked_mods, 0); + } + if (input_config && input_config->repeat_delay != INT_MIN && input_config->repeat_rate != INT_MIN) { wlr_keyboard_set_repeat_info(wlr_device->keyboard, -- cgit v1.2.3 From 76ece5788bffe27b32c85968886f3738d244abf9 Mon Sep 17 00:00:00 2001 From: ProgAndy Date: Wed, 25 Jul 2018 17:09:34 +0200 Subject: Fix LEDs for configured modifier states --- sway/input/keyboard.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'sway/input/keyboard.c') diff --git a/sway/input/keyboard.c b/sway/input/keyboard.c index 36c5a064..643ff510 100644 --- a/sway/input/keyboard.c +++ b/sway/input/keyboard.c @@ -401,6 +401,14 @@ void sway_keyboard_configure(struct sway_keyboard *keyboard) { } if (locked_mods) { wlr_keyboard_notify_modifiers(wlr_device->keyboard, 0, 0, locked_mods, 0); + uint32_t leds = 0; + for (uint32_t i = 0; i < WLR_LED_COUNT; ++i) { + if (xkb_state_led_index_is_active(wlr_device->keyboard->xkb_state, + wlr_device->keyboard->led_indexes[i])) { + leds |= (1 << i); + } + } + wlr_keyboard_led_update(wlr_device->keyboard, leds); } if (input_config && input_config->repeat_delay != INT_MIN -- cgit v1.2.3 From 30fee94354b61c2604431a53f4d1a1daf6c0a67a Mon Sep 17 00:00:00 2001 From: Geoff Greer Date: Fri, 27 Jul 2018 22:42:50 -0700 Subject: Don't enable numlock by default. This fixes an annoying issue where laptop keyboards would have 'numlock mode' enabled, remapping parts of the alphabet to numbers. --- sway/input/keyboard.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sway/input/keyboard.c') diff --git a/sway/input/keyboard.c b/sway/input/keyboard.c index 643ff510..8dc8239c 100644 --- a/sway/input/keyboard.c +++ b/sway/input/keyboard.c @@ -387,7 +387,7 @@ void sway_keyboard_configure(struct sway_keyboard *keyboard) { wlr_keyboard_set_keymap(wlr_device->keyboard, keyboard->keymap); xkb_mod_mask_t locked_mods = 0; - if (!input_config || input_config->xkb_numlock != 0) { + if (input_config && input_config->xkb_numlock > 0) { xkb_mod_index_t mod_index = xkb_map_mod_get_index(keymap, XKB_MOD_NAME_NUM); if (mod_index != XKB_MOD_INVALID) { locked_mods |= (uint32_t)1 << mod_index; -- cgit v1.2.3 From e33dfbfa758fb899c276135d06f25359ceee0002 Mon Sep 17 00:00:00 2001 From: frsfnrrg Date: Sun, 29 Jul 2018 16:25:43 -0400 Subject: Implement key repeat for pressed key bindings Each sway_keyboard is provided with a wayland timer event source. When a valid keypress binding has been found, a callback to handle_keyboard_repeat is set. Any key event will either clear the callback or (if the new key event is a valid keypress binding) delay the callback again. --- sway/input/keyboard.c | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) (limited to 'sway/input/keyboard.c') diff --git a/sway/input/keyboard.c b/sway/input/keyboard.c index 8dc8239c..be000fb9 100644 --- a/sway/input/keyboard.c +++ b/sway/input/keyboard.c @@ -264,6 +264,7 @@ static void handle_keyboard_key(struct wl_listener *listener, void *data) { } // Identify and execute active pressed binding + struct sway_binding *next_repeat_binding = NULL; if (event->state == WLR_KEY_PRESSED) { struct sway_binding *binding_pressed = NULL; get_active_binding(&keyboard->state_keycodes, @@ -279,6 +280,21 @@ static void handle_keyboard_key(struct wl_listener *listener, void *data) { if (binding_pressed) { seat_execute_command(seat, binding_pressed); handled = true; + next_repeat_binding = binding_pressed; + } + } + + // Set up (or clear) keyboard repeat for a pressed binding + if (next_repeat_binding) { + keyboard->repeat_binding = next_repeat_binding; + if (wl_event_source_timer_update(keyboard->key_repeat_source, + keyboard->key_repeat_initial_delay) < 0) { + wlr_log(WLR_DEBUG, "failed to set key repeat timer"); + } + } else if (keyboard->repeat_binding) { + keyboard->repeat_binding = NULL; + if (wl_event_source_timer_update(keyboard->key_repeat_source, 0) < 0) { + wlr_log(WLR_DEBUG, "failed to disarm key repeat timer"); } } @@ -303,6 +319,22 @@ static void handle_keyboard_key(struct wl_listener *listener, void *data) { transaction_commit_dirty(); } +static int handle_keyboard_repeat(void *data) { + struct sway_keyboard *keyboard = (struct sway_keyboard *)data; + if (keyboard->repeat_binding) { + // We queue the next event first, as the command might cancel it + if (wl_event_source_timer_update(keyboard->key_repeat_source, + keyboard->key_repeat_step_delay) < 0) { + wlr_log(WLR_DEBUG, "failed to update key repeat timer"); + } + + seat_execute_command(keyboard->seat_device->sway_seat, + keyboard->repeat_binding); + transaction_commit_dirty(); + } + return 0; +} + static void handle_keyboard_modifiers(struct wl_listener *listener, void *data) { struct sway_keyboard *keyboard = @@ -328,6 +360,11 @@ struct sway_keyboard *sway_keyboard_create(struct sway_seat *seat, wl_list_init(&keyboard->keyboard_key.link); wl_list_init(&keyboard->keyboard_modifiers.link); + keyboard->key_repeat_source = wl_event_loop_add_timer(server.wl_event_loop, + handle_keyboard_repeat, keyboard); + keyboard->key_repeat_initial_delay = 660; + keyboard->key_repeat_step_delay = 40; + return keyboard; } @@ -441,5 +478,6 @@ void sway_keyboard_destroy(struct sway_keyboard *keyboard) { } wl_list_remove(&keyboard->keyboard_key.link); wl_list_remove(&keyboard->keyboard_modifiers.link); + wl_event_source_remove(keyboard->key_repeat_source); free(keyboard); } -- cgit v1.2.3 From 8dbbfa5965ca8bfe4bc023100387dd657bafe48e Mon Sep 17 00:00:00 2001 From: frsfnrrg Date: Sun, 29 Jul 2018 18:50:20 -0400 Subject: Bindings use advised keyboard repeat parameters Now 'repeat_delay' and 'repeat_rate' control the initial delay and rate (per second) of repeated binding invocations. If the repeat delay is zero, binding repetition is disabled. When the repeat rate is zero, the binding is repeated exactly once, assuming no other key events intervene. --- sway/input/keyboard.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) (limited to 'sway/input/keyboard.c') diff --git a/sway/input/keyboard.c b/sway/input/keyboard.c index be000fb9..160ef10b 100644 --- a/sway/input/keyboard.c +++ b/sway/input/keyboard.c @@ -285,10 +285,10 @@ static void handle_keyboard_key(struct wl_listener *listener, void *data) { } // Set up (or clear) keyboard repeat for a pressed binding - if (next_repeat_binding) { + if (next_repeat_binding && wlr_device->keyboard->repeat_info.delay > 0) { keyboard->repeat_binding = next_repeat_binding; if (wl_event_source_timer_update(keyboard->key_repeat_source, - keyboard->key_repeat_initial_delay) < 0) { + wlr_device->keyboard->repeat_info.delay) < 0) { wlr_log(WLR_DEBUG, "failed to set key repeat timer"); } } else if (keyboard->repeat_binding) { @@ -321,11 +321,15 @@ static void handle_keyboard_key(struct wl_listener *listener, void *data) { static int handle_keyboard_repeat(void *data) { struct sway_keyboard *keyboard = (struct sway_keyboard *)data; + struct wlr_keyboard *wlr_device = + keyboard->seat_device->input_device->wlr_device->keyboard; if (keyboard->repeat_binding) { - // We queue the next event first, as the command might cancel it - if (wl_event_source_timer_update(keyboard->key_repeat_source, - keyboard->key_repeat_step_delay) < 0) { - wlr_log(WLR_DEBUG, "failed to update key repeat timer"); + if (wlr_device->repeat_info.rate > 0) { + // We queue the next event first, as the command might cancel it + if (wl_event_source_timer_update(keyboard->key_repeat_source, + 1000 / wlr_device->repeat_info.rate) < 0) { + wlr_log(WLR_DEBUG, "failed to update key repeat timer"); + } } seat_execute_command(keyboard->seat_device->sway_seat, @@ -362,8 +366,6 @@ struct sway_keyboard *sway_keyboard_create(struct sway_seat *seat, keyboard->key_repeat_source = wl_event_loop_add_timer(server.wl_event_loop, handle_keyboard_repeat, keyboard); - keyboard->key_repeat_initial_delay = 660; - keyboard->key_repeat_step_delay = 40; return keyboard; } -- cgit v1.2.3