|
@@ -34,30 +34,65 @@ package com.jme3.input.lwjgl;
|
|
|
import com.jme3.input.*;
|
|
import com.jme3.input.*;
|
|
|
import com.jme3.input.event.JoyAxisEvent;
|
|
import com.jme3.input.event.JoyAxisEvent;
|
|
|
import com.jme3.input.event.JoyButtonEvent;
|
|
import com.jme3.input.event.JoyButtonEvent;
|
|
|
|
|
+import com.jme3.math.FastMath;
|
|
|
|
|
+
|
|
|
import java.nio.ByteBuffer;
|
|
import java.nio.ByteBuffer;
|
|
|
import java.nio.FloatBuffer;
|
|
import java.nio.FloatBuffer;
|
|
|
import java.util.HashMap;
|
|
import java.util.HashMap;
|
|
|
import java.util.Map;
|
|
import java.util.Map;
|
|
|
|
|
+import java.util.logging.Level;
|
|
|
import java.util.logging.Logger;
|
|
import java.util.logging.Logger;
|
|
|
|
|
+import com.jme3.system.AppSettings;
|
|
|
|
|
+import org.lwjgl.glfw.GLFWGamepadState;
|
|
|
import static org.lwjgl.glfw.GLFW.*;
|
|
import static org.lwjgl.glfw.GLFW.*;
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
* The LWJGL implementation of {@link JoyInput}.
|
|
* The LWJGL implementation of {@link JoyInput}.
|
|
|
*
|
|
*
|
|
|
- * @author Daniel Johansson (dannyjo)
|
|
|
|
|
|
|
+ * @author Daniel Johansson (dannyjo), Riccardo Balbo
|
|
|
* @since 3.1
|
|
* @since 3.1
|
|
|
*/
|
|
*/
|
|
|
public class GlfwJoystickInput implements JoyInput {
|
|
public class GlfwJoystickInput implements JoyInput {
|
|
|
-
|
|
|
|
|
private static final Logger LOGGER = Logger.getLogger(GlfwJoystickInput.class.getName());
|
|
private static final Logger LOGGER = Logger.getLogger(GlfwJoystickInput.class.getName());
|
|
|
|
|
+ private static final int POV_X_AXIS_ID = 7;
|
|
|
|
|
+ private static final int POV_Y_AXIS_ID = 8;
|
|
|
|
|
|
|
|
- private RawInputListener listener;
|
|
|
|
|
-
|
|
|
|
|
|
|
+ private final AppSettings settings;
|
|
|
private final Map<Integer, GlfwJoystick> joysticks = new HashMap<>();
|
|
private final Map<Integer, GlfwJoystick> joysticks = new HashMap<>();
|
|
|
-
|
|
|
|
|
private final Map<JoystickButton, Boolean> joyButtonPressed = new HashMap<>();
|
|
private final Map<JoystickButton, Boolean> joyButtonPressed = new HashMap<>();
|
|
|
|
|
+ private final Map<JoystickAxis, Float> joyAxisValues = new HashMap<>();
|
|
|
|
|
|
|
|
private boolean initialized = false;
|
|
private boolean initialized = false;
|
|
|
|
|
+ private float virtualTriggerThreshold;
|
|
|
|
|
+ private boolean xboxStyle;
|
|
|
|
|
+ private float globalJitterThreshold = 0f;
|
|
|
|
|
+ private GLFWGamepadState gamepadState;
|
|
|
|
|
+ private RawInputListener listener;
|
|
|
|
|
+
|
|
|
|
|
+ public GlfwJoystickInput(AppSettings settings) {
|
|
|
|
|
+ this.settings = settings;
|
|
|
|
|
+ try {
|
|
|
|
|
+ String path = settings.getSDLGameControllerDBResourcePath();
|
|
|
|
|
+ if (path != null && !path.trim().isEmpty()) {
|
|
|
|
|
+ ByteBuffer bbf = SdlGameControllerDb.getGamecontrollerDb(path);
|
|
|
|
|
+ if (!glfwUpdateGamepadMappings(bbf)) throw new Exception("Failed to load");
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ LOGGER.log(Level.WARNING, "Unable to load gamecontrollerdb, fallback to glfw default mappings",
|
|
|
|
|
+ e);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public void initialize() {
|
|
|
|
|
+ gamepadState = GLFWGamepadState.create();
|
|
|
|
|
+
|
|
|
|
|
+ virtualTriggerThreshold = settings.getJoysticksTriggerToButtonThreshold();
|
|
|
|
|
+ xboxStyle = settings.getJoysticksMapper().equals(AppSettings.JOYSTICKS_XBOX_LEGACY_MAPPER);
|
|
|
|
|
+ globalJitterThreshold = settings.getJoysticksAxisJitterThreshold();
|
|
|
|
|
+
|
|
|
|
|
+ initialized = true;
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
@Override
|
|
@Override
|
|
|
public void setJoyRumble(final int joyId, final float amount) {
|
|
public void setJoyRumble(final int joyId, final float amount) {
|
|
@@ -78,9 +113,9 @@ public class GlfwJoystickInput implements JoyInput {
|
|
|
|
|
|
|
|
public void reloadJoysticks() {
|
|
public void reloadJoysticks() {
|
|
|
joysticks.clear();
|
|
joysticks.clear();
|
|
|
-
|
|
|
|
|
|
|
+ joyButtonPressed.clear();
|
|
|
|
|
+ joyAxisValues.clear();
|
|
|
InputManager inputManager = (InputManager) listener;
|
|
InputManager inputManager = (InputManager) listener;
|
|
|
-
|
|
|
|
|
Joystick[] joysticks = loadJoysticks(inputManager);
|
|
Joystick[] joysticks = loadJoysticks(inputManager);
|
|
|
inputManager.setJoysticks(joysticks);
|
|
inputManager.setJoysticks(joysticks);
|
|
|
}
|
|
}
|
|
@@ -90,43 +125,95 @@ public class GlfwJoystickInput implements JoyInput {
|
|
|
|
|
|
|
|
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 GlfwJoystick joystick = new GlfwJoystick(inputManager, this, i, name);
|
|
|
|
|
- joysticks.put(i, joystick);
|
|
|
|
|
-
|
|
|
|
|
- final FloatBuffer floatBuffer = glfwGetJoystickAxes(i);
|
|
|
|
|
-
|
|
|
|
|
- int axisIndex = 0;
|
|
|
|
|
- while (floatBuffer.hasRemaining()) {
|
|
|
|
|
- floatBuffer.get();
|
|
|
|
|
-
|
|
|
|
|
- final String logicalId = JoystickCompatibilityMappings.remapAxis(joystick.getName(), convertAxisIndex(axisIndex));
|
|
|
|
|
- final JoystickAxis joystickAxis = new DefaultJoystickAxis(inputManager, joystick, axisIndex, convertAxisIndex(axisIndex), logicalId, true, false, 0.0f);
|
|
|
|
|
- joystick.addAxis(axisIndex, joystickAxis);
|
|
|
|
|
- axisIndex++;
|
|
|
|
|
|
|
+ boolean isGlfwGamepad = xboxStyle && glfwJoystickIsGamepad(i);
|
|
|
|
|
+
|
|
|
|
|
+ String name;
|
|
|
|
|
+ if (isGlfwGamepad) {
|
|
|
|
|
+ name = glfwGetGamepadName(i);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ name = glfwGetJoystickName(i);
|
|
|
|
|
+ LOGGER.log(Level.WARNING,
|
|
|
|
|
+ "Unknown controller detected: {0} - guid: {1}. Fallback to raw input handling",
|
|
|
|
|
+ new Object[] { name, glfwGetJoystickGUID(i) });
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- final ByteBuffer byteBuffer = glfwGetJoystickButtons(i);
|
|
|
|
|
|
|
+ GlfwJoystick joystick = new GlfwJoystick(inputManager, this, i, name, isGlfwGamepad);
|
|
|
|
|
+ joysticks.put(i, joystick);
|
|
|
|
|
|
|
|
- if (byteBuffer != null) {
|
|
|
|
|
- int buttonIndex = 0;
|
|
|
|
|
- while (byteBuffer.hasRemaining()) {
|
|
|
|
|
- byteBuffer.get();
|
|
|
|
|
|
|
+ if(!isGlfwGamepad){
|
|
|
|
|
+ // RAW axis
|
|
|
|
|
+ FloatBuffer floatBuffer = glfwGetJoystickAxes(i);
|
|
|
|
|
+ if (floatBuffer == null) continue;
|
|
|
|
|
+
|
|
|
|
|
+ int axisIndex = 0;
|
|
|
|
|
+ while (floatBuffer.hasRemaining()) {
|
|
|
|
|
+ floatBuffer.get();
|
|
|
|
|
+
|
|
|
|
|
+ String logicalId = JoystickCompatibilityMappings.remapAxis(joystick.getName(),
|
|
|
|
|
+ convertAxisIndex(axisIndex));
|
|
|
|
|
+ JoystickAxis joystickAxis = new DefaultJoystickAxis(inputManager, joystick, axisIndex,
|
|
|
|
|
+ convertAxisIndex(axisIndex), logicalId, true, false, 0.0f);
|
|
|
|
|
+ joystick.addAxis(axisIndex, joystickAxis);
|
|
|
|
|
+ axisIndex++;
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- final String logicalId = JoystickCompatibilityMappings.remapButton(joystick.getName(), String.valueOf(buttonIndex));
|
|
|
|
|
- final JoystickButton button = new DefaultJoystickButton(inputManager, joystick, buttonIndex, String.valueOf(buttonIndex), logicalId);
|
|
|
|
|
|
|
+ // raw buttons
|
|
|
|
|
+ ByteBuffer byteBuffer = glfwGetJoystickButtons(i);
|
|
|
|
|
+
|
|
|
|
|
+ if (byteBuffer != null) {
|
|
|
|
|
+ int buttonIndex = 0;
|
|
|
|
|
+ while (byteBuffer.hasRemaining()) {
|
|
|
|
|
+ byteBuffer.get();
|
|
|
|
|
+
|
|
|
|
|
+ String logicalId = JoystickCompatibilityMappings.remapButton(joystick.getName(),
|
|
|
|
|
+ String.valueOf(buttonIndex));
|
|
|
|
|
+ JoystickButton button = new DefaultJoystickButton(inputManager, joystick,
|
|
|
|
|
+ buttonIndex, String.valueOf(buttonIndex), logicalId);
|
|
|
|
|
+ joystick.addButton(button);
|
|
|
|
|
+ joyButtonPressed.put(button, false);
|
|
|
|
|
+ buttonIndex++;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ } else {
|
|
|
|
|
+ // Managed axis
|
|
|
|
|
+ for (int axisIndex = 0; axisIndex <= GLFW_GAMEPAD_AXIS_LAST; axisIndex++) {
|
|
|
|
|
+ String logicalId = remapAxisToJme(axisIndex);
|
|
|
|
|
+ if (logicalId == null) continue;
|
|
|
|
|
+ String axisName = logicalId; // no need to remap with JoystickCompatibilityMappings as
|
|
|
|
|
+ // glfw already handles remapping
|
|
|
|
|
+ JoystickAxis axis = new DefaultJoystickAxis(inputManager, joystick, axisIndex,
|
|
|
|
|
+ axisName, logicalId, true, false, 0.0f);
|
|
|
|
|
+ joystick.addAxis(axisIndex, axis);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // Virtual POV axes for D-pad.
|
|
|
|
|
+ JoystickAxis povX = new DefaultJoystickAxis(inputManager, joystick, POV_X_AXIS_ID,
|
|
|
|
|
+ JoystickAxis.POV_X, JoystickAxis.POV_X, true, false, 0.0f);
|
|
|
|
|
+ joystick.addAxis(POV_X_AXIS_ID, povX);
|
|
|
|
|
+
|
|
|
|
|
+ JoystickAxis povY = new DefaultJoystickAxis(inputManager, joystick, POV_Y_AXIS_ID,
|
|
|
|
|
+ JoystickAxis.POV_Y, JoystickAxis.POV_Y, true, false, 0.0f);
|
|
|
|
|
+ joystick.addAxis(POV_Y_AXIS_ID, povY);
|
|
|
|
|
+
|
|
|
|
|
+ // managed buttons
|
|
|
|
|
+ for (int buttonIndex = 0; buttonIndex <= GLFW_GAMEPAD_BUTTON_LAST; buttonIndex++) {
|
|
|
|
|
+ String logicalId = remapButtonToJme(buttonIndex);
|
|
|
|
|
+ if (logicalId == null) continue;
|
|
|
|
|
+ String buttonName = logicalId;
|
|
|
|
|
+ JoystickButton button = new DefaultJoystickButton(inputManager, joystick, buttonIndex,
|
|
|
|
|
+ buttonName, logicalId);
|
|
|
joystick.addButton(button);
|
|
joystick.addButton(button);
|
|
|
joyButtonPressed.put(button, false);
|
|
joyButtonPressed.put(button, false);
|
|
|
- buttonIndex++;
|
|
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
return joysticks.values().toArray(new GlfwJoystick[joysticks.size()]);
|
|
return joysticks.values().toArray(new GlfwJoystick[joysticks.size()]);
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
- private String convertAxisIndex(final int index) {
|
|
|
|
|
|
|
+
|
|
|
|
|
+ private String convertAxisIndex(int index) {
|
|
|
if (index == 0) {
|
|
if (index == 0) {
|
|
|
return "pov_x";
|
|
return "pov_x";
|
|
|
} else if (index == 1) {
|
|
} else if (index == 1) {
|
|
@@ -136,52 +223,194 @@ public class GlfwJoystickInput implements JoyInput {
|
|
|
} else if (index == 3) {
|
|
} else if (index == 3) {
|
|
|
return "rz";
|
|
return "rz";
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
return String.valueOf(index);
|
|
return String.valueOf(index);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- @Override
|
|
|
|
|
- public void initialize() {
|
|
|
|
|
- initialized = true;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
@Override
|
|
@Override
|
|
|
public void update() {
|
|
public void update() {
|
|
|
float rawValue, value;
|
|
float rawValue, value;
|
|
|
- for (final Map.Entry<Integer, GlfwJoystick> entry : joysticks.entrySet()) {
|
|
|
|
|
|
|
+ for (Map.Entry<Integer, GlfwJoystick> entry : joysticks.entrySet()) {
|
|
|
|
|
+ if (!glfwJoystickPresent(entry.getKey())) continue;
|
|
|
|
|
+ if (!entry.getValue().isGlfwGamepad()) {
|
|
|
|
|
+
|
|
|
|
|
+ // Axes
|
|
|
|
|
+ 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 (JoystickAxis axis : entry.getValue().getAxes()) {
|
|
|
|
|
+ rawValue = axisValues.get(axis.getAxisId());
|
|
|
|
|
+ value = JoystickCompatibilityMappings.remapAxisRange(axis, rawValue);
|
|
|
|
|
+ // listener.onJoyAxisEvent(new JoyAxisEvent(axis, value, rawValue));
|
|
|
|
|
+ updateAxis(axis, value, rawValue);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // Buttons
|
|
|
|
|
+ ByteBuffer byteBuffer = glfwGetJoystickButtons(entry.getKey());
|
|
|
|
|
|
|
|
- // Axes
|
|
|
|
|
- final FloatBuffer axisValues = glfwGetJoystickAxes(entry.getKey());
|
|
|
|
|
|
|
+ if (byteBuffer != null) {
|
|
|
|
|
+ for (JoystickButton button : entry.getValue().getButtons()) {
|
|
|
|
|
+ boolean pressed = byteBuffer.get(button.getButtonId()) == GLFW_PRESS;
|
|
|
|
|
+ updateButton(button, pressed);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ } else {
|
|
|
|
|
+ if (!glfwGetGamepadState(entry.getKey(), gamepadState)) return;
|
|
|
|
|
+ Joystick joystick = entry.getValue();
|
|
|
|
|
|
|
|
- // 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.
|
|
|
|
|
|
|
+ FloatBuffer axes = gamepadState.axes();
|
|
|
|
|
|
|
|
- if (axisValues != null) {
|
|
|
|
|
- for (final JoystickAxis axis : entry.getValue().getAxes()) {
|
|
|
|
|
- rawValue = axisValues.get(axis.getAxisId());
|
|
|
|
|
- value = JoystickCompatibilityMappings.remapAxisRange(axis, rawValue);
|
|
|
|
|
- listener.onJoyAxisEvent(new JoyAxisEvent(axis, value, rawValue));
|
|
|
|
|
|
|
+ // handle axes (skip virtual POV axes)
|
|
|
|
|
+ for (JoystickAxis axis : entry.getValue().getAxes()) {
|
|
|
|
|
+ int axisId = axis.getAxisId();
|
|
|
|
|
+ if (axisId == POV_X_AXIS_ID || axisId == POV_Y_AXIS_ID) continue;
|
|
|
|
|
+ if (axisId < 0 || axisId > GLFW_GAMEPAD_AXIS_LAST) continue;
|
|
|
|
|
+
|
|
|
|
|
+ rawValue = axes.get(axisId);
|
|
|
|
|
+ rawValue = remapAxisValueToJme(axisId, rawValue);
|
|
|
|
|
+ value = rawValue; // scaling handled by GLFW
|
|
|
|
|
+
|
|
|
|
|
+ updateAxis(axis, value, rawValue);
|
|
|
}
|
|
}
|
|
|
- }
|
|
|
|
|
|
|
|
|
|
- // Buttons
|
|
|
|
|
- final ByteBuffer byteBuffer = glfwGetJoystickButtons(entry.getKey());
|
|
|
|
|
|
|
+ // virtual trigger buttons
|
|
|
|
|
+ if (virtualTriggerThreshold > 0.0f) {
|
|
|
|
|
+ float leftTrigger = remapAxisValueToJme(GLFW_GAMEPAD_AXIS_LEFT_TRIGGER,
|
|
|
|
|
+ axes.get(GLFW_GAMEPAD_AXIS_LEFT_TRIGGER));
|
|
|
|
|
+ float rightTrigger = remapAxisValueToJme(GLFW_GAMEPAD_AXIS_RIGHT_TRIGGER,
|
|
|
|
|
+ axes.get(GLFW_GAMEPAD_AXIS_RIGHT_TRIGGER));
|
|
|
|
|
+ updateButton(joystick.getButton(JoystickButton.BUTTON_XBOX_LT),
|
|
|
|
|
+ leftTrigger > virtualTriggerThreshold);
|
|
|
|
|
+ updateButton(joystick.getButton(JoystickButton.BUTTON_XBOX_RT),
|
|
|
|
|
+ rightTrigger > virtualTriggerThreshold);
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- if (byteBuffer != null) {
|
|
|
|
|
- for (final JoystickButton button : entry.getValue().getButtons()) {
|
|
|
|
|
- final boolean pressed = byteBuffer.get(button.getButtonId()) == GLFW_PRESS;
|
|
|
|
|
|
|
+ ByteBuffer buttons = gamepadState.buttons();
|
|
|
|
|
+
|
|
|
|
|
+ for (int btnIndex = 0; btnIndex <= GLFW_GAMEPAD_BUTTON_LAST; btnIndex++) {
|
|
|
|
|
+ String jmeButtonIndex = remapButtonToJme(btnIndex);
|
|
|
|
|
+ if (jmeButtonIndex == null) continue;
|
|
|
|
|
|
|
|
- if (joyButtonPressed.get(button) != pressed) {
|
|
|
|
|
- joyButtonPressed.put(button, pressed);
|
|
|
|
|
- listener.onJoyButtonEvent(new JoyButtonEvent(button, pressed));
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ JoystickButton button = joystick.getButton(jmeButtonIndex);
|
|
|
|
|
+ if (button == null) continue;
|
|
|
|
|
+
|
|
|
|
|
+ boolean pressed = buttons.get(btnIndex) == GLFW_PRESS;
|
|
|
|
|
+ updateButton(button, pressed);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // D-pad to virtual POV axes
|
|
|
|
|
+ boolean dpadUp = buttons.get(GLFW_GAMEPAD_BUTTON_DPAD_UP) == GLFW_PRESS;
|
|
|
|
|
+ boolean dpadDown = buttons.get(GLFW_GAMEPAD_BUTTON_DPAD_DOWN) == GLFW_PRESS;
|
|
|
|
|
+ boolean dpadLeft = buttons.get(GLFW_GAMEPAD_BUTTON_DPAD_LEFT) == GLFW_PRESS;
|
|
|
|
|
+ boolean dpadRight = buttons.get(GLFW_GAMEPAD_BUTTON_DPAD_RIGHT) == GLFW_PRESS;
|
|
|
|
|
+
|
|
|
|
|
+ float povX = dpadLeft ? -1f : (dpadRight ? 1f : 0f);
|
|
|
|
|
+ float povY = dpadDown ? -1f : (dpadUp ? 1f : 0f);
|
|
|
|
|
+
|
|
|
|
|
+ JoystickAxis povXAxis = joystick.getPovXAxis();
|
|
|
|
|
+ if (povXAxis != null) {
|
|
|
|
|
+ updateAxis(povXAxis, povX, povX);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ JoystickAxis povYAxis = joystick.getPovYAxis();
|
|
|
|
|
+ if (povYAxis != null) {
|
|
|
|
|
+ updateAxis(povYAxis, povY, povY);
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ private String remapAxisToJme(int glfwAxisIndex) {
|
|
|
|
|
+ switch (glfwAxisIndex) {
|
|
|
|
|
+ case GLFW_GAMEPAD_AXIS_LEFT_X:
|
|
|
|
|
+ return JoystickAxis.AXIS_XBOX_LEFT_THUMB_STICK_X;
|
|
|
|
|
+ case GLFW_GAMEPAD_AXIS_LEFT_Y:
|
|
|
|
|
+ return JoystickAxis.AXIS_XBOX_LEFT_THUMB_STICK_Y;
|
|
|
|
|
+ case GLFW_GAMEPAD_AXIS_RIGHT_X:
|
|
|
|
|
+ return JoystickAxis.AXIS_XBOX_RIGHT_THUMB_STICK_X;
|
|
|
|
|
+ case GLFW_GAMEPAD_AXIS_RIGHT_Y:
|
|
|
|
|
+ return JoystickAxis.AXIS_XBOX_RIGHT_THUMB_STICK_Y;
|
|
|
|
|
+ case GLFW_GAMEPAD_AXIS_LEFT_TRIGGER:
|
|
|
|
|
+ return JoystickAxis.AXIS_XBOX_LEFT_TRIGGER;
|
|
|
|
|
+ case GLFW_GAMEPAD_AXIS_RIGHT_TRIGGER:
|
|
|
|
|
+ return JoystickAxis.AXIS_XBOX_RIGHT_TRIGGER;
|
|
|
|
|
+ default:
|
|
|
|
|
+ return null;
|
|
|
|
|
+
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private String remapButtonToJme(int glfwButtonIndex) {
|
|
|
|
|
+ switch (glfwButtonIndex) {
|
|
|
|
|
+ case GLFW_GAMEPAD_BUTTON_Y:
|
|
|
|
|
+ return JoystickButton.BUTTON_XBOX_Y;
|
|
|
|
|
+ case GLFW_GAMEPAD_BUTTON_B:
|
|
|
|
|
+ return JoystickButton.BUTTON_XBOX_B;
|
|
|
|
|
+ case GLFW_GAMEPAD_BUTTON_A:
|
|
|
|
|
+ return JoystickButton.BUTTON_XBOX_A;
|
|
|
|
|
+ case GLFW_GAMEPAD_BUTTON_X:
|
|
|
|
|
+ return JoystickButton.BUTTON_XBOX_X;
|
|
|
|
|
+ case GLFW_GAMEPAD_BUTTON_LEFT_BUMPER:
|
|
|
|
|
+ return JoystickButton.BUTTON_XBOX_LB;
|
|
|
|
|
+ case GLFW_GAMEPAD_BUTTON_RIGHT_BUMPER:
|
|
|
|
|
+ return JoystickButton.BUTTON_XBOX_RB;
|
|
|
|
|
+ case GLFW_GAMEPAD_BUTTON_BACK:
|
|
|
|
|
+ return JoystickButton.BUTTON_XBOX_BACK;
|
|
|
|
|
+ case GLFW_GAMEPAD_BUTTON_START:
|
|
|
|
|
+ return JoystickButton.BUTTON_XBOX_START;
|
|
|
|
|
+ case GLFW_GAMEPAD_BUTTON_LEFT_THUMB:
|
|
|
|
|
+ return JoystickButton.BUTTON_XBOX_L3;
|
|
|
|
|
+ case GLFW_GAMEPAD_BUTTON_RIGHT_THUMB:
|
|
|
|
|
+ return JoystickButton.BUTTON_XBOX_R3;
|
|
|
|
|
+ case GLFW_GAMEPAD_BUTTON_DPAD_UP:
|
|
|
|
|
+ return JoystickButton.BUTTON_XBOX_DPAD_UP;
|
|
|
|
|
+ case GLFW_GAMEPAD_BUTTON_DPAD_DOWN:
|
|
|
|
|
+ return JoystickButton.BUTTON_XBOX_DPAD_DOWN;
|
|
|
|
|
+ case GLFW_GAMEPAD_BUTTON_DPAD_LEFT:
|
|
|
|
|
+ return JoystickButton.BUTTON_XBOX_DPAD_LEFT;
|
|
|
|
|
+ case GLFW_GAMEPAD_BUTTON_DPAD_RIGHT:
|
|
|
|
|
+ return JoystickButton.BUTTON_XBOX_DPAD_RIGHT;
|
|
|
|
|
+ default:
|
|
|
|
|
+ return null;
|
|
|
|
|
+
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private static float remapAxisValueToJme(int axisId, float v) {
|
|
|
|
|
+ if (axisId == GLFW_GAMEPAD_AXIS_LEFT_TRIGGER || axisId == GLFW_GAMEPAD_AXIS_RIGHT_TRIGGER) {
|
|
|
|
|
+ if (v < -1f) v = -1f;
|
|
|
|
|
+ if (v > 1f) v = 1f;
|
|
|
|
|
+ return (v + 1f) * 0.5f;
|
|
|
|
|
+ }
|
|
|
|
|
+ return v;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private void updateButton(JoystickButton button, boolean pressed) {
|
|
|
|
|
+ if (button == null) return;
|
|
|
|
|
+ Boolean old = joyButtonPressed.get(button);
|
|
|
|
|
+ if (old == null || old != pressed) {
|
|
|
|
|
+ joyButtonPressed.put(button, pressed);
|
|
|
|
|
+ listener.onJoyButtonEvent(new JoyButtonEvent(button, pressed));
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private void updateAxis(JoystickAxis axis, float value, float rawValue) {
|
|
|
|
|
+ if (axis == null) return;
|
|
|
|
|
+ Float old = joyAxisValues.get(axis);
|
|
|
|
|
+ float jitter = FastMath.clamp(Math.max(axis.getJitterThreshold(), globalJitterThreshold), 0f, 1f);
|
|
|
|
|
+ if (old == null || FastMath.abs(old - value) > jitter) {
|
|
|
|
|
+ joyAxisValues.put(axis, value);
|
|
|
|
|
+ listener.onJoyAxisEvent(new JoyAxisEvent(axis, value, rawValue));
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
@Override
|
|
@Override
|
|
|
public void destroy() {
|
|
public void destroy() {
|
|
|
initialized = false;
|
|
initialized = false;
|
|
@@ -199,41 +428,71 @@ public class GlfwJoystickInput implements JoyInput {
|
|
|
|
|
|
|
|
@Override
|
|
@Override
|
|
|
public long getInputTimeNanos() {
|
|
public long getInputTimeNanos() {
|
|
|
- return 0;
|
|
|
|
|
|
|
+ return (long) (glfwGetTime() * 1000000000);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- protected class GlfwJoystick extends AbstractJoystick {
|
|
|
|
|
-
|
|
|
|
|
|
|
+ private static class GlfwJoystick extends AbstractJoystick {
|
|
|
|
|
+ private final boolean isGlfwGamepad;
|
|
|
|
|
+ private JoystickAxis xAxis;
|
|
|
|
|
+ private JoystickAxis yAxis;
|
|
|
private JoystickAxis povAxisX;
|
|
private JoystickAxis povAxisX;
|
|
|
private JoystickAxis povAxisY;
|
|
private JoystickAxis povAxisY;
|
|
|
|
|
|
|
|
- public GlfwJoystick(final InputManager inputManager, final JoyInput joyInput, final int joyId, final String name) {
|
|
|
|
|
|
|
+ public GlfwJoystick(InputManager inputManager, JoyInput joyInput, int joyId, String name,
|
|
|
|
|
+ boolean gamepad) {
|
|
|
super(inputManager, joyInput, joyId, name);
|
|
super(inputManager, joyInput, joyId, name);
|
|
|
|
|
+ this.isGlfwGamepad = gamepad;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- public void addAxis(final int index, final JoystickAxis axis) {
|
|
|
|
|
- super.addAxis(axis);
|
|
|
|
|
|
|
+ public boolean isGlfwGamepad() {
|
|
|
|
|
+ return isGlfwGamepad;
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- if (index == 0) {
|
|
|
|
|
- povAxisX = axis;
|
|
|
|
|
- } else if (index == 1) {
|
|
|
|
|
- povAxisY = axis;
|
|
|
|
|
|
|
+ public void addAxis(int index, JoystickAxis axis) {
|
|
|
|
|
+ super.addAxis(axis);
|
|
|
|
|
+ if (isGlfwGamepad) {
|
|
|
|
|
+ switch (index) {
|
|
|
|
|
+ case GLFW_GAMEPAD_AXIS_LEFT_X: {
|
|
|
|
|
+ xAxis = axis;
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+ case GLFW_GAMEPAD_AXIS_LEFT_Y: {
|
|
|
|
|
+ yAxis = axis;
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+ case POV_X_AXIS_ID: {
|
|
|
|
|
+ povAxisX = axis;
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+ case POV_Y_AXIS_ID: {
|
|
|
|
|
+ povAxisY = axis;
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ } else {
|
|
|
|
|
+ if (index == 0) {
|
|
|
|
|
+ xAxis = axis;
|
|
|
|
|
+ povAxisX = axis;
|
|
|
|
|
+ } else if (index == 1) {
|
|
|
|
|
+ yAxis = axis;
|
|
|
|
|
+ povAxisY = axis;
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
@Override
|
|
|
- protected void addButton(final JoystickButton button) {
|
|
|
|
|
|
|
+ protected void addButton(JoystickButton button) {
|
|
|
super.addButton(button);
|
|
super.addButton(button);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
@Override
|
|
|
public JoystickAxis getXAxis() {
|
|
public JoystickAxis getXAxis() {
|
|
|
- return povAxisX;
|
|
|
|
|
|
|
+ return xAxis;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
@Override
|
|
|
public JoystickAxis getYAxis() {
|
|
public JoystickAxis getYAxis() {
|
|
|
- return povAxisY;
|
|
|
|
|
|
|
+ return yAxis;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
@Override
|
|
@@ -248,12 +507,13 @@ public class GlfwJoystickInput implements JoyInput {
|
|
|
|
|
|
|
|
@Override
|
|
@Override
|
|
|
public int getXAxisIndex() {
|
|
public int getXAxisIndex() {
|
|
|
- return povAxisX.getAxisId();
|
|
|
|
|
|
|
+ return xAxis != null ? xAxis.getAxisId() : 0;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
@Override
|
|
|
public int getYAxisIndex() {
|
|
public int getYAxisIndex() {
|
|
|
- return povAxisY.getAxisId();
|
|
|
|
|
|
|
+ return yAxis != null ? yAxis.getAxisId() : 1;
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
}
|
|
}
|