aboutsummaryrefslogtreecommitdiff
path: root/Minecraft.Client/Windows64
diff options
context:
space:
mode:
Diffstat (limited to 'Minecraft.Client/Windows64')
-rw-r--r--Minecraft.Client/Windows64/KeyboardMouseInput.cpp217
-rw-r--r--Minecraft.Client/Windows64/KeyboardMouseInput.h76
-rw-r--r--Minecraft.Client/Windows64/Windows64_Minecraft.cpp84
3 files changed, 377 insertions, 0 deletions
diff --git a/Minecraft.Client/Windows64/KeyboardMouseInput.cpp b/Minecraft.Client/Windows64/KeyboardMouseInput.cpp
new file mode 100644
index 00000000..e67946da
--- /dev/null
+++ b/Minecraft.Client/Windows64/KeyboardMouseInput.cpp
@@ -0,0 +1,217 @@
+#include "stdafx.h"
+
+#ifdef _WINDOWS64
+
+#include "KeyboardMouseInput.h"
+
+KeyboardMouseInput KMInput;
+
+KeyboardMouseInput::KeyboardMouseInput()
+ : m_mouseDeltaX(0.0f)
+ , m_mouseDeltaY(0.0f)
+ , m_mouseDeltaXAccum(0.0f)
+ , m_mouseDeltaYAccum(0.0f)
+ , m_scrollDelta(0)
+ , m_scrollDeltaAccum(0)
+ , m_captured(false)
+ , m_hWnd(NULL)
+ , m_initialized(false)
+{
+ 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));
+}
+
+KeyboardMouseInput::~KeyboardMouseInput()
+{
+ if (m_captured)
+ {
+ SetCapture(false);
+ }
+}
+
+void KeyboardMouseInput::Init(HWND hWnd)
+{
+ m_hWnd = hWnd;
+ m_initialized = true;
+
+ // Register for raw mouse input
+ RAWINPUTDEVICE rid;
+ rid.usUsagePage = HID_USAGE_PAGE_GENERIC;
+ rid.usUsage = HID_USAGE_GENERIC_MOUSE;
+ rid.dwFlags = 0;
+ rid.hwndTarget = hWnd;
+ RegisterRawInputDevices(&rid, 1, sizeof(rid));
+}
+
+void KeyboardMouseInput::Tick()
+{
+ // Snapshot accumulated mouse deltas
+ m_mouseDeltaX = m_mouseDeltaXAccum;
+ m_mouseDeltaY = m_mouseDeltaYAccum;
+ m_mouseDeltaXAccum = 0.0f;
+ m_mouseDeltaYAccum = 0.0f;
+
+ // Snapshot scroll delta
+ m_scrollDelta = m_scrollDeltaAccum;
+ m_scrollDeltaAccum = 0;
+
+ // Keep cursor pinned to center while captured
+ if (m_captured)
+ CenterCursor();
+}
+
+void KeyboardMouseInput::EndFrame()
+{
+ // Advance previous state for next frame's edge detection.
+ // Must be called AFTER all consumers have read IsKeyPressed/Released etc.
+ memcpy(m_keyStatePrev, m_keyState, sizeof(m_keyState));
+ memcpy(m_mouseButtonsPrev, m_mouseButtons, sizeof(m_mouseButtons));
+}
+
+void KeyboardMouseInput::OnKeyDown(WPARAM vk)
+{
+ if (vk < 256)
+ {
+ m_keyState[vk] = true;
+ }
+}
+
+void KeyboardMouseInput::OnKeyUp(WPARAM vk)
+{
+ if (vk < 256)
+ {
+ m_keyState[vk] = false;
+ }
+}
+
+void KeyboardMouseInput::OnRawMouseInput(LPARAM lParam)
+{
+ 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 (raw->data.mouse.usFlags == MOUSE_MOVE_RELATIVE)
+ {
+ m_mouseDeltaXAccum += (float)raw->data.mouse.lLastX;
+ m_mouseDeltaYAccum += (float)raw->data.mouse.lLastY;
+ }
+ }
+}
+
+void KeyboardMouseInput::OnMouseButton(int button, bool down)
+{
+ if (button >= 0 && button < 3)
+ {
+ m_mouseButtons[button] = down;
+ }
+}
+
+void KeyboardMouseInput::OnMouseWheel(int delta)
+{
+ m_scrollDeltaAccum += delta;
+}
+
+void KeyboardMouseInput::ClearAllState()
+{
+ memset(m_keyState, 0, sizeof(m_keyState));
+ memset(m_mouseButtons, 0, sizeof(m_mouseButtons));
+ m_mouseDeltaXAccum = 0.0f;
+ m_mouseDeltaYAccum = 0.0f;
+ m_scrollDeltaAccum = 0;
+}
+
+// Key queries
+bool KeyboardMouseInput::IsKeyDown(int vk) const
+{
+ if (vk < 0 || vk >= 256) return false;
+ return m_keyState[vk];
+}
+
+bool KeyboardMouseInput::IsKeyPressed(int vk) const
+{
+ if (vk < 0 || vk >= 256) return false;
+ return m_keyState[vk] && !m_keyStatePrev[vk];
+}
+
+bool KeyboardMouseInput::IsKeyReleased(int vk) const
+{
+ if (vk < 0 || vk >= 256) return false;
+ return !m_keyState[vk] && m_keyStatePrev[vk];
+}
+
+// Mouse button queries
+bool KeyboardMouseInput::IsMouseDown(int btn) const
+{
+ if (btn < 0 || btn >= 3) return false;
+ return m_mouseButtons[btn];
+}
+
+bool KeyboardMouseInput::IsMousePressed(int btn) const
+{
+ if (btn < 0 || btn >= 3) return false;
+ return m_mouseButtons[btn] && !m_mouseButtonsPrev[btn];
+}
+
+bool KeyboardMouseInput::IsMouseReleased(int btn) const
+{
+ if (btn < 0 || btn >= 3) return false;
+ return !m_mouseButtons[btn] && m_mouseButtonsPrev[btn];
+}
+
+// Delta queries
+float KeyboardMouseInput::GetMouseDeltaX() const { return m_mouseDeltaX; }
+float KeyboardMouseInput::GetMouseDeltaY() const { return m_mouseDeltaY; }
+int KeyboardMouseInput::GetScrollDelta() const { return m_scrollDelta; }
+
+// Mouse capture
+void KeyboardMouseInput::SetCapture(bool capture)
+{
+ if (capture == m_captured) return;
+ m_captured = capture;
+
+ if (capture)
+ {
+ 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;
+ }
+ else
+ {
+ ShowCursor(TRUE);
+ ClipCursor(NULL);
+ }
+}
+
+bool KeyboardMouseInput::IsCaptured() const { return m_captured; }
+
+void KeyboardMouseInput::CenterCursor()
+{
+ 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);
+}
+
+#endif // _WINDOWS64
diff --git a/Minecraft.Client/Windows64/KeyboardMouseInput.h b/Minecraft.Client/Windows64/KeyboardMouseInput.h
new file mode 100644
index 00000000..722c9f3d
--- /dev/null
+++ b/Minecraft.Client/Windows64/KeyboardMouseInput.h
@@ -0,0 +1,76 @@
+#pragma once
+
+#ifdef _WINDOWS64
+
+#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);
+ void Tick();
+ void EndFrame();
+
+ // Called from WndProc
+ void OnKeyDown(WPARAM vk);
+ void OnKeyUp(WPARAM vk);
+ void OnRawMouseInput(LPARAM lParam);
+ void OnMouseButton(int button, bool down);
+ void OnMouseWheel(int delta);
+ void ClearAllState();
+
+ // Key state queries (call after Tick)
+ bool IsKeyDown(int vk) const;
+ bool IsKeyPressed(int vk) const;
+ bool IsKeyReleased(int vk) const;
+
+ // Mouse button queries: 0=left, 1=right, 2=middle
+ bool IsMouseDown(int btn) const;
+ bool IsMousePressed(int btn) const;
+ bool IsMouseReleased(int btn) const;
+
+ // Mouse deltas (consumed each Tick)
+ float GetMouseDeltaX() const;
+ float GetMouseDeltaY() const;
+ int GetScrollDelta() const;
+
+ // Mouse capture for FPS look
+ void SetCapture(bool capture);
+ bool IsCaptured() const;
+
+private:
+ void CenterCursor();
+
+ bool m_keyState[256];
+ bool m_keyStatePrev[256];
+
+ bool m_mouseButtons[3];
+ bool m_mouseButtonsPrev[3];
+
+ float m_mouseDeltaX;
+ float m_mouseDeltaY;
+ float m_mouseDeltaXAccum;
+ float m_mouseDeltaYAccum;
+
+ int m_scrollDelta;
+ int m_scrollDeltaAccum;
+
+ bool m_captured;
+ HWND m_hWnd;
+ bool m_initialized;
+};
+
+extern KeyboardMouseInput KMInput;
+
+#endif // _WINDOWS64
diff --git a/Minecraft.Client/Windows64/Windows64_Minecraft.cpp b/Minecraft.Client/Windows64/Windows64_Minecraft.cpp
index d2251e4e..4002fc3b 100644
--- a/Minecraft.Client/Windows64/Windows64_Minecraft.cpp
+++ b/Minecraft.Client/Windows64/Windows64_Minecraft.cpp
@@ -339,6 +339,63 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
case WM_DESTROY:
PostQuitMessage(0);
break;
+
+ // Keyboard/Mouse input handling
+ case WM_KEYDOWN:
+ if (!(lParam & 0x40000000)) // ignore auto-repeat
+ KMInput.OnKeyDown(wParam);
+ break;
+ case WM_KEYUP:
+ KMInput.OnKeyUp(wParam);
+ break;
+ 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);
+ case WM_SYSKEYUP:
+ if (wParam == VK_MENU)
+ {
+ KMInput.OnKeyUp(wParam);
+ return 0;
+ }
+ return DefWindowProc(hWnd, message, wParam, lParam);
+ case WM_INPUT:
+ KMInput.OnRawMouseInput(lParam);
+ break;
+ case WM_LBUTTONDOWN:
+ KMInput.OnMouseButton(0, true);
+ break;
+ case WM_LBUTTONUP:
+ KMInput.OnMouseButton(0, false);
+ break;
+ case WM_RBUTTONDOWN:
+ KMInput.OnMouseButton(1, true);
+ break;
+ case WM_RBUTTONUP:
+ KMInput.OnMouseButton(1, false);
+ break;
+ case WM_MBUTTONDOWN:
+ KMInput.OnMouseButton(2, true);
+ break;
+ case WM_MBUTTONUP:
+ KMInput.OnMouseButton(2, false);
+ break;
+ case WM_MOUSEWHEEL:
+ KMInput.OnMouseWheel(GET_WHEEL_DELTA_WPARAM(wParam));
+ break;
+ case WM_ACTIVATE:
+ if (LOWORD(wParam) == WA_INACTIVE)
+ KMInput.SetCapture(false);
+ break;
+ case WM_KILLFOCUS:
+ KMInput.SetCapture(false);
+ KMInput.ClearAllState();
+ break;
+
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
@@ -715,6 +772,9 @@ int APIENTRY _tWinMain(_In_ HINSTANCE hInstance,
// Set the number of possible joypad layouts that the user can switch between, and the number of actions
InputManager.Initialise(1,3,MINECRAFT_ACTION_MAX, ACTION_MAX_MENU);
+ // Initialize keyboard/mouse input
+ KMInput.Init(g_hWnd);
+
// Set the default joypad action mappings for Minecraft
DefineActions();
InputManager.SetJoypadMapVal(0,0);
@@ -940,6 +1000,7 @@ int APIENTRY _tWinMain(_In_ HINSTANCE hInstance,
app.UpdateTime();
PIXBeginNamedEvent(0,"Input manager tick");
InputManager.Tick();
+ KMInput.Tick();
PIXEndNamedEvent();
PIXBeginNamedEvent(0,"Profile manager tick");
// ProfileManager.Tick();
@@ -1067,6 +1128,27 @@ int APIENTRY _tWinMain(_In_ HINSTANCE hInstance,
RenderManager.Present();
ui.CheckMenuDisplayed();
+
+ // Update mouse capture: capture when in-game and no menu is open
+ {
+ static bool altToggleSuppressCapture = false;
+ bool shouldCapture = app.GetGameStarted() && !ui.GetMenuDisplayed(0);
+ // Left Alt key toggles capture on/off for debugging
+ if (KMInput.IsKeyPressed(VK_MENU))
+ {
+ if (KMInput.IsCaptured()) { KMInput.SetCapture(false); altToggleSuppressCapture = true; }
+ else if (shouldCapture) { KMInput.SetCapture(true); altToggleSuppressCapture = false; }
+ }
+ else if (!shouldCapture)
+ {
+ if (KMInput.IsCaptured()) KMInput.SetCapture(false);
+ altToggleSuppressCapture = false;
+ }
+ else if (shouldCapture && !KMInput.IsCaptured() && GetFocus() == g_hWnd && !altToggleSuppressCapture)
+ {
+ KMInput.SetCapture(true);
+ }
+ }
#if 0
PIXBeginNamedEvent(0,"Profile load check");
// has the game defined profile data been changed (by a profile load)
@@ -1158,6 +1240,8 @@ 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.