config/input: validate xkb keymap before storing
This allows for an optional validation stage when storing an input config. Currently, only the xkb keymap is validated. If storing the delta input config will result in any invalid xkb keymaps, the input config will not be stored and error will be populated with the first line of the xkbcommon log.
This commit is contained in:
parent
be2d2a299a
commit
5b1a8d62b9
|
@ -581,7 +581,7 @@ struct input_config *new_input_config(const char* identifier);
|
||||||
|
|
||||||
void merge_input_config(struct input_config *dst, struct input_config *src);
|
void merge_input_config(struct input_config *dst, struct input_config *src);
|
||||||
|
|
||||||
struct input_config *store_input_config(struct input_config *ic);
|
struct input_config *store_input_config(struct input_config *ic, char **error);
|
||||||
|
|
||||||
void input_config_fill_rule_names(struct input_config *ic,
|
void input_config_fill_rule_names(struct input_config *ic,
|
||||||
struct xkb_rule_names *rules);
|
struct xkb_rule_names *rules);
|
||||||
|
|
|
@ -88,9 +88,10 @@ struct cmd_results *cmd_input(int argc, char **argv) {
|
||||||
|
|
||||||
if (!res || res->status == CMD_SUCCESS) {
|
if (!res || res->status == CMD_SUCCESS) {
|
||||||
char *error = NULL;
|
char *error = NULL;
|
||||||
struct xkb_keymap *keymap = sway_keyboard_compile_keymap(
|
struct input_config *ic =
|
||||||
config->handler_context.input_config, &error);
|
store_input_config(config->handler_context.input_config, &error);
|
||||||
if (!keymap) {
|
if (!ic) {
|
||||||
|
free_input_config(config->handler_context.input_config);
|
||||||
if (res) {
|
if (res) {
|
||||||
free_cmd_results(res);
|
free_cmd_results(res);
|
||||||
}
|
}
|
||||||
|
@ -99,10 +100,6 @@ struct cmd_results *cmd_input(int argc, char **argv) {
|
||||||
free(error);
|
free(error);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
xkb_keymap_unref(keymap);
|
|
||||||
|
|
||||||
struct input_config *ic =
|
|
||||||
store_input_config(config->handler_context.input_config);
|
|
||||||
|
|
||||||
input_manager_apply_input_config(ic);
|
input_manager_apply_input_config(ic);
|
||||||
retranslate_keysyms(ic);
|
retranslate_keysyms(ic);
|
||||||
|
|
|
@ -101,7 +101,7 @@ static void toggle_wildcard_send_events(int argc, char **argv) {
|
||||||
} else {
|
} else {
|
||||||
toggle_supported_send_events_for_device(ic, input_device);
|
toggle_supported_send_events_for_device(ic, input_device);
|
||||||
}
|
}
|
||||||
store_input_config(ic);
|
store_input_config(ic, NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <float.h>
|
#include <float.h>
|
||||||
#include "sway/config.h"
|
#include "sway/config.h"
|
||||||
|
#include "sway/input/keyboard.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
|
|
||||||
struct input_config *new_input_config(const char* identifier) {
|
struct input_config *new_input_config(const char* identifier) {
|
||||||
|
@ -133,6 +134,49 @@ void merge_input_config(struct input_config *dst, struct input_config *src) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool validate_xkb_merge(struct input_config *dest,
|
||||||
|
struct input_config *src, char **xkb_error) {
|
||||||
|
struct input_config *temp = new_input_config("temp");
|
||||||
|
if (dest) {
|
||||||
|
merge_input_config(temp, dest);
|
||||||
|
}
|
||||||
|
merge_input_config(temp, src);
|
||||||
|
|
||||||
|
struct xkb_keymap *keymap = sway_keyboard_compile_keymap(temp, xkb_error);
|
||||||
|
free_input_config(temp);
|
||||||
|
if (!keymap) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
xkb_keymap_unref(keymap);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool validate_wildcard_on_all(struct input_config *wildcard,
|
||||||
|
char **error) {
|
||||||
|
for (int i = 0; i < config->input_configs->length; i++) {
|
||||||
|
struct input_config *ic = config->input_configs->items[i];
|
||||||
|
if (strcmp(wildcard->identifier, ic->identifier) != 0) {
|
||||||
|
sway_log(SWAY_DEBUG, "Validating xkb merge of * on %s",
|
||||||
|
ic->identifier);
|
||||||
|
if (!validate_xkb_merge(ic, wildcard, error)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < config->input_type_configs->length; i++) {
|
||||||
|
struct input_config *ic = config->input_type_configs->items[i];
|
||||||
|
sway_log(SWAY_DEBUG, "Validating xkb merge of * config on %s",
|
||||||
|
ic->identifier);
|
||||||
|
if (!validate_xkb_merge(ic, wildcard, error)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
static void merge_wildcard_on_all(struct input_config *wildcard) {
|
static void merge_wildcard_on_all(struct input_config *wildcard) {
|
||||||
for (int i = 0; i < config->input_configs->length; i++) {
|
for (int i = 0; i < config->input_configs->length; i++) {
|
||||||
struct input_config *ic = config->input_configs->items[i];
|
struct input_config *ic = config->input_configs->items[i];
|
||||||
|
@ -144,11 +188,28 @@ static void merge_wildcard_on_all(struct input_config *wildcard) {
|
||||||
|
|
||||||
for (int i = 0; i < config->input_type_configs->length; i++) {
|
for (int i = 0; i < config->input_type_configs->length; i++) {
|
||||||
struct input_config *ic = config->input_type_configs->items[i];
|
struct input_config *ic = config->input_type_configs->items[i];
|
||||||
if (strcmp(wildcard->identifier, ic->identifier) != 0) {
|
sway_log(SWAY_DEBUG, "Merging input * config on %s", ic->identifier);
|
||||||
sway_log(SWAY_DEBUG, "Merging input * config on %s", ic->identifier);
|
merge_input_config(ic, wildcard);
|
||||||
merge_input_config(ic, wildcard);
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool validate_type_on_existing(struct input_config *type_wildcard,
|
||||||
|
char **error) {
|
||||||
|
for (int i = 0; i < config->input_configs->length; i++) {
|
||||||
|
struct input_config *ic = config->input_configs->items[i];
|
||||||
|
if (ic->input_type == NULL) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strcmp(ic->input_type, type_wildcard->identifier + 5) == 0) {
|
||||||
|
sway_log(SWAY_DEBUG, "Validating merge of %s on %s",
|
||||||
|
type_wildcard->identifier, ic->identifier);
|
||||||
|
if (!validate_xkb_merge(ic, type_wildcard, error)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void merge_type_on_existing(struct input_config *type_wildcard) {
|
static void merge_type_on_existing(struct input_config *type_wildcard) {
|
||||||
|
@ -167,44 +228,59 @@ static void merge_type_on_existing(struct input_config *type_wildcard) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct input_config *store_input_config(struct input_config *ic) {
|
struct input_config *store_input_config(struct input_config *ic,
|
||||||
|
char **error) {
|
||||||
bool wildcard = strcmp(ic->identifier, "*") == 0;
|
bool wildcard = strcmp(ic->identifier, "*") == 0;
|
||||||
|
if (wildcard && error && !validate_wildcard_on_all(ic, error)) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool type = strncmp(ic->identifier, "type:", strlen("type:")) == 0;
|
||||||
|
if (type && error && !validate_type_on_existing(ic, error)) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
list_t *config_list = type ? config->input_type_configs
|
||||||
|
: config->input_configs;
|
||||||
|
|
||||||
|
struct input_config *current = NULL;
|
||||||
|
bool new_current = false;
|
||||||
|
|
||||||
|
int i = list_seq_find(config_list, input_identifier_cmp, ic->identifier);
|
||||||
|
if (i >= 0) {
|
||||||
|
current = config_list->items[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
i = list_seq_find(config->input_configs, input_identifier_cmp, "*");
|
||||||
|
if (!current && i >= 0) {
|
||||||
|
current = new_input_config(ic->identifier);
|
||||||
|
merge_input_config(current, config->input_configs->items[i]);
|
||||||
|
new_current = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (error && !validate_xkb_merge(current, ic, error)) {
|
||||||
|
if (new_current) {
|
||||||
|
free_input_config(current);
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
if (wildcard) {
|
if (wildcard) {
|
||||||
merge_wildcard_on_all(ic);
|
merge_wildcard_on_all(ic);
|
||||||
}
|
}
|
||||||
|
|
||||||
list_t *config_list = NULL;
|
if (type) {
|
||||||
if (strncmp(ic->identifier, "type:", 5) == 0) {
|
|
||||||
config_list = config->input_type_configs;
|
|
||||||
merge_type_on_existing(ic);
|
merge_type_on_existing(ic);
|
||||||
} else {
|
|
||||||
config_list = config->input_configs;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int i = list_seq_find(config_list, input_identifier_cmp,
|
if (current) {
|
||||||
ic->identifier);
|
|
||||||
if (i >= 0) {
|
|
||||||
sway_log(SWAY_DEBUG, "Merging on top of existing input config");
|
|
||||||
struct input_config *current = config_list->items[i];
|
|
||||||
merge_input_config(current, ic);
|
merge_input_config(current, ic);
|
||||||
free_input_config(ic);
|
free_input_config(ic);
|
||||||
ic = current;
|
ic = current;
|
||||||
} else if (!wildcard) {
|
}
|
||||||
sway_log(SWAY_DEBUG, "Adding non-wildcard input config");
|
|
||||||
i = list_seq_find(config->input_configs, input_identifier_cmp, "*");
|
if (!current || new_current) {
|
||||||
if (i >= 0) {
|
|
||||||
sway_log(SWAY_DEBUG, "Merging on top of input * config");
|
|
||||||
struct input_config *current = new_input_config(ic->identifier);
|
|
||||||
merge_input_config(current, config->input_configs->items[i]);
|
|
||||||
merge_input_config(current, ic);
|
|
||||||
free_input_config(ic);
|
|
||||||
ic = current;
|
|
||||||
}
|
|
||||||
list_add(config_list, ic);
|
list_add(config_list, ic);
|
||||||
} else {
|
|
||||||
// New wildcard config. Just add it
|
|
||||||
sway_log(SWAY_DEBUG, "Adding input * config");
|
|
||||||
list_add(config->input_configs, ic);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sway_log(SWAY_DEBUG, "Config stored for input %s", ic->identifier);
|
sway_log(SWAY_DEBUG, "Config stored for input %s", ic->identifier);
|
||||||
|
|
Loading…
Reference in a new issue