diff --git a/i3lock.c b/i3lock.c index 30922eb..e3d1e76 100644 --- a/i3lock.c +++ b/i3lock.c @@ -19,6 +19,7 @@ #include #include /* FIXME: can we get rid of this header? */ +#include #include #include #include @@ -51,6 +52,8 @@ static bool modeswitch_active = false; static bool iso_level3_shift_active = false; static bool iso_level5_shift_active = false; static int numlockmask; +static int shiftlockmask; +static int capslockmask; static bool beep = false; static bool debug_mode = false; static bool dpms = false; @@ -282,13 +285,47 @@ static void handle_key_press(xcb_key_press_event_t *event) { if ((input_position + 8) >= sizeof(password)) return; + /* Whether the user currently holds down the shift key. */ + bool shift = (event->state & XCB_MOD_MASK_SHIFT); + + /* Whether Caps Lock (all lowercase alphabetic keys will be replaced by + * their uppercase variant) is active at the moment. */ + bool capslock = (event->state & capslockmask); + + /* Whether Shift Lock (shift state is reversed) is active at the moment. */ + bool shiftlock = (event->state & shiftlockmask); + + /* Whether Caps Lock or Shift Lock is active at the moment. */ + bool lock = (capslock || shiftlock); + + DEBUG("shift = %d, lock = %d, capslock = %d, shiftlock = %d\n", + shift, lock, capslock, shiftlock); + if ((event->state & numlockmask) && xcb_is_keypad_key(sym1)) { /* this key was a keypad key */ - if ((event->state & XCB_MOD_MASK_SHIFT)) + if (shift || shiftlock) sym = sym0; else sym = sym1; } else { - if ((event->state & XCB_MOD_MASK_SHIFT)) + xcb_keysym_t upper, lower; + XConvertCase(sym0, (KeySym*)&lower, (KeySym*)&upper); + DEBUG("sym0 = %c (%d), sym1 = %c (%d), lower = %c (%d), upper = %c (%d)\n", + sym0, sym0, sym1, sym1, lower, lower, upper, upper); + /* If there is no difference between the uppercase and lowercase + * variant of this key, we consider Caps Lock off — it is only relevant + * for alphabetic keys, unlike Shift Lock. */ + if (lower == upper) { + capslock = false; + lock = (capslock || shiftlock); + DEBUG("lower == upper, now shift = %d, lock = %d, capslock = %d, shiftlock = %d\n", + shift, lock, capslock, shiftlock); + } + + /* In two different cases we need to use the uppercase keysym: + * 1) The user holds shift, no lock is active. + * 2) Any of the two locks is active. + */ + if ((shift && !lock) || (!shift && lock)) sym = sym1; else sym = sym0; } @@ -667,6 +704,11 @@ int main(int argc, char *argv[]) { symbols = xcb_key_symbols_alloc(conn); numlockmask = get_mod_mask(conn, symbols, XK_Num_Lock); + shiftlockmask = get_mod_mask(conn, symbols, XK_Shift_Lock); + capslockmask = get_mod_mask(conn, symbols, XK_Caps_Lock); + + DEBUG("shift lock mask = %d\n", shiftlockmask); + DEBUG("caps lock mask = %d\n", capslockmask); if (dpms) dpms_turn_off_screen(conn);