mirror of
https://github.com/TeamMidnightDust/MidnightControls.git
synced 2025-12-17 08:55:10 +01:00
Eye Tracking Support, Minecraft Without Hands
Add support for eye tracking hardware, eg the Tobii 5. Add settings to toggle eye tracking in the settings menu. Add settings to adjust the deadzone while looking at the crosshair. Disable mouse raw input while eye tracking is in use, as these two modes are not compatible.
This commit is contained in:
@@ -0,0 +1,39 @@
|
||||
package eu.midnightdust.midnightcontrols.client.mixin;
|
||||
|
||||
import net.minecraft.client.util.InputUtil;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.Overwrite;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import eu.midnightdust.midnightcontrols.client.MidnightControlsConfig;
|
||||
import java.lang.invoke.MethodHandle;
|
||||
|
||||
|
||||
@Mixin(InputUtil.class)
|
||||
public abstract class InputUtilMixin {
|
||||
|
||||
@Final
|
||||
@Shadow
|
||||
private static MethodHandle GLFW_RAW_MOUSE_MOTION_SUPPORTED_HANDLE;
|
||||
|
||||
/**
|
||||
* @author kabliz
|
||||
* @reason This method is static, and there is a terrible UX issue if raw input is turned on at the same time as
|
||||
* eye tracking. Raw input only tracks literal mice and not other devices, leading to the game appearing to be
|
||||
* unresponsive and the player not understanding why. This overwrite preserves the user's mouse preferences,
|
||||
* while not interfering with eye tracking, and the two modes can be switched between during a play session.
|
||||
*/
|
||||
@Overwrite
|
||||
public static boolean isRawMouseMotionSupported(){
|
||||
if(MidnightControlsConfig.eyeTrackerAsMouse){
|
||||
return false;
|
||||
} else { //Paste original implementation from InputUtil below.
|
||||
try {
|
||||
return GLFW_RAW_MOUSE_MOTION_SUPPORTED_HANDLE != null &&
|
||||
(boolean) GLFW_RAW_MOUSE_MOTION_SUPPORTED_HANDLE.invokeExact();
|
||||
} catch (Throwable var1) {
|
||||
throw new RuntimeException(var1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -15,7 +15,9 @@ import eu.midnightdust.midnightcontrols.client.MidnightControlsConfig;
|
||||
import eu.midnightdust.midnightcontrols.client.util.MouseAccessor;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.Mouse;
|
||||
import net.minecraft.client.gui.screen.Screen;
|
||||
import net.minecraft.client.option.KeyBinding;
|
||||
import net.minecraft.client.util.GlfwUtil;
|
||||
import net.minecraft.client.util.SmoothUtil;
|
||||
import org.lwjgl.glfw.GLFW;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
@@ -26,6 +28,10 @@ import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
import eu.midnightdust.midnightcontrols.client.mouse.EyeTrackerHandler;
|
||||
|
||||
import static org.lwjgl.glfw.GLFW.GLFW_CURSOR;
|
||||
import static org.lwjgl.glfw.GLFW.GLFW_CURSOR_HIDDEN;
|
||||
|
||||
/**
|
||||
* Adds extra access to the mouse.
|
||||
@@ -36,6 +42,37 @@ public abstract class MouseMixin implements MouseAccessor {
|
||||
@Final
|
||||
private MinecraftClient client;
|
||||
|
||||
@Shadow
|
||||
private double y;
|
||||
|
||||
@Shadow
|
||||
private double cursorDeltaX;
|
||||
|
||||
@Shadow
|
||||
private double cursorDeltaY;
|
||||
|
||||
@Shadow
|
||||
private double x;
|
||||
|
||||
@Shadow
|
||||
private boolean cursorLocked;
|
||||
|
||||
@Shadow
|
||||
private boolean hasResolutionChanged;
|
||||
|
||||
@Shadow
|
||||
private double lastMouseUpdateTime;
|
||||
|
||||
@Shadow
|
||||
@Final
|
||||
private SmoothUtil cursorXSmoother;
|
||||
|
||||
@Shadow
|
||||
@Final
|
||||
private SmoothUtil cursorYSmoother;
|
||||
|
||||
@Shadow private boolean leftButtonClicked;
|
||||
|
||||
@Accessor
|
||||
public abstract void setLeftButtonClicked(boolean value);
|
||||
|
||||
@@ -67,4 +104,37 @@ public abstract class MouseMixin implements MouseAccessor {
|
||||
||*/ (MidnightControlsConfig.controlsMode == ControlsMode.CONTROLLER && MidnightControlsConfig.virtualMouse))
|
||||
ci.cancel();
|
||||
}
|
||||
|
||||
@Inject(method = "updateMouse", at = @At("HEAD"), cancellable = true)
|
||||
private void updateMouse(CallbackInfo ci) {
|
||||
if (MidnightControlsConfig.eyeTrackerAsMouse && cursorLocked && client.isWindowFocused()) {
|
||||
//Eye Tracking is only for the camera controlling cursor, we need the normal cursor everywhere else.
|
||||
if (!client.options.smoothCameraEnabled) {
|
||||
cursorXSmoother.clear();
|
||||
cursorYSmoother.clear();
|
||||
}
|
||||
EyeTrackerHandler.updateMouseWithEyeTracking(x + cursorDeltaX, y + cursorDeltaY, client,
|
||||
lastMouseUpdateTime, leftButtonClicked, cursorXSmoother, cursorYSmoother);
|
||||
lastMouseUpdateTime = GlfwUtil.getTime();
|
||||
cursorDeltaX = 0.0;
|
||||
cursorDeltaY = 0.0;
|
||||
ci.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(method = "lockCursor", at = @At("HEAD"), cancellable = true)
|
||||
private void lockCursor(CallbackInfo ci) {
|
||||
if (MidnightControlsConfig.eyeTrackerAsMouse && client.isWindowFocused() && !this.cursorLocked) {
|
||||
if (!MinecraftClient.IS_SYSTEM_MAC) {
|
||||
KeyBinding.updatePressedStates();
|
||||
}
|
||||
//In eye tracking mode, we cannot have the cursor locked to the center.
|
||||
GLFW.glfwSetInputMode(client.getWindow().getHandle(), GLFW_CURSOR, GLFW_CURSOR_HIDDEN);
|
||||
cursorLocked = true; //The game uses this flag for other gameplay checks
|
||||
client.setScreen(null);
|
||||
hasResolutionChanged = true;
|
||||
ci.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user