diff --git a/Makefile.am b/Makefile.am index 46efec52..8e9d5961 100644 --- a/Makefile.am +++ b/Makefile.am @@ -32,6 +32,7 @@ rofi_SOURCES=\ source/history.c\ config/config.c\ source/helper.c\ + source/keyb.c\ source/x11-helper.c\ source/dialogs/dmenu.c\ source/dialogs/run.c\ @@ -45,6 +46,7 @@ rofi_SOURCES=\ include/history.h\ include/textbox.h\ include/helper.h\ + include/keyb.h\ include/x11-helper.h\ include/dialogs/run.h\ include/dialogs/combi.h\ @@ -124,8 +126,12 @@ rofi_test_SOURCES=\ textbox_test_SOURCES=\ source/textbox.c\ config/config.c\ + source/keyb.c\ + source/x11-helper.c\ + include/keyb.h\ include/rofi.h\ include/textbox.h\ + source/x11-helper.h\ test/textbox-test.c helper_test_SOURCES=\ diff --git a/include/keyb.h b/include/keyb.h new file mode 100644 index 00000000..fce2b540 --- /dev/null +++ b/include/keyb.h @@ -0,0 +1,36 @@ +#ifndef __KEYB_H__ +#define __KEYB_H__ + +typedef enum _KeyBindingAction +{ + PASTE_PRIMARY = 0, + PASTE_SECONDARY, + CLEAR_LINE, + MOVE_FRONT, + MOVE_END, + REMOVE_WORD_BACK, + REMOVE_WORD_FORWARD, + REMOVE_CHAR_FORWARD, + NUM_ABE +} KeyBindingAction; + + +typedef struct _KeyBinding +{ + unsigned int modmask; + KeySym keysym; +} KeyBinding; + +typedef struct _ActionBindingEntry +{ + const char *name; + int num_bindings; + KeyBinding *kb; +} ActionBindingEntry; + + +void setup_abe ( void ); + +extern ActionBindingEntry abe[NUM_ABE]; +int abe_test_action ( KeyBindingAction action, unsigned int mask, KeySym key ); +#endif // __KEYB_H__ diff --git a/include/rofi.h b/include/rofi.h index 8f7ff651..a4fa28c2 100644 --- a/include/rofi.h +++ b/include/rofi.h @@ -3,7 +3,7 @@ #include <X11/X.h> #include <glib.h> #include <textbox.h> - +#include "keyb.h" /** * Pointer to xdg cache directory. diff --git a/source/keyb.c b/source/keyb.c new file mode 100644 index 00000000..6108e9ab --- /dev/null +++ b/source/keyb.c @@ -0,0 +1,83 @@ +#include "rofi.h" +#include <X11/keysym.h> +#include "x11-helper.h" + +ActionBindingEntry abe[NUM_ABE]; +// Use this so we can ignore numlock mask. +// TODO: maybe use something smarter here.. +extern unsigned int NumlockMask; +const char *KeyBindingActionName[NUM_ABE] = +{ + // PASTE_PRIMARY + "primary-paste", + // PASTE_SECONDARY + "secondary-paste", + // CLEAR_LINE + "clear-line", + // MOVE_FRONT + "move-front", + // MOVE_END + "move-end", + // REMOVE_WORD_BACK + "remove-word-back", + // REMOVE_WORD_FORWARD + "remove-word-forward", + // REMOVE_CHAR_FORWARD + "remove-char-forward" +}; + +const char *KeyBindingActionDefault[NUM_ABE] = +{ + // PASTE_PRIMARY + "Control+Shift+v,Shift+Insert", + // PASTE_SECONDARY + "Control+v,Insert", + // CLEAR_LINE + "Control+u", + // MOVE_FRONT + "Control+a", + // MOVE_END + "Control+e", + // REMOVE_WORD_BACK + "Control+Alt+h", + // REMOVE_WORD_FORWARD + "Control+Alt+d", + // REMOVE_CHAR_FORWARD + "Delete,Control+d", +}; + +void setup_abe ( void ) +{ + for ( int iter = 0; iter < NUM_ABE; iter++ ) { + char *keystr = g_strdup ( KeyBindingActionDefault[iter] ); + char *sp = NULL; + // set pointer to name. + abe[iter].name = KeyBindingActionName[iter]; + + // Iter over bindings. + for ( char *entry = strtok_r ( keystr, ",", &sp ); entry != NULL; entry = strtok_r ( NULL, ",", &sp ) ) { + abe[iter].kb = g_realloc ( abe[iter].kb, ( abe[iter].num_bindings + 1 ) * sizeof ( KeyBinding ) ); + KeyBinding *kb = &( abe[iter].kb[abe[iter].num_bindings] ); + x11_parse_key ( entry, &( kb->modmask ), &( kb->keysym ) ); + abe[iter].num_bindings++; + } + + g_free ( keystr ); + } +} + +int abe_test_action ( KeyBindingAction action, unsigned int mask, KeySym key ) +{ + ActionBindingEntry *akb = &( abe[action] ); + + for ( int iter = 0; iter < akb->num_bindings; iter++ ) { + const KeyBinding * const kb = &( akb->kb[iter] ); + if ( kb->keysym == key ) { + if ( ( mask & ~NumlockMask ) == kb->modmask ) { + return TRUE; + } + } + } + + return FALSE; +} diff --git a/source/rofi.c b/source/rofi.c index 04581dee..045a3a4a 100644 --- a/source/rofi.c +++ b/source/rofi.c @@ -70,17 +70,15 @@ typedef enum _MainLoopEvent } MainLoopEvent; // Pidfile. -char *pidfile = NULL; -const char *cache_dir = NULL; -Display *display = NULL; -char *display_str = NULL; - -const char *netatom_names[] = { EWMH_ATOMS ( ATOM_CHAR ) }; -Atom netatoms[NUM_NETATOMS]; +char *pidfile = NULL; +const char *cache_dir = NULL; +Display *display = NULL; +char *display_str = NULL; +extern Atom netatoms[NUM_NETATOMS]; // Array of switchers. -Switcher **switchers = NULL; +Switcher **switchers = NULL; // Number of switchers. unsigned int num_switchers = 0; // Current selected switcher. @@ -1151,14 +1149,12 @@ MenuReturn menu ( char **lines, unsigned int num_lines, char **input, char *prom KeySym key = XkbKeycodeToKeysym ( display, ev.xkey.keycode, 0, 0 ); // Handling of paste - if ( ( ( ( ev.xkey.state & ControlMask ) == ControlMask ) && key == XK_v ) ) { - XConvertSelection ( display, ( ev.xkey.state & ShiftMask ) ? - XA_PRIMARY : netatoms[CLIPBOARD], + 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 ( key == XK_Insert ) { - XConvertSelection ( display, ( ev.xkey.state & ShiftMask ) ? - XA_PRIMARY : netatoms[CLIPBOARD], + 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 ( ( ( ev.xkey.state & ShiftMask ) == ShiftMask ) && key == XK_Left ) { @@ -1751,6 +1747,7 @@ int main ( int argc, char *argv[] ) // Reload for dynamic part. load_configuration_dynamic ( display ); + setup_abe (); // Dump. if ( find_arg ( "-dump-xresources" ) >= 0 ) { xresource_dump (); diff --git a/source/textbox.c b/source/textbox.c index 84c860ea..5d035e39 100644 --- a/source/textbox.c +++ b/source/textbox.c @@ -38,6 +38,7 @@ #include "rofi.h" #include "textbox.h" +#include "keyb.h" #include <glib.h> #define SIDE_MARGIN 1 @@ -538,34 +539,31 @@ int textbox_keypress ( textbox *tb, XEvent *ev ) } // Ctrl-U: Kill from the beginning to the end of the line. - else if ( ( ev->xkey.state & ControlMask ) && key == XK_u ) { + else if ( abe_test_action ( CLEAR_LINE, ev->xkey.state, key ) ) { textbox_text ( tb, "" ); return 1; } // Ctrl-A - else if ( ( ev->xkey.state & ControlMask ) && key == XK_a ) { + else if ( abe_test_action ( MOVE_FRONT, ev->xkey.state, key ) ) { textbox_cursor ( tb, 0 ); return 1; } // Ctrl-E - else if ( ( ev->xkey.state & ControlMask ) && key == XK_e ) { + else if ( abe_test_action ( MOVE_END, ev->xkey.state, key ) ) { textbox_cursor_end ( tb ); return 1; } // Ctrl-Alt-h - else if ( ( ev->xkey.state & ControlMask ) && - ( ev->xkey.state & Mod1Mask ) && key == XK_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 ( ( ev->xkey.state & ControlMask ) && - ( ev->xkey.state & Mod1Mask ) && key == XK_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 ( key == XK_Delete || - ( ( ev->xkey.state & ControlMask ) && key == XK_d ) ) { + else if ( abe_test_action ( REMOVE_CHAR_FORWARD, ev->xkey.state, key ) ) { textbox_cursor_del ( tb ); return 1; } diff --git a/source/x11-helper.c b/source/x11-helper.c index 26032dbc..86cbe50c 100644 --- a/source/x11-helper.c +++ b/source/x11-helper.c @@ -48,6 +48,8 @@ #define INTERSECT( x, y, w, h, x1, y1, w1, h1 ) ( OVERLAP ( ( x ), ( w ), ( x1 ), ( w1 ) ) && OVERLAP ( ( y ), ( h ), ( y1 ), ( h1 ) ) ) #include "x11-helper.h" +Atom netatoms[NUM_NETATOMS]; +const char *netatom_names[] = { EWMH_ATOMS ( ATOM_CHAR ) }; // Mask indicating num-lock. unsigned int NumlockMask = 0; diff --git a/test/textbox-test.c b/test/textbox-test.c index a9bab187..899c7f2e 100644 --- a/test/textbox-test.c +++ b/test/textbox-test.c @@ -62,6 +62,8 @@ int main ( G_GNUC_UNUSED int argc, G_GNUC_UNUSED char **argv ) return EXIT_FAILURE; } create_visual_and_colormap(); + + setup_abe(); TASSERT( display != NULL ); XSetWindowAttributes attr; attr.colormap = map;