forked from Clones/Controlify
better theme handling and better mouse hide handling (still not perfect)
This commit is contained in:
@ -48,8 +48,8 @@ public class Controlify {
|
|||||||
|
|
||||||
controllerHIDService.start();
|
controllerHIDService.start();
|
||||||
|
|
||||||
// load after initial controller discovery
|
config().load(); // load after initial controller discovery
|
||||||
config().load();
|
config().save(); // save new controller configs if they don't exist
|
||||||
|
|
||||||
// listen for new controllers
|
// listen for new controllers
|
||||||
GLFW.glfwSetJoystickCallback((jid, event) -> {
|
GLFW.glfwSetJoystickCallback((jid, event) -> {
|
||||||
@ -148,6 +148,7 @@ public class Controlify {
|
|||||||
this.currentInputMode = currentInputMode;
|
this.currentInputMode = currentInputMode;
|
||||||
|
|
||||||
var minecraft = Minecraft.getInstance();
|
var minecraft = Minecraft.getInstance();
|
||||||
|
if (!minecraft.mouseHandler.isMouseGrabbed())
|
||||||
hideMouse(currentInputMode == InputMode.CONTROLLER);
|
hideMouse(currentInputMode == InputMode.CONTROLLER);
|
||||||
if (minecraft.screen != null) {
|
if (minecraft.screen != null) {
|
||||||
ScreenProcessorProvider.provide(minecraft.screen).onInputModeChanged(currentInputMode);
|
ScreenProcessorProvider.provide(minecraft.screen).onInputModeChanged(currentInputMode);
|
||||||
@ -170,7 +171,7 @@ public class Controlify {
|
|||||||
if (hide && !virtualMouseHandler().isVirtualMouseEnabled()) {
|
if (hide && !virtualMouseHandler().isVirtualMouseEnabled()) {
|
||||||
// stop mouse hovering over last element before hiding cursor but don't actually move it
|
// stop mouse hovering over last element before hiding cursor but don't actually move it
|
||||||
// so when the user switches back to mouse it will be in the same place
|
// so when the user switches back to mouse it will be in the same place
|
||||||
mouseHandlerAccessor.invokeOnMove(minecraft.getWindow().getWindow(), 0, 0);
|
mouseHandlerAccessor.invokeOnMove(minecraft.getWindow().getWindow(), -50, -50);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -47,7 +47,7 @@ public enum Bind {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public ResourceLocation textureLocation(Controller controller) {
|
public ResourceLocation textureLocation(Controller controller) {
|
||||||
return new ResourceLocation("controlify", "textures/gui/buttons/" + controller.config().theme.id(controller) + "/" + identifier + ".png");
|
return new ResourceLocation("controlify", "textures/gui/buttons/" + controller.config().theme.id() + "/" + identifier + ".png");
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Bind fromIdentifier(String identifier) {
|
public static Bind fromIdentifier(String identifier) {
|
||||||
|
@ -1,28 +0,0 @@
|
|||||||
package dev.isxander.controlify.bindings;
|
|
||||||
|
|
||||||
import dev.isxander.controlify.controller.Controller;
|
|
||||||
import dev.isxander.yacl.api.NameableEnum;
|
|
||||||
import net.minecraft.network.chat.Component;
|
|
||||||
|
|
||||||
import java.util.function.Function;
|
|
||||||
|
|
||||||
public enum ControllerTheme implements NameableEnum {
|
|
||||||
AUTO(c -> c.type().theme().id(c)),
|
|
||||||
XBOX_ONE(c -> "xbox"),
|
|
||||||
DUALSHOCK4(c -> "dualshock4");
|
|
||||||
|
|
||||||
private final Function<Controller, String> idGetter;
|
|
||||||
|
|
||||||
ControllerTheme(Function<Controller, String> idGetter) {
|
|
||||||
this.idGetter = idGetter;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String id(Controller controller) {
|
|
||||||
return idGetter.apply(controller);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Component getDisplayName() {
|
|
||||||
return Component.translatable("controlify.controller_theme." + name().toLowerCase());
|
|
||||||
}
|
|
||||||
}
|
|
@ -3,7 +3,6 @@ package dev.isxander.controlify.config;
|
|||||||
import com.google.gson.*;
|
import com.google.gson.*;
|
||||||
import dev.isxander.controlify.Controlify;
|
import dev.isxander.controlify.Controlify;
|
||||||
import dev.isxander.controlify.controller.Controller;
|
import dev.isxander.controlify.controller.Controller;
|
||||||
import dev.isxander.controlify.controller.ControllerConfig;
|
|
||||||
import net.fabricmc.loader.api.FabricLoader;
|
import net.fabricmc.loader.api.FabricLoader;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@ -93,7 +92,7 @@ public class ControlifyConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void applyControllerConfig(Controller controller, JsonObject object) {
|
private void applyControllerConfig(Controller controller, JsonObject object) {
|
||||||
controller.setConfig(GSON.fromJson(object.getAsJsonObject("config"), ControllerConfig.class));
|
controller.setConfig(GSON.fromJson(object.getAsJsonObject("config"), Controller.ControllerConfig.class));
|
||||||
controller.bindings().fromJson(object.getAsJsonObject("bindings"));
|
controller.bindings().fromJson(object.getAsJsonObject("bindings"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,19 +2,17 @@ package dev.isxander.controlify.config.gui;
|
|||||||
|
|
||||||
import dev.isxander.controlify.Controlify;
|
import dev.isxander.controlify.Controlify;
|
||||||
import dev.isxander.controlify.bindings.Bind;
|
import dev.isxander.controlify.bindings.Bind;
|
||||||
import dev.isxander.controlify.bindings.ControllerTheme;
|
|
||||||
import dev.isxander.controlify.config.GlobalSettings;
|
import dev.isxander.controlify.config.GlobalSettings;
|
||||||
|
import dev.isxander.controlify.controller.ControllerTheme;
|
||||||
import dev.isxander.controlify.controller.Controller;
|
import dev.isxander.controlify.controller.Controller;
|
||||||
import dev.isxander.controlify.controller.ControllerConfig;
|
|
||||||
import dev.isxander.yacl.api.*;
|
import dev.isxander.yacl.api.*;
|
||||||
|
import dev.isxander.yacl.gui.controllers.TickBoxController;
|
||||||
import dev.isxander.yacl.gui.controllers.cycling.CyclingListController;
|
import dev.isxander.yacl.gui.controllers.cycling.CyclingListController;
|
||||||
import dev.isxander.yacl.gui.controllers.cycling.EnumController;
|
import dev.isxander.yacl.gui.controllers.cycling.EnumController;
|
||||||
import dev.isxander.yacl.gui.controllers.slider.FloatSliderController;
|
import dev.isxander.yacl.gui.controllers.slider.FloatSliderController;
|
||||||
import dev.isxander.yacl.gui.controllers.slider.IntegerSliderController;
|
import dev.isxander.yacl.gui.controllers.slider.IntegerSliderController;
|
||||||
import dev.isxander.yacl.gui.controllers.string.StringController;
|
|
||||||
import net.minecraft.ChatFormatting;
|
import net.minecraft.ChatFormatting;
|
||||||
import net.minecraft.client.gui.screens.Screen;
|
import net.minecraft.client.gui.screens.Screen;
|
||||||
import net.minecraft.locale.Language;
|
|
||||||
import net.minecraft.network.chat.Component;
|
import net.minecraft.network.chat.Component;
|
||||||
|
|
||||||
public class YACLHelper {
|
public class YACLHelper {
|
||||||
@ -33,13 +31,6 @@ public class YACLHelper {
|
|||||||
.binding(Controlify.instance().currentController(), () -> Controlify.instance().currentController(), v -> Controlify.instance().setCurrentController(v))
|
.binding(Controlify.instance().currentController(), () -> Controlify.instance().currentController(), v -> Controlify.instance().setCurrentController(v))
|
||||||
.controller(opt -> new CyclingListController<>(opt, Controller.CONTROLLERS.values().stream().filter(Controller::connected).toList(), c -> Component.literal(c.name())))
|
.controller(opt -> new CyclingListController<>(opt, Controller.CONTROLLERS.values().stream().filter(Controller::connected).toList(), c -> Component.literal(c.name())))
|
||||||
.instant(true)
|
.instant(true)
|
||||||
.build())
|
|
||||||
.option(ListOption.createBuilder(String.class)
|
|
||||||
.name(Component.translatable("controlify.gui.vmouse_screens"))
|
|
||||||
.tooltip(Component.translatable("controlify.gui.vmouse_screens.tooltip"))
|
|
||||||
.binding(GlobalSettings.DEFAULT.virtualMouseScreens, () -> controlify.config().globalSettings().virtualMouseScreens, v -> controlify.config().globalSettings().virtualMouseScreens = v)
|
|
||||||
.controller(StringController::new)
|
|
||||||
.initial(Language.getInstance().getOrDefault("controlify.gui.vmouse_screens.placeholder"))
|
|
||||||
.build());
|
.build());
|
||||||
|
|
||||||
yacl.category(globalCategory.build());
|
yacl.category(globalCategory.build());
|
||||||
@ -51,7 +42,7 @@ public class YACLHelper {
|
|||||||
category.name(Component.literal(customName == null ? controller.name() : customName));
|
category.name(Component.literal(customName == null ? controller.name() : customName));
|
||||||
|
|
||||||
var config = controller.config();
|
var config = controller.config();
|
||||||
var def = ControllerConfig.DEFAULT;
|
var def = controller.defaultConfig();
|
||||||
var configGroup = OptionGroup.createBuilder()
|
var configGroup = OptionGroup.createBuilder()
|
||||||
.name(Component.translatable("controlify.gui.group.config"))
|
.name(Component.translatable("controlify.gui.group.config"))
|
||||||
.tooltip(Component.translatable("controlify.gui.group.config.tooltip"))
|
.tooltip(Component.translatable("controlify.gui.group.config.tooltip"))
|
||||||
@ -108,7 +99,7 @@ public class YACLHelper {
|
|||||||
.option(Option.createBuilder(ControllerTheme.class)
|
.option(Option.createBuilder(ControllerTheme.class)
|
||||||
.name(Component.translatable("controlify.gui.controller_theme"))
|
.name(Component.translatable("controlify.gui.controller_theme"))
|
||||||
.tooltip(Component.translatable("controlify.gui.controller_theme.tooltip"))
|
.tooltip(Component.translatable("controlify.gui.controller_theme.tooltip"))
|
||||||
.binding(def.theme, () -> config.theme, v -> config.theme = v)
|
.binding(controller.type().theme(), () -> config.theme, v -> config.theme = v)
|
||||||
.controller(EnumController::new)
|
.controller(EnumController::new)
|
||||||
.instant(true)
|
.instant(true)
|
||||||
.build());
|
.build());
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package dev.isxander.controlify.controller;
|
package dev.isxander.controlify.controller;
|
||||||
|
|
||||||
import dev.isxander.controlify.bindings.ControllerBindings;
|
import dev.isxander.controlify.bindings.ControllerBindings;
|
||||||
import dev.isxander.controlify.bindings.ControllerTheme;
|
|
||||||
import dev.isxander.controlify.controller.hid.HIDIdentifier;
|
import dev.isxander.controlify.controller.hid.HIDIdentifier;
|
||||||
import dev.isxander.controlify.event.ControlifyEvents;
|
import dev.isxander.controlify.event.ControlifyEvents;
|
||||||
import org.hid4java.HidDevice;
|
import org.hid4java.HidDevice;
|
||||||
@ -27,7 +26,7 @@ public final class Controller {
|
|||||||
private ControllerState prevState = ControllerState.EMPTY;
|
private ControllerState prevState = ControllerState.EMPTY;
|
||||||
|
|
||||||
private final ControllerBindings bindings = new ControllerBindings(this);
|
private final ControllerBindings bindings = new ControllerBindings(this);
|
||||||
private ControllerConfig config = new ControllerConfig();
|
private ControllerConfig config, defaultConfig;
|
||||||
|
|
||||||
public Controller(int joystickId, String guid, String name, boolean gamepad, String uid, ControllerType type) {
|
public Controller(int joystickId, String guid, String name, boolean gamepad, String uid, ControllerType type) {
|
||||||
this.joystickId = joystickId;
|
this.joystickId = joystickId;
|
||||||
@ -36,6 +35,8 @@ public final class Controller {
|
|||||||
this.gamepad = gamepad;
|
this.gamepad = gamepad;
|
||||||
this.uid = uid;
|
this.uid = uid;
|
||||||
this.type = type;
|
this.type = type;
|
||||||
|
this.config = new ControllerConfig();
|
||||||
|
this.defaultConfig = new ControllerConfig();
|
||||||
}
|
}
|
||||||
|
|
||||||
public ControllerState state() {
|
public ControllerState state() {
|
||||||
@ -110,6 +111,10 @@ public final class Controller {
|
|||||||
return config;
|
return config;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ControllerConfig defaultConfig() {
|
||||||
|
return defaultConfig;
|
||||||
|
}
|
||||||
|
|
||||||
public void setConfig(ControllerConfig config) {
|
public void setConfig(ControllerConfig config) {
|
||||||
this.config = config;
|
this.config = config;
|
||||||
}
|
}
|
||||||
@ -150,4 +155,26 @@ public final class Controller {
|
|||||||
return controller;
|
return controller;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class ControllerConfig {
|
||||||
|
public float horizontalLookSensitivity = 1f;
|
||||||
|
public float verticalLookSensitivity = 0.9f;
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
public float leftTriggerActivationThreshold = 0.5f;
|
||||||
|
public float rightTriggerActivationThreshold = 0.5f;
|
||||||
|
|
||||||
|
public int screenRepeatNavigationDelay = 4;
|
||||||
|
|
||||||
|
public float virtualMouseSensitivity = 1f;
|
||||||
|
|
||||||
|
public ControllerTheme theme = type().theme();
|
||||||
|
|
||||||
|
public String customName = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,28 +0,0 @@
|
|||||||
package dev.isxander.controlify.controller;
|
|
||||||
|
|
||||||
import dev.isxander.controlify.bindings.ControllerTheme;
|
|
||||||
|
|
||||||
public class ControllerConfig {
|
|
||||||
public static final ControllerConfig DEFAULT = new ControllerConfig();
|
|
||||||
|
|
||||||
public float horizontalLookSensitivity = 1f;
|
|
||||||
public float verticalLookSensitivity = 0.9f;
|
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
public float leftTriggerActivationThreshold = 0.5f;
|
|
||||||
public float rightTriggerActivationThreshold = 0.5f;
|
|
||||||
|
|
||||||
public int screenRepeatNavigationDelay = 4;
|
|
||||||
|
|
||||||
public float virtualMouseSensitivity = 1f;
|
|
||||||
|
|
||||||
public ControllerTheme theme = ControllerTheme.AUTO;
|
|
||||||
|
|
||||||
public String customName = null;
|
|
||||||
}
|
|
@ -0,0 +1,24 @@
|
|||||||
|
package dev.isxander.controlify.controller;
|
||||||
|
|
||||||
|
import dev.isxander.yacl.api.NameableEnum;
|
||||||
|
import net.minecraft.network.chat.Component;
|
||||||
|
|
||||||
|
public enum ControllerTheme implements NameableEnum {
|
||||||
|
XBOX_ONE("xbox"),
|
||||||
|
DUALSHOCK4("dualshock4");
|
||||||
|
|
||||||
|
private final String id;
|
||||||
|
|
||||||
|
ControllerTheme(String id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String id() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Component getDisplayName() {
|
||||||
|
return Component.translatable("controlify.controller_theme." + name().toLowerCase());
|
||||||
|
}
|
||||||
|
}
|
@ -3,7 +3,6 @@ package dev.isxander.controlify.controller;
|
|||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
import com.google.gson.GsonBuilder;
|
import com.google.gson.GsonBuilder;
|
||||||
import com.google.gson.JsonObject;
|
import com.google.gson.JsonObject;
|
||||||
import dev.isxander.controlify.bindings.ControllerTheme;
|
|
||||||
import dev.isxander.controlify.controller.hid.HIDIdentifier;
|
import dev.isxander.controlify.controller.hid.HIDIdentifier;
|
||||||
|
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
|
@ -2,6 +2,7 @@ package dev.isxander.controlify.mixins.feature.virtualmouse;
|
|||||||
|
|
||||||
import net.minecraft.client.MouseHandler;
|
import net.minecraft.client.MouseHandler;
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||||
import org.spongepowered.asm.mixin.gen.Invoker;
|
import org.spongepowered.asm.mixin.gen.Invoker;
|
||||||
|
|
||||||
@Mixin(MouseHandler.class)
|
@Mixin(MouseHandler.class)
|
||||||
@ -14,4 +15,7 @@ public interface MouseHandlerAccessor {
|
|||||||
|
|
||||||
@Invoker
|
@Invoker
|
||||||
void invokeOnScroll(long window, double scrollDeltaX, double scrollDeltaY);
|
void invokeOnScroll(long window, double scrollDeltaX, double scrollDeltaY);
|
||||||
|
|
||||||
|
@Accessor
|
||||||
|
void setMouseGrabbed(boolean mouseGrabbed);
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,17 @@
|
|||||||
|
package dev.isxander.controlify.mixins.feature.virtualmouse;
|
||||||
|
|
||||||
|
import com.llamalad7.mixinextras.injector.WrapWithCondition;
|
||||||
|
import dev.isxander.controlify.Controlify;
|
||||||
|
import dev.isxander.controlify.InputMode;
|
||||||
|
import net.minecraft.client.MouseHandler;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
|
||||||
|
@Mixin(MouseHandler.class)
|
||||||
|
public class MouseHandlerMixin {
|
||||||
|
@WrapWithCondition(method = "releaseMouse", at = @At(value = "INVOKE", target = "Lcom/mojang/blaze3d/platform/InputConstants;grabOrReleaseMouse(JIDD)V"))
|
||||||
|
private boolean shouldReleaseMouse(long window, int newMouseState, double x, double y) {
|
||||||
|
// mouse cursor appears for a split second when going into guis on controller input
|
||||||
|
return Controlify.instance().currentInputMode() != InputMode.CONTROLLER;
|
||||||
|
}
|
||||||
|
}
|
@ -102,7 +102,8 @@ public class VirtualMouseHandler {
|
|||||||
GLFW.glfwSetInputMode(minecraft.getWindow().getWindow(), GLFW.GLFW_CURSOR, GLFW.GLFW_CURSOR_HIDDEN);
|
GLFW.glfwSetInputMode(minecraft.getWindow().getWindow(), GLFW.GLFW_CURSOR, GLFW.GLFW_CURSOR_HIDDEN);
|
||||||
} else if (virtualMouseEnabled) {
|
} else if (virtualMouseEnabled) {
|
||||||
disableVirtualMouse();
|
disableVirtualMouse();
|
||||||
minecraft.mouseHandler.grabMouse();
|
|
||||||
|
minecraft.mouseHandler.grabMouse(); // re-grab mouse after vmouse disable
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -127,7 +128,7 @@ public class VirtualMouseHandler {
|
|||||||
var scaledY = currentY * (double)this.minecraft.getWindow().getGuiScaledHeight() / (double)this.minecraft.getWindow().getScreenHeight();
|
var scaledY = currentY * (double)this.minecraft.getWindow().getGuiScaledHeight() / (double)this.minecraft.getWindow().getScreenHeight();
|
||||||
|
|
||||||
matrices.pushPose();
|
matrices.pushPose();
|
||||||
matrices.translate(scaledX, scaledY, 0);
|
matrices.translate(scaledX, scaledY, 1000f);
|
||||||
matrices.scale(0.5f, 0.5f, 0.5f);
|
matrices.scale(0.5f, 0.5f, 0.5f);
|
||||||
|
|
||||||
GuiComponent.blit(matrices, -16, -16, 0, 0, 32, 32, 32, 32);
|
GuiComponent.blit(matrices, -16, -16, 0, 0, 32, 32, 32, 32);
|
||||||
@ -158,6 +159,9 @@ public class VirtualMouseHandler {
|
|||||||
public void disableVirtualMouse() {
|
public void disableVirtualMouse() {
|
||||||
if (!virtualMouseEnabled) return;
|
if (!virtualMouseEnabled) return;
|
||||||
|
|
||||||
|
// make sure minecraft doesn't think the mouse is grabbed when it isn't
|
||||||
|
((MouseHandlerAccessor) minecraft.mouseHandler).setMouseGrabbed(false);
|
||||||
|
|
||||||
GLFW.glfwSetInputMode(minecraft.getWindow().getWindow(), GLFW.GLFW_CURSOR, GLFW.GLFW_CURSOR_NORMAL);
|
GLFW.glfwSetInputMode(minecraft.getWindow().getWindow(), GLFW.GLFW_CURSOR, GLFW.GLFW_CURSOR_NORMAL);
|
||||||
setMousePosition();
|
setMousePosition();
|
||||||
virtualMouseEnabled = false;
|
virtualMouseEnabled = false;
|
||||||
|
@ -41,11 +41,10 @@
|
|||||||
"controlify.toast.vmouse_disabled.title": "Virtual Mouse Disabled",
|
"controlify.toast.vmouse_disabled.title": "Virtual Mouse Disabled",
|
||||||
"controlify.toast.vmouse_disabled.description": "Controlify virtual mouse is now disabled for this screen.",
|
"controlify.toast.vmouse_disabled.description": "Controlify virtual mouse is now disabled for this screen.",
|
||||||
"controlify.toast.controller_connected.title": "Controller Connected",
|
"controlify.toast.controller_connected.title": "Controller Connected",
|
||||||
"controlify.toast.controller_connected.description": "A new controller has just been connected. You can switch to it in Controlify settings.",
|
"controlify.toast.controller_connected.description": "A new '%s' controller named has just been connected. You can switch to your other controller in Controlify settings.",
|
||||||
"controlify.toast.controller_disconnected.title": "Controller Disconnected",
|
"controlify.toast.controller_disconnected.title": "Controller Disconnected",
|
||||||
"controlify.toast.controller_disconnected.description": "'%s' was disconnected.",
|
"controlify.toast.controller_disconnected.description": "'%s' was disconnected.",
|
||||||
|
|
||||||
"controlify.controller_theme.auto": "Auto",
|
|
||||||
"controlify.controller_theme.xbox_one": "Xbox",
|
"controlify.controller_theme.xbox_one": "Xbox",
|
||||||
"controlify.controller_theme.dualshock4": "PS4",
|
"controlify.controller_theme.dualshock4": "PS4",
|
||||||
|
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
"feature.virtualmouse.GameRendererMixin",
|
"feature.virtualmouse.GameRendererMixin",
|
||||||
"feature.virtualmouse.KeyboardHandlerAccessor",
|
"feature.virtualmouse.KeyboardHandlerAccessor",
|
||||||
"feature.virtualmouse.MinecraftMixin",
|
"feature.virtualmouse.MinecraftMixin",
|
||||||
"feature.virtualmouse.MouseHandlerAccessor"
|
"feature.virtualmouse.MouseHandlerAccessor",
|
||||||
|
"feature.virtualmouse.MouseHandlerMixin"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user