diff options
-rw-r--r-- | include/sway/commands.h | 1 | ||||
-rw-r--r-- | include/sway/config.h | 3 | ||||
-rw-r--r-- | sway/commands/input.c | 5 | ||||
-rw-r--r-- | sway/commands/input/xkb_file.c | 28 | ||||
-rw-r--r-- | sway/config/input.c | 9 | ||||
-rw-r--r-- | sway/input/keyboard.c | 47 | ||||
-rw-r--r-- | sway/meson.build | 1 | ||||
-rw-r--r-- | sway/sway-input.5.scd | 5 |
8 files changed, 90 insertions, 9 deletions
diff --git a/include/sway/commands.h b/include/sway/commands.h index ddee2994..7ff3b651 100644 --- a/include/sway/commands.h +++ b/include/sway/commands.h | |||
@@ -257,6 +257,7 @@ sway_cmd input_cmd_scroll_method; | |||
257 | sway_cmd input_cmd_tap; | 257 | sway_cmd input_cmd_tap; |
258 | sway_cmd input_cmd_tap_button_map; | 258 | sway_cmd input_cmd_tap_button_map; |
259 | sway_cmd input_cmd_xkb_capslock; | 259 | sway_cmd input_cmd_xkb_capslock; |
260 | sway_cmd input_cmd_xkb_file; | ||
260 | sway_cmd input_cmd_xkb_layout; | 261 | sway_cmd input_cmd_xkb_layout; |
261 | sway_cmd input_cmd_xkb_model; | 262 | sway_cmd input_cmd_xkb_model; |
262 | sway_cmd input_cmd_xkb_numlock; | 263 | sway_cmd input_cmd_xkb_numlock; |
diff --git a/include/sway/config.h b/include/sway/config.h index c5558c0d..f1426453 100644 --- a/include/sway/config.h +++ b/include/sway/config.h | |||
@@ -138,6 +138,9 @@ struct input_config { | |||
138 | char *xkb_options; | 138 | char *xkb_options; |
139 | char *xkb_rules; | 139 | char *xkb_rules; |
140 | char *xkb_variant; | 140 | char *xkb_variant; |
141 | char *xkb_file; | ||
142 | |||
143 | bool xkb_file_is_set; | ||
141 | 144 | ||
142 | int xkb_numlock; | 145 | int xkb_numlock; |
143 | int xkb_capslock; | 146 | int xkb_capslock; |
diff --git a/sway/commands/input.c b/sway/commands/input.c index 588ef2d5..2289ede5 100644 --- a/sway/commands/input.c +++ b/sway/commands/input.c | |||
@@ -28,6 +28,7 @@ static struct cmd_handler input_handlers[] = { | |||
28 | { "scroll_method", input_cmd_scroll_method }, | 28 | { "scroll_method", input_cmd_scroll_method }, |
29 | { "tap", input_cmd_tap }, | 29 | { "tap", input_cmd_tap }, |
30 | { "tap_button_map", input_cmd_tap_button_map }, | 30 | { "tap_button_map", input_cmd_tap_button_map }, |
31 | { "xkb_file", input_cmd_xkb_file }, | ||
31 | { "xkb_layout", input_cmd_xkb_layout }, | 32 | { "xkb_layout", input_cmd_xkb_layout }, |
32 | { "xkb_model", input_cmd_xkb_model }, | 33 | { "xkb_model", input_cmd_xkb_model }, |
33 | { "xkb_options", input_cmd_xkb_options }, | 34 | { "xkb_options", input_cmd_xkb_options }, |
@@ -48,8 +49,8 @@ static struct cmd_handler input_config_handlers[] = { | |||
48 | static void retranslate_keysyms(struct input_config *input_config) { | 49 | static void retranslate_keysyms(struct input_config *input_config) { |
49 | for (int i = 0; i < config->input_configs->length; ++i) { | 50 | for (int i = 0; i < config->input_configs->length; ++i) { |
50 | struct input_config *ic = config->input_configs->items[i]; | 51 | struct input_config *ic = config->input_configs->items[i]; |
51 | if (ic->xkb_layout) { | 52 | if (ic->xkb_layout || ic->xkb_file) { |
52 | // this is the first config with xkb_layout | 53 | // this is the first config with xkb_layout or xkb_file |
53 | if (ic->identifier == input_config->identifier) { | 54 | if (ic->identifier == input_config->identifier) { |
54 | translate_keysyms(ic); | 55 | translate_keysyms(ic); |
55 | } | 56 | } |
diff --git a/sway/commands/input/xkb_file.c b/sway/commands/input/xkb_file.c new file mode 100644 index 00000000..063f544d --- /dev/null +++ b/sway/commands/input/xkb_file.c | |||
@@ -0,0 +1,28 @@ | |||
1 | #define _POSIX_C_SOURCE 200809L | ||
2 | #include "sway/config.h" | ||
3 | #include "sway/commands.h" | ||
4 | #include "sway/input/input-manager.h" | ||
5 | #include "log.h" | ||
6 | |||
7 | struct cmd_results *input_cmd_xkb_file(int argc, char **argv) { | ||
8 | struct cmd_results *error = NULL; | ||
9 | if ((error = checkarg(argc, "xkb_file", EXPECTED_EQUAL_TO, 1))) { | ||
10 | return error; | ||
11 | } | ||
12 | struct input_config *ic = config->handler_context.input_config; | ||
13 | if (!ic) { | ||
14 | return cmd_results_new(CMD_FAILURE, "No input device defined."); | ||
15 | } | ||
16 | |||
17 | if (strcmp(argv[0], "-") == 0) { | ||
18 | free(ic->xkb_file); | ||
19 | ic->xkb_file = NULL; | ||
20 | } else { | ||
21 | ic->xkb_file = strdup(argv[0]); | ||
22 | } | ||
23 | ic->xkb_file_is_set = true; | ||
24 | |||
25 | sway_log(SWAY_DEBUG, "set-xkb_file for config: %s file: %s", | ||
26 | ic->identifier, ic->xkb_file); | ||
27 | return cmd_results_new(CMD_SUCCESS, NULL); | ||
28 | } | ||
diff --git a/sway/config/input.c b/sway/config/input.c index b5be4f26..ad4a64ee 100644 --- a/sway/config/input.c +++ b/sway/config/input.c | |||
@@ -39,6 +39,7 @@ struct input_config *new_input_config(const char* identifier) { | |||
39 | input->repeat_rate = INT_MIN; | 39 | input->repeat_rate = INT_MIN; |
40 | input->xkb_numlock = INT_MIN; | 40 | input->xkb_numlock = INT_MIN; |
41 | input->xkb_capslock = INT_MIN; | 41 | input->xkb_capslock = INT_MIN; |
42 | input->xkb_file_is_set = false; | ||
42 | 43 | ||
43 | return input; | 44 | return input; |
44 | } | 45 | } |
@@ -95,6 +96,11 @@ void merge_input_config(struct input_config *dst, struct input_config *src) { | |||
95 | if (src->tap_button_map != INT_MIN) { | 96 | if (src->tap_button_map != INT_MIN) { |
96 | dst->tap_button_map = src->tap_button_map; | 97 | dst->tap_button_map = src->tap_button_map; |
97 | } | 98 | } |
99 | if (src->xkb_file_is_set) { | ||
100 | free(dst->xkb_file); | ||
101 | dst->xkb_file = src->xkb_file ? strdup(src->xkb_file) : NULL; | ||
102 | dst->xkb_file_is_set = dst->xkb_file != NULL; | ||
103 | } | ||
98 | if (src->xkb_layout) { | 104 | if (src->xkb_layout) { |
99 | free(dst->xkb_layout); | 105 | free(dst->xkb_layout); |
100 | dst->xkb_layout = strdup(src->xkb_layout); | 106 | dst->xkb_layout = strdup(src->xkb_layout); |
@@ -284,6 +290,8 @@ struct input_config *store_input_config(struct input_config *ic, | |||
284 | ic = current; | 290 | ic = current; |
285 | } | 291 | } |
286 | 292 | ||
293 | ic->xkb_file_is_set = ic->xkb_file != NULL; | ||
294 | |||
287 | if (!current || new_current) { | 295 | if (!current || new_current) { |
288 | list_add(config_list, ic); | 296 | list_add(config_list, ic); |
289 | } | 297 | } |
@@ -307,6 +315,7 @@ void free_input_config(struct input_config *ic) { | |||
307 | return; | 315 | return; |
308 | } | 316 | } |
309 | free(ic->identifier); | 317 | free(ic->identifier); |
318 | free(ic->xkb_file); | ||
310 | free(ic->xkb_layout); | 319 | free(ic->xkb_layout); |
311 | free(ic->xkb_model); | 320 | free(ic->xkb_model); |
312 | free(ic->xkb_options); | 321 | free(ic->xkb_options); |
diff --git a/sway/input/keyboard.c b/sway/input/keyboard.c index ef20a3cf..1f7ed849 100644 --- a/sway/input/keyboard.c +++ b/sway/input/keyboard.c | |||
@@ -534,11 +534,6 @@ static void handle_xkb_context_log(struct xkb_context *context, | |||
534 | 534 | ||
535 | struct xkb_keymap *sway_keyboard_compile_keymap(struct input_config *ic, | 535 | struct xkb_keymap *sway_keyboard_compile_keymap(struct input_config *ic, |
536 | char **error) { | 536 | char **error) { |
537 | struct xkb_rule_names rules = {0}; | ||
538 | if (ic) { | ||
539 | input_config_fill_rule_names(ic, &rules); | ||
540 | } | ||
541 | |||
542 | struct xkb_context *context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); | 537 | struct xkb_context *context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); |
543 | if (!sway_assert(context, "cannot create XKB context")) { | 538 | if (!sway_assert(context, "cannot create XKB context")) { |
544 | return NULL; | 539 | return NULL; |
@@ -546,8 +541,46 @@ struct xkb_keymap *sway_keyboard_compile_keymap(struct input_config *ic, | |||
546 | xkb_context_set_user_data(context, error); | 541 | xkb_context_set_user_data(context, error); |
547 | xkb_context_set_log_fn(context, handle_xkb_context_log); | 542 | xkb_context_set_log_fn(context, handle_xkb_context_log); |
548 | 543 | ||
549 | struct xkb_keymap *keymap = | 544 | struct xkb_keymap *keymap = NULL; |
550 | xkb_keymap_new_from_names(context, &rules, XKB_KEYMAP_COMPILE_NO_FLAGS); | 545 | |
546 | if (ic && ic->xkb_file) { | ||
547 | FILE *keymap_file = fopen(ic->xkb_file, "r"); | ||
548 | if (!keymap_file) { | ||
549 | if (error) { | ||
550 | size_t len = snprintf(NULL, 0, "cannot read XKB file %s: %s", | ||
551 | ic->xkb_file, strerror(errno)) + 1; | ||
552 | *error = malloc(len); | ||
553 | if (*error) { | ||
554 | snprintf(*error, len, "cannot read XKB file %s: %s", | ||
555 | ic->xkb_file, strerror(errno)); | ||
556 | } else { | ||
557 | sway_log_errno(SWAY_ERROR, "cannot read XKB file %s: %s", | ||
558 | ic->xkb_file, strerror(errno)); | ||
559 | } | ||
560 | } else { | ||
561 | sway_log_errno(SWAY_ERROR, "cannot read XKB file %s: %s", | ||
562 | ic->xkb_file, strerror(errno)); | ||
563 | } | ||
564 | goto cleanup; | ||
565 | } | ||
566 | |||
567 | keymap = xkb_keymap_new_from_file(context, keymap_file, | ||
568 | XKB_KEYMAP_FORMAT_TEXT_V1, XKB_KEYMAP_COMPILE_NO_FLAGS); | ||
569 | |||
570 | if (!fclose(keymap_file)) { | ||
571 | sway_log_errno(SWAY_ERROR, "cannot close XKB file %s: %s", | ||
572 | ic->xkb_file, strerror(errno)); | ||
573 | } | ||
574 | } else { | ||
575 | struct xkb_rule_names rules = {0}; | ||
576 | if (ic) { | ||
577 | input_config_fill_rule_names(ic, &rules); | ||
578 | } | ||
579 | keymap = xkb_keymap_new_from_names(context, &rules, | ||
580 | XKB_KEYMAP_COMPILE_NO_FLAGS); | ||
581 | } | ||
582 | |||
583 | cleanup: | ||
551 | xkb_context_set_user_data(context, NULL); | 584 | xkb_context_set_user_data(context, NULL); |
552 | xkb_context_unref(context); | 585 | xkb_context_unref(context); |
553 | return keymap; | 586 | return keymap; |
diff --git a/sway/meson.build b/sway/meson.build index c60be008..934dbe68 100644 --- a/sway/meson.build +++ b/sway/meson.build | |||
@@ -160,6 +160,7 @@ sway_sources = files( | |||
160 | 'commands/input/tap.c', | 160 | 'commands/input/tap.c', |
161 | 'commands/input/tap_button_map.c', | 161 | 'commands/input/tap_button_map.c', |
162 | 'commands/input/xkb_capslock.c', | 162 | 'commands/input/xkb_capslock.c', |
163 | 'commands/input/xkb_file.c', | ||
163 | 'commands/input/xkb_layout.c', | 164 | 'commands/input/xkb_layout.c', |
164 | 'commands/input/xkb_model.c', | 165 | 'commands/input/xkb_model.c', |
165 | 'commands/input/xkb_numlock.c', | 166 | 'commands/input/xkb_numlock.c', |
diff --git a/sway/sway-input.5.scd b/sway/sway-input.5.scd index 4fb14fd2..9a9c5c4c 100644 --- a/sway/sway-input.5.scd +++ b/sway/sway-input.5.scd | |||
@@ -44,6 +44,11 @@ on top of the existing device configurations. | |||
44 | For more information on these xkb configuration options, see | 44 | For more information on these xkb configuration options, see |
45 | *xkeyboard-config*(7). | 45 | *xkeyboard-config*(7). |
46 | 46 | ||
47 | *input* <identifier> xkb_file <file_name> | ||
48 | Sets all xkb configurations from a complete .xkb file. This file can be | ||
49 | dumped from _xkbcomp $DISPLAY keymap.xkb_. This setting overrides | ||
50 | xkb_layout, xkb_model, xkb_options, xkb_rules, and xkb_variant settings. | ||
51 | |||
47 | *input* <identifier> xkb_layout <layout_name> | 52 | *input* <identifier> xkb_layout <layout_name> |
48 | Sets the layout of the keyboard like _us_ or _de_. | 53 | Sets the layout of the keyboard like _us_ or _de_. |
49 | 54 | ||