diff --git a/jme3-core/src/main/java/com/jme3/input/JoystickAxis.java b/jme3-core/src/main/java/com/jme3/input/JoystickAxis.java index fbbddb9f06..c66e3ee8e1 100644 --- a/jme3-core/src/main/java/com/jme3/input/JoystickAxis.java +++ b/jme3-core/src/main/java/com/jme3/input/JoystickAxis.java @@ -44,27 +44,14 @@ public interface JoystickAxis { public static final String Z_ROTATION = "rz"; public static final String LEFT_TRIGGER = "rx"; public static final String RIGHT_TRIGGER = "ry"; - - // Note: the left/right trigger bit may be a bit controversial in - // the sense that this is one case where XBox controllers make a lot - // more sense. - // I've seen the following mappings for various things: - // - // Axis | XBox | Non-Xbox (generally) (includes actual Sony PS4 controllers) - // --------------+-------+--------------- - // left trigger | z | rx (also button 6) - // right trigger | rz | ry (also button 7) - // left stick x | x | x - // left stick y | y | y - // right stick x | rx | z - // right stick y | ry | rz - // - // The issue is that in all cases I've seen, the XBox controllers will - // use the name "xbox" somewhere in their name. The Non-XBox controllers - // never mention anything uniform... even the PS4 controller only calls - // itself "Wireless Controller". In that light, it seems easier to make - // the default the ugly case and the "XBox" way the exception because it - // can more easily be identified. + + public static final String AXIS_XBOX_LEFT_TRIGGER = LEFT_TRIGGER; + public static final String AXIS_XBOX_RIGHT_TRIGGER = RIGHT_TRIGGER; + public static final String AXIS_XBOX_LEFT_THUMB_STICK_X = X_AXIS; + public static final String AXIS_XBOX_LEFT_THUMB_STICK_Y = Y_AXIS; + public static final String AXIS_XBOX_RIGHT_THUMB_STICK_X = Z_AXIS; + public static final String AXIS_XBOX_RIGHT_THUMB_STICK_Y = Z_ROTATION; + public static final String POV_X = "pov_x"; public static final String POV_Y = "pov_y"; diff --git a/jme3-core/src/main/java/com/jme3/input/JoystickButton.java b/jme3-core/src/main/java/com/jme3/input/JoystickButton.java index 8d2336c18c..11c0155087 100644 --- a/jme3-core/src/main/java/com/jme3/input/JoystickButton.java +++ b/jme3-core/src/main/java/com/jme3/input/JoystickButton.java @@ -55,6 +55,26 @@ public interface JoystickButton { public static final String BUTTON_14 = "14"; public static final String BUTTON_15 = "15"; + + public static final String BUTTON_XBOX_A = BUTTON_2; + public static final String BUTTON_XBOX_B = BUTTON_1; + public static final String BUTTON_XBOX_X = BUTTON_3; + public static final String BUTTON_XBOX_Y = BUTTON_0; + public static final String BUTTON_XBOX_LB = BUTTON_4; + public static final String BUTTON_XBOX_RB = BUTTON_5; + public static final String BUTTON_XBOX_LT = BUTTON_6; + public static final String BUTTON_XBOX_RT = BUTTON_7; + public static final String BUTTON_XBOX_BACK = BUTTON_8; + public static final String BUTTON_XBOX_START = BUTTON_9; + public static final String BUTTON_XBOX_L3 = BUTTON_10; + public static final String BUTTON_XBOX_R3 = BUTTON_11; + + public static final String BUTTON_XBOX_DPAD_UP = BUTTON_12; + public static final String BUTTON_XBOX_DPAD_DOWN = BUTTON_13; + public static final String BUTTON_XBOX_DPAD_LEFT = BUTTON_14; + public static final String BUTTON_XBOX_DPAD_RIGHT = BUTTON_15; + + /** * Assign the mapping name to receive events from the given button index * on the joystick. diff --git a/jme3-core/src/main/java/com/jme3/system/AppSettings.java b/jme3-core/src/main/java/com/jme3/system/AppSettings.java index e159586f2f..a2b05b1e7e 100644 --- a/jme3-core/src/main/java/com/jme3/system/AppSettings.java +++ b/jme3-core/src/main/java/com/jme3/system/AppSettings.java @@ -300,6 +300,8 @@ public final class AppSettings extends HashMap { defaults.put("WindowYPosition", 0); defaults.put("WindowXPosition", 0); defaults.put("X11PlatformPreferred", false); + defaults.put("XboxLikeControllerLayout", true); + defaults.put("TriggerToButtonThreshold", 0.5f); // defaults.put("Icons", null); } @@ -1612,4 +1614,52 @@ public void setX11PlatformPreferred(boolean preferred) { public boolean isX11PlatformPreferred() { return getBoolean("X11PlatformPreferred"); } + + /** + * Enable/disable automatic normalization of gamepad mappings to an Xbox-like layout, + * when possible. + * + *

+ * Depending on the platform and controller model, this setting might have no effect. + * It is primarily intended to provide a consistent default button/axis layout across common + * controllers. + * + * @param enabled true to enable, false to disable (default: true) + */ + public void setXboxLikeControllerLayout(boolean enabled){ + putBoolean("XboxLikeControllerLayout", enabled); + } + + /** + * Whether automatic normalization of controller mappings to an Xbox-like layout is enabled. + * + * @return true if enabled, otherwise false + */ + public boolean isXboxLikeControllerLayout(){ + return getBoolean("XboxLikeControllerLayout"); + } + + /** + * Sets the threshold above which an analog trigger should also generate a button-press event. + * If the value is set to -1, the trigger will never generate button-press events. + * + *

+ * This is intended to normalize behavior between controllers that expose triggers as analog + * axes and controllers that expose triggers as digital buttons. + * + * @param threshold the trigger threshold in the range [0, 1] (default: 0.5f) + */ + public void setTriggerToButtonThreshold(float threshold) { + putFloat("TriggerToButtonThreshold", threshold); + } + + /** + * Gets the threshold above which an analog trigger should also generate a button-press event. + * + * @return the trigger threshold in the range [0, 1] (default: 0.5f) + * @see #setTriggerToButtonThreshold(float) + */ + public float getTriggerToButtonThreshold() { + return getFloat("TriggerToButtonThreshold"); + } } diff --git a/jme3-examples/src/main/java/jme3test/input/TestJoystick.java b/jme3-examples/src/main/java/jme3test/input/TestJoystick.java index 3f25532d50..f2520382d1 100644 --- a/jme3-examples/src/main/java/jme3test/input/TestJoystick.java +++ b/jme3-examples/src/main/java/jme3test/input/TestJoystick.java @@ -255,24 +255,24 @@ public GamepadView() { attachChild(rightStick); // A "standard" mapping... fits a majority of my game pads - addButton( JoystickButton.BUTTON_0, 371, 512 - 176, 42, 42 ); - addButton( JoystickButton.BUTTON_1, 407, 512 - 212, 42, 42 ); - addButton( JoystickButton.BUTTON_2, 371, 512 - 248, 42, 42 ); - addButton( JoystickButton.BUTTON_3, 334, 512 - 212, 42, 42 ); + addButton( JoystickButton.BUTTON_XBOX_Y, 371, 512 - 176, 42, 42 ); + addButton( JoystickButton.BUTTON_XBOX_B, 407, 512 - 212, 42, 42 ); + addButton( JoystickButton.BUTTON_XBOX_A, 371, 512 - 248, 42, 42 ); + addButton( JoystickButton.BUTTON_XBOX_X, 334, 512 - 212, 42, 42 ); // Front buttons Some of these have the top ones and the bottoms ones flipped. - addButton( JoystickButton.BUTTON_4, 67, 512 - 111, 95, 21 ); - addButton( JoystickButton.BUTTON_5, 348, 512 - 111, 95, 21 ); - addButton( JoystickButton.BUTTON_6, 67, 512 - 89, 95, 21 ); - addButton( JoystickButton.BUTTON_7, 348, 512 - 89, 95, 21 ); + addButton( JoystickButton.BUTTON_XBOX_LB, 67, 512 - 111, 95, 21 ); + addButton( JoystickButton.BUTTON_XBOX_RB, 348, 512 - 111, 95, 21 ); + addButton( JoystickButton.BUTTON_XBOX_LT, 67, 512 - 89, 95, 21 ); + addButton( JoystickButton.BUTTON_XBOX_RT, 348, 512 - 89, 95, 21 ); // Select and start buttons - addButton( JoystickButton.BUTTON_8, 206, 512 - 198, 48, 30 ); - addButton( JoystickButton.BUTTON_9, 262, 512 - 198, 48, 30 ); + addButton( JoystickButton.BUTTON_XBOX_BACK, 206, 512 - 198, 48, 30 ); + addButton( JoystickButton.BUTTON_XBOX_START, 262, 512 - 198, 48, 30 ); // Joystick push buttons - addButton( JoystickButton.BUTTON_10, 147, 512 - 300, 75, 70 ); - addButton( JoystickButton.BUTTON_11, 285, 512 - 300, 75, 70 ); + addButton( JoystickButton.BUTTON_XBOX_L3, 147, 512 - 300, 75, 70 ); + addButton( JoystickButton.BUTTON_XBOX_R3, 285, 512 - 300, 75, 70 ); // Fake button highlights for the POV axes // @@ -280,10 +280,14 @@ public GamepadView() { // -X +X // -Y // - addButton( "POV +Y", 96, 512 - 174, 40, 38 ); - addButton( "POV +X", 128, 512 - 208, 40, 38 ); - addButton( "POV -Y", 96, 512 - 239, 40, 38 ); - addButton( "POV -X", 65, 512 - 208, 40, 38 ); + // addButton( "POV +Y", 96, 512 - 174, 40, 38 ); + // addButton( "POV +X", 128, 512 - 208, 40, 38 ); + // addButton( "POV -Y", 96, 512 - 239, 40, 38 ); + // addButton( "POV -X", 65, 512 - 208, 40, 38 ); + addButton( JoystickButton.BUTTON_XBOX_DPAD_UP, 96, 512 - 174, 40, 38 ); + addButton( JoystickButton.BUTTON_XBOX_DPAD_RIGHT, 128, 512 - 208, 40, 38 ); + addButton( JoystickButton.BUTTON_XBOX_DPAD_DOWN, 96, 512 - 239, 40, 38 ); + addButton( JoystickButton.BUTTON_XBOX_DPAD_LEFT, 65, 512 - 208, 40, 38 ); resetPositions(); } @@ -296,21 +300,20 @@ private void addButton( String name, float x, float y, float width, float height public void setAxisValue( JoystickAxis axis, float value ) { - System.out.println( "Axis:" + axis.getName() + "(id:" + axis.getLogicalId() + ")=" + value ); - if( axis == axis.getJoystick().getXAxis() ) { + if( axis == axis.getJoystick().getAxis(JoystickAxis.AXIS_XBOX_LEFT_THUMB_STICK_X)){ setXAxis(value); - } else if( axis == axis.getJoystick().getYAxis() ) { + } else if( axis == axis.getJoystick().getAxis(JoystickAxis.AXIS_XBOX_LEFT_THUMB_STICK_Y)){ setYAxis(-value); - } else if( axis == axis.getJoystick().getAxis(JoystickAxis.Z_AXIS) ) { + } else if( axis == axis.getJoystick().getAxis(JoystickAxis.AXIS_XBOX_RIGHT_THUMB_STICK_X)) { // Note: in the above condition, we could check the axis name, but // I have at least one joystick that reports 2 "Z Axis" axes. // In this particular case, the first one is the right one so // a name based lookup will find the proper one. It's a problem // because the erroneous axis sends a constant stream of values. setZAxis(value); - } else if( axis == axis.getJoystick().getAxis(JoystickAxis.Z_ROTATION) ) { + } else if( axis == axis.getJoystick().getAxis(JoystickAxis.AXIS_XBOX_RIGHT_THUMB_STICK_Y) ) { setZRotation(-value); - } else if( axis == axis.getJoystick().getAxis(JoystickAxis.LEFT_TRIGGER) ) { + } else if( axis == axis.getJoystick().getAxis(JoystickAxis.AXIS_XBOX_LEFT_TRIGGER) ) { if( axis.getJoystick().getButton(JoystickButton.BUTTON_6) == null ) { // left/right triggers sometimes only show up as axes boolean pressed = value != 0; @@ -318,7 +321,7 @@ public void setAxisValue( JoystickAxis axis, float value ) { setButtonValue(JoystickButton.BUTTON_6, pressed); } } - } else if( axis == axis.getJoystick().getAxis(JoystickAxis.RIGHT_TRIGGER) ) { + } else if( axis == axis.getJoystick().getAxis(JoystickAxis.AXIS_XBOX_RIGHT_TRIGGER) ) { if( axis.getJoystick().getButton(JoystickButton.BUTTON_7) == null ) { // left/right triggers sometimes only show up as axes boolean pressed = value != 0; diff --git a/jme3-lwjgl3/src/main/java/com/jme3/input/lwjgl/GlfwJoystickInput.java b/jme3-lwjgl3/src/main/java/com/jme3/input/lwjgl/GlfwJoystickInput.java index 39f0fa6b5a..dc8eacad21 100644 --- a/jme3-lwjgl3/src/main/java/com/jme3/input/lwjgl/GlfwJoystickInput.java +++ b/jme3-lwjgl3/src/main/java/com/jme3/input/lwjgl/GlfwJoystickInput.java @@ -39,18 +39,22 @@ import java.util.HashMap; import java.util.Map; import java.util.logging.Logger; +import com.jme3.system.AppSettings; +import org.lwjgl.glfw.GLFWGamepadState; import static org.lwjgl.glfw.GLFW.*; /** * The LWJGL implementation of {@link JoyInput}. * - * @author Daniel Johansson (dannyjo) + * @author Daniel Johansson (dannyjo), Riccardo Balbo * @since 3.1 */ public class GlfwJoystickInput implements JoyInput { private static final Logger LOGGER = Logger.getLogger(GlfwJoystickInput.class.getName()); + private final AppSettings settings; + private RawInputListener listener; private final Map joysticks = new HashMap<>(); @@ -59,6 +63,16 @@ public class GlfwJoystickInput implements JoyInput { private boolean initialized = false; + private GLFWGamepadState gamepadState; + + private float virtualTriggerThreshold; + + private boolean xboxStyle; + + public GlfwJoystickInput(AppSettings settings) { + this.settings = settings; + } + @Override public void setJoyRumble(final int joyId, final float amount) { if (joyId >= joysticks.size()) { @@ -78,6 +92,7 @@ public void fireJoystickDisconnectedEvent(int jid) { public void reloadJoysticks() { joysticks.clear(); + joyButtonPressed.clear(); InputManager inputManager = (InputManager) listener; @@ -90,42 +105,84 @@ public Joystick[] loadJoysticks(final InputManager inputManager) { for (int i = 0; i < GLFW_JOYSTICK_LAST; i++) { if (glfwJoystickPresent(i)) { - final String name = glfwGetJoystickName(i); - final GlfwJoystick joystick = new GlfwJoystick(inputManager, this, i, name); + boolean isGlfwGamepad = xboxStyle && glfwJoystickIsGamepad(i); + final String name = isGlfwGamepad ? glfwGetGamepadName(i) : glfwGetJoystickName(i); + final GlfwJoystick joystick = new GlfwJoystick(inputManager, this, i, name, isGlfwGamepad); joysticks.put(i, joystick); - final FloatBuffer floatBuffer = glfwGetJoystickAxes(i); + if(!isGlfwGamepad){ + // RAW axis + final FloatBuffer floatBuffer = glfwGetJoystickAxes(i); + if (floatBuffer == null) continue; - int axisIndex = 0; - while (floatBuffer.hasRemaining()) { - floatBuffer.get(); + 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++; - } + 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++; + } - final ByteBuffer byteBuffer = glfwGetJoystickButtons(i); + // raw buttons + final ByteBuffer byteBuffer = glfwGetJoystickButtons(i); - if (byteBuffer != null) { - int buttonIndex = 0; - while (byteBuffer.hasRemaining()) { - byteBuffer.get(); + if (byteBuffer != null) { + int buttonIndex = 0; + while (byteBuffer.hasRemaining()) { + byteBuffer.get(); + + final String logicalId = JoystickCompatibilityMappings.remapButton(joystick.getName(), String.valueOf(buttonIndex)); + final JoystickButton button = new DefaultJoystickButton(inputManager, joystick, buttonIndex, String.valueOf(buttonIndex), logicalId); + joystick.addButton(button); + joyButtonPressed.put(button, false); + buttonIndex++; + } + } + } else { + // Managed axis + + final String[] axisNames = { + JoystickAxis.X_AXIS, // 0: LEFT_X + JoystickAxis.Y_AXIS, // 1: LEFT_Y + JoystickAxis.Z_AXIS, // 2: RIGHT_X + JoystickAxis.Z_ROTATION, // 3: RIGHT_Y + JoystickAxis.LEFT_TRIGGER, // 4: LEFT_TRIGGER + JoystickAxis.RIGHT_TRIGGER // 5: RIGHT_TRIGGER + }; + + for (int axisIndex = 0; axisIndex <= GLFW_GAMEPAD_AXIS_LAST; axisIndex++) { + final String axisName = axisNames[axisIndex]; + final String logicalId = axisName; // no need to remap with JoystickCompatibilityMappings + // as glfw already handles remapping + final JoystickAxis axis = new DefaultJoystickAxis(inputManager, joystick, axisIndex, axisName, logicalId, true, false, 0.0f); + joystick.addAxis(axisIndex, axis); + } + + // Virtual POV axes for D-pad. + final JoystickAxis povX = new DefaultJoystickAxis(inputManager, joystick, 6, JoystickAxis.POV_X, JoystickAxis.POV_X, true, false, 0.0f); + joystick.addAxis(6, povX); + + final JoystickAxis povY = new DefaultJoystickAxis(inputManager, joystick, 7, JoystickAxis.POV_Y, JoystickAxis.POV_Y, true, false, 0.0f); + joystick.addAxis(7, povY); - final String logicalId = JoystickCompatibilityMappings.remapButton(joystick.getName(), String.valueOf(buttonIndex)); - final JoystickButton button = new DefaultJoystickButton(inputManager, joystick, buttonIndex, String.valueOf(buttonIndex), logicalId); + // managed buttons + for (int j = 0; j <= 15; j++) { + final String logicalId = String.valueOf(j); + final String buttonName = logicalId; + final JoystickButton button = new DefaultJoystickButton(inputManager, joystick, j, buttonName, logicalId); joystick.addButton(button); joyButtonPressed.put(button, false); - buttonIndex++; } } + } } return joysticks.values().toArray(new GlfwJoystick[joysticks.size()]); } - + private String convertAxisIndex(final int index) { if (index == 0) { return "pov_x"; @@ -142,46 +199,164 @@ private String convertAxisIndex(final int index) { @Override public void initialize() { + gamepadState = GLFWGamepadState.create(); initialized = true; + virtualTriggerThreshold = settings.getTriggerToButtonThreshold(); + xboxStyle = settings.isXboxLikeControllerLayout(); } @Override public void update() { float rawValue, value; for (final Map.Entry entry : joysticks.entrySet()) { + if (!glfwJoystickPresent(entry.getKey())) continue; + if (!entry.getValue().isGlfwGamepad()) { + + // Axes + 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()) { + rawValue = axisValues.get(axis.getAxisId()); + value = JoystickCompatibilityMappings.remapAxisRange(axis, rawValue); + listener.onJoyAxisEvent(new JoyAxisEvent(axis, value, rawValue)); + } + } + + // Buttons + final ByteBuffer byteBuffer = glfwGetJoystickButtons(entry.getKey()); - // Axes - final FloatBuffer axisValues = glfwGetJoystickAxes(entry.getKey()); + if (byteBuffer != null) { + for (final JoystickButton button : entry.getValue().getButtons()) { + final 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. + final FloatBuffer axes = gamepadState.axes(); - if (axisValues != null) { + // handle axes (skip virtual POV axes 6 & 7) for (final JoystickAxis axis : entry.getValue().getAxes()) { - rawValue = axisValues.get(axis.getAxisId()); - value = JoystickCompatibilityMappings.remapAxisRange(axis, rawValue); + final int axisId = axis.getAxisId(); + if (axisId == 6 || axisId == 7) continue; + if (axisId < 0 || axisId > GLFW_GAMEPAD_AXIS_LAST) continue; + + rawValue = axes.get(axisId); + + if (axisId == GLFW_GAMEPAD_AXIS_LEFT_TRIGGER || axisId == GLFW_GAMEPAD_AXIS_RIGHT_TRIGGER) { + rawValue = remapAxisToJme(rawValue); + } + + value = rawValue; // scaling handled by GLFW listener.onJoyAxisEvent(new JoyAxisEvent(axis, value, rawValue)); } - } - // Buttons - final ByteBuffer byteBuffer = glfwGetJoystickButtons(entry.getKey()); - if (byteBuffer != null) { - for (final JoystickButton button : entry.getValue().getButtons()) { - final boolean pressed = byteBuffer.get(button.getButtonId()) == GLFW_PRESS; + // virtual trigger buttons + if (virtualTriggerThreshold > 0.0f) { + final float leftTrigger = remapAxisToJme(axes.get(GLFW_GAMEPAD_AXIS_LEFT_TRIGGER)); + final float rightTrigger = remapAxisToJme(axes.get(GLFW_GAMEPAD_AXIS_RIGHT_TRIGGER)); + updateButton(joystick.getButton(JoystickButton.BUTTON_6), leftTrigger > virtualTriggerThreshold); + updateButton(joystick.getButton(JoystickButton.BUTTON_7), rightTrigger > virtualTriggerThreshold); + } - if (joyButtonPressed.get(button) != pressed) { - joyButtonPressed.put(button, pressed); - listener.onJoyButtonEvent(new JoyButtonEvent(button, pressed)); + final ByteBuffer buttons = gamepadState.buttons(); + + + for( int btnIndex = 0; btnIndex <= GLFW_GAMEPAD_BUTTON_LAST; btnIndex++) { + int glfwButtonIndex = btnIndex; + boolean pressed = buttons.get(glfwButtonIndex) == GLFW_PRESS; + String jmeButtonIndex = remapButtonToJme(btnIndex); + if(jmeButtonIndex==null) continue; + JoystickButton button = joystick.getButton(jmeButtonIndex); + if (button != null) { + updateButton(button, pressed); } } + + // D-pad to virtual POV axes + final boolean dpadUp = buttons.get(GLFW_GAMEPAD_BUTTON_DPAD_UP) == GLFW_PRESS; + final boolean dpadDown = buttons.get(GLFW_GAMEPAD_BUTTON_DPAD_DOWN) == GLFW_PRESS; + final boolean dpadLeft = buttons.get(GLFW_GAMEPAD_BUTTON_DPAD_LEFT) == GLFW_PRESS; + final boolean dpadRight = buttons.get(GLFW_GAMEPAD_BUTTON_DPAD_RIGHT) == GLFW_PRESS; + + final float povX = dpadLeft ? -1f : (dpadRight ? 1f : 0f); + final float povY = dpadDown ? -1f : (dpadUp ? 1f : 0f); + + final JoystickAxis povXAxis = joystick.getPovXAxis(); + if (povXAxis != null) { + listener.onJoyAxisEvent(new JoyAxisEvent(povXAxis, povX, povX)); + } + + final JoystickAxis povYAxis = joystick.getPovYAxis(); + if (povYAxis != null) { + listener.onJoyAxisEvent(new JoyAxisEvent(povYAxis, povY, povY)); + } } } } + + + private static 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 remapAxisToJme(float v) { + if (v < -1f) v = -1f; + if (v > 1f) v = 1f; + return (v + 1f) * 0.5f; + } + + private void updateButton(final JoystickButton button, final boolean pressed) { + if (button == null) return; + final Boolean old = joyButtonPressed.get(button); + if (old == null || old != pressed) { + joyButtonPressed.put(button, pressed); + listener.onJoyButtonEvent(new JoyButtonEvent(button, pressed)); + } + } + @Override public void destroy() { initialized = false; @@ -203,21 +378,42 @@ public long getInputTimeNanos() { } protected class GlfwJoystick extends AbstractJoystick { - + private final boolean isGlfwGamepad; + private JoystickAxis xAxis; + private JoystickAxis yAxis; private JoystickAxis povAxisX; private JoystickAxis povAxisY; - public GlfwJoystick(final InputManager inputManager, final JoyInput joyInput, final int joyId, final String name) { + public GlfwJoystick(final InputManager inputManager, final JoyInput joyInput, final int joyId, final String name, final boolean gamepad) { super(inputManager, joyInput, joyId, name); + this.isGlfwGamepad = gamepad; + } + + public boolean isGlfwGamepad() { + return isGlfwGamepad; } public void addAxis(final int index, final JoystickAxis axis) { super.addAxis(axis); - if (index == 0) { - povAxisX = axis; - } else if (index == 1) { - povAxisY = axis; + if (isGlfwGamepad) { + if (index == GLFW_GAMEPAD_AXIS_LEFT_X) { + xAxis = axis; + } else if (index == GLFW_GAMEPAD_AXIS_LEFT_Y) { + yAxis = axis; + } else if (index == 6) { + povAxisX = axis; + } else if (index == 7) { + povAxisY = axis; + } + } else { + if (index == 0) { + xAxis = axis; + povAxisX = axis; + } else if (index == 1) { + yAxis = axis; + povAxisY = axis; + } } } @@ -228,12 +424,12 @@ protected void addButton(final JoystickButton button) { @Override public JoystickAxis getXAxis() { - return povAxisX; + return xAxis; } @Override public JoystickAxis getYAxis() { - return povAxisY; + return yAxis; } @Override @@ -248,12 +444,12 @@ public JoystickAxis getPovYAxis() { @Override public int getXAxisIndex() { - return povAxisX.getAxisId(); + return xAxis != null ? xAxis.getAxisId() : 0; } @Override public int getYAxisIndex() { - return povAxisY.getAxisId(); + return yAxis != null ? yAxis.getAxisId() : 1; } } } diff --git a/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglWindow.java b/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglWindow.java index 0cc59b07fc..4d0234a129 100644 --- a/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglWindow.java +++ b/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglWindow.java @@ -834,7 +834,7 @@ public void run() { @Override public JoyInput getJoyInput() { if (joyInput == null) { - joyInput = new GlfwJoystickInput(); + joyInput = new GlfwJoystickInput(settings); } return joyInput; } diff --git a/jme3-vr/src/main/java/com/jme3/system/lwjgl/LwjglWindowVR.java b/jme3-vr/src/main/java/com/jme3/system/lwjgl/LwjglWindowVR.java index 5c21cd6e92..d5ac213d92 100644 --- a/jme3-vr/src/main/java/com/jme3/system/lwjgl/LwjglWindowVR.java +++ b/jme3-vr/src/main/java/com/jme3/system/lwjgl/LwjglWindowVR.java @@ -478,7 +478,7 @@ public void run() { @Override public JoyInput getJoyInput() { if (joyInput == null) { - joyInput = new GlfwJoystickInput(); + joyInput = new GlfwJoystickInput(settings); } return joyInput; }