From patchwork Fri Aug 27 12:16:42 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Programmingkid X-Patchwork-Id: 12462017 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-12.8 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 9AC06C432BE for ; Fri, 27 Aug 2021 12:18:09 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 0013F60EB3 for ; Fri, 27 Aug 2021 12:18:08 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.4.1 mail.kernel.org 0013F60EB3 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=gmail.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=nongnu.org Received: from localhost ([::1]:38660 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1mJaoC-0002pH-8X for qemu-devel@archiver.kernel.org; Fri, 27 Aug 2021 08:18:08 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:46204) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1mJamu-0000qE-DK for qemu-devel@nongnu.org; Fri, 27 Aug 2021 08:16:48 -0400 Received: from mail-qt1-x831.google.com ([2607:f8b0:4864:20::831]:43921) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1mJams-0000pS-Hi for qemu-devel@nongnu.org; Fri, 27 Aug 2021 08:16:48 -0400 Received: by mail-qt1-x831.google.com with SMTP id s15so1741789qta.10 for ; Fri, 27 Aug 2021 05:16:44 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:content-transfer-encoding:mime-version:subject:message-id:date :cc:to; bh=7+YuRDb7CY/A4KtdiOSigAyt5dgagaSufxFz2sC7D8E=; b=HtB6wopGcfPzhlMKi/r+9tHFkSTRyICepXj//sj+LwhAIEGIjPQ9ginzdL9gK0HCtS TeyG7Mw/b1XsYP/dDvh6Rs+wbSdrU9RugkvDX1naufzBreYN/dAzRSyVEjmuvzvEte6s K6UWm+0tBmcJ5BEn/ZbSQRK5xiT5n+Cmgx2YQcpWwZZIr85ntZ2HR3uGMz2v4P+XF6jJ 4yzNzy8F2j4bKgBwcjwyoMVrG3C4ATE+Wgy5mdKhcsJJ1D4bVmLQT3Qt359s/f7a6mwr pNrTt3j60v0ESiVZ6x+y2BUXfO4H9fGFwCnhQGM8EQq2oM2yoX54dHnMUzMo2vm4bmeo Ob4Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:content-transfer-encoding:mime-version :subject:message-id:date:cc:to; bh=7+YuRDb7CY/A4KtdiOSigAyt5dgagaSufxFz2sC7D8E=; b=NvAOmbph3ZAc5fL0GEgaV3zqCriCVU6p6gnH/CGcjKGa+V6cU+Mdz+dDrozc+xTKqs at7YsrzM6LfUSyH3Gqe346OjOEOqFr0FdAPbj0k8SGT6WH4vGOhI1TM3M7c4qNbNi3UM Oe2aeu93bAMADGurV73bNSVx0MEKGSFRXQWmAuGdqk7/Av6LWESjKHycNPY7UDfHjEQ9 9oO+QkdPsnFEeU4mySd7tJqnkA0p/nYp51TlkcgRGbk29mveuc94NERmo3j6QVW5b2x2 Wqm401afjWtcqfOBZ/WYLTdfnSO8CL0ZrcyJ+DTPyzfGl3ntkPSjX3csb1IsoyHDqCOk YElg== X-Gm-Message-State: AOAM530Uz1GA3wq/70EyJNTUZ6SMwYZ8GgmtZtCNgM65ExOOKEw/4d7n avf09sirwlVEV04HlQRVaew= X-Google-Smtp-Source: ABdhPJx6mMe8kkWfCkUOIn471HEVuwWwgDmTAlVHjoJF7m1up4peFBBFnDuaDtD5+5a+UdXmqQJG5Q== X-Received: by 2002:ac8:4684:: with SMTP id g4mr8031332qto.290.1630066603889; Fri, 27 Aug 2021 05:16:43 -0700 (PDT) Received: from [192.168.0.5] (d149-67-175-105.try.wideopenwest.com. [67.149.105.175]) by smtp.gmail.com with ESMTPSA id c2sm3430357qte.22.2021.08.27.05.16.42 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Fri, 27 Aug 2021 05:16:43 -0700 (PDT) From: Programmingkid Mime-Version: 1.0 (Mac OS X Mail 14.0 \(3654.40.0.2.32\)) Subject: Ping: [PATCH 1/2] ui/cocoa.m: Add full keyboard grab support Message-Id: <90E28997-9AFA-4D8C-8323-BD087E629638@gmail.com> Date: Fri, 27 Aug 2021 08:16:42 -0400 To: Peter Maydell X-Mailer: Apple Mail (2.3654.40.0.2.32) Received-SPF: pass client-ip=2607:f8b0:4864:20::831; envelope-from=programmingkidx@gmail.com; helo=mail-qt1-x831.google.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, FREEMAIL_FROM=0.001, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: QEMU Developers Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" ping From: John Arbuckle Date: Thu, 29 Jul 2021 14:41:57 -0400 Subject: [PATCH 1/2] ui/cocoa.m: Add full keyboard grab support There are keyboard shortcuts that are vital for use in a guest that runs Mac OS. These shortcuts are reserved for Mac OS use only which makes having the guest see them impossible on a Mac OS host - until now. This patch will enable the user to decide if the guest should see all keyboard shortcuts using a menu item. This patch adds a new menu called Options and a new menu item called "Full Keyboard Grab". Simply selecting this menu item will turn the feature on or off at any time. Mac OS requires the user to enable access to assistive devices to use this feature. How to do this varies with each Mac OS version. Based on patch by Gustavo Noronha Silva . Signed-off-by: John Arbuckle --- ui/cocoa.m | 112 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 112 insertions(+) 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