mirror of
https://github.com/swaywm/sway.git
synced 2025-01-27 21:38:25 +01:00
input/keyboard: extend bindsym --to-code to work with duplicate matches
This modifies `get_active_binding` to treat bindsym --to-codes separately: per each keysym `i` in `binding->keys`, look through the list of matching keycodes in `binding->translations[i]`. Another solution is to take the cartesian product of all syms and make a binding per each product. This makes retranslation more difficult though because the dups from the old layout have to be cleared out before translating to the new `xkb_layout`. Whether by retaining a parent binding, searching through all bindings for matching `binding->command`, or some other ref count structure, that would introduce more complexity than modifying get_active binding to account for dups. Notice this requires no changes to the existing retranslation logic.
This commit is contained in:
parent
78fa4e9856
commit
4d0d553338
3 changed files with 73 additions and 66 deletions
|
@ -62,7 +62,7 @@ struct sway_binding {
|
||||||
char *input;
|
char *input;
|
||||||
uint32_t flags;
|
uint32_t flags;
|
||||||
list_t *keys; // sorted in ascending order
|
list_t *keys; // sorted in ascending order
|
||||||
list_t *syms; // sorted in ascending order; NULL if BINDING_CODE is not set
|
list_t **translations; // translations[i] = all keycodes for keysym keys[i]
|
||||||
uint32_t modifiers;
|
uint32_t modifiers;
|
||||||
xkb_layout_index_t group;
|
xkb_layout_index_t group;
|
||||||
char *command;
|
char *command;
|
||||||
|
|
|
@ -14,7 +14,6 @@
|
||||||
#include "list.h"
|
#include "list.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "stringop.h"
|
#include "stringop.h"
|
||||||
#include "util.h"
|
|
||||||
|
|
||||||
int binding_order = 0;
|
int binding_order = 0;
|
||||||
|
|
||||||
|
@ -22,9 +21,12 @@ void free_sway_binding(struct sway_binding *binding) {
|
||||||
if (!binding) {
|
if (!binding) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (binding->translations) {
|
||||||
|
for (int i = 0; i < binding->keys->length; i++) {
|
||||||
|
list_free_items_and_destroy(binding->translations[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
list_free_items_and_destroy(binding->keys);
|
list_free_items_and_destroy(binding->keys);
|
||||||
list_free_items_and_destroy(binding->syms);
|
|
||||||
free(binding->input);
|
free(binding->input);
|
||||||
free(binding->command);
|
free(binding->command);
|
||||||
free(binding);
|
free(binding);
|
||||||
|
@ -653,97 +655,81 @@ void seat_execute_command(struct sway_seat *seat, struct sway_binding *binding)
|
||||||
* and the total count of matches.
|
* and the total count of matches.
|
||||||
*/
|
*/
|
||||||
struct keycode_matches {
|
struct keycode_matches {
|
||||||
xkb_keysym_t keysym;
|
xkb_keysym_t *keysym;
|
||||||
xkb_keycode_t keycode;
|
list_t *keys;
|
||||||
int count;
|
int error;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Iterate through keycodes in the keymap to find ones matching
|
* Iterate through keycodes in the keymap to find ones matching
|
||||||
* the specified keysym.
|
* the specified keysym.
|
||||||
*/
|
*/
|
||||||
static void find_keycode(struct xkb_keymap *keymap,
|
static void add_matching_keycodes(struct xkb_keymap *keymap,
|
||||||
xkb_keycode_t keycode, void *data) {
|
xkb_keycode_t keycode, void *data) {
|
||||||
xkb_keysym_t keysym = xkb_state_key_get_one_sym(
|
xkb_keysym_t keysym = xkb_state_key_get_one_sym(
|
||||||
config->keysym_translation_state, keycode);
|
config->keysym_translation_state, keycode);
|
||||||
|
|
||||||
|
struct keycode_matches *matches = data;
|
||||||
if (keysym == XKB_KEY_NoSymbol) {
|
if (keysym == XKB_KEY_NoSymbol) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct keycode_matches *matches = data;
|
if (*matches->keysym == keysym) {
|
||||||
if (matches->keysym == keysym) {
|
xkb_keycode_t *new_keycode = malloc(sizeof(keycode));
|
||||||
matches->keycode = keycode;
|
if (!new_keycode) {
|
||||||
matches->count++;
|
sway_log(SWAY_ERROR, "Unable to allocate memory for keysym");
|
||||||
|
matches->error++;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
*new_keycode = keycode;
|
||||||
|
char buffer[64] = {0};
|
||||||
|
xkb_keysym_get_name(keysym, buffer, sizeof(buffer));
|
||||||
|
sway_log(SWAY_DEBUG, "Translated keysym [%d (%s)] -> keycode [%d (%s)]",
|
||||||
|
keysym, buffer,
|
||||||
|
*new_keycode, xkb_keymap_key_get_name(keymap, *new_keycode));
|
||||||
|
list_add(matches->keys, new_keycode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the keycode for the specified keysym.
|
|
||||||
*/
|
|
||||||
static struct keycode_matches get_keycode_for_keysym(xkb_keysym_t keysym) {
|
|
||||||
struct keycode_matches matches = {
|
|
||||||
.keysym = keysym,
|
|
||||||
.keycode = XKB_KEYCODE_INVALID,
|
|
||||||
.count = 0,
|
|
||||||
};
|
|
||||||
|
|
||||||
xkb_keymap_key_for_each(
|
|
||||||
xkb_state_get_keymap(config->keysym_translation_state),
|
|
||||||
find_keycode, &matches);
|
|
||||||
return matches;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool translate_binding(struct sway_binding *binding) {
|
bool translate_binding(struct sway_binding *binding) {
|
||||||
if ((binding->flags & BINDING_CODE) == 0) {
|
if ((binding->flags & BINDING_CODE) == 0) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
int keys_len = binding->keys->length;
|
||||||
|
|
||||||
switch (binding->type) {
|
// Clean out for retranslation
|
||||||
// a bindsym to translate
|
if (binding->type == BINDING_KEYCODE) {
|
||||||
case BINDING_KEYSYM:
|
for (int i = 0; i < keys_len; i++) {
|
||||||
binding->syms = binding->keys;
|
list_free_items_and_destroy(binding->translations[i]);
|
||||||
binding->keys = create_list();
|
}
|
||||||
break;
|
|
||||||
// a bindsym to re-translate
|
|
||||||
case BINDING_KEYCODE:
|
|
||||||
list_free_items_and_destroy(binding->keys);
|
|
||||||
binding->keys = create_list();
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < binding->syms->length; ++i) {
|
// Begin translation
|
||||||
xkb_keysym_t *keysym = binding->syms->items[i];
|
binding->translations = malloc(keys_len * sizeof(*binding->keys));
|
||||||
struct keycode_matches matches = get_keycode_for_keysym(*keysym);
|
for (int i = 0; i < keys_len; ++i) {
|
||||||
|
struct keycode_matches matches = {
|
||||||
|
.keysym = (xkb_keysym_t*)binding->keys->items[i],
|
||||||
|
.keys = binding->translations[i] = create_list(),
|
||||||
|
.error = 0,
|
||||||
|
};
|
||||||
|
|
||||||
if (matches.count != 1) {
|
xkb_keymap_key_for_each(
|
||||||
sway_log(SWAY_INFO, "Unable to convert keysym %" PRIu32 " into"
|
xkb_state_get_keymap(config->keysym_translation_state),
|
||||||
" a single keycode (found %d matches)",
|
add_matching_keycodes, &matches);
|
||||||
*keysym, matches.count);
|
|
||||||
|
if (matches.error) {
|
||||||
|
sway_log(SWAY_INFO, "Unable to convert keysym %" PRIu32 " into", *matches.keysym);
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
xkb_keycode_t *keycode = malloc(sizeof(xkb_keycode_t));
|
|
||||||
if (!keycode) {
|
|
||||||
sway_log(SWAY_ERROR, "Unable to allocate memory for a keycode");
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
*keycode = matches.keycode;
|
|
||||||
list_add(binding->keys, keycode);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
list_qsort(binding->keys, key_qsort_cmp);
|
|
||||||
binding->type = BINDING_KEYCODE;
|
binding->type = BINDING_KEYCODE;
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
list_free_items_and_destroy(binding->keys);
|
for (int i = 0; i < keys_len; i++) {
|
||||||
|
list_free_items_and_destroy(binding->translations[i]);
|
||||||
|
}
|
||||||
binding->type = BINDING_KEYSYM;
|
binding->type = BINDING_KEYSYM;
|
||||||
binding->keys = binding->syms;
|
|
||||||
binding->syms = NULL;
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -180,10 +180,31 @@ static void get_active_binding(const struct sway_shortcut_state *state,
|
||||||
if (state->npressed == (size_t)binding->keys->length) {
|
if (state->npressed == (size_t)binding->keys->length) {
|
||||||
match = true;
|
match = true;
|
||||||
for (size_t j = 0; j < state->npressed; j++) {
|
for (size_t j = 0; j < state->npressed; j++) {
|
||||||
uint32_t key = *(uint32_t *)binding->keys->items[j];
|
uint32_t key;
|
||||||
if (key != state->pressed_keys[j]) {
|
|
||||||
match = false;
|
// If translated bindsym, keys are syms not keycodes.
|
||||||
break;
|
// keysym j mapped to keycodes translations[j]
|
||||||
|
if (binding->type & BINDING_CODE) {
|
||||||
|
bool dup_match = false;
|
||||||
|
list_t *duplicate_keys = binding->translations[j];
|
||||||
|
for (int k = 0; k < duplicate_keys->length; k++) {
|
||||||
|
key = *(uint32_t *)duplicate_keys->items[k];
|
||||||
|
if (key == state->pressed_keys[j]) {
|
||||||
|
dup_match = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!dup_match) {
|
||||||
|
match = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
key = *(uint32_t *)binding->keys->items[j];
|
||||||
|
if (key != state->pressed_keys[j]) {
|
||||||
|
match = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (binding->keys->length == 1) {
|
} else if (binding->keys->length == 1) {
|
||||||
|
|
Loading…
Reference in a new issue