forked from Clones/Controlify
➕ Implement SDL controller identification when hid4java is unavailable (macOS ARM)
This commit is contained in:
@ -3,7 +3,6 @@ package dev.isxander.controlify;
|
||||
import com.mojang.blaze3d.Blaze3D;
|
||||
import dev.isxander.controlify.api.ControlifyApi;
|
||||
import dev.isxander.controlify.api.entrypoint.ControlifyEntrypoint;
|
||||
import dev.isxander.controlify.driver.SteamDeckDriver;
|
||||
import dev.isxander.controlify.gui.controllers.ControllerBindHandler;
|
||||
import dev.isxander.controlify.gui.screen.ControllerCarouselScreen;
|
||||
import dev.isxander.controlify.controller.Controller;
|
||||
@ -16,7 +15,7 @@ import dev.isxander.controlify.reacharound.ReachAroundHandler;
|
||||
import dev.isxander.controlify.reacharound.ReachAroundMode;
|
||||
import dev.isxander.controlify.screenop.ScreenProcessorProvider;
|
||||
import dev.isxander.controlify.config.ControlifyConfig;
|
||||
import dev.isxander.controlify.controller.hid.ControllerHIDService;
|
||||
import dev.isxander.controlify.hid.ControllerHIDService;
|
||||
import dev.isxander.controlify.api.event.ControlifyEvents;
|
||||
import dev.isxander.controlify.gui.guide.InGameButtonGuide;
|
||||
import dev.isxander.controlify.ingame.InGameInputHandler;
|
||||
|
@ -3,10 +3,11 @@ package dev.isxander.controlify;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import dev.isxander.controlify.controller.Controller;
|
||||
import dev.isxander.controlify.controller.gamepad.GamepadController;
|
||||
import dev.isxander.controlify.controller.hid.ControllerHIDService;
|
||||
import dev.isxander.controlify.hid.ControllerHIDService;
|
||||
import dev.isxander.controlify.controller.joystick.CompoundJoystickController;
|
||||
import dev.isxander.controlify.controller.joystick.SingleJoystickController;
|
||||
import dev.isxander.controlify.debug.DebugProperties;
|
||||
import dev.isxander.controlify.hid.HIDDevice;
|
||||
import dev.isxander.controlify.utils.DebugLog;
|
||||
import dev.isxander.controlify.utils.Log;
|
||||
import net.minecraft.CrashReport;
|
||||
@ -54,7 +55,7 @@ public final class ControllerManager {
|
||||
CrashReportCategory category = crashReport.addCategory("Controller Info");
|
||||
category.setDetail("Joystick ID", joystickId);
|
||||
category.setDetail("Controller identification", hidInfo.type());
|
||||
category.setDetail("HID path", hidInfo.hidDevice().map(HidDevice::getPath).orElse("N/A"));
|
||||
category.setDetail("HID path", hidInfo.hidDevice().map(HIDDevice::path).orElse("N/A"));
|
||||
category.setDetail("HID service status", Controlify.instance().controllerHIDService().isDisabled() ? "Disabled" : "Enabled");
|
||||
category.setDetail("GLFW name", Optional.ofNullable(GLFW.glfwGetJoystickName(joystickId)).orElse("N/A"));
|
||||
throw new ReportedException(crashReport);
|
||||
|
@ -6,7 +6,7 @@ import com.google.gson.JsonElement;
|
||||
import dev.isxander.controlify.Controlify;
|
||||
import dev.isxander.controlify.ControllerManager;
|
||||
import dev.isxander.controlify.bindings.ControllerBindings;
|
||||
import dev.isxander.controlify.controller.hid.ControllerHIDService;
|
||||
import dev.isxander.controlify.hid.ControllerHIDService;
|
||||
import dev.isxander.controlify.rumble.RumbleCapable;
|
||||
import dev.isxander.controlify.utils.Log;
|
||||
import org.apache.commons.lang3.SerializationUtils;
|
||||
|
@ -3,7 +3,7 @@ package dev.isxander.controlify.controller;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonElement;
|
||||
import dev.isxander.controlify.bindings.ControllerBindings;
|
||||
import dev.isxander.controlify.controller.hid.ControllerHIDService;
|
||||
import dev.isxander.controlify.hid.ControllerHIDService;
|
||||
import dev.isxander.controlify.rumble.RumbleCapable;
|
||||
import dev.isxander.controlify.rumble.RumbleManager;
|
||||
import dev.isxander.controlify.rumble.RumbleSource;
|
||||
|
@ -1,7 +1,7 @@
|
||||
package dev.isxander.controlify.controller;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import dev.isxander.controlify.controller.hid.HIDIdentifier;
|
||||
import dev.isxander.controlify.hid.HIDIdentifier;
|
||||
import dev.isxander.controlify.utils.Log;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
@ -4,7 +4,7 @@ import dev.isxander.controlify.Controlify;
|
||||
import dev.isxander.controlify.bindings.ControllerBindings;
|
||||
import dev.isxander.controlify.controller.AbstractController;
|
||||
import dev.isxander.controlify.controller.BatteryLevel;
|
||||
import dev.isxander.controlify.controller.hid.ControllerHIDService;
|
||||
import dev.isxander.controlify.hid.ControllerHIDService;
|
||||
import dev.isxander.controlify.debug.DebugProperties;
|
||||
import dev.isxander.controlify.driver.*;
|
||||
import dev.isxander.controlify.rumble.RumbleManager;
|
||||
@ -44,7 +44,7 @@ public class GamepadController extends AbstractController<GamepadState, GamepadC
|
||||
|
||||
this.defaultConfig = new GamepadConfig();
|
||||
this.config = new GamepadConfig();
|
||||
if (hidInfo.hidDevice().map(hid -> SteamDeckDriver.isSteamDeck(hid.getVendorId(), hid.getProductId())).orElse(false)) {
|
||||
if (hidInfo.hidDevice().map(hid -> SteamDeckDriver.isSteamDeck(hid.vendorID(), hid.productID())).orElse(false)) {
|
||||
this.defaultConfig.mixedInput = true;
|
||||
this.config.mixedInput = true;
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ import com.google.gson.Gson;
|
||||
import com.google.gson.JsonElement;
|
||||
import dev.isxander.controlify.bindings.ControllerBindings;
|
||||
import dev.isxander.controlify.controller.ControllerType;
|
||||
import dev.isxander.controlify.controller.hid.ControllerHIDService;
|
||||
import dev.isxander.controlify.hid.ControllerHIDService;
|
||||
import dev.isxander.controlify.controller.joystick.mapping.JoystickMapping;
|
||||
import dev.isxander.controlify.controller.joystick.mapping.RPJoystickMapping;
|
||||
import dev.isxander.controlify.rumble.RumbleCapable;
|
||||
|
@ -4,7 +4,7 @@ import com.google.gson.Gson;
|
||||
import com.google.gson.JsonElement;
|
||||
import dev.isxander.controlify.bindings.ControllerBindings;
|
||||
import dev.isxander.controlify.controller.AbstractController;
|
||||
import dev.isxander.controlify.controller.hid.ControllerHIDService;
|
||||
import dev.isxander.controlify.hid.ControllerHIDService;
|
||||
import dev.isxander.controlify.controller.joystick.mapping.RPJoystickMapping;
|
||||
import dev.isxander.controlify.controller.joystick.mapping.JoystickMapping;
|
||||
import dev.isxander.controlify.controller.sdl2.SDL2NativesManager;
|
||||
|
@ -130,7 +130,7 @@ public class SDL2NativesManager {
|
||||
return initialised;
|
||||
}
|
||||
|
||||
private record Target(Util.OS os, boolean is64Bit, boolean isARM) {
|
||||
public record Target(Util.OS os, boolean is64Bit, boolean isARM) {
|
||||
public static final Target CURRENT = Util.make(() -> {
|
||||
Util.OS os = Util.getPlatform();
|
||||
|
||||
@ -155,5 +155,9 @@ public class SDL2NativesManager {
|
||||
.resolve("controlify-natives")
|
||||
.resolve(getArtifactName());
|
||||
}
|
||||
|
||||
public boolean isMacArm() {
|
||||
return os == Util.OS.OSX && isARM;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,8 +3,8 @@ package dev.isxander.controlify.driver;
|
||||
import com.google.common.collect.Sets;
|
||||
import dev.isxander.controlify.controller.sdl2.SDL2NativesManager;
|
||||
import dev.isxander.controlify.debug.DebugProperties;
|
||||
import dev.isxander.controlify.hid.HIDDevice;
|
||||
import dev.isxander.controlify.utils.Log;
|
||||
import org.hid4java.HidDevice;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
@ -28,7 +28,7 @@ public record GamepadDrivers(BasicGamepadInputDriver basicGamepadInputDriver, Gy
|
||||
}
|
||||
}
|
||||
|
||||
public static GamepadDrivers forController(int jid, Optional<HidDevice> hid) {
|
||||
public static GamepadDrivers forController(int jid, Optional<HIDDevice> hid) {
|
||||
GLFWGamepadDriver glfwDriver = new GLFWGamepadDriver(jid);
|
||||
|
||||
BasicGamepadInputDriver basicGamepadInputDriver = glfwDriver;
|
||||
@ -50,7 +50,7 @@ public record GamepadDrivers(BasicGamepadInputDriver basicGamepadInputDriver, Gy
|
||||
}
|
||||
|
||||
// TODO: Fix Steam Deck driver
|
||||
if (hid.isPresent() && SteamDeckDriver.isSteamDeck(hid.get().getVendorId(), hid.get().getProductId()) && false) {
|
||||
if (hid.isPresent() && hid.get().supportsCommunication() && SteamDeckDriver.isSteamDeck(hid.get().vendorID(), hid.get().productID()) && false) {
|
||||
gyroDriver = new SteamDeckDriver(hid.get());
|
||||
}
|
||||
|
||||
|
@ -1,9 +1,8 @@
|
||||
package dev.isxander.controlify.driver;
|
||||
|
||||
import dev.isxander.controlify.controller.gamepad.GamepadState;
|
||||
import dev.isxander.controlify.controller.hid.HIDIdentifier;
|
||||
import dev.isxander.controlify.hid.HIDDevice;
|
||||
import dev.isxander.controlify.utils.Log;
|
||||
import org.hid4java.HidDevice;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
@ -12,16 +11,15 @@ public class SteamDeckDriver implements GyroDriver, BasicGamepadInputDriver {
|
||||
private static final int cByteposInput = 4; // Position in the raw hid data where HID data byte is
|
||||
private static final byte[] startMarker = new byte[] { 0x01, 0x00, 0x09, 0x40 }; // Beginning of every Steam deck HID frame
|
||||
|
||||
private final HidDevice hidDevice;
|
||||
private final HIDDevice hidDevice;
|
||||
private int interval = 0;
|
||||
|
||||
private GamepadState.GyroState gyroDelta = new GamepadState.GyroState();
|
||||
private BasicGamepadState basicGamepadState = new BasicGamepadState(GamepadState.AxesState.EMPTY, GamepadState.ButtonState.EMPTY);
|
||||
|
||||
public SteamDeckDriver(HidDevice hidDevice) {
|
||||
public SteamDeckDriver(HIDDevice hidDevice) {
|
||||
this.hidDevice = hidDevice;
|
||||
this.hidDevice.open();
|
||||
this.hidDevice.setNonBlocking(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -50,7 +48,7 @@ public class SteamDeckDriver implements GyroDriver, BasicGamepadInputDriver {
|
||||
}
|
||||
|
||||
private void keepAlive() {
|
||||
hidDevice.sendFeatureReport(new byte[0], (byte) 8);
|
||||
//hidDevice.sendFeatureReport(new byte[0], (byte) 8);
|
||||
}
|
||||
|
||||
private void readFrame(Frame frame) {
|
||||
|
@ -514,7 +514,7 @@ public class ControllerConfigScreenFactory {
|
||||
return opt;
|
||||
}));
|
||||
} else {
|
||||
boolean isSteamDeck = gamepad != null && gamepad.hidInfo().map(hid -> hid.hidDevice().map(d -> SteamDeckDriver.isSteamDeck(d.getVendorId(), d.getProductId())).orElse(false)).orElse(false);
|
||||
boolean isSteamDeck = gamepad != null && gamepad.hidInfo().map(hid -> hid.hidDevice().map(d -> SteamDeckDriver.isSteamDeck(d.vendorID(), d.productID())).orElse(false)).orElse(false);
|
||||
gyroGroup.option(LabelOption.create(Component.translatable(!isSteamDeck ? "controlify.gui.group.gyro.no_gyro.tooltip" : "controlify.gui.group.gyro.no_gyro_steamdeck.tooltip").withStyle(ChatFormatting.RED)));
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
package dev.isxander.controlify.gui.screen;
|
||||
|
||||
import dev.isxander.controlify.Controlify;
|
||||
import dev.isxander.controlify.controller.sdl2.SDL2NativesManager;
|
||||
import it.unimi.dsi.fastutil.booleans.BooleanConsumer;
|
||||
import net.minecraft.ChatFormatting;
|
||||
import net.minecraft.Util;
|
||||
@ -25,9 +26,9 @@ public class SDLOnboardingScreen extends ConfirmScreen {
|
||||
Util.make(() -> {
|
||||
var message = Component.translatable("controlify.sdl2_onboarding.message");
|
||||
|
||||
// if (Util.getPlatform() == Util.OS.OSX) {
|
||||
// message.append("\n").append(Component.translatable("controlify.sdl2_onboarding.message_mac").withStyle(ChatFormatting.RED));
|
||||
// }
|
||||
if (SDL2NativesManager.Target.CURRENT.isMacArm()) {
|
||||
message.append("\n").append(Component.translatable("controlify.sdl2_onboarding.message_mac").withStyle(ChatFormatting.RED));
|
||||
}
|
||||
|
||||
message.append("\n\n").append(Component.translatable("controlify.sdl2_onboarding.question"));
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
package dev.isxander.controlify.controller.hid;
|
||||
package dev.isxander.controlify.hid;
|
||||
|
||||
import com.mojang.datafixers.util.Pair;
|
||||
import dev.isxander.controlify.Controlify;
|
||||
@ -8,6 +8,8 @@ import dev.isxander.controlify.utils.Log;
|
||||
import dev.isxander.controlify.utils.ToastUtils;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import org.hid4java.*;
|
||||
import org.libsdl.SDL;
|
||||
import org.lwjgl.glfw.GLFW;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ArrayBlockingQueue;
|
||||
@ -58,16 +60,18 @@ public class ControllerHIDService {
|
||||
}
|
||||
}
|
||||
|
||||
// if (SDL2NativesManager.isLoaded()) {
|
||||
// int vid = SDL.SDL_JoystickGetDeviceVendor(jid);
|
||||
// int pid = SDL.SDL_JoystickGetDeviceProduct(jid);
|
||||
//
|
||||
// if (vid != 0 && pid != 0) {
|
||||
// return new ControllerHIDInfo(ControllerType.getTypeForHID(new HIDIdentifier(vid, pid)), Optional.empty());
|
||||
// }
|
||||
// }
|
||||
|
||||
if (disabled) {
|
||||
if (SDL2NativesManager.isLoaded()) {
|
||||
int vid = SDL.SDL_JoystickGetDeviceVendor(jid);
|
||||
int pid = SDL.SDL_JoystickGetDeviceProduct(jid);
|
||||
String path = GLFW.glfwGetJoystickGUID(jid);
|
||||
|
||||
if (vid != 0 && pid != 0) {
|
||||
Log.LOGGER.info("Using SDL to identify controller type.");
|
||||
return new ControllerHIDInfo(ControllerType.getTypeForHID(new HIDIdentifier(vid, pid)), Optional.of(new HIDDevice.IDOnly(vid, pid, path)));
|
||||
}
|
||||
}
|
||||
|
||||
return new ControllerHIDInfo(ControllerType.UNKNOWN, Optional.empty());
|
||||
}
|
||||
|
||||
@ -85,7 +89,7 @@ public class ControllerHIDService {
|
||||
|
||||
unconsumedControllerHIDs.removeIf(h -> hid.getFirst().getPath().equals(h.getFirst().getPath()));
|
||||
|
||||
return new ControllerHIDInfo(type, Optional.of(hid.getFirst()));
|
||||
return new ControllerHIDInfo(type, Optional.of(new HIDDevice.Hid4Java(hid.getFirst())));
|
||||
}
|
||||
|
||||
public boolean isDisabled() {
|
||||
@ -133,7 +137,7 @@ public class ControllerHIDService {
|
||||
}
|
||||
|
||||
public void unconsumeController(ControllerHIDInfo hid) {
|
||||
hid.hidDevice.ifPresent(device -> attachedDevices.remove(device.getPath()));
|
||||
hid.hidDevice.ifPresent(device -> attachedDevices.remove(device.path()));
|
||||
}
|
||||
|
||||
private boolean isController(HidDevice device) {
|
||||
@ -144,9 +148,9 @@ public class ControllerHIDService {
|
||||
return isControllerType || (isGenericDesktopControlOrGameControl && isSelfIdentifiedController);
|
||||
}
|
||||
|
||||
public record ControllerHIDInfo(ControllerType type, Optional<HidDevice> hidDevice) {
|
||||
public record ControllerHIDInfo(ControllerType type, Optional<HIDDevice> hidDevice) {
|
||||
public Optional<String> createControllerUID() {
|
||||
return hidDevice.map(HidDevice::getPath).map(p -> UUID.nameUUIDFromBytes(p.getBytes())).map(UUID::toString);
|
||||
return hidDevice.map(HIDDevice::path).map(p -> UUID.nameUUIDFromBytes(p.getBytes())).map(UUID::toString);
|
||||
}
|
||||
}
|
||||
}
|
91
src/main/java/dev/isxander/controlify/hid/HIDDevice.java
Normal file
91
src/main/java/dev/isxander/controlify/hid/HIDDevice.java
Normal file
@ -0,0 +1,91 @@
|
||||
package dev.isxander.controlify.hid;
|
||||
|
||||
public sealed interface HIDDevice permits HIDDevice.Hid4Java, HIDDevice.IDOnly {
|
||||
int vendorID();
|
||||
|
||||
int productID();
|
||||
|
||||
String path();
|
||||
|
||||
boolean supportsCommunication();
|
||||
void open();
|
||||
void close();
|
||||
int read(byte[] buffer);
|
||||
int write(byte[] buffer, int packetLength, byte reportId);
|
||||
|
||||
final class Hid4Java implements HIDDevice {
|
||||
private final org.hid4java.HidDevice hidDevice;
|
||||
|
||||
public Hid4Java(org.hid4java.HidDevice hidDevice) {
|
||||
this.hidDevice = hidDevice;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int vendorID() {
|
||||
return hidDevice.getVendorId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int productID() {
|
||||
return hidDevice.getProductId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String path() {
|
||||
return hidDevice.getPath();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsCommunication() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void open() {
|
||||
hidDevice.open();
|
||||
hidDevice.setNonBlocking(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
hidDevice.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read(byte[] buffer) {
|
||||
return hidDevice.read(buffer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int write(byte[] buffer, int packetLength, byte reportId) {
|
||||
return hidDevice.write(buffer, packetLength, reportId);
|
||||
}
|
||||
}
|
||||
|
||||
record IDOnly(int vendorID, int productID, String path) implements HIDDevice {
|
||||
@Override
|
||||
public boolean supportsCommunication() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void open() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read(byte[] buffer) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int write(byte[] buffer, int packetLength, byte reportId) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package dev.isxander.controlify.controller.hid;
|
||||
package dev.isxander.controlify.hid;
|
||||
|
||||
public record HIDIdentifier(int vendorId, int productId) {
|
||||
}
|
Reference in New Issue
Block a user