All of lore.kernel.org
 help / color / mirror / Atom feed
From: Will Cohen <wwcohen@gmail.com>
To: "Philippe Mathieu-Daudé" <philippe.mathieu.daude@gmail.com>
Cc: "Peter Maydell" <peter.maydell@linaro.org>,
	"Thomas Huth" <thuth@redhat.com>,
	qemu-block@nongnu.org, "Markus Armbruster" <armbru@redhat.com>,
	"Christian Schoenebeck" <qemu_oss@crudebyte.com>,
	"Philippe Mathieu-Daudé" <f4bug@amsat.org>,
	"Cameron Esfahani" <dirty@apple.com>,
	"qemu Developers" <qemu-devel@nongnu.org>,
	"Roman Bolshakov" <r.bolshakov@yadro.com>,
	"Gerd Hoffmann" <kraxel@redhat.com>,
	"Akihiko Odaki" <akihiko.odaki@gmail.com>,
	"Alex Bennée" <alex.bennee@linaro.org>,
	"Gustavo Noronha Silva" <gustavo@noronha.dev.br>
Subject: Re: [PATCH v7 20/22] ui/cocoa: capture all keys and combos when mouse is grabbed
Date: Mon, 7 Mar 2022 12:01:20 -0500	[thread overview]
Message-ID: <CAB26zV371f=Sb_mvJ_Hpzoc5CQo3FcRHxwtm8oGHCwWP=bTZEQ@mail.gmail.com> (raw)
In-Reply-To: <20220306231753.50277-21-philippe.mathieu.daude@gmail.com>

[-- Attachment #1: Type: text/plain, Size: 7156 bytes --]

On Sun, Mar 6, 2022 at 6:19 PM Philippe Mathieu-Daudé <
philippe.mathieu.daude@gmail.com> wrote:

> From: Gustavo Noronha Silva <gustavo@noronha.dev.br>
>
> Applications such as Gnome may use Alt-Tab and Super-Tab for different
> purposes, some use Ctrl-arrows so we want to allow qemu to handle
> everything when it captures the mouse/keyboard.
>
> However, Mac OS handles some combos like Command-Tab and Ctrl-arrows
> at an earlier part of the event handling chain, not letting qemu see it.
>
> We add a global Event Tap that allows qemu to see all events when the
> mouse is grabbed. Note that this requires additional permissions.
>
> See:
>
>
> https://developer.apple.com/documentation/coregraphics/1454426-cgeventtapcreate?language=objc#discussion
> https://support.apple.com/en-in/guide/mac-help/mh32356/mac
>
> Acked-by: Markus Armbruster <armbru@redhat.com>
> Signed-off-by: Gustavo Noronha Silva <gustavo@noronha.dev.br>
> Message-Id: <20210713213200.2547-2-gustavo@noronha.dev.br>
> Signed-off-by: Akihiko Odaki <akihiko.odaki@gmail.com>
> Message-Id: <20220306121119.45631-2-akihiko.odaki@gmail.com>
> Signed-off-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
> ---
>  qapi/ui.json    |  8 +++++-
>  qemu-options.hx |  3 +++
>  ui/cocoa.m      | 65 ++++++++++++++++++++++++++++++++++++++++++++++++-
>  3 files changed, 74 insertions(+), 2 deletions(-)
>
> diff --git a/qapi/ui.json b/qapi/ui.json
> index 4dea35a819..1d60d5fc78 100644
> --- a/qapi/ui.json
> +++ b/qapi/ui.json
> @@ -1270,11 +1270,17 @@
>  #                    host without sending this key to the guest when
>  #                    "off". Defaults to "on"
>  #
> +# @full-grab: Capture all key presses, including system combos. This
> +#             requires accessibility permissions, since it performs
> +#             a global grab on key events. (default: off)
> +#             See
> https://support.apple.com/en-in/guide/mac-help/mh32356/mac
> +#
>  # Since: 7.0
>  ##
>  { 'struct': 'DisplayCocoa',
>    'data': {
> -      '*left-command-key': 'bool'
> +      '*left-command-key': 'bool',
> +      '*full-grab': 'bool'
>    } }
>
>  ##
> diff --git a/qemu-options.hx b/qemu-options.hx
> index ffaeab61ed..2e6d54db4f 100644
> --- a/qemu-options.hx
> +++ b/qemu-options.hx
> @@ -1916,6 +1916,9 @@ DEF("display", HAS_ARG, QEMU_OPTION_display,
>  #if defined(CONFIG_CURSES)
>      "-display curses[,charset=<encoding>]\n"
>  #endif
> +#if defined(CONFIG_COCOA)
> +    "-display cocoa[,full_grab=on|off]\n"
> +#endif
>  #if defined(CONFIG_OPENGL)
>      "-display egl-headless[,rendernode=<file>]\n"
>  #endif
> diff --git a/ui/cocoa.m b/ui/cocoa.m
> index 31f0846c30..ca1cab1ae6 100644
> --- a/ui/cocoa.m
> +++ b/ui/cocoa.m
> @@ -309,11 +309,13 @@ static void handleAnyDeviceErrors(Error * err)
>      BOOL isMouseGrabbed;
>      BOOL isFullscreen;
>      BOOL isAbsoluteEnabled;
> +    CFMachPortRef eventsTap;
>  }
>  - (void) switchSurface:(pixman_image_t *)image;
>  - (void) grabMouse;
>  - (void) ungrabMouse;
>  - (void) toggleFullScreen:(id)sender;
> +- (void) setFullGrab:(id)sender;
>  - (void) handleMonitorInput:(NSEvent *)event;
>  - (bool) handleEvent:(NSEvent *)event;
>  - (bool) handleEventLocked:(NSEvent *)event;
> @@ -336,6 +338,19 @@ static void handleAnyDeviceErrors(Error * err)
>
>  QemuCocoaView *cocoaView;
>
> +static CGEventRef handleTapEvent(CGEventTapProxy proxy, CGEventType type,
> CGEventRef cgEvent, void *userInfo)
> +{
> +    QemuCocoaView *cocoaView = 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 +376,11 @@ QemuCocoaView *cocoaView;
>      }
>
>      qkbd_state_free(kbd);
> +
> +    if (eventsTap) {
> +        CFRelease(eventsTap);
> +    }
> +
>      [super dealloc];
>  }
>
> @@ -655,6 +675,36 @@ QemuCocoaView *cocoaView;
>      }
>  }
>
> +- (void) setFullGrab:(id)sender
> +{
> +    COCOA_DEBUG("QemuCocoaView: setFullGrab\n");
> +
> +    CGEventMask mask = CGEventMaskBit(kCGEventKeyDown) |
> CGEventMaskBit(kCGEventKeyUp) | CGEventMaskBit(kCGEventFlagsChanged);
> +    eventsTap = CGEventTapCreate(kCGHIDEventTap, kCGHeadInsertEventTap,
> kCGEventTapOptionDefault,
> +                                 mask, handleTapEvent, self);
> +    if (!eventsTap) {
> +        warn_report("Could not create event tap, system key combos will
> not be captured.\n");
> +        return;
> +    } else {
> +        COCOA_DEBUG("Global events tap created! Will capture system key
> combos.\n");
> +    }
> +
> +    CFRunLoopRef runLoop = CFRunLoopGetCurrent();
> +    if (!runLoop) {
> +        warn_report("Could not obtain current CF RunLoop, system key
> combos will not be captured.\n");
> +        return;
> +    }
> +
> +    CFRunLoopSourceRef tapEventsSrc =
> CFMachPortCreateRunLoopSource(kCFAllocatorDefault, eventsTap, 0);
> +    if (!tapEventsSrc ) {
> +        warn_report("Could not obtain current CF RunLoop, system key
> combos will not be captured.\n");
> +        return;
> +    }
> +
> +    CFRunLoopAddSource(runLoop, tapEventsSrc, kCFRunLoopDefaultMode);
> +    CFRelease(tapEventsSrc);
> +}
> +
>  - (void) toggleKey: (int)keycode {
>      qkbd_state_key_event(kbd, keycode, !qkbd_state_key_get(kbd, keycode));
>  }
> @@ -1284,6 +1334,13 @@ QemuCocoaView *cocoaView;
>      [cocoaView toggleFullScreen:sender];
>  }
>
> +- (void) setFullGrab:(id)sender
> +{
> +    COCOA_DEBUG("QemuCocoaAppController: setFullGrab\n");
> +
> +    [cocoaView setFullGrab:sender];
> +}
> +
>  /* Tries to find then open the specified filename */
>  - (void) openDocumentation: (NSString *) filename
>  {
> @@ -2060,11 +2117,17 @@ static void cocoa_display_init(DisplayState *ds,
> DisplayOptions *opts)
>      qemu_sem_wait(&app_started_sem);
>      COCOA_DEBUG("cocoa_display_init: app start completed\n");
>
> +    QemuCocoaAppController *controller = (QemuCocoaAppController
> *)[[NSApplication sharedApplication] delegate];
>      /* if fullscreen mode is to be used */
>      if (opts->has_full_screen && opts->full_screen) {
>          dispatch_async(dispatch_get_main_queue(), ^{
>              [NSApp activateIgnoringOtherApps: YES];
> -            [(QemuCocoaAppController *)[[NSApplication sharedApplication]
> delegate] toggleFullScreen: nil];
> +            [controller toggleFullScreen: nil];
> +        });
> +    }
> +    if (opts->u.cocoa.has_full_grab && opts->u.cocoa.full_grab) {
> +        dispatch_async(dispatch_get_main_queue(), ^{
> +            [controller setFullGrab: nil];
>          });
>      }
>
> --
> 2.34.1
>
> Reviewed-by: Will Cohen <wwcohen@gmail.com>

[-- Attachment #2: Type: text/html, Size: 9326 bytes --]

  reply	other threads:[~2022-03-07 17:09 UTC|newest]

Thread overview: 48+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-03-06 23:17 [PATCH v7 00/22] host: Support macOS 12 Philippe Mathieu-Daudé
2022-03-06 23:17 ` [PATCH v7 01/22] configure: Allow passing extra Objective C compiler flags Philippe Mathieu-Daudé
2022-03-06 23:17 ` [PATCH v7 02/22] tests/fp/berkeley-testfloat-3: Ignore ignored #pragma directives Philippe Mathieu-Daudé
2022-03-09 11:17   ` Alex Bennée
2022-03-06 23:17 ` [PATCH v7 03/22] hvf: Use standard CR0 and CR4 register definitions Philippe Mathieu-Daudé
2022-03-06 23:17 ` [PATCH v7 04/22] hvf: Make hvf_get_segments() / hvf_put_segments() local Philippe Mathieu-Daudé
2022-03-06 23:17 ` [PATCH v7 05/22] hvf: Remove deprecated hv_vcpu_flush() calls Philippe Mathieu-Daudé
2022-03-06 23:17 ` [PATCH v7 06/22] hvf: Fix OOB write in RDTSCP instruction decode Philippe Mathieu-Daudé
2022-03-09 10:20   ` Philippe Mathieu-Daudé
2022-03-15 12:58     ` Peter Maydell
2022-03-15 13:00       ` Philippe Mathieu-Daudé
2022-03-06 23:17 ` [PATCH v7 07/22] block/file-posix: Remove a deprecation warning on macOS 12 Philippe Mathieu-Daudé
2022-03-06 23:17 ` [PATCH v7 08/22] audio/coreaudio: " Philippe Mathieu-Daudé
2022-03-06 23:17 ` [PATCH v7 09/22] audio/dbus: Fix building with modules on macOS Philippe Mathieu-Daudé
2022-03-06 23:17 ` [PATCH v7 10/22] audio: Log context for audio bug Philippe Mathieu-Daudé
2022-03-06 23:17 ` [PATCH v7 11/22] coreaudio: Always return 0 in handle_voice_change Philippe Mathieu-Daudé
2022-03-06 23:17 ` [PATCH v7 12/22] audio: Rename coreaudio extension to use Objective-C compiler Philippe Mathieu-Daudé
2022-03-06 23:17 ` [PATCH v7 13/22] osdep: Avoid using Clang-specific __builtin_available() Philippe Mathieu-Daudé
2022-03-07  4:11   ` Akihiko Odaki
2022-03-06 23:17 ` [PATCH v7 14/22] meson: Resolve the entitlement.sh script once for good Philippe Mathieu-Daudé
2022-03-07  4:13   ` Akihiko Odaki
2022-03-06 23:17 ` [PATCH v7 15/22] meson: Log QEMU_CXXFLAGS content in summary Philippe Mathieu-Daudé
2022-03-07  4:13   ` Akihiko Odaki
2022-03-06 23:17 ` [PATCH v7 16/22] configure: Pass filtered QEMU_OBJCFLAGS to meson Philippe Mathieu-Daudé
2022-03-07  4:15   ` Akihiko Odaki
2022-03-06 23:17 ` [PATCH v7 17/22] ui/cocoa: Constify qkeycode translation arrays Philippe Mathieu-Daudé
2022-03-07  4:16   ` Akihiko Odaki
2022-03-06 23:17 ` [PATCH v7 18/22] ui/cocoa: add option to disable left-command forwarding to guest Philippe Mathieu-Daudé
2022-03-06 23:17 ` [PATCH v7 19/22] ui/cocoa: release mouse when user switches away from QEMU window Philippe Mathieu-Daudé
2022-03-06 23:17 ` [PATCH v7 20/22] ui/cocoa: capture all keys and combos when mouse is grabbed Philippe Mathieu-Daudé
2022-03-07 17:01   ` Will Cohen [this message]
2022-03-06 23:17 ` [PATCH v7 21/22] ui/cocoa: add option to swap Option and Command Philippe Mathieu-Daudé
2022-03-07 17:00   ` Will Cohen
2022-03-06 23:17 ` [PATCH v7 22/22] gitlab-ci: Support macOS 12 via cirrus-run Philippe Mathieu-Daudé
2022-03-09 10:24   ` Philippe Mathieu-Daudé
2022-03-09 11:58     ` Thomas Huth
2022-03-09 12:33       ` Daniel P. Berrangé
2022-03-09 12:50         ` Philippe Mathieu-Daudé
2022-03-09 12:52           ` Thomas Huth
2022-03-09 12:55             ` Daniel P. Berrangé
2022-03-09 13:02           ` Daniel P. Berrangé
2022-03-09 13:09             ` Peter Maydell
2022-03-09 13:40               ` Philippe Mathieu-Daudé
2022-03-09 10:28   ` Daniel P. Berrangé
2022-03-15 12:48 ` [PATCH v7 00/22] host: Support macOS 12 Philippe Mathieu-Daudé
2022-05-03  9:40 ` Claudio Fontana
2022-05-09 12:31   ` Philippe Mathieu-Daudé via
2022-05-09 13:08     ` Claudio Fontana

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to='CAB26zV371f=Sb_mvJ_Hpzoc5CQo3FcRHxwtm8oGHCwWP=bTZEQ@mail.gmail.com' \
    --to=wwcohen@gmail.com \
    --cc=akihiko.odaki@gmail.com \
    --cc=alex.bennee@linaro.org \
    --cc=armbru@redhat.com \
    --cc=dirty@apple.com \
    --cc=f4bug@amsat.org \
    --cc=gustavo@noronha.dev.br \
    --cc=kraxel@redhat.com \
    --cc=peter.maydell@linaro.org \
    --cc=philippe.mathieu.daude@gmail.com \
    --cc=qemu-block@nongnu.org \
    --cc=qemu-devel@nongnu.org \
    --cc=qemu_oss@crudebyte.com \
    --cc=r.bolshakov@yadro.com \
    --cc=thuth@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.