From 266ee5efb781e0e086316163720127767291d4b4 Mon Sep 17 00:00:00 2001 From: Dave Davenport Date: Fri, 20 Nov 2015 20:53:27 +0100 Subject: [PATCH] Hopefully fix for #268 --- include/textbox.h | 2 +- source/keyb.c | 5 +- source/rofi.c | 98 +++++++++++++++------------- source/textbox.c | 154 +++++++++++++++++++++----------------------- source/x11-helper.c | 34 +++++++--- 5 files changed, 156 insertions(+), 137 deletions(-) diff --git a/include/textbox.h b/include/textbox.h index fbf6e0a9..0e46db04 100644 --- a/include/textbox.h +++ b/include/textbox.h @@ -100,7 +100,7 @@ void textbox_draw ( textbox *tb, cairo_t *draw ); * * @returns if the key was handled (1), unhandled(0) or handled and return was pressed (-1) */ -int textbox_keypress ( textbox *tb, XIC xic, XEvent *ev ); +int textbox_keypress ( textbox *tb, XEvent *ev, char *pad, KeySym key, Status stat ); /** * @param tb Handle to the textbox diff --git a/source/keyb.c b/source/keyb.c index 4b5ae350..975e16bd 100644 --- a/source/keyb.c +++ b/source/keyb.c @@ -30,6 +30,9 @@ ActionBindingEntry abe[NUM_ABE]; // Use this so we can ignore numlock mask. // TODO: maybe use something smarter here.. extern unsigned int NumlockMask; +extern unsigned int AltMask; +extern unsigned int SuperRMask; +extern unsigned int SuperLMask; /** * LIST OF DEFAULT SETTINGS @@ -142,7 +145,7 @@ int abe_test_action ( KeyBindingAction action, unsigned int mask, KeySym key ) if ( kb->keysym == key ) { // Bits 13 and 14 of the modifiers together are the group number, and // should be ignored when looking up key bindings - if ( ( mask & ~( LockMask | NumlockMask | ( 1 << 13 ) | ( 1 << 14 ) ) ) == kb->modmask ) { + if ( ( mask & ( AltMask | ControlMask | SuperRMask | SuperLMask ) ) == kb->modmask ) { return TRUE; } } diff --git a/source/rofi.c b/source/rofi.c index e21c80eb..461d4b13 100644 --- a/source/rofi.c +++ b/source/rofi.c @@ -1468,52 +1468,61 @@ MenuReturn menu ( Switcher *sw, char **input, char *prompt, unsigned int *select // Key press event. else if ( ev.type == KeyPress ) { do { - KeySym key = XkbKeycodeToKeysym ( display, ev.xkey.keycode, 0, 0 ); + // This is needed for letting the Input Method handle combined keys. + // E.g. `e into è + if ( XFilterEvent ( &ev, main_window ) ) { + continue; + } + Status stat; + char pad[32]; + KeySym key;// = XkbKeycodeToKeysym ( display, ev.xkey.keycode, 0, 0 ); + int len = Xutf8LookupString ( xic, &( ev.xkey ), pad, sizeof ( pad ), &key, &stat ); + pad[len] = 0; - // Handling of paste - if ( abe_test_action ( PASTE_PRIMARY, ev.xkey.state, key ) ) { - XConvertSelection ( display, XA_PRIMARY, netatoms[UTF8_STRING], netatoms[UTF8_STRING], main_window, CurrentTime ); - } - else if ( abe_test_action ( PASTE_SECONDARY, ev.xkey.state, key ) ) { - XConvertSelection ( display, netatoms[CLIPBOARD], netatoms[UTF8_STRING], netatoms[UTF8_STRING], main_window, - CurrentTime ); - } - else if ( abe_test_action ( MODE_PREVIOUS, ev.xkey.state, key ) ) { - state.retv = MENU_PREVIOUS; - *( state.selected_line ) = 0; - state.quit = TRUE; - break; - } - // Menu navigation. - else if ( abe_test_action ( MODE_NEXT, ev.xkey.state, key ) ) { - state.retv = MENU_NEXT; - *( state.selected_line ) = 0; - state.quit = TRUE; - break; - } - // Toggle case sensitivity. - else if ( abe_test_action ( TOGGLE_CASE_SENSITIVITY, ev.xkey.state, key ) ) { - config.case_sensitive = !config.case_sensitive; - *( state.selected_line ) = 0; - state.refilter = TRUE; - state.update = TRUE; - if ( config.case_sensitive ) { - textbox_text ( state.case_indicator, "*" ); + if ( stat == XLookupKeySym || stat == XLookupBoth ) { + // Handling of paste + if ( abe_test_action ( PASTE_PRIMARY, ev.xkey.state, key ) ) { + XConvertSelection ( display, XA_PRIMARY, netatoms[UTF8_STRING], netatoms[UTF8_STRING], main_window, CurrentTime ); } - else { - textbox_text ( state.case_indicator, " " ); + else if ( abe_test_action ( PASTE_SECONDARY, ev.xkey.state, key ) ) { + XConvertSelection ( display, netatoms[CLIPBOARD], netatoms[UTF8_STRING], netatoms[UTF8_STRING], main_window, + CurrentTime ); } - } - // Special delete entry command. - else if ( abe_test_action ( DELETE_ENTRY, ev.xkey.state, key ) ) { - if ( state.selected < state.filtered_lines ) { - *( state.selected_line ) = state.line_map[state.selected]; - state.retv = MENU_ENTRY_DELETE; + else if ( abe_test_action ( MODE_PREVIOUS, ev.xkey.state, key ) ) { + state.retv = MENU_PREVIOUS; + *( state.selected_line ) = 0; state.quit = TRUE; break; } - } - else{ + // Menu navigation. + else if ( abe_test_action ( MODE_NEXT, ev.xkey.state, key ) ) { + state.retv = MENU_NEXT; + *( state.selected_line ) = 0; + state.quit = TRUE; + break; + } + // Toggle case sensitivity. + else if ( abe_test_action ( TOGGLE_CASE_SENSITIVITY, ev.xkey.state, key ) ) { + config.case_sensitive = !config.case_sensitive; + *( state.selected_line ) = 0; + state.refilter = TRUE; + state.update = TRUE; + if ( config.case_sensitive ) { + textbox_text ( state.case_indicator, "*" ); + } + else { + textbox_text ( state.case_indicator, " " ); + } + } + // Special delete entry command. + else if ( abe_test_action ( DELETE_ENTRY, ev.xkey.state, key ) ) { + if ( state.selected < state.filtered_lines ) { + *( state.selected_line ) = state.line_map[state.selected]; + state.retv = MENU_ENTRY_DELETE; + state.quit = TRUE; + break; + } + } for ( unsigned int a = CUSTOM_1; a <= CUSTOM_19; a++ ) { if ( abe_test_action ( a, ev.xkey.state, key ) ) { if ( state.selected < state.filtered_lines ) { @@ -1524,17 +1533,14 @@ MenuReturn menu ( Switcher *sw, char **input, char *prompt, unsigned int *select break; } } + } + { // Skip if we detected key before. if ( state.quit ) { continue; } - // This is needed for letting the Input Method handle combined keys. - // E.g. `e into è - if ( XFilterEvent ( &ev, main_window ) ) { - continue; - } - int rc = textbox_keypress ( state.text, xic, &ev ); + int rc = textbox_keypress ( state.text, &ev, pad, key, stat ); // Row is accepted. if ( rc < 0 ) { shift = ( ( ev.xkey.state & ShiftMask ) == ShiftMask ); diff --git a/source/textbox.c b/source/textbox.c index 06fa46b6..81a0b3ca 100644 --- a/source/textbox.c +++ b/source/textbox.c @@ -45,7 +45,9 @@ // Use this so we can ignore numlock mask. // TODO: maybe use something smarter here.. extern unsigned int NumlockMask; -extern unsigned int ModeSwitchMask; +extern unsigned int AltMask; +extern unsigned int SuperRMask; +extern unsigned int SuperLMask; /** * Font + font color cache. @@ -496,90 +498,84 @@ static void textbox_cursor_del_word ( textbox *tb ) // 0 = unhandled // 1 = handled // -1 = handled and return pressed (finished) -int textbox_keypress ( textbox *tb, XIC xic, XEvent *ev ) +int textbox_keypress ( textbox *tb, XEvent *ev, char *pad, KeySym key, Status stat ) { - KeySym key; - Status stat; - char pad[32]; - int len; - if ( !( tb->flags & TB_EDITABLE ) ) { return 0; } + if ( stat == XLookupKeySym || stat == XLookupBoth ) { + // Left or Ctrl-b + if ( abe_test_action ( MOVE_CHAR_BACK, ev->xkey.state, key ) ) { + textbox_cursor_dec ( tb ); + return 2; + } + // Right or Ctrl-F + else if ( abe_test_action ( MOVE_CHAR_FORWARD, ev->xkey.state, key ) ) { + textbox_cursor_inc ( tb ); + return 2; + } - len = Xutf8LookupString ( xic, &ev->xkey, pad, sizeof ( pad ), &key, &stat ); - pad[len] = 0; - // Left or Ctrl-b - if ( abe_test_action ( MOVE_CHAR_BACK, ev->xkey.state, key ) ) { - textbox_cursor_dec ( tb ); - return 2; + // Ctrl-U: Kill from the beginning to the end of the line. + else if ( abe_test_action ( CLEAR_LINE, ev->xkey.state, key ) ) { + textbox_text ( tb, "" ); + return 1; + } + // Ctrl-A + else if ( abe_test_action ( MOVE_FRONT, ev->xkey.state, key ) ) { + textbox_cursor ( tb, 0 ); + return 2; + } + // Ctrl-E + else if ( abe_test_action ( MOVE_END, ev->xkey.state, key ) ) { + textbox_cursor_end ( tb ); + return 2; + } + // Ctrl-Alt-h + else if ( abe_test_action ( REMOVE_WORD_BACK, ev->xkey.state, key ) ) { + textbox_cursor_bkspc_word ( tb ); + return 1; + } + // Ctrl-Alt-d + else if ( abe_test_action ( REMOVE_WORD_FORWARD, ev->xkey.state, key ) ) { + textbox_cursor_del_word ( tb ); + return 1; + } // Delete or Ctrl-D + else if ( abe_test_action ( REMOVE_CHAR_FORWARD, ev->xkey.state, key ) ) { + textbox_cursor_del ( tb ); + return 1; + } + // Alt-B + else if ( abe_test_action ( MOVE_WORD_BACK, ev->xkey.state, key ) ) { + textbox_cursor_dec_word ( tb ); + return 2; + } + // Alt-F + else if ( abe_test_action ( MOVE_WORD_FORWARD, ev->xkey.state, key ) ) { + textbox_cursor_inc_word ( tb ); + return 2; + } + // BackSpace, Ctrl-h + else if ( abe_test_action ( REMOVE_CHAR_BACK, ev->xkey.state, key ) ) { + textbox_cursor_bkspc ( tb ); + return 1; + } + else if ( abe_test_action ( ACCEPT_CUSTOM, ev->xkey.state, key ) ) { + return -2; + } + else if ( abe_test_action ( ACCEPT_ENTRY_CONTINUE, ev->xkey.state, key ) ) { + return -3; + } + else if ( abe_test_action ( ACCEPT_ENTRY, ev->xkey.state, key ) ) { + return -1; + } } - // Right or Ctrl-F - else if ( abe_test_action ( MOVE_CHAR_FORWARD, ev->xkey.state, key ) ) { - textbox_cursor_inc ( tb ); - return 2; - } - - // Ctrl-U: Kill from the beginning to the end of the line. - else if ( abe_test_action ( CLEAR_LINE, ev->xkey.state, key ) ) { - textbox_text ( tb, "" ); - return 1; - } - // Ctrl-A - else if ( abe_test_action ( MOVE_FRONT, ev->xkey.state, key ) ) { - textbox_cursor ( tb, 0 ); - return 2; - } - // Ctrl-E - else if ( abe_test_action ( MOVE_END, ev->xkey.state, key ) ) { - textbox_cursor_end ( tb ); - return 2; - } - // Ctrl-Alt-h - else if ( abe_test_action ( REMOVE_WORD_BACK, ev->xkey.state, key ) ) { - textbox_cursor_bkspc_word ( tb ); - return 1; - } - // Ctrl-Alt-d - else if ( abe_test_action ( REMOVE_WORD_FORWARD, ev->xkey.state, key ) ) { - textbox_cursor_del_word ( tb ); - return 1; - } // Delete or Ctrl-D - else if ( abe_test_action ( REMOVE_CHAR_FORWARD, ev->xkey.state, key ) ) { - textbox_cursor_del ( tb ); - return 1; - } - // Alt-B - else if ( abe_test_action ( MOVE_WORD_BACK, ev->xkey.state, key ) ) { - textbox_cursor_dec_word ( tb ); - return 2; - } - // Alt-F - else if ( abe_test_action ( MOVE_WORD_FORWARD, ev->xkey.state, key ) ) { - textbox_cursor_inc_word ( tb ); - return 2; - } - // BackSpace, Ctrl-h - else if ( abe_test_action ( REMOVE_CHAR_BACK, ev->xkey.state, key ) ) { - textbox_cursor_bkspc ( tb ); - return 1; - } - else if ( abe_test_action ( ACCEPT_CUSTOM, ev->xkey.state, key ) ) { - return -2; - } - else if ( abe_test_action ( ACCEPT_ENTRY_CONTINUE, ev->xkey.state, key ) ) { - return -3; - } - else if ( abe_test_action ( ACCEPT_ENTRY, ev->xkey.state, key ) ) { - return -1; - } - // Filter When alt/ctrl/etc is pressed do not accept the character. - // Ignore others (numlock, shift,..). - else if ( !iscntrl ( *pad ) && 0 == - ( ev->xkey.state & ~( ModeSwitchMask | NumlockMask | ( 1 << 12 ) | ( 1 << 13 ) | ShiftMask | LockMask ) ) ) { - textbox_insert ( tb, tb->cursor, pad ); - textbox_cursor_inc ( tb ); - return 1; + if ( *pad != 0 && ( stat == XLookupBoth || stat == XLookupChars ) ) { + // Filter When alt/ctrl is pressed do not accept the character. + if ( !g_ascii_iscntrl ( *pad ) && 0 == ( ev->xkey.state & ( ControlMask | AltMask | SuperRMask | SuperLMask ) ) ) { + textbox_insert ( tb, tb->cursor, pad ); + textbox_cursor_inc ( tb ); + return 1; + } } return 0; diff --git a/source/x11-helper.c b/source/x11-helper.c index 3850cb9f..1edbcc4e 100644 --- a/source/x11-helper.c +++ b/source/x11-helper.c @@ -57,8 +57,10 @@ Atom netatoms[NUM_NETATOMS]; const char *netatom_names[] = { EWMH_ATOMS ( ATOM_CHAR ) }; // Mask indicating num-lock. -unsigned int NumlockMask = 0; -unsigned int ModeSwitchMask = 0; +unsigned int NumlockMask = 0; +unsigned int AltMask = 0; +unsigned int SuperRMask = 0; +unsigned int SuperLMask = 0; extern Colormap map; @@ -368,16 +370,24 @@ void x11_ungrab_key ( Display *display, unsigned int modmask, KeySym key ) */ static void x11_figure_out_numlock_mask ( Display *display ) { - XModifierKeymap *modmap = XGetModifierMapping ( display ); - KeyCode kc = XKeysymToKeycode ( display, XK_Num_Lock ); - KeyCode kc_ms = XKeysymToKeycode ( display, XK_Mode_switch ); + XModifierKeymap *modmap = XGetModifierMapping ( display ); + KeyCode kc = XKeysymToKeycode ( display, XK_Num_Lock ); + KeyCode kc_altl = XKeysymToKeycode ( display, XK_Alt_L ); + KeyCode kc_superr = XKeysymToKeycode ( display, XK_Super_R ); + KeyCode kc_superl = XKeysymToKeycode ( display, XK_Super_L ); for ( int i = 0; i < 8; i++ ) { for ( int j = 0; j < ( int ) modmap->max_keypermod; j++ ) { if ( modmap->modifiermap[i * modmap->max_keypermod + j] == kc ) { NumlockMask = ( 1 << i ); } - if ( modmap->modifiermap[i * modmap->max_keypermod + j] == kc_ms ) { - ModeSwitchMask = ( 1 << i ); + if ( modmap->modifiermap[i * modmap->max_keypermod + j] == kc_altl ) { + AltMask |= ( 1 << i ); + } + if ( modmap->modifiermap[i * modmap->max_keypermod + j] == kc_superr ) { + SuperRMask |= ( 1 << i ); + } + if ( modmap->modifiermap[i * modmap->max_keypermod + j] == kc_superl ) { + SuperLMask |= ( 1 << i ); } } } @@ -402,9 +412,14 @@ void x11_parse_key ( char *combo, unsigned int *mod, KeySym *key ) } if ( strcasestr ( combo, "alt" ) ) { - modmask |= Mod1Mask; + modmask |= AltMask; + } + if ( strcasestr ( combo, "superr" ) ) { + modmask |= SuperRMask; + } + if ( strcasestr ( combo, "superl" ) ) { + modmask |= SuperLMask; } - if ( strcasestr ( combo, "mod2" ) ) { modmask |= Mod2Mask; } @@ -436,7 +451,6 @@ void x11_parse_key ( char *combo, unsigned int *mod, KeySym *key ) // TODO popup fprintf ( stderr, "sorry, cannot understand key combination: %s\n", combo ); } - *key = sym; }