From 5f6586400044a4bed80b1b6c114eec532b432894 Mon Sep 17 00:00:00 2001 From: Adria Date: Thu, 16 Apr 2026 13:04:16 +0200 Subject: [PATCH 1/5] Change mouse icon on hover --- Minecraft.Client/Common/UI/UIController.cpp | 9 +++++++++ Minecraft.Client/Windows64/KeyboardMouseInput.cpp | 6 ++++++ Minecraft.Client/Windows64/KeyboardMouseInput.h | 2 ++ 3 files changed, 17 insertions(+) diff --git a/Minecraft.Client/Common/UI/UIController.cpp b/Minecraft.Client/Common/UI/UIController.cpp index 96e0ba2f9..1a2751b37 100644 --- a/Minecraft.Client/Common/UI/UIController.cpp +++ b/Minecraft.Client/Common/UI/UIController.cpp @@ -1004,6 +1004,15 @@ void UIController::tickInput() } } } + + if (hitCtrl && (hitCtrl->getControlType() == UIControl::eButton || hitCtrl->getControlType() == UIControl::eCheckBox || hitCtrl->getControlType() == UIControl::eButtonList || hitCtrl->getControlType() == UIControl::eSaveList)) + g_KBMInput.SetCursorIcon(MAKEINTRESOURCEW(IDC_HAND)); + else if (hitCtrl && hitCtrl->getControlType() == UIControl::eSlider || hitCtrl && hitCtrl->getControlType() == UIControl::eTexturePackList) + g_KBMInput.SetCursorIcon(MAKEINTRESOURCEW(IDC_SIZEWE)); + else if (hitCtrl && hitCtrl->getControlType() == UIControl::eTextInput) + g_KBMInput.SetCursorIcon(MAKEINTRESOURCEW(IDC_IBEAM)); + else if (hitCtrl && hitCtrl->getControlType() == UIControl::eNoControl) + g_KBMInput.SetCursorIcon(MAKEINTRESOURCEW(IDC_ARROW)); } } diff --git a/Minecraft.Client/Windows64/KeyboardMouseInput.cpp b/Minecraft.Client/Windows64/KeyboardMouseInput.cpp index be6efe906..5cc432474 100644 --- a/Minecraft.Client/Windows64/KeyboardMouseInput.cpp +++ b/Minecraft.Client/Windows64/KeyboardMouseInput.cpp @@ -390,6 +390,12 @@ float KeyboardMouseInput::GetLookY(float sensitivity) const return static_cast(-m_mouseDeltaY) * sensitivity; } +void KeyboardMouseInput::SetCursorIcon(LPCWSTR cursorName) +{ + HCURSOR hCursor = LoadCursorW(nullptr, cursorName); + if (hCursor) SetCursor(hCursor); +} + void KeyboardMouseInput::OnChar(wchar_t c) { int next = (m_charBufferHead + 1) % CHAR_BUFFER_SIZE; diff --git a/Minecraft.Client/Windows64/KeyboardMouseInput.h b/Minecraft.Client/Windows64/KeyboardMouseInput.h index e8b5f5888..3dcb4313b 100644 --- a/Minecraft.Client/Windows64/KeyboardMouseInput.h +++ b/Minecraft.Client/Windows64/KeyboardMouseInput.h @@ -105,6 +105,8 @@ public: float GetLookX(float sensitivity) const; float GetLookY(float sensitivity) const; + void SetCursorIcon(LPCWSTR cursorName); + private: bool m_keyDown[MAX_KEYS]; bool m_keyDownPrev[MAX_KEYS]; From fe7cd25b859806ef532ae76fa76bc94ea28f9789 Mon Sep 17 00:00:00 2001 From: ACL Date: Thu, 16 Apr 2026 20:44:13 +0200 Subject: [PATCH 2/5] Fixed ButtonList and TexturePackList issue --- Minecraft.Client/Common/UI/UIController.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Minecraft.Client/Common/UI/UIController.cpp b/Minecraft.Client/Common/UI/UIController.cpp index 1a2751b37..a67dbe817 100644 --- a/Minecraft.Client/Common/UI/UIController.cpp +++ b/Minecraft.Client/Common/UI/UIController.cpp @@ -955,7 +955,7 @@ void UIController::tickInput() static_cast(sceneMouseX), static_cast(sceneMouseY), false); hitControlId = -1; hitArea = INT_MAX; - hitCtrl = NULL; + hitCtrl = ctrl; break; // ButtonList takes priority } if (type == UIControl::eTexturePackList) @@ -968,7 +968,7 @@ void UIController::tickInput() m_bMouseHoverHorizontalList = true; hitControlId = -1; hitArea = INT_MAX; - hitCtrl = NULL; + hitCtrl = ctrl; break; } S32 area = cw * ch; @@ -1005,7 +1005,7 @@ void UIController::tickInput() } } - if (hitCtrl && (hitCtrl->getControlType() == UIControl::eButton || hitCtrl->getControlType() == UIControl::eCheckBox || hitCtrl->getControlType() == UIControl::eButtonList || hitCtrl->getControlType() == UIControl::eSaveList)) + if (hitCtrl && (hitCtrl->getControlType() == UIControl::eButton || hitCtrl->getControlType() == UIControl::eCheckBox || hitCtrl->getControlType() == UIControl::eButtonList)) g_KBMInput.SetCursorIcon(MAKEINTRESOURCEW(IDC_HAND)); else if (hitCtrl && hitCtrl->getControlType() == UIControl::eSlider || hitCtrl && hitCtrl->getControlType() == UIControl::eTexturePackList) g_KBMInput.SetCursorIcon(MAKEINTRESOURCEW(IDC_SIZEWE)); From db8b4f6bffa297232638c69a29f997f49399de2c Mon Sep 17 00:00:00 2001 From: ACL Date: Fri, 17 Apr 2026 21:48:08 +0200 Subject: [PATCH 3/5] Cross sign icon for disabled checkBox elements + comments to mark this snippet --- Minecraft.Client/Common/UI/UIController.cpp | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/Minecraft.Client/Common/UI/UIController.cpp b/Minecraft.Client/Common/UI/UIController.cpp index a67dbe817..326cb7bfc 100644 --- a/Minecraft.Client/Common/UI/UIController.cpp +++ b/Minecraft.Client/Common/UI/UIController.cpp @@ -5,6 +5,7 @@ #include "UIScene.h" #include "UIControl_Slider.h" #include "UIControl_TexturePackList.h" +#include "UIControl_CheckBox.h" #include "../../../Minecraft.World/StringHelpers.h" #include "../../LocalPlayer.h" #include "../../DLCTexturePack.h" @@ -1005,12 +1006,21 @@ void UIController::tickInput() } } - if (hitCtrl && (hitCtrl->getControlType() == UIControl::eButton || hitCtrl->getControlType() == UIControl::eCheckBox || hitCtrl->getControlType() == UIControl::eButtonList)) + // Set cursor icon based on hovered UI element (WinUser.h) + if (hitCtrl && (hitCtrl->getControlType() == UIControl::eButton || hitCtrl->getControlType() == UIControl::eButtonList)) g_KBMInput.SetCursorIcon(MAKEINTRESOURCEW(IDC_HAND)); - else if (hitCtrl && hitCtrl->getControlType() == UIControl::eSlider || hitCtrl && hitCtrl->getControlType() == UIControl::eTexturePackList) + else if (hitCtrl && (hitCtrl->getControlType() == UIControl::eSlider || hitCtrl->getControlType() == UIControl::eTexturePackList)) g_KBMInput.SetCursorIcon(MAKEINTRESOURCEW(IDC_SIZEWE)); else if (hitCtrl && hitCtrl->getControlType() == UIControl::eTextInput) g_KBMInput.SetCursorIcon(MAKEINTRESOURCEW(IDC_IBEAM)); + else if (hitCtrl && hitCtrl->getControlType() == UIControl::eCheckBox) // Show the cross sign shaped cursor only when the checkbox is disabled/grayed out + { + UIControl_CheckBox *pCheck = static_cast(hitCtrl); + if (pCheck && !pCheck->IsEnabled()) + g_KBMInput.SetCursorIcon(MAKEINTRESOURCEW(IDC_NO)); + else + g_KBMInput.SetCursorIcon(MAKEINTRESOURCEW(IDC_HAND)); + } else if (hitCtrl && hitCtrl->getControlType() == UIControl::eNoControl) g_KBMInput.SetCursorIcon(MAKEINTRESOURCEW(IDC_ARROW)); } From e8523925055fbd87f810bdf7b827ae2ba798d8fc Mon Sep 17 00:00:00 2001 From: ACL Date: Fri, 17 Apr 2026 23:33:43 +0200 Subject: [PATCH 4/5] Fixed icon reseting on click - Moved the whole icon updater snippet to a new function inside UIController so it can be called outside tickInput. - Made a new variable inside tickInput function for the same reason. - Modified SetCursorIcon inside KeyboardMouseInput so it gets the current icon instead of reloading the cursor. --- Minecraft.Client/Common/UI/UIController.cpp | 43 +++++++++++-------- Minecraft.Client/Common/UI/UIController.h | 1 + .../Windows64/KeyboardMouseInput.cpp | 13 +++++- 3 files changed, 37 insertions(+), 20 deletions(-) diff --git a/Minecraft.Client/Common/UI/UIController.cpp b/Minecraft.Client/Common/UI/UIController.cpp index 326cb7bfc..2209c4afa 100644 --- a/Minecraft.Client/Common/UI/UIController.cpp +++ b/Minecraft.Client/Common/UI/UIController.cpp @@ -792,6 +792,7 @@ void UIController::tickInput() { #ifdef _WINDOWS64 m_mouseClickConsumedByScene = false; + UIControl* currHitCtrl = NULL; if (!g_KBMInput.IsMouseGrabbed() && g_KBMInput.IsKBMActive()) { UIScene *pScene = nullptr; @@ -1005,24 +1006,9 @@ void UIController::tickInput() } } } - - // Set cursor icon based on hovered UI element (WinUser.h) - if (hitCtrl && (hitCtrl->getControlType() == UIControl::eButton || hitCtrl->getControlType() == UIControl::eButtonList)) - g_KBMInput.SetCursorIcon(MAKEINTRESOURCEW(IDC_HAND)); - else if (hitCtrl && (hitCtrl->getControlType() == UIControl::eSlider || hitCtrl->getControlType() == UIControl::eTexturePackList)) - g_KBMInput.SetCursorIcon(MAKEINTRESOURCEW(IDC_SIZEWE)); - else if (hitCtrl && hitCtrl->getControlType() == UIControl::eTextInput) - g_KBMInput.SetCursorIcon(MAKEINTRESOURCEW(IDC_IBEAM)); - else if (hitCtrl && hitCtrl->getControlType() == UIControl::eCheckBox) // Show the cross sign shaped cursor only when the checkbox is disabled/grayed out - { - UIControl_CheckBox *pCheck = static_cast(hitCtrl); - if (pCheck && !pCheck->IsEnabled()) - g_KBMInput.SetCursorIcon(MAKEINTRESOURCEW(IDC_NO)); - else - g_KBMInput.SetCursorIcon(MAKEINTRESOURCEW(IDC_HAND)); - } - else if (hitCtrl && hitCtrl->getControlType() == UIControl::eNoControl) - g_KBMInput.SetCursorIcon(MAKEINTRESOURCEW(IDC_ARROW)); + + currHitCtrl = hitCtrl; + UpdateCursorIcon(currHitCtrl); } } @@ -1146,6 +1132,27 @@ void UIController::tickInput() } } +void UIController::UpdateCursorIcon(UIControl *hitCtrl) +{ + // Set cursor icon based on hovered UI element (WinUser.h) + if (hitCtrl && (hitCtrl->getControlType() == UIControl::eButton || hitCtrl->getControlType() == UIControl::eButtonList)) + g_KBMInput.SetCursorIcon(MAKEINTRESOURCEW(IDC_HAND)); + else if (hitCtrl && (hitCtrl->getControlType() == UIControl::eSlider || hitCtrl->getControlType() == UIControl::eTexturePackList)) + g_KBMInput.SetCursorIcon(MAKEINTRESOURCEW(IDC_SIZEWE)); + else if (hitCtrl && hitCtrl->getControlType() == UIControl::eTextInput) + g_KBMInput.SetCursorIcon(MAKEINTRESOURCEW(IDC_IBEAM)); + else if (hitCtrl && hitCtrl->getControlType() == UIControl::eCheckBox) // Show the cross sign shaped cursor only when the checkbox is disabled/grayed out + { + UIControl_CheckBox *pCheck = static_cast(hitCtrl); + if (pCheck && !pCheck->IsEnabled()) + g_KBMInput.SetCursorIcon(MAKEINTRESOURCEW(IDC_NO)); + else + g_KBMInput.SetCursorIcon(MAKEINTRESOURCEW(IDC_HAND)); + } + else + g_KBMInput.SetCursorIcon(MAKEINTRESOURCEW(IDC_ARROW)); +} + void UIController::handleInput() { // For each user, loop over each key type and send messages based on the state diff --git a/Minecraft.Client/Common/UI/UIController.h b/Minecraft.Client/Common/UI/UIController.h index 08a5ba088..fc5ee4e6e 100644 --- a/Minecraft.Client/Common/UI/UIController.h +++ b/Minecraft.Client/Common/UI/UIController.h @@ -245,6 +245,7 @@ public: // INPUT private: void tickInput(); + void UpdateCursorIcon(UIControl *hitCtrl); void handleInput(); void handleKeyPress(unsigned int iPad, unsigned int key); diff --git a/Minecraft.Client/Windows64/KeyboardMouseInput.cpp b/Minecraft.Client/Windows64/KeyboardMouseInput.cpp index 5cc432474..40c82dc70 100644 --- a/Minecraft.Client/Windows64/KeyboardMouseInput.cpp +++ b/Minecraft.Client/Windows64/KeyboardMouseInput.cpp @@ -392,8 +392,17 @@ float KeyboardMouseInput::GetLookY(float sensitivity) const void KeyboardMouseInput::SetCursorIcon(LPCWSTR cursorName) { - HCURSOR hCursor = LoadCursorW(nullptr, cursorName); - if (hCursor) SetCursor(hCursor); + HCURSOR hCursor = LoadCursorW(nullptr, cursorName); + if (hCursor) + { + SetCursor(hCursor); + + if (g_hWnd) + { + // Update the cursor icon to keep the current one + SetClassLongPtrW(g_hWnd, GCLP_HCURSOR, (LONG_PTR)hCursor); + } + } } void KeyboardMouseInput::OnChar(wchar_t c) From 53de20272616c7f51f1fce282e01a54184f8c276 Mon Sep 17 00:00:00 2001 From: puffmon Date: Thu, 23 Apr 2026 10:15:35 +0200 Subject: [PATCH 5/5] update cursor icon on scene loaded --- Minecraft.Client/Common/UI/UIController.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Minecraft.Client/Common/UI/UIController.cpp b/Minecraft.Client/Common/UI/UIController.cpp index 2209c4afa..f1039ca2b 100644 --- a/Minecraft.Client/Common/UI/UIController.cpp +++ b/Minecraft.Client/Common/UI/UIController.cpp @@ -2021,6 +2021,7 @@ bool UIController::NavigateToScene(int iPad, EUIScene scene, void *initData, EUI SetMenuDisplayed(menuDisplayedPad,true); bool success = m_groups[static_cast(group)]->NavigateToScene(iPad, scene, initData, layer); if(success && group == eUIGroup_Fullscreen) setFullscreenMenuDisplayed(true); + UpdateCursorIcon(nullptr); LeaveCriticalSection(&m_navigationLock); timer.PrintElapsedTime(L"Navigate to scene"); @@ -2061,6 +2062,8 @@ bool UIController::NavigateBack(int iPad, bool forceUsePad, EUIScene eScene, EUI if(!m_groups[static_cast(eUIGroup_Fullscreen)]->GetMenuDisplayed()) SetMenuDisplayed(XUSER_INDEX_ANY,false); } return navComplete; + + UpdateCursorIcon(nullptr); } void UIController::NavigateToHomeMenu()