diff --git a/completions/bash/swaymsg b/completions/bash/swaymsg index 0b0119029..fa71098d4 100644 --- a/completions/bash/swaymsg +++ b/completions/bash/swaymsg @@ -15,6 +15,7 @@ _swaymsg() 'get_bar_config' 'get_version' 'get_binding_modes' + 'get_bindings' 'get_config' 'send_tick' ) diff --git a/completions/fish/swaymsg.fish b/completions/fish/swaymsg.fish index 3f1cc50c1..18cd1152e 100644 --- a/completions/fish/swaymsg.fish +++ b/completions/fish/swaymsg.fish @@ -17,6 +17,7 @@ complete -c swaymsg -s t -l type -fra 'get_marks' --description "Get a JSON-enco complete -c swaymsg -s t -l type -fra 'get_bar_config' --description "Get a JSON-encoded configuration for swaybar." complete -c swaymsg -s t -l type -fra 'get_version' --description "Get JSON-encoded version information for the running instance of sway." complete -c swaymsg -s t -l type -fra 'get_binding_modes' --description "Gets a JSON-encoded list of currently configured binding modes." +complete -c swaymsg -s t -l type -fra 'get_bindings' --description "Gets a JSON-encoded object mapping binding modes to their keyboard and mouse bindings." complete -c swaymsg -s t -l type -fra 'get_config' --description "Gets a JSON-encoded copy of the current configuration." complete -c swaymsg -s t -l type -fra 'get_seats' --description "Gets a JSON-encoded list of all seats, its properties and all assigned devices." complete -c swaymsg -s t -l type -fra 'send_tick' --description "Sends a tick event to all subscribed clients." diff --git a/completions/zsh/_swaymsg b/completions/zsh/_swaymsg index c11fa9905..78089154d 100644 --- a/completions/zsh/_swaymsg +++ b/completions/zsh/_swaymsg @@ -23,6 +23,7 @@ types=( 'get_bar_config' 'get_version' 'get_binding_modes' +'get_bindings' 'get_config' 'send_tick' ) diff --git a/include/ipc.h b/include/ipc.h index 6063f69c5..511a79fb9 100644 --- a/include/ipc.h +++ b/include/ipc.h @@ -21,6 +21,7 @@ enum ipc_command_type { // sway-specific command types IPC_GET_INPUTS = 100, IPC_GET_SEATS = 101, + IPC_GET_BINDINGS = 102, // Events sent from sway to clients. Events have the highest bits set. IPC_EVENT_WORKSPACE = ((1<<31) | 0), diff --git a/include/sway/config.h b/include/sway/config.h index 46ca7cee4..378da5866 100644 --- a/include/sway/config.h +++ b/include/sway/config.h @@ -354,9 +354,10 @@ enum ipc_feature { IPC_FEATURE_EVENT_BINDING = 4096, IPC_FEATURE_EVENT_INPUT = 8192, IPC_FEATURE_GET_SEATS = 16384, + IPC_FEATURE_GET_BINDINGS = 32768, IPC_FEATURE_ALL_COMMANDS = - 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128 | 16384, + 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128 | 16384 | 32768, IPC_FEATURE_ALL_EVENTS = 256 | 512 | 1024 | 2048 | 4096 | 8192, IPC_FEATURE_ALL = IPC_FEATURE_ALL_COMMANDS | IPC_FEATURE_ALL_EVENTS, diff --git a/include/sway/ipc-json.h b/include/sway/ipc-json.h index 3e584dbbb..8f147184f 100644 --- a/include/sway/ipc-json.h +++ b/include/sway/ipc-json.h @@ -12,5 +12,7 @@ json_object *ipc_json_describe_node_recursive(struct sway_node *node); json_object *ipc_json_describe_input(struct sway_input_device *device); json_object *ipc_json_describe_seat(struct sway_seat *seat); json_object *ipc_json_describe_bar_config(struct bar_config *bar); +json_object *ipc_json_describe_binding(struct sway_binding *binding); +json_object *ipc_json_describe_mode_bindings(struct sway_mode *mode); #endif diff --git a/sway/ipc-json.c b/sway/ipc-json.c index e9564b049..64609a13c 100644 --- a/sway/ipc-json.c +++ b/sway/ipc-json.c @@ -12,6 +12,7 @@ #include "sway/output.h" #include "sway/input/input-manager.h" #include "sway/input/cursor.h" +#include "sway/input/keyboard.h" #include "sway/input/seat.h" #include #include @@ -1103,3 +1104,95 @@ json_object *ipc_json_describe_bar_config(struct bar_config *bar) { #endif return json; } + +json_object *ipc_json_describe_binding(struct sway_binding *binding) { + if (!sway_assert(binding, "Binding must not be NULL")) { + return NULL; + } + + json_object *json_binding = json_object_new_object(); + json_object_object_add(json_binding, "command", json_object_new_string(binding->command)); + + const char *names[10]; + int len = get_modifier_names(names, binding->modifiers); + json_object *modifiers = json_object_new_array(); + for (int i = 0; i < len; ++i) { + json_object_array_add(modifiers, json_object_new_string(names[i])); + } + json_object_object_add(json_binding, "event_state_mask", modifiers); + + json_object *input_codes = json_object_new_array(); + int input_code = 0; + json_object *symbols = json_object_new_array(); + json_object *symbol = NULL; + + if (binding->type == BINDING_KEYCODE) { // bindcode: populate input_codes + uint32_t keycode; + for (int i = 0; i < binding->keys->length; ++i) { + keycode = *(uint32_t *)binding->keys->items[i]; + json_object_array_add(input_codes, json_object_new_int(keycode)); + if (i == 0) { + input_code = keycode; + } + } + } else { // bindsym/mouse: populate symbols + uint32_t keysym; + char buffer[64]; + for (int i = 0; i < binding->keys->length; ++i) { + keysym = *(uint32_t *)binding->keys->items[i]; + if (keysym >= BTN_LEFT && keysym <= BTN_LEFT + 8) { + snprintf(buffer, 64, "button%u", keysym - BTN_LEFT + 1); + } else if (xkb_keysym_get_name(keysym, buffer, 64) < 0) { + continue; + } + + json_object *str = json_object_new_string(buffer); + if (i == 0) { + // str is owned by both symbol and symbols. Make sure + // to bump the ref count. + json_object_array_add(symbols, json_object_get(str)); + symbol = str; + } else { + json_object_array_add(symbols, str); + } + } + } + + json_object_object_add(json_binding, "input_codes", input_codes); + json_object_object_add(json_binding, "input_code", json_object_new_int(input_code)); + json_object_object_add(json_binding, "symbols", symbols); + json_object_object_add(json_binding, "symbol", symbol); + + bool mouse = binding->type == BINDING_MOUSECODE || + binding->type == BINDING_MOUSESYM; + json_object_object_add(json_binding, "input_type", mouse + ? json_object_new_string("mouse") + : json_object_new_string("keyboard")); + + return json_binding; +} + +json_object *ipc_json_describe_mode_bindings(struct sway_mode * mode) { + if (!sway_assert(mode, "Mode must not be NULL")) { + return NULL; + } + + json_object *json_bindings = json_object_new_array(); + + for (int i = 0; i < mode->keysym_bindings->length; i++) { + json_object_array_add(json_bindings, + ipc_json_describe_binding(mode->keysym_bindings->items[i])); + } + + for (int i = 0; i < mode->keycode_bindings->length; i++) { + json_object_array_add(json_bindings, + ipc_json_describe_binding(mode->keycode_bindings->items[i])); + } + + for (int i = 0; i < mode->mouse_bindings->length; i++) { + json_object_array_add(json_bindings, + ipc_json_describe_binding(mode->mouse_bindings->items[i])); + } + + return json_bindings; +} diff --git a/sway/ipc-server.c b/sway/ipc-server.c index df57cba51..f24664bb1 100644 --- a/sway/ipc-server.c +++ b/sway/ipc-server.c @@ -23,7 +23,6 @@ #include "sway/output.h" #include "sway/server.h" #include "sway/input/input-manager.h" -#include "sway/input/keyboard.h" #include "sway/input/seat.h" #include "sway/tree/root.h" #include "sway/tree/view.h" @@ -394,68 +393,10 @@ void ipc_event_binding(struct sway_binding *binding) { } sway_log(SWAY_DEBUG, "Sending binding event"); - json_object *json_binding = json_object_new_object(); - json_object_object_add(json_binding, "command", json_object_new_string(binding->command)); - - const char *names[10]; - int len = get_modifier_names(names, binding->modifiers); - json_object *modifiers = json_object_new_array(); - for (int i = 0; i < len; ++i) { - json_object_array_add(modifiers, json_object_new_string(names[i])); - } - json_object_object_add(json_binding, "event_state_mask", modifiers); - - json_object *input_codes = json_object_new_array(); - int input_code = 0; - json_object *symbols = json_object_new_array(); - json_object *symbol = NULL; - - if (binding->type == BINDING_KEYCODE) { // bindcode: populate input_codes - uint32_t keycode; - for (int i = 0; i < binding->keys->length; ++i) { - keycode = *(uint32_t *)binding->keys->items[i]; - json_object_array_add(input_codes, json_object_new_int(keycode)); - if (i == 0) { - input_code = keycode; - } - } - } else { // bindsym/mouse: populate symbols - uint32_t keysym; - char buffer[64]; - for (int i = 0; i < binding->keys->length; ++i) { - keysym = *(uint32_t *)binding->keys->items[i]; - if (keysym >= BTN_LEFT && keysym <= BTN_LEFT + 8) { - snprintf(buffer, 64, "button%u", keysym - BTN_LEFT + 1); - } else if (xkb_keysym_get_name(keysym, buffer, 64) < 0) { - continue; - } - - json_object *str = json_object_new_string(buffer); - if (i == 0) { - // str is owned by both symbol and symbols. Make sure - // to bump the ref count. - json_object_array_add(symbols, json_object_get(str)); - symbol = str; - } else { - json_object_array_add(symbols, str); - } - } - } - - json_object_object_add(json_binding, "input_codes", input_codes); - json_object_object_add(json_binding, "input_code", json_object_new_int(input_code)); - json_object_object_add(json_binding, "symbols", symbols); - json_object_object_add(json_binding, "symbol", symbol); - - bool mouse = binding->type == BINDING_MOUSECODE || - binding->type == BINDING_MOUSESYM; - json_object_object_add(json_binding, "input_type", mouse - ? json_object_new_string("mouse") - : json_object_new_string("keyboard")); - json_object *json = json_object_new_object(); json_object_object_add(json, "change", json_object_new_string("run")); - json_object_object_add(json, "binding", json_binding); + json_object_object_add(json, "binding", ipc_json_describe_binding(binding)); + const char *json_string = json_object_to_json_string(json); ipc_send_event(json_string, IPC_EVENT_BINDING); json_object_put(json); @@ -836,6 +777,21 @@ void ipc_client_handle_command(struct ipc_client *client) { goto exit_cleanup; } + case IPC_GET_BINDINGS: + { + json_object *modes = json_object_new_object(); + for (int i = 0; i < config->modes->length; i++) { + struct sway_mode *mode = config->modes->items[i]; + json_object_object_add( + modes, mode->name, ipc_json_describe_mode_bindings(mode)); + } + const char *json_string = json_object_to_json_string(modes); + client_valid = + ipc_send_reply(client, json_string, (uint32_t)strlen(json_string)); + json_object_put(modes); // free + goto exit_cleanup; + } + case IPC_GET_CONFIG: { json_object *json = json_object_new_object(); diff --git a/swaymsg/main.c b/swaymsg/main.c index a0ef7e3d9..def5f761d 100644 --- a/swaymsg/main.c +++ b/swaymsg/main.c @@ -417,6 +417,8 @@ int main(int argc, char **argv) { type = IPC_GET_VERSION; } else if (strcasecmp(cmdtype, "get_binding_modes") == 0) { type = IPC_GET_BINDING_MODES; + } else if (strcasecmp(cmdtype, "get_bindings") == 0) { + type = IPC_GET_BINDINGS; } else if (strcasecmp(cmdtype, "get_config") == 0) { type = IPC_GET_CONFIG; } else if (strcasecmp(cmdtype, "send_tick") == 0) { diff --git a/swaymsg/swaymsg.1.scd b/swaymsg/swaymsg.1.scd index 1bcf956ad..e56b57132 100644 --- a/swaymsg/swaymsg.1.scd +++ b/swaymsg/swaymsg.1.scd @@ -75,6 +75,10 @@ _swaymsg_ [options...] [message] *get\_binding\_modes* Gets a JSON-encoded list of currently configured binding modes. +*get\_bindings* + Gets a JSON-encoded object mapping binding modes to their keyboard and + mouse bindings. + *get\_config* Gets a JSON-encoded copy of the current configuration.