Add support for listening to joystick connection/disconnection.
Fixes bug causing NullPointerException when removing joysticks. Allows adding joysticks after the application has started.
This commit is contained in:
parent
c4d2de1656
commit
318d6d0e89
@ -42,6 +42,7 @@ import com.jme3.util.IntMap.Entry;
|
|||||||
import com.jme3.util.SafeArrayList;
|
import com.jme3.util.SafeArrayList;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
@ -106,6 +107,7 @@ public class InputManager implements RawInputListener {
|
|||||||
private final IntMap<Float> axisValues = new IntMap<Float>();
|
private final IntMap<Float> axisValues = new IntMap<Float>();
|
||||||
private final SafeArrayList<RawInputListener> rawListeners = new SafeArrayList<RawInputListener>(RawInputListener.class);
|
private final SafeArrayList<RawInputListener> rawListeners = new SafeArrayList<RawInputListener>(RawInputListener.class);
|
||||||
private final ArrayList<InputEvent> inputQueue = new ArrayList<InputEvent>();
|
private final ArrayList<InputEvent> inputQueue = new ArrayList<InputEvent>();
|
||||||
|
private final List<JoystickConnectionListener> joystickConnectionListeners = new ArrayList<>();
|
||||||
|
|
||||||
private static class Mapping {
|
private static class Mapping {
|
||||||
|
|
||||||
@ -953,4 +955,52 @@ public class InputManager implements RawInputListener {
|
|||||||
cursorPos.set(evt.getX(), evt.getY());
|
cursorPos.set(evt.getX(), evt.getY());
|
||||||
inputQueue.add(evt);
|
inputQueue.add(evt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Re-sets the joystick list when a joystick is added or removed.
|
||||||
|
* This should only be called internally.
|
||||||
|
*
|
||||||
|
* @param joysticks
|
||||||
|
*/
|
||||||
|
public void setJoysticks(Joystick[] joysticks) {
|
||||||
|
this.joysticks = joysticks;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a listener that reports when a joystick has been added or removed.
|
||||||
|
* Currently only implemented in LWJGL3
|
||||||
|
* @param listener the listner.
|
||||||
|
*/
|
||||||
|
public boolean addJoystickConnectionListener(JoystickConnectionListener listener) {
|
||||||
|
return joystickConnectionListeners.add(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove an existing listener.
|
||||||
|
* @param listener the listener to remove.
|
||||||
|
* @return true if this listener was removed, or false if it was not found.
|
||||||
|
*/
|
||||||
|
public boolean removeJoystickConnectionListener(JoystickConnectionListener listener) {
|
||||||
|
return joystickConnectionListeners.remove(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove all joystick connection listeners.
|
||||||
|
*/
|
||||||
|
public void clearJoystickConnectionListeners() {
|
||||||
|
joystickConnectionListeners.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when a joystick has been added or removed.
|
||||||
|
* This should only be called internally.
|
||||||
|
* @param joystickId the ID of the joystick.
|
||||||
|
* @param event the event that occured (connected / disconnected).
|
||||||
|
*/
|
||||||
|
public void fireJoystickConnectionEvent(int joystickId, int event) {
|
||||||
|
for (JoystickConnectionListener listener : joystickConnectionListeners) {
|
||||||
|
listener.connectionChanged(joystickId, JoystickState.fromCode(event));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,7 @@
|
|||||||
|
package com.jme3.input;
|
||||||
|
|
||||||
|
public interface JoystickConnectionListener {
|
||||||
|
|
||||||
|
void connectionChanged(int joystickId, JoystickState action);
|
||||||
|
|
||||||
|
}
|
47
jme3-core/src/main/java/com/jme3/input/JoystickState.java
Normal file
47
jme3-core/src/main/java/com/jme3/input/JoystickState.java
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
package com.jme3.input;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Response for joystick callback events.
|
||||||
|
* @author jayfella
|
||||||
|
*/
|
||||||
|
public enum JoystickState {
|
||||||
|
|
||||||
|
// a list of connected/disconnected codes from various contexts.
|
||||||
|
|
||||||
|
// using the JoystickState.fromCode(int) method, if the code matches
|
||||||
|
// it will return the enum value.
|
||||||
|
|
||||||
|
CONNECTED(new int[] {
|
||||||
|
0x40001 // GLFW.GLFW_CONNECTED / LWJGL3
|
||||||
|
}),
|
||||||
|
|
||||||
|
DISCONNECTED(new int[] {
|
||||||
|
0x40002 // GLFW.GLFW_DISCONNECTED / LWJGL3
|
||||||
|
}),
|
||||||
|
|
||||||
|
UNKNOWN(new int[0]);
|
||||||
|
|
||||||
|
private int[] codes;
|
||||||
|
|
||||||
|
JoystickState(int[] codes) {
|
||||||
|
this.codes = codes;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int[] getCodes() {
|
||||||
|
return codes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static JoystickState fromCode(int value) {
|
||||||
|
|
||||||
|
for (JoystickState state : values()) {
|
||||||
|
for (int code : state.getCodes()) {
|
||||||
|
if (value == code) {
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -57,6 +57,8 @@ public class GlfwJoystickInput implements JoyInput {
|
|||||||
|
|
||||||
private final Map<JoystickButton, Boolean> joyButtonPressed = new HashMap<>();
|
private final Map<JoystickButton, Boolean> joyButtonPressed = new HashMap<>();
|
||||||
|
|
||||||
|
private InputManager inputManager;
|
||||||
|
|
||||||
private boolean initialized = false;
|
private boolean initialized = false;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -66,8 +68,24 @@ public class GlfwJoystickInput implements JoyInput {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void fireJoystickConnectionEvent(int jid, int event) {
|
||||||
|
inputManager.fireJoystickConnectionEvent(jid, event);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void reloadJoysticks() {
|
||||||
|
joysticks.clear();
|
||||||
|
|
||||||
|
if (inputManager != null) {
|
||||||
|
Joystick[] joysticks = loadJoysticks(inputManager);
|
||||||
|
inputManager.setJoysticks(joysticks);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Joystick[] loadJoysticks(final InputManager inputManager) {
|
public Joystick[] loadJoysticks(final InputManager inputManager) {
|
||||||
|
|
||||||
|
this.inputManager = inputManager;
|
||||||
|
|
||||||
for (int i = 0; i < GLFW_JOYSTICK_LAST; i++) {
|
for (int i = 0; i < GLFW_JOYSTICK_LAST; i++) {
|
||||||
if (glfwJoystickPresent(i)) {
|
if (glfwJoystickPresent(i)) {
|
||||||
final String name = glfwGetJoystickName(i);
|
final String name = glfwGetJoystickName(i);
|
||||||
@ -126,17 +144,26 @@ public class GlfwJoystickInput implements JoyInput {
|
|||||||
@Override
|
@Override
|
||||||
public void update() {
|
public void update() {
|
||||||
for (final Map.Entry<Integer, GlfwJoystick> entry : joysticks.entrySet()) {
|
for (final Map.Entry<Integer, GlfwJoystick> entry : joysticks.entrySet()) {
|
||||||
|
|
||||||
// Axes
|
// Axes
|
||||||
final FloatBuffer axisValues = glfwGetJoystickAxes(entry.getKey());
|
final FloatBuffer axisValues = glfwGetJoystickAxes(entry.getKey());
|
||||||
|
|
||||||
|
// if a joystick is added or removed, the callback reloads the joysticks.
|
||||||
|
// when the callback is called and reloads the joystick, this iterator may already have started iterating.
|
||||||
|
// To avoid a NullPointerException we null-check the axisValues and bytebuffer objects.
|
||||||
|
// If the joystick it's iterating over no-longer exists it will return null.
|
||||||
|
|
||||||
|
if (axisValues != null) {
|
||||||
for (final JoystickAxis axis : entry.getValue().getAxes()) {
|
for (final JoystickAxis axis : entry.getValue().getAxes()) {
|
||||||
final float value = axisValues.get(axis.getAxisId());
|
final float value = axisValues.get(axis.getAxisId());
|
||||||
listener.onJoyAxisEvent(new JoyAxisEvent(axis, value));
|
listener.onJoyAxisEvent(new JoyAxisEvent(axis, value));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Buttons
|
// Buttons
|
||||||
final ByteBuffer byteBuffer = glfwGetJoystickButtons(entry.getKey());
|
final ByteBuffer byteBuffer = glfwGetJoystickButtons(entry.getKey());
|
||||||
|
|
||||||
|
if (byteBuffer != null) {
|
||||||
for (final JoystickButton button : entry.getValue().getButtons()) {
|
for (final JoystickButton button : entry.getValue().getButtons()) {
|
||||||
final boolean pressed = byteBuffer.get(button.getButtonId()) == GLFW_PRESS;
|
final boolean pressed = byteBuffer.get(button.getButtonId()) == GLFW_PRESS;
|
||||||
|
|
||||||
@ -147,6 +174,7 @@ public class GlfwJoystickInput implements JoyInput {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void destroy() {
|
public void destroy() {
|
||||||
|
@ -65,6 +65,7 @@ import com.jme3.util.LWJGLBufferAllocator.ConcurrentLWJGLBufferAllocator;
|
|||||||
import org.lwjgl.PointerBuffer;
|
import org.lwjgl.PointerBuffer;
|
||||||
import org.lwjgl.Version;
|
import org.lwjgl.Version;
|
||||||
import org.lwjgl.glfw.GLFW;
|
import org.lwjgl.glfw.GLFW;
|
||||||
|
import org.lwjgl.glfw.GLFWJoystickCallback;
|
||||||
import org.lwjgl.opencl.APPLEGLSharing;
|
import org.lwjgl.opencl.APPLEGLSharing;
|
||||||
import org.lwjgl.opencl.CL10;
|
import org.lwjgl.opencl.CL10;
|
||||||
import org.lwjgl.opencl.KHRGLSharing;
|
import org.lwjgl.opencl.KHRGLSharing;
|
||||||
@ -233,6 +234,14 @@ public abstract class LwjglContext implements JmeContext {
|
|||||||
joyInput.initialize();
|
joyInput.initialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GLFW.glfwSetJoystickCallback(new GLFWJoystickCallback() {
|
||||||
|
@Override
|
||||||
|
public void invoke(int jid, int event) {
|
||||||
|
joyInput.reloadJoysticks();
|
||||||
|
joyInput.fireJoystickConnectionEvent(jid, event);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
renderable.set(true);
|
renderable.set(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user