From c64047157d19e51c35ab66d13a4bb86aafaf3217 Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Thu, 2 Aug 2012 02:14:56 +0200 Subject: [PATCH] =?UTF-8?q?config-wizard:=20use=20the=20level=200=20keysym?= =?UTF-8?q?=20whenever=20it=E2=80=99s=20unambiguous?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit From the code: Try to use the keysym on the first level (lower-case). In case this doesn’t make it ambiguous (think of a keyboard layout having '1' on two different keys, but '!' only on keycode 10), we’ll stick with the keysym of the first level. This reduces a lot of confusion for users who switch keyboard layouts from qwerty to qwertz or other slight variations of qwerty (yes, that happens quite often). --- i3-config-wizard/cfgparse.y | 46 ++++++++++++++++++++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) diff --git a/i3-config-wizard/cfgparse.y b/i3-config-wizard/cfgparse.y index e5a86868..17c3953c 100644 --- a/i3-config-wizard/cfgparse.y +++ b/i3-config-wizard/cfgparse.y @@ -39,6 +39,8 @@ extern FILE *yyin; YY_BUFFER_STATE yy_scan_string(const char *); static struct context *context; +static xcb_connection_t *conn; +static xcb_key_symbols_t *keysyms; /* We don’t need yydebug for now, as we got decent error messages using * yyerror(). Should you ever want to extend the parser, it might be handy @@ -67,6 +69,13 @@ int yywrap() { char *rewrite_binding(const char *bindingline) { char *result = NULL; + conn = xcb_connect(NULL, NULL); + if (conn == NULL || xcb_connection_has_error(conn)) { + fprintf(stderr, "Cannot open display\n"); + exit(1); + } + keysyms = xcb_key_symbols_alloc(conn); + context = calloc(sizeof(struct context), 1); yy_scan_string(bindingline); @@ -81,6 +90,8 @@ char *rewrite_binding(const char *bindingline) { if (context->line_copy) free(context->line_copy); free(context); + xcb_key_symbols_free(keysyms); + xcb_disconnect(conn); return result; } @@ -101,6 +112,28 @@ static char *modifier_to_string(int modifiers) { else return strdup(""); } +/* + * Returns true if sym is bound to any key except for 'except_keycode' on the + * first four layers (normal, shift, mode_switch, mode_switch + shift). + * + */ +static bool keysym_used_on_other_key(KeySym sym, xcb_keycode_t except_keycode) { + xcb_keycode_t i, + min_keycode = xcb_get_setup(conn)->min_keycode, + max_keycode = xcb_get_setup(conn)->max_keycode; + + for (i = min_keycode; i && i <= max_keycode; i++) { + if (i == except_keycode) + continue; + for (int level = 0; level < 4; level++) { + if (xcb_key_symbols_get_keysym(keysyms, i, level) != sym) + continue; + return true; + } + } + return false; +} + %} %error-verbose @@ -139,11 +172,22 @@ bindcode: * different key than the upper-case one (unlikely for letters, but * more likely for special characters). */ level = 1; + + /* Try to use the keysym on the first level (lower-case). In case + * this doesn’t make it ambiguous (think of a keyboard layout + * having '1' on two different keys, but '!' only on keycode 10), + * we’ll stick with the keysym of the first level. + * + * This reduces a lot of confusion for users who switch keyboard + * layouts from qwerty to qwertz or other slight variations of + * qwerty (yes, that happens quite often). */ + KeySym sym = XkbKeycodeToKeysym(dpy, $4, 0, 0); + if (!keysym_used_on_other_key(sym, $4)) + level = 0; } KeySym sym = XkbKeycodeToKeysym(dpy, $4, 0, level); char *str = XKeysymToString(sym); char *modifiers = modifier_to_string($3); - // TODO: modifier to string sasprintf(&(context->result), "bindsym %s%s %s\n", modifiers, str, $6); free(modifiers); }