[iOS] Treat a two-finger single tap as if the user tapped with the Cmd key pressed
authorcommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 3 Sep 2019 16:38:09 +0000 (16:38 +0000)
committercommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 3 Sep 2019 16:38:09 +0000 (16:38 +0000)
https://bugs.webkit.org/show_bug.cgi?id=201420
<rdar://problem/53207786>

Patch by Antoine Quint <graouts@apple.com> on 2019-09-03
Reviewed by Simon Fraser.

Source/WebKit:

Set the metaKey modifier to true when generating a click event based on a two-finger single tap. This is important so that sites like Google and DuckDuckGo
correctly open links in their search results page in a new tab in Safari on iOS. This currently doesn't work because those sites will call preventDefault()
if the metaKey flag isn't set on a "click" event, and if it is set, they let the browser handle the navigation themselves.

* UIProcess/ios/WKContentViewInteraction.mm:
(-[WKContentView _twoFingerSingleTapGestureRecognized:]):

Tools:

Add a new twoFingerSingleTapAtPoint() method to UIScriptController, which just calls into the existing (but unused)
-[HIDEventGenerator twoFingerTap:completionBlock:].

* TestRunnerShared/UIScriptContext/Bindings/UIScriptController.idl:
* TestRunnerShared/UIScriptContext/UIScriptController.h:
(WTR::UIScriptController::twoFingerSingleTapAtPoint):
* WebKitTestRunner/ios/UIScriptControllerIOS.h:
* WebKitTestRunner/ios/UIScriptControllerIOS.mm:
(WTR::UIScriptControllerIOS::twoFingerSingleTapAtPoint):

LayoutTests:

Add a new event that checks that a two-finger single tap on a clickable element yields a "click" event with the metaKey flag set to true.

* fast/events/ios/click-event-two-finger-single-tap-meta-key-expected.txt: Added.
* fast/events/ios/click-event-two-finger-single-tap-meta-key.html: Added.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@249431 268f45cc-cd09-0410-ab3c-d52691b4dbfc

LayoutTests/ChangeLog
LayoutTests/fast/events/ios/click-event-two-finger-single-tap-meta-key-expected.txt [new file with mode: 0644]
LayoutTests/fast/events/ios/click-event-two-finger-single-tap-meta-key.html [new file with mode: 0644]
Source/WebKit/ChangeLog
Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm
Tools/ChangeLog
Tools/TestRunnerShared/UIScriptContext/Bindings/UIScriptController.idl
Tools/TestRunnerShared/UIScriptContext/UIScriptController.h
Tools/WebKitTestRunner/ios/UIScriptControllerIOS.h
Tools/WebKitTestRunner/ios/UIScriptControllerIOS.mm

index 48a4555..d16a95b 100644 (file)
@@ -1,3 +1,16 @@
+2019-09-03  Antoine Quint  <graouts@apple.com>
+
+        [iOS] Treat a two-finger single tap as if the user tapped with the Cmd key pressed
+        https://bugs.webkit.org/show_bug.cgi?id=201420
+        <rdar://problem/53207786>
+
+        Reviewed by Simon Fraser.
+
+        Add a new event that checks that a two-finger single tap on a clickable element yields a "click" event with the metaKey flag set to true.
+
+        * fast/events/ios/click-event-two-finger-single-tap-meta-key-expected.txt: Added.
+        * fast/events/ios/click-event-two-finger-single-tap-meta-key.html: Added.
+
 2019-09-03  Rob Buis  <rbuis@igalia.com>
 
         Remove support for load/error on link=prefetch
diff --git a/LayoutTests/fast/events/ios/click-event-two-finger-single-tap-meta-key-expected.txt b/LayoutTests/fast/events/ios/click-event-two-finger-single-tap-meta-key-expected.txt
new file mode 100644 (file)
index 0000000..3fa2581
--- /dev/null
@@ -0,0 +1 @@
+PASS: received click event with metaKey set to true
diff --git a/LayoutTests/fast/events/ios/click-event-two-finger-single-tap-meta-key.html b/LayoutTests/fast/events/ios/click-event-two-finger-single-tap-meta-key.html
new file mode 100644 (file)
index 0000000..b526d33
--- /dev/null
@@ -0,0 +1,47 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <meta name="viewport" content="width=device-width">
+    <script>
+
+        if (window.testRunner) {
+            testRunner.dumpAsText();
+            testRunner.waitUntilDone();
+        }
+        
+        function getUIScript()
+        {
+            return document.getElementById('ui-script').text;
+        }
+
+        function runTest()
+        {
+            if (testRunner.runUIScript)
+                testRunner.runUIScript(`(() => uiController.twoFingerSingleTapAtPoint(50, 50, () => uiController.uiScriptComplete()))()`);
+        }
+        
+        function boxClicked(event)
+        {
+            if (event.metaKey)
+                document.getElementById('target').textContent = 'PASS: received click event with metaKey set to true';
+            else
+                document.getElementById('target').textContent = 'FAIL: received click event with metaKey set to false';
+            testRunner.notifyDone();
+        }
+    </script>
+    <style>
+        #target {
+            height: 100px;
+            width: 100px;
+            background-color: silver;
+        }
+    </style>
+</head>
+<body onload="runTest()">
+
+<div id="target" onclick="boxClicked(event)">
+    FAIL: did not receive click event.
+</div>
+
+</body>
+</html>
index 7c48f08..ca8ce69 100644 (file)
@@ -1,3 +1,18 @@
+2019-09-03  Antoine Quint  <graouts@apple.com>
+
+        [iOS] Treat a two-finger single tap as if the user tapped with the Cmd key pressed
+        https://bugs.webkit.org/show_bug.cgi?id=201420
+        <rdar://problem/53207786>
+
+        Reviewed by Simon Fraser.
+
+        Set the metaKey modifier to true when generating a click event based on a two-finger single tap. This is important so that sites like Google and DuckDuckGo
+        correctly open links in their search results page in a new tab in Safari on iOS. This currently doesn't work because those sites will call preventDefault()
+        if the metaKey flag isn't set on a "click" event, and if it is set, they let the browser handle the navigation themselves.
+
+        * UIProcess/ios/WKContentViewInteraction.mm:
+        (-[WKContentView _twoFingerSingleTapGestureRecognized:]):
+
 2019-08-28  Brent Fulgham  <bfulgham@apple.com>
 
         [macOS] Correct sandbox violation in Flash plugin
index 8bd9382..ddd5675 100644 (file)
@@ -2403,7 +2403,7 @@ static inline bool isSamePair(UIGestureRecognizer *a, UIGestureRecognizer *b, UI
 {
     _isTapHighlightIDValid = YES;
     _isExpectingFastSingleTapCommit = YES;
-    _page->handleTwoFingerTapAtPoint(WebCore::roundedIntPoint(gestureRecognizer.centroid), WebKit::webEventModifierFlags(gestureRecognizerModifierFlags(gestureRecognizer)), ++_latestTapID);
+    _page->handleTwoFingerTapAtPoint(WebCore::roundedIntPoint(gestureRecognizer.centroid), WebKit::webEventModifierFlags(gestureRecognizerModifierFlags(gestureRecognizer) | UIKeyModifierCommand), ++_latestTapID);
 }
 
 - (void)_stylusSingleTapRecognized:(UITapGestureRecognizer *)gestureRecognizer
index f952660..cec38e7 100644 (file)
@@ -1,3 +1,21 @@
+2019-09-03  Antoine Quint  <graouts@apple.com>
+
+        [iOS] Treat a two-finger single tap as if the user tapped with the Cmd key pressed
+        https://bugs.webkit.org/show_bug.cgi?id=201420
+        <rdar://problem/53207786>
+
+        Reviewed by Simon Fraser.
+
+        Add a new twoFingerSingleTapAtPoint() method to UIScriptController, which just calls into the existing (but unused)
+        -[HIDEventGenerator twoFingerTap:completionBlock:].
+
+        * TestRunnerShared/UIScriptContext/Bindings/UIScriptController.idl:
+        * TestRunnerShared/UIScriptContext/UIScriptController.h:
+        (WTR::UIScriptController::twoFingerSingleTapAtPoint):
+        * WebKitTestRunner/ios/UIScriptControllerIOS.h:
+        * WebKitTestRunner/ios/UIScriptControllerIOS.mm:
+        (WTR::UIScriptControllerIOS::twoFingerSingleTapAtPoint):
+
 2019-09-03  Zan Dobersek  <zdobersek@igalia.com>
 
         [WPE] MiniBrowser should handle the WebKitWebView::create signal
index 6b90ae5..d8dbe6e 100644 (file)
@@ -59,6 +59,7 @@ interface UIScriptController {
     void liftUpAtPoint(long x, long y, long touchCount, object callback);
     void singleTapAtPoint(long x, long y, object callback);
     void singleTapAtPointWithModifiers(long x, long y, object modifierArray, object callback);
+    void twoFingerSingleTapAtPoint(long x, long y, object callback);
     void doubleTapAtPoint(long x, long y, float delay, object callback);
     void dragFromPointToPoint(long startX, long startY, long endX, long endY, double durationSeconds, object callback);
 
index 2a36730..1029041 100644 (file)
@@ -137,6 +137,7 @@ public:
     virtual void liftUpAtPoint(long x, long y, long touchCount, JSValueRef callback) { notImplemented(); }
     virtual void singleTapAtPoint(long x, long y, JSValueRef callback) { notImplemented(); }
     virtual void singleTapAtPointWithModifiers(long x, long y, JSValueRef modifierArray, JSValueRef callback) { notImplemented(); }
+    virtual void twoFingerSingleTapAtPoint(long x, long y, JSValueRef callback) { notImplemented(); }
     virtual void doubleTapAtPoint(long x, long y, float delay, JSValueRef callback) { notImplemented(); }
     virtual void dragFromPointToPoint(long startX, long startY, long endX, long endY, double durationSeconds, JSValueRef callback) { notImplemented(); }
     virtual void longPressAtPoint(long x, long y, JSValueRef callback) { notImplemented(); }
index 31272bb..02a61e6 100644 (file)
@@ -53,6 +53,7 @@ public:
     void liftUpAtPoint(long x, long y, long touchCount, JSValueRef) override;
     void singleTapAtPoint(long x, long y, JSValueRef) override;
     void singleTapAtPointWithModifiers(long x, long y, JSValueRef modifierArray, JSValueRef) override;
+    void twoFingerSingleTapAtPoint(long x, long y, JSValueRef callback) override;
     void doubleTapAtPoint(long x, long y, float delay, JSValueRef) override;
     void stylusDownAtPoint(long x, long y, float azimuthAngle, float altitudeAngle, float pressure, JSValueRef) override;
     void stylusMoveToPoint(long x, long y, float azimuthAngle, float altitudeAngle, float pressure, JSValueRef) override;
index 9f3b45f..191c5eb 100644 (file)
@@ -272,6 +272,18 @@ void UIScriptControllerIOS::waitForSingleTapToReset() const
     TestController::singleton().runUntil(doneWaitingForSingleTapToReset, 0.5_s);
 }
 
+void UIScriptControllerIOS::twoFingerSingleTapAtPoint(long x, long y, JSValueRef callback)
+{
+    unsigned callbackID = m_context->prepareForAsyncTask(callback, CallbackTypeNonPersistent);
+
+    auto location = globalToContentCoordinates(webView(), x, y);
+    [[HIDEventGenerator sharedHIDEventGenerator] twoFingerTap:location completionBlock:^{
+        if (!m_context)
+            return;
+        m_context->asyncTaskComplete(callbackID);
+    }];
+}
+
 void UIScriptControllerIOS::singleTapAtPointWithModifiers(long x, long y, JSValueRef modifierArray, JSValueRef callback)
 {
     unsigned callbackID = m_context->prepareForAsyncTask(callback, CallbackTypeNonPersistent);