From 36f119753636d2a2880396c0f4e75634d4cf5304 Mon Sep 17 00:00:00 2001 From: ed Date: Fri, 13 Nov 2020 16:39:20 +0000 Subject: [PATCH] macOS: Forward key events from WKWebView correctly Also added support for selectAll: selector forwarding in NSViewComponentPeer --- .../native/juce_mac_NSViewComponentPeer.mm | 9 +- .../native/juce_mac_WebBrowserComponent.mm | 92 ++++++++++++------- 2 files changed, 63 insertions(+), 38 deletions(-) diff --git a/modules/juce_gui_basics/native/juce_mac_NSViewComponentPeer.mm b/modules/juce_gui_basics/native/juce_mac_NSViewComponentPeer.mm index edadc97e1f..ed74cff79d 100644 --- a/modules/juce_gui_basics/native/juce_mac_NSViewComponentPeer.mm +++ b/modules/juce_gui_basics/native/juce_mac_NSViewComponentPeer.mm @@ -710,9 +710,10 @@ public: handleMagnifyGesture (MouseInputSource::InputSourceType::mouse, getMousePos (ev, view), getMouseTime (ev), 1.0f / invScale); } - void redirectCopy (NSObject*) { handleKeyPress (KeyPress ('c', ModifierKeys (ModifierKeys::commandModifier), 'c')); } - void redirectPaste (NSObject*) { handleKeyPress (KeyPress ('v', ModifierKeys (ModifierKeys::commandModifier), 'v')); } - void redirectCut (NSObject*) { handleKeyPress (KeyPress ('x', ModifierKeys (ModifierKeys::commandModifier), 'x')); } + void redirectCopy (NSObject*) { handleKeyPress (KeyPress ('c', ModifierKeys (ModifierKeys::commandModifier), 'c')); } + void redirectPaste (NSObject*) { handleKeyPress (KeyPress ('v', ModifierKeys (ModifierKeys::commandModifier), 'v')); } + void redirectCut (NSObject*) { handleKeyPress (KeyPress ('x', ModifierKeys (ModifierKeys::commandModifier), 'x')); } + void redirectSelectAll (NSObject*) { handleKeyPress (KeyPress ('a', ModifierKeys (ModifierKeys::commandModifier), 'a')); } void redirectWillMoveToWindow (NSWindow* newWindow) { @@ -1665,6 +1666,7 @@ struct JuceNSViewClass : public ObjCClass addMethod (@selector (paste:), paste, "v@:@"); addMethod (@selector (copy:), copy, "v@:@"); addMethod (@selector (cut:), cut, "v@:@"); + addMethod (@selector (selectAll:), selectAll, "v@:@"); addMethod (@selector (viewWillMoveToWindow:), willMoveToWindow, "v@:@"); @@ -1716,6 +1718,7 @@ private: static void copy (id self, SEL, NSObject* s) { if (auto* p = getOwner (self)) p->redirectCopy (s); } static void paste (id self, SEL, NSObject* s) { if (auto* p = getOwner (self)) p->redirectPaste (s); } static void cut (id self, SEL, NSObject* s) { if (auto* p = getOwner (self)) p->redirectCut (s); } + static void selectAll (id self, SEL, NSObject* s) { if (auto* p = getOwner (self)) p->redirectSelectAll (s); } static void willMoveToWindow (id self, SEL, NSWindow* w) { if (auto* p = getOwner (self)) p->redirectWillMoveToWindow (w); } static BOOL acceptsFirstMouse (id, SEL, NSEvent*) { return YES; } diff --git a/modules/juce_gui_extra/native/juce_mac_WebBrowserComponent.mm b/modules/juce_gui_extra/native/juce_mac_WebBrowserComponent.mm index 13d21c9a9f..a99ad1e96b 100644 --- a/modules/juce_gui_extra/native/juce_mac_WebBrowserComponent.mm +++ b/modules/juce_gui_extra/native/juce_mac_WebBrowserComponent.mm @@ -78,6 +78,55 @@ static NSMutableURLRequest* getRequestForURL (const String& url, const StringArr return nullptr; } +#if JUCE_MAC + +#if JUCE_USE_WKWEBVIEW + using WebViewBase = ObjCClass; +#else + using WebViewBase = ObjCClass; +#endif + +struct WebViewKeyEquivalentResponder : public WebViewBase +{ + WebViewKeyEquivalentResponder() + : WebViewBase ("WebViewKeyEquivalentResponder_") + { + addIvar ("owner"); + addMethod (@selector (performKeyEquivalent:), performKeyEquivalent, @encode (BOOL), "@:@"); + registerClass(); + } + +private: + static WebViewKeyEquivalentResponder* getOwner (id self) + { + return getIvar (self, "owner"); + } + + static BOOL performKeyEquivalent (id self, SEL selector, NSEvent* event) + { + NSResponder* first = [[self window] firstResponder]; + + if (([event modifierFlags] & NSDeviceIndependentModifierFlagsMask) == NSCommandKeyMask) + { + auto sendAction = [&] (SEL actionSelector) -> BOOL + { + return [NSApp sendAction: actionSelector + to: first + from: self]; + }; + + if ([[event charactersIgnoringModifiers] isEqualToString: @"x"]) return sendAction (@selector (cut:)); + if ([[event charactersIgnoringModifiers] isEqualToString: @"c"]) return sendAction (@selector (copy:)); + if ([[event charactersIgnoringModifiers] isEqualToString: @"v"]) return sendAction (@selector (paste:)); + if ([[event charactersIgnoringModifiers] isEqualToString: @"a"]) return sendAction (@selector (selectAll:)); + } + + return sendSuperclassMessage (self, selector, event); + } +}; + +#endif + #if JUCE_USE_WKWEBVIEW struct WebViewDelegateClass : public ObjCClass @@ -96,8 +145,7 @@ struct WebViewDelegateClass : public ObjCClass windowFeatures:), createWebView, "@@:@@@@"); #if WKWEBVIEW_OPENPANEL_SUPPORTED - addMethod (@selector (webView:runOpenPanelWithParameters: - initiatedByFrame:completionHandler:), runOpenPanel, "v@:@@@@"); + addMethod (@selector (webView:runOpenPanelWithParameters:initiatedByFrame:completionHandler:), runOpenPanel, "v@:@@@@"); #endif registerClass(); @@ -211,12 +259,17 @@ public: #if JUCE_MAC auto frame = NSMakeRect (0, 0, 100.0f, 100.0f); + + static WebViewKeyEquivalentResponder webviewClass; + webView = (WKWebView*) webviewClass.createInstance(); + + webView = [webView initWithFrame: frame + configuration: config]; #else auto frame = CGRectMake (0, 0, 100.0f, 100.0f); - #endif - webView = [[WKWebView alloc] initWithFrame: frame configuration: config]; + #endif static WebViewDelegateClass cls; webViewDelegate = [cls.createInstance() init]; @@ -270,37 +323,6 @@ private: #if JUCE_MAC -struct WebViewKeyEquivalentResponder : public ObjCClass -{ - WebViewKeyEquivalentResponder() : ObjCClass ("WebViewKeyEquivalentResponder_") - { - addIvar ("owner"); - addMethod (@selector (performKeyEquivalent:), performKeyEquivalent, @encode (BOOL), "@:@"); - registerClass(); - } - -private: - static WebViewKeyEquivalentResponder* getOwner (id self) - { - return getIvar (self, "owner"); - } - - static BOOL performKeyEquivalent (id self, SEL selector, NSEvent* event) - { - NSResponder* first = [[self window] firstResponder]; - - if (([event modifierFlags] & NSDeviceIndependentModifierFlagsMask) == NSCommandKeyMask) - { - if ([[event charactersIgnoringModifiers] isEqualToString:@"x"]) return [NSApp sendAction:@selector(cut:) to:first from:self]; - if ([[event charactersIgnoringModifiers] isEqualToString:@"c"]) return [NSApp sendAction:@selector(copy:) to:first from:self]; - if ([[event charactersIgnoringModifiers] isEqualToString:@"v"]) return [NSApp sendAction:@selector(paste:) to:first from:self]; - if ([[event charactersIgnoringModifiers] isEqualToString:@"a"]) return [NSApp sendAction:@selector(selectAll:) to:first from:self]; - } - - return sendSuperclassMessage (self, selector, event); - } -}; - struct DownloadClickDetectorClass : public ObjCClass { DownloadClickDetectorClass() : ObjCClass ("JUCEWebClickDetector_")