--- /dev/null
+#include "events.h"
+
+/* this is only to queue GDK key events, in order to later send them if the map didn't match */
+static struct {
+    GdkEventKey **queue;                /* queue holding submitted events */
+    int            qlen;                /* pointer to last char in queue */
+    bool           processing;          /* whether or not events are processing */
+} events;
+
+/**
+ * Append an event into the queue.
+ */
+void queue_event(GdkEventKey* e)
+{
+    if (vb.mode->id != 'i') {
+        /* events are only needed for input mode */
+        return;
+    }
+
+    if (events.queue == NULL) {
+        events.queue = malloc(0);
+    }
+
+    events.queue = realloc(events.queue, (events.qlen + 1) * sizeof *events.queue);
+    events.queue[events.qlen] = e;
+    events.qlen ++;
+}
+
+/**
+ * Process events in the queue, sending the key events to GDK.
+ */
+void process_events()
+{
+    if (vb.mode->id != 'i') {
+        /* events are only needed for input mode */
+        return;
+    }
+
+    events.processing = true; /* signal not to map our events */
+
+    for (int i = 0; i < events.qlen; ++i)
+    {
+        // TODO send to gdk
+    }
+
+    events.qlen = 0;
+    events.processing = false;
+}
+
+/**
+ * Check if the events are currently processing (i.e. being sent to GDK
+ * unhandled).  Provided in order to encapsulate the "events" global struct.
+ */
+bool is_processing_events()
+{
+    return events.processing;
+}
+
+/**
+ * Clear the event queue by resetting the length. Provided in order to
+ * encapsulate the "events" global struct.
+ */
+void clear_events()
+{
+    events.qlen = 0;
+}
 
--- /dev/null
+#ifndef _EVENTS_H
+#define _EVENTS_H
+
+#include <gdk/gdkkeysyms.h>
+#include <gdk/gdkkeysyms-compat.h>
+#include "main.h"
+#include "map.h"
+
+void queue_event(GdkEventKey* e);
+void clear_events();
+void process_events();
+bool is_processing_events();
+
+extern VbCore vb;
+
+#endif /* end of include guard: _MAP_H */
 
 #include <gdk/gdkkeysyms.h>
 #include <gdk/gdkkeysyms-compat.h>
 #include "config.h"
+#include "events.h"
 #include "main.h"
 #include "map.h"
 #include "normal.h"
  */
 gboolean map_keypress(GtkWidget *widget, GdkEventKey* event, gpointer data)
 {
+    if (is_processing_events()) {
+        // events are processing, pass all keys unmodified
+        return false;
+    }
+
     guint state  = event->state;
     guint keyval = event->keyval;
     guchar string[32];
     vb.state.typed         = true;
     vb.state.processed_key = true;
 
-    map_handle_keys(string, len, true);
+    MapState res = map_handle_keys(string, len, true);
 
     /* reset the typed flag */
     vb.state.typed = false;
 
+    if (res == MAP_NOMATCH) {
+        /* consume any unprocessed events */
+        process_events();
+    } else if (res == MAP_AMBIGUOUS) {
+        /* queue event for later processing */
+        queue_event(event);
+    } else if (res == MAP_DONE) {
+        /* we're done - clear events */
+        clear_events();
+    }
+
     return vb.state.processed_key;
 }
 
 static gboolean do_timeout(gpointer data)
 {
     /* signalize the timeout to the key handler */
-    map_handle_keys((guchar*)"", 0, true);
+    MapState res = map_handle_keys((guchar*)"", 0, true);
+
+    if (res == MAP_DONE) {
+        /* we're done - clear events */
+        clear_events();
+    } else {
+        /* consume any unprocessed events */
+        process_events();
+    }
 
     /* we return true to not automatically remove the resource - this is
      * required to prevent critical error when we remove the source in