fix: 🐛 press m & move w/ arrows

This commit is contained in:
Istvan Matejcsok 2026-06-16 15:46:43 +02:00
commit aa9d613f50
6 changed files with 327 additions and 8 deletions

View file

@ -186,7 +186,8 @@ all: minimal_test.html \
$(S)/coroutine-pthread/nested_repro_ex.html \
$(S)/coroutine-pthread/vcall_repro.html \
$(S)/textctrl-reentry/textctrl-reentry_test.html \
$(S)/tooltip-lifetime/tooltip-lifetime_test.html
$(S)/tooltip-lifetime/tooltip-lifetime_test.html \
$(S)/warp-pointer/warp-pointer_test.html
# Main test app
minimal_test.o: minimal_test.cpp
@ -216,6 +217,15 @@ $(S)/tooltip-lifetime/tooltip-lifetime_test.html: $(S)/tooltip-lifetime/tooltip-
tooltip-lifetime: $(S)/tooltip-lifetime/tooltip-lifetime_test.html
# wxWindow::WarpPointer must update the cached mouse position (wxGetMousePosition).
$(S)/warp-pointer/warp-pointer_test.o: $(S)/warp-pointer/warp-pointer_test.cpp
$(CXX) -c $(CXXFLAGS) $< -o $@
$(S)/warp-pointer/warp-pointer_test.html: $(S)/warp-pointer/warp-pointer_test.o $(WX_CORE_LIB) $(JS_FILES)
$(CXX) $< $(LDFLAGS_NOGL) --pre-js $(JS) --shell-file $(HTML) -o $@
warp-pointer: $(S)/warp-pointer/warp-pointer_test.html
# Menu test (no GL)
$(S)/menu/menu_test.o: $(S)/menu/menu_test.cpp
$(CXX) -c $(CXXFLAGS) $< -o $@

View file

@ -0,0 +1,93 @@
// wxWindow::WarpPointer must update the cached mouse position (DOM port).
//
// Bug (src/wasm/window.cpp): wxWindowWasm::WarpPointer() is a no-op because the
// browser cannot move the OS pointer. KiCad nudges the cursor with the arrow
// keys by warping the pointer and then reading it back via wxGetMousePosition()
// (WX_VIEW_CONTROLS::SetCursorPosition -> WarpMouseCursor -> WarpPointer, then
// the interactive-move loop reads GetViewControls()->GetMousePosition()). With
// the warp a no-op the cached position never changes, so a selected item never
// follows the arrow keys and snaps to the stale cursor on grab.
//
// The invariant the bug violates: after WarpPointer(x, y), wxGetMousePosition()
// must report the screen-space equivalent of (x, y) — exactly what a real OS
// pointer warp produces on desktop.
//
// RED (bug present): wxGetMousePosition() is unchanged by the warp.
// GREEN (fixed): wxGetMousePosition() == ClientToScreen({x, y}).
#include "wx/wxprec.h"
#ifndef WX_PRECOMP
#include "wx/wx.h"
#endif
#ifdef __EMSCRIPTEN__
#include <emscripten/emscripten.h>
#endif
static void Report(const char *name, bool pass, const wxString &detail)
{
#ifdef __EMSCRIPTEN__
EM_ASM({
var msg = '[REPRO] ' + UTF8ToString($0) + ': ' + ($1 ? 'PASS' : 'FAIL')
+ ' - ' + UTF8ToString($2);
if ($1) { console.log(msg); } else { console.error(msg); }
}, name, pass ? 1 : 0, (const char *)detail.utf8_str());
#endif
}
class ReproFrame : public wxFrame
{
public:
ReproFrame();
private:
void RunTest();
};
ReproFrame::ReproFrame()
: wxFrame(nullptr, wxID_ANY, "wxWindow::WarpPointer repro")
{
CallAfter(&ReproFrame::RunTest);
}
void ReproFrame::RunTest()
{
// Two distinct targets so a stale/default cached position cannot accidentally
// match. Warp to each, then require wxGetMousePosition() to report the
// screen-space equivalent (the same conversion a real OS warp performs).
const wxPoint targets[] = { wxPoint(137, 211), wxPoint(56, 92) };
bool allPass = true;
wxString detail;
for (const wxPoint &client : targets)
{
WarpPointer(client.x, client.y);
const wxPoint expected = ClientToScreen(client);
const wxPoint actual = wxGetMousePosition();
const bool pass = (actual == expected);
allPass = allPass && pass;
detail += wxString::Format("[client=(%d,%d) expected=(%d,%d) actual=(%d,%d) %s] ",
client.x, client.y, expected.x, expected.y,
actual.x, actual.y, pass ? "ok" : "MISMATCH");
}
Report("warppointer_updates_position", allPass, detail);
}
class ReproApp : public wxApp
{
public:
bool OnInit() override
{
if (!wxApp::OnInit())
return false;
(new ReproFrame())->Show(true);
return true;
}
};
wxIMPLEMENT_APP(ReproApp);