Well as it seems it’s somewhat impossible to get the events into jfx.
Here is what i have so far, the problem is, the jfx/swing stuff only reacts to events if its focused (except mousemove events, those work fine already)
For the jfx stuff to be focused it needs to be attached to a window of some kind, wich itself must be focused, resulting in the loss of the focus for the jme application.
Maybee someone knows a solution?
package jme3test.jfx;
import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.concurrent.Semaphore;
import javafx.application.Platform;
import javafx.embed.swing.JFXPanel;
import javafx.embed.swing.SwingFXUtils;
import javafx.scene.Scene;
import javafx.scene.SnapshotParameters;
import javafx.scene.image.WritableImage;
import javafx.scene.paint.Color;
import com.jme3.export.JmeExporter;
import com.jme3.export.JmeImporter;
import com.jme3.input.event.KeyInputEvent;
import com.jme3.input.event.MouseButtonEvent;
import com.jme3.input.event.MouseMotionEvent;
import com.jme3.material.Material;
import com.jme3.renderer.RenderManager;
import com.jme3.renderer.ViewPort;
import com.jme3.scene.Geometry;
import com.jme3.scene.Mesh;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial;
import com.jme3.scene.control.Control;
import com.jme3.scene.shape.Quad;
import com.jme3.texture.Image.Format;
import com.jme3.texture.Texture;
import com.jme3.texture.Texture2D;
import com.jme3.texture.plugins.AWTLoader;
public class JFXQuad extends Node {
private JFXPanel fxPanel;
private Scene scene;
private boolean alive = true;
private Texture texture;
private Material mat;
// caches
private BufferedImage awtImage;
private WritableImage fxImage;
Semaphore mutalExclusiveImageAccess = new Semaphore(1);
private JFXInitCallback initJFX;
private Mesh displayMesh;
private Geometry displayGeometry;
public JFXQuad(final JFXInitCallback initJFX, final int quadWidth, final int quadHeight) {
this.displayMesh = new Quad(quadWidth, quadHeight);
this.displayGeometry = new Geometry("JFXQuad", this.displayMesh);
this.initJFX = initJFX;
this.initRenderTarget();
this.fxPanel = new JFXPanel(); // init jfx integration
Platform.runLater(new Runnable() {
@Override
public void run() {
JFXQuad.this.scene = initJFX.getScene();
JFXQuad.this.fxPanel.setScene(JFXQuad.this.scene);
}
});
final Thread updateThread = new Thread() {
@Override
public void run() {
while (JFXQuad.this.alive) {
JFXQuad.this.synchronizedImage();
try {
Thread.sleep(initJFX.getUpdateDelay());
} catch (final InterruptedException e) {
e.printStackTrace();
}
}
}
};
updateThread.start();
this.addControl(new Control() {
@Override
public void write(final JmeExporter ex) throws IOException {
throw new RuntimeException("Not supported");
}
@Override
public void read(final JmeImporter im) throws IOException {
throw new RuntimeException("Not supported");
}
@Override
public void update(final float tpf) {
if (JFXQuad.this.texture != null) {
JFXQuad.this.fxPanel.getFocusListeners();
JFXQuad.this.mat.setTexture("ColorMap", JFXQuad.this.texture);
}
}
@Override
public void setSpatial(final Spatial spatial) {
}
@Override
public void render(final RenderManager rm, final ViewPort vp) {
}
@Override
public Control cloneForSpatial(final Spatial spatial) {
return null;
}
});
}
private void initRenderTarget() {
this.texture = new Texture2D(2, 2, Format.ABGR8);
this.mat = new Material(this.initJFX.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");
this.mat.setTexture("ColorMap", this.texture);
this.displayGeometry.setMaterial(this.mat);
this.attachChild(this.displayGeometry);
}
public void dispose() {
this.alive = false;
this.removeFromParent();
this.fxPanel.removeAll();
}
void synchronizedImage() {
Platform.runLater(new Runnable() {
@Override
public void run() {
try {
JFXQuad.this.mutalExclusiveImageAccess.acquire();
final SnapshotParameters params = new SnapshotParameters();
params.setFill(Color.ALICEBLUE);
JFXQuad.this.fxImage = JFXQuad.this.scene.snapshot(JFXQuad.this.fxImage);
JFXQuad.this.mutalExclusiveImageAccess.release();
} catch (final InterruptedException e) {
e.printStackTrace();
}
}
});
try {
if (this.fxImage != null) {
this.mutalExclusiveImageAccess.acquire();
this.awtImage = SwingFXUtils.fromFXImage(this.fxImage, this.awtImage);
JFXQuad.this.texture = JFXQuad.awtImageToTexture(this.awtImage);
this.mutalExclusiveImageAccess.release();
}
} catch (final InterruptedException e) {
e.printStackTrace();
}
}
public static Texture awtImageToTexture(final BufferedImage img) {
final AWTLoader loader = new AWTLoader();
final Texture tex = new Texture2D();
tex.setImage(loader.load(img, true));
return tex;
}
public void fireKeyEvent(final KeyInputEvent evt) {
final KeyEvent virtualEvent = new KeyEvent(this.fxPanel, KeyEvent.KEY_PRESSED, System.currentTimeMillis(), 0, evt.getKeyCode(), evt.getKeyChar());
System.out.println(virtualEvent);
this.fxPanel.dispatchEvent(virtualEvent);
}
public void fireMouseEvent(final MouseMotionEvent evt) {
final MouseEvent virtualEvent = new java.awt.event.MouseEvent(this.fxPanel, MouseEvent.MOUSE_MOVED, System.currentTimeMillis(), 0, evt.getX(), this.initJFX.getScreenHeight() - evt.getY(), 1, false);
this.fxPanel.dispatchEvent(virtualEvent);
}
public void fireMouseClick(final MouseButtonEvent evt) {
final MouseEvent virtualEvent = new java.awt.event.MouseEvent(this.fxPanel, MouseEvent.MOUSE_CLICKED, System.currentTimeMillis(), 0, evt.getX(), this.initJFX.getScreenHeight() - evt.getY(), 1, false, evt.getButtonIndex());
System.out.println(virtualEvent);
this.fxPanel.dispatchEvent(virtualEvent);
}
}
package jme3test.jfx;
import javafx.event.Event;
import javafx.scene.Scene;
import javafx.scene.paint.Color;
import com.jme3.app.SimpleApplication;
import com.jme3.asset.AssetManager;
import com.jme3.input.RawInputListener;
import com.jme3.input.event.JoyAxisEvent;
import com.jme3.input.event.JoyButtonEvent;
import com.jme3.input.event.KeyInputEvent;
import com.jme3.input.event.MouseButtonEvent;
import com.jme3.input.event.MouseMotionEvent;
import com.jme3.input.event.TouchEvent;
import com.jme3.renderer.queue.RenderQueue.Bucket;
public class TestJFXInteration extends SimpleApplication {
private JFXInitCallback initJFX;
@Override
public void simpleInitApp() {
this.setPauseOnLostFocus(false);
this.flyCam.setEnabled(false);
this.initJFX = new JFXInitCallback() {
private JfxBrowser element;
@Override
public long getUpdateDelay() {
return 50;
}
@Override
public int getTargetWidth() {
return TestJFXInteration.this.settings.getWidth();
}
@Override
public int getTargetHeight() {
return TestJFXInteration.this.settings.getHeight();
}
@Override
public Scene getScene() {
this.element = new JfxBrowser("http://www.dict.cc/?s=key+input");
return new Scene(this.element, this.getTargetWidth(), this.getTargetHeight(), Color.web("#666970"));
}
@Override
public AssetManager getAssetManager() {
return TestJFXInteration.this.getAssetManager();
}
@Override
public void fireEvent(final Event evt) {
this.element.fireEvent(evt);
}
@Override
public int getScreenHeight() {
return TestJFXInteration.this.settings.getHeight();
}
};
final JFXQuad jfXQuad = new JFXQuad(this.initJFX, this.settings.getWidth(), this.settings.getHeight());
jfXQuad.setQueueBucket(Bucket.Gui);
this.rootNode.attachChild(jfXQuad);
this.inputManager.addRawInputListener(new RawInputListener() {
@Override
public void onTouchEvent(final TouchEvent evt) {
// TODO Auto-generated method stub
}
@Override
public void onMouseMotionEvent(final MouseMotionEvent evt) {
jfXQuad.fireMouseEvent(evt);
}
@Override
public void onMouseButtonEvent(final MouseButtonEvent evt) {
jfXQuad.fireMouseClick(evt);
}
@Override
public void onKeyEvent(final KeyInputEvent evt) {
jfXQuad.fireKeyEvent(evt);
}
@Override
public void onJoyButtonEvent(final JoyButtonEvent evt) {
// TODO Auto-generated method stub
}
@Override
public void onJoyAxisEvent(final JoyAxisEvent evt) {
// TODO Auto-generated method stub
}
@Override
public void endInput() {
// TODO Auto-generated method stub
}
@Override
public void beginInput() {
// TODO Auto-generated method stub
}
});
}
@Override
public void destroy() {
super.destroy();
}
public static void main(final String[] args) {
new TestJFXInteration().start();
}
}
package jme3test.jfx;
import javafx.event.Event;
import javafx.scene.Scene;
import com.jme3.asset.AssetManager;
public interface JFXInitCallback {
Scene getScene();
long getUpdateDelay();
int getTargetWidth();
int getTargetHeight();
AssetManager getAssetManager();
void fireEvent(Event evt);
int getScreenHeight();
}
package jme3test.jfx;
import javafx.geometry.HPos;
import javafx.geometry.VPos;
import javafx.scene.layout.Region;
import javafx.scene.web.WebEngine;
import javafx.scene.web.WebView;
class JfxBrowser extends Region {
final WebView browser = new WebView();
final WebEngine webEngine = this.browser.getEngine();
public JfxBrowser(final String website) {
// apply the styles
this.getStyleClass().add("browser");
// load the web page
this.webEngine.load(website);
// add the web view to the scene
this.getChildren().add(this.browser);
}
@Override
protected void layoutChildren() {
final double w = this.getWidth();
final double h = this.getHeight();
this.layoutInArea(this.browser, 0, 0, w, h, 0, HPos.CENTER, VPos.CENTER);
}
@Override
protected double computePrefWidth(final double height) {
return 750;
}
@Override
protected double computePrefHeight(final double width) {
return 500;
}
}