forked from Clones/Controlify
better HID service failure handling
This commit is contained in:
@ -150,6 +150,10 @@ public class Controlify {
|
||||
return virtualMouseHandler;
|
||||
}
|
||||
|
||||
public ControllerHIDService controllerHIDService() {
|
||||
return controllerHIDService;
|
||||
}
|
||||
|
||||
public InputMode currentInputMode() {
|
||||
return currentInputMode;
|
||||
}
|
||||
|
@ -58,7 +58,7 @@ public class ControlifyConfig {
|
||||
|
||||
for (var controller : Controller.CONTROLLERS.values()) {
|
||||
// `add` replaces if already existing
|
||||
newControllerData.add(controller.uid().toString(), generateControllerConfig(controller));
|
||||
newControllerData.add(controller.uid(), generateControllerConfig(controller));
|
||||
}
|
||||
|
||||
controllerData = newControllerData;
|
||||
@ -92,7 +92,7 @@ public class ControlifyConfig {
|
||||
}
|
||||
|
||||
public void loadOrCreateControllerData(Controller controller) {
|
||||
var uid = controller.uid().toString();
|
||||
var uid = controller.uid();
|
||||
if (controllerData.has(uid)) {
|
||||
applyControllerConfig(controller, controllerData.getAsJsonObject(uid));
|
||||
} else {
|
||||
|
@ -2,8 +2,8 @@ package dev.isxander.controlify.controller;
|
||||
|
||||
import dev.isxander.controlify.bindings.ControllerBindings;
|
||||
import dev.isxander.controlify.controller.hid.HIDIdentifier;
|
||||
import dev.isxander.controlify.event.ControlifyEvents;
|
||||
import org.hid4java.HidDevice;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.lwjgl.glfw.GLFW;
|
||||
import org.lwjgl.glfw.GLFWGamepadState;
|
||||
|
||||
@ -15,13 +15,13 @@ 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(), ControllerType.UNKNOWN);
|
||||
public static final Controller DUMMY = new Controller(-1, "DUMMY", "DUMMY", false, UUID.randomUUID().toString(), ControllerType.UNKNOWN);
|
||||
|
||||
private final int joystickId;
|
||||
private final String guid;
|
||||
private final String name;
|
||||
private final boolean gamepad;
|
||||
private final UUID uid;
|
||||
private final String uid;
|
||||
private final ControllerType type;
|
||||
|
||||
private ControllerState state = ControllerState.EMPTY;
|
||||
@ -30,7 +30,7 @@ public final class Controller {
|
||||
private final ControllerBindings bindings = new ControllerBindings(this);
|
||||
private ControllerConfig config, defaultConfig;
|
||||
|
||||
public Controller(int joystickId, String guid, String name, boolean gamepad, UUID uid, ControllerType type) {
|
||||
public Controller(int joystickId, String guid, String name, boolean gamepad, String uid, ControllerType type) {
|
||||
this.joystickId = joystickId;
|
||||
this.guid = guid;
|
||||
this.name = name;
|
||||
@ -93,7 +93,7 @@ public final class Controller {
|
||||
return guid;
|
||||
}
|
||||
|
||||
public UUID uid() {
|
||||
public String uid() {
|
||||
return uid;
|
||||
}
|
||||
|
||||
@ -136,7 +136,7 @@ public final class Controller {
|
||||
return Objects.hash(guid);
|
||||
}
|
||||
|
||||
public static Controller create(int id, HidDevice device) {
|
||||
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))
|
||||
@ -145,8 +145,8 @@ public final class Controller {
|
||||
String guid = GLFW.glfwGetJoystickGUID(id);
|
||||
boolean gamepad = GLFW.glfwJoystickIsGamepad(id);
|
||||
String fallbackName = gamepad ? GLFW.glfwGetGamepadName(id) : GLFW.glfwGetJoystickName(id);
|
||||
UUID uid = UUID.nameUUIDFromBytes(device.getPath().getBytes(StandardCharsets.UTF_8));
|
||||
ControllerType type = ControllerType.getTypeForHID(new HIDIdentifier(device.getVendorId(), device.getProductId()));
|
||||
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 name = type != ControllerType.UNKNOWN || fallbackName == null ? type.friendlyName() : fallbackName;
|
||||
int tries = 1;
|
||||
while (CONTROLLERS.values().stream().map(Controller::name).anyMatch(name::equals)) {
|
||||
|
@ -21,6 +21,8 @@ public class ControllerHIDService implements HidServicesListener {
|
||||
private final HidServicesSpecification specification;
|
||||
private final Queue<Consumer<HidDevice>> deviceQueue;
|
||||
|
||||
private boolean disabled = false;
|
||||
|
||||
public ControllerHIDService() {
|
||||
this.deviceQueue = new ArrayDeque<>();
|
||||
|
||||
@ -30,13 +32,23 @@ public class ControllerHIDService implements HidServicesListener {
|
||||
}
|
||||
|
||||
public void start() {
|
||||
var services = HidManager.getHidServices(specification);
|
||||
services.addHidServicesListener(this);
|
||||
try {
|
||||
var services = HidManager.getHidServices(specification);
|
||||
services.addHidServicesListener(this);
|
||||
|
||||
services.start();
|
||||
services.start();
|
||||
} catch (HidException e) {
|
||||
Controlify.LOGGER.error("Failed to start controller HID service!", e);
|
||||
disabled = true;
|
||||
}
|
||||
disabled = true;
|
||||
}
|
||||
|
||||
public void awaitNextController(Consumer<HidDevice> consumer) {
|
||||
if (disabled) {
|
||||
consumer.accept(null);
|
||||
return;
|
||||
}
|
||||
deviceQueue.add(consumer);
|
||||
}
|
||||
|
||||
@ -46,7 +58,7 @@ public class ControllerHIDService implements HidServicesListener {
|
||||
|
||||
if (isController(device)) {
|
||||
if (deviceQueue.peek() != null) {
|
||||
deviceQueue.poll().accept(event.getHidDevice());
|
||||
deviceQueue.poll().accept(device);
|
||||
} else {
|
||||
Controlify.LOGGER.error("Unhandled controller: " + ControllerType.getTypeForHID(new HIDIdentifier(device.getVendorId(), device.getProductId())).friendlyName());
|
||||
}
|
||||
@ -59,6 +71,10 @@ public class ControllerHIDService implements HidServicesListener {
|
||||
return isGenericDesktopControlOrGameControl && isController;
|
||||
}
|
||||
|
||||
public boolean isDisabled() {
|
||||
return disabled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void hidDeviceDetached(HidServicesEvent event) {
|
||||
|
||||
|
@ -1,10 +1,15 @@
|
||||
package dev.isxander.controlify.mixins.core;
|
||||
|
||||
import com.llamalad7.mixinextras.injector.ModifyExpressionValue;
|
||||
import dev.isxander.controlify.Controlify;
|
||||
import dev.isxander.controlify.gui.screen.BetaNoticeScreen;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.components.toasts.SystemToast;
|
||||
import net.minecraft.client.gui.components.toasts.ToastComponent;
|
||||
import net.minecraft.client.gui.screens.Screen;
|
||||
import net.minecraft.client.main.GameConfig;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.server.packs.resources.ReloadInstance;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
@ -20,6 +25,8 @@ public abstract class MinecraftMixin {
|
||||
|
||||
@Shadow public abstract float getFrameTime();
|
||||
|
||||
@Shadow public abstract ToastComponent getToasts();
|
||||
|
||||
@Inject(method = "<init>", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/KeyboardHandler;setup(J)V", shift = At.Shift.AFTER))
|
||||
private void onInputInitialized(CallbackInfo ci) {
|
||||
Controlify.instance().onInitializeInput();
|
||||
@ -35,4 +42,14 @@ public abstract class MinecraftMixin {
|
||||
if (Controlify.instance().config().isFirstLaunch())
|
||||
setScreen(new BetaNoticeScreen());
|
||||
}
|
||||
|
||||
@ModifyExpressionValue(method = "<init>", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/packs/resources/ReloadableResourceManager;createReload(Ljava/util/concurrent/Executor;Ljava/util/concurrent/Executor;Ljava/util/concurrent/CompletableFuture;Ljava/util/List;)Lnet/minecraft/server/packs/resources/ReloadInstance;"))
|
||||
private ReloadInstance onReloadResources(ReloadInstance resourceReload) {
|
||||
resourceReload.done().thenRun(() -> {
|
||||
if (Controlify.instance().controllerHIDService().isDisabled()) {
|
||||
getToasts().addToast(SystemToast.multiline((Minecraft) (Object) this, SystemToast.SystemToastIds.UNSECURE_SERVER_WARNING, Component.translatable("controlify.error.hid"), Component.translatable("controlify.error.hid.desc")));
|
||||
}
|
||||
});
|
||||
return resourceReload;
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user