diff --git a/ui/cocoa.m b/ui/cocoa.m
index 9f72844b07..fdef9e9901 100644
--- a/ui/cocoa.m
+++ b/ui/cocoa.m
@@ -114,6 +114,9 @@ static void cocoa_switch(DisplayChangeListener *dcl,
 typedef void (^CodeBlock)(void);
 typedef bool (^BoolCodeBlock)(void);
 
+static CFMachPortRef eventsTap = NULL;
+static CFRunLoopSourceRef eventsTapSource = NULL;
+
 static void with_iothread_lock(CodeBlock block)
 {
     bool locked = qemu_mutex_iothread_locked();
@@ -332,10 +335,27 @@ - (float) cdx;
 - (float) cdy;
 - (QEMUScreen) gscreen;
 - (void) raiseAllKeys;
+- (void) setFullGrab;
 @end
 
 QemuCocoaView *cocoaView;
 
+// Part of the full keyboard grab system
+static CGEventRef handleTapEvent(CGEventTapProxy proxy, CGEventType type,
+CGEventRef cgEvent, void *userInfo)
+{
+    QemuCocoaView *cocoaView = (QemuCocoaView*) userInfo;
+    NSEvent* event = [NSEvent eventWithCGEvent:cgEvent];
+    if ([cocoaView isMouseGrabbed] && [cocoaView handleEvent:event]) {
+        COCOA_DEBUG("Global events tap: qemu handled the event, capturing!\n");
+        return NULL;
+    }
+    COCOA_DEBUG("Global events tap: qemu did not handle the event, letting it"
+                " through...\n");
+
+    return cgEvent;
+}
+
 @implementation QemuCocoaView
 - (id)initWithFrame:(NSRect)frameRect
 {
@@ -361,6 +381,12 @@ - (void) dealloc
     }
 
     qkbd_state_free(kbd);
+    if (eventsTap) {
+        CFRelease(eventsTap);
+    }
+    if (eventsTapSource) {
+        CFRelease(eventsTapSource);
+    }
     [super dealloc];
 }
 
@@ -1086,6 +1112,50 @@ - (void) raiseAllKeys
         qkbd_state_lift_all_keys(kbd);
     });
 }
+
+// Inserts the event tap.
+// This enables us to receive keyboard events that Mac OS would
+// otherwise not let us see - like Command-Option-Esc.
+- (void) setFullGrab
+{
+    COCOA_DEBUG("QemuCocoaView: setFullGrab\n");
+    NSString *advice = @"Try enabling access to assistive devices";
+    CGEventMask mask = CGEventMaskBit(kCGEventKeyDown) |
+    CGEventMaskBit(kCGEventKeyUp) | CGEventMaskBit(kCGEventFlagsChanged);
+    eventsTap = CGEventTapCreate(kCGHIDEventTap, kCGHeadInsertEventTap,
+                                 kCGEventTapOptionDefault, mask, handleTapEvent,
+                                 self);
+    if (!eventsTap) {
+        @throw [NSException
+                 exceptionWithName:@"Tap failure"
+                reason:[NSString stringWithFormat:@"%@\n%@", @"Could not "
+                        "create event tap.", advice]
+                userInfo:nil];
+    } else {
+        COCOA_DEBUG("Global events tap created! Will capture system key"
+                    " combos.\n");
+    }
+
+    eventsTapSource =
+    CFMachPortCreateRunLoopSource(kCFAllocatorDefault, eventsTap, 0);
+    if (!eventsTapSource ) {
+        @throw [NSException
+                 exceptionWithName:@"Tap failure"
+                 reason:@"Could not obtain current CFRunLoop source."
+                userInfo:nil];
+    }
+    CFRunLoopRef runLoop = CFRunLoopGetCurrent();
+    if (!runLoop) {
+           @throw [NSException
+                 exceptionWithName:@"Tap failure"
+                 reason:@"Could not obtain current CFRunLoop."
+                userInfo:nil];
+    }
+
+    CFRunLoopAddSource(runLoop, eventsTapSource, kCFRunLoopDefaultMode);
+    CFRelease(eventsTapSource);
+}
+
 @end
 
 
@@ -1117,6 +1187,7 @@ - (void)openDocumentation:(NSString *)filename;
 - (IBAction) do_about_menu_item: (id) sender;
 - (void)make_about_window;
 - (void)adjustSpeed:(id)sender;
+- (IBAction)doFullGrab:(id)sender;
 @end
 
 @implementation QemuCocoaAppController
@@ -1569,6 +1640,35 @@ - (void)adjustSpeed:(id)sender
     COCOA_DEBUG("cpu throttling at %d%c\n", cpu_throttle_get_percentage(), '%');
 }
 
+// The action method to the 'Options->Full Keyboard Grab' menu item
+- (IBAction)doFullGrab:(id) sender
+{
+    @try
+    {
+        // Set the state of the menu item
+        // if already checked
+        if ([sender state] == NSControlStateValueOn) {
+            // remove runloop source
+            CFRunLoopSourceInvalidate(eventsTapSource);
+            if (!eventsTap) {
+                CFRelease(eventsTap);
+            }
+            [sender setState: NSControlStateValueOff];
+        }
+
+        // if not already checked
+        else {
+            [cocoaView setFullGrab];
+            [sender setState: NSControlStateValueOn];
+        }
+    }
+    @catch(NSException *e) {
+        NSBeep();
+        NSLog(@"Exception in doFullGrab: %@", [e reason]);
+        QEMU_Alert([e reason]);
+    }
+}
+
 @end
 
 @interface QemuApplication : NSApplication
@@ -1655,6 +1755,18 @@ static void create_initial_menus(void)
     [menuItem setSubmenu:menu];
     [[NSApp mainMenu] addItem:menuItem];
 
+    // Options menu
+    menu = [[NSMenu alloc] initWithTitle:@"Options"];
+
+    [menu addItem: [[[NSMenuItem alloc] initWithTitle:
+                         @"Full Keyboard Grab" action:@selector(doFullGrab:)
+                                        keyEquivalent:@""] autorelease]];
+
+    menuItem = [[[NSMenuItem alloc] initWithTitle:@"Options" action:nil
+                                    keyEquivalent:@""] autorelease];
+    [menuItem setSubmenu:menu];
+    [[NSApp mainMenu] addItem:menuItem];
+
     // Window menu
     menu = [[NSMenu alloc] initWithTitle:@"Window"];
     [menu addItem: [[[NSMenuItem alloc] initWithTitle:@"Minimize" action:@selector(performMiniaturize:) keyEquivalent:@"m"] autorelease]]; // Miniaturize
