Add get_bindings IPC interface

The new get_bindings IPC interface (IPC_GET_BINDINGS) allows swaymsg (and
other IPC clients) to interrogate sway's input bindings for all configured
binding modes.

The output of get_bindings is a JSON object mapping each configured binding
mode (e.g. "default", "resize", etc.) to an array of binding objects. The
binding JSON objects are of the same form as those in IPC_EVENT_BINDING.

N.B. a big chunk of code from ipc_event_binding() is moved to a new
ipc_json_describe_binding() function which services both the new
IPC_GET_BINDINGS as well as the existing IPC_EVENT_BINDING commands.

Signed-off-by: Peter Grayson <pete@jpgrayson.net>
This commit is contained in:
Peter Grayson 2019-03-08 12:43:04 -05:00
parent b7fe5097e9
commit 331bcac3ea
10 changed files with 124 additions and 62 deletions

View file

@ -15,6 +15,7 @@ _swaymsg()
'get_bar_config'
'get_version'
'get_binding_modes'
'get_bindings'
'get_config'
'send_tick'
)

View file

@ -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."

View file

@ -23,6 +23,7 @@ types=(
'get_bar_config'
'get_version'
'get_binding_modes'
'get_bindings'
'get_config'
'send_tick'
)

View file

@ -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),

View file

@ -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,

View file

@ -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

View file

@ -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 <wlr/backend/libinput.h>
#include <wlr/types/wlr_box.h>
@ -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;
}

View file

@ -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();

View file

@ -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) {

View file

@ -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.