[GTK] Implement MouseEvent.buttons
authorcarlosgc@webkit.org <carlosgc@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 25 Apr 2018 10:16:59 +0000 (10:16 +0000)
committercarlosgc@webkit.org <carlosgc@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 25 Apr 2018 10:16:59 +0000 (10:16 +0000)
https://bugs.webkit.org/show_bug.cgi?id=184913

Reviewed by Žan Doberšek.

Source/WebCore:

Add helper function to get the state modifier of a GDK button.

* platform/gtk/GtkUtilities.cpp:
(WebCore::stateModifierForGdkButton):
* platform/gtk/GtkUtilities.h:

Source/WebKit:

It's currently returning always 0.

* Shared/gtk/WebEventFactory.cpp:
(WebKit::pressedMouseButtons): Helper function to get the pressed mouse buttons.
(WebKit::WebEventFactory::createWebMouseEvent): Pass presssed mouse buttons to constructor instead of 0.
* UIProcess/Automation/gtk/WebAutomationSessionGtk.cpp:
(WebKit::WebAutomationSession::platformSimulateMouseInteraction): Include the mouse buttons state in automation
synthesized events and update m_currentModifiers with the mouse buttons state.
(WebKit::keyCodeForVirtualKey): Do not set the state here.
(WebKit::modifiersForKeyCode): Helper to get the modifiers for a key code.
(WebKit::WebAutomationSession::platformSimulateKeyboardInteraction): Initialize the modifiers also when
virtualKey is std::nullopt;

Tools:

Include the mouse buttons state in WTR synthesized events.

* WebKitTestRunner/EventSenderProxy.h:
* WebKitTestRunner/gtk/EventSenderProxyGtk.cpp:
(WTR::EventSenderProxy::EventSenderProxy):
(WTR::EventSenderProxy::createMouseButtonEvent):
(WTR::EventSenderProxy::mouseDown):
(WTR::EventSenderProxy::mouseUp):
(WTR::EventSenderProxy::mouseMoveTo):

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

Source/WebCore/ChangeLog
Source/WebCore/platform/gtk/GtkUtilities.cpp
Source/WebCore/platform/gtk/GtkUtilities.h
Source/WebKit/ChangeLog
Source/WebKit/Shared/gtk/WebEventFactory.cpp
Source/WebKit/UIProcess/Automation/gtk/WebAutomationSessionGtk.cpp
Tools/ChangeLog
Tools/WebKitTestRunner/EventSenderProxy.h
Tools/WebKitTestRunner/gtk/EventSenderProxyGtk.cpp

index 195df52..fc2a457 100644 (file)
@@ -1,3 +1,16 @@
+2018-04-25  Carlos Garcia Campos  <cgarcia@igalia.com>
+
+        [GTK] Implement MouseEvent.buttons
+        https://bugs.webkit.org/show_bug.cgi?id=184913
+
+        Reviewed by Žan Doberšek.
+
+        Add helper function to get the state modifier of a GDK button.
+
+        * platform/gtk/GtkUtilities.cpp:
+        (WebCore::stateModifierForGdkButton):
+        * platform/gtk/GtkUtilities.h:
+
 2018-04-24  Ryosuke Niwa  <rniwa@webkit.org>
 
         Release assert in ScriptController::canExecuteScripts via CachedSVGFont::ensureCustomFontData during
index f3ec342..4f26d41 100644 (file)
@@ -77,4 +77,9 @@ String defaultGtkSystemFont()
     return String::fromUTF8(fontString.get());
 }
 
+unsigned stateModifierForGdkButton(unsigned button)
+{
+    return 1 << (8 + button - 1);
+}
+
 } // namespace WebCore
index 53f9070..c8d0870 100644 (file)
@@ -16,8 +16,7 @@
  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
  */
 
-#ifndef GtkUtilities_h 
-#define GtkUtilities_h 
+#pragma once
 
 #include <gtk/gtk.h>
 #include <wtf/MonotonicTime.h>
@@ -45,6 +44,6 @@ WallTime wallTimeForEvent(const GdkEvent*);
 
 String defaultGtkSystemFont();
 
-} // namespace WebCore
+unsigned stateModifierForGdkButton(unsigned button);
 
-#endif // GtkUtilities_h
+} // namespace WebCore
index bd54e36..f5b3dcb 100644 (file)
@@ -1,3 +1,23 @@
+2018-04-25  Carlos Garcia Campos  <cgarcia@igalia.com>
+
+        [GTK] Implement MouseEvent.buttons
+        https://bugs.webkit.org/show_bug.cgi?id=184913
+
+        Reviewed by Žan Doberšek.
+
+        It's currently returning always 0.
+
+        * Shared/gtk/WebEventFactory.cpp:
+        (WebKit::pressedMouseButtons): Helper function to get the pressed mouse buttons.
+        (WebKit::WebEventFactory::createWebMouseEvent): Pass presssed mouse buttons to constructor instead of 0.
+        * UIProcess/Automation/gtk/WebAutomationSessionGtk.cpp:
+        (WebKit::WebAutomationSession::platformSimulateMouseInteraction): Include the mouse buttons state in automation
+        synthesized events and update m_currentModifiers with the mouse buttons state.
+        (WebKit::keyCodeForVirtualKey): Do not set the state here.
+        (WebKit::modifiersForKeyCode): Helper to get the modifiers for a key code.
+        (WebKit::WebAutomationSession::platformSimulateKeyboardInteraction): Initialize the modifiers also when
+        virtualKey is std::nullopt;
+
 2018-04-24  Nan Wang  <n_wang@apple.com>
 
         AX: soft link libAccessibility.dylb
index dd94e19..c9151a9 100644 (file)
@@ -106,12 +106,40 @@ static inline WebMouseEvent::Button buttonForEvent(const GdkEvent* event)
     return static_cast<WebMouseEvent::Button>(button);
 }
 
+static inline short pressedMouseButtons(GdkModifierType state)
+{
+    // MouseEvent.buttons
+    // https://www.w3.org/TR/uievents/#ref-for-dom-mouseevent-buttons-1
+
+    // 0 MUST indicate no button is currently active.
+    short buttons = 0;
+
+    // 1 MUST indicate the primary button of the device (in general, the left button or the only button on
+    // single-button devices, used to activate a user interface control or select text).
+    if (state & GDK_BUTTON1_MASK)
+        buttons |= 1;
+
+    // 4 MUST indicate the auxiliary button (in general, the middle button, often combined with a mouse wheel).
+    if (state & GDK_BUTTON2_MASK)
+        buttons |= 4;
+
+    // 2 MUST indicate the secondary button (in general, the right button, often used to display a context menu),
+    // if present.
+    if (state & GDK_BUTTON3_MASK)
+        buttons |= 2;
+
+    return buttons;
+}
+
 WebMouseEvent WebEventFactory::createWebMouseEvent(const GdkEvent* event, int currentClickCount)
 {
     double x, y, xRoot, yRoot;
     gdk_event_get_coords(event, &x, &y);
     gdk_event_get_root_coords(event, &xRoot, &yRoot);
 
+    GdkModifierType state = static_cast<GdkModifierType>(0);
+    gdk_event_get_state(event, &state);
+
     WebEvent::Type type = static_cast<WebEvent::Type>(0);
     switch (event->type) {
     case GDK_MOTION_NOTIFY:
@@ -121,19 +149,25 @@ WebMouseEvent WebEventFactory::createWebMouseEvent(const GdkEvent* event, int cu
         break;
     case GDK_BUTTON_PRESS:
     case GDK_2BUTTON_PRESS:
-    case GDK_3BUTTON_PRESS:
+    case GDK_3BUTTON_PRESS: {
         type = WebEvent::MouseDown;
+        auto modifier = stateModifierForGdkButton(event->button.button);
+        state = static_cast<GdkModifierType>(state | modifier);
         break;
-    case GDK_BUTTON_RELEASE:
+    }
+    case GDK_BUTTON_RELEASE: {
         type = WebEvent::MouseUp;
+        auto modifier = stateModifierForGdkButton(event->button.button);
+        state = static_cast<GdkModifierType>(state & ~modifier);
         break;
+    }
     default :
         ASSERT_NOT_REACHED();
     }
 
     return WebMouseEvent(type,
         buttonForEvent(event),
-        0,
+        pressedMouseButtons(state),
         IntPoint(x, y),
         IntPoint(xRoot, yRoot),
         0 /* deltaX */,
index bf0d5e6..594a813 100644 (file)
@@ -28,6 +28,7 @@
 
 #include "WebAutomationSessionMacros.h"
 #include "WebPageProxy.h"
+#include <WebCore/GtkUtilities.h>
 #include <gtk/gtk.h>
 
 namespace WebKit {
@@ -104,7 +105,8 @@ static void doMotionEvent(GtkWidget* widget, const WebCore::IntPoint& location,
 void WebAutomationSession::platformSimulateMouseInteraction(WebPageProxy& page, MouseInteraction interaction, WebMouseEvent::Button button, const WebCore::IntPoint& locationInView, WebEvent::Modifiers keyModifiers)
 {
     unsigned gdkButton = mouseButtonToGdkButton(button);
-    unsigned state = modifiersToEventState(keyModifiers);
+    auto modifier = stateModifierForGdkButton(gdkButton);
+    unsigned state = modifiersToEventState(keyModifiers) | m_currentModifiers;
 
     switch (interaction) {
     case MouseInteraction::Move:
@@ -112,19 +114,21 @@ void WebAutomationSession::platformSimulateMouseInteraction(WebPageProxy& page,
         break;
     case MouseInteraction::Down:
         doMouseEvent(GDK_BUTTON_PRESS, page.viewWidget(), locationInView, gdkButton, state);
+        m_currentModifiers |= modifier;
         break;
     case MouseInteraction::Up:
         doMouseEvent(GDK_BUTTON_RELEASE, page.viewWidget(), locationInView, gdkButton, state);
+        m_currentModifiers &= ~modifier;
         break;
     case MouseInteraction::SingleClick:
         doMouseEvent(GDK_BUTTON_PRESS, page.viewWidget(), locationInView, gdkButton, state);
-        doMouseEvent(GDK_BUTTON_RELEASE, page.viewWidget(), locationInView, gdkButton, state);
+        doMouseEvent(GDK_BUTTON_RELEASE, page.viewWidget(), locationInView, gdkButton, state | modifier);
         break;
     case MouseInteraction::DoubleClick:
         doMouseEvent(GDK_BUTTON_PRESS, page.viewWidget(), locationInView, gdkButton, state);
-        doMouseEvent(GDK_BUTTON_RELEASE, page.viewWidget(), locationInView, gdkButton, state);
+        doMouseEvent(GDK_BUTTON_RELEASE, page.viewWidget(), locationInView, gdkButton, state | modifier);
         doMouseEvent(GDK_BUTTON_PRESS, page.viewWidget(), locationInView, gdkButton, state);
-        doMouseEvent(GDK_BUTTON_RELEASE, page.viewWidget(), locationInView, gdkButton, state);
+        doMouseEvent(GDK_BUTTON_RELEASE, page.viewWidget(), locationInView, gdkButton, state | modifier);
         break;
     }
 }
@@ -156,21 +160,16 @@ static void doKeyStrokeEvent(GdkEventType type, GtkWidget* widget, unsigned keyV
     }
 }
 
-static int keyCodeForVirtualKey(Inspector::Protocol::Automation::VirtualKey key, GdkModifierType& state)
+static int keyCodeForVirtualKey(Inspector::Protocol::Automation::VirtualKey key)
 {
-    state = static_cast<GdkModifierType>(0);
     switch (key) {
     case Inspector::Protocol::Automation::VirtualKey::Shift:
-        state = GDK_SHIFT_MASK;
         return GDK_KEY_Shift_R;
     case Inspector::Protocol::Automation::VirtualKey::Control:
-        state = GDK_CONTROL_MASK;
         return GDK_KEY_Control_R;
     case Inspector::Protocol::Automation::VirtualKey::Alternate:
-        state = GDK_MOD1_MASK;
         return GDK_KEY_Alt_L;
     case Inspector::Protocol::Automation::VirtualKey::Meta:
-        state = GDK_META_MASK;
         return GDK_KEY_Meta_R;
     case Inspector::Protocol::Automation::VirtualKey::Command:
         return GDK_KEY_Execute;
@@ -280,24 +279,39 @@ static int keyCodeForVirtualKey(Inspector::Protocol::Automation::VirtualKey key,
     return 0;
 }
 
+static unsigned modifiersForKeyCode(unsigned keyCode)
+{
+    switch (keyCode) {
+    case GDK_KEY_Shift_R:
+        return GDK_SHIFT_MASK;
+    case GDK_KEY_Control_R:
+        return GDK_CONTROL_MASK;
+    case GDK_KEY_Alt_L:
+        return GDK_MOD1_MASK;
+    case GDK_KEY_Meta_R:
+        return GDK_META_MASK;
+    }
+    return 0;
+}
+
 void WebAutomationSession::platformSimulateKeyboardInteraction(WebPageProxy& page, KeyboardInteraction interaction, std::optional<VirtualKey> virtualKey, std::optional<CharKey> charKey)
 {
     ASSERT(virtualKey.has_value() || charKey.has_value());
 
-    GdkModifierType updateState;
-    int keyCode;
+    unsigned keyCode;
     if (virtualKey.has_value())
-        keyCode = keyCodeForVirtualKey(virtualKey.value(), updateState);
+        keyCode = keyCodeForVirtualKey(virtualKey.value());
     else
         keyCode = gdk_unicode_to_keyval(g_utf8_get_char(&charKey.value()));
+    unsigned modifiers = modifiersForKeyCode(keyCode);
 
     switch (interaction) {
     case KeyboardInteraction::KeyPress:
-        m_currentModifiers |= updateState;
+        m_currentModifiers |= modifiers;
         doKeyStrokeEvent(GDK_KEY_PRESS, page.viewWidget(), keyCode, m_currentModifiers);
         break;
     case KeyboardInteraction::KeyRelease:
-        m_currentModifiers &= ~updateState;
+        m_currentModifiers &= ~modifiers;
         doKeyStrokeEvent(GDK_KEY_RELEASE, page.viewWidget(), keyCode, m_currentModifiers);
         break;
     case KeyboardInteraction::InsertByKey:
index f78f818..4eefc0d 100644 (file)
@@ -1,3 +1,20 @@
+2018-04-25  Carlos Garcia Campos  <cgarcia@igalia.com>
+
+        [GTK] Implement MouseEvent.buttons
+        https://bugs.webkit.org/show_bug.cgi?id=184913
+
+        Reviewed by Žan Doberšek.
+
+        Include the mouse buttons state in WTR synthesized events.
+
+        * WebKitTestRunner/EventSenderProxy.h:
+        * WebKitTestRunner/gtk/EventSenderProxyGtk.cpp:
+        (WTR::EventSenderProxy::EventSenderProxy):
+        (WTR::EventSenderProxy::createMouseButtonEvent):
+        (WTR::EventSenderProxy::mouseDown):
+        (WTR::EventSenderProxy::mouseUp):
+        (WTR::EventSenderProxy::mouseMoveTo):
+
 2018-04-24  Pablo Saavedra  <psaavedra@igalia.com>
 
         [GTK][WPE] Fix triggered bot name on the WPE Debug Build bot
index b2a8b4f..665e7ad 100644 (file)
@@ -136,7 +136,7 @@ private:
     int eventNumber;
 #elif PLATFORM(GTK)
     Deque<WTREventQueueItem> m_eventQueue;
-    unsigned m_mouseButtonCurrentlyDown;
+    unsigned m_mouseButtonsCurrentlyDown { 0 };
     Vector<GUniquePtr<GdkEvent>> m_touchEvents;
     HashSet<int> m_updatedTouchEvents;
 #elif PLATFORM(WPE)
index 6b916df..de578f7 100644 (file)
@@ -35,6 +35,7 @@
 
 #include "PlatformWebView.h"
 #include "TestController.h"
+#include <WebCore/GtkUtilities.h>
 #include <WebCore/NotImplemented.h>
 #include <gdk/gdkkeysyms.h>
 #include <gtk/gtk.h>
@@ -79,7 +80,6 @@ EventSenderProxy::EventSenderProxy(TestController* testController)
     , m_clickCount(0)
     , m_clickTime(0)
     , m_clickButton(kWKEventMouseButtonNoButton)
-    , m_mouseButtonCurrentlyDown(0)
 {
 }
 
@@ -87,17 +87,6 @@ EventSenderProxy::~EventSenderProxy()
 {
 }
 
-static guint getMouseButtonModifiers(int gdkButton)
-{
-    if (gdkButton == 1)
-        return GDK_BUTTON1_MASK;
-    if (gdkButton == 2)
-        return GDK_BUTTON2_MASK;
-    if (gdkButton == 3)
-        return GDK_BUTTON3_MASK;
-    return 0;
-}
-
 static unsigned eventSenderButtonToGDKButton(unsigned button)
 {
     int mouseButton = 3;
@@ -132,13 +121,13 @@ GdkEvent* EventSenderProxy::createMouseButtonEvent(GdkEventType eventType, unsig
 {
     GdkEvent* mouseEvent = gdk_event_new(eventType);
 
-    mouseEvent->button.button = eventSenderButtonToGDKButton(button);
+    mouseEvent->button.button = button;
     mouseEvent->button.x = m_position.x;
     mouseEvent->button.y = m_position.y;
     mouseEvent->button.window = gtk_widget_get_window(GTK_WIDGET(m_testController->mainWebView()->platformView()));
     g_object_ref(mouseEvent->button.window);
     gdk_event_set_device(mouseEvent, gdk_device_manager_get_client_pointer(gdk_display_get_device_manager(gdk_window_get_display(mouseEvent->button.window))));
-    mouseEvent->button.state = webkitModifiersToGDKModifiers(modifiers) | getMouseButtonModifiers(mouseEvent->button.button);
+    mouseEvent->button.state = webkitModifiersToGDKModifiers(modifiers) | m_mouseButtonsCurrentlyDown;
     mouseEvent->button.time = GDK_CURRENT_TIME;
     mouseEvent->button.axes = 0;
 
@@ -326,14 +315,14 @@ void EventSenderProxy::keyDown(WKStringRef keyRef, WKEventModifiers wkModifiers,
 
 void EventSenderProxy::mouseDown(unsigned button, WKEventModifiers wkModifiers)
 {
+    unsigned gdkButton = eventSenderButtonToGDKButton(button);
+    auto modifier = WebCore::stateModifierForGdkButton(gdkButton);
+
     // If the same mouse button is already in the down position don't
     // send another event as it may confuse Xvfb.
-    unsigned gdkButton = eventSenderButtonToGDKButton(button);
-    if (m_mouseButtonCurrentlyDown == gdkButton)
+    if (m_mouseButtonsCurrentlyDown & modifier)
         return;
 
-    m_mouseButtonCurrentlyDown = gdkButton;
-
     // Normally GDK will send both GDK_BUTTON_PRESS and GDK_2BUTTON_PRESS for
     // the second button press during double-clicks. WebKit GTK+ selectively
     // ignores the first GDK_BUTTON_PRESS of that pair using gdk_event_peek.
@@ -352,18 +341,20 @@ void EventSenderProxy::mouseDown(unsigned button, WKEventModifiers wkModifiers)
     else
         eventType = GDK_BUTTON_PRESS;
 
-    GdkEvent* event = createMouseButtonEvent(eventType, button, wkModifiers);
+    GdkEvent* event = createMouseButtonEvent(eventType, gdkButton, wkModifiers);
+    m_mouseButtonsCurrentlyDown |= modifier;
     sendOrQueueEvent(event);
 }
 
 void EventSenderProxy::mouseUp(unsigned button, WKEventModifiers wkModifiers)
 {
     m_clickButton = kWKEventMouseButtonNoButton;
-    GdkEvent* event = createMouseButtonEvent(GDK_BUTTON_RELEASE, button, wkModifiers);
+    unsigned gdkButton = eventSenderButtonToGDKButton(button);
+    GdkEvent* event = createMouseButtonEvent(GDK_BUTTON_RELEASE, gdkButton, wkModifiers);
+    auto modifier = WebCore::stateModifierForGdkButton(gdkButton);
+    m_mouseButtonsCurrentlyDown &= ~modifier;
     sendOrQueueEvent(event);
 
-    if (m_mouseButtonCurrentlyDown == event->button.button)
-        m_mouseButtonCurrentlyDown = 0;
     m_clickPosition = m_position;
     m_clickTime = GDK_CURRENT_TIME;
 }
@@ -381,7 +372,7 @@ void EventSenderProxy::mouseMoveTo(double x, double y)
     event->motion.window = gtk_widget_get_window(GTK_WIDGET(m_testController->mainWebView()->platformView()));
     g_object_ref(event->motion.window);
     gdk_event_set_device(event, gdk_device_manager_get_client_pointer(gdk_display_get_device_manager(gdk_window_get_display(event->motion.window))));
-    event->motion.state = 0 | getMouseButtonModifiers(m_mouseButtonCurrentlyDown);
+    event->motion.state = m_mouseButtonsCurrentlyDown;
     event->motion.axes = 0;
 
     int xRoot, yRoot;