diff --git a/include/sway/commands.h b/include/sway/commands.h index 6606775aa..332227360 100644 --- a/include/sway/commands.h +++ b/include/sway/commands.h @@ -236,6 +236,7 @@ sway_cmd input_cmd_scroll_method; sway_cmd input_cmd_tap; sway_cmd input_cmd_tap_button_map; sway_cmd input_cmd_xkb_capslock; +sway_cmd input_cmd_xkb_current_layout; sway_cmd input_cmd_xkb_layout; sway_cmd input_cmd_xkb_model; sway_cmd input_cmd_xkb_numlock; diff --git a/sway/commands/input.c b/sway/commands/input.c index c50926a85..91338020a 100644 --- a/sway/commands/input.c +++ b/sway/commands/input.c @@ -38,6 +38,11 @@ static struct cmd_handler input_config_handlers[] = { { "xkb_numlock", input_cmd_xkb_numlock }, }; +// must be in order for the bsearch +static struct cmd_handler input_runtime_handlers[] = { + { "xkb_current_layout", input_cmd_xkb_current_layout }, +}; + struct cmd_results *cmd_input(int argc, char **argv) { struct cmd_results *error = NULL; if ((error = checkarg(argc, "input", EXPECTED_AT_LEAST, 2))) { @@ -51,6 +56,7 @@ struct cmd_results *cmd_input(int argc, char **argv) { return cmd_results_new(CMD_FAILURE, NULL, "Couldn't allocate config"); } + bool apply_config = true; struct cmd_results *res; if (find_handler(argv[1], input_config_handlers, @@ -62,12 +68,22 @@ struct cmd_results *cmd_input(int argc, char **argv) { res = cmd_results_new(CMD_FAILURE, "input", "Can only be used in config file."); } + } else if (find_handler(argv[1], input_runtime_handlers, + sizeof(input_runtime_handlers))) { + apply_config = false; + if (!config->reading) { + res = config_subcommand(argv + 1, argc - 1, + input_runtime_handlers, sizeof(input_runtime_handlers)); + } else { + res = cmd_results_new(CMD_FAILURE, "input", + "Can only be used while sway is running."); + } } else { res = config_subcommand(argv + 1, argc - 1, input_handlers, sizeof(input_handlers)); } - if (!res || res->status == CMD_SUCCESS) { + if (apply_config && (!res || res->status == CMD_SUCCESS)) { struct input_config *ic = store_input_config(config->handler_context.input_config); diff --git a/sway/commands/input/xkb_current_layout.c b/sway/commands/input/xkb_current_layout.c new file mode 100644 index 000000000..14e8216c8 --- /dev/null +++ b/sway/commands/input/xkb_current_layout.c @@ -0,0 +1,47 @@ +#define _XOPEN_SOURCE 700 +#include "sway/config.h" +#include "sway/commands.h" +#include "sway/input/keyboard.h" +#include "log.h" + +static void switch_xkb_layout(struct xkb_state *xkb_state, + xkb_layout_index_t layout_index) { + xkb_mod_mask_t depressed = xkb_state_serialize_mods(xkb_state, XKB_STATE_MODS_DEPRESSED); + xkb_mod_mask_t latched = xkb_state_serialize_mods(xkb_state, XKB_STATE_MODS_LATCHED); + xkb_mod_mask_t locked = xkb_state_serialize_mods(xkb_state, XKB_STATE_MODS_LOCKED); + xkb_state_update_mask(xkb_state, depressed, latched, locked, 0, 0, layout_index); +} + +struct cmd_results *input_cmd_xkb_current_layout(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "xkb_current_layout", EXPECTED_EQUAL_TO, 1))) { + return error; + } + struct input_config *ic = config->handler_context.input_config; + if (!ic) { + return cmd_results_new(CMD_FAILURE, "xkb_current_layout", + "No input device defined."); + } + + int layout_index = atoi(argv[0]); + if (layout_index < 0) { + return cmd_results_new(CMD_INVALID, "xkb_current_layout", + "Layout index cannot be negative"); + } + + struct sway_input_device *input_device = NULL; + bool wildcard = strcmp(ic->identifier, "*") == 0; + wl_list_for_each(input_device, &server.input->devices, link) { + if (strcmp(input_device->identifier, ic->identifier) == 0 + || wildcard) { + if (input_device->wlr_device->type == WLR_INPUT_DEVICE_KEYBOARD) { + switch_xkb_layout(input_device->wlr_device->keyboard->xkb_state, + layout_index); + wlr_log(WLR_DEBUG, "switch-xkb-layout '%s' -> %i", + input_device->identifier, layout_index); + } + } + } + + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/meson.build b/sway/meson.build index cde09a020..f6e04b4a2 100644 --- a/sway/meson.build +++ b/sway/meson.build @@ -139,6 +139,7 @@ sway_sources = files( 'commands/input/tap.c', 'commands/input/tap_button_map.c', 'commands/input/xkb_capslock.c', + 'commands/input/xkb_current_layout.c', 'commands/input/xkb_layout.c', 'commands/input/xkb_model.c', 'commands/input/xkb_numlock.c', diff --git a/sway/sway-input.5.scd b/sway/sway-input.5.scd index 82273ef3d..c41f46e95 100644 --- a/sway/sway-input.5.scd +++ b/sway/sway-input.5.scd @@ -46,6 +46,11 @@ The following commands may only be used in the configuration file. *input* xkb\_numlock enabled|disabled Initially enables or disables NumLock on startup, the default is disabled. +The following commands may only be used while sway is running. + +*input* xkb\_current\_layout + Switches the current layout of the keyboard. + ## MAPPING CONFIGURATION *input* map\_to\_output