From bef355487d3b1041ae67f05bd4c954e1f854e8a5 Mon Sep 17 00:00:00 2001 From: Diego Waxemberg Date: Fri, 20 Dec 2013 23:13:18 -0500 Subject: [PATCH] fixed up gamepad mapping a bit. added options to invert and to act as a trigger --- src/com/limelight/gui/SettingsFrame.java | 190 ++++++++++++------ .../limelight/input/ControllerComponent.java | 36 ++++ src/com/limelight/input/Gamepad.java | 21 +- src/com/limelight/input/GamepadMapping.java | 4 + 4 files changed, 178 insertions(+), 73 deletions(-) diff --git a/src/com/limelight/gui/SettingsFrame.java b/src/com/limelight/gui/SettingsFrame.java index 60e1184..43a0623 100644 --- a/src/com/limelight/gui/SettingsFrame.java +++ b/src/com/limelight/gui/SettingsFrame.java @@ -5,6 +5,8 @@ import java.awt.Dimension; import java.awt.Toolkit; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.util.List; @@ -12,6 +14,7 @@ import java.util.List; import javax.swing.Box; import javax.swing.BoxLayout; import javax.swing.JButton; +import javax.swing.JCheckBox; import javax.swing.JFrame; import javax.swing.JOptionPane; import javax.swing.JPanel; @@ -29,49 +32,75 @@ import com.limelight.settings.GamepadSettingsManager; public class SettingsFrame extends JFrame { private static final long serialVersionUID = 1L; - + private boolean configChanged = false; private boolean shouldStartHandler = false; - + + private Thread mappingThread; private GamepadMapping config; - + public SettingsFrame() { super("Gamepad Settings"); System.out.println("Creating Settings Frame"); - this.setSize(500, 500); + this.setSize(900, 500); this.setResizable(false); this.setAlwaysOnTop(true); config = GamepadSettingsManager.getSettings(); - + } - + public void build() { Container c = this.getContentPane(); JPanel mainPanel = new JPanel(); mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.X_AXIS)); - + Box leftColumn = Box.createVerticalBox(); Box rightColumn = Box.createVerticalBox(); - + 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(); - + componentBox.add(Box.createHorizontalStrut(10)); componentBox.add(components[i].getLabel()); componentBox.add(Box.createHorizontalGlue()); componentBox.add(components[i].getMapButton()); + componentBox.add(Box.createHorizontalStrut(5)); + componentBox.add(components[i].getInvertBox()); + componentBox.add(Box.createHorizontalStrut(5)); + componentBox.add(components[i].getTriggerBox()); componentBox.add(Box.createHorizontalStrut(10)); - Dimension buttonSize = new Dimension(50,30); + Dimension buttonSize = new Dimension(110,32); 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])); + + components[i].getInvertBox().addItemListener(new ItemListener() { + @Override + public void itemStateChanged(ItemEvent e) { + JCheckBox clicked = (JCheckBox)e.getItem(); + ControllerComponent contComp = ControllerComponent.valueOf(clicked.getName()); + contComp.invert(e.getStateChange() == ItemEvent.SELECTED); + configChanged = true; + } + }); + + components[i].getTriggerBox().addItemListener(new ItemListener() { + @Override + public void itemStateChanged(ItemEvent e) { + JCheckBox clicked = (JCheckBox)e.getItem(); + ControllerComponent contComp = ControllerComponent.valueOf(clicked.getName()); + contComp.trigger(e.getStateChange() == ItemEvent.SELECTED); + configChanged = true; + } + }); if (i > components.length / 2) { rightColumn.add(componentBox); @@ -85,23 +114,25 @@ public class SettingsFrame extends JFrame { } } } - + rightColumn.add(Box.createVerticalGlue()); leftColumn.add(Box.createVerticalGlue()); - - mainPanel.add(Box.createHorizontalStrut(20)); + + mainPanel.add(Box.createHorizontalStrut(10)); mainPanel.add(leftColumn); - mainPanel.add(Box.createHorizontalGlue()); + mainPanel.add(Box.createHorizontalStrut(75)); mainPanel.add(rightColumn); - - mainPanel.add(Box.createHorizontalStrut(20)); - + mainPanel.add(Box.createHorizontalStrut(10)); + c.add(mainPanel); - + this.addWindowListener(new WindowAdapter() { @Override public void windowClosing(WindowEvent e) { super.windowClosing(e); + if (mappingThread != null && mappingThread.isAlive()) { + mappingThread.interrupt(); + } if (configChanged) { updateConfigs(); ControllerListener.startUp(); @@ -111,72 +142,97 @@ public class SettingsFrame extends JFrame { } } }); - + Dimension dim = Toolkit.getDefaultToolkit().getScreenSize(); this.setLocation(dim.width/2-this.getSize().width/2, dim.height/2-this.getSize().height/2); this.setVisible(true); } - + private ActionListener createListener() { return new ActionListener() { @Override public void actionPerformed(ActionEvent e) { //#allthejank 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"); - - ControllerListener.stopListening(); - - if (GamepadHandler.isRunning()) { - GamepadHandler.stopHandler(); - shouldStartHandler = true; - } - - 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; + map(contComp, gamepads.get(0)); } }; } - + + private void map(final ControllerComponent contComp, final Gamepad pad) { + if (mappingThread == null || !mappingThread.isAlive()) { + contComp.getMapButton().setSelected(true); + ControllerListener.stopListening(); + + if (GamepadHandler.isRunning()) { + GamepadHandler.stopHandler(); + shouldStartHandler = true; + } + + contComp.getMapButton().setText("Select Input"); + + mappingThread = new Thread(new Runnable() { + @Override + public void run() { + Component newMapping = null; + + while (newMapping == null) { + pad.poll(); + EventQueue queue = pad.getEvents(); + Event event = new Event(); + + while (queue.getNextEvent(event)) { + if (Math.abs(event.getValue()) > .75F) { + newMapping = event.getComponent(); + break; + } + } + + try { + Thread.sleep(100); + } catch (InterruptedException e) {} + } + + // start a new thread to go through all of the remaining events + Thread consumeEvents = new Thread(new Runnable() { + @Override + public void run() { + pad.poll(); + EventQueue queue = pad.getEvents(); + Event event = new Event(); + + while (queue.getNextEvent(event)) { + } + } + }); + consumeEvents.setName("Consume Events Thread"); + consumeEvents.start(); + + ControllerComponent oldConfig = config.getControllerComponent(newMapping); + if (oldConfig != null) { + config.removeMapping(newMapping); + oldConfig.getMapButton().setText(""); + } + + config.insertMapping(contComp, newMapping); + contComp.getMapButton().setText(newMapping.getName()); + configChanged = true; + contComp.getMapButton().setSelected(false); + } + }); + mappingThread.setName("Gamepad Mapping Thread"); + mappingThread.start(); + } + + } + private void updateConfigs() { GamepadSettingsManager.writeSettings(config); } diff --git a/src/com/limelight/input/ControllerComponent.java b/src/com/limelight/input/ControllerComponent.java index 143ff01..f5fda6e 100644 --- a/src/com/limelight/input/ControllerComponent.java +++ b/src/com/limelight/input/ControllerComponent.java @@ -3,6 +3,7 @@ package com.limelight.input; import java.io.Serializable; import javax.swing.JButton; +import javax.swing.JCheckBox; import javax.swing.JLabel; public enum ControllerComponent implements Serializable { @@ -15,13 +16,24 @@ public enum ControllerComponent implements Serializable { private JLabel label; private JButton mapButton; + private JCheckBox invertBox; + private JCheckBox triggerBox; private boolean analog; + private boolean invert; + private boolean trigger; private ControllerComponent(String name, boolean analog) { this.label = new JLabel(name); this.mapButton = new JButton(); this.mapButton.setName(this.name()); + this.invertBox = new JCheckBox("Invert"); + this.invertBox.setName(this.name()); + this.triggerBox = new JCheckBox("Trigger"); + this.triggerBox.setName(this.name()); + this.triggerBox.setToolTipText("If this component should act as a trigger."); this.analog = analog; + this.invert = false; + this.trigger = false; } public JLabel getLabel() { @@ -32,7 +44,31 @@ public enum ControllerComponent implements Serializable { return mapButton; } + public JCheckBox getInvertBox() { + return invertBox; + } + + public JCheckBox getTriggerBox() { + return triggerBox; + } + public boolean isAnalog() { return analog; } + + public boolean isTrigger() { + return trigger; + } + + public void trigger(boolean isTrigger) { + trigger = isTrigger; + } + + public void invert(boolean invert) { + this.invert = invert; + } + + public boolean invert() { + return invert; + } } diff --git a/src/com/limelight/input/Gamepad.java b/src/com/limelight/input/Gamepad.java index a3326d2..5e1208c 100644 --- a/src/com/limelight/input/Gamepad.java +++ b/src/com/limelight/input/Gamepad.java @@ -107,13 +107,24 @@ public class Gamepad { ControllerComponent contComp = config.getControllerComponent(comp); if (contComp != null) { if (contComp.isAnalog()) { - handleAnalog(contComp, value); + handleAnalog(contComp, sanitizeValue(contComp, value)); } else { - handleButtons(contComp, value); + handleButtons(contComp, sanitizeValue(contComp, value)); } } } + private float sanitizeValue(ControllerComponent contComp, float value) { + float sanitized = value; + if (contComp.invert()) { + sanitized = -sanitized; + } + if (contComp.isTrigger()) { + sanitized = (sanitized + 1)/2; + } + return sanitized; + } + private void toggle(short button, boolean press) { if (press) { inputMap |= button; @@ -123,8 +134,6 @@ public class Gamepad { } private void handleAnalog(ControllerComponent contComp, float value) { - - switch (contComp) { case LS_X: leftStickX = (short)Math.round(value * 0x7FFF); @@ -139,10 +148,10 @@ public class Gamepad { rightStickY = (short)Math.round(value * 0x7FFF); break; case LT: - leftTrigger = (byte)Math.round((value + 1) / 2 * 0xFF); + leftTrigger = (byte)Math.round(value * 0xFF); break; case RT: - rightTrigger = (byte)Math.round((value + 1) / 2 * 0xFF); + rightTrigger = (byte)Math.round(value * 0xFF); break; default: System.out.println("A mapping error has occured. Ignoring: " + contComp.name()); diff --git a/src/com/limelight/input/GamepadMapping.java b/src/com/limelight/input/GamepadMapping.java index acd8675..919f262 100644 --- a/src/com/limelight/input/GamepadMapping.java +++ b/src/com/limelight/input/GamepadMapping.java @@ -23,6 +23,10 @@ public class GamepadMapping implements Serializable { return mapping.get(comp.getIdentifier().getName()); } + public void removeMapping(Component comp) { + mapping.remove(comp.getIdentifier().getName()); + } + /** * Gets the mapping for the specified component.
* NOTE: Use sparingly takes O(N) time.