diff --git a/src/com/limelight/gui/MainFrame.java b/src/com/limelight/gui/MainFrame.java index 03ff9d6..5c882ca 100644 --- a/src/com/limelight/gui/MainFrame.java +++ b/src/com/limelight/gui/MainFrame.java @@ -18,6 +18,9 @@ import javax.swing.BoxLayout; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JFrame; +import javax.swing.JMenu; +import javax.swing.JMenuBar; +import javax.swing.JMenuItem; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JTextField; @@ -94,14 +97,6 @@ public class MainFrame { Box contentBox = Box.createVerticalBox(); contentBox.add(Box.createVerticalStrut(20)); contentBox.add(hostBox); - JButton settings = new JButton("Settings"); - settings.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - new SettingsFrame().build(); - } - }); - contentBox.add(settings); contentBox.add(Box.createVerticalStrut(5)); contentBox.add(fullscreen); contentBox.add(Box.createVerticalStrut(5)); @@ -109,23 +104,38 @@ public class MainFrame { contentBox.add(Box.createVerticalStrut(10)); contentBox.add(pairBox); - - - - contentBox.add(Box.createVerticalGlue()); centerPane.add(contentBox); mainPane.add(centerPane, "Center"); Dimension dim = Toolkit.getDefaultToolkit().getScreenSize(); + limeFrame.setJMenuBar(createMenuBar()); limeFrame.getRootPane().setDefaultButton(stream); - limeFrame.setSize(300, 175); + limeFrame.setSize(300, 200); limeFrame.setLocation(dim.width/2-limeFrame.getSize().width/2, dim.height/2-limeFrame.getSize().height/2); limeFrame.setResizable(false); limeFrame.setVisible(true); } + private JMenuBar createMenuBar() { + JMenuBar menuBar = new JMenuBar(); + JMenu optionsMenu = new JMenu("Options"); + JMenuItem settings = new JMenuItem("Gamepad Settings"); + + settings.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + new SettingsFrame().build(); + } + }); + + optionsMenu.add(settings); + menuBar.add(optionsMenu); + + return menuBar; + } + private ActionListener createStreamButtonListener() { return new ActionListener() { @Override diff --git a/src/com/limelight/gui/SettingsFrame.java b/src/com/limelight/gui/SettingsFrame.java index ce28a33..60e1184 100644 --- a/src/com/limelight/gui/SettingsFrame.java +++ b/src/com/limelight/gui/SettingsFrame.java @@ -7,34 +7,42 @@ import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; +import java.util.List; import javax.swing.Box; import javax.swing.BoxLayout; +import javax.swing.JButton; import javax.swing.JFrame; +import javax.swing.JOptionPane; import javax.swing.JPanel; -import javax.swing.JTextField; import net.java.games.input.Component; import net.java.games.input.Event; import net.java.games.input.EventQueue; import com.limelight.input.ControllerComponent; +import com.limelight.input.ControllerListener; import com.limelight.input.Gamepad; import com.limelight.input.GamepadHandler; -import com.limelight.input.GamepadSettings; +import com.limelight.input.GamepadMapping; import com.limelight.settings.GamepadSettingsManager; public class SettingsFrame extends JFrame { private static final long serialVersionUID = 1L; private boolean configChanged = false; - private GamepadSettings config; + private boolean shouldStartHandler = false; + + private GamepadMapping config; public SettingsFrame() { - super("Limelight Settings"); - this.setSize(800, 500); + super("Gamepad Settings"); + System.out.println("Creating Settings Frame"); + this.setSize(500, 500); this.setResizable(false); this.setAlwaysOnTop(true); + config = GamepadSettingsManager.getSettings(); + } public void build() { @@ -48,7 +56,6 @@ public class SettingsFrame extends JFrame { leftColumn.add(Box.createVerticalStrut(10)); rightColumn.add(Box.createVerticalStrut(10)); - ControllerComponent[] components = ControllerComponent.values(); for (int i = 0; i < components.length; i++) { Box componentBox = Box.createHorizontalBox(); @@ -58,8 +65,14 @@ public class SettingsFrame extends JFrame { componentBox.add(Box.createHorizontalGlue()); componentBox.add(components[i].getMapButton()); componentBox.add(Box.createHorizontalStrut(10)); - components[i].getMapButton().setMaximumSize(new Dimension(50, 30)); + + Dimension buttonSize = new Dimension(50,30); + components[i].getMapButton().setMaximumSize(buttonSize); + components[i].getMapButton().setMinimumSize(buttonSize); + components[i].getMapButton().setPreferredSize(buttonSize); components[i].getMapButton().addActionListener(createListener()); + components[i].getMapButton().setText(config.getMapping(components[i])); + if (i > components.length / 2) { rightColumn.add(componentBox); if (i < components.length - 1) { @@ -91,6 +104,10 @@ public class SettingsFrame extends JFrame { super.windowClosing(e); if (configChanged) { updateConfigs(); + ControllerListener.startUp(); + } + if (shouldStartHandler) { + GamepadHandler.startUp(); } } }); @@ -105,25 +122,56 @@ public class SettingsFrame extends JFrame { @Override public void actionPerformed(ActionEvent e) { //#allthejank - ControllerComponent contComp = ControllerComponent.valueOf(((JTextField)e.getSource()).getName()); + ControllerComponent contComp = ControllerComponent.valueOf(((JButton)e.getSource()).getName()); + + List gamepads = GamepadHandler.getGamepads(); + + if (gamepads.isEmpty()) { + JOptionPane.showMessageDialog(SettingsFrame.this, "No Gamepad Detected"); + return; + } contComp.getMapButton().setText("Select Input"); - Gamepad listenPad = GamepadHandler.getGamepads().get(0); - listenPad.poll(); - EventQueue queue = listenPad.getEvents(); - Event event = new Event(); - queue.getNextEvent(event); - Component comp = event.getComponent(); - contComp.getMapButton().setText(comp.getName()); + ControllerListener.stopListening(); - config = listenPad.getConfiguration(); - if (config == null) { - config = new GamepadSettings(); + if (GamepadHandler.isRunning()) { + GamepadHandler.stopHandler(); + shouldStartHandler = true; } - config.insertSetting(contComp, comp); + final Gamepad listenPad = gamepads.get(0); + Component newMapping = null; + + while (newMapping == null) { + listenPad.poll(); + EventQueue queue = listenPad.getEvents(); + Event event = new Event(); + + while (queue.getNextEvent(event)) { + if (Math.abs(event.getValue()) > .75F) { + newMapping = event.getComponent(); + break; + } + } + } + + //spin off a new thread to handle any other events we got + new Thread(new Runnable() { + @Override + public void run() { + listenPad.poll(); + listenPad.handleEvents(null); + } + }).start(); + + ControllerComponent oldConfig = config.getControllerComponent(newMapping); + if (oldConfig != null) { + oldConfig.getMapButton().setText(""); + } + config.insertMapping(contComp, newMapping); + contComp.getMapButton().setText(newMapping.getName()); configChanged = true; } }; diff --git a/src/com/limelight/input/ControllerComponent.java b/src/com/limelight/input/ControllerComponent.java index 8b2ff4d..143ff01 100644 --- a/src/com/limelight/input/ControllerComponent.java +++ b/src/com/limelight/input/ControllerComponent.java @@ -8,7 +8,7 @@ import javax.swing.JLabel; public enum ControllerComponent implements Serializable { BTN_A("Button 1 (A)", false), BTN_X("Button 2 (X)", false), BTN_Y("Button 3 (Y)", false), BTN_B("Button 4 (B)", false), DPAD_UP("D-pad Up", false), DPAD_DOWN("D-pad Down", false), DPAD_LEFT("D-pad Left", false), DPAD_RIGHT("D-pad Right", false), - LS_X("Left Stick X", true), LS_Y("Left Stick X", true), RS_X("Right Stick X", true), RS_Y("Left Stick Y", true), + LS_X("Left Stick X", true), LS_Y("Left Stick Y", true), RS_X("Right Stick X", true), RS_Y("Right Stick Y", true), LS_THUMB("Left Stick Button", false), RS_THUMB("Right Stick Button", false), LT("Left Trigger", true), RT("Right Trigger", true), LB("Left Bumper", false), RB("Right Bumper", false), BTN_START("Start Button", false), BTN_BACK("Back Button", false), BTN_SPECIAL("Special Button", false); diff --git a/src/com/limelight/input/ControllerListener.java b/src/com/limelight/input/ControllerListener.java index 2bfa30f..b80462c 100644 --- a/src/com/limelight/input/ControllerListener.java +++ b/src/com/limelight/input/ControllerListener.java @@ -86,11 +86,17 @@ public class ControllerListener { System.out.println("Stopping Controller Listener thread"); listenerThread.interrupt(); } + if (GamepadHandler.isRunning()) { + GamepadHandler.stopHandler(); + } } public static void startSendingInput(NvConnection connection) { System.out.println("Starting to send controller input"); conn = connection; + if (!GamepadHandler.isRunning()) { + GamepadHandler.startUp(); + } } public static void stopSendingInput() { diff --git a/src/com/limelight/input/Gamepad.java b/src/com/limelight/input/Gamepad.java index 84f5539..a3326d2 100644 --- a/src/com/limelight/input/Gamepad.java +++ b/src/com/limelight/input/Gamepad.java @@ -10,7 +10,7 @@ import net.java.games.input.EventQueue; public class Gamepad { private Controller pad; - private GamepadSettings config; + private GamepadMapping config; private short inputMap = 0x0000; private byte leftTrigger = 0x00; @@ -20,7 +20,7 @@ public class Gamepad { private short leftStickX = 0x0000; private short leftStickY = 0x0000; - public Gamepad(Controller pad, GamepadSettings settings) { + public Gamepad(Controller pad, GamepadMapping settings) { this.config = settings; this.pad = pad; @@ -29,7 +29,7 @@ public class Gamepad { } } - public GamepadSettings getConfiguration() { + public GamepadMapping getConfiguration() { return config; } @@ -104,8 +104,8 @@ public class Gamepad { } private void handleComponent(Component comp, float value) { - if (config != null) { - ControllerComponent contComp = config.getControllerComponent(comp); + ControllerComponent contComp = config.getControllerComponent(comp); + if (contComp != null) { if (contComp.isAnalog()) { handleAnalog(contComp, value); } else { diff --git a/src/com/limelight/input/GamepadHandler.java b/src/com/limelight/input/GamepadHandler.java index 6ec440d..69d3ed3 100644 --- a/src/com/limelight/input/GamepadHandler.java +++ b/src/com/limelight/input/GamepadHandler.java @@ -4,6 +4,8 @@ package com.limelight.input; import java.util.Collections; import java.util.LinkedList; import java.util.List; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; import com.limelight.nvstream.NvConnection; import com.limelight.settings.GamepadSettingsManager; @@ -12,19 +14,23 @@ import net.java.games.input.Controller; public class GamepadHandler { private static LinkedList gamepads = new LinkedList(); + private static Lock gamepadLock = new ReentrantLock(); private static NvConnection conn; private static Thread handler; - + private static boolean run = true; + public static void addGamepads(List pads) { - - gamepads.clear(); - + LinkedList newPadList = new LinkedList(); - GamepadSettings settings = GamepadSettingsManager.getSettings(); + GamepadMapping settings = GamepadSettingsManager.getSettings(); for (Controller pad : pads) { - gamepads.add(new Gamepad(pad, settings)); + newPadList.add(new Gamepad(pad, settings)); } + + gamepadLock.lock(); + gamepads = newPadList; + gamepadLock.unlock(); } public static void setConnection(NvConnection connection) { @@ -37,21 +43,29 @@ public class GamepadHandler { public static void startUp() { if (handler == null || !handler.isAlive()) { + run = true; System.out.println("Gamepad Handler thread starting up"); handler = new Thread(new Runnable() { @Override public void run() { - while (true) { + while (run) { + try { + gamepadLock.lockInterruptibly(); + } catch (InterruptedException e1) { + run = false; + } for (Gamepad gamepad : gamepads) { if (!gamepad.poll()) { break; } - gamepad.handleEvents(conn); } + gamepadLock.unlock(); try { Thread.sleep(20); - } catch (InterruptedException e) {} + } catch (InterruptedException e) { + run = false; + } } } }); @@ -67,4 +81,8 @@ public class GamepadHandler { } } + public static boolean isRunning() { + return (handler != null && handler.isAlive()); + } + } diff --git a/src/com/limelight/input/GamepadMapping.java b/src/com/limelight/input/GamepadMapping.java new file mode 100644 index 0000000..acd8675 --- /dev/null +++ b/src/com/limelight/input/GamepadMapping.java @@ -0,0 +1,40 @@ +package com.limelight.input; + +import java.io.Serializable; +import java.util.HashMap; +import java.util.Map.Entry; + +import net.java.games.input.Component; + +public class GamepadMapping implements Serializable { + private static final long serialVersionUID = -185035113915743149L; + + private HashMap mapping; + + public GamepadMapping() { + mapping = new HashMap(); + } + + public void insertMapping(ControllerComponent contComp, Component comp) { + mapping.put(comp.getIdentifier().getName(), contComp); + } + + public ControllerComponent getControllerComponent(Component comp) { + return mapping.get(comp.getIdentifier().getName()); + } + + /** + * Gets the mapping for the specified component.
+ * NOTE: Use sparingly takes O(N) time. + * @param contComp the component to get a mapping for + * @return a mapping or an empty string if there is none + */ + public String getMapping(ControllerComponent contComp) { + for (Entry entry : mapping.entrySet()) { + if (entry.getValue().equals(contComp)) { + return entry.getKey(); + } + } + return ""; + } +} diff --git a/src/com/limelight/input/GamepadSettings.java b/src/com/limelight/input/GamepadSettings.java deleted file mode 100644 index 0649d80..0000000 --- a/src/com/limelight/input/GamepadSettings.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.limelight.input; - -import java.io.Serializable; -import java.util.HashMap; - -import net.java.games.input.Component; - -public class GamepadSettings implements Serializable { - private static final long serialVersionUID = -185035113915743149L; - - private HashMap mapping; - private HashMap inverseMapping; - - public void insertSetting(ControllerComponent contComp, Component comp) { - mapping.put(contComp, comp); - inverseMapping.put(comp, contComp); - } - - public Component getComponent(ControllerComponent contComp) { - return mapping.get(contComp); - } - - public ControllerComponent getControllerComponent(Component comp) { - return inverseMapping.get(comp); - } -} diff --git a/src/com/limelight/settings/GamepadSettingsManager.java b/src/com/limelight/settings/GamepadSettingsManager.java index 475cbc0..7b753b5 100644 --- a/src/com/limelight/settings/GamepadSettingsManager.java +++ b/src/com/limelight/settings/GamepadSettingsManager.java @@ -8,20 +8,21 @@ import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; -import com.limelight.input.GamepadSettings; +import com.limelight.input.GamepadMapping; public class GamepadSettingsManager { - private static GamepadSettings cachedSettings; + private static GamepadMapping cachedSettings; - public static GamepadSettings getSettings() { + public static GamepadMapping getSettings() { if (cachedSettings == null) { + System.out.println("Reading Gamepad Settings"); File gamepadFile = SettingsManager.getInstance().getGamepadFile(); ObjectInputStream ois = null; try { ois = new ObjectInputStream(new FileInputStream(gamepadFile)); - GamepadSettings savedSettings = (GamepadSettings)ois.readObject(); + GamepadMapping savedSettings = (GamepadMapping)ois.readObject(); cachedSettings = savedSettings; } catch (ClassNotFoundException e) { @@ -47,13 +48,20 @@ public class GamepadSettingsManager { } } } + if (cachedSettings == null) { + System.out.println("Unable to get gamepad settings. Using an empty mapping instead."); + cachedSettings = new GamepadMapping(); + writeSettings(cachedSettings); + } return cachedSettings; } - public static void writeSettings(GamepadSettings settings) { + public static void writeSettings(GamepadMapping settings) { cachedSettings = settings; + System.out.println("Writing Gamepad Settings"); File gamepadFile = SettingsManager.getInstance().getGamepadFile(); + ObjectOutputStream ous = null; try { diff --git a/src/com/limelight/settings/SettingsManager.java b/src/com/limelight/settings/SettingsManager.java index 39ac08a..6e05be7 100644 --- a/src/com/limelight/settings/SettingsManager.java +++ b/src/com/limelight/settings/SettingsManager.java @@ -16,8 +16,8 @@ public class SettingsManager { private static SettingsManager manager; private SettingsManager() { - settingsFile = new File(SETTINGS_DIR + "settings"); - gamepadFile = new File(SETTINGS_DIR + "gamepad"); + settingsFile = new File(SETTINGS_DIR + File.separator + "settings.lime"); + gamepadFile = new File(SETTINGS_DIR + File.separator + "gamepad.lime"); settingsDir = new File(SETTINGS_DIR); }