diff --git a/Minecraft.Client/Common/UI/IUIScene_AbstractContainerMenu.cpp b/Minecraft.Client/Common/UI/IUIScene_AbstractContainerMenu.cpp index 29ddcf71d..03bc745ec 100644 --- a/Minecraft.Client/Common/UI/IUIScene_AbstractContainerMenu.cpp +++ b/Minecraft.Client/Common/UI/IUIScene_AbstractContainerMenu.cpp @@ -21,6 +21,7 @@ IUIScene_AbstractContainerMenu::IUIScene_AbstractContainerMenu() m_pointerPos.x = 0.0f; m_pointerPos.y = 0.0f; + m_bMousePointerControl = false; } @@ -63,6 +64,7 @@ void IUIScene_AbstractContainerMenu::Initialize(int iPad, AbstractContainerMenu* m_eMaxSection = maxSection; m_iConsectiveInputTicks = 0; + m_bMousePointerControl = false; m_bNavigateBack = bNavigateBack; @@ -463,6 +465,25 @@ void IUIScene_AbstractContainerMenu::onMouseTick() } #endif + if (m_bMousePointerControl) + { + // Force pointer to the externally provided mouse position so any + // residual stick input/drift cannot desync the software cursor. + vPointerPos = m_pointerPos; + vPointerPos.x += m_fPointerImageOffsetX; + vPointerPos.y += m_fPointerImageOffsetY; + + bStickInput = true; + m_iConsectiveInputTicks = 0; + m_eCurrTapState = eTapStateNoInput; +#ifdef USE_POINTER_ACCEL + m_fPointerVelX = 0.0f; + m_fPointerVelY = 0.0f; + m_fPointerAccelX = 0.0f; + m_fPointerAccelY = 0.0f; +#endif + } + // Determine which slot the pointer is currently over. ESceneSection eSectionUnderPointer = eSectionNone; int iNewSlotX = -1; @@ -689,10 +710,13 @@ void IUIScene_AbstractContainerMenu::onMouseTick() } // Clamp to pointer extents. - if ( vPointerPos.x < m_fPointerMinX ) vPointerPos.x = m_fPointerMinX; - else if ( vPointerPos.x > m_fPointerMaxX ) vPointerPos.x = m_fPointerMaxX; - if ( vPointerPos.y < m_fPointerMinY ) vPointerPos.y = m_fPointerMinY; - else if ( vPointerPos.y > m_fPointerMaxY ) vPointerPos.y = m_fPointerMaxY; + if (!m_bMousePointerControl) + { + if ( vPointerPos.x < m_fPointerMinX ) vPointerPos.x = m_fPointerMinX; + else if ( vPointerPos.x > m_fPointerMaxX ) vPointerPos.x = m_fPointerMaxX; + if ( vPointerPos.y < m_fPointerMinY ) vPointerPos.y = m_fPointerMinY; + else if ( vPointerPos.y > m_fPointerMaxY ) vPointerPos.y = m_fPointerMaxY; + } // Check if the pointer is outside of the panel. bool bPointerIsOutsidePanel = false; diff --git a/Minecraft.Client/Common/UI/IUIScene_AbstractContainerMenu.h b/Minecraft.Client/Common/UI/IUIScene_AbstractContainerMenu.h index bdb8bb4c8..70b5b6ca1 100644 --- a/Minecraft.Client/Common/UI/IUIScene_AbstractContainerMenu.h +++ b/Minecraft.Client/Common/UI/IUIScene_AbstractContainerMenu.h @@ -158,6 +158,7 @@ protected: Slot *m_lastPointerLabelSlot; bool m_bSplitscreen; + bool m_bMousePointerControl; bool m_bNavigateBack; // should we exit the xuiscenes or just navigate back on exit? virtual bool IsSectionSlotList( ESceneSection eSection ) { return eSection != eSectionNone; } diff --git a/Minecraft.Client/Common/UI/UIController.cpp b/Minecraft.Client/Common/UI/UIController.cpp index 8c3360885..2ccda159d 100644 --- a/Minecraft.Client/Common/UI/UIController.cpp +++ b/Minecraft.Client/Common/UI/UIController.cpp @@ -210,6 +210,18 @@ UIController::UIController() m_currentRenderViewport = C4JRender::VIEWPORT_TYPE_FULLSCREEN; m_bCustomRenderPosition = false; m_winUserIndex = 0; + +#ifdef _WINDOWS64 + m_menuMouseOkPressed = false; + m_menuMouseOkReleased = false; + m_menuMousePageUpPressed = false; + m_menuMousePageDownPressed = false; + m_menuMouseFocusMovie = NULL; + m_menuMouseFocusObject = IGGY_FOCUS_NULL; + m_menuMouseX = -1; + m_menuMouseY = -1; +#endif + m_accumulatedTicks = 0; InitializeCriticalSection(&m_navigationLock); @@ -694,6 +706,10 @@ void UIController::tickInput() void UIController::handleInput() { +#ifdef _WINDOWS64 + handleMouseMenuInput(); +#endif + // For each user, loop over each key type and send messages based on the state for(unsigned int iPad = 0; iPad < XUSER_MAX_COUNT; ++iPad) { @@ -753,6 +769,264 @@ void UIController::handleInput() #endif } +#ifdef _WINDOWS64 +void UIController::handleMouseMenuInput() +{ + m_menuMouseOkPressed = false; + m_menuMouseOkReleased = false; + m_menuMousePageUpPressed = false; + m_menuMousePageDownPressed = false; + + if (KMInput.IsCaptured() || !GetMenuDisplayed(0)) + { + m_menuMouseFocusMovie = NULL; + m_menuMouseFocusObject = IGGY_FOCUS_NULL; + m_menuMouseX = -1; + m_menuMouseY = -1; + return; + } + + m_menuMouseOkPressed = KMInput.IsMousePressed(0); + m_menuMouseOkReleased = KMInput.IsMouseReleased(0); + + int wheel = KMInput.ConsumeScrollDelta(); + if (wheel > 0) m_menuMousePageUpPressed = true; + else if (wheel < 0) m_menuMousePageDownPressed = true; + + if (IsContainerMenuDisplayed(0)) + { + m_menuMouseFocusMovie = NULL; + m_menuMouseFocusObject = IGGY_FOCUS_NULL; + m_menuMouseX = -1; + m_menuMouseY = -1; + return; + } + + EUIGroup group = eUIGroup_Fullscreen; + UIScene *scene = getMouseFocusableScene(group); + if (!scene || !scene->hasMovie()) + { + m_menuMouseFocusMovie = NULL; + m_menuMouseFocusObject = IGGY_FOCUS_NULL; + m_menuMouseX = -1; + m_menuMouseY = -1; + return; + } + + int clientWidth = 0; + int clientHeight = 0; + if (!KMInput.GetClientSize(clientWidth, clientHeight) || clientWidth <= 0 || clientHeight <= 0) + { + return; + } + + int clientX = 0; + int clientY = 0; + if (!KMInput.GetMouseClientPosition(clientX, clientY)) + { + return; + } + + S32 uiX = (S32)((float)clientX * (m_fScreenWidth / (float)clientWidth)); + S32 uiY = (S32)((float)clientY * (m_fScreenHeight / (float)clientHeight)); + + S32 viewportX = 0; + S32 viewportY = 0; + S32 viewportW = 0; + S32 viewportH = 0; + m_groups[(int)group]->getRenderDimensions(viewportW, viewportH); + getViewportOffset(m_groups[(int)group]->GetViewportType(), viewportX, viewportY); + + if (viewportW <= 0 || viewportH <= 0) + { + return; + } + + S32 localX = uiX - viewportX; + S32 localY = uiY - viewportY; + if (localX < 0 || localY < 0 || localX >= viewportW || localY >= viewportH) + { + return; + } + + Iggy *movie = scene->getMovie(); + IggyFocusableObject focusableObjects[256]; + S32 numFocusableObjects = 0; + IggyFocusHandle currentFocus = IGGY_FOCUS_NULL; + if (!IggyPlayerGetFocusableObjects(movie, ¤tFocus, focusableObjects, 256, &numFocusableObjects)) + { + return; + } + + S32 mouseX = (S32)((float)localX * ((float)scene->getRenderWidth() / (float)viewportW)); + S32 mouseY = (S32)((float)localY * ((float)scene->getRenderHeight() / (float)viewportH)); + + IggyFocusHandle bestFocus = IGGY_FOCUS_NULL; + float bestArea = 3.4e38f; + + for (S32 i = 0; i < numFocusableObjects; ++i) + { + const IggyFocusableObject &obj = focusableObjects[i]; + float minX = min(obj.x0, obj.x1); + float maxX = max(obj.x0, obj.x1); + float minY = min(obj.y0, obj.y1); + float maxY = max(obj.y0, obj.y1); + + if ((float)mouseX < minX || (float)mouseX > maxX || (float)mouseY < minY || (float)mouseY > maxY) + { + continue; + } + + float area = max(1.0f, (maxX - minX) * (maxY - minY)); + if (area <= bestArea) + { + bestArea = area; + bestFocus = obj.object; + } + } + + if (bestFocus == IGGY_FOCUS_NULL) + { + float fallbackBestArea = 3.4e38f; + for (S32 i = 0; i < numFocusableObjects; ++i) + { + const IggyFocusableObject &obj = focusableObjects[i]; + float minX = min(obj.x0, obj.x1); + float maxX = max(obj.x0, obj.x1); + float minY = min(obj.y0, obj.y1); + float maxY = max(obj.y0, obj.y1); + + if ((float)localX < minX || (float)localX > maxX || (float)localY < minY || (float)localY > maxY) + { + continue; + } + + float area = max(1.0f, (maxX - minX) * (maxY - minY)); + if (area <= fallbackBestArea) + { + fallbackBestArea = area; + bestFocus = obj.object; + } + } + + if (bestFocus != IGGY_FOCUS_NULL) + { + mouseX = localX; + mouseY = localY; + } + } + + IggyEvent mouseEvent; + IggyEventResult eventResult; + IggyMakeEventMouseMove(&mouseEvent, mouseX, mouseY); + IggyPlayerDispatchEventRS(movie, &mouseEvent, &eventResult); + + if (movie == m_menuMouseFocusMovie && mouseX == m_menuMouseX && mouseY == m_menuMouseY) + { + return; + } + bool movieChanged = (movie != m_menuMouseFocusMovie); + + m_menuMouseFocusMovie = movie; + m_menuMouseX = mouseX; + m_menuMouseY = mouseY; + if (movieChanged) m_menuMouseFocusObject = IGGY_FOCUS_NULL; + + if (bestFocus != IGGY_FOCUS_NULL && bestFocus != m_menuMouseFocusObject) + { + IggyPlayerSetFocusRS(movie, bestFocus, 0); + } + m_menuMouseFocusObject = bestFocus; +} + +UIScene *UIController::getMouseFocusableScene(EUIGroup &group) const +{ + static const EUILayer kLayerOrder[] = + { + eUILayer_Error, + eUILayer_Alert, + eUILayer_Popup, + eUILayer_Scene, + eUILayer_Fullscreen, + }; + + for (int groupIndex = 0; groupIndex < eUIGroup_COUNT; ++groupIndex) + { + EUIGroup testGroup = (EUIGroup)groupIndex; + for (int layerIndex = 0; layerIndex < (int)(sizeof(kLayerOrder) / sizeof(kLayerOrder[0])); ++layerIndex) + { + UIScene *scene = m_groups[groupIndex]->GetTopScene(kLayerOrder[layerIndex]); + if (!scene || !scene->canHandleInput() || !scene->hasMovie()) continue; + if (isContainerSceneType(scene->getSceneType())) continue; + group = testGroup; + return scene; + } + } + + return NULL; +} + +void UIController::getViewportOffset(C4JRender::eViewportType viewport, S32 &xPos, S32 &yPos) const +{ + xPos = 0; + yPos = 0; + const float screenWidth = m_fScreenWidth; + const float screenHeight = m_fScreenHeight; + + switch (viewport) + { + case C4JRender::VIEWPORT_TYPE_SPLIT_TOP: + xPos = (S32)(screenWidth / 4); + break; + case C4JRender::VIEWPORT_TYPE_SPLIT_BOTTOM: + xPos = (S32)(screenWidth / 4); + yPos = (S32)(screenHeight / 2); + break; + case C4JRender::VIEWPORT_TYPE_SPLIT_LEFT: + yPos = (S32)(screenHeight / 4); + break; + case C4JRender::VIEWPORT_TYPE_SPLIT_RIGHT: + xPos = (S32)(screenWidth / 2); + yPos = (S32)(screenHeight / 4); + break; + case C4JRender::VIEWPORT_TYPE_QUADRANT_TOP_RIGHT: + xPos = (S32)(screenWidth / 2); + break; + case C4JRender::VIEWPORT_TYPE_QUADRANT_BOTTOM_LEFT: + yPos = (S32)(screenHeight / 2); + break; + case C4JRender::VIEWPORT_TYPE_QUADRANT_BOTTOM_RIGHT: + xPos = (S32)(screenWidth / 2); + yPos = (S32)(screenHeight / 2); + break; + default: + break; + } +} + +bool UIController::isContainerSceneType(EUIScene sceneType) const +{ + switch (sceneType) + { + case eUIScene_Crafting2x2Menu: + case eUIScene_Crafting3x3Menu: + case eUIScene_FurnaceMenu: + case eUIScene_ContainerMenu: + case eUIScene_LargeContainerMenu: + case eUIScene_InventoryMenu: + case eUIScene_DispenserMenu: + case eUIScene_CreativeMenu: + case eUIScene_EnchantingMenu: + case eUIScene_BrewingStandMenu: + case eUIScene_TradingMenu: + case eUIScene_AnvilMenu: + return true; + default: + return false; + } +} +#endif + void UIController::handleKeyPress(unsigned int iPad, unsigned int key) { @@ -924,17 +1198,23 @@ void UIController::handleKeyPress(unsigned int iPad, unsigned int key) if (iPad == 0) { bool kbDown = false, kbPressed = false, kbReleased = false; + bool capturedContainerMenu = IsContainerMenuDisplayed(0) && KMInput.IsCaptured(); + bool capturedMouseOkDown = capturedContainerMenu && KMInput.IsMouseDown(0); + bool capturedMouseOkPressed = capturedContainerMenu && KMInput.IsMousePressed(0); + bool capturedMouseOkReleased = capturedContainerMenu && KMInput.IsMouseReleased(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_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) || capturedMouseOkDown; kbPressed = KMInput.IsKeyPressed(VK_RETURN) || m_menuMouseOkPressed || capturedMouseOkPressed; kbReleased = KMInput.IsKeyReleased(VK_RETURN) || m_menuMouseOkReleased || capturedMouseOkReleased; break; + case ACTION_MENU_A: kbDown = KMInput.IsKeyDown(VK_RETURN) || capturedMouseOkDown; kbPressed = KMInput.IsKeyPressed(VK_RETURN) || m_menuMouseOkPressed || capturedMouseOkPressed; kbReleased = KMInput.IsKeyReleased(VK_RETURN) || m_menuMouseOkReleased || capturedMouseOkReleased; 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_PAGEUP: kbPressed = m_menuMousePageUpPressed; break; + case ACTION_MENU_PAGEDOWN: kbPressed = m_menuMousePageDownPressed; break; } pressed = pressed || kbPressed; released = released || kbReleased; @@ -3035,4 +3315,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 ef064f80c..de7fa72d0 100644 --- a/Minecraft.Client/Common/UI/UIController.h +++ b/Minecraft.Client/Common/UI/UIController.h @@ -131,6 +131,18 @@ private: vector m_queuedMessageBoxData; unsigned int m_winUserIndex; + +#ifdef _WINDOWS64 + bool m_menuMouseOkPressed; + bool m_menuMouseOkReleased; + bool m_menuMousePageUpPressed; + bool m_menuMousePageDownPressed; + Iggy *m_menuMouseFocusMovie; + IggyFocusHandle m_menuMouseFocusObject; + int m_menuMouseX; + int m_menuMouseY; +#endif + //bool m_bSysUIShowing; bool m_bSystemUIShowing; C4JThread *m_reloadSkinThread; @@ -208,6 +220,12 @@ private: void tickInput(); void handleInput(); void handleKeyPress(unsigned int iPad, unsigned int key); +#ifdef _WINDOWS64 + void handleMouseMenuInput(); + UIScene *getMouseFocusableScene(EUIGroup &group) const; + void getViewportOffset(C4JRender::eViewportType viewport, S32 &xPos, S32 &yPos) const; + bool isContainerSceneType(EUIScene sceneType) const; +#endif protected: static rrbool RADLINK ExternalFunctionCallback( void * user_callback_data , Iggy * player , IggyExternalFunctionCallUTF16 * call ); diff --git a/Minecraft.Client/Common/UI/UIScene_AbstractContainerMenu.cpp b/Minecraft.Client/Common/UI/UIScene_AbstractContainerMenu.cpp index 7823fb4e4..2e339e365 100644 --- a/Minecraft.Client/Common/UI/UIScene_AbstractContainerMenu.cpp +++ b/Minecraft.Client/Common/UI/UIScene_AbstractContainerMenu.cpp @@ -5,8 +5,63 @@ #include "..\..\..\Minecraft.World\net.minecraft.world.inventory.h" #include "..\..\..\Minecraft.World\net.minecraft.world.item.h" #include "..\..\MultiplayerLocalPlayer.h" + #ifdef _WINDOWS64 -#include "..\..\Windows64\KeyboardMouseInput.h" +static void GetViewportRect(C4JRender::eViewportType viewport, S32 fullWidth, S32 fullHeight, S32 &xPos, S32 &yPos, S32 &width, S32 &height) +{ + xPos = 0; + yPos = 0; + width = fullWidth; + height = fullHeight; + + switch (viewport) + { + case C4JRender::VIEWPORT_TYPE_SPLIT_TOP: + xPos = width / 4; + width /= 2; + height /= 2; + break; + case C4JRender::VIEWPORT_TYPE_SPLIT_BOTTOM: + xPos = width / 4; + yPos = height / 2; + width /= 2; + height /= 2; + break; + case C4JRender::VIEWPORT_TYPE_SPLIT_LEFT: + yPos = height / 4; + width /= 2; + height /= 2; + break; + case C4JRender::VIEWPORT_TYPE_SPLIT_RIGHT: + xPos = width / 2; + yPos = height / 4; + width /= 2; + height /= 2; + break; + case C4JRender::VIEWPORT_TYPE_QUADRANT_TOP_LEFT: + width /= 2; + height /= 2; + break; + case C4JRender::VIEWPORT_TYPE_QUADRANT_TOP_RIGHT: + xPos = width / 2; + width /= 2; + height /= 2; + break; + case C4JRender::VIEWPORT_TYPE_QUADRANT_BOTTOM_LEFT: + yPos = height / 2; + width /= 2; + height /= 2; + break; + case C4JRender::VIEWPORT_TYPE_QUADRANT_BOTTOM_RIGHT: + xPos = width / 2; + yPos = height / 2; + width /= 2; + height /= 2; + break; + default: + break; + } +} #endif UIScene_AbstractContainerMenu::UIScene_AbstractContainerMenu(int iPad, UILayer *parentLayer) : UIScene(iPad, parentLayer) @@ -28,9 +83,6 @@ UIScene_AbstractContainerMenu::UIScene_AbstractContainerMenu(int iPad, UILayer * ui.OverrideSFX(m_iPad,ACTION_MENU_DOWN,true); m_bIgnoreInput=false; -#ifdef _WINDOWS64 - m_bMouseDragSlider=false; -#endif } UIScene_AbstractContainerMenu::~UIScene_AbstractContainerMenu() @@ -112,8 +164,8 @@ void UIScene_AbstractContainerMenu::PlatformInitialize(int iPad, int startIndex) #ifdef __ORBIS__ // we need to map the touchpad rectangle to the UI rectangle. While it works great for the creative menu, it is much too sensitive for the smaller menus. //X coordinate of the touch point (0 to 1919) - //Y coordinate of the touch point (0 to 941: DUALSHOCK�4 wireless controllers and the CUH-ZCT1J/CAP-ZCT1J/CAP-ZCT1U controllers for the PlayStation�4 development tool, - //0 to 753: JDX-1000x series controllers for the PlayStation�4 development tool,) + //Y coordinate of the touch point (0 to 941: DUALSHOCK�4 wireless controllers and the CUH-ZCT1J/CAP-ZCT1J/CAP-ZCT1U controllers for the PlayStation�4 development tool,) + //0 to 753: JDX-1000x series controllers for the PlayStation�4 development tool,) m_fTouchPadMulX=fPanelWidth/1919.0f; m_fTouchPadMulY=fPanelHeight/941.0f; m_fTouchPadDeadZoneX=15.0f*m_fTouchPadMulX; @@ -160,8 +212,8 @@ void UIScene_AbstractContainerMenu::PlatformInitialize(int iPad, int startIndex) IggyEvent mouseEvent; S32 width, height; m_parentLayer->getRenderDimensions(width, height); - S32 x = m_pointerPos.x*((float)width/m_movieWidth); - S32 y = m_pointerPos.y*((float)height/m_movieHeight); + S32 x = m_pointerPos.x*((float)width/m_renderWidth); + S32 y = m_pointerPos.y*((float)height/m_renderHeight); IggyMakeEventMouseMove( &mouseEvent, x, y); IggyEventResult result; @@ -179,118 +231,61 @@ void UIScene_AbstractContainerMenu::tick() { UIScene::tick(); + m_bMousePointerControl = false; #ifdef _WINDOWS64 - bool mouseActive = (m_iPad == 0 && !KMInput.IsCaptured()); - float rawMouseMovieX = 0, rawMouseMovieY = 0; - // Map Windows mouse position to the virtual pointer in movie coordinates - if (mouseActive) + if (getPad() == 0) { - RECT clientRect; - GetClientRect(KMInput.GetHWnd(), &clientRect); - int clientWidth = clientRect.right; - int clientHeight = clientRect.bottom; - if (clientWidth > 0 && clientHeight > 0) + if (KMInput.IsCaptured()) { - int mouseX = KMInput.GetMouseX(); - int mouseY = KMInput.GetMouseY(); + float dx = 0.0f; + float dy = 0.0f; + KMInput.ConsumeMouseDelta(dx, dy); - // Convert mouse position to movie coordinates using the movie/client ratio - float mx = (float)mouseX * ((float)m_movieWidth / (float)clientWidth); - float my = (float)mouseY * ((float)m_movieHeight / (float)clientHeight); + const float pointerSensitivity = 1.00f; + m_pointerPos.x += dx * pointerSensitivity; + m_pointerPos.y += dy * pointerSensitivity; + m_bMousePointerControl = true; + } + else + { + int clientX = 0; + int clientY = 0; + int clientWidth = 0; + int clientHeight = 0; + if (KMInput.GetMouseClientPosition(clientX, clientY) && KMInput.GetClientSize(clientWidth, clientHeight) && clientWidth > 0 && clientHeight > 0) + { + S32 viewportX = 0; + S32 viewportY = 0; + S32 viewportW = 0; + S32 viewportH = 0; + GetViewportRect(m_parentLayer->m_parentGroup->GetViewportType(), (S32)clientWidth, (S32)clientHeight, viewportX, viewportY, viewportW, viewportH); - m_pointerPos.x = mx; - m_pointerPos.y = my; - rawMouseMovieX = mx; - rawMouseMovieY = my; + if (viewportW > 0 && viewportH > 0) + { + S32 localX = (S32)clientX - viewportX; + S32 localY = (S32)clientY - viewportY; + if (localX >= 0 && localY >= 0 && localX < viewportW && localY < viewportH) + { + float pointerX = ((float)localX / (float)viewportW) * (float)m_renderWidth; + float pointerY = ((float)localY / (float)viewportH) * (float)m_renderHeight; + m_pointerPos.x = pointerX; + m_pointerPos.y = pointerY; + m_bMousePointerControl = true; + } + } + } } } #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 - int scrollDelta = KMInput.ConsumeScrollDelta(); - 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); + S32 x = m_pointerPos.x*((float)width/m_renderWidth); + S32 y = m_pointerPos.y*((float)height/m_renderHeight); -#ifdef _WINDOWS64 - S32 x, y; - if (mouseActive) - { - // 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); - x = (S32)((float)KMInput.GetMouseX() * ((float)width / (float)clientRect.right)); - y = (S32)((float)KMInput.GetMouseY() * ((float)height / (float)clientRect.bottom)); - } - 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 IggyMakeEventMouseMove( &mouseEvent, x, y); // 4J Stu - This seems to be broken on Durango, so do it ourself diff --git a/Minecraft.Client/Input.cpp b/Minecraft.Client/Input.cpp index c1a3bb31a..2ea75a3d7 100644 --- a/Minecraft.Client/Input.cpp +++ b/Minecraft.Client/Input.cpp @@ -138,7 +138,7 @@ void Input::tick(LocalPlayer *player) // 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 && KMInput.IsCaptured() && !ui.GetMenuDisplayed(iPad)) { float rawDx, rawDy; KMInput.ConsumeMouseDelta(rawDx, rawDy); diff --git a/Minecraft.Client/Minecraft.cpp b/Minecraft.Client/Minecraft.cpp index 3192410d0..e9b88ff55 100644 --- a/Minecraft.Client/Minecraft.cpp +++ b/Minecraft.Client/Minecraft.cpp @@ -1238,6 +1238,7 @@ void Minecraft::applyFrameMouseLook() if (iPad != 0) continue; // Mouse only applies to pad 0 if (!KMInput.IsCaptured()) continue; + if (ui.GetMenuDisplayed(iPad)) continue; if (localgameModes[iPad] == NULL) continue; float rawDx, rawDy; @@ -1250,6 +1251,12 @@ void Minecraft::applyFrameMouseLook() if (app.GetGameSettings(iPad, eGameSetting_ControlInvertLook)) mdy = -mdy; + bool canLookYaw = localgameModes[iPad]->isInputAllowed(MINECRAFT_ACTION_LOOK_LEFT) || localgameModes[iPad]->isInputAllowed(MINECRAFT_ACTION_LOOK_RIGHT); + bool canLookPitch = localgameModes[iPad]->isInputAllowed(MINECRAFT_ACTION_LOOK_UP) || localgameModes[iPad]->isInputAllowed(MINECRAFT_ACTION_LOOK_DOWN); + if (!canLookYaw) mdx = 0.0f; + if (!canLookPitch) mdy = 0.0f; + if (mdx == 0.0f && mdy == 0.0f) continue; + // Apply 0.15f scaling (same as Entity::interpolateTurn / Entity::turn) float dyaw = mdx * 0.15f; float dpitch = -mdy * 0.15f; @@ -3274,22 +3281,32 @@ void Minecraft::tick(bool bFirst, bool bUpdateTextures) // Mouse scroll wheel for hotbar if (iPad == 0) { - int kbWheel = KMInput.ConsumeScrollDelta(); + int kbWheel = 0; + if (KMInput.IsCaptured()) + { + kbWheel = KMInput.ConsumeScrollDelta(); + } + else if (!ui.GetMenuDisplayed(0)) + { + 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++) { - for (int k = '1'; k <= '9'; k++) + if (!KMInput.ConsumeKeyPress(k)) { - if (KMInput.ConsumeKeyPress(k)) - { - player->inventory->selected = k - '1'; - app.SetOpacityTimer(iPad); - break; - } + continue; } + + if (KMInput.IsCaptured() && gameMode->isInputAllowed(MINECRAFT_ACTION_LEFT_SCROLL)) + { + player->inventory->selected = k - '1'; + app.SetOpacityTimer(iPad); + } + break; } } #endif diff --git a/Minecraft.Client/Windows64/KeyboardMouseInput.cpp b/Minecraft.Client/Windows64/KeyboardMouseInput.cpp index fc7633947..4947b956c 100644 --- a/Minecraft.Client/Windows64/KeyboardMouseInput.cpp +++ b/Minecraft.Client/Windows64/KeyboardMouseInput.cpp @@ -216,6 +216,31 @@ int KeyboardMouseInput::ConsumeScrollDelta() return delta; } +bool KeyboardMouseInput::GetMouseClientPosition(int &x, int &y) const +{ + if (!m_hWnd) return false; + + POINT cursor; + if (!GetCursorPos(&cursor)) return false; + if (!ScreenToClient(m_hWnd, &cursor)) return false; + + x = cursor.x; + y = cursor.y; + return true; +} + +bool KeyboardMouseInput::GetClientSize(int &width, int &height) const +{ + if (!m_hWnd) return false; + + RECT rect; + if (!GetClientRect(m_hWnd, &rect)) return false; + + width = rect.right - rect.left; + height = rect.bottom - rect.top; + return true; +} + // Mouse capture void KeyboardMouseInput::SetCapture(bool capture) { diff --git a/Minecraft.Client/Windows64/KeyboardMouseInput.h b/Minecraft.Client/Windows64/KeyboardMouseInput.h index a09843f90..0fec138c6 100644 --- a/Minecraft.Client/Windows64/KeyboardMouseInput.h +++ b/Minecraft.Client/Windows64/KeyboardMouseInput.h @@ -45,6 +45,8 @@ public: bool ConsumeMouseRelease(int btn); void ConsumeMouseDelta(float &dx, float &dy); int ConsumeScrollDelta(); + bool GetMouseClientPosition(int &x, int &y) const; + bool GetClientSize(int &width, int &height) const; // Absolute cursor position (client-area coordinates, for GUI when not captured) void OnMouseMove(int x, int y); diff --git a/Minecraft.Client/Windows64/Windows64_Minecraft.cpp b/Minecraft.Client/Windows64/Windows64_Minecraft.cpp index 42fb2d448..47461da17 100644 --- a/Minecraft.Client/Windows64/Windows64_Minecraft.cpp +++ b/Minecraft.Client/Windows64/Windows64_Minecraft.cpp @@ -395,9 +395,6 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) case WM_MOUSEWHEEL: KMInput.OnMouseWheel(GET_WHEEL_DELTA_WPARAM(wParam)); 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); @@ -407,15 +404,6 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) KMInput.ClearAllState(); 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)) - { - SetCursor(NULL); - return TRUE; - } - return DefWindowProc(hWnd, message, wParam, lParam); - default: return DefWindowProc(hWnd, message, wParam, lParam); } @@ -606,7 +594,6 @@ app.DebugPrintf("width: %d, height: %d\n", width, height); // Create a depth stencil buffer D3D11_TEXTURE2D_DESC descDepth; - ZeroMemory(&descDepth, sizeof(descDepth)); descDepth.Width = width; descDepth.Height = height; @@ -622,7 +609,6 @@ app.DebugPrintf("width: %d, height: %d\n", width, height); hr = g_pd3dDevice->CreateTexture2D(&descDepth, NULL, &g_pDepthStencilBuffer); D3D11_DEPTH_STENCIL_VIEW_DESC descDSView; - ZeroMemory(&descDSView, sizeof(descDSView)); descDSView.Format = DXGI_FORMAT_D24_UNORM_S8_UINT; descDSView.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D; descDSView.Texture2D.MipSlice = 0; @@ -716,26 +702,6 @@ int APIENTRY _tWinMain(_In_ HINSTANCE hInstance, UNREFERENCED_PARAMETER(hPrevInstance); UNREFERENCED_PARAMETER(lpCmdLine); - - WCHAR exePath[MAX_PATH] = { 0 }; - GetModuleFileNameW(NULL, exePath, MAX_PATH); - WCHAR* lastSlash = wcsrchr(exePath, L'\\'); - if (lastSlash) { - *lastSlash = L'\0'; - - WCHAR devCheckPath[MAX_PATH] = { 0 }; - swprintf_s(devCheckPath, MAX_PATH, L"%s\\..\\..\\Minecraft.Client\\Minecraft.Client.vcxproj", exePath); - - if (GetFileAttributesW(devCheckPath) != INVALID_FILE_ATTRIBUTES) { - WCHAR projectPath[MAX_PATH] = { 0 }; - swprintf_s(projectPath, MAX_PATH, L"%s\\..\\..\\Minecraft.Client", exePath); - SetCurrentDirectoryW(projectPath); - } - else { - SetCurrentDirectoryW(exePath); - } - } - // Declare DPI awareness so GetSystemMetrics returns physical pixels SetProcessDPIAware(); g_iScreenWidth = GetSystemMetrics(SM_CXSCREEN); @@ -1216,7 +1182,7 @@ int APIENTRY _tWinMain(_In_ HINSTANCE hInstance, // Update mouse capture: capture when in-game and no menu is open { static bool altToggleSuppressCapture = false; - bool shouldCapture = app.GetGameStarted() && !ui.GetMenuDisplayed(0) && pMinecraft->screen == NULL; + bool shouldCapture = app.GetGameStarted() && (!ui.GetMenuDisplayed(0) || ui.IsContainerMenuDisplayed(0)); // Left Alt key toggles capture on/off for debugging if (KMInput.IsKeyPressed(VK_MENU)) { @@ -1526,4 +1492,4 @@ void MemPixStuff() PIXAddNamedCounter(((float)allSectsTotal)/(4096.0f),"MemSect total pages"); } -#endif \ No newline at end of file +#endif