diff --git a/src/platform/ScriptLib/PythonBoot.cpp b/src/platform/ScriptLib/PythonBoot.cpp index 864fd6dd..9e6a4631 100644 --- a/src/platform/ScriptLib/PythonBoot.cpp +++ b/src/platform/ScriptLib/PythonBoot.cpp @@ -612,7 +612,16 @@ bool IsPointInsideFocusedWindow(int x, int y) { if (!g_window_manager) return false; UI::CWindow* pWin = g_window_manager->GetActivateWindow(); - return pWin && pWin->IsShow() && pWin->IsIn(x - g_window_manager->GetScreenOffsetX(), y); + if (!pWin || !pWin->IsRendering()) + return false; + // The focus can outlive the EditLine's use: UnlockWindow after an NPC dialog and DeactivateWindow + // hand it back to a chat line whose board is hidden (capture on again), and the full-screen + // GameWindow can hold it. Only a tap that picks the focused window itself (or its child) is one on it. + for (UI::CWindow* pPicked = g_window_manager->PickWindow(x - g_window_manager->GetScreenOffsetX(), y); + pPicked; pPicked = pPicked->GetParent()) + if (pPicked == pWin) + return true; + return false; } bool IsPointInsideActiveUI(int x, int y) diff --git a/src/platform/ScriptLib/PythonBoot.h b/src/platform/ScriptLib/PythonBoot.h index 90e6097b..c2059677 100644 --- a/src/platform/ScriptLib/PythonBoot.h +++ b/src/platform/ScriptLib/PythonBoot.h @@ -101,7 +101,7 @@ void SetTouchInput(bool touch); bool TouchInput(); // An EditLine has focus (40250 ui.EditLine.OnSetFocus -> ime.EnableCaptureInput). bool TextInputFocused(); -// (x, y) hits the focused window, i.e. the tap landed on the focused EditLine. +// (x, y) picks the focused window, shown with all its parents: the tap landed on the focused EditLine. bool IsPointInsideFocusedWindow(int x, int y); struct PlayerStatusInfo { diff --git a/tests/port/port_login_flow_test.cpp b/tests/port/port_login_flow_test.cpp index a0a090fb..4ab02ef8 100644 --- a/tests/port/port_login_flow_test.cpp +++ b/tests/port/port_login_flow_test.cpp @@ -683,6 +683,27 @@ int main(int argc, char** argv) CHECK(pump_until(2, [&] { return server->Has("game2:chat 0 hello"); })); // uichat.__SendTalkingChatPacket only resets the line; a Return on the empty line closes it (eventReturn). CHECK(py_true("_stream.curPhaseWindow.interface.IsOpenChat() and __import__('ime').GetText(0) == ''")); + // Touch hosts raise the system keyboard only for a tap on the focused, visible EditLine. A chat line + // that keeps the focus under a hidden board (interfacemodule.__HideWindows for an NPC dialog, then the + // focus handed back by UnlockWindow/DeactivateWindow) must not, wherever the tap lands. + { + std::string xywh; + CHECK(py("_line = _stream.curPhaseWindow.interface.wndChat.chatInputSet.chatLine")); + CHECK(PythonBoot::Evaluate("'%d %d %d %d' % (_line.GetGlobalPosition() + (_line.GetWidth(), _line.GetHeight()))", + &xywh, nullptr)); + int x = 0, y = 0, w = 0, h = 0; + std::sscanf(xywh.c_str(), "%d %d %d %d", &x, &y, &w, &h); + const int cx = x + w / 2, cy = y + h / 2; + CHECK(w > 0 && h > 0); + CHECK(PythonBoot::TextInputFocused()); + CHECK(PythonBoot::IsPointInsideFocusedWindow(cx, cy)); + CHECK(!PythonBoot::IsPointInsideFocusedWindow(790, 10)); + CHECK(py("_stream.curPhaseWindow.interface.wndChat.Hide()")); + CHECK(PythonBoot::TextInputFocused()); + CHECK(!PythonBoot::IsPointInsideFocusedWindow(cx, cy)); + CHECK(py("_stream.curPhaseWindow.interface.wndChat.Show()")); + CHECK(PythonBoot::IsPointInsideFocusedWindow(cx, cy)); + } PythonBoot::UIChar(VK_RETURN); CHECK(pump_until(1, [] { return py_true("not _stream.curPhaseWindow.interface.IsOpenChat()"); })); }