From 5758a3d04a75c1240c84444130f81febcb120253 Mon Sep 17 00:00:00 2001 From: AShiningRay Date: Fri, 3 Nov 2023 19:53:37 -0300 Subject: [PATCH] Introduce input remap support to FreeJ2ME's AWT frontend. Even though it doesn't support joypads of any kind yet, being able to remap keys is useful nonetheless. --- src/org/recompile/freej2me/AWTGUI.java | 187 ++++++++++++++++++++++- src/org/recompile/freej2me/FreeJ2ME.java | 114 +++++--------- 2 files changed, 225 insertions(+), 76 deletions(-) diff --git a/src/org/recompile/freej2me/AWTGUI.java b/src/org/recompile/freej2me/AWTGUI.java index 980102ea..3863a522 100644 --- a/src/org/recompile/freej2me/AWTGUI.java +++ b/src/org/recompile/freej2me/AWTGUI.java @@ -59,6 +59,7 @@ public final class AWTGUI final Dialog aboutDialog = new Dialog(main , "About FreeJ2ME", true); final Dialog memStatDialog = new Dialog(main, "FreeJ2ME MemStat", false); final Dialog restartRequiredDialog = new Dialog(main, "Restart Required", true); + final Dialog inputMapDialog = new Dialog(main, "Key Mapping", true); final Button closeAbout = new Button("Close"); final Button applyResChange = new Button("Apply"); @@ -66,6 +67,64 @@ public final class AWTGUI final Button closeNow = new Button("Close FreeJ2ME"); final Button restartLater = new Button("Restart later"); + /* Input mapping keys */ + final Button applyInputs = new Button("Apply Inputs"); + final Button inputButtons[] = new Button[] + { + new Button("Q"), + new Button("W"), + new Button("Up"), + new Button("Left"), + new Button("Enter"), + new Button("Right"), + new Button("Down"), + new Button("NumPad-7"), + new Button("NumPad-8"), + new Button("NumPad-9"), + new Button("NumPad-4"), + new Button("NumPad-5"), + new Button("NumPad-6"), + new Button("NumPad-1"), + new Button("NumPad=2"), + new Button("NumPad-3"), + new Button("E"), + new Button("NumPad-0"), + new Button("R"), + }; + + /* Constant fields for key mapping indices (matches the array above) */ + static final byte SOFT_LEFT_KEY = 0; + static final byte SOFT_RIGHT_KEY = 1; + static final byte UP_ARROW_KEY = 2; + static final byte LEFT_ARROW_KEY = 3; + static final byte OK_KEY = 4; + static final byte RIGHT_ARROW_KEY = 5; + static final byte DOWN_ARROW_KEY = 6; + static final byte NUMPAD1_KEY = 7; + static final byte NUMPAD2_KEY = 8; + static final byte NUMPAD3_KEY = 9; + static final byte NUMPAD4_KEY = 10; + static final byte NUMPAD5_KEY = 11; + static final byte NUMPAD6_KEY = 12; + static final byte NUMPAD7_KEY = 13; + static final byte NUMPAD8_KEY = 14; + static final byte NUMPAD9_KEY = 15; + static final byte NUMPAD_ASTERISK_KEY = 16; + static final byte NUMPAD0_KEY = 17; + static final byte NUMPAD_POUND_KEY = 18; + + /* Array of inputs in order to support input remapping */ + int inputKeycodes[] = new int[] { + KeyEvent.VK_Q, KeyEvent.VK_W, + KeyEvent.VK_UP, KeyEvent.VK_LEFT, KeyEvent.VK_ENTER, KeyEvent.VK_RIGHT, KeyEvent.VK_DOWN, + KeyEvent.VK_NUMPAD7, KeyEvent.VK_NUMPAD8, KeyEvent.VK_NUMPAD9, + KeyEvent.VK_NUMPAD4, KeyEvent.VK_NUMPAD5, KeyEvent.VK_NUMPAD6, + KeyEvent.VK_NUMPAD1, KeyEvent.VK_NUMPAD2, KeyEvent.VK_NUMPAD3, + KeyEvent.VK_E, KeyEvent.VK_NUMPAD0, KeyEvent.VK_R + }; + + private final int newInputKeycodes[] = Arrays.copyOf(inputKeycodes, inputKeycodes.length); + final Choice resChoice = new Choice(); final String[] supportedRes = new String[] {"96x65","96x96","104x80","128x128","132x176","128x160","176x208","176x220", "208x208", "240x320", "320x240", "240x400", "352x416", "360x640", "640x360" ,"480x800", "800x480"}; @@ -85,6 +144,7 @@ public final class AWTGUI final MenuItem closeMenuItem = new MenuItem("Close Jar (Stub)"); final MenuItem scrShot = new MenuItem("Take Screenshot"); final MenuItem exitMenuItem = new MenuItem("Exit FreeJ2ME"); + final MenuItem mapInputs = new MenuItem("Manage Inputs"); final CheckboxMenuItem enableAudio = new CheckboxMenuItem("Enable Audio", false); final CheckboxMenuItem enableRotation = new CheckboxMenuItem("Rotate Screen", false); @@ -129,6 +189,7 @@ public AWTGUI(Config config) cancelResChange.setBackground(Color.yellow); closeNow.setBackground(Color.green); restartLater.setBackground(Color.yellow); + applyInputs.setBackground(Color.green); aboutDialog.setBackground(Color.white); aboutDialog.setLayout( new FlowLayout(FlowLayout.CENTER, 200, 0)); @@ -143,6 +204,7 @@ public AWTGUI(Config config) aboutDialog.add(new Label("Saket Dandawate (hex007)")); aboutDialog.add(closeAbout); + resDialog.setBackground(Color.white); resDialog.setLayout( new FlowLayout(FlowLayout.CENTER, 60, 5)); resDialog.setUndecorated(true); @@ -165,6 +227,61 @@ public AWTGUI(Config config) memStatDialog.add(usedMemLabel); memStatDialog.add(maxMemLabel); + /* Input mapping dialog: It's a grid, so a few tricks had to be employed to align everything up */ + inputMapDialog.setBackground(Color.white); + inputMapDialog.setLayout(new GridLayout(0, 3)); /* Get as many rows as needed, as long it still uses only 3 columns */ + inputMapDialog.setSize(240, 320); + inputMapDialog.setResizable(false); + + inputMapDialog.add(new Label("Map keys by")); + inputMapDialog.add(new Label("clicking each")); + inputMapDialog.add(new Label("button below")); + + inputMapDialog.add(new Label("")); + inputMapDialog.add(applyInputs); + inputMapDialog.add(new Label("")); + + inputMapDialog.add(new Label("-----------------------")); + inputMapDialog.add(new Label("-----------------------")); + inputMapDialog.add(new Label("-----------------------")); + + inputMapDialog.add(inputButtons[0]); + inputMapDialog.add(new Label("")); + inputMapDialog.add(inputButtons[1]); + + inputMapDialog.add(new Label("")); + inputMapDialog.add(inputButtons[2]); + inputMapDialog.add(new Label("")); + + inputMapDialog.add(inputButtons[3]); + inputMapDialog.add(inputButtons[4]); + inputMapDialog.add(inputButtons[5]); + + inputMapDialog.add(new Label("")); + inputMapDialog.add(inputButtons[6]); + inputMapDialog.add(new Label("")); + + inputMapDialog.add(new Label("")); + inputMapDialog.add(new Label("")); + inputMapDialog.add(new Label("")); + + inputMapDialog.add(inputButtons[7]); + inputMapDialog.add(inputButtons[8]); + inputMapDialog.add(inputButtons[9]); + + inputMapDialog.add(inputButtons[10]); + inputMapDialog.add(inputButtons[11]); + inputMapDialog.add(inputButtons[12]); + + inputMapDialog.add(inputButtons[13]); + inputMapDialog.add(inputButtons[14]); + inputMapDialog.add(inputButtons[15]); + + inputMapDialog.add(inputButtons[16]); + inputMapDialog.add(inputButtons[17]); + inputMapDialog.add(inputButtons[18]); + + restartRequiredDialog.setBackground(Color.white); restartRequiredDialog.setLayout( new FlowLayout(FlowLayout.CENTER, 10, 10)); restartRequiredDialog.setUndecorated(true); @@ -185,7 +302,9 @@ public AWTGUI(Config config) closeAbout.setActionCommand("CloseAboutMenu"); closeNow.setActionCommand("CloseFreeJ2ME"); restartLater.setActionCommand("RestartLater"); - + mapInputs.setActionCommand("MapInputs"); + applyInputs.setActionCommand("ApplyInputs"); + openMenuItem.addActionListener(menuItemListener); closeMenuItem.addActionListener(menuItemListener); scrShot.addActionListener(menuItemListener); @@ -197,12 +316,58 @@ public AWTGUI(Config config) closeAbout.addActionListener(menuItemListener); closeNow.addActionListener(menuItemListener); restartLater.addActionListener(menuItemListener); + mapInputs.addActionListener(menuItemListener); + applyInputs.addActionListener(menuItemListener); + + addInputButtonListeners(); setActionListeners(); buildMenuBar(); } + private void addInputButtonListeners() + { + for(int i = 0; i < inputButtons.length; i++) + { + final int buttonIndex = i; + + /* Add a focus listener to each input mapping button */ + inputButtons[i].addFocusListener(new FocusAdapter() + { + Button focusedButton; + String lastButtonKey = new String(""); + boolean keySet = false; + + @Override + public void focusGained(FocusEvent e) + { + { + keySet = false; + focusedButton = (Button) e.getComponent(); + lastButtonKey = focusedButton.getLabel(); + focusedButton.setLabel("Waiting..."); + + focusedButton.addKeyListener(new KeyAdapter() + { + public void keyPressed(KeyEvent e) + { + focusedButton.setLabel(KeyEvent.getKeyText(e.getKeyCode())); + keySet = true; + /* Save the new key's code into the expected index of newInputKeycodes */ + newInputKeycodes[buttonIndex] = e.getKeyCode(); + } + }); + } + } + + /* Only used to restore the last key map if the user doesn't map a new one into the button */ + @Override + public void focusLost(FocusEvent e) { if(!keySet) { focusedButton.setLabel(lastButtonKey); } } + }); + } + } + private void setActionListeners() { enableAudio.addItemListener(new ItemListener() @@ -643,6 +808,7 @@ private void buildMenuBar() optionMenu.add(phoneType); optionMenu.add(fpsCap); optionMenu.add(midiPlayerNum); + optionMenu.add(mapInputs); debugMenu.add(dumpAudioData); debugMenu.add(dumpGraphicsData); @@ -704,10 +870,13 @@ public void updateMemStatDialog() maxMemLabel.setText(new String("Max Mem : " + (Runtime.getRuntime().maxMemory() / 1024) + " KB")); } - class UIListener implements ActionListener { - public void actionPerformed(ActionEvent a) { + class UIListener implements ActionListener + { + public void actionPerformed(ActionEvent a) + { - if(a.getActionCommand() == "Open") { + if(a.getActionCommand() == "Open") + { FileDialog filePicker = new FileDialog(main, "Open JAR File", FileDialog.LOAD); String filename; filePicker.setFilenameFilter(new FilenameFilter() @@ -765,6 +934,16 @@ else if(a.getActionCommand() == "ApplyResChange") else if(a.getActionCommand() == "CloseFreeJ2ME") { System.exit(0); } else if(a.getActionCommand() == "RestartLater") { restartRequiredDialog.setVisible(false); } + + else if(a.getActionCommand() == "MapInputs") { inputMapDialog.setLocation(main.getLocation().x, main.getLocation().y); inputMapDialog.setVisible(true); } + + /* TODO: Flesh out input mappings apply and file saving (preferably per-game, though a global config could also work great) */ + else if(a.getActionCommand() == "ApplyInputs") + { + System.arraycopy(newInputKeycodes, 0, inputKeycodes, 0, inputKeycodes.length); + inputMapDialog.setVisible(false); + } + } } diff --git a/src/org/recompile/freej2me/FreeJ2ME.java b/src/org/recompile/freej2me/FreeJ2ME.java index 241fbeb3..a8bd0022 100644 --- a/src/org/recompile/freej2me/FreeJ2ME.java +++ b/src/org/recompile/freej2me/FreeJ2ME.java @@ -484,88 +484,58 @@ private int getMobileKey(int keycode) { if(useNokiaControls) { - switch(keycode) - { - case KeyEvent.VK_UP: return Mobile.NOKIA_UP; - case KeyEvent.VK_DOWN: return Mobile.NOKIA_DOWN; - case KeyEvent.VK_LEFT: return Mobile.NOKIA_LEFT; - case KeyEvent.VK_RIGHT: return Mobile.NOKIA_RIGHT; - case KeyEvent.VK_ENTER: return Mobile.NOKIA_SOFT3; - } + if(keycode == awtGUI.inputKeycodes[AWTGUI.UP_ARROW_KEY]) { return Mobile.NOKIA_UP; } + else if(keycode == awtGUI.inputKeycodes[AWTGUI.DOWN_ARROW_KEY]) { return Mobile.NOKIA_DOWN; } + else if(keycode == awtGUI.inputKeycodes[AWTGUI.LEFT_ARROW_KEY]) { return Mobile.NOKIA_LEFT; } + else if(keycode == awtGUI.inputKeycodes[AWTGUI.RIGHT_ARROW_KEY]) { return Mobile.NOKIA_RIGHT; } + else if(keycode == awtGUI.inputKeycodes[AWTGUI.OK_KEY]) { return Mobile.NOKIA_SOFT3; } } if(useSiemensControls) { - switch(keycode) - { - case KeyEvent.VK_UP: return Mobile.SIEMENS_UP; - case KeyEvent.VK_DOWN: return Mobile.SIEMENS_DOWN; - case KeyEvent.VK_LEFT: return Mobile.SIEMENS_LEFT; - case KeyEvent.VK_RIGHT: return Mobile.SIEMENS_RIGHT; - case KeyEvent.VK_Q: return Mobile.SIEMENS_SOFT1; - case KeyEvent.VK_W: return Mobile.SIEMENS_SOFT2; - case KeyEvent.VK_ENTER: return Mobile.SIEMENS_FIRE; - } + if(keycode == awtGUI.inputKeycodes[AWTGUI.UP_ARROW_KEY]) { return Mobile.SIEMENS_UP; } + else if(keycode == awtGUI.inputKeycodes[AWTGUI.DOWN_ARROW_KEY]) { return Mobile.SIEMENS_DOWN; } + else if(keycode == awtGUI.inputKeycodes[AWTGUI.LEFT_ARROW_KEY]) { return Mobile.SIEMENS_LEFT; } + else if(keycode == awtGUI.inputKeycodes[AWTGUI.RIGHT_ARROW_KEY]) { return Mobile.SIEMENS_RIGHT; } + else if(keycode == awtGUI.inputKeycodes[AWTGUI.SOFT_LEFT_KEY]) { return Mobile.SIEMENS_SOFT1; } + else if(keycode == awtGUI.inputKeycodes[AWTGUI.SOFT_LEFT_KEY]) { return Mobile.SIEMENS_SOFT2; } + else if(keycode == awtGUI.inputKeycodes[AWTGUI.OK_KEY]) { return Mobile.SIEMENS_FIRE; } } if(useMotorolaControls) { - switch(keycode) - { - case KeyEvent.VK_UP: return Mobile.MOTOROLA_UP; - case KeyEvent.VK_DOWN: return Mobile.MOTOROLA_DOWN; - case KeyEvent.VK_LEFT: return Mobile.MOTOROLA_LEFT; - case KeyEvent.VK_RIGHT: return Mobile.MOTOROLA_RIGHT; - case KeyEvent.VK_Q: return Mobile.MOTOROLA_SOFT1; - case KeyEvent.VK_W: return Mobile.MOTOROLA_SOFT2; - case KeyEvent.VK_ENTER: return Mobile.MOTOROLA_FIRE; - } + if(keycode == awtGUI.inputKeycodes[AWTGUI.UP_ARROW_KEY]) { return Mobile.MOTOROLA_UP; } + else if(keycode == awtGUI.inputKeycodes[AWTGUI.DOWN_ARROW_KEY]) { return Mobile.MOTOROLA_DOWN; } + else if(keycode == awtGUI.inputKeycodes[AWTGUI.LEFT_ARROW_KEY]) { return Mobile.MOTOROLA_LEFT; } + else if(keycode == awtGUI.inputKeycodes[AWTGUI.RIGHT_ARROW_KEY]) { return Mobile.MOTOROLA_RIGHT; } + else if(keycode == awtGUI.inputKeycodes[AWTGUI.SOFT_LEFT_KEY]) { return Mobile.MOTOROLA_SOFT1; } + else if(keycode == awtGUI.inputKeycodes[AWTGUI.SOFT_LEFT_KEY]) { return Mobile.MOTOROLA_SOFT2; } + else if(keycode == awtGUI.inputKeycodes[AWTGUI.OK_KEY]) { return Mobile.MOTOROLA_FIRE; } } - switch(keycode) - { - case KeyEvent.VK_0: return Mobile.KEY_NUM0; - case KeyEvent.VK_1: return Mobile.KEY_NUM1; - case KeyEvent.VK_2: return Mobile.KEY_NUM2; - case KeyEvent.VK_3: return Mobile.KEY_NUM3; - case KeyEvent.VK_4: return Mobile.KEY_NUM4; - case KeyEvent.VK_5: return Mobile.KEY_NUM5; - case KeyEvent.VK_6: return Mobile.KEY_NUM6; - case KeyEvent.VK_7: return Mobile.KEY_NUM7; - case KeyEvent.VK_8: return Mobile.KEY_NUM8; - case KeyEvent.VK_9: return Mobile.KEY_NUM9; - case KeyEvent.VK_ASTERISK: return Mobile.KEY_STAR; - case KeyEvent.VK_NUMBER_SIGN: return Mobile.KEY_POUND; - - case KeyEvent.VK_NUMPAD0: return Mobile.KEY_NUM0; - case KeyEvent.VK_NUMPAD7: return Mobile.KEY_NUM1; - case KeyEvent.VK_NUMPAD8: return Mobile.KEY_NUM2; - case KeyEvent.VK_NUMPAD9: return Mobile.KEY_NUM3; - case KeyEvent.VK_NUMPAD4: return Mobile.KEY_NUM4; - case KeyEvent.VK_NUMPAD5: return Mobile.KEY_NUM5; - case KeyEvent.VK_NUMPAD6: return Mobile.KEY_NUM6; - case KeyEvent.VK_NUMPAD1: return Mobile.KEY_NUM7; - case KeyEvent.VK_NUMPAD2: return Mobile.KEY_NUM8; - case KeyEvent.VK_NUMPAD3: return Mobile.KEY_NUM9; - - case KeyEvent.VK_UP: return Mobile.KEY_NUM2; - case KeyEvent.VK_DOWN: return Mobile.KEY_NUM8; - case KeyEvent.VK_LEFT: return Mobile.KEY_NUM4; - case KeyEvent.VK_RIGHT: return Mobile.KEY_NUM6; - - case KeyEvent.VK_ENTER: return Mobile.KEY_NUM5; - - case KeyEvent.VK_Q: return Mobile.NOKIA_SOFT1; - case KeyEvent.VK_W: return Mobile.NOKIA_SOFT2; - case KeyEvent.VK_E: return Mobile.KEY_STAR; - case KeyEvent.VK_R: return Mobile.KEY_POUND; - - case KeyEvent.VK_A: return -1; - case KeyEvent.VK_Z: return -2; - - // Config // - case KeyEvent.VK_ESCAPE: config.start(); - } + if(keycode == awtGUI.inputKeycodes[AWTGUI.NUMPAD0_KEY]) return Mobile.KEY_NUM0; + else if(keycode == awtGUI.inputKeycodes[AWTGUI.NUMPAD1_KEY]) return Mobile.KEY_NUM1; + else if(keycode == awtGUI.inputKeycodes[AWTGUI.NUMPAD2_KEY]) return Mobile.KEY_NUM2; + else if(keycode == awtGUI.inputKeycodes[AWTGUI.NUMPAD3_KEY]) return Mobile.KEY_NUM3; + else if(keycode == awtGUI.inputKeycodes[AWTGUI.NUMPAD4_KEY]) return Mobile.KEY_NUM4; + else if(keycode == awtGUI.inputKeycodes[AWTGUI.NUMPAD5_KEY]) return Mobile.KEY_NUM5; + else if(keycode == awtGUI.inputKeycodes[AWTGUI.NUMPAD6_KEY]) return Mobile.KEY_NUM6; + else if(keycode == awtGUI.inputKeycodes[AWTGUI.NUMPAD7_KEY]) return Mobile.KEY_NUM7; + else if(keycode == awtGUI.inputKeycodes[AWTGUI.NUMPAD8_KEY]) return Mobile.KEY_NUM8; + else if(keycode == awtGUI.inputKeycodes[AWTGUI.NUMPAD9_KEY]) return Mobile.KEY_NUM9; + else if(keycode == awtGUI.inputKeycodes[AWTGUI.NUMPAD_ASTERISK_KEY]) return Mobile.KEY_STAR; + else if(keycode == awtGUI.inputKeycodes[AWTGUI.NUMPAD_POUND_KEY]) return Mobile.KEY_POUND; + + else if(keycode == awtGUI.inputKeycodes[AWTGUI.UP_ARROW_KEY]) return Mobile.KEY_NUM2; + else if(keycode == awtGUI.inputKeycodes[AWTGUI.DOWN_ARROW_KEY]) return Mobile.KEY_NUM8; + else if(keycode == awtGUI.inputKeycodes[AWTGUI.LEFT_ARROW_KEY]) return Mobile.KEY_NUM4; + else if(keycode == awtGUI.inputKeycodes[AWTGUI.RIGHT_ARROW_KEY]) return Mobile.KEY_NUM6; + + else if(keycode == awtGUI.inputKeycodes[AWTGUI.OK_KEY]) return Mobile.KEY_NUM5; + + else if(keycode == awtGUI.inputKeycodes[AWTGUI.SOFT_LEFT_KEY]) return Mobile.NOKIA_SOFT1; + else if(keycode == awtGUI.inputKeycodes[AWTGUI.SOFT_RIGHT_KEY]) return Mobile.NOKIA_SOFT2; + return 0; }