From 2a4015c8a55fb00a692be1d615242afbea086c1b Mon Sep 17 00:00:00 2001 From: Brendan Robert Date: Tue, 3 Feb 2015 22:03:28 -0600 Subject: [PATCH] Rewrote keyboard handling to support JavaFX, open/closed apple keyboard support needs to be reimplemented. --- src/main/java/jace/JaceApplication.java | 2 +- src/main/java/jace/JaceUIController.java | 14 +- src/main/java/jace/cheat/MetaCheats.java | 7 +- src/main/java/jace/core/KeyHandler.java | 62 ++++- src/main/java/jace/core/Keyboard.java | 323 +++++++++++----------- src/main/java/jace/hardware/Joystick.java | 12 +- 6 files changed, 234 insertions(+), 186 deletions(-) diff --git a/src/main/java/jace/JaceApplication.java b/src/main/java/jace/JaceApplication.java index 9503687..9785e6d 100644 --- a/src/main/java/jace/JaceApplication.java +++ b/src/main/java/jace/JaceApplication.java @@ -44,7 +44,7 @@ public class JaceApplication extends Application { while (Emulator.computer.getVideo() == null || Emulator.computer.getVideo().getFrameBuffer() == null) { Thread.yield(); } - controller.connectScreen(Emulator.computer.getVideo()); + controller.connectComputer(Emulator.computer); }); } diff --git a/src/main/java/jace/JaceUIController.java b/src/main/java/jace/JaceUIController.java index 04bbc83..603899f 100644 --- a/src/main/java/jace/JaceUIController.java +++ b/src/main/java/jace/JaceUIController.java @@ -6,12 +6,14 @@ package jace; +import jace.core.Computer; import jace.core.Video; import java.net.URL; -import javafx.scene.canvas.Canvas; import java.util.ResourceBundle; +import javafx.event.EventHandler; import javafx.fxml.FXML; import javafx.scene.image.ImageView; +import javafx.scene.input.KeyEvent; import javafx.scene.layout.AnchorPane; import javafx.scene.layout.Region; @@ -41,7 +43,13 @@ public class JaceUIController { appleScreen.fitHeightProperty().bind(rootPane.heightProperty()); } - public void connectScreen(Video video) { - appleScreen.setImage(video.getFrameBuffer()); + public void connectComputer(Computer computer) { + appleScreen.setImage(computer.getVideo().getFrameBuffer()); + EventHandler keyboardHandler = computer.getKeyboard().getListener(); + rootPane.setFocusTraversable(true); + rootPane.setOnKeyPressed(keyboardHandler); + rootPane.setOnKeyReleased(keyboardHandler); +// rootPane.onKeyTypedProperty().setValue(keyboardHandler); + rootPane.requestFocus(); } } diff --git a/src/main/java/jace/cheat/MetaCheats.java b/src/main/java/jace/cheat/MetaCheats.java index 7221cf7..f64ef88 100644 --- a/src/main/java/jace/cheat/MetaCheats.java +++ b/src/main/java/jace/cheat/MetaCheats.java @@ -24,7 +24,6 @@ import jace.core.KeyHandler; import jace.core.Keyboard; import jace.core.RAMEvent; import jace.core.RAMListener; -import java.awt.event.KeyEvent; import java.util.ArrayList; import java.util.HashSet; import java.util.List; @@ -33,6 +32,8 @@ import java.util.Set; import java.util.TreeMap; import java.util.logging.Level; import java.util.logging.Logger; +import javafx.scene.input.KeyCode; +import javafx.scene.input.KeyEvent; import javax.swing.table.DefaultTableModel; /** @@ -200,7 +201,7 @@ public class MetaCheats extends Cheats { } }); - Keyboard.registerKeyHandler(new KeyHandler(KeyEvent.VK_END) { + Keyboard.registerKeyHandler(new KeyHandler(KeyCode.END) { @Override public boolean handleKeyUp(KeyEvent e) { showCheatForm(); @@ -212,7 +213,7 @@ public class MetaCheats extends Cheats { return false; } }, this); - Keyboard.registerKeyHandler(new KeyHandler(KeyEvent.VK_HOME) { + Keyboard.registerKeyHandler(new KeyHandler(KeyCode.HOME) { @Override public boolean handleKeyUp(KeyEvent e) { showMemorySpy(); diff --git a/src/main/java/jace/core/KeyHandler.java b/src/main/java/jace/core/KeyHandler.java index 7b8c6a1..5bc28df 100644 --- a/src/main/java/jace/core/KeyHandler.java +++ b/src/main/java/jace/core/KeyHandler.java @@ -18,28 +18,60 @@ */ package jace.core; -import java.awt.event.KeyEvent; +import java.util.EnumMap; +import javafx.scene.input.KeyCode; +import javafx.scene.input.KeyEvent; /** - * Listen for a specific key or set of keys - * If there is a match, the handleKeyUp or handleKeyDown methods will be called. - * This is meant to save a lot of extra conditional logic elsewhere. - * - * The handler methods should return true if they have consumed the key event and do - * not want any other processing to continue for that keypress. - * @author Brendan Robert (BLuRry) brendan.robert@gmail.com + * Listen for a specific key or set of keys If there is a match, the handleKeyUp + * or handleKeyDown methods will be called. This is meant to save a lot of extra + * conditional logic elsewhere. + * + * The handler methods should return true if they have consumed the key event + * and do not want any other processing to continue for that keypress. + * + * @author Brendan Robert (BLuRry) brendan.robert@gmail.com */ public abstract class KeyHandler { - public int key = 0; - public int modifiers = 0; - public KeyHandler(int key, int... modifiers) { + + public static enum Modifiers { + + alt, control, shift, meta, shortcut,ignore + }; + public KeyCode key; + public EnumMap modifiers; + + public KeyHandler(KeyCode key, Modifiers... flags) { this.key = key; - this.modifiers = 0; - for (int m : modifiers) { - this.modifiers |= m; + this.modifiers = new EnumMap<>(Modifiers.class); + for (Modifiers flag : flags) { + modifiers.put(flag, true); } } - + + public boolean matchesModifiers(KeyEvent e) { + if (modifiers.get(Modifiers.ignore)) { + return true; + } + if (e.isAltDown() != modifiers.get(Modifiers.alt)) { + return false; + } + if (e.isControlDown() != modifiers.get(Modifiers.control)) { + return false; + } + if (e.isMetaDown() != modifiers.get(Modifiers.meta)) { + return false; + } + if (e.isShiftDown() != modifiers.get(Modifiers.shift)) { + return false; + } + if (e.isShortcutDown() != modifiers.get(Modifiers.shortcut)) { + return false; + } + return true; + } + public abstract boolean handleKeyUp(KeyEvent e); + public abstract boolean handleKeyDown(KeyEvent e); } diff --git a/src/main/java/jace/core/Keyboard.java b/src/main/java/jace/core/Keyboard.java index 620103e..9a202dd 100644 --- a/src/main/java/jace/core/Keyboard.java +++ b/src/main/java/jace/core/Keyboard.java @@ -27,8 +27,6 @@ import java.awt.Toolkit; import java.awt.datatransfer.Clipboard; import java.awt.datatransfer.DataFlavor; import java.awt.datatransfer.UnsupportedFlavorException; -import java.awt.event.KeyEvent; -import java.awt.event.KeyListener; import java.io.IOException; import java.io.StringReader; import java.util.HashMap; @@ -37,6 +35,9 @@ import java.util.Map; import java.util.Set; import java.util.logging.Level; import java.util.logging.Logger; +import javafx.event.EventHandler; +import javafx.scene.input.KeyCode; +import javafx.scene.input.KeyEvent; /** * Keyboard manages all keyboard-related activities. For now, all hotkeys are @@ -47,10 +48,13 @@ import java.util.logging.Logger; * @author Brendan Robert (BLuRry) brendan.robert@gmail.com */ public class Keyboard implements Reconfigurable { + private Computer computer; + public Keyboard(Computer computer) { this.computer = computer; } + @Override public String getShortName() { return "kbd"; @@ -82,7 +86,7 @@ public class Keyboard implements Reconfigurable { */ public Keyboard() { } - private static Map> keyHandlersByKey = new HashMap<>(); + private static Map> keyHandlersByKey = new HashMap<>(); private static Map> keyHandlersByOwner = new HashMap<>(); public static void registerKeyHandler(KeyHandler l, Object owner) { @@ -106,9 +110,9 @@ public class Keyboard implements Reconfigurable { } public static void processKeyDownEvents(KeyEvent e) { - if (keyHandlersByKey.containsKey(e.getKeyCode())) { - for (KeyHandler h : keyHandlersByKey.get(e.getKeyCode())) { - if (h.modifiers != e.getModifiers() && h.modifiers != -1) { + if (keyHandlersByKey.containsKey(e.getCode())) { + for (KeyHandler h : keyHandlersByKey.get(e.getCode())) { + if (!h.matchesModifiers(e)) { continue; } boolean isHandled = h.handleKeyDown(e); @@ -121,9 +125,9 @@ public class Keyboard implements Reconfigurable { } public static void processKeyUpEvents(KeyEvent e) { - if (keyHandlersByKey.containsKey(e.getKeyCode())) { - for (KeyHandler h : keyHandlersByKey.get(e.getKeyCode())) { - if (h.modifiers != e.getModifiers() && h.modifiers != -1) { + if (keyHandlersByKey.containsKey(e.getCode())) { + for (KeyHandler h : keyHandlersByKey.get(e.getCode())) { + if (!h.matchesModifiers(e)) { continue; } boolean isHandled = h.handleKeyUp(e); @@ -135,157 +139,159 @@ public class Keyboard implements Reconfigurable { } } - public KeyListener getListener() { - return new KeyListener() { - @Override - public void keyTyped(KeyEvent e) { - } - - @Override - public void keyPressed(KeyEvent e) { - processKeyDownEvents(e); - if (e.getKeyCode() == 0 || e.isConsumed()) { - return; - } - - KeyboardSoftSwitch key = - (KeyboardSoftSwitch) SoftSwitches.KEYBOARD.getSwitch(); - char c = e.getKeyChar(); - if ((e.getModifiers() & (KeyEvent.ALT_MASK|KeyEvent.META_MASK|KeyEvent.META_DOWN_MASK)) > 0) { - // explicit left and right here because other locations - // can be sent as well, e.g. KEY_LOCATION_STANDARD - if (e.getKeyLocation() == KeyEvent.KEY_LOCATION_LEFT) { - pressOpenApple(); - } else if (e.getKeyLocation() == KeyEvent.KEY_LOCATION_RIGHT) { - pressSolidApple(); - } - } - - int code = e.getKeyCode(); - - switch (code) { - case KeyEvent.VK_LEFT: - case KeyEvent.VK_KP_LEFT: - c = 8; - break; - case KeyEvent.VK_RIGHT: - case KeyEvent.VK_KP_RIGHT: - c = 21; - break; - case KeyEvent.VK_UP: - case KeyEvent.VK_KP_UP: - c = 11; - break; - case KeyEvent.VK_DOWN: - case KeyEvent.VK_KP_DOWN: - c = 10; - break; - case KeyEvent.VK_TAB: - c = 9; - break; - case KeyEvent.VK_ENTER: - c = 13; - break; - case KeyEvent.VK_BACK_SPACE: - c = 127; - break; - default: - if ((e.getModifiers() & KeyEvent.CTRL_DOWN_MASK) > 0) { - c = (char) (code - 'A' + 1); - } - } - - if (c < 128) { - pressKey((byte) c); - } - -// e.consume(); - } - - @Override - public void keyReleased(KeyEvent e) { - int code = e.getKeyCode(); - processKeyUpEvents(e); - if (code == 0 || e.isConsumed()) { - return; - } - if (code == KeyEvent.VK_INSERT && e.isShiftDown()) { - doPaste(); - } - if (code == KeyEvent.VK_F10) { - EmulatorUILogic.toggleDebugPanel(); - } - if ((code == KeyEvent.VK_F12 || code == KeyEvent.VK_PAGE_UP || code == KeyEvent.VK_BACK_SPACE || code == KeyEvent.VK_PAUSE) && ((e.getModifiers() & KeyEvent.CTRL_MASK) > 0)) { - computer.warmStart(); - } - if (code == KeyEvent.VK_F1) { - EmulatorUILogic.showMediaManager(); - } - if (code == KeyEvent.VK_F4) { - EmulatorUILogic.showConfig(); - } - if (code == KeyEvent.VK_F7) { - Speaker.toggleFileOutput(); - } - if (code == KeyEvent.VK_F8) { - EmulatorUILogic.scaleIntegerRatio(); - } - if (code == KeyEvent.VK_F9) { - EmulatorUILogic.toggleFullscreen(); - } - if (code == KeyEvent.VK_PRINTSCREEN || code == KeyEvent.VK_SCROLL_LOCK) { - try { - if (e.isShiftDown()) { - EmulatorUILogic.saveScreenshotRaw(); - } else { - EmulatorUILogic.saveScreenshot(); - } - } catch (IOException ex) { - Logger.getLogger(Keyboard.class.getName()).log(Level.SEVERE, null, ex); - } - computer.resume(); - } - if ((e.getModifiers() & (KeyEvent.ALT_MASK|KeyEvent.META_MASK|KeyEvent.META_DOWN_MASK)) > 0) { - // explicit left and right here because other locations - // can be sent as well, e.g. KEY_LOCATION_STANDARD - if (e.getKeyLocation() == KeyEvent.KEY_LOCATION_LEFT) { - releaseOpenApple(); - } else if (e.getKeyLocation() == KeyEvent.KEY_LOCATION_RIGHT) { - releaseSolidApple(); - } - } - - e.consume(); -// e.setKeyChar((char) 0); -// e.setKeyCode(0); - } - - private void pressOpenApple() { - computer.pause(); - SoftSwitches.PB0.getSwitch().setState(true); - computer.resume(); - } - - private void pressSolidApple() { - computer.pause(); - SoftSwitches.PB1.getSwitch().setState(true); - computer.resume(); - } - - private void releaseOpenApple() { - computer.pause(); - SoftSwitches.PB0.getSwitch().setState(false); - computer.resume(); - } - - private void releaseSolidApple() { - computer.pause(); - SoftSwitches.PB1.getSwitch().setState(false); - computer.resume(); + public EventHandler getListener() { + return (KeyEvent event) -> { + if (event.getEventType() == KeyEvent.KEY_PRESSED) { + keyPressed(event); + } else if (event.getEventType() == KeyEvent.KEY_RELEASED) { + keyReleased(event); } }; } + public void keyPressed(KeyEvent e) { + processKeyDownEvents(e); + if (e.isConsumed()) { + return; + } + + char c=255; + if (e.getText().length() > 0) { + c = e.getText().charAt(0); + } + + switch (e.getCode()) { + case LEFT: + case KP_LEFT: + c = 8; + break; + case RIGHT: + case KP_RIGHT: + c = 21; + break; + case UP: + case KP_UP: + c = 11; + break; + case DOWN: + case KP_DOWN: + c = 10; + break; + case TAB: + c = 9; + break; + case ENTER: + c = 13; + break; + case BACK_SPACE: + c = 127; + break; + default: + +// if (e.isControlDown()) { +// c = (char) (c - 'A' + 1); +// } + } + + if (c < 128) { + pressKey((byte) c); + } + +// e.consume(); + } + + public void keyReleased(KeyEvent e) { + KeyCode code = e.getCode(); + processKeyUpEvents(e); + if (code == null || e.isConsumed()) { + return; + } + switch (code) { + case INSERT: + if (e.isShiftDown()) { + doPaste(); + + } + break; + case F10: + EmulatorUILogic.toggleDebugPanel(); + break; + case F12: + case PAGE_UP: + case BACK_SPACE: + case PAUSE: + if (e.isControlDown()) { + computer.warmStart(); + } + break; + case F1: + EmulatorUILogic.showMediaManager(); + break; + case F4: + EmulatorUILogic.showConfig(); + break; + case F7: + Speaker.toggleFileOutput(); + break; + case F8: + EmulatorUILogic.scaleIntegerRatio(); + break; + case F9: + EmulatorUILogic.toggleFullscreen(); + break; + case PRINTSCREEN: + case SCROLL_LOCK: + try { + if (e.isShiftDown()) { + EmulatorUILogic.saveScreenshotRaw(); + } else { + EmulatorUILogic.saveScreenshot(); + } + } catch (IOException ex) { + Logger.getLogger(Keyboard.class.getName()).log(Level.SEVERE, null, ex); + } + computer.resume(); + break; + } +// if ((e.getModifiers() & (KeyEvent.ALT_MASK | KeyEvent.META_MASK | KeyEvent.META_DOWN_MASK)) > 0) { +// // explicit left and right here because other locations +// // can be sent as well, e.g. KEY_LOCATION_STANDARD +// if (e.getKeyLocation() == KeyEvent.KEY_LOCATION_LEFT) { +// releaseOpenApple(); +// } else if (e.getKeyLocation() == KeyEvent.KEY_LOCATION_RIGHT) { +// releaseSolidApple(); +// } +// } + + e.consume(); +// e.setKeyChar((char) 0); +// e.setKeyCode(0); + } + + private void pressOpenApple() { + computer.pause(); + SoftSwitches.PB0.getSwitch().setState(true); + computer.resume(); + } + + private void pressSolidApple() { + computer.pause(); + SoftSwitches.PB1.getSwitch().setState(true); + computer.resume(); + } + + private void releaseOpenApple() { + computer.pause(); + SoftSwitches.PB0.getSwitch().setState(false); + computer.resume(); + } + + private void releaseSolidApple() { + computer.pause(); + SoftSwitches.PB1.getSwitch().setState(false); + computer.resume(); + } + public static void doPaste(String text) { pasteBuffer = new StringReader(text); } @@ -320,11 +326,10 @@ public class Keyboard implements Reconfigurable { return -1; } - KeyboardSoftSwitch key = - (KeyboardSoftSwitch) SoftSwitches.KEYBOARD.getSwitch(); + KeyboardSoftSwitch key + = (KeyboardSoftSwitch) SoftSwitches.KEYBOARD.getSwitch(); return (keypress & 0x0ff); - } catch (IOException ex) { Logger.getLogger(Keyboard.class .getName()).log(Level.SEVERE, null, ex); diff --git a/src/main/java/jace/hardware/Joystick.java b/src/main/java/jace/hardware/Joystick.java index edb1175..5929f98 100644 --- a/src/main/java/jace/hardware/Joystick.java +++ b/src/main/java/jace/hardware/Joystick.java @@ -34,9 +34,10 @@ import java.awt.MouseInfo; import java.awt.Point; import java.awt.Robot; import java.awt.Toolkit; -import java.awt.event.KeyEvent; import java.util.logging.Level; import java.util.logging.Logger; +import javafx.scene.input.KeyCode; +import javafx.scene.input.KeyEvent; /** * Simple implementation of joystick support that supports mouse or keyboard. @@ -183,6 +184,7 @@ public class Joystick extends Device { removeListeners(); } + @Override public void reconfigure() { x = 0; y = 0; @@ -218,7 +220,7 @@ public class Joystick extends Device { computer.getMemory().addListener(listener); if (useKeyboard) { System.out.println("Registering key handlers"); - Keyboard.registerKeyHandler(new KeyHandler(KeyEvent.VK_LEFT, -1) { + Keyboard.registerKeyHandler(new KeyHandler(KeyCode.LEFT, KeyHandler.Modifiers.ignore) { @Override public boolean handleKeyUp(KeyEvent e) { leftPressed = false; @@ -231,7 +233,7 @@ public class Joystick extends Device { return hogKeyboard; } }, this); - Keyboard.registerKeyHandler(new KeyHandler(KeyEvent.VK_RIGHT, -1) { + Keyboard.registerKeyHandler(new KeyHandler(KeyCode.RIGHT, KeyHandler.Modifiers.ignore) { @Override public boolean handleKeyUp(KeyEvent e) { rightPressed = false; @@ -244,7 +246,7 @@ public class Joystick extends Device { return hogKeyboard; } }, this); - Keyboard.registerKeyHandler(new KeyHandler(KeyEvent.VK_UP, -1) { + Keyboard.registerKeyHandler(new KeyHandler(KeyCode.UP, KeyHandler.Modifiers.ignore) { @Override public boolean handleKeyUp(KeyEvent e) { upPressed = false; @@ -257,7 +259,7 @@ public class Joystick extends Device { return hogKeyboard; } }, this); - Keyboard.registerKeyHandler(new KeyHandler(KeyEvent.VK_DOWN, -1) { + Keyboard.registerKeyHandler(new KeyHandler(KeyCode.DOWN, KeyHandler.Modifiers.ignore) { @Override public boolean handleKeyUp(KeyEvent e) { downPressed = false;