Skip to content

Commit

Permalink
8278759: PointerEvent: buttons property set to 0 when mouse down
Browse files Browse the repository at this point in the history
Backport-of: 2e8a4a5
  • Loading branch information
arapte committed May 2, 2022
1 parent 350fb53 commit dd592f1
Show file tree
Hide file tree
Showing 8 changed files with 301 additions and 9 deletions.
4 changes: 2 additions & 2 deletions modules/javafx.web/src/main/java/com/sun/webkit/WebPage.java
Original file line number Diff line number Diff line change
Expand Up @@ -816,7 +816,7 @@ public boolean dispatchMouseEvent(WCMouseEvent me) {
//for system DnD loop and not intereasted in
//intermediate mouse events that can change text selection.
&& twkProcessMouseEvent(getPage(), me.getID(),
me.getButton(), me.getClickCount(),
me.getButton(), me.getButtonMask(), me.getClickCount(),
me.getX(), me.getY(), me.getScreenX(), me.getScreenY(),
me.isShiftDown(), me.isControlDown(), me.isAltDown(), me.isMetaDown(), me.isPopupTrigger(),
me.getWhen() / 1000.0);
Expand Down Expand Up @@ -2626,7 +2626,7 @@ private native boolean twkProcessKeyEvent(long pPage, int type, String text,
boolean shift, boolean ctrl,
boolean alt, boolean meta, double when);
private native boolean twkProcessMouseEvent(long pPage, int id,
int button, int clickCount,
int button, int buttonMask, int clickCount,
int x, int y, int sx, int sy,
boolean shift, boolean control, boolean alt, boolean meta,
boolean popupTrigger, double when);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,14 +38,15 @@ public final class WCMouseEvent {

// button
@Native public final static int NOBUTTON = 0;
@Native public final static int BUTTON1 = 1;
@Native public final static int BUTTON2 = 2;
@Native public final static int BUTTON3 = 4;
@Native public final static int BUTTON1 = 1; // Left Button
@Native public final static int BUTTON2 = 2; // Middle Button
@Native public final static int BUTTON3 = 4; // Right Button

private final int id;
private final long when;

private final int button;
private final int buttonMask;
private final int clickCount;

private final int x;
Expand All @@ -61,8 +62,7 @@ public final class WCMouseEvent {
private final boolean popupTrigger;

public WCMouseEvent(int id, int button, int clickCount, int x, int y, int screenX, int screenY,
long when, boolean shift, boolean control, boolean alt, boolean meta, boolean popupTrigger)
{
long when, boolean shift, boolean control, boolean alt, boolean meta, boolean popupTrigger, int buttonMask) {
this.id = id;
this.button = button;
this.clickCount = clickCount;
Expand All @@ -76,8 +76,14 @@ public WCMouseEvent(int id, int button, int clickCount, int x, int y, int screen
this.alt = alt;
this.meta = meta;
this.popupTrigger = popupTrigger;
this.buttonMask = buttonMask;
}

public WCMouseEvent(int id, int button, int clickCount, int x, int y, int screenX, int screenY,
long when, boolean shift, boolean control, boolean alt, boolean meta, boolean popupTrigger) {
this(id, button, clickCount, x, y, screenX, screenY, when, shift, control, alt, meta, popupTrigger, 0);
}

public int getID() { return id; }
public long getWhen() { return when; }

Expand All @@ -95,4 +101,6 @@ public WCMouseEvent(int id, int button, int clickCount, int x, int y, int screen
public boolean isMetaDown() { return meta; }

public boolean isPopupTrigger() { return popupTrigger; }

public int getButtonMask() { return buttonMask; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -1010,13 +1010,16 @@ private void processMouseEvent(MouseEvent ev) {
// not supported by webkit
return;
}
final int buttonMask = ((ev.isPrimaryButtonDown() ? WCMouseEvent.BUTTON1 : WCMouseEvent.NOBUTTON) |
(ev.isMiddleButtonDown() ? WCMouseEvent.BUTTON2 : WCMouseEvent.NOBUTTON) |
(ev.isSecondaryButtonDown() ? WCMouseEvent.BUTTON3 : WCMouseEvent.NOBUTTON));
WCMouseEvent mouseEvent =
new WCMouseEvent(id, button,
ev.getClickCount(), (int) x, (int) y,
(int) screenX, (int) screenY,
System.currentTimeMillis(),
ev.isShiftDown(), ev.isControlDown(), ev.isAltDown(),
ev.isMetaDown(), ev.isPopupTrigger());
ev.isMetaDown(), ev.isPopupTrigger(), buttonMask);
page.dispatchMouseEvent(mouseEvent);
ev.consume();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ const double ForceAtForceClick = 2;
// indicate that the pressed mouse button hasn't changed since the last event.
enum MouseButton : int8_t { LeftButton = 0, MiddleButton, RightButton, NoButton = -2 };
enum SyntheticClickType : int8_t { NoTap, OneFingerTap, TwoFingerTap };
#if PLATFORM(JAVA)
enum MouseButtonMask : uint8_t { NoButtonMask = 0, LeftButtonMask, RightButtonMask, MiddleButtonMask = 4 };
#endif

class PlatformMouseEvent : public PlatformEvent {
public:
Expand All @@ -65,6 +68,23 @@ const double ForceAtForceClick = 2;
{
}

#if PLATFORM(JAVA)
PlatformMouseEvent(const IntPoint& position, const IntPoint& globalPosition, MouseButton button, unsigned short buttons, PlatformEvent::Type type,
int clickCount, bool shiftKey, bool ctrlKey, bool altKey, bool metaKey, WallTime timestamp, double force,
SyntheticClickType syntheticClickType, PointerID pointerId = mousePointerID)
: PlatformEvent(type, shiftKey, ctrlKey, altKey, metaKey, timestamp)
, m_button(button)
, m_syntheticClickType(syntheticClickType)
, m_position(position)
, m_globalPosition(globalPosition)
, m_force(force)
, m_pointerId(pointerId)
, m_clickCount(clickCount)
, m_buttons(buttons)
{
}
#endif

// This position is relative to the enclosing NSWindow in WebKit1, and is WKWebView-relative in WebKit2.
// Use ScrollView::windowToContents() to convert it to into the contents of a given view.
const IntPoint& position() const { return m_position; }
Expand Down Expand Up @@ -136,6 +156,7 @@ const double ForceAtForceClick = 2;

#if PLATFORM(JAVA)
MouseButton getWebCoreMouseButton(jint javaButton);
unsigned short getWebCoreMouseButtons(jint javaButton);
PlatformEvent::Type getWebCoreMouseEventType(jint eventID);
#endif

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,21 @@ MouseButton getWebCoreMouseButton(jint javaButton)
}
}

unsigned short getWebCoreMouseButtons(jint javaButton)
{
unsigned short buttons = NoButtonMask;
if (javaButton & com_sun_webkit_event_WCMouseEvent_BUTTON1) {
buttons |= LeftButtonMask;
}
if (javaButton & com_sun_webkit_event_WCMouseEvent_BUTTON2) {
buttons |= MiddleButtonMask;
}
if (javaButton & com_sun_webkit_event_WCMouseEvent_BUTTON3) {
buttons |= RightButtonMask;
}
return buttons;
}

PlatformEvent::Type getWebCoreMouseEventType(jint eventID)
{
switch (eventID) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1748,7 +1748,7 @@ JNIEXPORT jboolean JNICALL Java_com_sun_webkit_WebPage_twkProcessKeyEvent

JNIEXPORT jboolean JNICALL Java_com_sun_webkit_WebPage_twkProcessMouseEvent
(JNIEnv* env, jobject self, jlong pPage,
jint id, jint button, jint clickCount,
jint id, jint button, jint buttonMask, jint clickCount,
jint x, jint y, jint screenX, jint screenY,
jboolean shift, jboolean ctrl, jboolean alt, jboolean meta,
jboolean popupTrigger, jdouble timestamp)
Expand All @@ -1774,6 +1774,7 @@ JNIEXPORT jboolean JNICALL Java_com_sun_webkit_WebPage_twkProcessMouseEvent
PlatformMouseEvent mouseEvent = PlatformMouseEvent(loc,
IntPoint(screenX, screenY),
getWebCoreMouseButton(button),
getWebCoreMouseButtons(buttonMask),
getWebCoreMouseEventType(id),
clickCount,
shift, ctrl, alt, meta,
Expand Down
225 changes: 225 additions & 0 deletions tests/system/src/test/java/test/robot/javafx/web/PointerEventTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,225 @@
/*
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
p * This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/

package test.robot.javafx.web;

import com.sun.javafx.PlatformUtil;

import javafx.application.Application;
import javafx.application.Platform;
import javafx.beans.value.ObservableValue;
import javafx.concurrent.Worker.State;
import javafx.concurrent.Worker;
import javafx.scene.input.MouseButton;
import javafx.scene.layout.StackPane;
import javafx.scene.robot.Robot;
import javafx.scene.Scene;
import javafx.scene.web.WebEngine;
import javafx.scene.web.WebView;
import javafx.scene.input.KeyCode;
import javafx.stage.Stage;

import java.lang.Integer;
import java.lang.Number;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

import org.w3c.dom.Document;
import org.w3c.dom.Element;

import org.junit.After;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;

import test.util.Util;

import static org.junit.Assert.*;

/*
* Tests for validating the buttons property received in "pointermove" event,
* when various mouse buttons are pressed and dragged
* testLeftButtonDrag - Press the Mouse Left Button and drag
* testRightButtonDrag - Press the Mouse Right Button and drag
* testMiddleButtonDrag - Press the Mouse Middle Button and drag
* testLeftMiddleButtonDrag - Press Left and Middle Buttons and drag
* testMiddleRightButtonDrag - Press Middle and Right Buttons and drag
* testLeftRightButtonDrag - Press Left and Right Buttons and drag
* testLeftMiddleRightButtonDrag- Press Left, Middle and Right Buttons and drag
*/

public class PointerEventTest {

private static final int LEFT_BUTTON_DRAG = 1;
private static final int MIDDLE_BUTTON_DRAG = 4;
private static final int RIGHT_BUTTON_DRAG = 2;
private static final int SCENE_WIDTH = 250;
private static final int SCENE_HEIGHT = SCENE_WIDTH;
// Sleep time between mouseMove and element access
private static final int SLEEP_TIME = 500;

private final int DRAG_DISTANCE = 15;
private final int DX = 125;
private final int DY = 125;

private static CountDownLatch startupLatch;

static Document document;
static Element element;
static Robot robot;
static WebView webView;
static WebEngine webEngine;

static volatile Stage stage;
static volatile Scene scene;

private String buttonMask;
private int result = 0;

public static class TestApp extends Application {
@Override
public void start(Stage primaryStage) {
robot = new Robot();
stage = primaryStage;
stage.setTitle("Mouse Drag Test");
webView = new WebView();
webEngine = webView.getEngine();
String URL = this.getClass().getResource("pointerEvent.html").toString();
webView.getEngine().getLoadWorker().stateProperty().addListener((ov, o, n) -> {
if (n == Worker.State.SUCCEEDED) {
document = webEngine.getDocument();
element = document.getElementById("buttonPressed");
startupLatch.countDown();
}
});
webEngine.load(URL);
scene = new Scene(new StackPane(webView), SCENE_WIDTH, SCENE_HEIGHT);
stage.setScene(scene);
stage.setAlwaysOnTop(true);
stage.setOnShown(e -> startupLatch.countDown());
stage.show();
}
}

public int mouseButtonDrag(MouseButton... buttons) {
Util.runAndWait(() -> {
robot.mouseMove((int)(scene.getWindow().getX() + scene.getX() + DX),
(int)(scene.getWindow().getY() + scene.getY() + DY));
robot.mousePress(buttons);
});

Util.runAndWait(() -> {
for (int i = 0; i < DRAG_DISTANCE; i++) {
// Move the mouse backwards so that the pointer does not stay on the popup, if any.
robot.mouseMove((int)(scene.getWindow().getX() + scene.getX() + DX - i),
(int)(scene.getWindow().getY() + scene.getY() + DY));
}
});

Util.sleep(SLEEP_TIME);
Util.runAndWait(() -> {
buttonMask = element.getTextContent();
robot.mouseRelease(buttons);
});

return Integer.parseInt(buttonMask);
}

@Test
public void testLeftButtonDrag() {
int result = mouseButtonDrag(MouseButton.PRIMARY);
assertEquals(LEFT_BUTTON_DRAG, result);
}

@Test
public void testRightButtonDrag() {
int result = mouseButtonDrag(MouseButton.SECONDARY);
assertEquals(RIGHT_BUTTON_DRAG, result);
}

@Test
public void testMiddleButtonDrag() {
int result = mouseButtonDrag(MouseButton.MIDDLE);
assertEquals(MIDDLE_BUTTON_DRAG, result);
}

@Test
public void testLeftMiddleButtonDrag() {
int result = mouseButtonDrag(MouseButton.PRIMARY, MouseButton.MIDDLE);
assertEquals((LEFT_BUTTON_DRAG | MIDDLE_BUTTON_DRAG), result);
}

@Test
public void testMiddleRightButtonDrag() {
int result = mouseButtonDrag(MouseButton.MIDDLE, MouseButton.SECONDARY);
assertEquals((MIDDLE_BUTTON_DRAG | RIGHT_BUTTON_DRAG), result);
}

@Test
public void testLeftRightButtonDrag() {
int result = mouseButtonDrag(MouseButton.PRIMARY, MouseButton.SECONDARY);
assertEquals((LEFT_BUTTON_DRAG | RIGHT_BUTTON_DRAG), result);
}

@Test
public void testLeftMiddleRightButtonDrag() {
int result = mouseButtonDrag(MouseButton.PRIMARY, MouseButton.MIDDLE, MouseButton.SECONDARY);
assertEquals((LEFT_BUTTON_DRAG | MIDDLE_BUTTON_DRAG | RIGHT_BUTTON_DRAG), result);
}

@BeforeClass
public static void initFX() {
startupLatch = new CountDownLatch(2);
new Thread(() -> Application.launch(TestApp.class, (String[])null)).start();
waitForLatch(startupLatch, 15, "Timeout waiting for FX runtime to start");
}

@AfterClass
public static void exit() {
Platform.runLater(() -> {
stage.hide();
});
Platform.exit();
}

@After
public void resetTest() {
Util.runAndWait(() -> {
robot.mouseRelease(MouseButton.PRIMARY, MouseButton.MIDDLE, MouseButton.SECONDARY);
robot.keyType(KeyCode.ESCAPE);
});
}

public static void waitForLatch(CountDownLatch latch, int seconds, String msg) {
try {
if (!latch.await(seconds, TimeUnit.SECONDS)) {
fail(msg);
}
} catch (Exception ex) {
fail("Unexpected exception: " + ex);
}
}
}

1 comment on commit dd592f1

@openjdk-notifier
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.