Merge pull request #1087 from jayfella/master

Add support for listening to joystick connection/disconnection.
accellbaker
Paul Speed 6 years ago committed by GitHub
commit 33ade6b874
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 60
      jme3-core/src/main/java/com/jme3/input/InputManager.java
  2. 21
      jme3-core/src/main/java/com/jme3/input/JoystickConnectionListener.java
  3. 32
      jme3-lwjgl3/src/main/java/com/jme3/input/lwjgl/GlfwJoystickInput.java
  4. 20
      jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglContext.java

@ -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,62 @@ 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 connected.
* This should only be called internally.
* @param joystick the joystick that has been connected.
*/
public void fireJoystickConnectedEvent(Joystick joystick) {
for (JoystickConnectionListener listener : joystickConnectionListeners) {
listener.onConnected(joystick);
}
}
/**
* Called when a joystick has been disconnected.
* This should only be called internally.
* @param joystick the joystick that has been disconnected.
*/
public void fireJoystickDisconnectedEvent(Joystick joystick) {
for (JoystickConnectionListener listener : joystickConnectionListeners) {
listener.onDisconnected(joystick);
}
}
} }

@ -0,0 +1,21 @@
package com.jme3.input;
/**
* Listens for the state of a joystick connection.
* @author jayfella
*/
public interface JoystickConnectionListener {
/**
* Occurs when a new joystick has been detected.
* @param joystick the joystick that has been detected.
*/
void onConnected(Joystick joystick);
/**
* Occurs when an existing joystick has been disconnected.
* @param joystick the joystick that has been disconnected.
*/
void onDisconnected(Joystick joystick);
}

@ -49,7 +49,7 @@ import static org.lwjgl.glfw.GLFW.*;
*/ */
public class GlfwJoystickInput implements JoyInput { public class GlfwJoystickInput implements JoyInput {
private static final Logger LOGGER = Logger.getLogger(InputManager.class.getName()); private static final Logger LOGGER = Logger.getLogger(GlfwJoystickInput.class.getName());
private RawInputListener listener; private RawInputListener listener;
@ -66,8 +66,28 @@ public class GlfwJoystickInput implements JoyInput {
} }
} }
public void fireJoystickConnectedEvent(int jid) {
Joystick joystick = joysticks.get(jid);
((InputManager)listener).fireJoystickConnectedEvent(joystick);
}
public void fireJoystickDisconnectedEvent(int jid) {
Joystick joystick = joysticks.get(jid);
((InputManager)listener).fireJoystickDisconnectedEvent(joystick);
}
public void reloadJoysticks() {
joysticks.clear();
InputManager inputManager = (InputManager) listener;
Joystick[] joysticks = loadJoysticks(inputManager);
inputManager.setJoysticks(joysticks);
}
@Override @Override
public Joystick[] loadJoysticks(final InputManager inputManager) { public Joystick[] loadJoysticks(final 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 +146,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 +176,7 @@ public class GlfwJoystickInput implements JoyInput {
} }
} }
} }
}
@Override @Override
public void destroy() { public void destroy() {

@ -37,6 +37,7 @@ import static java.util.stream.Collectors.toSet;
import static org.lwjgl.opencl.CL10.CL_CONTEXT_PLATFORM; import static org.lwjgl.opencl.CL10.CL_CONTEXT_PLATFORM;
import static org.lwjgl.opengl.GL.createCapabilities; import static org.lwjgl.opengl.GL.createCapabilities;
import static org.lwjgl.opengl.GL11.glGetInteger; import static org.lwjgl.opengl.GL11.glGetInteger;
import com.jme3.input.lwjgl.GlfwJoystickInput; import com.jme3.input.lwjgl.GlfwJoystickInput;
import com.jme3.input.lwjgl.GlfwKeyInput; import com.jme3.input.lwjgl.GlfwKeyInput;
import com.jme3.input.lwjgl.GlfwMouseInput; import com.jme3.input.lwjgl.GlfwMouseInput;
@ -65,6 +66,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 +235,24 @@ public abstract class LwjglContext implements JmeContext {
joyInput.initialize(); joyInput.initialize();
} }
GLFW.glfwSetJoystickCallback(new GLFWJoystickCallback() {
@Override
public void invoke(int jid, int event) {
// Invoke the disconnected event before we reload the joysticks or we lose the reference to it.
// Invoke the connected event after we reload the joysticks to obtain the reference to it.
if ( event == GLFW.GLFW_CONNECTED ) {
joyInput.reloadJoysticks();
joyInput.fireJoystickConnectedEvent(jid);
}
else {
joyInput.fireJoystickDisconnectedEvent(jid);
joyInput.reloadJoysticks();
}
}
});
renderable.set(true); renderable.set(true);
} }

Loading…
Cancel
Save