From e37409d4669e26fea064f6acb168570687754226 Mon Sep 17 00:00:00 2001 From: UniversePM Date: Wed, 26 Aug 2026 16:14:02 -0500 Subject: [PATCH] i can feel it in my bones ts will not work --- Minecraft.Client/Minecraft.Client.vcxproj | 44 ++ Minecraft.Client/Windows64/KBMInput.cpp | 429 ++++++++++++++++++ Minecraft.Client/Windows64/KBMInput.h | 153 +++++++ .../Windows64/Windows64_Minecraft.cpp | 20 + 4 files changed, 646 insertions(+) create mode 100644 Minecraft.Client/Windows64/KBMInput.cpp create mode 100644 Minecraft.Client/Windows64/KBMInput.h diff --git a/Minecraft.Client/Minecraft.Client.vcxproj b/Minecraft.Client/Minecraft.Client.vcxproj index 85d1718c..900d8c1f 100644 --- a/Minecraft.Client/Minecraft.Client.vcxproj +++ b/Minecraft.Client/Minecraft.Client.vcxproj @@ -28784,6 +28784,50 @@ xcopy /q /y /i /s /e $(ProjectDir)Durango\CU $(LayoutDir)Image\Loose\CUtrue true + + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + false + false + false + false + false + false + false + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true true diff --git a/Minecraft.Client/Windows64/KBMInput.cpp b/Minecraft.Client/Windows64/KBMInput.cpp new file mode 100644 index 00000000..daad5063 --- /dev/null +++ b/Minecraft.Client/Windows64/KBMInput.cpp @@ -0,0 +1,429 @@ +#include "stdafx.h" + + +#include "KBMInput.h" +#include + +KeyboardMouseInput g_KBMInput; + +extern HWND g_hWnd; + +// Forward declaration +static void ClipCursorToWindow(HWND hWnd); + +static bool IsModifierKeyDown(const bool* keyState, int vkCode) +{ + switch (vkCode) + { + case VK_SHIFT: + return keyState[VK_LSHIFT] || keyState[VK_RSHIFT]; + case VK_CONTROL: + return keyState[VK_LCONTROL] || keyState[VK_RCONTROL]; + case VK_MENU: + return keyState[VK_LMENU] || keyState[VK_RMENU]; + default: + return false; + } +} + +void KeyboardMouseInput::Init() +{ + memset(m_keyDown, 0, sizeof(m_keyDown)); + memset(m_keyDownPrev, 0, sizeof(m_keyDownPrev)); + memset(m_keyPressedAccum, 0, sizeof(m_keyPressedAccum)); + memset(m_keyReleasedAccum, 0, sizeof(m_keyReleasedAccum)); + memset(m_keyPressed, 0, sizeof(m_keyPressed)); + memset(m_keyReleased, 0, sizeof(m_keyReleased)); + memset(m_mouseButtonDown, 0, sizeof(m_mouseButtonDown)); + memset(m_mouseButtonDownPrev, 0, sizeof(m_mouseButtonDownPrev)); + memset(m_mouseBtnPressedAccum, 0, sizeof(m_mouseBtnPressedAccum)); + memset(m_mouseBtnReleasedAccum, 0, sizeof(m_mouseBtnReleasedAccum)); + memset(m_mouseBtnPressed, 0, sizeof(m_mouseBtnPressed)); + memset(m_mouseBtnReleased, 0, sizeof(m_mouseBtnReleased)); + m_mouseX = 0; + m_mouseY = 0; + m_mouseDeltaX = 0; + m_mouseDeltaY = 0; + m_mouseDeltaAccumX = 0; + m_mouseDeltaAccumY = 0; + m_mouseWheelAccum = 0; + m_mouseWheelConsumed = false; + m_mouseGrabbed = false; + m_cursorHiddenForUI = false; + m_windowFocused = true; + m_hasInput = false; + m_kbmActive = true; + m_screenWantsCursorHidden = false; + m_charBufferHead = 0; + m_charBufferTail = 0; + + RAWINPUTDEVICE rid; + rid.usUsagePage = 0x01; // HID_USAGE_PAGE_GENERIC + rid.usUsage = 0x02; // HID_USAGE_GENERIC_MOUSE + rid.dwFlags = 0; + rid.hwndTarget = g_hWnd; + RegisterRawInputDevices(&rid, 1, sizeof(rid)); +} + +void KeyboardMouseInput::ClearAllState() +{ + memset(m_keyDown, 0, sizeof(m_keyDown)); + memset(m_keyDownPrev, 0, sizeof(m_keyDownPrev)); + memset(m_keyPressedAccum, 0, sizeof(m_keyPressedAccum)); + memset(m_keyReleasedAccum, 0, sizeof(m_keyReleasedAccum)); + memset(m_keyPressed, 0, sizeof(m_keyPressed)); + memset(m_keyReleased, 0, sizeof(m_keyReleased)); + memset(m_mouseButtonDown, 0, sizeof(m_mouseButtonDown)); + memset(m_mouseButtonDownPrev, 0, sizeof(m_mouseButtonDownPrev)); + memset(m_mouseBtnPressedAccum, 0, sizeof(m_mouseBtnPressedAccum)); + memset(m_mouseBtnReleasedAccum, 0, sizeof(m_mouseBtnReleasedAccum)); + memset(m_mouseBtnPressed, 0, sizeof(m_mouseBtnPressed)); + memset(m_mouseBtnReleased, 0, sizeof(m_mouseBtnReleased)); + m_mouseDeltaX = 0; + m_mouseDeltaY = 0; + m_mouseDeltaAccumX = 0; + m_mouseDeltaAccumY = 0; + m_mouseWheelAccum = 0; + m_mouseWheelConsumed = false; +} + +void KeyboardMouseInput::Tick() +{ + memcpy(m_keyDownPrev, m_keyDown, sizeof(m_keyDown)); + memcpy(m_mouseButtonDownPrev, m_mouseButtonDown, sizeof(m_mouseButtonDown)); + + memcpy(m_keyPressed, m_keyPressedAccum, sizeof(m_keyPressedAccum)); + memcpy(m_keyReleased, m_keyReleasedAccum, sizeof(m_keyReleasedAccum)); + memset(m_keyPressedAccum, 0, sizeof(m_keyPressedAccum)); + memset(m_keyReleasedAccum, 0, sizeof(m_keyReleasedAccum)); + + memcpy(m_mouseBtnPressed, m_mouseBtnPressedAccum, sizeof(m_mouseBtnPressedAccum)); + memcpy(m_mouseBtnReleased, m_mouseBtnReleasedAccum, sizeof(m_mouseBtnReleasedAccum)); + memset(m_mouseBtnPressedAccum, 0, sizeof(m_mouseBtnPressedAccum)); + memset(m_mouseBtnReleasedAccum, 0, sizeof(m_mouseBtnReleasedAccum)); + + m_mouseDeltaX = m_mouseDeltaAccumX; + m_mouseDeltaY = m_mouseDeltaAccumY; + m_mouseDeltaAccumX = 0; + m_mouseDeltaAccumY = 0; + m_mouseWheelConsumed = false; + + m_hasInput = (m_mouseDeltaX != 0 || m_mouseDeltaY != 0 || m_mouseWheelAccum != 0); + if (!m_hasInput) + { + for (int i = 0; i < MAX_KEYS; i++) + { + if (m_keyDown[i]) { m_hasInput = true; break; } + } + } + if (!m_hasInput) + { + for (int i = 0; i < MAX_MOUSE_BUTTONS; i++) + { + if (m_mouseButtonDown[i]) { m_hasInput = true; break; } + } + } + + if ((m_mouseGrabbed || m_cursorHiddenForUI) && m_windowFocused && g_hWnd) + { + RECT rc; + GetClientRect(g_hWnd, &rc); + POINT center; + center.x = (rc.right - rc.left) / 2; + center.y = (rc.bottom - rc.top) / 2; + ClientToScreen(g_hWnd, ¢er); + SetCursorPos(center.x, center.y); + } +} + +void KeyboardMouseInput::OnKeyDown(int vkCode) +{ + if (vkCode >= 0 && vkCode < MAX_KEYS) + { + if (!m_keyDown[vkCode]) + m_keyPressedAccum[vkCode] = true; + m_keyDown[vkCode] = true; + } +} + +void KeyboardMouseInput::OnKeyUp(int vkCode) +{ + if (vkCode >= 0 && vkCode < MAX_KEYS) + { + if (m_keyDown[vkCode]) + m_keyReleasedAccum[vkCode] = true; + m_keyDown[vkCode] = false; + } +} + +void KeyboardMouseInput::OnMouseButtonDown(int button) +{ + if (button >= 0 && button < MAX_MOUSE_BUTTONS) + { + if (!m_mouseButtonDown[button]) + m_mouseBtnPressedAccum[button] = true; + m_mouseButtonDown[button] = true; + } +} + +void KeyboardMouseInput::OnMouseButtonUp(int button) +{ + if (button >= 0 && button < MAX_MOUSE_BUTTONS) + { + if (m_mouseButtonDown[button]) + m_mouseBtnReleasedAccum[button] = true; + m_mouseButtonDown[button] = false; + } +} + +void KeyboardMouseInput::OnMouseMove(int x, int y) +{ + m_mouseX = x; + m_mouseY = y; +} + +void KeyboardMouseInput::OnMouseWheel(int delta) +{ + // Normalize from raw Windows delta (multiples of WHEEL_DELTA=120) to discrete notch counts + m_mouseWheelAccum += delta / WHEEL_DELTA; +} + +int KeyboardMouseInput::GetMouseWheel() +{ + int val = m_mouseWheelAccum; + if (val != 0) + m_mouseWheelConsumed = true; + m_mouseWheelAccum = 0; + return val; +} + +void KeyboardMouseInput::OnRawMouseDelta(int dx, int dy) +{ + m_mouseDeltaAccumX += dx; + m_mouseDeltaAccumY += dy; +} + +bool KeyboardMouseInput::IsKeyDown(int vkCode) const +{ + if (vkCode == VK_SHIFT || vkCode == VK_CONTROL || vkCode == VK_MENU) + return IsModifierKeyDown(m_keyDown, vkCode); + + if (vkCode >= 0 && vkCode < MAX_KEYS) + return m_keyDown[vkCode]; + return false; +} + +bool KeyboardMouseInput::IsKeyPressed(int vkCode) const +{ + if (vkCode == VK_SHIFT || vkCode == VK_CONTROL || vkCode == VK_MENU) + return IsModifierKeyDown(m_keyPressed, vkCode); + + if (vkCode >= 0 && vkCode < MAX_KEYS) + return m_keyPressed[vkCode]; + return false; +} + +bool KeyboardMouseInput::IsKeyReleased(int vkCode) const +{ + if (vkCode == VK_SHIFT || vkCode == VK_CONTROL || vkCode == VK_MENU) + return IsModifierKeyDown(m_keyReleased, vkCode); + + if (vkCode >= 0 && vkCode < MAX_KEYS) + return m_keyReleased[vkCode]; + return false; +} + +int KeyboardMouseInput::GetPressedKey() const +{ + for (int i = 0; i < MAX_KEYS; ++i) + if (m_keyPressed[i]) return i; + return 0; +} + +bool KeyboardMouseInput::IsMouseButtonDown(int button) const +{ + if (button >= 0 && button < MAX_MOUSE_BUTTONS) + return m_mouseButtonDown[button]; + return false; +} + +bool KeyboardMouseInput::IsMouseButtonPressed(int button) const +{ + if (button >= 0 && button < MAX_MOUSE_BUTTONS) + return m_mouseBtnPressed[button]; + return false; +} + +bool KeyboardMouseInput::IsMouseButtonReleased(int button) const +{ + if (button >= 0 && button < MAX_MOUSE_BUTTONS) + return m_mouseBtnReleased[button]; + return false; +} + +void KeyboardMouseInput::ConsumeMouseDelta(float &dx, float &dy) +{ + dx = static_cast(m_mouseDeltaAccumX); + dy = static_cast(m_mouseDeltaAccumY); + m_mouseDeltaAccumX = 0; + m_mouseDeltaAccumY = 0; +} + +void KeyboardMouseInput::SetMouseGrabbed(bool grabbed) +{ + if (m_mouseGrabbed == grabbed) + return; + + m_mouseGrabbed = grabbed; + if (grabbed && g_hWnd) + { + while (ShowCursor(FALSE) >= 0) {} + ClipCursorToWindow(g_hWnd); + + RECT rc; + GetClientRect(g_hWnd, &rc); + POINT center; + center.x = (rc.right - rc.left) / 2; + center.y = (rc.bottom - rc.top) / 2; + ClientToScreen(g_hWnd, ¢er); + SetCursorPos(center.x, center.y); + + m_mouseDeltaAccumX = 0; + m_mouseDeltaAccumY = 0; + } + else if (!grabbed && !m_cursorHiddenForUI && g_hWnd) + { + while (ShowCursor(TRUE) < 0) {} + ClipCursor(nullptr); + } +} + +void KeyboardMouseInput::SetCursorHiddenForUI(bool hidden) +{ + if (m_cursorHiddenForUI == hidden) + return; + + m_cursorHiddenForUI = hidden; + if (hidden && g_hWnd) + { + while (ShowCursor(FALSE) >= 0) {} + ClipCursorToWindow(g_hWnd); + + RECT rc; + GetClientRect(g_hWnd, &rc); + POINT center; + center.x = (rc.right - rc.left) / 2; + center.y = (rc.bottom - rc.top) / 2; + ClientToScreen(g_hWnd, ¢er); + SetCursorPos(center.x, center.y); + + m_mouseDeltaAccumX = 0; + m_mouseDeltaAccumY = 0; + } + else if (!hidden && !m_mouseGrabbed && g_hWnd) + { + while (ShowCursor(TRUE) < 0) {} + ClipCursor(nullptr); + } +} + +static void ClipCursorToWindow(HWND hWnd) +{ + if (!hWnd) return; + RECT rc; + GetClientRect(hWnd, &rc); + POINT topLeft = { rc.left, rc.top }; + POINT bottomRight = { rc.right, rc.bottom }; + ClientToScreen(hWnd, &topLeft); + ClientToScreen(hWnd, &bottomRight); + RECT clipRect = { topLeft.x, topLeft.y, bottomRight.x, bottomRight.y }; + ClipCursor(&clipRect); +} + +void KeyboardMouseInput::SetWindowFocused(bool focused) +{ + m_windowFocused = focused; + if (focused) + { + if (m_mouseGrabbed || m_cursorHiddenForUI) + { + while (ShowCursor(FALSE) >= 0) {} + ClipCursorToWindow(g_hWnd); + } + else + { + while (ShowCursor(TRUE) < 0) {} + ClipCursor(nullptr); + } + } + else + { + while (ShowCursor(TRUE) < 0) {} + ClipCursor(nullptr); + } +} + +float KeyboardMouseInput::GetMoveX() const +{ + float x = 0.0f; + if (m_keyDown[KEY_LEFT]) x += 1.0f; + if (m_keyDown[KEY_RIGHT]) x -= 1.0f; + return x; +} + +float KeyboardMouseInput::GetMoveY() const +{ + float y = 0.0f; + if (m_keyDown[KEY_FORWARD]) y += 1.0f; + if (m_keyDown[KEY_BACKWARD]) y -= 1.0f; + return y; +} + +float KeyboardMouseInput::GetLookX(float sensitivity) const +{ + return static_cast(m_mouseDeltaX) * sensitivity; +} + +float KeyboardMouseInput::GetLookY(float sensitivity) const +{ + return static_cast(-m_mouseDeltaY) * sensitivity; +} + +void KeyboardMouseInput::SetCursorIcon(LPCWSTR cursorName) +{ + HCURSOR hCursor = LoadCursorW(nullptr, cursorName); + if (hCursor) + { + SetCursor(hCursor); + + if (g_hWnd) + { + SetClassLongPtrW(g_hWnd, GCLP_HCURSOR, (LONG_PTR)hCursor); + } + } +} + +void KeyboardMouseInput::OnChar(wchar_t c) +{ + int next = (m_charBufferHead + 1) % CHAR_BUFFER_SIZE; + if (next != m_charBufferTail) + { + m_charBuffer[m_charBufferHead] = c; + m_charBufferHead = next; + } +} + +bool KeyboardMouseInput::ConsumeChar(wchar_t &outChar) +{ + if (m_charBufferTail == m_charBufferHead) + return false; + outChar = m_charBuffer[m_charBufferTail]; + m_charBufferTail = (m_charBufferTail + 1) % CHAR_BUFFER_SIZE; + return true; +} + +void KeyboardMouseInput::ClearCharBuffer() +{ + m_charBufferHead = 0; + m_charBufferTail = 0; +} diff --git a/Minecraft.Client/Windows64/KBMInput.h b/Minecraft.Client/Windows64/KBMInput.h new file mode 100644 index 00000000..ec8343d3 --- /dev/null +++ b/Minecraft.Client/Windows64/KBMInput.h @@ -0,0 +1,153 @@ +#pragma once + +#include + +class KeyboardMouseInput +{ +public: + static const int MAX_KEYS = 256; + + static const int MOUSE_LEFT = 0; + static const int MOUSE_RIGHT = 1; + static const int MOUSE_MIDDLE = 2; + static const int MAX_MOUSE_BUTTONS = 3; + + static const int KEY_FORWARD = 'W'; + static const int KEY_BACKWARD = 'S'; + static const int KEY_LEFT = 'A'; + static const int KEY_RIGHT = 'D'; + static const int KEY_JUMP = VK_SPACE; + static const int KEY_SNEAK = VK_LSHIFT; + static const int KEY_SPRINT = VK_CONTROL; + static const int KEY_INVENTORY = 'E'; + static const int KEY_DROP = 'Q'; + static const int KEY_CRAFTING = 'C'; + static const int KEY_CRAFTING_ALT = 'R'; + static const int KEY_CHAT = 'T'; + static const int KEY_CONFIRM = VK_RETURN; + static const int KEY_CANCEL = VK_ESCAPE; + static const int KEY_PAUSE = VK_ESCAPE; + static const int KEY_TOGGLE_HUD = VK_F1; + static const int KEY_DEBUG_INFO = VK_F3; + static const int KEY_DEBUG_MENU = VK_F4; + static const int KEY_CONTROL = VK_CONTROL; + static const int KEY_THIRD_PERSON = VK_F5; + static const int KEY_DEBUG_CONSOLE = VK_F6; + static const int KEY_HOST_SETTINGS = VK_TAB; + static const int KEY_FULLSCREEN = VK_F11; + static const int KEY_SCREENSHOT = VK_F2; + + void Init(); + void Tick(); + void ClearAllState(); + + void OnKeyDown(int vkCode); + void OnKeyUp(int vkCode); + void OnMouseButtonDown(int button); + void OnMouseButtonUp(int button); + void OnMouseMove(int x, int y); + void OnMouseWheel(int delta); + void OnRawMouseDelta(int dx, int dy); + + bool IsKeyDown(int vkCode) const; + bool IsKeyPressed(int vkCode) const; + bool IsKeyReleased(int vkCode) const; + + int GetPressedKey() const; + + bool IsMouseButtonDown(int button) const; + bool IsMouseButtonPressed(int button) const; + bool IsMouseButtonReleased(int button) const; + + int GetMouseX() const { return m_mouseX; } + int GetMouseY() const { return m_mouseY; } + + int GetMouseDeltaX() const { return m_mouseDeltaX; } + int GetMouseDeltaY() const { return m_mouseDeltaY; } + + int GetMouseWheel(); + int PeekMouseWheel() const { return m_mouseWheelAccum; } + void ConsumeMouseWheel() { if (m_mouseWheelAccum != 0) m_mouseWheelConsumed = true; m_mouseWheelAccum = 0; } + bool WasMouseWheelConsumed() const { return m_mouseWheelConsumed; } + + // Per-frame delta consumption for low-latency mouse look. + // Reads and clears the raw accumulators (not the per-tick snapshot). + void ConsumeMouseDelta(float &dx, float &dy); + + void SetMouseGrabbed(bool grabbed); + bool IsMouseGrabbed() const { return m_mouseGrabbed; } + + void SetCursorHiddenForUI(bool hidden); + bool IsCursorHiddenForUI() const { return m_cursorHiddenForUI; } + + void SetWindowFocused(bool focused); + bool IsWindowFocused() const { return m_windowFocused; } + + bool HasAnyInput() const { return m_hasInput; } + + void SetKBMActive(bool active) { m_kbmActive = active; } + bool IsKBMActive() const { return m_kbmActive; } + + void SetScreenCursorHidden(bool hidden) { m_screenWantsCursorHidden = hidden; } + bool IsScreenCursorHidden() const { return m_screenWantsCursorHidden; } + + // Text input: buffer characters typed while the native keyboard scene is open + void OnChar(wchar_t c); + bool ConsumeChar(wchar_t &outChar); + void ClearCharBuffer(); + + float GetMoveX() const; + float GetMoveY() const; + + float GetLookX(float sensitivity) const; + float GetLookY(float sensitivity) const; + + void SetCursorIcon(LPCWSTR cursorName); + +private: + bool m_keyDown[MAX_KEYS]; + bool m_keyDownPrev[MAX_KEYS]; + + bool m_keyPressedAccum[MAX_KEYS]; + bool m_keyReleasedAccum[MAX_KEYS]; + bool m_keyPressed[MAX_KEYS]; + bool m_keyReleased[MAX_KEYS]; + + bool m_mouseButtonDown[MAX_MOUSE_BUTTONS]; + bool m_mouseButtonDownPrev[MAX_MOUSE_BUTTONS]; + + bool m_mouseBtnPressedAccum[MAX_MOUSE_BUTTONS]; + bool m_mouseBtnReleasedAccum[MAX_MOUSE_BUTTONS]; + bool m_mouseBtnPressed[MAX_MOUSE_BUTTONS]; + bool m_mouseBtnReleased[MAX_MOUSE_BUTTONS]; + + int m_mouseX; + int m_mouseY; + + int m_mouseDeltaX; + int m_mouseDeltaY; + int m_mouseDeltaAccumX; + int m_mouseDeltaAccumY; + + int m_mouseWheelAccum; + bool m_mouseWheelConsumed; + + bool m_mouseGrabbed; + + bool m_cursorHiddenForUI; + + bool m_windowFocused; + + bool m_hasInput; + + bool m_kbmActive; + + bool m_screenWantsCursorHidden; + + static const int CHAR_BUFFER_SIZE = 32; + wchar_t m_charBuffer[CHAR_BUFFER_SIZE]; + int m_charBufferHead; + int m_charBufferTail; +}; + +extern KeyboardMouseInput g_KBMInput; diff --git a/Minecraft.Client/Windows64/Windows64_Minecraft.cpp b/Minecraft.Client/Windows64/Windows64_Minecraft.cpp index 836f23e4..35f89393 100644 --- a/Minecraft.Client/Windows64/Windows64_Minecraft.cpp +++ b/Minecraft.Client/Windows64/Windows64_Minecraft.cpp @@ -20,6 +20,7 @@ #include "..\..\Minecraft.World\net.minecraft.world.level.tile.h" #include "..\ClientConnection.h" +#include "KBMInput.h" #include "..\User.h" #include "..\..\Minecraft.World\Socket.h" #include "..\..\Minecraft.World\ThreadName.h" @@ -842,6 +843,25 @@ int APIENTRY _tWinMain(_In_ HINSTANCE hInstance, { InputManager.Tick(); } + + if (InputManager.IsPadConnected(0)) + { + const bool controllerUsed = InputManager.ButtonPressed(0) || + InputManager.GetJoypadStick_LX(0, false) != 0.0f || + InputManager.GetJoypadStick_LY(0, false) != 0.0f || + InputManager.GetJoypadStick_RX(0, false) != 0.0f || + InputManager.GetJoypadStick_RY(0, false) != 0.0f; + + if (controllerUsed) { + g_KBMInput.SetKBMActive(false); + //if (ui.FindScene(eUIScene_BookMenu) != nullptr) ui.FindScene(eUIScene_BookMenu)->KBMUpdate(false); + } + else if (g_KBMInput.HasAnyInput()) { + g_KBMInput.SetKBMActive(true); + //if (ui.FindScene(eUIScene_BookMenu) != nullptr) ui.FindScene(eUIScene_BookMenu)->KBMUpdate(true); + } + } + PIXEndNamedEvent(); /*PIXBeginNamedEvent(0,"Profile manager tick"); ProfileManager.Tick();