aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFurkan Sahin <furkan-dev@proton.me>2024-09-23 16:07:01 -0500
committerFurkan Sahin <furkan-dev@proton.me>2024-09-23 16:07:01 -0500
commit2dea242e299bf9a8f48e9f52577e3e4ce78d9f6e (patch)
tree924c09bf41465a7f7be7e8fe1c758712cd3758cc
parent3f6dc0fbe10cd567ab04215da28c95db0fa212fe (diff)
input/keyboard: extend bindsym --to-code to work with duplicate matchesbindsym-tocode-dup-children
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.
-rw-r--r--include/sway/config.h2
-rw-r--r--sway/commands/bind.c110
-rw-r--r--sway/input/keyboard.c29
3 files changed, 74 insertions, 67 deletions
diff --git a/include/sway/config.h b/include/sway/config.h
index 3c380933..399ed6a7 100644
--- a/include/sway/config.h
+++ b/include/sway/config.h
@@ -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;
diff --git a/sway/commands/bind.c b/sway/commands/bind.c
index 15373d5a..ed18b6e4 100644
--- a/sway/commands/bind.c
+++ b/sway/commands/bind.c
@@ -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);
@@ -652,97 +654,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;
- }
-
- 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);
-
- if (matches.count != 1) {
- sway_log(SWAY_INFO, "Unable to convert keysym %" PRIu32 " into"
- " a single keycode (found %d matches)",
- *keysym, matches.count);
- goto error;
+ // 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]);
}
+ }
- xkb_keycode_t *keycode = malloc(sizeof(xkb_keycode_t));
- if (!keycode) {
- sway_log(SWAY_ERROR, "Unable to allocate memory for a keycode");
+ // 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,
+ };
+
+ 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;
}
-
- *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;
}
diff --git a/sway/input/keyboard.c b/sway/input/keyboard.c
index d1823737..3d61464a 100644
--- a/sway/input/keyboard.c
+++ b/sway/input/keyboard.c
@@ -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) {