config-wizard: use the level 0 keysym whenever it’s unambiguous

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).
This commit is contained in:
Michael Stapelberg 2012-08-02 02:14:56 +02:00
parent 875130e7e8
commit c64047157d
1 changed files with 45 additions and 1 deletions

View File

@ -39,6 +39,8 @@ extern FILE *yyin;
YY_BUFFER_STATE yy_scan_string(const char *); YY_BUFFER_STATE yy_scan_string(const char *);
static struct context *context; static struct context *context;
static xcb_connection_t *conn;
static xcb_key_symbols_t *keysyms;
/* We dont need yydebug for now, as we got decent error messages using /* We dont need yydebug for now, as we got decent error messages using
* yyerror(). Should you ever want to extend the parser, it might be handy * 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 *rewrite_binding(const char *bindingline) {
char *result = NULL; 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); context = calloc(sizeof(struct context), 1);
yy_scan_string(bindingline); yy_scan_string(bindingline);
@ -81,6 +90,8 @@ char *rewrite_binding(const char *bindingline) {
if (context->line_copy) if (context->line_copy)
free(context->line_copy); free(context->line_copy);
free(context); free(context);
xcb_key_symbols_free(keysyms);
xcb_disconnect(conn);
return result; return result;
} }
@ -101,6 +112,28 @@ static char *modifier_to_string(int modifiers) {
else return strdup(""); 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 %error-verbose
@ -139,11 +172,22 @@ bindcode:
* different key than the upper-case one (unlikely for letters, but * different key than the upper-case one (unlikely for letters, but
* more likely for special characters). */ * more likely for special characters). */
level = 1; level = 1;
/* Try to use the keysym on the first level (lower-case). In case
* this doesnt make it ambiguous (think of a keyboard layout
* having '1' on two different keys, but '!' only on keycode 10),
* well 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); KeySym sym = XkbKeycodeToKeysym(dpy, $4, 0, level);
char *str = XKeysymToString(sym); char *str = XKeysymToString(sym);
char *modifiers = modifier_to_string($<number>3); char *modifiers = modifier_to_string($<number>3);
// TODO: modifier to string
sasprintf(&(context->result), "bindsym %s%s %s\n", modifiers, str, $<string>6); sasprintf(&(context->result), "bindsym %s%s %s\n", modifiers, str, $<string>6);
free(modifiers); free(modifiers);
} }