mirror of
https://github.com/swaywm/sway.git
synced 2024-11-27 18:31:28 +00: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
|
@ -62,7 +62,7 @@ struct sway_binding {
|
|||
char *input;
|
||||
uint32_t flags;
|
||||
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;
|
||||
xkb_layout_index_t group;
|
||||
char *command;
|
||||
|
|
|
@ -14,7 +14,6 @@
|
|||
#include "list.h"
|
||||
#include "log.h"
|
||||
#include "stringop.h"
|
||||
#include "util.h"
|
||||
|
||||
int binding_order = 0;
|
||||
|
||||
|
@ -22,9 +21,12 @@ void free_sway_binding(struct sway_binding *binding) {
|
|||
if (!binding) {
|
||||
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->syms);
|
||||
free(binding->input);
|
||||
free(binding->command);
|
||||
free(binding);
|
||||
|
@ -653,97 +655,81 @@ void seat_execute_command(struct sway_seat *seat, struct sway_binding *binding)
|
|||
* and the total count of matches.
|
||||
*/
|
||||
struct keycode_matches {
|
||||
xkb_keysym_t keysym;
|
||||
xkb_keycode_t keycode;
|
||||
int count;
|
||||
xkb_keysym_t *keysym;
|
||||
list_t *keys;
|
||||
int error;
|
||||
};
|
||||
|
||||
/**
|
||||
* Iterate through keycodes in the keymap to find ones matching
|
||||
* 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_keysym_t keysym = xkb_state_key_get_one_sym(
|
||||
config->keysym_translation_state, keycode);
|
||||
|
||||
struct keycode_matches *matches = data;
|
||||
if (keysym == XKB_KEY_NoSymbol) {
|
||||
return;
|
||||
}
|
||||
|
||||
struct keycode_matches *matches = data;
|
||||
if (matches->keysym == keysym) {
|
||||
matches->keycode = keycode;
|
||||
matches->count++;
|
||||
if (*matches->keysym == keysym) {
|
||||
xkb_keycode_t *new_keycode = malloc(sizeof(keycode));
|
||||
if (!new_keycode) {
|
||||
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) {
|
||||
if ((binding->flags & BINDING_CODE) == 0) {
|
||||
return true;
|
||||
}
|
||||
int keys_len = binding->keys->length;
|
||||
|
||||
switch (binding->type) {
|
||||
// a bindsym to translate
|
||||
case BINDING_KEYSYM:
|
||||
binding->syms = binding->keys;
|
||||
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;
|
||||
// Clean out for retranslation
|
||||
if (binding->type == BINDING_KEYCODE) {
|
||||
for (int i = 0; i < keys_len; i++) {
|
||||
list_free_items_and_destroy(binding->translations[i]);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < binding->syms->length; ++i) {
|
||||
xkb_keysym_t *keysym = binding->syms->items[i];
|
||||
struct keycode_matches matches = get_keycode_for_keysym(*keysym);
|
||||
// Begin translation
|
||||
binding->translations = malloc(keys_len * sizeof(*binding->keys));
|
||||
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) {
|
||||
sway_log(SWAY_INFO, "Unable to convert keysym %" PRIu32 " into"
|
||||
" a single keycode (found %d matches)",
|
||||
*keysym, matches.count);
|
||||
xkb_keymap_key_for_each(
|
||||
xkb_state_get_keymap(config->keysym_translation_state),
|
||||
add_matching_keycodes, &matches);
|
||||
|
||||
if (matches.error) {
|
||||
sway_log(SWAY_INFO, "Unable to convert keysym %" PRIu32 " into", *matches.keysym);
|
||||
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;
|
||||
return true;
|
||||
|
||||
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->keys = binding->syms;
|
||||
binding->syms = NULL;
|
||||
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) {
|
||||
match = true;
|
||||
for (size_t j = 0; j < state->npressed; j++) {
|
||||
uint32_t key = *(uint32_t *)binding->keys->items[j];
|
||||
if (key != state->pressed_keys[j]) {
|
||||
match = false;
|
||||
break;
|
||||
uint32_t key;
|
||||
|
||||
// If translated bindsym, keys are syms not keycodes.
|
||||
// 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) {
|
||||
|
|
Loading…
Reference in a new issue