Fix bugs relating to hotkeys with modifiers

This commit makes the following changes:
1) Fix a bad check introduced in dee0bfb, which checks the modstate of the
event with the keysym of the switcher, not its modmask:

        modstate & ( switchers[i].keysym )

I think it was broken before as well, a binary AND between the two masks
will not tell much about whether they are equal. Instead, the masks are
now checked for equality after removing LockMask and NumlockMask.

2) Stop binding to AnyModifier when none is used. This conflicts with the case
in which we want to bind different modes to the same key, but different
modifiers.

for example, rofi -key-run F2 -key-ssh alt+F2 -key-window shift+F2

Binding F2 with AnyModifier would prevent alt+F2 and shift+F2 from being used.

3) Remove UngrabKey from x11_grab_key to make the above example possible.
4) Refactor search for any of the global keybindings into function locate_switcher.
This commit is contained in:
Georgios Bitzes 2015-02-16 03:03:26 +02:00
parent faf6a708dc
commit 07df49a5af
2 changed files with 35 additions and 37 deletions

View File

@ -543,6 +543,27 @@ inline static void menu_nav_down ( MenuState *state )
state->filtered_lines - 1, state->selected + 1 ) : 0;
state->update = TRUE;
}
/**
* @param key the Key to match
* @param modstate the modifier state to match
*
* Return the index of the switcher that matches the key combination
* specified by key and modstate. Returns -1 if none was found
*/
extern unsigned int NumlockMask;
static int locate_switcher( KeySym key, unsigned int modstate ) {
// ignore annoying modifiers
unsigned int modstate_filtered = modstate & ~(LockMask | NumlockMask);
for ( unsigned int i = 0; i < num_switchers; i++ ) {
if ( switchers[i].keystr != NULL ) {
if ( ( modstate_filtered == switchers[i].modmask ) &&
switchers[i].keysym == key ) {
return i;
}
}
}
return -1;
}
/**
* @param state Internal state of the menu.
* @param key the Key being pressed.
@ -554,18 +575,7 @@ static void menu_keyboard_navigation ( MenuState *state, KeySym key, unsigned in
{
// pressing one of the global key bindings closes the switcher. this allows fast closing of the
// menu if an item is not selected
for ( unsigned int i = 0; i < num_switchers; i++ ) {
if ( switchers[i].keystr != NULL ) {
if ( ( switchers[i].modmask == AnyModifier || modstate & ( switchers[i].keysym ) ) &&
switchers[i].keysym == key ) {
state->retv = MENU_CANCEL;
state->quit = TRUE;
state->prev_key = key;
return;
}
}
}
if ( key == XK_Escape ) {
if ( locate_switcher( key, modstate ) != -1 || key == XK_Escape ) {
state->retv = MENU_CANCEL;
state->quit = TRUE;
}
@ -1425,19 +1435,15 @@ static void run_switcher ( int do_fork, SwitcherMode mode )
*/
static void handle_keypress ( XEvent *ev )
{
int index = -1;
int index;
KeySym key = XkbKeycodeToKeysym ( display, ev->xkey.keycode, 0, 0 );
for ( unsigned int i = 0; i < num_switchers; i++ ) {
if ( switchers[i].keystr != NULL ) {
if ( ( switchers[i].modmask == AnyModifier || ( ev->xkey.state ) & ( switchers[i].keysym ) ) &&
switchers[i].keysym == key ) {
index = i;
}
}
}
if ( index >= 0 ) {
index = locate_switcher( key, ev->xkey.state );
if( index >= 0 ) {
run_switcher ( TRUE, index );
}
else {
fprintf ( stderr, "Warning: Unhandled keypress in global keyhandler, keycode = %u mask = %u\n", ev->xkey.keycode, ev->xkey.state );
}
}

View File

@ -257,21 +257,14 @@ void x11_grab_key ( Display *display, unsigned int modmask, KeySym key )
Screen *screen = DefaultScreenOfDisplay ( display );
Window root = RootWindow ( display, XScreenNumberOfScreen ( screen ) );
KeyCode keycode = XKeysymToKeycode ( display, key );
XUngrabKey ( display, keycode, AnyModifier, root );
if ( modmask != AnyModifier ) {
// bind to combinations of mod and lock masks, so caps and numlock don't confuse people
XGrabKey ( display, keycode, modmask, root, True, GrabModeAsync, GrabModeAsync );
XGrabKey ( display, keycode, modmask | LockMask, root, True, GrabModeAsync, GrabModeAsync );
// bind to combinations of mod and lock masks, so caps and numlock don't confuse people
XGrabKey ( display, keycode, modmask, root, True, GrabModeAsync, GrabModeAsync );
XGrabKey ( display, keycode, modmask | LockMask, root, True, GrabModeAsync, GrabModeAsync );
if ( NumlockMask ) {
XGrabKey ( display, keycode, modmask | NumlockMask, root, True, GrabModeAsync, GrabModeAsync );
XGrabKey ( display, keycode, modmask | NumlockMask | LockMask, root, True, GrabModeAsync, GrabModeAsync );
}
}
else{
// nice simple single key bind
XGrabKey ( display, keycode, AnyModifier, root, True, GrabModeAsync, GrabModeAsync );
if ( NumlockMask ) {
XGrabKey ( display, keycode, modmask | NumlockMask, root, True, GrabModeAsync, GrabModeAsync );
XGrabKey ( display, keycode, modmask | NumlockMask | LockMask, root, True, GrabModeAsync, GrabModeAsync );
}
}
@ -332,8 +325,7 @@ void x11_parse_key ( char *combo, unsigned int *mod, KeySym *key )
modmask |= Mod5Mask;
}
// If no modifier mask is set, allow any modifier.
*mod = modmask ? modmask : AnyModifier;
*mod = modmask;
// Skip modifier (if exist) and parse key.
char i = strlen ( combo );