diff --git a/Minecraft.Client/Common/UI/UIControl_TextInput.cpp b/Minecraft.Client/Common/UI/UIControl_TextInput.cpp index 193dbf41f..0bfa0bbd3 100644 --- a/Minecraft.Client/Common/UI/UIControl_TextInput.cpp +++ b/Minecraft.Client/Common/UI/UIControl_TextInput.cpp @@ -193,7 +193,7 @@ UIControl_TextInput::EDirectEditResult UIControl_TextInput::tickDirectEdit() { m_bDirectEditing = false; m_iDirectEditCooldown = 4; - setLabel(m_editBuffer.c_str()); + setLabel(m_editBuffer.c_str(), true); setCaretVisible(false); return eDirectEdit_Confirmed; } @@ -263,7 +263,7 @@ void UIControl_TextInput::cancelDirectEdit() m_editBuffer = m_textBeforeEdit; m_bDirectEditing = false; m_iDirectEditCooldown = 4; - setLabel(m_editBuffer.c_str()); + setLabel(m_editBuffer.c_str(), true); setCaretVisible(false); } } @@ -273,7 +273,7 @@ void UIControl_TextInput::confirmDirectEdit() if (m_bDirectEditing) { m_bDirectEditing = false; - setLabel(m_editBuffer.c_str()); + setLabel(m_editBuffer.c_str(), true); setCaretVisible(false); } } diff --git a/Minecraft.Client/Common/UI/UIController.cpp b/Minecraft.Client/Common/UI/UIController.cpp index 9418d9509..d098aa1dd 100644 --- a/Minecraft.Client/Common/UI/UIController.cpp +++ b/Minecraft.Client/Common/UI/UIController.cpp @@ -3,6 +3,7 @@ #include "UI.h" #include "UIScene.h" #include "UIControl_Slider.h" +#include "UIControl_TexturePackList.h" #include "..\..\..\Minecraft.World\StringHelpers.h" #include "..\..\LocalPlayer.h" #include "..\..\DLCTexturePack.h" @@ -238,6 +239,7 @@ UIController::UIController() m_mouseDraggingSliderScene = eUIScene_COUNT; m_mouseDraggingSliderId = -1; m_mouseClickConsumedByScene = false; + m_bMouseHoverHorizontalList = false; m_lastHoverMouseX = -1; m_lastHoverMouseY = -1; m_accumulatedTicks = 0; @@ -899,12 +901,13 @@ void UIController::tickInput() // use their own SetTouchFocus for Flash-side hit testing. if (mouseMoved) { + m_bMouseHoverHorizontalList = false; vector *controls = pScene->GetControls(); if (controls) { int hitControlId = -1; S32 hitArea = INT_MAX; - bool hitIsTextInput = false; + UIControl *hitCtrl = NULL; for (size_t i = 0; i < controls->size(); ++i) { UIControl *ctrl = (*controls)[i]; @@ -914,7 +917,7 @@ void UIController::tickInput() UIControl::eUIControlType type = ctrl->getControlType(); if (type != UIControl::eButton && type != UIControl::eTextInput && type != UIControl::eCheckBox && type != UIControl::eSlider && - type != UIControl::eButtonList) + type != UIControl::eButtonList && type != UIControl::eTexturePackList) continue; // If the scene has an active panel (e.g. tab menus), @@ -927,6 +930,10 @@ void UIController::tickInput() S32 cy = ctrl->getYPos() + panelOffsetY; S32 cw = ctrl->getWidth(); S32 ch = ctrl->getHeight(); + // TexturePackList origin is where the slot area starts, + // not the top-left of the whole control — use GetRealHeight. + if (type == UIControl::eTexturePackList) + ch = ((UIControl_TexturePackList *)ctrl)->GetRealHeight(); if (cw <= 0 || ch <= 0) continue; @@ -941,24 +948,54 @@ void UIController::tickInput() (S32)sceneMouseX, (S32)sceneMouseY, false); hitControlId = -1; hitArea = INT_MAX; + hitCtrl = NULL; break; // ButtonList takes priority } + if (type == UIControl::eTexturePackList) + { + // TexturePackList expects coords relative to its origin. + UIControl_TexturePackList *pList = (UIControl_TexturePackList *)ctrl; + pScene->SetFocusToElement(ctrl->getId()); + pList->SetTouchFocus( + (S32)(sceneMouseX - cx), (S32)(sceneMouseY - cy), false); + m_bMouseHoverHorizontalList = true; + hitControlId = -1; + hitArea = INT_MAX; + hitCtrl = NULL; + break; + } S32 area = cw * ch; if (area < hitArea) { hitControlId = ctrl->getId(); hitArea = area; - hitIsTextInput = (type == UIControl::eTextInput); + hitCtrl = ctrl; + if (type == UIControl::eSlider) + m_bMouseHoverHorizontalList = true; } } } - // Set focus directly via Flash AS, matching the click path. - // Skip TextInput — its Iggy focus is set on click (below) - // to avoid showing the caret on mere hover. - if (hitControlId >= 0 && !hitIsTextInput && pScene->getControlFocus() != hitControlId) + if (hitControlId >= 0 && pScene->getControlFocus() != hitControlId) { - pScene->SetFocusToElement(hitControlId); + // During direct editing, don't let hover move focus + // away to other TextInputs (e.g. sign lines). + if (hitCtrl && hitCtrl->getControlType() == UIControl::eTextInput + && pScene->isDirectEditBlocking()) + { + // Skip — keep focus on the actively-edited input + } + else + { + pScene->SetFocusToElement(hitControlId); + // TextInput: SetFocusToElement triggers ChangeState which + // shows the caret. Hide it immediately — the render pass + // happens after both tickInput and scene tick, so no flicker. + if (hitCtrl && hitCtrl->getControlType() == UIControl::eTextInput) + { + ((UIControl_TextInput *)hitCtrl)->setCaretVisible(false); + } + } } } } @@ -1372,11 +1409,14 @@ void UIController::handleKeyPress(unsigned int iPad, unsigned int key) down = true; } - // Remap scroll wheel to UP/DOWN so all scenes get it without - // needing per-scene OTHER_STICK handling. + // Remap scroll wheel to navigation actions. Use LEFT/RIGHT when + // hovering a horizontal list (e.g. TexturePackList), UP/DOWN otherwise. if (pressed && g_KBMInput.IsKBMActive()) { - key = (key == ACTION_MENU_OTHER_STICK_UP) ? ACTION_MENU_UP : ACTION_MENU_DOWN; + if (m_bMouseHoverHorizontalList) + key = (key == ACTION_MENU_OTHER_STICK_UP) ? ACTION_MENU_LEFT : ACTION_MENU_RIGHT; + else + key = (key == ACTION_MENU_OTHER_STICK_UP) ? ACTION_MENU_UP : ACTION_MENU_DOWN; } } } diff --git a/Minecraft.Client/Common/UI/UIController.h b/Minecraft.Client/Common/UI/UIController.h index 46983c100..7a0c6075c 100644 --- a/Minecraft.Client/Common/UI/UIController.h +++ b/Minecraft.Client/Common/UI/UIController.h @@ -161,6 +161,7 @@ private: EUIScene m_mouseDraggingSliderScene; int m_mouseDraggingSliderId; bool m_mouseClickConsumedByScene; + bool m_bMouseHoverHorizontalList; int m_lastHoverMouseX; int m_lastHoverMouseY; //bool m_bSysUIShowing; diff --git a/Minecraft.Client/Common/UI/UIScene.cpp b/Minecraft.Client/Common/UI/UIScene.cpp index 0aedbf18f..061f9832f 100644 --- a/Minecraft.Client/Common/UI/UIScene.cpp +++ b/Minecraft.Client/Common/UI/UIScene.cpp @@ -447,6 +447,19 @@ void UIScene::tick() IggyPlayerTickRS( swf ); m_hasTickedOnce = true; } + +#ifdef _WINDOWS64 + { + vector inputs; + getDirectEditInputs(inputs); + for (size_t i = 0; i < inputs.size(); i++) + { + UIControl_TextInput::EDirectEditResult result = inputs[i]->tickDirectEdit(); + if (result != UIControl_TextInput::eDirectEdit_Continue) + onDirectEditFinished(inputs[i], result); + } + } +#endif } UIControl* UIScene::GetMainPanel() @@ -455,6 +468,18 @@ UIControl* UIScene::GetMainPanel() } #ifdef _WINDOWS64 +bool UIScene::isDirectEditBlocking() +{ + vector inputs; + getDirectEditInputs(inputs); + for (size_t i = 0; i < inputs.size(); i++) + { + if (inputs[i]->isDirectEditing() || inputs[i]->getDirectEditCooldown() > 0) + return true; + } + return false; +} + bool UIScene::handleMouseClick(F32 x, F32 y) { S32 panelOffsetX = 0, panelOffsetY = 0; @@ -466,6 +491,28 @@ bool UIScene::handleMouseClick(F32 x, F32 y) panelOffsetY = pMainPanel->getYPos(); } + // Click-outside-to-deselect: confirm any active direct edit if + // the click landed outside the editing text input. + { + vector deInputs; + getDirectEditInputs(deInputs); + for (size_t i = 0; i < deInputs.size(); i++) + { + if (!deInputs[i]->isDirectEditing()) + continue; + deInputs[i]->UpdateControl(); + S32 cx = deInputs[i]->getXPos() + panelOffsetX; + S32 cy = deInputs[i]->getYPos() + panelOffsetY; + S32 cw = deInputs[i]->getWidth(); + S32 ch = deInputs[i]->getHeight(); + if (!(cw > 0 && ch > 0 && x >= cx && x <= cx + cw && y >= cy && y <= cy + ch)) + { + deInputs[i]->confirmDirectEdit(); + onDirectEditFinished(deInputs[i], UIControl_TextInput::eDirectEdit_Confirmed); + } + } + } + vector *controls = GetControls(); if (!controls) return false; diff --git a/Minecraft.Client/Common/UI/UIScene.h b/Minecraft.Client/Common/UI/UIScene.h index df2bc840d..8fb4983bd 100644 --- a/Minecraft.Client/Common/UI/UIScene.h +++ b/Minecraft.Client/Common/UI/UIScene.h @@ -6,6 +6,7 @@ using namespace std; #include "UIEnums.h" #include "UIControl_Base.h" +#include "UIControl_TextInput.h" class ItemRenderer; class UILayer; @@ -184,6 +185,13 @@ public: virtual UIControl* GetMainPanel(); #ifdef _WINDOWS64 + // Direct edit support: scenes override to register their text inputs. + // Base class handles tickDirectEdit in tick(), click-outside-to-deselect + // in handleMouseClick(), and provides isDirectEditBlocking() for guards. + virtual void getDirectEditInputs(vector &inputs) {} + virtual void onDirectEditFinished(UIControl_TextInput *input, UIControl_TextInput::EDirectEditResult result) {} + bool isDirectEditBlocking(); + // Mouse click dispatch. Hit-tests C++ controls and picks the smallest-area // match, then calls handlePress. Override for custom behaviour (e.g. crafting). virtual bool handleMouseClick(F32 x, F32 y); diff --git a/Minecraft.Client/Common/UI/UIScene_AnvilMenu.cpp b/Minecraft.Client/Common/UI/UIScene_AnvilMenu.cpp index 0d6918661..4d43a638b 100644 --- a/Minecraft.Client/Common/UI/UIScene_AnvilMenu.cpp +++ b/Minecraft.Client/Common/UI/UIScene_AnvilMenu.cpp @@ -97,11 +97,15 @@ void UIScene_AnvilMenu::tick() UIScene_AbstractContainerMenu::tick(); #ifdef _WINDOWS64 - UIControl_TextInput::EDirectEditResult editResult = m_textInputAnvil.tickDirectEdit(); - if (editResult == UIControl_TextInput::eDirectEdit_Confirmed) + // Live update: sync item name per-keystroke while editing (like Java edition) + if (m_textInputAnvil.isDirectEditing()) { - m_itemName = m_textInputAnvil.getEditBuffer(); - updateItemName(); + const wstring& buf = m_textInputAnvil.getEditBuffer(); + if (buf != m_itemName) + { + m_itemName = buf; + updateItemName(); + } } #endif @@ -315,6 +319,19 @@ UIControl *UIScene_AnvilMenu::getSection(ESceneSection eSection) return control; } +#ifdef _WINDOWS64 +void UIScene_AnvilMenu::getDirectEditInputs(vector &inputs) +{ + inputs.push_back(&m_textInputAnvil); +} + +void UIScene_AnvilMenu::onDirectEditFinished(UIControl_TextInput *input, UIControl_TextInput::EDirectEditResult result) +{ + m_itemName = input->getEditBuffer(); + updateItemName(); +} +#endif + int UIScene_AnvilMenu::KeyboardCompleteCallback(LPVOID lpParam,bool bRes) { UIScene_AnvilMenu *pClass=(UIScene_AnvilMenu *)lpParam; @@ -344,7 +361,7 @@ int UIScene_AnvilMenu::KeyboardCompleteCallback(LPVOID lpParam,bool bRes) void UIScene_AnvilMenu::handleEditNamePressed() { #ifdef _WINDOWS64 - if (m_textInputAnvil.isDirectEditing() || m_textInputAnvil.getDirectEditCooldown() > 0) + if (isDirectEditBlocking()) return; if (g_KBMInput.IsKBMActive()) diff --git a/Minecraft.Client/Common/UI/UIScene_AnvilMenu.h b/Minecraft.Client/Common/UI/UIScene_AnvilMenu.h index 3afc63338..44f759929 100644 --- a/Minecraft.Client/Common/UI/UIScene_AnvilMenu.h +++ b/Minecraft.Client/Common/UI/UIScene_AnvilMenu.h @@ -55,6 +55,10 @@ protected: virtual UIControl *getSection(ESceneSection eSection); +#ifdef _WINDOWS64 + virtual void getDirectEditInputs(vector &inputs); + virtual void onDirectEditFinished(UIControl_TextInput *input, UIControl_TextInput::EDirectEditResult result); +#endif static int KeyboardCompleteCallback(LPVOID lpParam,bool bRes); virtual void handleEditNamePressed(); virtual void setEditNameValue(const wstring &name); diff --git a/Minecraft.Client/Common/UI/UIScene_CreateWorldMenu.cpp b/Minecraft.Client/Common/UI/UIScene_CreateWorldMenu.cpp index 364c9ebda..a9cd9853f 100644 --- a/Minecraft.Client/Common/UI/UIScene_CreateWorldMenu.cpp +++ b/Minecraft.Client/Common/UI/UIScene_CreateWorldMenu.cpp @@ -289,14 +289,6 @@ void UIScene_CreateWorldMenu::tick() { UIScene::tick(); -#ifdef _WINDOWS64 - UIControl_TextInput::EDirectEditResult editResult = m_editWorldName.tickDirectEdit(); - if (editResult == UIControl_TextInput::eDirectEdit_Confirmed || editResult == UIControl_TextInput::eDirectEdit_Cancelled) - { - m_worldName = m_editWorldName.getEditBuffer(); - m_buttonCreateWorld.setEnable(!m_worldName.empty()); - } -#endif if(m_iSetTexturePackDescription >= 0 ) { @@ -360,11 +352,24 @@ int UIScene_CreateWorldMenu::ContinueOffline(void *pParam,int iPad,C4JStorage::E #endif +#ifdef _WINDOWS64 +void UIScene_CreateWorldMenu::getDirectEditInputs(vector &inputs) +{ + inputs.push_back(&m_editWorldName); +} + +void UIScene_CreateWorldMenu::onDirectEditFinished(UIControl_TextInput *input, UIControl_TextInput::EDirectEditResult result) +{ + m_worldName = input->getEditBuffer(); + m_buttonCreateWorld.setEnable(!m_worldName.empty()); +} +#endif + void UIScene_CreateWorldMenu::handleInput(int iPad, int key, bool repeat, bool pressed, bool released, bool &handled) { if(m_bIgnoreInput) return; #ifdef _WINDOWS64 - if (m_editWorldName.isDirectEditing() || m_editWorldName.getDirectEditCooldown() > 0) { handled = true; return; } + if (isDirectEditBlocking()) { handled = true; return; } #endif ui.AnimateKeyPress(m_iPad, key, repeat, pressed, released); @@ -421,7 +426,7 @@ void UIScene_CreateWorldMenu::handlePress(F64 controlId, F64 childId) { if(m_bIgnoreInput) return; #ifdef _WINDOWS64 - if (m_editWorldName.isDirectEditing() || m_editWorldName.getDirectEditCooldown() > 0) return; + if (isDirectEditBlocking()) return; #endif //CD - Added for audio diff --git a/Minecraft.Client/Common/UI/UIScene_CreateWorldMenu.h b/Minecraft.Client/Common/UI/UIScene_CreateWorldMenu.h index 49ab6ec50..75bfe602b 100644 --- a/Minecraft.Client/Common/UI/UIScene_CreateWorldMenu.h +++ b/Minecraft.Client/Common/UI/UIScene_CreateWorldMenu.h @@ -78,6 +78,10 @@ protected: public: // INPUT virtual void handleInput(int iPad, int key, bool repeat, bool pressed, bool released, bool &handled); +#ifdef _WINDOWS64 + virtual void getDirectEditInputs(vector &inputs); + virtual void onDirectEditFinished(UIControl_TextInput *input, UIControl_TextInput::EDirectEditResult result); +#endif private: void StartSharedLaunchFlow(); diff --git a/Minecraft.Client/Common/UI/UIScene_DebugCreateSchematic.cpp b/Minecraft.Client/Common/UI/UIScene_DebugCreateSchematic.cpp index 2eee6ce6a..d3da08709 100644 --- a/Minecraft.Client/Common/UI/UIScene_DebugCreateSchematic.cpp +++ b/Minecraft.Client/Common/UI/UIScene_DebugCreateSchematic.cpp @@ -34,10 +34,6 @@ UIScene_DebugCreateSchematic::UIScene_DebugCreateSchematic(int iPad, void *initD m_buttonCreate.init(L"Create",eControl_Create); m_data = new ConsoleSchematicFile::XboxSchematicInitParam(); - -#ifdef _WINDOWS64 - m_activeDirectEditControl = eControl_Create; // sentinel: no active edit -#endif } wstring UIScene_DebugCreateSchematic::getMoviePath() @@ -61,9 +57,41 @@ UIControl_TextInput* UIScene_DebugCreateSchematic::getTextInputForControl(eContr } #ifdef _WINDOWS64 +void UIScene_DebugCreateSchematic::getDirectEditInputs(vector &inputs) +{ + inputs.push_back(&m_textInputName); + inputs.push_back(&m_textInputStartX); + inputs.push_back(&m_textInputStartY); + inputs.push_back(&m_textInputStartZ); + inputs.push_back(&m_textInputEndX); + inputs.push_back(&m_textInputEndY); + inputs.push_back(&m_textInputEndZ); +} + +void UIScene_DebugCreateSchematic::onDirectEditFinished(UIControl_TextInput *input, UIControl_TextInput::EDirectEditResult result) +{ + wstring value = input->getEditBuffer(); + int iVal = 0; + if (!value.empty()) + iVal = _fromString(value); + + if (input == &m_textInputName) + { + if (!value.empty()) + swprintf(m_data->name, 64, L"%ls", value.c_str()); + else + swprintf(m_data->name, 64, L"schematic"); + } + else if (input == &m_textInputStartX) m_data->startX = iVal; + else if (input == &m_textInputStartY) m_data->startY = iVal; + else if (input == &m_textInputStartZ) m_data->startZ = iVal; + else if (input == &m_textInputEndX) m_data->endX = iVal; + else if (input == &m_textInputEndY) m_data->endY = iVal; + else if (input == &m_textInputEndZ) m_data->endZ = iVal; +} + bool UIScene_DebugCreateSchematic::handleMouseClick(F32 x, F32 y) { - if (m_activeDirectEditControl != eControl_Create) return true; UIScene::handleMouseClick(x, y); return true; // always consume to prevent Iggy re-entry on empty space } @@ -72,48 +100,12 @@ bool UIScene_DebugCreateSchematic::handleMouseClick(F32 x, F32 y) void UIScene_DebugCreateSchematic::tick() { UIScene::tick(); - -#ifdef _WINDOWS64 - UIControl_TextInput* allInputs[] = { &m_textInputName, &m_textInputStartX, &m_textInputStartY, &m_textInputStartZ, &m_textInputEndX, &m_textInputEndY, &m_textInputEndZ }; - for (int i = 0; i < 7; i++) - allInputs[i]->tickDirectEdit(); - - if (m_activeDirectEditControl != eControl_Create) - { - UIControl_TextInput* active = getTextInputForControl(m_activeDirectEditControl); - if (active && !active->isDirectEditing()) - { - // Edit finished — apply value - wstring value = active->getEditBuffer(); - int iVal = 0; - if (!value.empty() && m_activeDirectEditControl != eControl_Name) - iVal = _fromString(value); - - switch (m_activeDirectEditControl) - { - case eControl_Name: - if (!value.empty()) - swprintf(m_data->name, 64, L"%ls", value.c_str()); - else - swprintf(m_data->name, 64, L"schematic"); - break; - case eControl_StartX: m_data->startX = iVal; break; - case eControl_StartY: m_data->startY = iVal; break; - case eControl_StartZ: m_data->startZ = iVal; break; - case eControl_EndX: m_data->endX = iVal; break; - case eControl_EndY: m_data->endY = iVal; break; - case eControl_EndZ: m_data->endZ = iVal; break; - } - m_activeDirectEditControl = eControl_Create; - } - } -#endif } void UIScene_DebugCreateSchematic::handleInput(int iPad, int key, bool repeat, bool pressed, bool released, bool &handled) { #ifdef _WINDOWS64 - if (m_activeDirectEditControl != eControl_Create) return; + if (isDirectEditBlocking()) return; #endif ui.AnimateKeyPress(iPad, key, repeat, pressed, released); @@ -140,7 +132,7 @@ void UIScene_DebugCreateSchematic::handleInput(int iPad, int key, bool repeat, b void UIScene_DebugCreateSchematic::handlePress(F64 controlId, F64 childId) { #ifdef _WINDOWS64 - if (m_activeDirectEditControl != eControl_Create) return; + if (isDirectEditBlocking()) return; #endif switch((int)controlId) { @@ -192,8 +184,7 @@ void UIScene_DebugCreateSchematic::handlePress(F64 controlId, F64 childId) #ifdef _WINDOWS64 if (g_KBMInput.IsKBMActive()) { - m_activeDirectEditControl = m_keyboardCallbackControl; - UIControl_TextInput* input = getTextInputForControl(m_activeDirectEditControl); + UIControl_TextInput* input = getTextInputForControl(m_keyboardCallbackControl); if (input) input->beginDirectEdit(25); } else diff --git a/Minecraft.Client/Common/UI/UIScene_DebugCreateSchematic.h b/Minecraft.Client/Common/UI/UIScene_DebugCreateSchematic.h index f830727a2..e18d9f5d0 100644 --- a/Minecraft.Client/Common/UI/UIScene_DebugCreateSchematic.h +++ b/Minecraft.Client/Common/UI/UIScene_DebugCreateSchematic.h @@ -24,9 +24,6 @@ private: ConsoleSchematicFile::XboxSchematicInitParam *m_data; -#ifdef _WINDOWS64 - eControls m_activeDirectEditControl; -#endif public: UIScene_DebugCreateSchematic(int iPad, void *initData, UILayer *parentLayer); @@ -63,6 +60,8 @@ protected: virtual wstring getMoviePath(); #ifdef _WINDOWS64 + virtual void getDirectEditInputs(vector &inputs); + virtual void onDirectEditFinished(UIControl_TextInput *input, UIControl_TextInput::EDirectEditResult result); virtual bool handleMouseClick(F32 x, F32 y); #endif diff --git a/Minecraft.Client/Common/UI/UIScene_DebugSetCamera.cpp b/Minecraft.Client/Common/UI/UIScene_DebugSetCamera.cpp index 440d51b4c..62ee60b13 100644 --- a/Minecraft.Client/Common/UI/UIScene_DebugSetCamera.cpp +++ b/Minecraft.Client/Common/UI/UIScene_DebugSetCamera.cpp @@ -56,9 +56,6 @@ UIScene_DebugSetCamera::UIScene_DebugSetCamera(int iPad, void *initData, UILayer m_labelCamZ.init(L"CamZ"); m_labelYRotElev.init(L"Y-Rot & Elevation (Degs)"); -#ifdef _WINDOWS64 - m_activeDirectEditControl = eControl_Teleport; // sentinel — no active edit -#endif } wstring UIScene_DebugSetCamera::getMoviePath() @@ -80,30 +77,30 @@ UIControl_TextInput* UIScene_DebugSetCamera::getTextInputForControl(eControls ct } } +void UIScene_DebugSetCamera::getDirectEditInputs(vector &inputs) +{ + inputs.push_back(&m_textInputX); + inputs.push_back(&m_textInputY); + inputs.push_back(&m_textInputZ); + inputs.push_back(&m_textInputYRot); + inputs.push_back(&m_textInputElevation); +} + +void UIScene_DebugSetCamera::onDirectEditFinished(UIControl_TextInput *input, UIControl_TextInput::EDirectEditResult result) +{ + wstring value = input->getEditBuffer(); + double val = 0; + if (!value.empty()) val = _fromString(value); + + if (input == &m_textInputX) currentPosition->m_camX = val; + else if (input == &m_textInputY) currentPosition->m_camY = val; + else if (input == &m_textInputZ) currentPosition->m_camZ = val; + else if (input == &m_textInputYRot) currentPosition->m_yRot = val; + else if (input == &m_textInputElevation) currentPosition->m_elev = val; +} + bool UIScene_DebugSetCamera::handleMouseClick(F32 x, F32 y) { - // If currently editing, confirm the current edit before processing the click - if (m_activeDirectEditControl != eControl_Teleport) - { - UIControl_TextInput* active = getTextInputForControl(m_activeDirectEditControl); - if (active && active->isDirectEditing()) - { - wstring value = active->getEditBuffer(); - double val = 0; - if (!value.empty()) val = _fromString(value); - switch (m_activeDirectEditControl) - { - case eControl_CamX: currentPosition->m_camX = val; break; - case eControl_CamY: currentPosition->m_camY = val; break; - case eControl_CamZ: currentPosition->m_camZ = val; break; - case eControl_YRot: currentPosition->m_yRot = val; break; - case eControl_Elevation: currentPosition->m_elev = val; break; - } - active->confirmDirectEdit(); - } - m_activeDirectEditControl = eControl_Teleport; - } - UIScene::handleMouseClick(x, y); return true; // always consume to prevent Iggy re-entry on empty space } @@ -112,40 +109,12 @@ bool UIScene_DebugSetCamera::handleMouseClick(F32 x, F32 y) void UIScene_DebugSetCamera::tick() { UIScene::tick(); - -#ifdef _WINDOWS64 - UIControl_TextInput* inputs[] = { &m_textInputX, &m_textInputY, &m_textInputZ, &m_textInputYRot, &m_textInputElevation }; - for (int i = 0; i < 5; i++) - { - UIControl_TextInput::EDirectEditResult result = inputs[i]->tickDirectEdit(); - if (result == UIControl_TextInput::eDirectEdit_Confirmed) - { - wstring value = inputs[i]->getEditBuffer(); - double val = 0; - if (!value.empty()) val = _fromString(value); - eControls ctrl = (eControls)i; // eControl_CamX=0, CamY=1, CamZ=2, YRot=3, Elevation=4 - switch (ctrl) - { - case eControl_CamX: currentPosition->m_camX = val; break; - case eControl_CamY: currentPosition->m_camY = val; break; - case eControl_CamZ: currentPosition->m_camZ = val; break; - case eControl_YRot: currentPosition->m_yRot = val; break; - case eControl_Elevation: currentPosition->m_elev = val; break; - } - m_activeDirectEditControl = eControl_Teleport; - } - else if (result == UIControl_TextInput::eDirectEdit_Cancelled) - { - m_activeDirectEditControl = eControl_Teleport; - } - } -#endif } void UIScene_DebugSetCamera::handleInput(int iPad, int key, bool repeat, bool pressed, bool released, bool &handled) { #ifdef _WINDOWS64 - if (m_activeDirectEditControl != eControl_Teleport) { handled = true; return; } + if (isDirectEditBlocking()) { handled = true; return; } #endif ui.AnimateKeyPress(iPad, key, repeat, pressed, released); @@ -172,7 +141,7 @@ void UIScene_DebugSetCamera::handleInput(int iPad, int key, bool repeat, bool pr void UIScene_DebugSetCamera::handlePress(F64 controlId, F64 childId) { #ifdef _WINDOWS64 - if (m_activeDirectEditControl != eControl_Teleport) return; + if (isDirectEditBlocking()) return; #endif switch((int)controlId) { @@ -190,8 +159,7 @@ void UIScene_DebugSetCamera::handlePress(F64 controlId, F64 childId) #ifdef _WINDOWS64 if (g_KBMInput.IsKBMActive()) { - m_activeDirectEditControl = m_keyboardCallbackControl; - UIControl_TextInput* input = getTextInputForControl(m_activeDirectEditControl); + UIControl_TextInput* input = getTextInputForControl(m_keyboardCallbackControl); if (input) input->beginDirectEdit(25); } else diff --git a/Minecraft.Client/Common/UI/UIScene_DebugSetCamera.h b/Minecraft.Client/Common/UI/UIScene_DebugSetCamera.h index 95b72f761..d758e049e 100644 --- a/Minecraft.Client/Common/UI/UIScene_DebugSetCamera.h +++ b/Minecraft.Client/Common/UI/UIScene_DebugSetCamera.h @@ -27,7 +27,6 @@ private: eControls m_keyboardCallbackControl; #ifdef _WINDOWS64 - eControls m_activeDirectEditControl; UIControl_TextInput* getTextInputForControl(eControls ctrl); #endif @@ -60,6 +59,8 @@ protected: virtual wstring getMoviePath(); virtual void tick(); #ifdef _WINDOWS64 + virtual void getDirectEditInputs(vector &inputs); + virtual void onDirectEditFinished(UIControl_TextInput *input, UIControl_TextInput::EDirectEditResult result); virtual bool handleMouseClick(F32 x, F32 y); #endif diff --git a/Minecraft.Client/Common/UI/UIScene_LaunchMoreOptionsMenu.cpp b/Minecraft.Client/Common/UI/UIScene_LaunchMoreOptionsMenu.cpp index 7c3ec0138..96dd744e9 100644 --- a/Minecraft.Client/Common/UI/UIScene_LaunchMoreOptionsMenu.cpp +++ b/Minecraft.Client/Common/UI/UIScene_LaunchMoreOptionsMenu.cpp @@ -211,12 +211,6 @@ void UIScene_LaunchMoreOptionsMenu::tick() { UIScene::tick(); -#ifdef _WINDOWS64 - UIControl_TextInput::EDirectEditResult editResult = m_editSeed.tickDirectEdit(); - if (editResult == UIControl_TextInput::eDirectEdit_Confirmed) - m_params->seed = m_editSeed.getEditBuffer(); -#endif - bool bMultiplayerAllowed = ProfileManager.IsSignedInLive(m_params->iPad) && ProfileManager.AllowedToPlayMultiplayer(m_params->iPad); if (bMultiplayerAllowed != m_bMultiplayerAllowed) @@ -264,7 +258,7 @@ void UIScene_LaunchMoreOptionsMenu::handleInput(int iPad, int key, bool repeat, { if(m_bIgnoreInput) return; #ifdef _WINDOWS64 - if (m_editSeed.isDirectEditing() || m_editSeed.getDirectEditCooldown() > 0) return; + if (isDirectEditBlocking()) return; #endif //app.DebugPrintf("UIScene_DebugOverlay handling input for pad %d, key %d, down- %s, pressed- %s, released- %s\n", iPad, key, down?"TRUE":"FALSE", pressed?"TRUE":"FALSE", released?"TRUE":"FALSE"); @@ -581,11 +575,24 @@ int UIScene_LaunchMoreOptionsMenu::KeyboardCompleteSeedCallback(LPVOID lpParam,b return 0; } +#ifdef _WINDOWS64 +void UIScene_LaunchMoreOptionsMenu::getDirectEditInputs(vector &inputs) +{ + inputs.push_back(&m_editSeed); +} + +void UIScene_LaunchMoreOptionsMenu::onDirectEditFinished(UIControl_TextInput *input, UIControl_TextInput::EDirectEditResult result) +{ + if (result == UIControl_TextInput::eDirectEdit_Confirmed) + m_params->seed = input->getEditBuffer(); +} +#endif + void UIScene_LaunchMoreOptionsMenu::handlePress(F64 controlId, F64 childId) { if(m_bIgnoreInput) return; #ifdef _WINDOWS64 - if (m_editSeed.isDirectEditing() || m_editSeed.getDirectEditCooldown() > 0) return; + if (isDirectEditBlocking()) return; #endif switch((int)controlId) diff --git a/Minecraft.Client/Common/UI/UIScene_LaunchMoreOptionsMenu.h b/Minecraft.Client/Common/UI/UIScene_LaunchMoreOptionsMenu.h index e7da49183..caf9a71f0 100644 --- a/Minecraft.Client/Common/UI/UIScene_LaunchMoreOptionsMenu.h +++ b/Minecraft.Client/Common/UI/UIScene_LaunchMoreOptionsMenu.h @@ -140,6 +140,10 @@ protected: public: virtual void tick(); virtual void handleDestroy(); +#ifdef _WINDOWS64 + virtual void getDirectEditInputs(vector &inputs); + virtual void onDirectEditFinished(UIControl_TextInput *input, UIControl_TextInput::EDirectEditResult result); +#endif // INPUT virtual void handleInput(int iPad, int key, bool repeat, bool pressed, bool released, bool &handled); virtual void handleFocusChange(F64 controlId, F64 childId); diff --git a/Minecraft.Client/Common/UI/UIScene_SignEntryMenu.cpp b/Minecraft.Client/Common/UI/UIScene_SignEntryMenu.cpp index cfb1624bf..9f049c8c9 100644 --- a/Minecraft.Client/Common/UI/UIScene_SignEntryMenu.cpp +++ b/Minecraft.Client/Common/UI/UIScene_SignEntryMenu.cpp @@ -18,8 +18,11 @@ UIScene_SignEntryMenu::UIScene_SignEntryMenu(int iPad, void *_initData, UILayer m_bConfirmed = false; m_bIgnoreInput = false; + m_iSignCursorFrame = 0; #ifdef _WINDOWS64 m_iActiveDirectEditLine = -1; + m_bNeedsInitialEdit = true; + m_bSkipTickNav = false; #endif m_buttonConfirm.init(app.GetString(IDS_DONE), eControl_Confirm); @@ -56,6 +59,7 @@ UIScene_SignEntryMenu::UIScene_SignEntryMenu(int iPad, void *_initData, UILayer UIScene_SignEntryMenu::~UIScene_SignEntryMenu() { + m_sign->SetSelectedLine(-1); m_parentLayer->removeComponent(eUIComponent_MenuBackground); } @@ -81,17 +85,78 @@ void UIScene_SignEntryMenu::tick() UIScene::tick(); #ifdef _WINDOWS64 - for (int i = 0; i < 4; i++) - m_textInputLines[i].tickDirectEdit(); - - if (m_iActiveDirectEditLine >= 0) + // On first tick, auto-start editing line 1 if KBM is active (Java-style flow) + if (m_bNeedsInitialEdit) { - UIControl_TextInput& line = m_textInputLines[m_iActiveDirectEditLine]; - if (!line.isDirectEditing()) - m_iActiveDirectEditLine = -1; + m_bNeedsInitialEdit = false; + if (g_KBMInput.IsKBMActive()) + { + SetFocusToElement(eControl_Line1); + m_iActiveDirectEditLine = 0; + m_textInputLines[0].beginDirectEdit(15); + } } + + // UP/DOWN navigation — must happen after tickDirectEdit (so typed chars are consumed) + // and before sign cursor update (so the cursor is correct for this frame's render) + // m_bSkipTickNav prevents double-processing when handleInput auto-started editing this frame + if (m_iActiveDirectEditLine >= 0 && !m_bSkipTickNav) + { + int navDir = 0; + if (g_KBMInput.IsKeyPressed(VK_DOWN)) navDir = 1; + else if (g_KBMInput.IsKeyPressed(VK_UP)) navDir = -1; + + if (navDir != 0) + { + int newLine = m_iActiveDirectEditLine + navDir; + if (newLine >= eControl_Line1 && newLine <= eControl_Line4) + { + m_textInputLines[m_iActiveDirectEditLine].confirmDirectEdit(); + SetFocusToElement(newLine); + m_iActiveDirectEditLine = newLine; + m_textInputLines[newLine].beginDirectEdit(15); + } + else if (navDir > 0) + { + m_textInputLines[m_iActiveDirectEditLine].confirmDirectEdit(); + SetFocusToElement(eControl_Confirm); + m_iActiveDirectEditLine = -1; + } + } + } + m_bSkipTickNav = false; + + if (m_iActiveDirectEditLine >= 0 && !m_textInputLines[m_iActiveDirectEditLine].isDirectEditing()) + m_iActiveDirectEditLine = -1; #endif + // Blinking > text < cursor on the 3D sign + m_iSignCursorFrame++; + if (m_iSignCursorFrame / 6 % 2 == 0) + { +#ifdef _WINDOWS64 + if (m_iActiveDirectEditLine >= 0) + m_sign->SetSelectedLine(m_iActiveDirectEditLine); + else +#endif + { + int focusedLine = -1; + for (int i = eControl_Line1; i <= eControl_Line4; i++) + { + if (controlHasFocus(i)) + { + focusedLine = i; + break; + } + } + m_sign->SetSelectedLine(focusedLine); + } + } + else + { + m_sign->SetSelectedLine(-1); + } + if(m_bConfirmed) { m_bConfirmed = false; @@ -123,28 +188,7 @@ void UIScene_SignEntryMenu::handleInput(int iPad, int key, bool repeat, bool pre { if(m_bConfirmed || m_bIgnoreInput) return; #ifdef _WINDOWS64 - if (m_iActiveDirectEditLine >= 0) - { - // Mouse click while editing — confirm current line and let click through - if (key == ACTION_MENU_OK && pressed && g_KBMInput.IsMouseButtonPressed(KeyboardMouseInput::MOUSE_LEFT)) - { - m_textInputLines[m_iActiveDirectEditLine].confirmDirectEdit(); - m_iActiveDirectEditLine = -1; - } - else - { - handled = true; - return; - } - } - for (int i = 0; i < 4; i++) - { - if (m_textInputLines[i].getDirectEditCooldown() > 0) - { - handled = true; - return; - } - } + if (isDirectEditBlocking()) { handled = true; return; } #endif ui.AnimateKeyPress(iPad, key, repeat, pressed, released); @@ -171,14 +215,98 @@ void UIScene_SignEntryMenu::handleInput(int iPad, int key, bool repeat, bool pre #ifdef __ORBIS__ case ACTION_MENU_TOUCHPAD_PRESS: #endif + sendInputToMovie(key, repeat, pressed, released); + handled = true; + break; case ACTION_MENU_UP: case ACTION_MENU_DOWN: sendInputToMovie(key, repeat, pressed, released); +#ifdef _WINDOWS64 + // Auto-start editing if focus moved to a line (e.g. UP from Confirm) + if (g_KBMInput.IsKBMActive()) + { + for (int i = eControl_Line1; i <= eControl_Line4; i++) + { + if (controlHasFocus(i)) + { + m_iActiveDirectEditLine = i; + m_textInputLines[i].beginDirectEdit(15); + m_bSkipTickNav = true; + break; + } + } + } +#endif handled = true; break; } } +#ifdef _WINDOWS64 +void UIScene_SignEntryMenu::getDirectEditInputs(vector &inputs) +{ + for (int i = 0; i < 4; i++) + inputs.push_back(&m_textInputLines[i]); +} + +void UIScene_SignEntryMenu::onDirectEditFinished(UIControl_TextInput *input, UIControl_TextInput::EDirectEditResult result) +{ + int line = -1; + for (int i = 0; i < 4; i++) + { + if (input == &m_textInputLines[i]) { line = i; break; } + } + if (line != m_iActiveDirectEditLine) return; + + if (result == UIControl_TextInput::eDirectEdit_Confirmed) + { + int newLine = line + 1; + if (newLine <= eControl_Line4) + { + SetFocusToElement(newLine); + m_iActiveDirectEditLine = newLine; + m_textInputLines[newLine].beginDirectEdit(15); + } + else + { + m_iActiveDirectEditLine = -1; + m_bConfirmed = true; + } + } + else if (result == UIControl_TextInput::eDirectEdit_Cancelled) + { + m_iActiveDirectEditLine = -1; + wstring temp = L""; + for (int j = 0; j < 4; j++) + m_sign->SetMessage(j, temp); + navigateBack(); + ui.PlayUISFX(eSFX_Back); + } +} + +bool UIScene_SignEntryMenu::handleMouseClick(F32 x, F32 y) +{ + if (m_iActiveDirectEditLine >= 0) + { + // During direct edit, only the Done button is clickable. + // Hit-test it manually — all other clicks are consumed but ignored. + m_buttonConfirm.UpdateControl(); + S32 cx = m_buttonConfirm.getXPos(); + S32 cy = m_buttonConfirm.getYPos(); + S32 cw = m_buttonConfirm.getWidth(); + S32 ch = m_buttonConfirm.getHeight(); + if (cw > 0 && ch > 0 && x >= cx && x <= cx + cw && y >= cy && y <= cy + ch) + { + m_textInputLines[m_iActiveDirectEditLine].confirmDirectEdit(); + m_iActiveDirectEditLine = -1; + m_bConfirmed = true; + } + return true; + } + return UIScene::handleMouseClick(x, y); +} +#endif + int UIScene_SignEntryMenu::KeyboardCompleteCallback(LPVOID lpParam,bool bRes) { UIScene_SignEntryMenu *pClass=(UIScene_SignEntryMenu *)lpParam; @@ -203,13 +331,7 @@ int UIScene_SignEntryMenu::KeyboardCompleteCallback(LPVOID lpParam,bool bRes) void UIScene_SignEntryMenu::handlePress(F64 controlId, F64 childId) { #ifdef _WINDOWS64 - // After direct edit ends (Enter/Escape), skip input for a few frames - // to absorb the matching ACTION_MENU_OK that would re-open the edit. - for (int i = 0; i < 4; i++) - { - if (m_textInputLines[i].isDirectEditing() || m_textInputLines[i].getDirectEditCooldown() > 0) - return; - } + if (isDirectEditBlocking()) return; #endif switch((int)controlId) { @@ -227,8 +349,12 @@ void UIScene_SignEntryMenu::handlePress(F64 controlId, F64 childId) #ifdef _WINDOWS64 if (g_KBMInput.IsKBMActive()) { - m_iActiveDirectEditLine = m_iEditingLine; - m_textInputLines[m_iEditingLine].beginDirectEdit(15); + // Only start editing from keyboard (Enter on focused line), not mouse clicks + if (!g_KBMInput.IsMouseButtonPressed(KeyboardMouseInput::MOUSE_LEFT)) + { + m_iActiveDirectEditLine = m_iEditingLine; + m_textInputLines[m_iEditingLine].beginDirectEdit(15); + } } else { diff --git a/Minecraft.Client/Common/UI/UIScene_SignEntryMenu.h b/Minecraft.Client/Common/UI/UIScene_SignEntryMenu.h index 68767be74..4e1c2a5ba 100644 --- a/Minecraft.Client/Common/UI/UIScene_SignEntryMenu.h +++ b/Minecraft.Client/Common/UI/UIScene_SignEntryMenu.h @@ -21,8 +21,11 @@ private: int m_iEditingLine; bool m_bConfirmed; bool m_bIgnoreInput; + int m_iSignCursorFrame; #ifdef _WINDOWS64 int m_iActiveDirectEditLine; + bool m_bNeedsInitialEdit; + bool m_bSkipTickNav; #endif UIControl_Button m_buttonConfirm; @@ -53,6 +56,11 @@ protected: public: // INPUT virtual void handleInput(int iPad, int key, bool repeat, bool pressed, bool released, bool &handled); +#ifdef _WINDOWS64 + virtual void getDirectEditInputs(vector &inputs); + virtual void onDirectEditFinished(UIControl_TextInput *input, UIControl_TextInput::EDirectEditResult result); + virtual bool handleMouseClick(F32 x, F32 y); +#endif protected: void handlePress(F64 controlId, F64 childId); diff --git a/Minecraft.Client/Minecraft.cpp b/Minecraft.Client/Minecraft.cpp index 38bfcdbf4..ef40fe920 100644 --- a/Minecraft.Client/Minecraft.cpp +++ b/Minecraft.Client/Minecraft.cpp @@ -1485,7 +1485,7 @@ void Minecraft::run_middle() } // Utility keys always work regardless of KBM active state - if(g_KBMInput.IsKeyPressed(KeyboardMouseInput::KEY_PAUSE) && !ui.IsTutorialVisible(i) && !ui.GetMenuDisplayed(i)) + if(g_KBMInput.IsKeyPressed(KeyboardMouseInput::KEY_PAUSE) && !ui.GetMenuDisplayed(i)) { localplayers[i]->ullButtonsPressed|=1LL< currentHeapSize ) + { + unsigned int pagesRequired = ( desiredSize + (CSF_PAGE_SIZE - 1 ) ) / CSF_PAGE_SIZE; + void *pvRet = VirtualAlloc(pvHeap, pagesRequired * CSF_PAGE_SIZE, COMMIT_ALLOCATION, PAGE_READWRITE); + if( pvRet == NULL ) + { + __debugbreak(); + } + pagesCommitted = pagesRequired; + } + header.WriteHeader( pvSaveMem ); ReleaseSaveAccess(); }