aboutsummaryrefslogtreecommitdiff
path: root/Minecraft.Client/Windows64
diff options
context:
space:
mode:
Diffstat (limited to 'Minecraft.Client/Windows64')
-rw-r--r--Minecraft.Client/Windows64/KeyboardMouseInput.cpp418
-rw-r--r--Minecraft.Client/Windows64/KeyboardMouseInput.h166
-rw-r--r--Minecraft.Client/Windows64/Windows64_Minecraft.cpp184
3 files changed, 472 insertions, 296 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
diff --git a/Minecraft.Client/Windows64/KeyboardMouseInput.h b/Minecraft.Client/Windows64/KeyboardMouseInput.h
index a09843f9..f098ccab 100644
--- a/Minecraft.Client/Windows64/KeyboardMouseInput.h
+++ b/Minecraft.Client/Windows64/KeyboardMouseInput.h
@@ -4,88 +4,130 @@
#include <windows.h>
-// HID usage page and usage for raw input registration
-#ifndef HID_USAGE_PAGE_GENERIC
-#define HID_USAGE_PAGE_GENERIC ((USHORT)0x01)
-#endif
-#ifndef HID_USAGE_GENERIC_MOUSE
-#define HID_USAGE_GENERIC_MOUSE ((USHORT)0x02)
-#endif
-
class KeyboardMouseInput
{
public:
- KeyboardMouseInput();
- ~KeyboardMouseInput();
-
- void Init(HWND hWnd);
+ 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_LCONTROL;
+ 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_CONFIRM = VK_RETURN;
+ static const int KEY_CANCEL = VK_ESCAPE;
+ static const int KEY_PAUSE = VK_ESCAPE;
+ static const int KEY_THIRD_PERSON = VK_F5;
+ static const int KEY_DEBUG_INFO = VK_F3;
+
+ void Init();
void Tick();
- void EndFrame();
+ void ClearAllState();
- // Called from WndProc
- void OnKeyDown(WPARAM vk);
- void OnKeyUp(WPARAM vk);
- void OnRawMouseInput(LPARAM lParam);
- void OnMouseButton(int button, bool down);
+ 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 ClearAllState();
+ void OnRawMouseDelta(int dx, int dy);
+
+ bool IsKeyDown(int vkCode) const;
+ bool IsKeyPressed(int vkCode) const;
+ bool IsKeyReleased(int vkCode) const;
+
+ bool IsMouseButtonDown(int button) const;
+ bool IsMouseButtonPressed(int button) const;
+ bool IsMouseButtonReleased(int button) const;
- // Per-frame edge detection (for UI / per-frame logic like Alt toggle)
- bool IsKeyDown(int vk) const;
- bool IsKeyPressed(int vk) const;
- bool IsKeyReleased(int vk) const;
- bool IsMouseDown(int btn) const;
- bool IsMousePressed(int btn) const;
- bool IsMouseReleased(int btn) const;
-
- // Game-tick consume methods: accumulate across frames, clear on read.
- // Use these from code that runs at game tick rate (20Hz).
- bool ConsumeKeyPress(int vk);
- bool ConsumeMousePress(int btn);
- bool ConsumeMouseRelease(int btn);
+ 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() { m_mouseWheelAccum = 0; }
+
+ // 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);
- int ConsumeScrollDelta();
- // Absolute cursor position (client-area coordinates, for GUI when not captured)
- void OnMouseMove(int x, int y);
- int GetMouseX() const;
- int GetMouseY() const;
- HWND GetHWnd() const;
+ void SetMouseGrabbed(bool grabbed);
+ bool IsMouseGrabbed() const { return m_mouseGrabbed; }
- // Mouse capture for FPS look
- void SetCapture(bool capture);
- bool IsCaptured() const;
+ void SetCursorHiddenForUI(bool hidden);
+ bool IsCursorHiddenForUI() const { return m_cursorHiddenForUI; }
-private:
- void CenterCursor();
+ void SetWindowFocused(bool focused);
+ bool IsWindowFocused() const { return m_windowFocused; }
- // Per-frame double-buffered state (for IsKeyPressed/Released per-frame edge detection)
- bool m_keyState[256];
- bool m_keyStatePrev[256];
- bool m_mouseButtons[3];
- bool m_mouseButtonsPrev[3];
+ bool HasAnyInput() const { return m_hasInput; }
- // Sticky press accumulators (persist until consumed by game tick)
- bool m_keyPressedAccum[256];
- bool m_mousePressedAccum[3];
- bool m_mouseReleasedAccum[3];
+ void SetKBMActive(bool active) { m_kbmActive = active; }
+ bool IsKBMActive() const { return m_kbmActive; }
- // Mouse delta accumulators (persist until consumed by game tick)
- float m_mouseDeltaXAccum;
- float m_mouseDeltaYAccum;
+ void SetScreenCursorHidden(bool hidden) { m_screenWantsCursorHidden = hidden; }
+ bool IsScreenCursorHidden() const { return m_screenWantsCursorHidden; }
- // Scroll accumulator (persists until consumed by game tick)
- int m_scrollDeltaAccum;
+ float GetMoveX() const;
+ float GetMoveY() const;
- bool m_captured;
- HWND m_hWnd;
- bool m_initialized;
+ float GetLookX(float sensitivity) const;
+ float GetLookY(float sensitivity) const;
+
+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];
- // Absolute cursor position in client coordinates
int m_mouseX;
int m_mouseY;
+
+ int m_mouseDeltaX;
+ int m_mouseDeltaY;
+ int m_mouseDeltaAccumX;
+ int m_mouseDeltaAccumY;
+
+ int m_mouseWheelAccum;
+
+ bool m_mouseGrabbed;
+
+ bool m_cursorHiddenForUI;
+
+ bool m_windowFocused;
+
+ bool m_hasInput;
+
+ bool m_kbmActive;
+
+ bool m_screenWantsCursorHidden;
};
-extern KeyboardMouseInput KMInput;
+extern KeyboardMouseInput g_KBMInput;
#endif // _WINDOWS64
diff --git a/Minecraft.Client/Windows64/Windows64_Minecraft.cpp b/Minecraft.Client/Windows64/Windows64_Minecraft.cpp
index ec89feb1..0f83fae5 100644
--- a/Minecraft.Client/Windows64/Windows64_Minecraft.cpp
+++ b/Minecraft.Client/Windows64/Windows64_Minecraft.cpp
@@ -501,82 +501,90 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
PostQuitMessage(0);
break;
- // Keyboard/Mouse input handling
- case WM_KEYDOWN:
- if (!(lParam & 0x40000000)) // ignore auto-repeat
- KMInput.OnKeyDown(wParam);
+ case WM_KILLFOCUS:
+ g_KBMInput.ClearAllState();
+ g_KBMInput.SetWindowFocused(false);
+ if (g_KBMInput.IsMouseGrabbed())
+ g_KBMInput.SetMouseGrabbed(false);
break;
- case WM_KEYUP:
- KMInput.OnKeyUp(wParam);
+
+ case WM_SETFOCUS:
+ g_KBMInput.SetWindowFocused(true);
break;
+
+ case WM_KEYDOWN:
case WM_SYSKEYDOWN:
- if (wParam == VK_MENU) // Alt key
- {
- if (!(lParam & 0x40000000))
- KMInput.OnKeyDown(wParam);
- return 0; // prevent default Alt behavior
- }
- return DefWindowProc(hWnd, message, wParam, lParam);
+ {
+ int vk = (int)wParam;
+ if (lParam & 0x40000000) break; // ignore auto-repeat
+ if (vk == VK_SHIFT)
+ vk = (MapVirtualKey((lParam >> 16) & 0xFF, MAPVK_VSC_TO_VK_EX) == VK_RSHIFT) ? VK_RSHIFT : VK_LSHIFT;
+ else if (vk == VK_CONTROL)
+ vk = (lParam & (1 << 24)) ? VK_RCONTROL : VK_LCONTROL;
+ else if (vk == VK_MENU)
+ vk = (lParam & (1 << 24)) ? VK_RMENU : VK_LMENU;
+ g_KBMInput.OnKeyDown(vk);
+ break;
+ }
+ case WM_KEYUP:
case WM_SYSKEYUP:
- if (wParam == VK_MENU)
- {
- KMInput.OnKeyUp(wParam);
- return 0;
- }
- return DefWindowProc(hWnd, message, wParam, lParam);
- case WM_INPUT:
- KMInput.OnRawMouseInput(lParam);
+ {
+ int vk = (int)wParam;
+ if (vk == VK_SHIFT)
+ vk = (MapVirtualKey((lParam >> 16) & 0xFF, MAPVK_VSC_TO_VK_EX) == VK_RSHIFT) ? VK_RSHIFT : VK_LSHIFT;
+ else if (vk == VK_CONTROL)
+ vk = (lParam & (1 << 24)) ? VK_RCONTROL : VK_LCONTROL;
+ else if (vk == VK_MENU)
+ vk = (lParam & (1 << 24)) ? VK_RMENU : VK_LMENU;
+ g_KBMInput.OnKeyUp(vk);
break;
+ }
+
case WM_LBUTTONDOWN:
- KMInput.OnMouseButton(0, true);
+ g_KBMInput.OnMouseButtonDown(KeyboardMouseInput::MOUSE_LEFT);
break;
case WM_LBUTTONUP:
- KMInput.OnMouseButton(0, false);
+ g_KBMInput.OnMouseButtonUp(KeyboardMouseInput::MOUSE_LEFT);
break;
case WM_RBUTTONDOWN:
- KMInput.OnMouseButton(1, true);
+ g_KBMInput.OnMouseButtonDown(KeyboardMouseInput::MOUSE_RIGHT);
break;
case WM_RBUTTONUP:
- KMInput.OnMouseButton(1, false);
+ g_KBMInput.OnMouseButtonUp(KeyboardMouseInput::MOUSE_RIGHT);
break;
case WM_MBUTTONDOWN:
- KMInput.OnMouseButton(2, true);
+ g_KBMInput.OnMouseButtonDown(KeyboardMouseInput::MOUSE_MIDDLE);
break;
case WM_MBUTTONUP:
- KMInput.OnMouseButton(2, false);
- break;
- case WM_MOUSEWHEEL:
- KMInput.OnMouseWheel(GET_WHEEL_DELTA_WPARAM(wParam));
+ g_KBMInput.OnMouseButtonUp(KeyboardMouseInput::MOUSE_MIDDLE);
break;
+
case WM_MOUSEMOVE:
- KMInput.OnMouseMove(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
- break;
- case WM_ACTIVATE:
- if (LOWORD(wParam) == WA_INACTIVE)
- KMInput.SetCapture(false);
- break;
- case WM_SETFOCUS:
- {
- // Re-capture when window receives focus (e.g., after clicking on it)
- Minecraft *pMinecraft = Minecraft::GetInstance();
- bool shouldCapture = pMinecraft && app.GetGameStarted() && !ui.GetMenuDisplayed(0) && pMinecraft->screen == NULL;
- if (shouldCapture)
- KMInput.SetCapture(true);
- }
+ g_KBMInput.OnMouseMove(LOWORD(lParam), HIWORD(lParam));
break;
- case WM_KILLFOCUS:
- KMInput.SetCapture(false);
- KMInput.ClearAllState();
+
+ case WM_MOUSEWHEEL:
+ g_KBMInput.OnMouseWheel(GET_WHEEL_DELTA_WPARAM(wParam));
break;
- case WM_SETCURSOR:
- // Hide the OS cursor when an Iggy/Flash menu is displayed (it has its own Flash cursor)
- if (LOWORD(lParam) == HTCLIENT && !KMInput.IsCaptured() && ui.GetMenuDisplayed(0))
+ case WM_INPUT:
{
- SetCursor(NULL);
- return TRUE;
+ UINT dwSize = 0;
+ GetRawInputData((HRAWINPUT)lParam, RID_INPUT, NULL, &dwSize, sizeof(RAWINPUTHEADER));
+ if (dwSize > 0 && dwSize <= 256)
+ {
+ BYTE rawBuffer[256];
+ if (GetRawInputData((HRAWINPUT)lParam, RID_INPUT, rawBuffer, &dwSize, sizeof(RAWINPUTHEADER)) == dwSize)
+ {
+ RAWINPUT* raw = (RAWINPUT*)rawBuffer;
+ if (raw->header.dwType == RIM_TYPEMOUSE)
+ {
+ g_KBMInput.OnRawMouseDelta(raw->data.mouse.lLastX, raw->data.mouse.lLastY);
+ }
+ }
+ }
}
- return DefWindowProc(hWnd, message, wParam, lParam);
+ break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
@@ -852,6 +860,9 @@ void ToggleFullscreen()
SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_FRAMECHANGED);
}
g_isFullscreen = !g_isFullscreen;
+
+ if (g_KBMInput.IsWindowFocused())
+ g_KBMInput.SetWindowFocused(true);
}
//--------------------------------------------------------------------------------------
@@ -877,7 +888,7 @@ static Minecraft* InitialiseMinecraftRuntime()
ui.init(g_pd3dDevice, g_pImmediateContext, g_pRenderTargetView, g_pDepthStencilView, g_iScreenWidth, g_iScreenHeight);
InputManager.Initialise(1, 3, MINECRAFT_ACTION_MAX, ACTION_MAX_MENU);
- KMInput.Init(g_hWnd);
+ g_KBMInput.Init();
DefineActions();
InputManager.SetJoypadMapVal(0, 0);
InputManager.SetKeyRepeatRate(0.3f, 0.2f);
@@ -1263,12 +1274,16 @@ int APIENTRY _tWinMain(_In_ HINSTANCE hInstance,
MSG msg = {0};
while( WM_QUIT != msg.message && !app.m_bShutdown)
{
- if( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) )
+ g_KBMInput.Tick();
+
+ while( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) )
{
TranslateMessage( &msg );
DispatchMessage( &msg );
- continue;
+ if (msg.message == WM_QUIT) break;
}
+ if (msg.message == WM_QUIT) break;
+
RenderManager.StartFrame();
#if 0
if(pMinecraft->soundEngine->isStreamingWavebankReady() &&
@@ -1290,7 +1305,34 @@ int APIENTRY _tWinMain(_In_ HINSTANCE hInstance,
app.UpdateTime();
PIXBeginNamedEvent(0,"Input manager tick");
InputManager.Tick();
- KMInput.Tick();
+
+ // Detect KBM vs controller input mode
+ if (InputManager.IsPadConnected(0))
+ {
+ 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);
+ else if (g_KBMInput.HasAnyInput())
+ g_KBMInput.SetKBMActive(true);
+ }
+ else
+ {
+ g_KBMInput.SetKBMActive(true);
+ }
+
+ if (!g_KBMInput.IsMouseGrabbed())
+ {
+ if (!g_KBMInput.IsKBMActive())
+ g_KBMInput.SetCursorHiddenForUI(true);
+ else if (!g_KBMInput.IsScreenCursorHidden())
+ g_KBMInput.SetCursorHiddenForUI(false);
+ }
+
PIXEndNamedEvent();
PIXBeginNamedEvent(0,"Profile manager tick");
// ProfileManager.Tick();
@@ -1420,29 +1462,29 @@ int APIENTRY _tWinMain(_In_ HINSTANCE hInstance,
ui.CheckMenuDisplayed();
- // Update mouse capture: capture when in-game and no menu is open
+ // Update mouse grab: grab when in-game and no menu is open
{
static bool altToggleSuppressCapture = false;
bool shouldCapture = app.GetGameStarted() && !ui.GetMenuDisplayed(0) && pMinecraft->screen == NULL;
// Left Alt key toggles capture on/off for debugging
- if (KMInput.IsKeyPressed(VK_MENU))
+ if (g_KBMInput.IsKeyPressed(VK_LMENU) || g_KBMInput.IsKeyPressed(VK_RMENU))
{
- if (KMInput.IsCaptured()) { KMInput.SetCapture(false); altToggleSuppressCapture = true; }
- else if (shouldCapture) { KMInput.SetCapture(true); altToggleSuppressCapture = false; }
+ if (g_KBMInput.IsMouseGrabbed()) { g_KBMInput.SetMouseGrabbed(false); altToggleSuppressCapture = true; }
+ else if (shouldCapture) { g_KBMInput.SetMouseGrabbed(true); altToggleSuppressCapture = false; }
}
else if (!shouldCapture)
{
- if (KMInput.IsCaptured()) KMInput.SetCapture(false);
+ if (g_KBMInput.IsMouseGrabbed()) g_KBMInput.SetMouseGrabbed(false);
altToggleSuppressCapture = false;
}
- else if (shouldCapture && !KMInput.IsCaptured() && GetFocus() == g_hWnd && !altToggleSuppressCapture)
+ else if (shouldCapture && !g_KBMInput.IsMouseGrabbed() && GetFocus() == g_hWnd && !altToggleSuppressCapture)
{
- KMInput.SetCapture(true);
+ g_KBMInput.SetMouseGrabbed(true);
}
}
// F1 toggles the HUD
- if (KMInput.IsKeyPressed(VK_F1))
+ if (g_KBMInput.IsKeyPressed(VK_F1))
{
int primaryPad = ProfileManager.GetPrimaryPad();
unsigned char displayHud = app.GetGameSettings(primaryPad, eGameSetting_DisplayHUD);
@@ -1451,7 +1493,7 @@ int APIENTRY _tWinMain(_In_ HINSTANCE hInstance,
}
// F3 toggles onscreen debug info
- if (KMInput.IsKeyPressed(VK_F3))
+ if (g_KBMInput.IsKeyPressed(VK_F3))
{
if (Minecraft* pMinecraft = Minecraft::GetInstance())
{
@@ -1464,7 +1506,7 @@ int APIENTRY _tWinMain(_In_ HINSTANCE hInstance,
#ifdef _DEBUG_MENUS_ENABLED
// F4 Open debug overlay
- if (KMInput.IsKeyPressed(VK_F4))
+ if (g_KBMInput.IsKeyPressed(VK_F4))
{
if (Minecraft *pMinecraft = Minecraft::GetInstance())
{
@@ -1477,7 +1519,7 @@ int APIENTRY _tWinMain(_In_ HINSTANCE hInstance,
}
// F6 Open debug console
- if (KMInput.IsKeyPressed(VK_F6))
+ if (g_KBMInput.IsKeyPressed(VK_F6))
{
static bool s_debugConsole = false;
s_debugConsole = !s_debugConsole;
@@ -1486,13 +1528,13 @@ int APIENTRY _tWinMain(_In_ HINSTANCE hInstance,
#endif
// F11 Toggle fullscreen
- if (KMInput.IsKeyPressed(VK_F11))
+ if (g_KBMInput.IsKeyPressed(VK_F11))
{
ToggleFullscreen();
}
// TAB opens game info menu. - Vvis :3 - Updated by detectiveren
- if (KMInput.IsKeyPressed(VK_TAB) && !ui.GetMenuDisplayed(0))
+ if (g_KBMInput.IsKeyPressed(VK_TAB) && !ui.GetMenuDisplayed(0))
{
if (Minecraft* pMinecraft = Minecraft::GetInstance())
{
@@ -1593,8 +1635,6 @@ int APIENTRY _tWinMain(_In_ HINSTANCE hInstance,
// Fix for #7318 - Title crashes after short soak in the leaderboards menu
// A memory leak was caused because the icon renderer kept creating new Vec3's because the pool wasn't reset
Vec3::resetPool();
-
- KMInput.EndFrame();
}
// Free resources, unregister custom classes, and exit.