Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cmd_bind{sym,code}: Implement per-device bindings #2875

Merged
merged 1 commit into from
Oct 19, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions include/sway/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
5 changes: 3 additions & 2 deletions include/sway/input/cursor.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
1 change: 1 addition & 0 deletions include/sway/input/input-manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
14 changes: 12 additions & 2 deletions sway/commands/bind.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand All @@ -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;
}
Expand Down Expand Up @@ -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;
Expand All @@ -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;
}
Expand Down Expand Up @@ -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);

}
Expand Down
2 changes: 1 addition & 1 deletion sway/commands/seat/cursor.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
40 changes: 27 additions & 13 deletions sway/input/cursor.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand All @@ -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();
}
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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();
}
Expand Down Expand Up @@ -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();
Expand All @@ -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--;
Expand Down
6 changes: 3 additions & 3 deletions sway/input/input-manager.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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'",
Expand Down Expand Up @@ -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'",
Expand Down
34 changes: 23 additions & 11 deletions sway/input/keyboard.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
}

Expand All @@ -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;
}
}

Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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 &&
Expand All @@ -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);
Expand Down Expand Up @@ -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) {
Expand Down
10 changes: 6 additions & 4 deletions sway/sway.5.scd
Original file line number Diff line number Diff line change
Expand Up @@ -257,20 +257,22 @@ runtime.

for\_window <criteria> move container to output <output>

*bindsym* [--release|--locked] <key combo> <command>
*bindsym* [--release|--locked] [--input-device=<device>] <key combo> <command>
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] <code> <command> is also available for
binding with key codes instead of key names.
*bindcode* [--release|--locked] [--input-device=<device>] <code> <command>
is also available for binding with key codes instead of key names.

*client.<class>* <border> <background> <text> <indicator> <child\_border>
Configures the color of window borders and title bars. All 5 colors are
Expand Down