1
0
forked from Clones/Controlify

joystick support

This commit is contained in:
isXander
2023-02-16 12:25:55 +00:00
parent 1b5c9daf94
commit 5a1504df76
134 changed files with 2296 additions and 820 deletions

View File

@ -1,193 +1,127 @@
package dev.isxander.controlify.controller;
import dev.isxander.controlify.Controlify;
import com.google.gson.Gson;
import com.google.gson.JsonElement;
import dev.isxander.controlify.bindings.ControllerBindings;
import dev.isxander.controlify.controller.hid.HIDIdentifier;
import dev.isxander.controlify.controller.gamepad.GamepadController;
import dev.isxander.controlify.controller.joystick.JoystickController;
import org.hid4java.HidDevice;
import org.jetbrains.annotations.Nullable;
import org.lwjgl.glfw.GLFW;
import org.lwjgl.glfw.GLFWGamepadState;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.UUID;
public final class Controller {
public static final Map<Integer, Controller> CONTROLLERS = new HashMap<>();
public static final Controller DUMMY = new Controller(-1, "DUMMY", "DUMMY", false, UUID.randomUUID().toString(), ControllerType.UNKNOWN);
public interface Controller<S extends ControllerState, C extends ControllerConfig> {
String uid();
int joystickId();
String guid();
private final int joystickId;
private final String guid;
private final String name;
private final boolean gamepad;
private final String uid;
private final ControllerType type;
ControllerBindings<S> bindings();
private ControllerState state = ControllerState.EMPTY;
private ControllerState prevState = ControllerState.EMPTY;
S state();
S prevState();
private final ControllerBindings bindings = new ControllerBindings(this);
private ControllerConfig config, defaultConfig;
C config();
C defaultConfig();
void setConfig(Gson gson, JsonElement json);
public Controller(int joystickId, String guid, String name, boolean gamepad, String uid, ControllerType type) {
this.joystickId = joystickId;
this.guid = guid;
this.name = name;
this.gamepad = gamepad;
this.uid = uid;
this.type = type;
this.config = new ControllerConfig();
this.defaultConfig = new ControllerConfig();
}
ControllerType type();
public ControllerState state() {
return state;
}
String name();
public ControllerState prevState() {
return prevState;
}
void updateState();
public void updateState() {
if (!connected()) {
state = prevState = ControllerState.EMPTY;
return;
Map<Integer, Controller<?, ?>> CONTROLLERS = new HashMap<>();
static Controller<?, ?> createOrGet(int joystickId, @Nullable HidDevice device) {
if (CONTROLLERS.containsKey(joystickId)) {
return CONTROLLERS.get(joystickId);
}
prevState = state;
AxesState rawAxesState = AxesState.fromController(this);
AxesState axesState = rawAxesState
.leftJoystickDeadZone(config().leftStickDeadzone, config().leftStickDeadzone)
.rightJoystickDeadZone(config().rightStickDeadzone, config().rightStickDeadzone)
.leftTriggerDeadZone(config().leftTriggerDeadzone)
.rightTriggerDeadZone(config().rightTriggerDeadzone);
ButtonState buttonState = ButtonState.fromController(this);
state = new ControllerState(axesState, rawAxesState, buttonState);
}
public void consumeButtonState() {
this.state = new ControllerState(state().axes(), state().rawAxes(), ButtonState.EMPTY);
}
public ControllerBindings bindings() {
return bindings;
}
public boolean connected() {
return GLFW.glfwJoystickPresent(joystickId);
}
GLFWGamepadState getGamepadState() {
GLFWGamepadState state = GLFWGamepadState.create();
if (gamepad)
GLFW.glfwGetGamepadState(joystickId, state);
return state;
}
public int id() {
return joystickId;
}
public String guid() {
return guid;
}
public String uid() {
return uid;
}
public ControllerType type() {
return type;
}
public String name() {
if (config().customName != null)
return config().customName;
return name;
}
public boolean gamepad() {
return gamepad;
}
public ControllerConfig config() {
return config;
}
public ControllerConfig defaultConfig() {
return defaultConfig;
}
public void setConfig(ControllerConfig config) {
this.config = config;
}
@Override
public boolean equals(Object obj) {
if (obj == this) return true;
if (obj == null || obj.getClass() != this.getClass()) return false;
var that = (Controller) obj;
return Objects.equals(this.guid, that.guid);
}
@Override
public int hashCode() {
return Objects.hash(guid);
}
public static Controller create(int id, @Nullable HidDevice device) {
if (id > GLFW.GLFW_JOYSTICK_LAST)
throw new IllegalArgumentException("Invalid joystick id: " + id);
if (CONTROLLERS.containsKey(id))
return CONTROLLERS.get(id);
String guid = GLFW.glfwGetJoystickGUID(id);
boolean gamepad = GLFW.glfwJoystickIsGamepad(id);
String fallbackName = gamepad ? GLFW.glfwGetGamepadName(id) : GLFW.glfwGetJoystickName(id);
String uid = device != null ? UUID.nameUUIDFromBytes(device.getPath().getBytes(StandardCharsets.UTF_8)).toString() : "unidentified-" + UUID.randomUUID();
ControllerType type = device != null ? ControllerType.getTypeForHID(new HIDIdentifier(device.getVendorId(), device.getProductId())) : ControllerType.UNKNOWN;
String ogName = type != ControllerType.UNKNOWN || fallbackName == null ? type.friendlyName() : fallbackName;
String name = ogName;
int tries = 1;
while (CONTROLLERS.values().stream().map(Controller::name).anyMatch(name::equals)) {
name = ogName + " (" + tries++ + ")";
if (GLFW.glfwJoystickIsGamepad(joystickId)) {
GamepadController controller = new GamepadController(joystickId, device);
CONTROLLERS.put(joystickId, controller);
return controller;
}
Controller controller = new Controller(id, guid, name, gamepad, uid, type);
CONTROLLERS.put(id, controller);
JoystickController controller = new JoystickController(joystickId, device);
CONTROLLERS.put(joystickId, controller);
return controller;
}
public class ControllerConfig {
public float horizontalLookSensitivity = 1f;
public float verticalLookSensitivity = 0.9f;
Controller<?, ?> DUMMY = new Controller<>() {
private final ControllerBindings<ControllerState> bindings = new ControllerBindings<>(this);
private final ControllerConfig config = new ControllerConfig() {
@Override
public void setDeadzone(int axis, float deadzone) {
public float leftStickDeadzone = 0.2f;
public float rightStickDeadzone = 0.2f;
}
// not sure if triggers need deadzones
public float leftTriggerDeadzone = 0.0f;
public float rightTriggerDeadzone = 0.0f;
@Override
public float getDeadzone(int axis) {
return 0;
}
};
public float buttonActivationThreshold = 0.5f;
@Override
public String uid() {
return "DUMMY";
}
public int screenRepeatNavigationDelay = 4;
@Override
public int joystickId() {
return -1;
}
public float virtualMouseSensitivity = 1f;
@Override
public String guid() {
return "DUMMY";
}
public ControllerTheme theme = type().theme();
@Override
public ControllerBindings<ControllerState> bindings() {
return bindings;
}
public boolean autoJump = false;
public boolean toggleSprint = true;
public boolean toggleSneak = true;
@Override
public ControllerConfig config() {
return config;
}
public String customName = null;
@Override
public ControllerConfig defaultConfig() {
return config;
}
public boolean showGuide = true;
}
@Override
public void setConfig(Gson gson, JsonElement json) {
}
@Override
public ControllerType type() {
return ControllerType.UNKNOWN;
}
@Override
public String name() {
return "DUMMY";
}
@Override
public ControllerState state() {
return ControllerState.EMPTY;
}
@Override
public ControllerState prevState() {
return ControllerState.EMPTY;
}
@Override
public void updateState() {
}
};
}