Merge branch 'pr/keyboard-fixes' into split-screen

This commit is contained in:
MrTheShy 2026-03-06 17:31:39 +01:00
commit ae9afafc69
19 changed files with 429 additions and 182 deletions

View file

@ -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);
}
}

View file

@ -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<UIControl *> *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;
}
}
}

View file

@ -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;

View file

@ -447,6 +447,19 @@ void UIScene::tick()
IggyPlayerTickRS( swf );
m_hasTickedOnce = true;
}
#ifdef _WINDOWS64
{
vector<UIControl_TextInput*> 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<UIControl_TextInput*> 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<UIControl_TextInput*> 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<UIControl *> *controls = GetControls();
if (!controls) return false;

View file

@ -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<UIControl_TextInput*> &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);

View file

@ -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<UIControl_TextInput*> &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())

View file

@ -55,6 +55,10 @@ protected:
virtual UIControl *getSection(ESceneSection eSection);
#ifdef _WINDOWS64
virtual void getDirectEditInputs(vector<UIControl_TextInput*> &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);

View file

@ -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<UIControl_TextInput*> &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

View file

@ -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<UIControl_TextInput*> &inputs);
virtual void onDirectEditFinished(UIControl_TextInput *input, UIControl_TextInput::EDirectEditResult result);
#endif
private:
void StartSharedLaunchFlow();

View file

@ -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<UIControl_TextInput*> &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<int>(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<int>(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

View file

@ -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<UIControl_TextInput*> &inputs);
virtual void onDirectEditFinished(UIControl_TextInput *input, UIControl_TextInput::EDirectEditResult result);
virtual bool handleMouseClick(F32 x, F32 y);
#endif

View file

@ -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<UIControl_TextInput*> &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<double>(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<double>(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<double>(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

View file

@ -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<UIControl_TextInput*> &inputs);
virtual void onDirectEditFinished(UIControl_TextInput *input, UIControl_TextInput::EDirectEditResult result);
virtual bool handleMouseClick(F32 x, F32 y);
#endif

View file

@ -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<UIControl_TextInput*> &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)

View file

@ -140,6 +140,10 @@ protected:
public:
virtual void tick();
virtual void handleDestroy();
#ifdef _WINDOWS64
virtual void getDirectEditInputs(vector<UIControl_TextInput*> &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);

View file

@ -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<UIControl_TextInput*> &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
{

View file

@ -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<UIControl_TextInput*> &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);

View file

@ -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<<MINECRAFT_ACTION_PAUSEMENU;
app.DebugPrintf("PAUSE PRESSED (keyboard) - ipad = %d\n",i);

View file

@ -463,6 +463,23 @@ BOOL ConsoleSaveFileOriginal::closeHandle( FileEntry *file )
void ConsoleSaveFileOriginal::finalizeWrite()
{
LockSaveAccess();
// Ensure buffer is large enough for the full file including header table.
// New file entries (e.g. from RegionFile creation) increase GetFileSize()
// without triggering MoveDataBeyond, so the committed pages may be short.
DWORD currentHeapSize = pagesCommitted * CSF_PAGE_SIZE;
DWORD desiredSize = header.GetFileSize();
if( desiredSize > 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();
}