Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8187126

[win]WebView embedded in a Swing JFrame reports MouseEvent.metaKey=true for a right click to JavaScript

XMLWordPrintable

    • web
    • generic
    • windows

      FULL PRODUCT VERSION :


      ADDITIONAL OS VERSION INFORMATION :
      Windows 10

      EXTRA RELEVANT SYSTEM CONFIGURATION :
      - tested on MacOS to verify that it's Windows specific


      A DESCRIPTION OF THE PROBLEM :
      The attached sample shows that the webview invokes the onContextMenu mouse event in JavaScript and falsely reports metaKey=true.
      Running the same HTML in a pure JavaFX web view (not embedded in Swing) does not show this anomaly and correctly reports no modifier. So it looks like somewhere in the Swing/JavaFX embedding something goes in the weeds.

      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      - run the attached sample in Windows
      - right-click on the yellow box to see what modifier keys are reported to JavaScript
      - compare with Mac OS or other OS
      - use the "contextmenu.html" down in the source code to test with pure JavaFX WebView, like from the Oracle sample, or with plain web browsers

      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      expecting "metaKey=false" if no modifier key is pressed while performing mouse right-click

      REPRODUCIBILITY :
      This bug can be reproduced always.

      ---------- BEGIN SOURCE ----------
      import java.awt.Dimension;
      import java.awt.Point;
      import java.lang.reflect.Method;

      import javafx.application.Platform;
      import javafx.embed.swing.JFXPanel;
      import javafx.event.Event;
      import javafx.event.EventDispatchChain;
      import javafx.event.EventDispatcher;
      import javafx.scene.Group;
      import javafx.scene.Scene;
      import javafx.scene.input.MouseButton;
      import javafx.scene.input.MouseEvent;
      import javafx.scene.web.WebEngine;
      import javafx.scene.web.WebView;

      import javax.swing.JFrame;
      import javax.swing.SwingUtilities;

      public class JavaFX {

          private final static int WIDTH = 500;
          private final static int HEIGHT = 500;
          

          /* Create a JFrame with a JButton and a JFXPanel containing the WebView. */
          private static void initAndShowGUI() {
              // This method is invoked on Swing thread
              JFrame frame = new JFrame(javafx());
              frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

              //frame.getContentPane().setLayout(null); // do the layout manually

              final JFXPanel fxPanel = new JFXPanel();
              
              frame.add(fxPanel);
              frame.setVisible(true);

              fxPanel.setLocation(new Point(100,100));
              //fxPanel.setSize(new Dimension(WIDTH,HEIGHT));

              frame.getContentPane().setPreferredSize(new Dimension(WIDTH,HEIGHT));
              frame.pack();
              //frame.setResizable(false);

              Platform.runLater(new Runnable() { // this will run initFX as JavaFX-Thread
                  @Override
                  public void run() {
                      initFX(fxPanel);
                  }
              });
          }

          /* Creates a WebView and loads a test page. */
          private static void initFX(final JFXPanel fxPanel) {
          
              Group group = new Group();
              Scene scene = new Scene(group);
              fxPanel.setScene(scene);
              WebView webView = new WebView();
              
              webView.setMinSize(WIDTH,HEIGHT);
              webView.setMaxSize(WIDTH,HEIGHT);
              
              group.getChildren().add(webView);
              WebEngine webEngine = webView.getEngine();
              
              //uncomment these two lines for a hacky workaround
              //webView.setEventDispatcher(new MyEventDispatcher(webView.getEventDispatcher()));
              

              String content =
      "<html><head><script>"
      +"function registerContextMenu(){"
      +" var myDiv=document.getElementById(\"myYellowDiv\");"
      +" myDiv.addEventListener(\"contextmenu\",function (mouseevent){"
      +" myDiv.innerHTML=\"RightClick Ctrl-Key:\"+mouseevent.ctrlKey+\" Meta-Key:\"+mouseevent.metaKey;"
      +" return true;"
      +" });}"
      +"</script></head>"
      +"<body onLoad=\"registerContextMenu();\">"
      +"<div onContextMenu=\"return false;\" id=\"myYellowDiv\" style=\"width:400px; height:200px; background-color:yellow\">right-click here...</div>"
      +"</body></html>";
              webEngine.loadContent(content);
             
              
          }



          public static String javafx()
          {
              String javafx;
              try
              {
                  Class<?> c = Class.forName("com.sun.javafx.runtime.VersionInfo");
                  Method m = c.getMethod("getRuntimeVersion", new Class[]{});
                  javafx = (String)m.invoke(c);
              }
              catch (Exception e)
              {
                  javafx = "";
              }
              return javafx;
          }

          public static void main(final String[] args) {

           System.out.println("javax.runtime.version="+javafx());
              SwingUtilities.invokeLater(new Runnable() {
                  @Override
                  public void run() {
                      initAndShowGUI();
                  }
              });
          }
          
          
          /**
           *
           * alternate event dispatcher to work around the problem
           *
           */
          public class MyEventDispatcher implements EventDispatcher {

           private EventDispatcher originalDispatcher;

           public MyEventDispatcher(EventDispatcher originalDispatcher) {
           this.originalDispatcher = originalDispatcher;
           }

           @Override
           public Event dispatchEvent(Event event, EventDispatchChain tail) {
          
           if (event instanceof MouseEvent) {
           MouseEvent mouseEvent = (MouseEvent) event;
          
           if (MouseButton.SECONDARY == mouseEvent.getButton() && mouseEvent.isMetaDown() ) {

           // if SECONDARY mouse button has MetaDown
           // the underlying Web Page will not get the CONTEXTMENU event
           // so removing the isMetaDown() by firing a corrected event
           MouseEvent new_event = new MouseEvent(
           mouseEvent.getEventType(),
           mouseEvent.getX(),
           mouseEvent.getY(),
           mouseEvent.getScreenX(),
           mouseEvent.getScreenY()+100,
           mouseEvent.getButton(),
           mouseEvent.getClickCount(),
           mouseEvent.isShiftDown(),
           mouseEvent.isControlDown(),
           mouseEvent.isAltDown(),
           false,
           mouseEvent.isPrimaryButtonDown(),
           mouseEvent.isMiddleButtonDown(),
           mouseEvent.isSecondaryButtonDown(),
           mouseEvent.isSynthesized(),
           mouseEvent.isPopupTrigger(),
           mouseEvent.isStillSincePress(),
           mouseEvent.getPickResult()
           );
          
           event.consume();
           Event.fireEvent(mouseEvent.getTarget(), new_event);
          
           }
           }
           return originalDispatcher.dispatchEvent(event, tail);
           }


           }
      }

      /*

      ------------contextmenu.html for standalone use------------------------

      <html>
      <head>
      <script>
      function registerContextMenu(){

      var myDiv=document.getElementById("myYellowDiv");
      console.log(myDiv);
      myDiv.addEventListener("contextmenu",function (mouseevent){
      myDiv.innerHTML="RightClick Ctrl-Key:"+mouseevent.ctrlKey+" Meta-Key:"+mouseevent.metaKey;
      return true;
      });
      }

      </script>
      </head>

      <body onLoad="registerContextMenu();">

      <div onContextMenu="return false;" id="myYellowDiv" style="width:400px; height:200px; background-color:yellow">right-click here...</div>

      </body>
      </html>


      */
      ---------- END SOURCE ----------

            Unassigned Unassigned
            webbuggrp Webbug Group
            Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

              Created:
              Updated: