aboutsummaryrefslogtreecommitdiff
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
parentac03b88a907bb49f5159f08de07398f3fce32991 (diff)
refactor: refactor KBM input code
-rw-r--r--Minecraft.Client/Common/Tutorial/ChoiceTask.cpp4
-rw-r--r--Minecraft.Client/Common/Tutorial/InfoTask.cpp4
-rw-r--r--Minecraft.Client/Common/UI/IUIScene_AbstractContainerMenu.cpp42
-rw-r--r--Minecraft.Client/Common/UI/IUIScene_AbstractContainerMenu.h12
-rw-r--r--Minecraft.Client/Common/UI/UIControl.cpp2
-rw-r--r--Minecraft.Client/Common/UI/UIControl.h2
-rw-r--r--Minecraft.Client/Common/UI/UIController.cpp254
-rw-r--r--Minecraft.Client/Common/UI/UIController.h4
-rw-r--r--Minecraft.Client/Common/UI/UIGroup.h2
-rw-r--r--Minecraft.Client/Common/UI/UIScene.h4
-rw-r--r--Minecraft.Client/Common/UI/UIScene_AbstractContainerMenu.cpp168
-rw-r--r--Minecraft.Client/Common/UI/UIScene_AbstractContainerMenu.h8
-rw-r--r--Minecraft.Client/Common/UI/UIScene_LoadOrJoinMenu.cpp8
-rw-r--r--Minecraft.Client/Common/UI/UIScene_SettingsGraphicsMenu.cpp38
-rw-r--r--Minecraft.Client/Input.cpp147
-rw-r--r--Minecraft.Client/Input.h9
-rw-r--r--Minecraft.Client/LocalPlayer.cpp33
-rw-r--r--Minecraft.Client/Minecraft.cpp146
-rw-r--r--Minecraft.Client/Screen.cpp8
-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
-rw-r--r--Minecraft.Client/stubs.cpp103
-rw-r--r--Minecraft.Client/stubs.h33
-rw-r--r--README.md1
25 files changed, 1149 insertions, 651 deletions
diff --git a/Minecraft.Client/Common/Tutorial/ChoiceTask.cpp b/Minecraft.Client/Common/Tutorial/ChoiceTask.cpp
index f42b3ee0..1ea34ace 100644
--- a/Minecraft.Client/Common/Tutorial/ChoiceTask.cpp
+++ b/Minecraft.Client/Common/Tutorial/ChoiceTask.cpp
@@ -58,7 +58,7 @@ bool ChoiceTask::isCompleted()
#ifdef _WINDOWS64
if (!m_bConfirmMappingComplete &&
(InputManager.GetValue(xboxPad, m_iConfirmMapping) > 0
- || KMInput.IsKeyDown(VK_RETURN)))
+ || g_KBMInput.IsKeyDown(VK_RETURN)))
#else
if (!m_bConfirmMappingComplete &&
InputManager.GetValue(xboxPad, m_iConfirmMapping) > 0)
@@ -70,7 +70,7 @@ bool ChoiceTask::isCompleted()
#ifdef _WINDOWS64
if (!m_bCancelMappingComplete &&
(InputManager.GetValue(xboxPad, m_iCancelMapping) > 0
- || KMInput.IsKeyDown('B')))
+ || g_KBMInput.IsKeyDown('B')))
#else
if (!m_bCancelMappingComplete &&
InputManager.GetValue(xboxPad, m_iCancelMapping) > 0)
diff --git a/Minecraft.Client/Common/Tutorial/InfoTask.cpp b/Minecraft.Client/Common/Tutorial/InfoTask.cpp
index 43a10357..748093e5 100644
--- a/Minecraft.Client/Common/Tutorial/InfoTask.cpp
+++ b/Minecraft.Client/Common/Tutorial/InfoTask.cpp
@@ -7,7 +7,7 @@
#include "TutorialConstraints.h"
#include "InfoTask.h"
#include "..\..\..\Minecraft.World\Material.h"
-#include "..\..\KeyboardMouseInput.h"
+#include "..\..\Windows64\KeyboardMouseInput.h"
InfoTask::InfoTask(Tutorial *tutorial, int descriptionId, int promptId /*= -1*/, bool requiresUserInput /*= false*/,
int iMapping /*= 0*/, ETelemetryChallenges telemetryEvent /*= eTelemetryTutorial_NoEvent*/)
@@ -67,7 +67,7 @@ bool InfoTask::isCompleted()
if(!current)
{
#ifdef _WINDOWS64
- if (InputManager.GetValue(pMinecraft->player->GetXboxPad(), (*it).first) > 0 || KMInput.IsKeyDown(VK_SPACE))
+ if (InputManager.GetValue(pMinecraft->player->GetXboxPad(), (*it).first) > 0 || g_KBMInput.IsKeyDown(VK_SPACE))
#else
if( InputManager.GetValue(pMinecraft->player->GetXboxPad(), (*it).first) > 0)
#endif
diff --git a/Minecraft.Client/Common/UI/IUIScene_AbstractContainerMenu.cpp b/Minecraft.Client/Common/UI/IUIScene_AbstractContainerMenu.cpp
index 667431b2..88258421 100644
--- a/Minecraft.Client/Common/UI/IUIScene_AbstractContainerMenu.cpp
+++ b/Minecraft.Client/Common/UI/IUIScene_AbstractContainerMenu.cpp
@@ -13,6 +13,12 @@
#include <pad.h>
#endif
+#ifdef _WINDOWS64
+#include "..\..\Windows64\KeyboardMouseInput.h"
+
+SavedInventoryCursorPos g_savedInventoryCursorPos = { 0.0f, 0.0f, false };
+#endif
+
IUIScene_AbstractContainerMenu::IUIScene_AbstractContainerMenu()
{
m_menu = NULL;
@@ -474,6 +480,34 @@ void IUIScene_AbstractContainerMenu::onMouseTick()
}
#endif
+#ifdef _WINDOWS64
+ if (!g_KBMInput.IsMouseGrabbed() && g_KBMInput.IsKBMActive())
+ {
+ int deltaX = g_KBMInput.GetMouseDeltaX();
+ int deltaY = g_KBMInput.GetMouseDeltaY();
+
+ extern HWND g_hWnd;
+ RECT rc;
+ GetClientRect(g_hWnd, &rc);
+ int winW = rc.right - rc.left;
+ int winH = rc.bottom - rc.top;
+
+ if (winW > 0 && winH > 0)
+ {
+ float scaleX = (float)getMovieWidth() / (float)winW;
+ float scaleY = (float)getMovieHeight() / (float)winH;
+
+ vPointerPos.x += (float)deltaX * scaleX;
+ vPointerPos.y += (float)deltaY * scaleY;
+ }
+
+ if (deltaX != 0 || deltaY != 0)
+ {
+ bStickInput = true;
+ }
+ }
+#endif
+
// Determine which slot the pointer is currently over.
ESceneSection eSectionUnderPointer = eSectionNone;
int iNewSlotX = -1;
@@ -694,7 +728,11 @@ void IUIScene_AbstractContainerMenu::onMouseTick()
// If there is no stick input, and we are over a slot, then snap pointer to slot centre.
// 4J - TomK - only if this particular component allows so!
- if(!m_bPointerDrivenByMouse && CanHaveFocus(eSectionUnderPointer))
+#ifdef _WINDOWS64
+ if((g_KBMInput.IsMouseGrabbed() || !g_KBMInput.IsKBMActive()) && CanHaveFocus(eSectionUnderPointer))
+#else
+ if(CanHaveFocus(eSectionUnderPointer))
+#endif
{
vPointerPos.x = vSnapPos.x;
vPointerPos.y = vSnapPos.y;
@@ -1329,7 +1367,7 @@ bool IUIScene_AbstractContainerMenu::handleKeyDown(int iPad, int iAction, bool b
// Standard left click
buttonNum = 0;
- if (KMInput.IsKeyDown(VK_SHIFT))
+ if (g_KBMInput.IsKeyDown(VK_LSHIFT))
{
{
validKeyPress = TRUE;
diff --git a/Minecraft.Client/Common/UI/IUIScene_AbstractContainerMenu.h b/Minecraft.Client/Common/UI/IUIScene_AbstractContainerMenu.h
index fe79bf19..4877cfce 100644
--- a/Minecraft.Client/Common/UI/IUIScene_AbstractContainerMenu.h
+++ b/Minecraft.Client/Common/UI/IUIScene_AbstractContainerMenu.h
@@ -1,5 +1,15 @@
#pragma once
+#ifdef _WINDOWS64
+struct SavedInventoryCursorPos
+{
+ float x;
+ float y;
+ bool hasSavedPos;
+};
+extern SavedInventoryCursorPos g_savedInventoryCursorPos;
+#endif
+
// Uncomment to enable tap input detection to jump 1 slot. Doesn't work particularly well yet, and I feel the system does not need it.
// Would probably be required if we decide to slow down the pointer movement.
// 4J Stu - There was a request to be able to navigate the scenes with the dpad, so I have used much of the TAP_DETECTION
@@ -265,4 +275,6 @@ protected:
public:
virtual int getPad() = 0;
+ virtual int getMovieWidth() = 0;
+ virtual int getMovieHeight() = 0;
};
diff --git a/Minecraft.Client/Common/UI/UIControl.cpp b/Minecraft.Client/Common/UI/UIControl.cpp
index ec2e13d8..be267ada 100644
--- a/Minecraft.Client/Common/UI/UIControl.cpp
+++ b/Minecraft.Client/Common/UI/UIControl.cpp
@@ -42,7 +42,6 @@ bool UIControl::setupControl(UIScene *scene, IggyValuePath *parent, const string
return res;
}
-#ifdef __PSVITA__
void UIControl::UpdateControl()
{
F64 fx, fy, fwidth, fheight;
@@ -55,7 +54,6 @@ void UIControl::UpdateControl()
m_width = (S32)Math::round(fwidth);
m_height = (S32)Math::round(fheight);
}
-#endif // __PSVITA__
void UIControl::ReInit()
{
diff --git a/Minecraft.Client/Common/UI/UIControl.h b/Minecraft.Client/Common/UI/UIControl.h
index e37f04de..29770df2 100644
--- a/Minecraft.Client/Common/UI/UIControl.h
+++ b/Minecraft.Client/Common/UI/UIControl.h
@@ -61,8 +61,8 @@ public:
UIControl();
virtual bool setupControl(UIScene *scene, IggyValuePath *parent, const string &controlName);
-#ifdef __PSVITA__
void UpdateControl();
+#ifdef __PSVITA__
void setHidden(bool bHidden) {m_bHidden=bHidden;}
bool getHidden(void) {return m_bHidden;}
#endif
diff --git a/Minecraft.Client/Common/UI/UIController.cpp b/Minecraft.Client/Common/UI/UIController.cpp
index 6ac2f9ba..01ab49ba 100644
--- a/Minecraft.Client/Common/UI/UIController.cpp
+++ b/Minecraft.Client/Common/UI/UIController.cpp
@@ -2,6 +2,7 @@
#include "UIController.h"
#include "UI.h"
#include "UIScene.h"
+#include "UIControl_Slider.h"
#include "..\..\..\Minecraft.World\StringHelpers.h"
#include "..\..\LocalPlayer.h"
#include "..\..\DLCTexturePack.h"
@@ -11,6 +12,9 @@
#include "..\..\EnderDragonRenderer.h"
#include "..\..\MultiPlayerLocalPlayer.h"
#include "UIFontData.h"
+#ifdef _WINDOWS64
+#include "..\..\Windows64\KeyboardMouseInput.h"
+#endif
#ifdef __PSVITA__
#include <message_dialog.h>
#endif
@@ -52,6 +56,21 @@ bool UIController::ms_bReloadSkinCSInitialised = false;
DWORD UIController::m_dwTrialTimerLimitSecs=DYNAMIC_CONFIG_DEFAULT_TRIAL_TIME;
+#ifdef _WINDOWS64
+static UIControl_Slider *FindSliderById(UIScene *pScene, int sliderId)
+{
+ vector<UIControl *> *controls = pScene->GetControls();
+ if (!controls) return NULL;
+ for (size_t i = 0; i < controls->size(); ++i)
+ {
+ UIControl *ctrl = (*controls)[i];
+ if (ctrl && ctrl->getControlType() == UIControl::eSlider && ctrl->getId() == sliderId)
+ return (UIControl_Slider *)ctrl;
+ }
+ return NULL;
+}
+#endif
+
static void RADLINK WarningCallback(void *user_callback_data, Iggy *player, IggyResult code, const char *message)
{
//enum IggyResult{ IGGY_RESULT_SUCCESS = 0, IGGY_RESULT_Warning_None = 0,
@@ -216,6 +235,10 @@ UIController::UIController()
m_currentRenderViewport = C4JRender::VIEWPORT_TYPE_FULLSCREEN;
m_bCustomRenderPosition = false;
m_winUserIndex = 0;
+ m_mouseDraggingSliderScene = eUIScene_COUNT;
+ m_mouseDraggingSliderId = -1;
+ m_lastHoverMouseX = -1;
+ m_lastHoverMouseY = -1;
m_accumulatedTicks = 0;
m_lastUiSfx = 0;
@@ -761,6 +784,168 @@ void UIController::tickInput()
else
#endif
{
+#ifdef _WINDOWS64
+ if (!g_KBMInput.IsMouseGrabbed() && g_KBMInput.IsKBMActive())
+ {
+ UIScene *pScene = NULL;
+ for (int grp = 0; grp < eUIGroup_COUNT && !pScene; ++grp)
+ {
+ pScene = m_groups[grp]->GetTopScene(eUILayer_Debug);
+ if (!pScene) pScene = m_groups[grp]->GetTopScene(eUILayer_Tooltips);
+ if (!pScene) pScene = m_groups[grp]->GetTopScene(eUILayer_Error);
+ if (!pScene) pScene = m_groups[grp]->GetTopScene(eUILayer_Alert);
+ if (!pScene) pScene = m_groups[grp]->GetTopScene(eUILayer_Popup);
+ if (!pScene) pScene = m_groups[grp]->GetTopScene(eUILayer_Fullscreen);
+ if (!pScene) pScene = m_groups[grp]->GetTopScene(eUILayer_Scene);
+ }
+ if (pScene && pScene->getMovie())
+ {
+ Iggy *movie = pScene->getMovie();
+ int rawMouseX = g_KBMInput.GetMouseX();
+ int rawMouseY = g_KBMInput.GetMouseY();
+ F32 mouseX = (F32)rawMouseX;
+ F32 mouseY = (F32)rawMouseY;
+
+ extern HWND g_hWnd;
+ if (g_hWnd)
+ {
+ RECT rc;
+ GetClientRect(g_hWnd, &rc);
+ int winW = rc.right - rc.left;
+ int winH = rc.bottom - rc.top;
+ if (winW > 0 && winH > 0)
+ {
+ mouseX = mouseX * (m_fScreenWidth / (F32)winW);
+ mouseY = mouseY * (m_fScreenHeight / (F32)winH);
+ }
+ }
+
+ // Only update hover focus when the mouse has actually moved,
+ // so that mouse-wheel scrolling can change list selection
+ // without the hover immediately snapping focus back.
+ bool mouseMoved = (rawMouseX != m_lastHoverMouseX || rawMouseY != m_lastHoverMouseY);
+ m_lastHoverMouseX = rawMouseX;
+ m_lastHoverMouseY = rawMouseY;
+
+ if (mouseMoved)
+ {
+ IggyFocusHandle currentFocus = IGGY_FOCUS_NULL;
+ IggyFocusableObject focusables[64];
+ S32 numFocusables = 0;
+ IggyPlayerGetFocusableObjects(movie, &currentFocus, focusables, 64, &numFocusables);
+
+ if (numFocusables > 0 && numFocusables <= 64)
+ {
+ IggyFocusHandle hitObject = IGGY_FOCUS_NULL;
+ for (S32 i = 0; i < numFocusables; ++i)
+ {
+ if (mouseX >= focusables[i].x0 && mouseX <= focusables[i].x1 &&
+ mouseY >= focusables[i].y0 && mouseY <= focusables[i].y1)
+ {
+ hitObject = focusables[i].object;
+ break;
+ }
+ }
+
+ if (hitObject != currentFocus)
+ {
+ IggyPlayerSetFocusRS(movie, hitObject, 0);
+ }
+ }
+ }
+
+ // Convert mouse to scene/movie coordinates for slider hit testing
+ F32 sceneMouseX = mouseX;
+ F32 sceneMouseY = mouseY;
+ {
+ S32 displayWidth = 0, displayHeight = 0;
+ pScene->GetParentLayer()->getRenderDimensions(displayWidth, displayHeight);
+ if (displayWidth > 0 && displayHeight > 0)
+ {
+ sceneMouseX = mouseX * ((F32)pScene->getRenderWidth() / (F32)displayWidth);
+ sceneMouseY = mouseY * ((F32)pScene->getRenderHeight() / (F32)displayHeight);
+ }
+ }
+
+ // Get main panel offset (controls are positioned relative to it)
+ S32 panelOffsetX = 0, panelOffsetY = 0;
+ UIControl *pMainPanel = pScene->GetMainPanel();
+ if (pMainPanel)
+ {
+ pMainPanel->UpdateControl();
+ panelOffsetX = pMainPanel->getXPos();
+ panelOffsetY = pMainPanel->getYPos();
+ }
+
+ bool leftPressed = g_KBMInput.IsMouseButtonPressed(KeyboardMouseInput::MOUSE_LEFT);
+ bool leftDown = leftPressed || g_KBMInput.IsMouseButtonDown(KeyboardMouseInput::MOUSE_LEFT);
+
+ if (m_mouseDraggingSliderScene != eUIScene_COUNT && m_mouseDraggingSliderScene != pScene->getSceneType())
+ {
+ m_mouseDraggingSliderScene = eUIScene_COUNT;
+ m_mouseDraggingSliderId = -1;
+ }
+
+ if (leftPressed)
+ {
+ vector<UIControl *> *controls = pScene->GetControls();
+ if (controls)
+ {
+ for (size_t i = 0; i < controls->size(); ++i)
+ {
+ UIControl *ctrl = (*controls)[i];
+ if (!ctrl || ctrl->getControlType() != UIControl::eSlider || !ctrl->getVisible())
+ continue;
+
+ UIControl_Slider *pSlider = (UIControl_Slider *)ctrl;
+ pSlider->UpdateControl();
+ S32 cx = pSlider->getXPos() + panelOffsetX;
+ S32 cy = pSlider->getYPos() + panelOffsetY;
+ S32 cw = pSlider->GetRealWidth();
+ S32 ch = pSlider->getHeight();
+ if (cw <= 0 || ch <= 0)
+ continue;
+
+ if (sceneMouseX >= cx && sceneMouseX <= cx + cw && sceneMouseY >= cy && sceneMouseY <= cy + ch)
+ {
+ m_mouseDraggingSliderScene = pScene->getSceneType();
+ m_mouseDraggingSliderId = pSlider->getId();
+ break;
+ }
+ }
+ }
+ }
+
+ if (leftDown && m_mouseDraggingSliderScene == pScene->getSceneType() && m_mouseDraggingSliderId >= 0)
+ {
+ UIControl_Slider *pSlider = FindSliderById(pScene, m_mouseDraggingSliderId);
+ if (pSlider && pSlider->getVisible())
+ {
+ pSlider->UpdateControl();
+ S32 sliderX = pSlider->getXPos() + panelOffsetX;
+ S32 sliderWidth = pSlider->GetRealWidth();
+ if (sliderWidth > 0)
+ {
+ float fNewSliderPos = (sceneMouseX - (float)sliderX) / (float)sliderWidth;
+ if (fNewSliderPos < 0.0f) fNewSliderPos = 0.0f;
+ if (fNewSliderPos > 1.0f) fNewSliderPos = 1.0f;
+ pSlider->SetSliderTouchPos(fNewSliderPos);
+ }
+ }
+ else
+ {
+ m_mouseDraggingSliderScene = eUIScene_COUNT;
+ m_mouseDraggingSliderId = -1;
+ }
+ }
+ else if (!leftDown)
+ {
+ m_mouseDraggingSliderScene = eUIScene_COUNT;
+ m_mouseDraggingSliderId = -1;
+ }
+ }
+ }
+#endif
handleInput();
++m_accumulatedTicks;
}
@@ -995,28 +1180,59 @@ void UIController::handleKeyPress(unsigned int iPad, unsigned int key)
released = InputManager.ButtonReleased(iPad,key); // Toggle
#ifdef _WINDOWS64
- // Keyboard menu input for player 0
if (iPad == 0)
{
- bool kbDown = false, kbPressed = false, kbReleased = false;
- switch(key)
+ int vk = 0;
+ switch (key)
{
- case ACTION_MENU_UP: kbDown = KMInput.IsKeyDown(VK_UP); kbPressed = KMInput.IsKeyPressed(VK_UP); kbReleased = KMInput.IsKeyReleased(VK_UP); break;
- case ACTION_MENU_DOWN: kbDown = KMInput.IsKeyDown(VK_DOWN); kbPressed = KMInput.IsKeyPressed(VK_DOWN); kbReleased = KMInput.IsKeyReleased(VK_DOWN); break;
- case ACTION_MENU_LEFT: kbDown = KMInput.IsKeyDown(VK_LEFT); kbPressed = KMInput.IsKeyPressed(VK_LEFT); kbReleased = KMInput.IsKeyReleased(VK_LEFT); break;
- case ACTION_MENU_RIGHT: kbDown = KMInput.IsKeyDown(VK_RIGHT); kbPressed = KMInput.IsKeyPressed(VK_RIGHT); kbReleased = KMInput.IsKeyReleased(VK_RIGHT); break;
- case ACTION_MENU_OK: kbDown = KMInput.IsKeyDown(VK_RETURN); kbPressed = KMInput.IsKeyPressed(VK_RETURN); kbReleased = KMInput.IsKeyReleased(VK_RETURN); break;
- case ACTION_MENU_A: kbDown = KMInput.IsKeyDown(VK_RETURN); kbPressed = KMInput.IsKeyPressed(VK_RETURN); kbReleased = KMInput.IsKeyReleased(VK_RETURN); break;
- case ACTION_MENU_CANCEL: kbDown = KMInput.IsKeyDown(VK_ESCAPE); kbPressed = KMInput.IsKeyPressed(VK_ESCAPE); kbReleased = KMInput.IsKeyReleased(VK_ESCAPE); break;
- case ACTION_MENU_B: kbDown = KMInput.IsKeyDown(VK_ESCAPE); kbPressed = KMInput.IsKeyPressed(VK_ESCAPE); kbReleased = KMInput.IsKeyReleased(VK_ESCAPE); break;
- case ACTION_MENU_PAUSEMENU: kbDown = KMInput.IsKeyDown(VK_ESCAPE); kbPressed = KMInput.IsKeyPressed(VK_ESCAPE); kbReleased = KMInput.IsKeyReleased(VK_ESCAPE); break;
- case ACTION_MENU_LEFT_SCROLL: kbDown = KMInput.IsKeyDown('Q'); kbPressed = KMInput.IsKeyPressed('Q'); kbReleased = KMInput.IsKeyReleased('Q'); break;
- case ACTION_MENU_RIGHT_SCROLL: kbDown = KMInput.IsKeyDown('E'); kbPressed = KMInput.IsKeyPressed('E'); kbReleased = KMInput.IsKeyReleased('E'); break;
- case ACTION_MENU_QUICK_MOVE: kbDown = KMInput.IsKeyDown(VK_SHIFT); kbPressed = KMInput.IsKeyPressed(VK_SHIFT); kbReleased = KMInput.IsKeyReleased(VK_SHIFT); break;
+ case ACTION_MENU_OK: case ACTION_MENU_A: vk = VK_RETURN; break;
+ case ACTION_MENU_CANCEL: case ACTION_MENU_B: vk = VK_ESCAPE; break;
+ case ACTION_MENU_UP: vk = VK_UP; break;
+ case ACTION_MENU_DOWN: vk = VK_DOWN; break;
+ case ACTION_MENU_LEFT: vk = VK_LEFT; break;
+ case ACTION_MENU_RIGHT: vk = VK_RIGHT; break;
+ case ACTION_MENU_X: vk = 'R'; break;
+ case ACTION_MENU_Y: vk = VK_TAB; break;
+ case ACTION_MENU_LEFT_SCROLL: vk = 'Q'; break;
+ case ACTION_MENU_RIGHT_SCROLL: vk = 'E'; break;
+ case ACTION_MENU_PAGEUP: vk = VK_PRIOR; break;
+ case ACTION_MENU_PAGEDOWN: vk = VK_NEXT; break;
+ }
+ if (vk != 0)
+ {
+ if (g_KBMInput.IsKeyPressed(vk)) { pressed = true; down = true; }
+ if (g_KBMInput.IsKeyReleased(vk)) { released = true; down = false; }
+ if (!pressed && !released && g_KBMInput.IsKeyDown(vk)) { down = true; }
+ }
+
+ if ((key == ACTION_MENU_OK || key == ACTION_MENU_A) && !g_KBMInput.IsMouseGrabbed())
+ {
+ if (m_mouseDraggingSliderId < 0)
+ {
+ if (g_KBMInput.IsMouseButtonPressed(KeyboardMouseInput::MOUSE_LEFT)) { pressed = true; down = true; }
+ if (g_KBMInput.IsMouseButtonReleased(KeyboardMouseInput::MOUSE_LEFT)) { released = true; down = false; }
+ if (!pressed && !released && g_KBMInput.IsMouseButtonDown(KeyboardMouseInput::MOUSE_LEFT)) { down = true; }
+ }
+ }
+
+ // Scroll wheel for list scrolling — only consume the wheel value when the
+ // action key actually matches, so the other direction isn't lost.
+ if (!g_KBMInput.IsMouseGrabbed() && (key == ACTION_MENU_OTHER_STICK_UP || key == ACTION_MENU_OTHER_STICK_DOWN))
+ {
+ int wheel = g_KBMInput.PeekMouseWheel();
+ if (key == ACTION_MENU_OTHER_STICK_UP && wheel > 0)
+ {
+ g_KBMInput.ConsumeMouseWheel();
+ pressed = true;
+ down = true;
+ }
+ else if (key == ACTION_MENU_OTHER_STICK_DOWN && wheel < 0)
+ {
+ g_KBMInput.ConsumeMouseWheel();
+ pressed = true;
+ down = true;
+ }
}
- pressed = pressed || kbPressed;
- released = released || kbReleased;
- down = down || kbDown;
}
#endif
@@ -3138,4 +3354,4 @@ void UIController::SendTouchInput(unsigned int iPad, unsigned int key, bool bPre
}
-#endif \ No newline at end of file
+#endif
diff --git a/Minecraft.Client/Common/UI/UIController.h b/Minecraft.Client/Common/UI/UIController.h
index 49c78032..373d67b2 100644
--- a/Minecraft.Client/Common/UI/UIController.h
+++ b/Minecraft.Client/Common/UI/UIController.h
@@ -158,6 +158,10 @@ private:
vector<QueuedMessageBoxData *> m_queuedMessageBoxData;
unsigned int m_winUserIndex;
+ EUIScene m_mouseDraggingSliderScene;
+ int m_mouseDraggingSliderId;
+ int m_lastHoverMouseX;
+ int m_lastHoverMouseY;
//bool m_bSysUIShowing;
bool m_bSystemUIShowing;
C4JThread *m_reloadSkinThread;
diff --git a/Minecraft.Client/Common/UI/UIGroup.h b/Minecraft.Client/Common/UI/UIGroup.h
index 0ffee0ca..28369f27 100644
--- a/Minecraft.Client/Common/UI/UIGroup.h
+++ b/Minecraft.Client/Common/UI/UIGroup.h
@@ -37,9 +37,7 @@ private:
public:
UIGroup(EUIGroup group, int iPad);
-#ifdef __PSVITA__
EUIGroup GetGroup() {return m_group;}
-#endif
UIComponent_Tooltips *getTooltips() { return m_tooltips; }
UIComponent_TutorialPopup *getTutorialPopup() { return m_tutorialPopup; }
UIScene_HUD *getHUD() { return m_hud; }
diff --git a/Minecraft.Client/Common/UI/UIScene.h b/Minecraft.Client/Common/UI/UIScene.h
index 8c20aaae..b4008fa0 100644
--- a/Minecraft.Client/Common/UI/UIScene.h
+++ b/Minecraft.Client/Common/UI/UIScene.h
@@ -107,8 +107,10 @@ public:
int getRenderHeight() { return m_renderHeight; }
#ifdef __PSVITA__
- UILayer *GetParentLayer() {return m_parentLayer;}
EUIGroup GetParentLayerGroup() {return m_parentLayer->m_parentGroup->GetGroup();}
+#endif
+#if defined(__PSVITA__) || defined(_WINDOWS64)
+ UILayer *GetParentLayer() {return m_parentLayer;}
vector<UIControl *> *GetControls() {return &m_controls;}
#endif
diff --git a/Minecraft.Client/Common/UI/UIScene_AbstractContainerMenu.cpp b/Minecraft.Client/Common/UI/UIScene_AbstractContainerMenu.cpp
index bb56c780..6b196c1b 100644
--- a/Minecraft.Client/Common/UI/UIScene_AbstractContainerMenu.cpp
+++ b/Minecraft.Client/Common/UI/UIScene_AbstractContainerMenu.cpp
@@ -28,17 +28,6 @@ UIScene_AbstractContainerMenu::UIScene_AbstractContainerMenu(int iPad, UILayer *
ui.OverrideSFX(m_iPad,ACTION_MENU_DOWN,true);
m_bIgnoreInput=false;
-#ifdef _WINDOWS64
- m_bMouseDragSlider=false;
- m_bHasMousePosition = false;
- m_lastMouseX = 0;
- m_lastMouseY = 0;
-
- for (int btn = 0; btn < 3; btn++)
- {
- KMInput.ConsumeMousePress(btn);
- }
-#endif
}
UIScene_AbstractContainerMenu::~UIScene_AbstractContainerMenu()
@@ -49,6 +38,16 @@ UIScene_AbstractContainerMenu::~UIScene_AbstractContainerMenu()
void UIScene_AbstractContainerMenu::handleDestroy()
{
app.DebugPrintf("UIScene_AbstractContainerMenu::handleDestroy\n");
+
+#ifdef _WINDOWS64
+ g_savedInventoryCursorPos.x = m_pointerPos.x;
+ g_savedInventoryCursorPos.y = m_pointerPos.y;
+ g_savedInventoryCursorPos.hasSavedPos = true;
+
+ g_KBMInput.SetScreenCursorHidden(false);
+ g_KBMInput.SetCursorHiddenForUI(false);
+#endif
+
Minecraft *pMinecraft = Minecraft::GetInstance();
if( pMinecraft->localgameModes[m_iPad] != NULL )
{
@@ -84,6 +83,10 @@ void UIScene_AbstractContainerMenu::InitDataAssociations(int iPad, AbstractConta
void UIScene_AbstractContainerMenu::PlatformInitialize(int iPad, int startIndex)
{
+#ifdef _WINDOWS64
+ g_KBMInput.SetScreenCursorHidden(true);
+ g_KBMInput.SetCursorHiddenForUI(true);
+#endif
m_labelInventory.init( app.GetString(IDS_INVENTORY) );
@@ -168,6 +171,19 @@ void UIScene_AbstractContainerMenu::PlatformInitialize(int iPad, int startIndex)
//m_pointerControl->SetPosition( &vPointerPos );
m_pointerPos = vPointerPos;
+#ifdef _WINDOWS64
+ if (g_savedInventoryCursorPos.hasSavedPos)
+ {
+ m_pointerPos.x = g_savedInventoryCursorPos.x;
+ m_pointerPos.y = g_savedInventoryCursorPos.y;
+
+ if (m_pointerPos.x < m_fPointerMinX) m_pointerPos.x = m_fPointerMinX;
+ if (m_pointerPos.x > m_fPointerMaxX) m_pointerPos.x = m_fPointerMaxX;
+ if (m_pointerPos.y < m_fPointerMinY) m_pointerPos.y = m_fPointerMinY;
+ if (m_pointerPos.y > m_fPointerMaxY) m_pointerPos.y = m_fPointerMaxY;
+ }
+#endif
+
IggyEvent mouseEvent;
S32 width, height;
m_parentLayer->getRenderDimensions(width, height);
@@ -190,139 +206,15 @@ void UIScene_AbstractContainerMenu::tick()
{
UIScene::tick();
-#ifdef _WINDOWS64
- bool mouseActive = (m_iPad == 0 && !KMInput.IsCaptured());
- bool drivePointerFromMouse = false;
- float rawMouseMovieX = 0, rawMouseMovieY = 0;
- int scrollDelta = 0;
- // Map Windows mouse position to the virtual pointer in movie coordinates
- if (mouseActive)
- {
- RECT clientRect;
- GetClientRect(KMInput.GetHWnd(), &clientRect);
- int clientWidth = clientRect.right;
- int clientHeight = clientRect.bottom;
- if (clientWidth > 0 && clientHeight > 0)
- {
- int mouseX = KMInput.GetMouseX();
- int mouseY = KMInput.GetMouseY();
- bool mouseMoved = !m_bHasMousePosition || mouseX != m_lastMouseX || mouseY != m_lastMouseY;
-
- m_bHasMousePosition = true;
- m_lastMouseX = mouseX;
- m_lastMouseY = mouseY;
- scrollDelta = KMInput.ConsumeScrollDelta();
-
- // Convert mouse position to movie coordinates using the movie/client ratio
- float mx = (float)mouseX * ((float)m_movieWidth / (float)clientWidth) - (float)m_controlMainPanel.getXPos();
- float my = (float)mouseY * ((float)m_movieHeight / (float)clientHeight) - (float)m_controlMainPanel.getYPos();
-
- rawMouseMovieX = mx;
- rawMouseMovieY = my;
-
- // Once the mouse has taken over the container cursor, keep following the OS cursor
- // until explicit controller input takes ownership back.
- drivePointerFromMouse = m_bPointerDrivenByMouse || mouseMoved || KMInput.IsMouseDown(0) || KMInput.IsMouseDown(1) || KMInput.IsMouseDown(2) || scrollDelta != 0;
- if (drivePointerFromMouse)
- {
- m_bPointerDrivenByMouse = true;
- m_eCurrTapState = eTapStateNoInput;
- m_pointerPos.x = mx;
- m_pointerPos.y = my;
- }
- }
- }
-#endif
-
onMouseTick();
-#ifdef _WINDOWS64
- // Dispatch mouse clicks AFTER onMouseTick() has updated m_eCurrSection from the new pointer position
- if (mouseActive)
- {
- if (KMInput.ConsumeMousePress(0))
- {
- if (m_eCurrSection == eSectionInventoryCreativeSlider)
- {
- // Scrollbar click: use raw mouse position (onMouseTick may have snapped m_pointerPos)
- m_bMouseDragSlider = true;
- m_pointerPos.x = rawMouseMovieX;
- m_pointerPos.y = rawMouseMovieY;
- handleOtherClicked(m_iPad, eSectionInventoryCreativeSlider, 0, false);
- }
- else
- {
- handleKeyDown(m_iPad, ACTION_MENU_A, false);
- }
- }
- else if (m_bMouseDragSlider && KMInput.IsMouseDown(0))
- {
- // Continue scrollbar drag: update scroll position from current mouse Y
- m_pointerPos.x = rawMouseMovieX;
- m_pointerPos.y = rawMouseMovieY;
- handleOtherClicked(m_iPad, eSectionInventoryCreativeSlider, 0, false);
- }
-
- if (!KMInput.IsMouseDown(0))
- m_bMouseDragSlider = false;
-
- if (KMInput.ConsumeMousePress(1))
- {
- handleKeyDown(m_iPad, ACTION_MENU_X, false);
- }
- if (KMInput.ConsumeMousePress(2))
- {
- handleKeyDown(m_iPad, ACTION_MENU_Y, false);
- }
-
- // Mouse scroll wheel for page scrolling
- if (scrollDelta > 0)
- {
- handleKeyDown(m_iPad, ACTION_MENU_OTHER_STICK_UP, false);
- }
- else if (scrollDelta < 0)
- {
- handleKeyDown(m_iPad, ACTION_MENU_OTHER_STICK_DOWN, false);
- }
-
- // ESC to close — must be last since it may destroy this scene
- if (KMInput.ConsumeKeyPress(VK_ESCAPE))
- {
- handleKeyDown(m_iPad, ACTION_MENU_B, false);
- return;
- }
- }
-#endif
-
IggyEvent mouseEvent;
S32 width, height;
m_parentLayer->getRenderDimensions(width, height);
-#ifdef _WINDOWS64
- S32 x, y;
- if (mouseActive && m_bPointerDrivenByMouse)
- {
- // Send raw mouse position directly as Iggy event to avoid coordinate round-trip errors
- // Scale mouse client coords to the Iggy display space (which was set to getRenderDimensions())
- RECT clientRect;
- GetClientRect(KMInput.GetHWnd(), &clientRect);
- float mouseMovieX = (float)KMInput.GetMouseX() * ((float)m_movieWidth / (float)clientRect.right);
- float mouseMovieY = (float)KMInput.GetMouseY() * ((float)m_movieHeight / (float)clientRect.bottom);
- float mouseLocalX = mouseMovieX - (float)m_controlMainPanel.getXPos();
- float mouseLocalY = mouseMovieY - (float)m_controlMainPanel.getYPos();
-
- x = (S32)(mouseLocalX * ((float)width / m_movieWidth));
- y = (S32)(mouseLocalY * ((float)height / m_movieHeight));
- }
- else
- {
- x = (S32)(m_pointerPos.x * ((float)width / m_movieWidth));
- y = (S32)(m_pointerPos.y * ((float)height / m_movieHeight));
- }
-#else
- S32 x = m_pointerPos.x*((float)width/m_movieWidth);
- S32 y = m_pointerPos.y*((float)height/m_movieHeight);
-#endif
+ S32 x = (S32)(m_pointerPos.x * ((float)width / m_movieWidth));
+ S32 y = (S32)(m_pointerPos.y * ((float)height / m_movieHeight));
+
IggyMakeEventMouseMove( &mouseEvent, x, y);
// 4J Stu - This seems to be broken on Durango, so do it ourself
diff --git a/Minecraft.Client/Common/UI/UIScene_AbstractContainerMenu.h b/Minecraft.Client/Common/UI/UIScene_AbstractContainerMenu.h
index 812c5b41..605f5dbd 100644
--- a/Minecraft.Client/Common/UI/UIScene_AbstractContainerMenu.h
+++ b/Minecraft.Client/Common/UI/UIScene_AbstractContainerMenu.h
@@ -10,12 +10,6 @@ class UIScene_AbstractContainerMenu : public UIScene, public virtual IUIScene_Ab
private:
ESceneSection m_focusSection;
bool m_bIgnoreInput;
-#ifdef _WINDOWS64
- bool m_bMouseDragSlider;
- bool m_bHasMousePosition;
- int m_lastMouseX;
- int m_lastMouseY;
-#endif
protected:
UIControl m_controlMainPanel;
@@ -42,6 +36,8 @@ public:
virtual void handleDestroy();
int getPad() { return m_iPad; }
+ int getMovieWidth() { return m_movieWidth; }
+ int getMovieHeight() { return m_movieHeight; }
bool getIgnoreInput() { return m_bIgnoreInput; }
void setIgnoreInput(bool bVal) { m_bIgnoreInput=bVal; }
diff --git a/Minecraft.Client/Common/UI/UIScene_LoadOrJoinMenu.cpp b/Minecraft.Client/Common/UI/UIScene_LoadOrJoinMenu.cpp
index a5cb9aa2..d3cbe4c3 100644
--- a/Minecraft.Client/Common/UI/UIScene_LoadOrJoinMenu.cpp
+++ b/Minecraft.Client/Common/UI/UIScene_LoadOrJoinMenu.cpp
@@ -1317,6 +1317,14 @@ void UIScene_LoadOrJoinMenu::handleInput(int iPad, int key, bool repeat, bool pr
sendInputToMovie(key, repeat, pressed, released);
handled = true;
break;
+ case ACTION_MENU_OTHER_STICK_UP:
+ sendInputToMovie(ACTION_MENU_UP, repeat, pressed, released);
+ handled = true;
+ break;
+ case ACTION_MENU_OTHER_STICK_DOWN:
+ sendInputToMovie(ACTION_MENU_DOWN, repeat, pressed, released);
+ handled = true;
+ break;
}
}
diff --git a/Minecraft.Client/Common/UI/UIScene_SettingsGraphicsMenu.cpp b/Minecraft.Client/Common/UI/UIScene_SettingsGraphicsMenu.cpp
index 9bf3b983..0a76a5e5 100644
--- a/Minecraft.Client/Common/UI/UIScene_SettingsGraphicsMenu.cpp
+++ b/Minecraft.Client/Common/UI/UIScene_SettingsGraphicsMenu.cpp
@@ -4,6 +4,33 @@
#include "..\..\Minecraft.h"
#include "..\..\GameRenderer.h"
+namespace
+{
+ const int FOV_MIN = 70;
+ const int FOV_MAX = 110;
+ const int FOV_SLIDER_MAX = 100;
+
+ int clampFov(int value)
+ {
+ if (value < FOV_MIN) return FOV_MIN;
+ if (value > FOV_MAX) return FOV_MAX;
+ return value;
+ }
+
+ int fovToSliderValue(float fov)
+ {
+ int clampedFov = clampFov((int)(fov + 0.5f));
+ return ((clampedFov - FOV_MIN) * FOV_SLIDER_MAX) / (FOV_MAX - FOV_MIN);
+ }
+
+ int sliderValueToFov(int sliderValue)
+ {
+ if (sliderValue < 0) sliderValue = 0;
+ if (sliderValue > FOV_SLIDER_MAX) sliderValue = FOV_SLIDER_MAX;
+ return FOV_MIN + ((sliderValue * (FOV_MAX - FOV_MIN)) / FOV_SLIDER_MAX);
+ }
+}
+
UIScene_SettingsGraphicsMenu::UIScene_SettingsGraphicsMenu(int iPad, void *initData, UILayer *parentLayer) : UIScene(iPad, parentLayer)
{
// Setup all the Iggy references we need for this scene
@@ -22,8 +49,9 @@ UIScene_SettingsGraphicsMenu::UIScene_SettingsGraphicsMenu(int iPad, void *initD
swprintf( (WCHAR *)TempString, 256, L"%ls: %d%%", app.GetString( IDS_SLIDER_GAMMA ),app.GetGameSettings(m_iPad,eGameSetting_Gamma));
m_sliderGamma.init(TempString,eControl_Gamma,0,100,app.GetGameSettings(m_iPad,eGameSetting_Gamma));
- swprintf((WCHAR*)TempString, 256, L"FOV: %d%%", (int)pMinecraft->gameRenderer->GetFovVal());
- m_sliderFOV.init(TempString, eControl_FOV, 70, 110, (int)pMinecraft->gameRenderer->GetFovVal());
+ int initialFov = clampFov((int)(pMinecraft->gameRenderer->GetFovVal() + 0.5f));
+ swprintf((WCHAR*)TempString, 256, L"FOV: %d", initialFov);
+ m_sliderFOV.init(TempString, eControl_FOV, 0, FOV_SLIDER_MAX, fovToSliderValue((float)initialFov));
swprintf( (WCHAR *)TempString, 256, L"%ls: %d%%", app.GetString( IDS_SLIDER_INTERFACEOPACITY ),app.GetGameSettings(m_iPad,eGameSetting_InterfaceOpacity));
m_sliderInterfaceOpacity.init(TempString,eControl_InterfaceOpacity,0,100,app.GetGameSettings(m_iPad,eGameSetting_InterfaceOpacity));
@@ -150,10 +178,12 @@ void UIScene_SettingsGraphicsMenu::handleSliderMove(F64 sliderId, F64 currentVal
case eControl_FOV:
{
+ m_sliderFOV.handleSliderMove(value);
Minecraft* pMinecraft = Minecraft::GetInstance();
- pMinecraft->gameRenderer->SetFovVal((float)currentValue);
+ int fovValue = sliderValueToFov(value);
+ pMinecraft->gameRenderer->SetFovVal((float)fovValue);
WCHAR TempString[256];
- swprintf((WCHAR*)TempString, 256, L"FOV: %d%%", (int)currentValue);
+ swprintf((WCHAR*)TempString, 256, L"FOV: %d", fovValue);
m_sliderFOV.setLabel(TempString);
}
break;
diff --git a/Minecraft.Client/Input.cpp b/Minecraft.Client/Input.cpp
index 1639d09b..5e41da29 100644
--- a/Minecraft.Client/Input.cpp
+++ b/Minecraft.Client/Input.cpp
@@ -7,20 +7,21 @@
#include "Input.h"
#include "..\Minecraft.Client\LocalPlayer.h"
#include "Options.h"
+#ifdef _WINDOWS64
+#include "Windows64\KeyboardMouseInput.h"
+#endif
Input::Input()
{
xa = 0;
ya = 0;
- sprintForward = 0;
wasJumping = false;
jumping = false;
sneaking = false;
- usingKeyboardMovement = false;
+ sprinting = false;
lReset = false;
rReset = false;
- m_gamepadSneaking = false;
}
void Input::tick(LocalPlayer *player)
@@ -32,43 +33,43 @@ void Input::tick(LocalPlayer *player)
Minecraft *pMinecraft=Minecraft::GetInstance();
int iPad=player->GetXboxPad();
+ float controllerXA = 0.0f;
+ float controllerYA = 0.0f;
+
// 4J-PB minecraft movement seems to be the wrong way round, so invert x!
if( pMinecraft->localgameModes[iPad]->isInputAllowed(MINECRAFT_ACTION_LEFT) || pMinecraft->localgameModes[iPad]->isInputAllowed(MINECRAFT_ACTION_RIGHT) )
- xa = -InputManager.GetJoypadStick_LX(iPad);
- else
- xa = 0.0f;
+ controllerXA = -InputManager.GetJoypadStick_LX(iPad);
if( pMinecraft->localgameModes[iPad]->isInputAllowed(MINECRAFT_ACTION_FORWARD) || pMinecraft->localgameModes[iPad]->isInputAllowed(MINECRAFT_ACTION_BACKWARD) )
- ya = InputManager.GetJoypadStick_LY(iPad);
- else
- ya = 0.0f;
- sprintForward = ya;
- usingKeyboardMovement = false;
+ controllerYA = InputManager.GetJoypadStick_LY(iPad);
+ float kbXA = 0.0f;
+ float kbYA = 0.0f;
#ifdef _WINDOWS64
- // WASD movement (combine with gamepad)
- if (iPad == 0 && KMInput.IsCaptured())
+ if (iPad == 0 && g_KBMInput.IsMouseGrabbed() && g_KBMInput.IsKBMActive())
{
- float kbX = 0.0f, kbY = 0.0f;
- if (KMInput.IsKeyDown('W')) { kbY += 1.0f; sprintForward += 1.0f; usingKeyboardMovement = true; }
- if (KMInput.IsKeyDown('S')) { kbY -= 1.0f; sprintForward -= 1.0f; usingKeyboardMovement = true; }
- if (KMInput.IsKeyDown('A')) { kbX += 1.0f; usingKeyboardMovement = true; } // inverted like gamepad
- if (KMInput.IsKeyDown('D')) { kbX -= 1.0f; usingKeyboardMovement = true; }
- // Normalize diagonal
- if (kbX != 0.0f && kbY != 0.0f) { kbX *= 0.707f; kbY *= 0.707f; }
- if (pMinecraft->localgameModes[iPad]->isInputAllowed(MINECRAFT_ACTION_LEFT) || pMinecraft->localgameModes[iPad]->isInputAllowed(MINECRAFT_ACTION_RIGHT))
- xa = max(min(xa + kbX, 1.0f), -1.0f);
- if (pMinecraft->localgameModes[iPad]->isInputAllowed(MINECRAFT_ACTION_FORWARD) || pMinecraft->localgameModes[iPad]->isInputAllowed(MINECRAFT_ACTION_BACKWARD))
- ya = max(min(ya + kbY, 1.0f), -1.0f);
+ if( pMinecraft->localgameModes[iPad]->isInputAllowed(MINECRAFT_ACTION_LEFT) || pMinecraft->localgameModes[iPad]->isInputAllowed(MINECRAFT_ACTION_RIGHT) )
+ kbXA = g_KBMInput.GetMoveX();
+ if( pMinecraft->localgameModes[iPad]->isInputAllowed(MINECRAFT_ACTION_FORWARD) || pMinecraft->localgameModes[iPad]->isInputAllowed(MINECRAFT_ACTION_BACKWARD) )
+ kbYA = g_KBMInput.GetMoveY();
}
#endif
- sprintForward = max(min(sprintForward, 1.0f), -1.0f);
+
+ if (kbXA != 0.0f || kbYA != 0.0f)
+ {
+ xa = kbXA;
+ ya = kbYA;
+ }
+ else
+ {
+ xa = controllerXA;
+ ya = controllerYA;
+ }
#ifndef _CONTENT_PACKAGE
if (app.GetFreezePlayers())
{
xa = ya = 0.0f;
- sprintForward = 0.0f;
player->abilities.flying = true;
}
#endif
@@ -80,7 +81,6 @@ void Input::tick(LocalPlayer *player)
lReset = true;
}
xa = ya = 0.0f;
- sprintForward = 0.0f;
}
// 4J: In flying mode, don't actually toggle sneaking (unless we're riding in which case we need to sneak to dismount)
@@ -88,15 +88,46 @@ void Input::tick(LocalPlayer *player)
{
if((player->ullButtonsPressed&(1LL<<MINECRAFT_ACTION_SNEAK_TOGGLE)) && pMinecraft->localgameModes[iPad]->isInputAllowed(MINECRAFT_ACTION_SNEAK_TOGGLE))
{
- m_gamepadSneaking=!m_gamepadSneaking;
+ sneaking=!sneaking;
}
}
- sneaking = m_gamepadSneaking;
#ifdef _WINDOWS64
- // Keyboard hold-to-sneak (overrides gamepad toggle)
- if (iPad == 0 && KMInput.IsCaptured() && KMInput.IsKeyDown(VK_SHIFT) && !player->abilities.flying)
- sneaking = true;
+ if (iPad == 0 && g_KBMInput.IsMouseGrabbed() && g_KBMInput.IsKBMActive())
+ {
+ // Left Shift = sneak (hold to crouch)
+ if (pMinecraft->localgameModes[iPad]->isInputAllowed(MINECRAFT_ACTION_SNEAK_TOGGLE))
+ {
+ if (!player->abilities.flying)
+ {
+ sneaking = g_KBMInput.IsKeyDown(KeyboardMouseInput::KEY_SNEAK);
+ }
+ }
+
+ // Left Ctrl + forward = sprint (hold to sprint)
+ if (!player->abilities.flying)
+ {
+ bool ctrlHeld = g_KBMInput.IsKeyDown(KeyboardMouseInput::KEY_SPRINT);
+ bool movingForward = (kbYA > 0.0f);
+
+ if (ctrlHeld && movingForward)
+ {
+ sprinting = true;
+ }
+ else
+ {
+ sprinting = false;
+ }
+ }
+ else
+ {
+ sprinting = false;
+ }
+ }
+ else if (iPad == 0)
+ {
+ sprinting = false;
+ }
#endif
if(sneaking)
@@ -109,6 +140,7 @@ void Input::tick(LocalPlayer *player)
float tx = 0.0f;
float ty = 0.0f;
+
if( pMinecraft->localgameModes[iPad]->isInputAllowed(MINECRAFT_ACTION_LOOK_LEFT) || pMinecraft->localgameModes[iPad]->isInputAllowed(MINECRAFT_ACTION_LOOK_RIGHT) )
tx = InputManager.GetJoypadStick_RX(iPad)*(((float)app.GetGameSettings(iPad,eGameSetting_Sensitivity_InGame))/100.0f); // apply sensitivity to look
if( pMinecraft->localgameModes[iPad]->isInputAllowed(MINECRAFT_ACTION_LOOK_UP) || pMinecraft->localgameModes[iPad]->isInputAllowed(MINECRAFT_ACTION_LOOK_DOWN) )
@@ -132,47 +164,52 @@ void Input::tick(LocalPlayer *player)
}
tx = ty = 0.0f;
}
- player->interpolateTurn(tx * abs(tx) * turnSpeed, ty * abs(ty) * turnSpeed);
+
+ float turnX = tx * abs(tx) * turnSpeed;
+ float turnY = ty * abs(ty) * turnSpeed;
#ifdef _WINDOWS64
- // Mouse look is now handled per-frame in Minecraft::applyFrameMouseLook()
- // to eliminate the 20Hz tick delay. Only flush any remaining delta here
- // as a safety measure.
- if (iPad == 0 && KMInput.IsCaptured())
+ if (iPad == 0 && g_KBMInput.IsMouseGrabbed() && g_KBMInput.IsKBMActive())
{
- float rawDx, rawDy;
- KMInput.ConsumeMouseDelta(rawDx, rawDy);
- // Delta should normally be 0 since applyFrameMouseLook() already consumed it
- if (rawDx != 0.0f || rawDy != 0.0f)
+ float mouseSensitivity = ((float)app.GetGameSettings(iPad,eGameSetting_Sensitivity_InGame)) / 100.0f;
+ float mouseLookScale = 5.0f;
+ float mx = g_KBMInput.GetLookX(mouseSensitivity * mouseLookScale);
+ float my = g_KBMInput.GetLookY(mouseSensitivity * mouseLookScale);
+
+ if ( app.GetGameSettings(iPad,eGameSetting_ControlInvertLook) )
{
- float mouseSensitivity = ((float)app.GetGameSettings(iPad, eGameSetting_Sensitivity_InGame)) / 100.0f;
- float mdx = rawDx * mouseSensitivity;
- float mdy = -rawDy * mouseSensitivity;
- if (app.GetGameSettings(iPad, eGameSetting_ControlInvertLook))
- mdy = -mdy;
- player->interpolateTurn(mdx, mdy);
+ my = -my;
}
+
+ turnX += mx;
+ turnY += my;
}
#endif
- //jumping = controller.isButtonPressed(0);
+ player->interpolateTurn(turnX, turnY);
+ //jumping = controller.isButtonPressed(0);
unsigned int jump = InputManager.GetValue(iPad, MINECRAFT_ACTION_JUMP);
- if( jump > 0 && pMinecraft->localgameModes[iPad]->isInputAllowed(MINECRAFT_ACTION_JUMP) )
+ bool kbJump = false;
+#ifdef _WINDOWS64
+ kbJump = (iPad == 0) && g_KBMInput.IsMouseGrabbed() && g_KBMInput.IsKBMActive() && g_KBMInput.IsKeyDown(KeyboardMouseInput::KEY_JUMP);
+#endif
+ if( (jump > 0 || kbJump) && pMinecraft->localgameModes[iPad]->isInputAllowed(MINECRAFT_ACTION_JUMP) )
jumping = true;
else
jumping = false;
-#ifdef _WINDOWS64
- // Keyboard jump (Space)
- if (iPad == 0 && KMInput.IsCaptured() && KMInput.IsKeyDown(VK_SPACE) && pMinecraft->localgameModes[iPad]->isInputAllowed(MINECRAFT_ACTION_JUMP))
- jumping = true;
-#endif
-
#ifndef _CONTENT_PACKAGE
if (app.GetFreezePlayers()) jumping = false;
#endif
+#ifdef _WINDOWS64
+ if (iPad == 0 && g_KBMInput.IsKeyPressed(VK_ESCAPE) && g_KBMInput.IsMouseGrabbed())
+ {
+ g_KBMInput.SetMouseGrabbed(false);
+ }
+#endif
+
//OutputDebugString("INPUT: End input tick\n");
}
diff --git a/Minecraft.Client/Input.h b/Minecraft.Client/Input.h
index d8dedd57..c7e1eec4 100644
--- a/Minecraft.Client/Input.h
+++ b/Minecraft.Client/Input.h
@@ -6,20 +6,17 @@ class Input
public:
float xa;
float ya;
- float sprintForward;
bool wasJumping;
bool jumping;
bool sneaking;
- bool usingKeyboardMovement;
-
- Input(); // 4J - added
+ bool sprinting;
+
+ Input();
virtual void tick(LocalPlayer *player);
private:
-
bool lReset;
bool rReset;
- bool m_gamepadSneaking;
};
diff --git a/Minecraft.Client/LocalPlayer.cpp b/Minecraft.Client/LocalPlayer.cpp
index bb25105f..77306621 100644
--- a/Minecraft.Client/LocalPlayer.cpp
+++ b/Minecraft.Client/LocalPlayer.cpp
@@ -251,13 +251,10 @@ void LocalPlayer::aiStep()
if (changingDimensionDelay > 0) changingDimensionDelay--;
bool wasJumping = input->jumping;
float runTreshold = 0.8f;
- float sprintForward = input->sprintForward;
-
- bool wasRunning = sprintForward >= runTreshold;
+ bool wasRunning = input->ya >= runTreshold;
//input->tick( dynamic_pointer_cast<Player>( shared_from_this() ) );
// 4J-PB - make it a localplayer
input->tick( this );
- sprintForward = input->sprintForward;
if (isUsingItem() && !isRiding())
{
input->xa *= 0.2f;
@@ -281,25 +278,9 @@ void LocalPlayer::aiStep()
// world with low food, then reload it in creative.
if(abilities.mayfly || isAllowedToFly() ) enoughFoodToSprint = true;
- bool forwardEnoughToTriggerSprint = sprintForward >= runTreshold;
- bool forwardReturnedToDeadzone = sprintForward == 0.0f;
- bool forwardEnoughToContinueSprint = sprintForward >= runTreshold;
-
-#ifdef _WINDOWS64
- if (GetXboxPad() == 0 && input->usingKeyboardMovement)
- {
- forwardEnoughToContinueSprint = sprintForward > 0.0f;
- }
-#endif
-
-#ifdef _WINDOWS64
- // Keyboard sprint: Ctrl held while moving forward
- if (GetXboxPad() == 0 && input->usingKeyboardMovement && KMInput.IsKeyDown(VK_CONTROL) && sprintForward > 0.0f &&
- enoughFoodToSprint && !isUsingItem() && !hasEffect(MobEffect::blindness) && onGround)
- {
- if (!isSprinting()) setSprinting(true);
- }
-#endif
+ bool forwardEnoughToTriggerSprint = input->ya >= runTreshold;
+ bool forwardReturnedToDeadzone = input->ya == 0.0f;
+ bool forwardEnoughToContinueSprint = input->ya >= runTreshold;
// 4J - altered this slightly to make sure that the joypad returns to below returnTreshold in between registering two movements up to runThreshold
if (onGround && !isSprinting() && enoughFoodToSprint && !isUsingItem() && !hasEffect(MobEffect::blindness))
@@ -327,6 +308,12 @@ void LocalPlayer::aiStep()
}
}
if (isSneaking()) sprintTriggerTime = 0;
+#ifdef _WINDOWS64
+ if (input->sprinting && onGround && enoughFoodToSprint && !isUsingItem() && !hasEffect(MobEffect::blindness) && !isSneaking())
+ {
+ setSprinting(true);
+ }
+#endif
// 4J-PB - try not stopping sprint on collision
//if (isSprinting() && (input->ya < runTreshold || horizontalCollision || !enoughFoodToSprint))
if (isSprinting() && (!forwardEnoughToContinueSprint || !enoughFoodToSprint || isSneaking() || isUsingItem()))
diff --git a/Minecraft.Client/Minecraft.cpp b/Minecraft.Client/Minecraft.cpp
index bd75a61a..19ee79bd 100644
--- a/Minecraft.Client/Minecraft.cpp
+++ b/Minecraft.Client/Minecraft.cpp
@@ -502,6 +502,13 @@ void Minecraft::setScreen(Screen *screen)
this->screen->removed();
}
+#ifdef _WINDOWS64
+ if (screen != NULL && g_KBMInput.IsMouseGrabbed())
+ {
+ g_KBMInput.SetMouseGrabbed(false);
+ }
+#endif
+
//4J Gordon: Do not force a stats save here
/*if (dynamic_cast<TitleScreen *>(screen)!=NULL)
{
@@ -1184,11 +1191,11 @@ void Minecraft::applyFrameMouseLook()
int iPad = localplayers[i]->GetXboxPad();
if (iPad != 0) continue; // Mouse only applies to pad 0
- if (!KMInput.IsCaptured()) continue;
+ if (!g_KBMInput.IsMouseGrabbed()) continue;
if (localgameModes[iPad] == NULL) continue;
float rawDx, rawDy;
- KMInput.ConsumeMouseDelta(rawDx, rawDy);
+ g_KBMInput.ConsumeMouseDelta(rawDx, rawDy);
if (rawDx == 0.0f && rawDy == 0.0f) continue;
float mouseSensitivity = ((float)app.GetGameSettings(iPad, eGameSetting_Sensitivity_InGame)) / 100.0f;
@@ -1450,14 +1457,54 @@ void Minecraft::run_middle()
// Keyboard/mouse button presses for player 0
if (i == 0)
{
- if (KMInput.ConsumeKeyPress(VK_ESCAPE)) localplayers[i]->ullButtonsPressed |= 1LL<<MINECRAFT_ACTION_PAUSEMENU;
- if (KMInput.ConsumeKeyPress('E')) localplayers[i]->ullButtonsPressed |= 1LL<<MINECRAFT_ACTION_INVENTORY;
- if (KMInput.ConsumeKeyPress('Q')) localplayers[i]->ullButtonsPressed |= 1LL<<MINECRAFT_ACTION_DROP;
- if (KMInput.ConsumeKeyPress('C')) localplayers[i]->ullButtonsPressed |= 1LL<<MINECRAFT_ACTION_CRAFTING;
- if (KMInput.ConsumeKeyPress(VK_F5)) localplayers[i]->ullButtonsPressed |= 1LL<<MINECRAFT_ACTION_RENDER_THIRD_PERSON;
+ if (g_KBMInput.IsKBMActive())
+ {
+ if(g_KBMInput.IsMouseButtonPressed(KeyboardMouseInput::MOUSE_LEFT))
+ localplayers[i]->ullButtonsPressed|=1LL<<MINECRAFT_ACTION_ACTION;
+
+ if(g_KBMInput.IsMouseButtonPressed(KeyboardMouseInput::MOUSE_RIGHT))
+ localplayers[i]->ullButtonsPressed|=1LL<<MINECRAFT_ACTION_USE;
+
+ if(g_KBMInput.IsKeyPressed(KeyboardMouseInput::KEY_INVENTORY))
+ localplayers[i]->ullButtonsPressed|=1LL<<MINECRAFT_ACTION_INVENTORY;
+
+ if(g_KBMInput.IsKeyPressed(KeyboardMouseInput::KEY_DROP))
+ localplayers[i]->ullButtonsPressed|=1LL<<MINECRAFT_ACTION_DROP;
+
+ if(g_KBMInput.IsKeyPressed(KeyboardMouseInput::KEY_CRAFTING) || g_KBMInput.IsKeyPressed(KeyboardMouseInput::KEY_CRAFTING_ALT))
+ localplayers[i]->ullButtonsPressed|=1LL<<MINECRAFT_ACTION_CRAFTING;
+
+ for (int slot = 0; slot < 9; slot++)
+ {
+ if (g_KBMInput.IsKeyPressed('1' + slot))
+ {
+ if (localplayers[i]->inventory)
+ localplayers[i]->inventory->selected = slot;
+ }
+ }
+ }
+
+ // Utility keys always work regardless of KBM active state
+ if(g_KBMInput.IsKeyPressed(KeyboardMouseInput::KEY_PAUSE) && !ui.IsTutorialVisible(i))
+ {
+ localplayers[i]->ullButtonsPressed|=1LL<<MINECRAFT_ACTION_PAUSEMENU;
+ app.DebugPrintf("PAUSE PRESSED (keyboard) - ipad = %d\n",i);
+ }
+
+ if(g_KBMInput.IsKeyPressed(KeyboardMouseInput::KEY_THIRD_PERSON))
+ localplayers[i]->ullButtonsPressed|=1LL<<MINECRAFT_ACTION_RENDER_THIRD_PERSON;
+
+ if(g_KBMInput.IsKeyPressed(KeyboardMouseInput::KEY_DEBUG_INFO))
+ {
+ localplayers[i]->ullButtonsPressed|=1LL<<MINECRAFT_ACTION_GAME_INFO;
+ }
+
// In flying mode, Shift held = sneak/descend
- if (localplayers[i]->abilities.flying && KMInput.IsKeyDown(VK_SHIFT) && !ui.GetMenuDisplayed(i))
- localplayers[i]->ullButtonsPressed |= 1LL<<MINECRAFT_ACTION_SNEAK_TOGGLE;
+ if(g_KBMInput.IsKBMActive() && g_KBMInput.IsKeyDown(KeyboardMouseInput::KEY_SNEAK))
+ {
+ if (localplayers[i]->abilities.flying && !ui.GetMenuDisplayed(i))
+ localplayers[i]->ullButtonsPressed|=1LL<<MINECRAFT_ACTION_SNEAK_TOGGLE;
+ }
}
#endif
@@ -2277,8 +2324,21 @@ void Minecraft::tick(bool bFirst, bool bUpdateTextures)
}
}
+#ifdef _WINDOWS64
+ if ((screen != NULL || ui.GetMenuDisplayed(iPad)) && g_KBMInput.IsMouseGrabbed())
+ {
+ g_KBMInput.SetMouseGrabbed(false);
+ }
+#endif
+
if (screen == NULL && !ui.GetMenuDisplayed(iPad) )
{
+#ifdef _WINDOWS64
+ if (!g_KBMInput.IsMouseGrabbed() && g_KBMInput.IsWindowFocused())
+ {
+ g_KBMInput.SetMouseGrabbed(true);
+ }
+#endif
// 4J-PB - add some tooltips if required
int iA=-1, iB=-1, iX, iY=IDS_CONTROLS_INVENTORY, iLT=-1, iRT=-1, iLB=-1, iRB=-1, iLS=-1, iRS=-1;
@@ -3432,26 +3492,9 @@ void Minecraft::tick(bool bFirst, bool bUpdateTextures)
}
#ifdef _WINDOWS64
- // Mouse scroll wheel for hotbar
- if (iPad == 0)
+ if (iPad == 0 && wheel == 0 && g_KBMInput.IsKBMActive())
{
- int kbWheel = KMInput.ConsumeScrollDelta();
- if (kbWheel > 0 && gameMode->isInputAllowed(MINECRAFT_ACTION_LEFT_SCROLL)) wheel += 1;
- else if (kbWheel < 0 && gameMode->isInputAllowed(MINECRAFT_ACTION_RIGHT_SCROLL)) wheel -= 1;
-
- // 1-9 keys for direct hotbar selection
- if (gameMode->isInputAllowed(MINECRAFT_ACTION_LEFT_SCROLL))
- {
- for (int k = '1'; k <= '9'; k++)
- {
- if (KMInput.ConsumeKeyPress(k))
- {
- player->inventory->selected = k - '1';
- app.SetOpacityTimer(iPad);
- break;
- }
- }
- }
+ wheel = g_KBMInput.GetMouseWheel();
}
#endif
if (wheel != 0)
@@ -3485,33 +3528,20 @@ void Minecraft::tick(bool bFirst, bool bUpdateTextures)
player->handleMouseClick(0);
player->lastClickTick[0] = ticks;
}
+
#ifdef _WINDOWS64
- else if (iPad == 0 && KMInput.IsCaptured() && KMInput.ConsumeMousePress(0))
- {
- player->handleMouseClick(0);
- player->lastClickTick[0] = ticks;
- }
+ bool actionHeld = InputManager.ButtonDown(iPad, MINECRAFT_ACTION_ACTION) || (iPad == 0 && g_KBMInput.IsKBMActive() && g_KBMInput.IsMouseButtonDown(KeyboardMouseInput::MOUSE_LEFT));
+#else
+ bool actionHeld = InputManager.ButtonDown(iPad, MINECRAFT_ACTION_ACTION);
#endif
-
- if (InputManager.ButtonDown(iPad, MINECRAFT_ACTION_ACTION) && ticks - player->lastClickTick[0] >= timer->ticksPerSecond / 4)
+ if (actionHeld && ticks - player->lastClickTick[0] >= timer->ticksPerSecond / 4)
{
//printf("MINECRAFT_ACTION_ACTION ButtonDown");
player->handleMouseClick(0);
player->lastClickTick[0] = ticks;
}
-#ifdef _WINDOWS64
- else if (iPad == 0 && KMInput.IsCaptured() && KMInput.IsMouseDown(0) && ticks - player->lastClickTick[0] >= timer->ticksPerSecond / 4)
- {
- player->handleMouseClick(0);
- player->lastClickTick[0] = ticks;
- }
-#endif
- if(InputManager.ButtonDown(iPad, MINECRAFT_ACTION_ACTION)
-#ifdef _WINDOWS64
- || (iPad == 0 && KMInput.IsCaptured() && KMInput.IsMouseDown(0))
-#endif
- )
+ if(actionHeld)
{
player->handleMouseDown(0, true );
}
@@ -3530,25 +3560,21 @@ void Minecraft::tick(bool bFirst, bool bUpdateTextures)
lastClickTick = ticks;
}
*/
- if( player->isUsingItem() )
- {
- if(!InputManager.ButtonDown(iPad, MINECRAFT_ACTION_USE)
#ifdef _WINDOWS64
- && !(iPad == 0 && KMInput.IsCaptured() && KMInput.IsMouseDown(1))
+ bool useHeld = InputManager.ButtonDown(iPad, MINECRAFT_ACTION_USE) || (iPad == 0 && g_KBMInput.IsKBMActive() && g_KBMInput.IsMouseButtonDown(KeyboardMouseInput::MOUSE_RIGHT));
+#else
+ bool useHeld = InputManager.ButtonDown(iPad, MINECRAFT_ACTION_USE);
#endif
- ) gameMode->releaseUsingItem(player);
+ if( player->isUsingItem() )
+ {
+ if(!useHeld) gameMode->releaseUsingItem(player);
}
else if( gameMode->isInputAllowed(MINECRAFT_ACTION_USE) )
{
-#ifdef _WINDOWS64
- bool useButtonDown = InputManager.ButtonDown(iPad, MINECRAFT_ACTION_USE) || (iPad == 0 && KMInput.IsCaptured() && KMInput.IsMouseDown(1));
-#else
- bool useButtonDown = InputManager.ButtonDown(iPad, MINECRAFT_ACTION_USE);
-#endif
if( player->abilities.instabuild )
{
// 4J - attempt to handle click in special creative mode fashion if possible (used for placing blocks at regular intervals)
- bool didClick = player->creativeModeHandleMouseClick(1, useButtonDown );
+ bool didClick = player->creativeModeHandleMouseClick(1, useHeld );
// If this handler has put us in lastClick_oldRepeat mode then it is because we aren't placing blocks - behave largely as the code used to
if( player->lastClickState == LocalPlayer::lastClick_oldRepeat )
{
@@ -3560,7 +3586,7 @@ void Minecraft::tick(bool bFirst, bool bUpdateTextures)
else
{
// Otherwise just the original game code for handling autorepeat
- if (useButtonDown && ticks - player->lastClickTick[1] >= timer->ticksPerSecond / 4)
+ if (useHeld && ticks - player->lastClickTick[1] >= timer->ticksPerSecond / 4)
{
player->handleMouseClick(1);
player->lastClickTick[1] = ticks;
@@ -3576,7 +3602,7 @@ void Minecraft::tick(bool bFirst, bool bUpdateTextures)
bool firstClick = ( player->lastClickTick[1] == 0 );
bool autoRepeat = ticks - player->lastClickTick[1] >= timer->ticksPerSecond / 4;
if ( player->isRiding() || player->isSprinting() || player->isSleeping() ) autoRepeat = false;
- if (useButtonDown )
+ if (useHeld )
{
// If the player has just exited a bed, then delay the time before a repeat key is allowed without releasing
if(player->isSleeping() ) player->lastClickTick[1] = ticks + (timer->ticksPerSecond * 2);
diff --git a/Minecraft.Client/Screen.cpp b/Minecraft.Client/Screen.cpp
index 6a402b04..e69b7373 100644
--- a/Minecraft.Client/Screen.cpp
+++ b/Minecraft.Client/Screen.cpp
@@ -110,13 +110,13 @@ void Screen::updateEvents()
// Poll mouse button state and dispatch click/release events
for (int btn = 0; btn < 3; btn++)
{
- if (KMInput.ConsumeMousePress(btn))
+ if (g_KBMInput.IsMouseButtonPressed(btn))
{
int xm = Mouse::getX() * width / minecraft->width;
int ym = height - Mouse::getY() * height / minecraft->height - 1;
mouseClicked(xm, ym, btn);
}
- if (KMInput.ConsumeMouseRelease(btn))
+ if (g_KBMInput.IsMouseButtonReleased(btn))
{
int xm = Mouse::getX() * width / minecraft->width;
int ym = height - Mouse::getY() * height / minecraft->height - 1;
@@ -127,7 +127,7 @@ void Screen::updateEvents()
// Poll keyboard events
for (int vk = 0; vk < 256; vk++)
{
- if (KMInput.ConsumeKeyPress(vk))
+ if (g_KBMInput.IsKeyPressed(vk))
{
// Map Windows virtual key to the Keyboard constants used by Screen::keyPressed
int mappedKey = -1;
@@ -144,7 +144,7 @@ void Screen::updateEvents()
else if (vk >= 'A' && vk <= 'Z')
{
ch = (wchar_t)(vk - 'A' + L'a');
- if (KMInput.IsKeyDown(VK_SHIFT)) ch = (wchar_t)vk;
+ if (g_KBMInput.IsKeyDown(VK_LSHIFT) || g_KBMInput.IsKeyDown(VK_RSHIFT)) ch = (wchar_t)vk;
}
else if (vk >= '0' && vk <= '9') ch = (wchar_t)vk;
else if (vk == VK_SPACE) ch = L' ';
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.
diff --git a/Minecraft.Client/stubs.cpp b/Minecraft.Client/stubs.cpp
index 16215ba2..af65eb75 100644
--- a/Minecraft.Client/stubs.cpp
+++ b/Minecraft.Client/stubs.cpp
@@ -3,41 +3,98 @@
#ifdef _WINDOWS64
#include "Windows64\KeyboardMouseInput.h"
+static const int s_keyToVK[] = {
+ 'A', // KEY_A = 0
+ 'B', // KEY_B = 1
+ 'C', // KEY_C = 2
+ 'D', // KEY_D = 3
+ 'E', // KEY_E = 4
+ 'F', // KEY_F = 5
+ 'G', // KEY_G = 6
+ 'H', // KEY_H = 7
+ 'I', // KEY_I = 8
+ 'J', // KEY_J = 9
+ 'K', // KEY_K = 10
+ 'L', // KEY_L = 11
+ 'M', // KEY_M = 12
+ 'N', // KEY_N = 13
+ 'O', // KEY_O = 14
+ 'P', // KEY_P = 15
+ 'Q', // KEY_Q = 16
+ 'R', // KEY_R = 17
+ 'S', // KEY_S = 18
+ 'T', // KEY_T = 19
+ 'U', // KEY_U = 20
+ 'V', // KEY_V = 21
+ 'W', // KEY_W = 22
+ 'X', // KEY_X = 23
+ 'Y', // KEY_Y = 24
+ 'Z', // KEY_Z = 25
+ VK_SPACE, // KEY_SPACE = 26
+ VK_LSHIFT, // KEY_LSHIFT = 27
+ VK_ESCAPE, // KEY_ESCAPE = 28
+ VK_BACK, // KEY_BACK = 29
+ VK_RETURN, // KEY_RETURN = 30
+ VK_RSHIFT, // KEY_RSHIFT = 31
+ VK_UP, // KEY_UP = 32
+ VK_DOWN, // KEY_DOWN = 33
+ VK_TAB, // KEY_TAB = 34
+ '1', // KEY_1 = 35
+ '2', // KEY_2 = 36
+ '3', // KEY_3 = 37
+ '4', // KEY_4 = 38
+ '5', // KEY_5 = 39
+ '6', // KEY_6 = 40
+ '7', // KEY_7 = 41
+ '8', // KEY_8 = 42
+ '9', // KEY_9 = 43
+ VK_F1, // KEY_F1 = 44
+ VK_F3, // KEY_F3 = 45
+ VK_F4, // KEY_F4 = 46
+ VK_F5, // KEY_F5 = 47
+ VK_F6, // KEY_F6 = 48
+ VK_F8, // KEY_F8 = 49
+ VK_F9, // KEY_F9 = 50
+ VK_F11, // KEY_F11 = 51
+ VK_ADD, // KEY_ADD = 52
+ VK_SUBTRACT,// KEY_SUBTRACT = 53
+ VK_LEFT, // KEY_LEFT = 54
+ VK_RIGHT, // KEY_RIGHT = 55
+};
+static const int s_keyToVKCount = sizeof(s_keyToVK) / sizeof(s_keyToVK[0]);
+
+int Keyboard::toVK(int keyConst)
+{
+ if (keyConst >= 0 && keyConst < s_keyToVKCount)
+ return s_keyToVK[keyConst];
+ return 0;
+}
+
+bool Keyboard::isKeyDown(int keyCode)
+{
+ int vk = toVK(keyCode);
+ if (vk > 0)
+ return g_KBMInput.IsKeyDown(vk);
+ return false;
+}
+
int Mouse::getX()
{
- return KMInput.GetMouseX();
+ return g_KBMInput.GetMouseX();
}
int Mouse::getY()
{
// Return Y in bottom-up coordinates (OpenGL convention, matching original Java LWJGL Mouse)
+ extern HWND g_hWnd;
RECT rect;
- GetClientRect(KMInput.GetHWnd(), &rect);
- return (rect.bottom - 1) - KMInput.GetMouseY();
+ GetClientRect(g_hWnd, &rect);
+ return (rect.bottom - 1) - g_KBMInput.GetMouseY();
}
bool Mouse::isButtonDown(int button)
{
- return KMInput.IsMouseDown(button);
-}
-
-bool Keyboard::isKeyDown(int key)
-{
- // Map Keyboard constants to Windows virtual key codes
- if (key == Keyboard::KEY_LSHIFT) return KMInput.IsKeyDown(VK_LSHIFT);
- if (key == Keyboard::KEY_RSHIFT) return KMInput.IsKeyDown(VK_RSHIFT);
- if (key == Keyboard::KEY_ESCAPE) return KMInput.IsKeyDown(VK_ESCAPE);
- if (key == Keyboard::KEY_RETURN) return KMInput.IsKeyDown(VK_RETURN);
- if (key == Keyboard::KEY_BACK) return KMInput.IsKeyDown(VK_BACK);
- if (key == Keyboard::KEY_SPACE) return KMInput.IsKeyDown(VK_SPACE);
- if (key == Keyboard::KEY_TAB) return KMInput.IsKeyDown(VK_TAB);
- if (key == Keyboard::KEY_UP) return KMInput.IsKeyDown(VK_UP);
- if (key == Keyboard::KEY_DOWN) return KMInput.IsKeyDown(VK_DOWN);
- if (key == Keyboard::KEY_LEFT) return KMInput.IsKeyDown(VK_LEFT);
- if (key == Keyboard::KEY_RIGHT) return KMInput.IsKeyDown(VK_RIGHT);
- if (key >= Keyboard::KEY_A && key <= Keyboard::KEY_Z)
- return KMInput.IsKeyDown('A' + (key - Keyboard::KEY_A));
- return false;
+ return g_KBMInput.IsMouseButtonDown(button);
}
#endif
diff --git a/Minecraft.Client/stubs.h b/Minecraft.Client/stubs.h
index cc788867..f4ae056f 100644
--- a/Minecraft.Client/stubs.h
+++ b/Minecraft.Client/stubs.h
@@ -187,12 +187,13 @@ public:
static void create() {}
static void destroy() {}
#ifdef _WINDOWS64
- static bool isKeyDown(int key);
+ static bool isKeyDown(int keyCode);
#else
- static bool isKeyDown(int) {return false;}
+ static bool isKeyDown(int) { return false; }
#endif
static wstring getKeyName(int) { return L"KEYNAME"; }
static void enableRepeatEvents(bool) {}
+
static const int KEY_A = 0;
static const int KEY_B = 1;
static const int KEY_C = 2;
@@ -228,8 +229,32 @@ public:
static const int KEY_UP = 32;
static const int KEY_DOWN = 33;
static const int KEY_TAB = 34;
- static const int KEY_LEFT = 35;
- static const int KEY_RIGHT = 36;
+ static const int KEY_1 = 35;
+ static const int KEY_2 = 36;
+ static const int KEY_3 = 37;
+ static const int KEY_4 = 38;
+ static const int KEY_5 = 39;
+ static const int KEY_6 = 40;
+ static const int KEY_7 = 41;
+ static const int KEY_8 = 42;
+ static const int KEY_9 = 43;
+ static const int KEY_F1 = 44;
+ static const int KEY_F3 = 45;
+ static const int KEY_F4 = 46;
+ static const int KEY_F5 = 47;
+ static const int KEY_F6 = 48;
+ static const int KEY_F8 = 49;
+ static const int KEY_F9 = 50;
+ static const int KEY_F11 = 51;
+ static const int KEY_ADD = 52;
+ static const int KEY_SUBTRACT = 53;
+ static const int KEY_LEFT = 54;
+ static const int KEY_RIGHT = 55;
+
+#ifdef _WINDOWS64
+ // Map LWJGL-style key constant to Windows VK code
+ static int toVK(int keyConst);
+#endif
};
class Mouse
diff --git a/README.md b/README.md
index 7578f159..960deff3 100644
--- a/README.md
+++ b/README.md
@@ -70,7 +70,6 @@ The headless server also reads and writes `server.properties` in the working dir
- **Toggle View (FPS/TPS)**: `F5`
- **Fullscreen**: `F11`
- **Pause Menu**: `Esc`
-- **Toggle Mouse Capture**: `Left Alt` (for debugging)
- **Attack / Destroy**: `Left Click`
- **Use / Place**: `Right Click`
- **Select Item**: `Mouse Wheel` or keys `1` to `9`