package bluej.utility.javafx;

import bluej.utility.Debug;
import javafx.embed.swing.SwingNode;
import javafx.event.EventHandler;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import threadchecker.OnThread;
import threadchecker.Tag;

import java.awt.AWTEvent;
import java.awt.Component;
import java.awt.EventQueue;
import java.awt.Toolkit;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.security.AccessController;
import java.security.PrivilegedAction;


| In SwingNode, there is a SwingKeyEventHandler class which translates | FX keypresses into Swing keypresses. Unfortunately it has a bug, | wherein AltGr shortcuts on Windows (which are used frequently by | some non-English users) do not work correctly. This is bug:<p> | | Https://bugs.openjdk.java.net/browse/JDK-8088471 | | <p>And currently has no fix date. Thankfully, a commenter on the bug | pointed to a solution: overriding the handler to suppress modifiers | on a particular event. | | <p>So this class is a near-copy of SwingNode.SwingKeyEventHandler, | with that suggested fix. Since some of the fields and classes we are | using are private or package-private, we have to use reflection | to access them. Not nice, but I can't see any other way to do it. | @OnThread(Tag.FXPlatform) public class SwingKeyEventHandlerFixed implements EventHandler<KeyEvent>{ private final SwingNode swingNode; private Field lwFrameField; @OnThread(Tag.Any) public SwingKeyEventHandlerFixed(SwingNode swingNode) { this.swingNode = swingNode; try { lwFrameField = SwingNode.class.getDeclaredField("lwFrame"); lwFrameField.setAccessible(true); } catch (NoSuchFieldException e) { e.printStackTrace(); } } @Override public void handle(javafx.scene.input.KeyEvent event) { try { handleSub(event); } catch (Exception e) { Debug.reportError(e); } } public void handleSub(javafx.scene.input.KeyEvent event) throws IllegalAccessException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException { Component frame = (Component) lwFrameField.get(swingNode); if (frame == null) { return; } if (event.getCharacter().isEmpty()) { return; } if (event.getCode() == KeyCode.LEFT || event.getCode() == KeyCode.RIGHT || event.getCode() == KeyCode.UP || event.getCode() == KeyCode.DOWN || event.getCode() == KeyCode.TAB) { event.consume(); } Method fxKeyEventTypeToKeyID = Class.forName("javafx.embed.swing.SwingEvents").getDeclaredMethod("fxKeyEventTypeToKeyID", javafx.scene.input.KeyEvent.class); fxKeyEventTypeToKeyID.setAccessible(true); int swingID = (Integer)fxKeyEventTypeToKeyID.invoke(null, event); if (swingID < 0) { return; } Method fxKeyModsToKeyMods = Class.forName("javafx.embed.swing.SwingEvents").getDeclaredMethod("fxKeyModsToKeyMods", javafx.scene.input.KeyEvent.class); fxKeyModsToKeyMods.setAccessible(true); int swingModifiers = (Integer)fxKeyModsToKeyMods.invoke(null, event); int swingKeyCode = event.getCode().getCode(); char swingChar = event.getCharacter().charAt(0); if (event.getEventType() == javafx.scene.input.KeyEvent.KEY_PRESSED) { String text = event.getText(); if (text.length() == 1) { swingChar = text.charAt(0); } } if (event.getEventType() == KeyEvent.KEY_TYPED && event.isAltDown() && event.isControlDown()) { swingModifiers = 0; } long swingWhen = System.currentTimeMillis(); java.awt.event.KeyEvent keyEvent = new java.awt.event.KeyEvent( frame, swingID, swingWhen, swingModifiers, swingKeyCode, swingChar); AccessController.doPrivileged(new PostEventAction(keyEvent)); } private static class PostEventAction implements PrivilegedAction<Void> { private AWTEvent event; public PostEventAction(AWTEvent event) { this.event = event; } @Override @OnThread(value = Tag.FXPlatform, ignoreParent = true) public Void run() { EventQueue eq = Toolkit.getDefaultToolkit().getSystemEventQueue(); eq.postEvent(event); return null; } } }

.   SwingKeyEventHandlerFixed
.   handle
.   handleSub
.   PostEventAction
.   run




152 neLoCode + 12 LoComm