aboutsummaryrefslogtreecommitdiff
path: root/Minecraft.Client/Windows64/KeyboardMouseInput.cpp
diff options
context:
space:
mode:
authordaoge_cmd <3523206925@qq.com>2026-03-04 21:19:40 +0800
committerdaoge_cmd <3523206925@qq.com>2026-03-05 01:12:48 +0800
commit1dc8a005ed111463c22c17b487e5ec8a3e2d30f3 (patch)
tree8f1825364bf14178f720ee124b01de78afa16d40 /Minecraft.Client/Windows64/KeyboardMouseInput.cpp
parentac03b88a907bb49f5159f08de07398f3fce32991 (diff)
refactor: refactor KBM input code
Diffstat (limited to 'Minecraft.Client/Windows64/KeyboardMouseInput.cpp')
-rw-r--r--Minecraft.Client/Windows64/KeyboardMouseInput.cpp418
1 files changed, 256 insertions, 162 deletions
diff --git a/Minecraft.Client/Windows64/KeyboardMouseInput.cpp b/Minecraft.Client/Windows64/KeyboardMouseInput.cpp
index df57db44..7ab99a71 100644
--- a/Minecraft.Client/Windows64/KeyboardMouseInput.cpp
+++ b/Minecraft.Client/Windows64/KeyboardMouseInput.cpp
@@ -3,118 +3,158 @@
#ifdef _WINDOWS64
#include "KeyboardMouseInput.h"
+#include <cmath>
-KeyboardMouseInput KMInput;
-
-KeyboardMouseInput::KeyboardMouseInput()
- : m_mouseDeltaXAccum(0.0f)
- , m_mouseDeltaYAccum(0.0f)
- , m_scrollDeltaAccum(0)
- , m_captured(false)
- , m_hWnd(NULL)
- , m_initialized(false)
- , m_mouseX(0)
- , m_mouseY(0)
-{
- memset(m_keyState, 0, sizeof(m_keyState));
- memset(m_keyStatePrev, 0, sizeof(m_keyStatePrev));
- memset(m_mouseButtons, 0, sizeof(m_mouseButtons));
- memset(m_mouseButtonsPrev, 0, sizeof(m_mouseButtonsPrev));
- memset(m_keyPressedAccum, 0, sizeof(m_keyPressedAccum));
- memset(m_mousePressedAccum, 0, sizeof(m_mousePressedAccum));
- memset(m_mouseReleasedAccum, 0, sizeof(m_mouseReleasedAccum));
-}
+KeyboardMouseInput g_KBMInput;
-KeyboardMouseInput::~KeyboardMouseInput()
-{
- if (m_captured)
- {
- SetCapture(false);
- }
-}
+extern HWND g_hWnd;
-void KeyboardMouseInput::Init(HWND hWnd)
+// Forward declaration
+static void ClipCursorToWindow(HWND hWnd);
+
+void KeyboardMouseInput::Init()
{
- m_hWnd = hWnd;
- m_initialized = true;
+ 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_mouseGrabbed = false;
+ m_cursorHiddenForUI = false;
+ m_windowFocused = true;
+ m_hasInput = false;
+ m_kbmActive = true;
+ m_screenWantsCursorHidden = false;
- // Register for raw mouse input
RAWINPUTDEVICE rid;
- rid.usUsagePage = HID_USAGE_PAGE_GENERIC;
- rid.usUsage = HID_USAGE_GENERIC_MOUSE;
+ rid.usUsagePage = 0x01; // HID_USAGE_PAGE_GENERIC
+ rid.usUsage = 0x02; // HID_USAGE_GENERIC_MOUSE
rid.dwFlags = 0;
- rid.hwndTarget = hWnd;
+ rid.hwndTarget = g_hWnd;
RegisterRawInputDevices(&rid, 1, sizeof(rid));
}
-void KeyboardMouseInput::Tick()
+void KeyboardMouseInput::ClearAllState()
{
- // Keep cursor pinned to center while captured
- if (m_captured)
- CenterCursor();
+ 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;
}
-void KeyboardMouseInput::EndFrame()
+void KeyboardMouseInput::Tick()
{
- // Advance previous state for next frame's edge detection.
- // Must be called AFTER all per-frame consumers have read IsKeyPressed/Released etc.
- memcpy(m_keyStatePrev, m_keyState, sizeof(m_keyState));
- memcpy(m_mouseButtonsPrev, m_mouseButtons, sizeof(m_mouseButtons));
-}
+ memcpy(m_keyDownPrev, m_keyDown, sizeof(m_keyDown));
+ memcpy(m_mouseButtonDownPrev, m_mouseButtonDown, sizeof(m_mouseButtonDown));
-void KeyboardMouseInput::OnKeyDown(WPARAM vk)
-{
- if (vk < 256)
+ 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_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) && g_hWnd)
{
- if (!m_keyState[vk]) m_keyPressedAccum[vk] = true;
- m_keyState[vk] = true;
+ 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, &center);
+ SetCursorPos(center.x, center.y);
}
}
-void KeyboardMouseInput::OnKeyUp(WPARAM vk)
+void KeyboardMouseInput::OnKeyDown(int vkCode)
{
- if (vk < 256)
+ if (vkCode >= 0 && vkCode < MAX_KEYS)
{
- m_keyState[vk] = false;
+ if (!m_keyDown[vkCode])
+ m_keyPressedAccum[vkCode] = true;
+ m_keyDown[vkCode] = true;
}
}
-void KeyboardMouseInput::OnRawMouseInput(LPARAM lParam)
+void KeyboardMouseInput::OnKeyUp(int vkCode)
{
- if (!m_captured) return;
-
- UINT dwSize = 0;
- GetRawInputData((HRAWINPUT)lParam, RID_INPUT, NULL, &dwSize, sizeof(RAWINPUTHEADER));
-
- BYTE* lpb = (BYTE*)alloca(dwSize);
- if (GetRawInputData((HRAWINPUT)lParam, RID_INPUT, lpb, &dwSize, sizeof(RAWINPUTHEADER)) != dwSize)
- return;
-
- RAWINPUT* raw = (RAWINPUT*)lpb;
- if (raw->header.dwType == RIM_TYPEMOUSE)
+ if (vkCode >= 0 && vkCode < MAX_KEYS)
{
- if (raw->data.mouse.usFlags == MOUSE_MOVE_RELATIVE)
- {
- m_mouseDeltaXAccum += (float)raw->data.mouse.lLastX;
- m_mouseDeltaYAccum += (float)raw->data.mouse.lLastY;
- }
+ if (m_keyDown[vkCode])
+ m_keyReleasedAccum[vkCode] = true;
+ m_keyDown[vkCode] = false;
}
}
-void KeyboardMouseInput::OnMouseButton(int button, bool down)
+void KeyboardMouseInput::OnMouseButtonDown(int button)
{
- if (ui.IsPauseMenuDisplayed(ProfileManager.GetPrimaryPad())) { return; }
- if (button >= 0 && button < 3)
+ if (button >= 0 && button < MAX_MOUSE_BUTTONS)
{
- if (down && !m_mouseButtons[button]) m_mousePressedAccum[button] = true;
- if (!down && m_mouseButtons[button]) m_mouseReleasedAccum[button] = true;
- m_mouseButtons[button] = down;
+ if (!m_mouseButtonDown[button])
+ m_mouseBtnPressedAccum[button] = true;
+ m_mouseButtonDown[button] = true;
}
}
-void KeyboardMouseInput::OnMouseWheel(int delta)
+void KeyboardMouseInput::OnMouseButtonUp(int button)
{
- m_scrollDeltaAccum += delta;
+ 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)
@@ -123,139 +163,193 @@ void KeyboardMouseInput::OnMouseMove(int x, int y)
m_mouseY = y;
}
-int KeyboardMouseInput::GetMouseX() const { return m_mouseX; }
-int KeyboardMouseInput::GetMouseY() const { return m_mouseY; }
-HWND KeyboardMouseInput::GetHWnd() const { return m_hWnd; }
-
-void KeyboardMouseInput::ClearAllState()
+void KeyboardMouseInput::OnMouseWheel(int delta)
{
- memset(m_keyState, 0, sizeof(m_keyState));
- memset(m_mouseButtons, 0, sizeof(m_mouseButtons));
- memset(m_keyPressedAccum, 0, sizeof(m_keyPressedAccum));
- memset(m_mousePressedAccum, 0, sizeof(m_mousePressedAccum));
- memset(m_mouseReleasedAccum, 0, sizeof(m_mouseReleasedAccum));
- m_mouseDeltaXAccum = 0.0f;
- m_mouseDeltaYAccum = 0.0f;
- m_scrollDeltaAccum = 0;
+ // Normalize from raw Windows delta (multiples of WHEEL_DELTA=120) to discrete notch counts
+ m_mouseWheelAccum += delta / WHEEL_DELTA;
}
-// Per-frame key queries
-bool KeyboardMouseInput::IsKeyDown(int vk) const
+int KeyboardMouseInput::GetMouseWheel()
{
- if (vk < 0 || vk >= 256) return false;
- return m_keyState[vk];
+ int val = m_mouseWheelAccum;
+ m_mouseWheelAccum = 0;
+ return val;
}
-bool KeyboardMouseInput::IsKeyPressed(int vk) const
+void KeyboardMouseInput::OnRawMouseDelta(int dx, int dy)
{
- if (vk < 0 || vk >= 256) return false;
- return m_keyState[vk] && !m_keyStatePrev[vk];
+ m_mouseDeltaAccumX += dx;
+ m_mouseDeltaAccumY += dy;
}
-bool KeyboardMouseInput::IsKeyReleased(int vk) const
+bool KeyboardMouseInput::IsKeyDown(int vkCode) const
{
- if (vk < 0 || vk >= 256) return false;
- return !m_keyState[vk] && m_keyStatePrev[vk];
+ if (vkCode >= 0 && vkCode < MAX_KEYS)
+ return m_keyDown[vkCode];
+ return false;
}
-// Per-frame mouse button queries
-bool KeyboardMouseInput::IsMouseDown(int btn) const
+bool KeyboardMouseInput::IsKeyPressed(int vkCode) const
{
- if (btn < 0 || btn >= 3) return false;
- return m_mouseButtons[btn];
+ if (vkCode >= 0 && vkCode < MAX_KEYS)
+ return m_keyPressed[vkCode];
+ return false;
}
-bool KeyboardMouseInput::IsMousePressed(int btn) const
+bool KeyboardMouseInput::IsKeyReleased(int vkCode) const
{
- if (btn < 0 || btn >= 3) return false;
- return m_mouseButtons[btn] && !m_mouseButtonsPrev[btn];
+ if (vkCode >= 0 && vkCode < MAX_KEYS)
+ return m_keyReleased[vkCode];
+ return false;
}
-bool KeyboardMouseInput::IsMouseReleased(int btn) const
+bool KeyboardMouseInput::IsMouseButtonDown(int button) const
{
- if (btn < 0 || btn >= 3) return false;
- return !m_mouseButtons[btn] && m_mouseButtonsPrev[btn];
+ if (button >= 0 && button < MAX_MOUSE_BUTTONS)
+ return m_mouseButtonDown[button];
+ return false;
}
-// Game-tick consume methods
-bool KeyboardMouseInput::ConsumeKeyPress(int vk)
+bool KeyboardMouseInput::IsMouseButtonPressed(int button) const
{
- if (vk < 0 || vk >= 256) return false;
- bool pressed = m_keyPressedAccum[vk];
- m_keyPressedAccum[vk] = false;
- return pressed;
+ if (button >= 0 && button < MAX_MOUSE_BUTTONS)
+ return m_mouseBtnPressed[button];
+ return false;
}
-bool KeyboardMouseInput::ConsumeMousePress(int btn)
+bool KeyboardMouseInput::IsMouseButtonReleased(int button) const
{
- if (btn < 0 || btn >= 3) return false;
- bool pressed = m_mousePressedAccum[btn];
- m_mousePressedAccum[btn] = false;
- return pressed;
+ if (button >= 0 && button < MAX_MOUSE_BUTTONS)
+ return m_mouseBtnReleased[button];
+ return false;
}
-bool KeyboardMouseInput::ConsumeMouseRelease(int btn)
+void KeyboardMouseInput::ConsumeMouseDelta(float &dx, float &dy)
{
- if (btn < 0 || btn >= 3) return false;
- bool released = m_mouseReleasedAccum[btn];
- m_mouseReleasedAccum[btn] = false;
- return released;
+ dx = (float)m_mouseDeltaAccumX;
+ dy = (float)m_mouseDeltaAccumY;
+ m_mouseDeltaAccumX = 0;
+ m_mouseDeltaAccumY = 0;
}
-void KeyboardMouseInput::ConsumeMouseDelta(float &dx, float &dy)
+void KeyboardMouseInput::SetMouseGrabbed(bool grabbed)
{
- dx = m_mouseDeltaXAccum;
- dy = m_mouseDeltaYAccum;
- m_mouseDeltaXAccum = 0.0f;
- m_mouseDeltaYAccum = 0.0f;
+ 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, &center);
+ SetCursorPos(center.x, center.y);
+
+ m_mouseDeltaAccumX = 0;
+ m_mouseDeltaAccumY = 0;
+ }
+ else if (!grabbed && !m_cursorHiddenForUI && g_hWnd)
+ {
+ while (ShowCursor(TRUE) < 0) {}
+ ClipCursor(NULL);
+ }
}
-int KeyboardMouseInput::ConsumeScrollDelta()
+void KeyboardMouseInput::SetCursorHiddenForUI(bool hidden)
{
- int delta = m_scrollDeltaAccum;
- m_scrollDeltaAccum = 0;
- return delta;
+ 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, &center);
+ SetCursorPos(center.x, center.y);
+
+ m_mouseDeltaAccumX = 0;
+ m_mouseDeltaAccumY = 0;
+ }
+ else if (!hidden && !m_mouseGrabbed && g_hWnd)
+ {
+ while (ShowCursor(TRUE) < 0) {}
+ ClipCursor(NULL);
+ }
}
-// Mouse capture
-void KeyboardMouseInput::SetCapture(bool capture)
+static void ClipCursorToWindow(HWND hWnd)
{
- if (capture == m_captured) return;
- m_captured = capture;
+ 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);
+}
- if (capture)
+void KeyboardMouseInput::SetWindowFocused(bool focused)
+{
+ m_windowFocused = focused;
+ if (focused)
{
- ShowCursor(FALSE);
- RECT rect;
- GetClientRect(m_hWnd, &rect);
- POINT topLeft = { rect.left, rect.top };
- POINT bottomRight = { rect.right, rect.bottom };
- ClientToScreen(m_hWnd, &topLeft);
- ClientToScreen(m_hWnd, &bottomRight);
- RECT screenRect = { topLeft.x, topLeft.y, bottomRight.x, bottomRight.y };
- ClipCursor(&screenRect);
- CenterCursor();
-
- // Flush accumulated deltas so the snap-to-center doesn't cause a jump
- m_mouseDeltaXAccum = 0.0f;
- m_mouseDeltaYAccum = 0.0f;
+ if (m_mouseGrabbed || m_cursorHiddenForUI)
+ {
+ while (ShowCursor(FALSE) >= 0) {}
+ ClipCursorToWindow(g_hWnd);
+ }
+ else
+ {
+ while (ShowCursor(TRUE) < 0) {}
+ ClipCursor(NULL);
+ }
}
else
{
- ShowCursor(TRUE);
+ while (ShowCursor(TRUE) < 0) {}
ClipCursor(NULL);
}
}
-bool KeyboardMouseInput::IsCaptured() const { return m_captured; }
+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 (float)m_mouseDeltaX * sensitivity;
+}
-void KeyboardMouseInput::CenterCursor()
+float KeyboardMouseInput::GetLookY(float sensitivity) const
{
- RECT rect;
- GetClientRect(m_hWnd, &rect);
- POINT center = { (rect.left + rect.right) / 2, (rect.top + rect.bottom) / 2 };
- ClientToScreen(m_hWnd, &center);
- SetCursorPos(center.x, center.y);
+ return (float)(-m_mouseDeltaY) * sensitivity;
}
#endif // _WINDOWS64