forked from Clones/Controlify
➕ Mixed input mode for Steam Deck
This commit is contained in:
@ -3,6 +3,7 @@ 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;
|
||||
@ -72,6 +73,8 @@ public class Controlify implements ControlifyApi {
|
||||
private int consecutiveInputSwitches = 0;
|
||||
private double lastInputSwitchTime = 0;
|
||||
|
||||
private int showMouseTicks = 0;
|
||||
|
||||
private @Nullable Controller<?, ?> switchableController = null;
|
||||
private double askSwitchTime = 0;
|
||||
private ToastUtils.ControlifyToast askSwitchToast = null;
|
||||
@ -278,6 +281,15 @@ public class Controlify implements ControlifyApi {
|
||||
}
|
||||
}
|
||||
|
||||
if (minecraft.mouseHandler.isMouseGrabbed())
|
||||
showMouseTicks = 0;
|
||||
if (currentInputMode() == InputMode.MIXED && showMouseTicks > 0) {
|
||||
showMouseTicks--;
|
||||
if (showMouseTicks == 0) {
|
||||
hideMouse(true, false);
|
||||
}
|
||||
}
|
||||
|
||||
LowBatteryNotifier.tick();
|
||||
|
||||
getCurrentController().ifPresent(currentController -> {
|
||||
@ -300,7 +312,11 @@ public class Controlify implements ControlifyApi {
|
||||
}
|
||||
|
||||
if (state.hasAnyInput()) {
|
||||
this.setInputMode(InputMode.CONTROLLER);
|
||||
// use MIXED input mode to support Steam Input for things like gyro mouse and touchpads
|
||||
// this is only temporary until the Steam Deck driver is finished
|
||||
boolean isSteamDeck = controller.hidInfo().map(info -> info.hidDevice().map(device -> SteamDeckDriver.isSteamDeck(device.getVendorId(), device.getProductId())).orElse(false)).orElse(false);
|
||||
|
||||
this.setInputMode(isSteamDeck ? InputMode.MIXED : InputMode.CONTROLLER);
|
||||
}
|
||||
|
||||
if (consecutiveInputSwitches > 100) {
|
||||
@ -483,7 +499,7 @@ public class Controlify implements ControlifyApi {
|
||||
this.currentInputMode = currentInputMode;
|
||||
|
||||
if (!minecraft.mouseHandler.isMouseGrabbed())
|
||||
hideMouse(currentInputMode == InputMode.CONTROLLER, true);
|
||||
hideMouse(currentInputMode.isController(), true);
|
||||
if (minecraft.screen != null) {
|
||||
ScreenProcessorProvider.provide(minecraft.screen).onInputModeChanged(currentInputMode);
|
||||
}
|
||||
@ -501,7 +517,7 @@ public class Controlify implements ControlifyApi {
|
||||
}
|
||||
lastInputSwitchTime = Blaze3D.getTime();
|
||||
|
||||
if (currentInputMode == InputMode.CONTROLLER)
|
||||
if (this.currentInputMode == InputMode.CONTROLLER)
|
||||
getCurrentController().ifPresent(Controller::clearState);
|
||||
|
||||
ControlifyEvents.INPUT_MODE_CHANGED.invoker().onInputModeChanged(currentInputMode);
|
||||
@ -527,6 +543,13 @@ public class Controlify implements ControlifyApi {
|
||||
}
|
||||
}
|
||||
|
||||
public void showCursorTemporarily() {
|
||||
if (currentInputMode() == InputMode.MIXED && !minecraft.mouseHandler.isMouseGrabbed()) {
|
||||
hideMouse(false, false);
|
||||
showMouseTicks = 20 * 3;
|
||||
}
|
||||
}
|
||||
|
||||
public static Controlify instance() {
|
||||
if (instance == null) instance = new Controlify();
|
||||
return instance;
|
||||
|
@ -2,5 +2,14 @@ package dev.isxander.controlify;
|
||||
|
||||
public enum InputMode {
|
||||
KEYBOARD_MOUSE,
|
||||
CONTROLLER;
|
||||
CONTROLLER,
|
||||
MIXED;
|
||||
|
||||
public boolean isKeyboardMouse() {
|
||||
return this != CONTROLLER;
|
||||
}
|
||||
|
||||
public boolean isController() {
|
||||
return this != KEYBOARD_MOUSE;
|
||||
}
|
||||
}
|
||||
|
@ -50,7 +50,7 @@ public record GamepadDrivers(BasicGamepadInputDriver basicGamepadInputDriver, Gy
|
||||
}
|
||||
|
||||
// TODO: Fix Steam Deck driver
|
||||
if (hid.isPresent() && SteamDeckDriver.isSteamDeck(hid.get()) && false) {
|
||||
if (hid.isPresent() && SteamDeckDriver.isSteamDeck(hid.get().getVendorId(), hid.get().getProductId()) && false) {
|
||||
gyroDriver = new SteamDeckDriver(hid.get());
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
package dev.isxander.controlify.driver;
|
||||
|
||||
import dev.isxander.controlify.controller.gamepad.GamepadState;
|
||||
import dev.isxander.controlify.controller.hid.HIDIdentifier;
|
||||
import dev.isxander.controlify.utils.Log;
|
||||
import org.hid4java.HidDevice;
|
||||
|
||||
@ -243,7 +244,7 @@ public class SteamDeckDriver implements GyroDriver, BasicGamepadInputDriver {
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isSteamDeck(HidDevice hid) {
|
||||
return hid.getVendorId() == 0x28DE && hid.getProductId() == 0x1205;
|
||||
public static boolean isSteamDeck(int vendorId, int productId) {
|
||||
return vendorId == 0x28DE && productId == 0x1205;
|
||||
}
|
||||
}
|
||||
|
@ -44,7 +44,7 @@ public class InGameInputHandler {
|
||||
|
||||
ControlifyEvents.INPUT_MODE_CHANGED.register(mode -> {
|
||||
if (minecraft.player != null) {
|
||||
minecraft.player.input = mode == InputMode.CONTROLLER
|
||||
minecraft.player.input = mode.isController()
|
||||
? new ControllerPlayerMovement(controller, minecraft.player)
|
||||
: new KeyboardInput(minecraft.options);
|
||||
}
|
||||
|
@ -35,7 +35,7 @@ public class ClientPacketListenerMixin {
|
||||
}
|
||||
|
||||
private void overrideInput(LocalPlayer player) {
|
||||
if (Controlify.instance().currentInputMode() == InputMode.CONTROLLER && player != null)
|
||||
if (Controlify.instance().currentInputMode().isController() && player != null)
|
||||
player.input = new ControllerPlayerMovement(Controlify.instance().currentController(), player);
|
||||
}
|
||||
}
|
||||
|
@ -18,7 +18,7 @@ public class KeyboardHandlerMixin {
|
||||
// m_unngxkoe is lambda for GLFW keypress hook - do it outside of the `keyPress` method due to fake inputs
|
||||
@Inject(method = "method_22678", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/KeyboardHandler;keyPress(JIIII)V"))
|
||||
private void onKeyboardInput(long window, int i, int j, int k, int m, CallbackInfo ci) {
|
||||
if (window == minecraft.getWindow().getWindow())
|
||||
if (window == minecraft.getWindow().getWindow() && Controlify.instance().currentInputMode() != InputMode.MIXED)
|
||||
Controlify.instance().setInputMode(InputMode.KEYBOARD_MOUSE);
|
||||
}
|
||||
}
|
||||
|
@ -16,25 +16,32 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
public class MouseHandlerMixin {
|
||||
@Shadow @Final private Minecraft minecraft;
|
||||
|
||||
// m_sljgmtqm is lambda for GLFW mouse click hook - do it outside of the `onPress` method due to fake inputs
|
||||
// method_22686 is lambda for GLFW mouse click hook - do it outside of the `onPress` method due to fake inputs
|
||||
@Inject(method = "method_22686", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/MouseHandler;onPress(JIII)V"))
|
||||
private void onMouseClickInput(long window, int button, int action, int modifiers, CallbackInfo ci) {
|
||||
if (window == minecraft.getWindow().getWindow())
|
||||
Controlify.instance().setInputMode(InputMode.KEYBOARD_MOUSE);
|
||||
onMouse(window);
|
||||
}
|
||||
|
||||
// m_swhlgdws is lambda for GLFW mouse move hook - do it outside of the `onMove` method due to fake inputs
|
||||
// method_22689 is lambda for GLFW mouse move hook - do it outside of the `onMove` method due to fake inputs
|
||||
@Inject(method = "method_22689", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/MouseHandler;onMove(JDD)V"))
|
||||
private void onMouseMoveInput(long window, double x, double y, CallbackInfo ci) {
|
||||
if (window == minecraft.getWindow().getWindow())
|
||||
Controlify.instance().setInputMode(InputMode.KEYBOARD_MOUSE);
|
||||
onMouse(window);
|
||||
}
|
||||
|
||||
// m_qoshpwkl is lambda for GLFW mouse scroll hook - do it outside of the `onScroll` method due to fake inputs
|
||||
// method_22687 is lambda for GLFW mouse scroll hook - do it outside of the `onScroll` method due to fake inputs
|
||||
@Inject(method = "method_22687", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/MouseHandler;onScroll(JDD)V"))
|
||||
private void onMouseScrollInput(long window, double scrollDeltaX, double scrollDeltaY, CallbackInfo ci) {
|
||||
if (window == minecraft.getWindow().getWindow())
|
||||
Controlify.instance().setInputMode(InputMode.KEYBOARD_MOUSE);
|
||||
onMouse(window);
|
||||
}
|
||||
|
||||
private void onMouse(long window) {
|
||||
if (window == minecraft.getWindow().getWindow()) {
|
||||
if (Controlify.instance().currentInputMode() != InputMode.MIXED) {
|
||||
Controlify.instance().setInputMode(InputMode.KEYBOARD_MOUSE);
|
||||
} else {
|
||||
Controlify.instance().showCursorTemporarily();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -42,7 +49,7 @@ public class MouseHandlerMixin {
|
||||
*/
|
||||
@Inject(method = "releaseMouse", at = @At(value = "INVOKE", target = "Lcom/mojang/blaze3d/platform/InputConstants;grabOrReleaseMouse(JIDD)V"))
|
||||
private void moveMouseIfNecessary(CallbackInfo ci) {
|
||||
if (ControlifyApi.get().currentInputMode() == InputMode.CONTROLLER) {
|
||||
if (ControlifyApi.get().currentInputMode().isController()) {
|
||||
Controlify.instance().hideMouse(true, true);
|
||||
}
|
||||
}
|
||||
|
@ -11,7 +11,7 @@ import org.spongepowered.asm.mixin.injection.At;
|
||||
public class LocalPlayerMixin {
|
||||
@ModifyExpressionValue(method = "sendPosition", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/OptionInstance;get()Ljava/lang/Object;"))
|
||||
private Object shouldUseAutoJump(Object keyboardAutoJump) {
|
||||
if (ControlifyApi.get().currentInputMode() == InputMode.CONTROLLER) {
|
||||
if (ControlifyApi.get().currentInputMode().isController()) {
|
||||
return ControlifyApi.get().getCurrentController()
|
||||
.map(controller -> controller.config().autoJump)
|
||||
.orElse(false);
|
||||
|
@ -3,33 +3,28 @@ package dev.isxander.controlify.mixins.feature.fixes.boatfix;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
|
||||
import dev.isxander.controlify.Controlify;
|
||||
import dev.isxander.controlify.InputMode;
|
||||
import dev.isxander.controlify.api.ControlifyApi;
|
||||
import dev.isxander.controlify.controller.Controller;
|
||||
import dev.isxander.controlify.fixes.boatfix.AnalogBoatInput;
|
||||
import net.minecraft.client.player.Input;
|
||||
import net.minecraft.client.player.LocalPlayer;
|
||||
import net.minecraft.world.entity.vehicle.Boat;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
@Mixin(LocalPlayer.class)
|
||||
public class LocalPlayerMixin {
|
||||
@Shadow public Input input;
|
||||
|
||||
@WrapOperation(method = "rideTick", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/vehicle/Boat;setInput(ZZZZ)V"))
|
||||
private void useAnalogInput(Boat boat, boolean pressingLeft, boolean pressingRight, boolean pressingForward, boolean pressingBack, Operation<Void> original) {
|
||||
if (ControlifyApi.get().currentInputMode() == InputMode.CONTROLLER && !Controlify.instance().config().globalSettings().keyboardMovement) {
|
||||
Optional<Controller<?, ?>> controllerOpt = ControlifyApi.get().getCurrentController();
|
||||
if (controllerOpt.isPresent()) {
|
||||
var controller = controllerOpt.get();
|
||||
if (ControlifyApi.get().currentInputMode().isController() && !Controlify.instance().config().globalSettings().keyboardMovement) {
|
||||
((AnalogBoatInput) boat).setAnalogInput(
|
||||
input.forwardImpulse,
|
||||
-input.leftImpulse
|
||||
);
|
||||
|
||||
((AnalogBoatInput) boat).setAnalogInput(
|
||||
controller.bindings().WALK_FORWARD.state() - controller.bindings().WALK_BACKWARD.state(),
|
||||
controller.bindings().WALK_RIGHT.state() - controller.bindings().WALK_LEFT.state()
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
original.call(boat, pressingLeft, pressingRight, pressingForward, pressingBack);
|
||||
|
@ -30,7 +30,7 @@ public class ClientPacketListenerMixin {
|
||||
}
|
||||
|
||||
private void initButtonGuide() {
|
||||
if (Controlify.instance().currentInputMode() == InputMode.CONTROLLER && minecraft.player != null)
|
||||
if (Controlify.instance().currentInputMode().isController() && minecraft.player != null)
|
||||
Controlify.instance().inGameButtonGuide = new InGameButtonGuide(Controlify.instance().getCurrentController().orElseThrow(), minecraft.player);
|
||||
}
|
||||
}
|
||||
|
@ -66,7 +66,7 @@ public abstract class AbstractButtonMixin extends AbstractWidgetMixin implements
|
||||
private boolean shouldRender() {
|
||||
return renderData != null
|
||||
&& this.isActive()
|
||||
&& Controlify.instance().currentInputMode() == InputMode.CONTROLLER
|
||||
&& Controlify.instance().currentInputMode().isController()
|
||||
&& Controlify.instance().getCurrentController().map(c -> c.config().showScreenGuide).orElse(false)
|
||||
&& !renderData.binding().apply(Controlify.instance().currentController().bindings()).isUnbound()
|
||||
&& renderData.renderPredicate().shouldDisplay((AbstractButton) (Object) this);
|
||||
|
@ -25,7 +25,7 @@ public class TabNavigationBarMixin {
|
||||
|
||||
@Inject(method = "render", at = @At("RETURN"))
|
||||
private void renderControllerButtonOverlay(GuiGraphics graphics, int mouseX, int mouseY, float delta, CallbackInfo ci) {
|
||||
if (Controlify.instance().currentInputMode() == InputMode.CONTROLLER) {
|
||||
if (Controlify.instance().currentInputMode().isController()) {
|
||||
Controlify.instance().getCurrentController().ifPresent(c -> {
|
||||
if (c.config().showScreenGuide) {
|
||||
this.renderControllerButtonOverlay(graphics, c);
|
||||
|
@ -11,6 +11,6 @@ import org.spongepowered.asm.mixin.injection.At;
|
||||
public class AbstractSelectionListMixin {
|
||||
@ModifyExpressionValue(method = "setFocused", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/InputType;isKeyboard()Z"))
|
||||
private boolean shouldEnsureEntryVisible(boolean keyboard) {
|
||||
return keyboard || Controlify.instance().currentInputMode() == InputMode.CONTROLLER;
|
||||
return keyboard || Controlify.instance().currentInputMode().isController();
|
||||
}
|
||||
}
|
||||
|
@ -29,7 +29,7 @@ public class AbstractSliderButtonMixin implements ComponentProcessorProvider {
|
||||
|
||||
@ModifyExpressionValue(method = "setFocused", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/Minecraft;getLastInputType()Lnet/minecraft/client/InputType;"))
|
||||
private InputType shouldChangeValue(InputType type) {
|
||||
if (Controlify.instance().currentInputMode() == InputMode.CONTROLLER)
|
||||
if (Controlify.instance().currentInputMode().isController())
|
||||
return InputType.NONE; // none doesn't pass condition
|
||||
return type;
|
||||
}
|
||||
|
@ -199,7 +199,7 @@ public class ScreenProcessor<T extends Screen> {
|
||||
}
|
||||
|
||||
protected void setInitialFocus() {
|
||||
if (screen.getFocused() == null && Controlify.instance().currentInputMode() == InputMode.CONTROLLER && !Controlify.instance().virtualMouseHandler().isVirtualMouseEnabled()) {
|
||||
if (screen.getFocused() == null && Controlify.instance().currentInputMode().isController() && !Controlify.instance().virtualMouseHandler().isVirtualMouseEnabled()) {
|
||||
var accessor = (ScreenAccessor) screen;
|
||||
ComponentPath path = screen.nextFocusPath(accessor.invokeCreateArrowEvent(ScreenDirection.DOWN));
|
||||
if (path != null) {
|
||||
|
@ -184,14 +184,14 @@ public class AbstractContainerScreenProcessor<T extends AbstractContainerScreen<
|
||||
AnchorPoint.BOTTOM_RIGHT
|
||||
);
|
||||
|
||||
if (ControlifyApi.get().currentInputMode() == InputMode.CONTROLLER) {
|
||||
if (ControlifyApi.get().currentInputMode().isController()) {
|
||||
setRenderGuide(true);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onInputModeChanged(InputMode mode) {
|
||||
setRenderGuide(mode == InputMode.CONTROLLER);
|
||||
setRenderGuide(mode.isController());
|
||||
}
|
||||
|
||||
private void setRenderGuide(boolean render) {
|
||||
|
@ -183,7 +183,7 @@ public class VirtualMouseHandler {
|
||||
} else {
|
||||
disableVirtualMouse();
|
||||
}
|
||||
if (Controlify.instance().currentInputMode() == InputMode.CONTROLLER)
|
||||
if (Controlify.instance().currentInputMode().isController())
|
||||
GLFW.glfwSetInputMode(minecraft.getWindow().getWindow(), GLFW.GLFW_CURSOR, GLFW.GLFW_CURSOR_HIDDEN);
|
||||
} else if (virtualMouseEnabled) {
|
||||
disableVirtualMouse();
|
||||
@ -193,7 +193,7 @@ public class VirtualMouseHandler {
|
||||
}
|
||||
|
||||
public void onInputModeChanged(InputMode mode) {
|
||||
if (mode == InputMode.CONTROLLER) {
|
||||
if (mode.isController()) {
|
||||
if (requiresVirtualMouse()) {
|
||||
enableVirtualMouse();
|
||||
}
|
||||
@ -269,7 +269,7 @@ public class VirtualMouseHandler {
|
||||
}
|
||||
|
||||
public boolean requiresVirtualMouse() {
|
||||
var isController = Controlify.instance().currentInputMode() == InputMode.CONTROLLER;
|
||||
var isController = Controlify.instance().currentInputMode().isController();
|
||||
var hasScreen = minecraft.screen != null;
|
||||
|
||||
if (isController && hasScreen) {
|
||||
|
Reference in New Issue
Block a user