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;