466 lines
		
	
	
	
		
			14 KiB
		
	
	
	
		
			Java
		
	
	
	
	
	
			
		
		
	
	
			466 lines
		
	
	
	
		
			14 KiB
		
	
	
	
		
			Java
		
	
	
	
	
	
| package net.minecraft.client;
 | |
| 
 | |
| import com.mojang.blaze3d.Blaze3D;
 | |
| import com.mojang.blaze3d.platform.InputConstants;
 | |
| import com.mojang.blaze3d.platform.Window;
 | |
| import com.mojang.logging.LogUtils;
 | |
| import java.nio.file.InvalidPathException;
 | |
| import java.nio.file.Path;
 | |
| import java.nio.file.Paths;
 | |
| import java.util.ArrayList;
 | |
| import java.util.List;
 | |
| import java.util.Locale;
 | |
| import net.fabricmc.api.EnvType;
 | |
| import net.fabricmc.api.Environment;
 | |
| import net.minecraft.CrashReport;
 | |
| import net.minecraft.CrashReportCategory;
 | |
| import net.minecraft.CrashReportDetail;
 | |
| import net.minecraft.ReportedException;
 | |
| import net.minecraft.client.gui.Font;
 | |
| import net.minecraft.client.gui.GuiGraphics;
 | |
| import net.minecraft.client.gui.components.toasts.SystemToast;
 | |
| import net.minecraft.client.gui.screens.Screen;
 | |
| import net.minecraft.util.Mth;
 | |
| import net.minecraft.util.SmoothDouble;
 | |
| import net.minecraft.world.entity.player.Inventory;
 | |
| import org.joml.Vector2i;
 | |
| import org.lwjgl.glfw.GLFWDropCallback;
 | |
| import org.slf4j.Logger;
 | |
| 
 | |
| @Environment(EnvType.CLIENT)
 | |
| public class MouseHandler {
 | |
| 	private static final Logger LOGGER = LogUtils.getLogger();
 | |
| 	private final Minecraft minecraft;
 | |
| 	private boolean isLeftPressed;
 | |
| 	private boolean isMiddlePressed;
 | |
| 	private boolean isRightPressed;
 | |
| 	private double xpos;
 | |
| 	private double ypos;
 | |
| 	private int fakeRightMouse;
 | |
| 	private int activeButton = -1;
 | |
| 	private boolean ignoreFirstMove = true;
 | |
| 	private int clickDepth;
 | |
| 	private double mousePressedTime;
 | |
| 	private final SmoothDouble smoothTurnX = new SmoothDouble();
 | |
| 	private final SmoothDouble smoothTurnY = new SmoothDouble();
 | |
| 	private double accumulatedDX;
 | |
| 	private double accumulatedDY;
 | |
| 	private final ScrollWheelHandler scrollWheelHandler;
 | |
| 	private double lastHandleMovementTime = Double.MIN_VALUE;
 | |
| 	private boolean mouseGrabbed;
 | |
| 
 | |
| 	public MouseHandler(Minecraft minecraft) {
 | |
| 		this.minecraft = minecraft;
 | |
| 		this.scrollWheelHandler = new ScrollWheelHandler();
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Will be called when a mouse button is pressed or released.
 | |
| 	 * 
 | |
| 	 * @see GLFWMouseButtonCallbackI
 | |
| 	 */
 | |
| 	private void onPress(long windowPointer, int button, int action, int modifiers) {
 | |
| 		Window window = this.minecraft.getWindow();
 | |
| 		if (windowPointer == window.getWindow()) {
 | |
| 			this.minecraft.getFramerateLimitTracker().onInputReceived();
 | |
| 			if (this.minecraft.screen != null) {
 | |
| 				this.minecraft.setLastInputType(InputType.MOUSE);
 | |
| 			}
 | |
| 
 | |
| 			boolean bl = action == 1;
 | |
| 			if (Minecraft.ON_OSX && button == 0) {
 | |
| 				if (bl) {
 | |
| 					if ((modifiers & 2) == 2) {
 | |
| 						button = 1;
 | |
| 						this.fakeRightMouse++;
 | |
| 					}
 | |
| 				} else if (this.fakeRightMouse > 0) {
 | |
| 					button = 1;
 | |
| 					this.fakeRightMouse--;
 | |
| 				}
 | |
| 			}
 | |
| 
 | |
| 			int i = button;
 | |
| 			if (bl) {
 | |
| 				if (this.minecraft.options.touchscreen().get() && this.clickDepth++ > 0) {
 | |
| 					return;
 | |
| 				}
 | |
| 
 | |
| 				this.activeButton = button;
 | |
| 				this.mousePressedTime = Blaze3D.getTime();
 | |
| 			} else if (this.activeButton != -1) {
 | |
| 				if (this.minecraft.options.touchscreen().get() && --this.clickDepth > 0) {
 | |
| 					return;
 | |
| 				}
 | |
| 
 | |
| 				this.activeButton = -1;
 | |
| 			}
 | |
| 
 | |
| 			if (this.minecraft.getOverlay() == null) {
 | |
| 				if (this.minecraft.screen == null) {
 | |
| 					if (!this.mouseGrabbed && bl) {
 | |
| 						this.grabMouse();
 | |
| 					}
 | |
| 				} else {
 | |
| 					double d = this.getScaledXPos(window);
 | |
| 					double e = this.getScaledYPos(window);
 | |
| 					Screen screen = this.minecraft.screen;
 | |
| 					if (bl) {
 | |
| 						screen.afterMouseAction();
 | |
| 
 | |
| 						try {
 | |
| 							if (screen.mouseClicked(d, e, i)) {
 | |
| 								return;
 | |
| 							}
 | |
| 						} catch (Throwable var18) {
 | |
| 							CrashReport crashReport = CrashReport.forThrowable(var18, "mouseClicked event handler");
 | |
| 							screen.fillCrashDetails(crashReport);
 | |
| 							CrashReportCategory crashReportCategory = crashReport.addCategory("Mouse");
 | |
| 							this.fillMousePositionDetails(crashReportCategory, window);
 | |
| 							crashReportCategory.setDetail("Button", button);
 | |
| 							throw new ReportedException(crashReport);
 | |
| 						}
 | |
| 					} else {
 | |
| 						try {
 | |
| 							if (screen.mouseReleased(d, e, i)) {
 | |
| 								return;
 | |
| 							}
 | |
| 						} catch (Throwable var17) {
 | |
| 							CrashReport crashReport = CrashReport.forThrowable(var17, "mouseReleased event handler");
 | |
| 							screen.fillCrashDetails(crashReport);
 | |
| 							CrashReportCategory crashReportCategory = crashReport.addCategory("Mouse");
 | |
| 							this.fillMousePositionDetails(crashReportCategory, window);
 | |
| 							crashReportCategory.setDetail("Button", button);
 | |
| 							throw new ReportedException(crashReport);
 | |
| 						}
 | |
| 					}
 | |
| 				}
 | |
| 			}
 | |
| 
 | |
| 			if (this.minecraft.screen == null && this.minecraft.getOverlay() == null) {
 | |
| 				if (button == 0) {
 | |
| 					this.isLeftPressed = bl;
 | |
| 				} else if (button == 2) {
 | |
| 					this.isMiddlePressed = bl;
 | |
| 				} else if (button == 1) {
 | |
| 					this.isRightPressed = bl;
 | |
| 				}
 | |
| 
 | |
| 				KeyMapping.set(InputConstants.Type.MOUSE.getOrCreate(button), bl);
 | |
| 				if (bl) {
 | |
| 					if (this.minecraft.player.isSpectator() && button == 2) {
 | |
| 						this.minecraft.gui.getSpectatorGui().onMouseMiddleClick();
 | |
| 					} else {
 | |
| 						KeyMapping.click(InputConstants.Type.MOUSE.getOrCreate(button));
 | |
| 					}
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	public void fillMousePositionDetails(CrashReportCategory category, Window window) {
 | |
| 		category.setDetail(
 | |
| 			"Mouse location",
 | |
| 			(CrashReportDetail<String>)(() -> String.format(
 | |
| 				Locale.ROOT, "Scaled: (%f, %f). Absolute: (%f, %f)", getScaledXPos(window, this.xpos), getScaledYPos(window, this.ypos), this.xpos, this.ypos
 | |
| 			))
 | |
| 		);
 | |
| 		category.setDetail(
 | |
| 			"Screen size",
 | |
| 			(CrashReportDetail<String>)(() -> String.format(
 | |
| 				Locale.ROOT,
 | |
| 				"Scaled: (%d, %d). Absolute: (%d, %d). Scale factor of %f",
 | |
| 				window.getGuiScaledWidth(),
 | |
| 				window.getGuiScaledHeight(),
 | |
| 				window.getWidth(),
 | |
| 				window.getHeight(),
 | |
| 				window.getGuiScale()
 | |
| 			))
 | |
| 		);
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Will be called when a scrolling device is used, such as a mouse wheel or scrolling area of a touchpad.
 | |
| 	 * 
 | |
| 	 * @see GLFWScrollCallbackI
 | |
| 	 */
 | |
| 	private void onScroll(long windowPointer, double xOffset, double yOffset) {
 | |
| 		if (windowPointer == Minecraft.getInstance().getWindow().getWindow()) {
 | |
| 			this.minecraft.getFramerateLimitTracker().onInputReceived();
 | |
| 			boolean bl = this.minecraft.options.discreteMouseScroll().get();
 | |
| 			double d = this.minecraft.options.mouseWheelSensitivity().get();
 | |
| 			double e = (bl ? Math.signum(xOffset) : xOffset) * d;
 | |
| 			double f = (bl ? Math.signum(yOffset) : yOffset) * d;
 | |
| 			if (this.minecraft.getOverlay() == null) {
 | |
| 				if (this.minecraft.screen != null) {
 | |
| 					double g = this.getScaledXPos(this.minecraft.getWindow());
 | |
| 					double h = this.getScaledYPos(this.minecraft.getWindow());
 | |
| 					this.minecraft.screen.mouseScrolled(g, h, e, f);
 | |
| 					this.minecraft.screen.afterMouseAction();
 | |
| 				} else if (this.minecraft.player != null) {
 | |
| 					Vector2i vector2i = this.scrollWheelHandler.onMouseScroll(e, f);
 | |
| 					if (vector2i.x == 0 && vector2i.y == 0) {
 | |
| 						return;
 | |
| 					}
 | |
| 
 | |
| 					int i = vector2i.y == 0 ? -vector2i.x : vector2i.y;
 | |
| 					if (this.minecraft.player.isSpectator()) {
 | |
| 						if (this.minecraft.gui.getSpectatorGui().isMenuActive()) {
 | |
| 							this.minecraft.gui.getSpectatorGui().onMouseScrolled(-i);
 | |
| 						} else {
 | |
| 							float j = Mth.clamp(this.minecraft.player.getAbilities().getFlyingSpeed() + vector2i.y * 0.005F, 0.0F, 0.2F);
 | |
| 							this.minecraft.player.getAbilities().setFlyingSpeed(j);
 | |
| 						}
 | |
| 					} else {
 | |
| 						Inventory inventory = this.minecraft.player.getInventory();
 | |
| 						inventory.setSelectedSlot(ScrollWheelHandler.getNextScrollWheelSelection(i, inventory.getSelectedSlot(), Inventory.getSelectionSize()));
 | |
| 					}
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	private void onDrop(long windowPointer, List<Path> files, int failedFiles) {
 | |
| 		this.minecraft.getFramerateLimitTracker().onInputReceived();
 | |
| 		if (this.minecraft.screen != null) {
 | |
| 			this.minecraft.screen.onFilesDrop(files);
 | |
| 		}
 | |
| 
 | |
| 		if (failedFiles > 0) {
 | |
| 			SystemToast.onFileDropFailure(this.minecraft, failedFiles);
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	public void setup(long windowPointer) {
 | |
| 		InputConstants.setupMouseCallbacks(
 | |
| 			windowPointer,
 | |
| 			(l, d, e) -> this.minecraft.execute(() -> this.onMove(l, d, e)),
 | |
| 			(l, i, j, k) -> this.minecraft.execute(() -> this.onPress(l, i, j, k)),
 | |
| 			(l, d, e) -> this.minecraft.execute(() -> this.onScroll(l, d, e)),
 | |
| 			(l, i, m) -> {
 | |
| 				List<Path> list = new ArrayList(i);
 | |
| 				int j = 0;
 | |
| 
 | |
| 				for (int k = 0; k < i; k++) {
 | |
| 					String string = GLFWDropCallback.getName(m, k);
 | |
| 
 | |
| 					try {
 | |
| 						list.add(Paths.get(string));
 | |
| 					} catch (InvalidPathException var11) {
 | |
| 						j++;
 | |
| 						LOGGER.error("Failed to parse path '{}'", string, var11);
 | |
| 					}
 | |
| 				}
 | |
| 
 | |
| 				if (!list.isEmpty()) {
 | |
| 					int k = j;
 | |
| 					this.minecraft.execute(() -> this.onDrop(l, list, k));
 | |
| 				}
 | |
| 			}
 | |
| 		);
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Will be called when the cursor is moved.
 | |
| 	 * 
 | |
| 	 * <p>The callback function receives the cursor position, measured in screen coordinates but relative to the top-left corner of the window client area. On platforms that provide it, the full sub-pixel cursor position is passed on.</p>
 | |
| 	 * 
 | |
| 	 * @see GLFWCursorPosCallbackI
 | |
| 	 */
 | |
| 	private void onMove(long windowPointer, double xpos, double ypos) {
 | |
| 		if (windowPointer == Minecraft.getInstance().getWindow().getWindow()) {
 | |
| 			if (this.ignoreFirstMove) {
 | |
| 				this.xpos = xpos;
 | |
| 				this.ypos = ypos;
 | |
| 				this.ignoreFirstMove = false;
 | |
| 			} else {
 | |
| 				if (this.minecraft.isWindowActive()) {
 | |
| 					this.accumulatedDX = this.accumulatedDX + (xpos - this.xpos);
 | |
| 					this.accumulatedDY = this.accumulatedDY + (ypos - this.ypos);
 | |
| 				}
 | |
| 
 | |
| 				this.xpos = xpos;
 | |
| 				this.ypos = ypos;
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	public void handleAccumulatedMovement() {
 | |
| 		double d = Blaze3D.getTime();
 | |
| 		double e = d - this.lastHandleMovementTime;
 | |
| 		this.lastHandleMovementTime = d;
 | |
| 		if (this.minecraft.isWindowActive()) {
 | |
| 			Screen screen = this.minecraft.screen;
 | |
| 			boolean bl = this.accumulatedDX != 0.0 || this.accumulatedDY != 0.0;
 | |
| 			if (bl) {
 | |
| 				this.minecraft.getFramerateLimitTracker().onInputReceived();
 | |
| 			}
 | |
| 
 | |
| 			if (screen != null && this.minecraft.getOverlay() == null && bl) {
 | |
| 				Window window = this.minecraft.getWindow();
 | |
| 				double f = this.getScaledXPos(window);
 | |
| 				double g = this.getScaledYPos(window);
 | |
| 
 | |
| 				try {
 | |
| 					screen.mouseMoved(f, g);
 | |
| 				} catch (Throwable var20) {
 | |
| 					CrashReport crashReport = CrashReport.forThrowable(var20, "mouseMoved event handler");
 | |
| 					screen.fillCrashDetails(crashReport);
 | |
| 					CrashReportCategory crashReportCategory = crashReport.addCategory("Mouse");
 | |
| 					this.fillMousePositionDetails(crashReportCategory, window);
 | |
| 					throw new ReportedException(crashReport);
 | |
| 				}
 | |
| 
 | |
| 				if (this.activeButton != -1 && this.mousePressedTime > 0.0) {
 | |
| 					double h = getScaledXPos(window, this.accumulatedDX);
 | |
| 					double i = getScaledYPos(window, this.accumulatedDY);
 | |
| 
 | |
| 					try {
 | |
| 						screen.mouseDragged(f, g, this.activeButton, h, i);
 | |
| 					} catch (Throwable var19) {
 | |
| 						CrashReport crashReport2 = CrashReport.forThrowable(var19, "mouseDragged event handler");
 | |
| 						screen.fillCrashDetails(crashReport2);
 | |
| 						CrashReportCategory crashReportCategory2 = crashReport2.addCategory("Mouse");
 | |
| 						this.fillMousePositionDetails(crashReportCategory2, window);
 | |
| 						throw new ReportedException(crashReport2);
 | |
| 					}
 | |
| 				}
 | |
| 
 | |
| 				screen.afterMouseMove();
 | |
| 			}
 | |
| 
 | |
| 			if (this.isMouseGrabbed() && this.minecraft.player != null) {
 | |
| 				this.turnPlayer(e);
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		this.accumulatedDX = 0.0;
 | |
| 		this.accumulatedDY = 0.0;
 | |
| 	}
 | |
| 
 | |
| 	public static double getScaledXPos(Window window, double xPos) {
 | |
| 		return xPos * window.getGuiScaledWidth() / window.getScreenWidth();
 | |
| 	}
 | |
| 
 | |
| 	public double getScaledXPos(Window window) {
 | |
| 		return getScaledXPos(window, this.xpos);
 | |
| 	}
 | |
| 
 | |
| 	public static double getScaledYPos(Window window, double yPos) {
 | |
| 		return yPos * window.getGuiScaledHeight() / window.getScreenHeight();
 | |
| 	}
 | |
| 
 | |
| 	public double getScaledYPos(Window window) {
 | |
| 		return getScaledYPos(window, this.ypos);
 | |
| 	}
 | |
| 
 | |
| 	private void turnPlayer(double movementTime) {
 | |
| 		double d = this.minecraft.options.sensitivity().get() * 0.6F + 0.2F;
 | |
| 		double e = d * d * d;
 | |
| 		double f = e * 8.0;
 | |
| 		double i;
 | |
| 		double j;
 | |
| 		if (this.minecraft.options.smoothCamera) {
 | |
| 			double g = this.smoothTurnX.getNewDeltaValue(this.accumulatedDX * f, movementTime * f);
 | |
| 			double h = this.smoothTurnY.getNewDeltaValue(this.accumulatedDY * f, movementTime * f);
 | |
| 			i = g;
 | |
| 			j = h;
 | |
| 		} else if (this.minecraft.options.getCameraType().isFirstPerson() && this.minecraft.player.isScoping()) {
 | |
| 			this.smoothTurnX.reset();
 | |
| 			this.smoothTurnY.reset();
 | |
| 			i = this.accumulatedDX * e;
 | |
| 			j = this.accumulatedDY * e;
 | |
| 		} else {
 | |
| 			this.smoothTurnX.reset();
 | |
| 			this.smoothTurnY.reset();
 | |
| 			i = this.accumulatedDX * f;
 | |
| 			j = this.accumulatedDY * f;
 | |
| 		}
 | |
| 
 | |
| 		int k = 1;
 | |
| 		if (this.minecraft.options.invertYMouse().get()) {
 | |
| 			k = -1;
 | |
| 		}
 | |
| 
 | |
| 		this.minecraft.getTutorial().onMouse(i, j);
 | |
| 		if (this.minecraft.player != null) {
 | |
| 			this.minecraft.player.turn(i, j * k);
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	public boolean isLeftPressed() {
 | |
| 		return this.isLeftPressed;
 | |
| 	}
 | |
| 
 | |
| 	public boolean isMiddlePressed() {
 | |
| 		return this.isMiddlePressed;
 | |
| 	}
 | |
| 
 | |
| 	public boolean isRightPressed() {
 | |
| 		return this.isRightPressed;
 | |
| 	}
 | |
| 
 | |
| 	public double xpos() {
 | |
| 		return this.xpos;
 | |
| 	}
 | |
| 
 | |
| 	public double ypos() {
 | |
| 		return this.ypos;
 | |
| 	}
 | |
| 
 | |
| 	public void setIgnoreFirstMove() {
 | |
| 		this.ignoreFirstMove = true;
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Returns {@code true} if the mouse is grabbed.
 | |
| 	 */
 | |
| 	public boolean isMouseGrabbed() {
 | |
| 		return this.mouseGrabbed;
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Will set the focus to in-game if the Minecraft window is the active with focus. Also clears any GUI screen currently displayed
 | |
| 	 */
 | |
| 	public void grabMouse() {
 | |
| 		if (this.minecraft.isWindowActive()) {
 | |
| 			if (!this.mouseGrabbed) {
 | |
| 				if (!Minecraft.ON_OSX) {
 | |
| 					KeyMapping.setAll();
 | |
| 				}
 | |
| 
 | |
| 				this.mouseGrabbed = true;
 | |
| 				this.xpos = this.minecraft.getWindow().getScreenWidth() / 2;
 | |
| 				this.ypos = this.minecraft.getWindow().getScreenHeight() / 2;
 | |
| 				InputConstants.grabOrReleaseMouse(this.minecraft.getWindow().getWindow(), 212995, this.xpos, this.ypos);
 | |
| 				this.minecraft.setScreen(null);
 | |
| 				this.minecraft.missTime = 10000;
 | |
| 				this.ignoreFirstMove = true;
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Resets the player keystate, disables the ingame focus, and ungrabs the mouse cursor.
 | |
| 	 */
 | |
| 	public void releaseMouse() {
 | |
| 		if (this.mouseGrabbed) {
 | |
| 			this.mouseGrabbed = false;
 | |
| 			this.xpos = this.minecraft.getWindow().getScreenWidth() / 2;
 | |
| 			this.ypos = this.minecraft.getWindow().getScreenHeight() / 2;
 | |
| 			InputConstants.grabOrReleaseMouse(this.minecraft.getWindow().getWindow(), 212993, this.xpos, this.ypos);
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	public void cursorEntered() {
 | |
| 		this.ignoreFirstMove = true;
 | |
| 	}
 | |
| 
 | |
| 	public void drawDebugMouseInfo(Font font, GuiGraphics guiGraphics) {
 | |
| 		Window window = this.minecraft.getWindow();
 | |
| 		double d = this.getScaledXPos(window);
 | |
| 		double e = this.getScaledYPos(window) - 8.0;
 | |
| 		String string = String.format(Locale.ROOT, "%.0f,%.0f", d, e);
 | |
| 		guiGraphics.drawString(font, string, (int)d, (int)e, -1);
 | |
| 	}
 | |
| }
 |