From 8e153411b507b499e3bd12bbc1ca67e592cb4657 Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Sat, 29 Oct 2011 23:23:41 +0100 Subject: [PATCH] Correctly handle Mode_switch/ISO_Level3_Shift (Thanks bacardi55) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I tested this with the following experiment: $ setxkbmap 'us(intl)' $ xmodmap ~/configfiles/midna/Xmodmap $ xmodmap -e 'keycode 38 = a A adiaeresis Adiaeresis o O' $ xmodmap -e 'keycode 49 = ISO_Level3_Shift ISO_Level3_Shift ISO_Level3_Shift ISO_Level3_Shift' Then, Mode_switch + a yields ä, but ` + a yields o. In i3lock, these were swapped (Mode_switch + a yielded o, while ä was not reachable at all). The comment in the code explains it (See http://code.stapelberg.de/git/configfiles for the Xmodmap) --- i3lock.c | 53 +++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 45 insertions(+), 8 deletions(-) diff --git a/i3lock.c b/i3lock.c index 55cedba..0298e1e 100644 --- a/i3lock.c +++ b/i3lock.c @@ -42,6 +42,7 @@ static int input_position = 0; /* holds the password you enter (in UTF-8) */ static char password[512]; static bool modeswitch_active = false; +static bool iso_level3_shift_active = false; static int modeswitchmask; static int numlockmask; static bool beep = false; @@ -122,6 +123,8 @@ static void handle_key_release(xcb_key_release_event_t *event) { if (sym == XK_Mode_switch) { //printf("Mode switch disabled\n"); modeswitch_active = false; + } else if (sym == XK_ISO_Level3_Shift) { + iso_level3_shift_active = false; } } @@ -135,19 +138,53 @@ static void handle_key_press(xcb_key_press_event_t *event) { //printf("keypress %d, state raw = %d\n", event->detail, event->state); xcb_keysym_t sym0, sym1, sym; - if (modeswitch_active) { - sym0 = xcb_key_press_lookup_keysym(symbols, event, 4); - sym1 = xcb_key_press_lookup_keysym(symbols, event, 5); - } else { - sym0 = xcb_key_press_lookup_keysym(symbols, event, 0); - sym1 = xcb_key_press_lookup_keysym(symbols, event, 1); - } + /* For each keycode, there is a list of symbols. The list could look like this: + * $ xmodmap -pke | grep 'keycode 38' + * keycode 38 = a A adiaeresis Adiaeresis o O + * In non-X11 terminology, the symbols for the keycode 38 (the key labeled + * with "a" on my keyboard) are "a A ä Ä o O". + * Another form to display the same information is using xkbcomp: + * $ xkbcomp $DISPLAY /tmp/xkb.dump + * Then open /tmp/xkb.dump and search for '\' (in VIM regexp-language): + * + * symbols[Group1]= [ a, A, o, O ], + * symbols[Group2]= [ adiaeresis, Adiaeresis ] + * + * So there are two *groups*, one containing 'a A' and one containing 'ä + * Ä'. You can use Mode_switch to switch between these groups. You can use + * ISO_Level3_Shift to reach the 'o O' part of the first group (it’s the + * same group, just an even higher shift level). + * + * So, using the "logical" XKB information, the following lookup will be + * performed: + * + * Neither Mode_switch nor ISO_Level3_Shift active: group 1, column 0 and 1 + * Mode_switch active: group 2, column 0 and 1 + * ISO_Level3_Shift active: group 1, column 2 and 3 + * + * Using the column index which xcb_key_press_lookup_keysym uses (and + * xmodmap prints out), the following lookup will be performed: + * + * Neither Mode_switch nor ISO_Level3_Shift active: column 0 and 1 + * Mode_switch active: column 2 and 3 + * ISO_Level3_Shift active: column 4 and 5 + */ + int base_column = 0; + if (modeswitch_active) + base_column = 2; + if (iso_level3_shift_active) + base_column = 4; + sym0 = xcb_key_press_lookup_keysym(symbols, event, base_column); + sym1 = xcb_key_press_lookup_keysym(symbols, event, base_column + 1); switch (sym0) { case XK_Mode_switch: //printf("Mode switch enabled\n"); modeswitch_active = true; return; - + case XK_ISO_Level3_Shift: + DEBUG("ISO_Level3_Shift enabled\n"); + iso_level3_shift_active = true; + return; case XK_Return: case XK_KP_Enter: input_done();