mirror of
https://github.com/smartcmd/MinecraftConsoles.git
synced 2026-08-20 09:57:09 +00:00
feat: improve Windows mouse input for menus and containers
Add robust keyboard/mouse menu focus/click handling, keep container cursor input responsive under capture, and align input consumption rules to prevent gameplay and UI from stealing each other’s mouse events.
This commit is contained in:
parent
b865228eed
commit
287d43a255
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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; }
|
||||
|
|
|
|||
|
|
@ -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
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -131,6 +131,18 @@ private:
|
|||
vector<QueuedMessageBoxData *> 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 );
|
||||
|
|
|
|||
|
|
@ -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<43>4 wireless controllers and the CUH-ZCT1J/CAP-ZCT1J/CAP-ZCT1U controllers for the PlayStation<6F>4 development tool,
|
||||
//0 to 753: JDX-1000x series controllers for the PlayStation<6F>4 development tool,)
|
||||
//Y coordinate of the touch point (0 to 941: DUALSHOCK<43>4 wireless controllers and the CUH-ZCT1J/CAP-ZCT1J/CAP-ZCT1U controllers for the PlayStation<6F>4 development tool,)
|
||||
//0 to 753: JDX-1000x series controllers for the PlayStation<6F>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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
#endif
|
||||
|
|
|
|||
Loading…
Reference in a new issue