From 2e637b7368de565a85f77fbd03408f33b763dd7b Mon Sep 17 00:00:00 2001 From: Brian Ashworth Date: Thu, 18 Oct 2018 13:13:40 -0400 Subject: [PATCH] cmd_bind{sym,code}: Implement per-device bindings bindsym --input-device= ... bindcode --input-device= ... --- include/sway/config.h | 1 + include/sway/input/cursor.h | 5 ++-- include/sway/input/input-manager.h | 1 + sway/commands/bind.c | 14 +++++++++-- sway/commands/seat/cursor.c | 2 +- sway/input/cursor.c | 40 ++++++++++++++++++++---------- sway/input/input-manager.c | 6 ++--- sway/input/keyboard.c | 34 +++++++++++++++++-------- sway/sway.5.scd | 10 +++++--- 9 files changed, 77 insertions(+), 36 deletions(-) diff --git a/include/sway/config.h b/include/sway/config.h index be5a00b56..fef3a60ac 100644 --- a/include/sway/config.h +++ b/include/sway/config.h @@ -43,6 +43,7 @@ enum binding_flags { struct sway_binding { enum binding_input_type type; int order; + char *input; uint32_t flags; list_t *keys; // sorted in ascending order uint32_t modifiers; diff --git a/include/sway/input/cursor.h b/include/sway/input/cursor.h index 5556ea11b..299721f0a 100644 --- a/include/sway/input/cursor.h +++ b/include/sway/input/cursor.h @@ -42,8 +42,9 @@ void sway_cursor_destroy(struct sway_cursor *cursor); struct sway_cursor *sway_cursor_create(struct sway_seat *seat); void cursor_send_pointer_motion(struct sway_cursor *cursor, uint32_t time_msec, bool allow_refocusing); -void dispatch_cursor_button(struct sway_cursor *cursor, uint32_t time_msec, - uint32_t button, enum wlr_button_state state); +void dispatch_cursor_button(struct sway_cursor *cursor, + struct wlr_input_device *device, uint32_t time_msec, uint32_t button, + enum wlr_button_state state); void cursor_set_image(struct sway_cursor *cursor, const char *image, struct wl_client *client); diff --git a/include/sway/input/input-manager.h b/include/sway/input/input-manager.h index bde3cf46c..b70730060 100644 --- a/include/sway/input/input-manager.h +++ b/include/sway/input/input-manager.h @@ -63,5 +63,6 @@ struct sway_seat *input_manager_current_seat(struct sway_input_manager *input); struct input_config *input_device_get_config(struct sway_input_device *device); +char *input_device_get_identifier(struct wlr_input_device *device); #endif diff --git a/sway/commands/bind.c b/sway/commands/bind.c index 701d97468..5832d01e8 100644 --- a/sway/commands/bind.c +++ b/sway/commands/bind.c @@ -26,6 +26,7 @@ void free_sway_binding(struct sway_binding *binding) { if (binding->keys) { free_flat_list(binding->keys); } + free(binding->input); free(binding->command); free(binding); } @@ -37,6 +38,10 @@ void free_sway_binding(struct sway_binding *binding) { */ static bool binding_key_compare(struct sway_binding *binding_a, struct sway_binding *binding_b) { + if (strcmp(binding_a->input, binding_b->input) != 0) { + return false; + } + if (binding_a->type != binding_b->type) { return false; } @@ -149,6 +154,7 @@ static struct cmd_results *cmd_bindsym_or_bindcode(int argc, char **argv, return cmd_results_new(CMD_FAILURE, bindtype, "Unable to allocate binding"); } + binding->input = strdup("*"); binding->keys = create_list(); binding->modifiers = 0; binding->flags = 0; @@ -168,6 +174,10 @@ static struct cmd_results *cmd_bindsym_or_bindcode(int argc, char **argv, binding->flags |= BINDING_BORDER; } else if (strcmp("--exclude-titlebar", argv[0]) == 0) { exclude_titlebar = true; + } else if (strncmp("--input-device=", argv[0], + strlen("--input-device=")) == 0) { + free(binding->input); + binding->input = strdup(argv[0] + strlen("--input-device=")); } else { break; } @@ -257,8 +267,8 @@ static struct cmd_results *cmd_bindsym_or_bindcode(int argc, char **argv, list_add(mode_bindings, binding); } - wlr_log(WLR_DEBUG, "%s - Bound %s to command %s", - bindtype, argv[0], binding->command); + wlr_log(WLR_DEBUG, "%s - Bound %s to command `%s` for device '%s'", + bindtype, argv[0], binding->command, binding->input); return cmd_results_new(CMD_SUCCESS, NULL, NULL); } diff --git a/sway/commands/seat/cursor.c b/sway/commands/seat/cursor.c index cd6630e0d..595e9bc6d 100644 --- a/sway/commands/seat/cursor.c +++ b/sway/commands/seat/cursor.c @@ -80,6 +80,6 @@ static struct cmd_results *press_or_release(struct sway_cursor *cursor, return cmd_results_new(CMD_INVALID, "cursor", expected_syntax); } } - dispatch_cursor_button(cursor, 0, button, state); + dispatch_cursor_button(cursor, NULL, 0, button, state); return cmd_results_new(CMD_SUCCESS, NULL, NULL); } diff --git a/sway/input/cursor.c b/sway/input/cursor.c index 688fc230c..7ac5013d6 100644 --- a/sway/input/cursor.c +++ b/sway/input/cursor.c @@ -727,19 +727,23 @@ static void state_add_button(struct sway_cursor *cursor, uint32_t button) { * Return the mouse binding which matches modifier, click location, release, * and pressed button state, otherwise return null. */ -static struct sway_binding* get_active_mouse_binding(const struct sway_cursor *cursor, - list_t *bindings, uint32_t modifiers, bool release, bool on_titlebar, - bool on_border, bool on_content) { +static struct sway_binding* get_active_mouse_binding( + const struct sway_cursor *cursor, list_t *bindings, uint32_t modifiers, + bool release, bool on_titlebar, bool on_border, bool on_content, + const char *identifier) { uint32_t click_region = (on_titlebar ? BINDING_TITLEBAR : 0) | (on_border ? BINDING_BORDER : 0) | (on_content ? BINDING_CONTENTS : 0); + struct sway_binding *current = NULL; for (int i = 0; i < bindings->length; ++i) { struct sway_binding *binding = bindings->items[i]; if (modifiers ^ binding->modifiers || cursor->pressed_button_count != (size_t)binding->keys->length || release != (binding->flags & BINDING_RELEASE) || - !(click_region & binding->flags)) { + !(click_region & binding->flags) || + (strcmp(binding->input, identifier) != 0 && + strcmp(binding->input, "*") != 0)) { continue; } @@ -755,13 +759,20 @@ static struct sway_binding* get_active_mouse_binding(const struct sway_cursor *c continue; } - return binding; + if (!current || strcmp(current->input, "*") == 0) { + current = binding; + if (strcmp(current->input, identifier) == 0) { + // If a binding is found for the exact input, quit searching + break; + } + } } - return NULL; + return current; } void dispatch_cursor_button(struct sway_cursor *cursor, - uint32_t time_msec, uint32_t button, enum wlr_button_state state) { + struct wlr_input_device *device, uint32_t time_msec, uint32_t button, + enum wlr_button_state state) { if (time_msec == 0) { time_msec = get_current_time_msec(); } @@ -797,18 +808,21 @@ void dispatch_cursor_button(struct sway_cursor *cursor, struct wlr_keyboard *keyboard = wlr_seat_get_keyboard(seat->wlr_seat); uint32_t modifiers = keyboard ? wlr_keyboard_get_modifiers(keyboard) : 0; + char *device_identifier = device ? input_device_get_identifier(device) + : strdup("*"); struct sway_binding *binding = NULL; if (state == WLR_BUTTON_PRESSED) { state_add_button(cursor, button); binding = get_active_mouse_binding(cursor, config->current_mode->mouse_bindings, modifiers, false, - on_titlebar, on_border, on_contents); + on_titlebar, on_border, on_contents, device_identifier); } else { binding = get_active_mouse_binding(cursor, config->current_mode->mouse_bindings, modifiers, true, - on_titlebar, on_border, on_contents); + on_titlebar, on_border, on_contents, device_identifier); state_erase_button(cursor, button); } + free(device_identifier); if (binding) { seat_execute_command(seat, binding); return; @@ -942,7 +956,7 @@ static void handle_cursor_button(struct wl_listener *listener, void *data) { struct sway_cursor *cursor = wl_container_of(listener, cursor, button); wlr_idle_notify_activity(cursor->seat->input->server->idle, cursor->seat->wlr_seat); struct wlr_event_pointer_button *event = data; - dispatch_cursor_button(cursor, + dispatch_cursor_button(cursor, event->device, event->time_msec, event->button, event->state); transaction_commit_dirty(); } @@ -1128,7 +1142,7 @@ static void handle_tool_tip(struct wl_listener *listener, void *data) { struct sway_cursor *cursor = wl_container_of(listener, cursor, tool_tip); wlr_idle_notify_activity(cursor->seat->input->server->idle, cursor->seat->wlr_seat); struct wlr_event_tablet_tool_tip *event = data; - dispatch_cursor_button(cursor, event->time_msec, + dispatch_cursor_button(cursor, event->device, event->time_msec, BTN_LEFT, event->state == WLR_TABLET_TOOL_TIP_DOWN ? WLR_BUTTON_PRESSED : WLR_BUTTON_RELEASED); transaction_commit_dirty(); @@ -1143,14 +1157,14 @@ static void handle_tool_button(struct wl_listener *listener, void *data) { switch (event->state) { case WLR_BUTTON_PRESSED: if (cursor->tool_buttons == 0) { - dispatch_cursor_button(cursor, + dispatch_cursor_button(cursor, event->device, event->time_msec, BTN_RIGHT, event->state); } cursor->tool_buttons++; break; case WLR_BUTTON_RELEASED: if (cursor->tool_buttons == 1) { - dispatch_cursor_button(cursor, + dispatch_cursor_button(cursor, event->device, event->time_msec, BTN_RIGHT, event->state); } cursor->tool_buttons--; diff --git a/sway/input/input-manager.c b/sway/input/input-manager.c index 70c2abf7b..671f9a47b 100644 --- a/sway/input/input-manager.c +++ b/sway/input/input-manager.c @@ -45,7 +45,7 @@ struct sway_seat *input_manager_get_seat( return seat_create(input, seat_name); } -static char *get_device_identifier(struct wlr_input_device *device) { +char *input_device_get_identifier(struct wlr_input_device *device) { int vendor = device->vendor; int product = device->product; char *name = strdup(device->name); @@ -278,7 +278,7 @@ static void handle_new_input(struct wl_listener *listener, void *data) { device->data = input_device; input_device->wlr_device = device; - input_device->identifier = get_device_identifier(device); + input_device->identifier = input_device_get_identifier(device); wl_list_insert(&input->devices, &input_device->link); wlr_log(WLR_DEBUG, "adding device: '%s'", @@ -375,7 +375,7 @@ void handle_virtual_keyboard(struct wl_listener *listener, void *data) { device->data = input_device; input_device->wlr_device = device; - input_device->identifier = get_device_identifier(device); + input_device->identifier = input_device_get_identifier(device); wl_list_insert(&input_manager->devices, &input_device->link); wlr_log(WLR_DEBUG, "adding virtual keyboard: '%s'", diff --git a/sway/input/keyboard.c b/sway/input/keyboard.c index 2c8b41cd7..4427dabee 100644 --- a/sway/input/keyboard.c +++ b/sway/input/keyboard.c @@ -87,7 +87,7 @@ static void update_shortcut_state(struct sway_shortcut_state *state, */ static void get_active_binding(const struct sway_shortcut_state *state, list_t *bindings, struct sway_binding **current_binding, - uint32_t modifiers, bool release, bool locked) { + uint32_t modifiers, bool release, bool locked, const char *input) { for (int i = 0; i < bindings->length; ++i) { struct sway_binding *binding = bindings->items[i]; bool binding_locked = binding->flags & BINDING_LOCKED; @@ -96,7 +96,9 @@ static void get_active_binding(const struct sway_shortcut_state *state, if (modifiers ^ binding->modifiers || state->npressed != (size_t)binding->keys->length || release != binding_release || - locked > binding_locked) { + locked > binding_locked || + (strcmp(binding->input, input) != 0 && + strcmp(binding->input, "*") != 0)) { continue; } @@ -112,13 +114,19 @@ static void get_active_binding(const struct sway_shortcut_state *state, continue; } - if (*current_binding && *current_binding != binding) { + if (*current_binding && *current_binding != binding && + strcmp((*current_binding)->input, binding->input) == 0) { wlr_log(WLR_DEBUG, "encountered duplicate bindings %d and %d", (*current_binding)->order, binding->order); - } else { + } else if (!*current_binding || + strcmp((*current_binding)->input, "*") == 0) { *current_binding = binding; + + if (strcmp((*current_binding)->input, input) == 0) { + // If a binding is found for the exact input, quit searching + return; + } } - return; } } @@ -202,6 +210,7 @@ static void handle_keyboard_key(struct wl_listener *listener, void *data) { struct wlr_seat *wlr_seat = seat->wlr_seat; struct wlr_input_device *wlr_device = keyboard->seat_device->input_device->wlr_device; + char *device_identifier = input_device_get_identifier(wlr_device); wlr_idle_notify_activity(seat->input->server->idle, wlr_seat); struct wlr_event_keyboard_key *event = data; bool input_inhibited = seat->exclusive_client != NULL; @@ -242,13 +251,13 @@ static void handle_keyboard_key(struct wl_listener *listener, void *data) { struct sway_binding *binding_released = NULL; get_active_binding(&keyboard->state_keycodes, config->current_mode->keycode_bindings, &binding_released, - code_modifiers, true, input_inhibited); + code_modifiers, true, input_inhibited, device_identifier); get_active_binding(&keyboard->state_keysyms_translated, config->current_mode->keysym_bindings, &binding_released, - translated_modifiers, true, input_inhibited); + translated_modifiers, true, input_inhibited, device_identifier); get_active_binding(&keyboard->state_keysyms_raw, config->current_mode->keysym_bindings, &binding_released, - raw_modifiers, true, input_inhibited); + raw_modifiers, true, input_inhibited, device_identifier); // Execute stored release binding once no longer active if (keyboard->held_binding && binding_released != keyboard->held_binding && @@ -268,13 +277,14 @@ static void handle_keyboard_key(struct wl_listener *listener, void *data) { if (event->state == WLR_KEY_PRESSED) { get_active_binding(&keyboard->state_keycodes, config->current_mode->keycode_bindings, &binding, - code_modifiers, false, input_inhibited); + code_modifiers, false, input_inhibited, device_identifier); get_active_binding(&keyboard->state_keysyms_translated, config->current_mode->keysym_bindings, &binding, - translated_modifiers, false, input_inhibited); + translated_modifiers, false, input_inhibited, + device_identifier); get_active_binding(&keyboard->state_keysyms_raw, config->current_mode->keysym_bindings, &binding, - raw_modifiers, false, input_inhibited); + raw_modifiers, false, input_inhibited, device_identifier); if (binding) { seat_execute_command(seat, binding); @@ -315,6 +325,8 @@ static void handle_keyboard_key(struct wl_listener *listener, void *data) { } transaction_commit_dirty(); + + free(device_identifier); } static int handle_keyboard_repeat(void *data) { diff --git a/sway/sway.5.scd b/sway/sway.5.scd index f6f0e8592..e5e7918fb 100644 --- a/sway/sway.5.scd +++ b/sway/sway.5.scd @@ -257,20 +257,22 @@ runtime. for\_window move container to output -*bindsym* [--release|--locked] +*bindsym* [--release|--locked] [--input-device=] Binds _key combo_ to execute the sway command _command_ when pressed. You may use XKB key names here (*xev*(1) is a good tool for discovering these). With the flag _--release_, the command is executed when the key combo is released. Unless the flag _--locked_ is set, the command will not be run - when a screen locking program is active. + when a screen locking program is active. If _input-device_ is given, the + binding will only be executed for that input device and will be executed + instead of any binding that is generic to all devices. Example: # Execute firefox when alt, shift, and f are pressed together bindsym Mod1+Shift+f exec firefox - *bindcode* [--release|--locked] is also available for - binding with key codes instead of key names. + *bindcode* [--release|--locked] [--input-device=] + is also available for binding with key codes instead of key names. *client.* Configures the color of window borders and title bars. All 5 colors are