Rewrote keyboard handling to support JavaFX, open/closed apple keyboard support needs to be reimplemented.

This commit is contained in:
Brendan Robert 2015-02-03 22:03:28 -06:00
parent e8b23c3f7a
commit 2a4015c8a5
6 changed files with 234 additions and 186 deletions

View File

@ -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);
});
}

View File

@ -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<KeyEvent> keyboardHandler = computer.getKeyboard().getListener();
rootPane.setFocusTraversable(true);
rootPane.setOnKeyPressed(keyboardHandler);
rootPane.setOnKeyReleased(keyboardHandler);
// rootPane.onKeyTypedProperty().setValue(keyboardHandler);
rootPane.requestFocus();
}
}

View File

@ -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();

View File

@ -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, Boolean> 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);
}

View File

@ -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<Integer, Set<KeyHandler>> keyHandlersByKey = new HashMap<>();
private static Map<KeyCode, Set<KeyHandler>> keyHandlersByKey = new HashMap<>();
private static Map<Object, Set<KeyHandler>> 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<KeyEvent> 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);

View File

@ -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;