Fix incorrect ordering of mouse click and escape key events

When pressing escape soon after left clicking (within ~60ms), KiCad
was processing the escape key before the mouse button release event
due to wxWidgets event queue ordering. This caused operations to be
canceled instead of completed.

The fix adds flushPendingClicks() which checks button state via polling
when an escape key event arrives. If a button was logically pressed but
has been physically released, the click event is generated before the
escape event is processed, maintaining proper ordering.

Fixes https://gitlab.com/kicad/code/kicad/-/issues/20527
This commit is contained in:
Seth Hillbrand
2026-01-26 20:14:02 -08:00
parent 0b116673ab
commit b9327dbe7e
2 changed files with 33 additions and 0 deletions
+28
View File
@@ -474,6 +474,28 @@ std::optional<TOOL_EVENT> TOOL_DISPATCHER::GetToolEvent( wxKeyEvent* aKeyEvent,
}
void TOOL_DISPATCHER::flushPendingClicks()
{
// When an escape key event arrives, keyboard events can be processed before mouse button
// events due to wxWidgets event queue ordering. If a mouse button was pressed and has since
// been released (detected via polling), we need to process that click before handling the
// escape to maintain proper event ordering.
for( BUTTON_STATE* st : m_buttons )
{
if( st->pressed && !st->GetState() )
{
st->pressed = false;
TOOL_EVENT clickEvt( TC_MOUSE, TA_MOUSE_CLICK, st->button );
clickEvt.SetMousePosition( st->downPosition );
m_toolMgr->ProcessEvent( clickEvt );
st->dragging = false;
}
}
}
void TOOL_DISPATCHER::DispatchWxEvent( wxEvent& aEvent )
{
bool motion = false;
@@ -592,6 +614,12 @@ void TOOL_DISPATCHER::DispatchWxEvent( wxEvent& aEvent )
keyIsEscape = ( ke->GetKeyCode() == WXK_ESCAPE );
// When escape is pressed shortly after a mouse click, the keyboard event can be
// processed before the mouse button release event. Flush any pending clicks first
// to ensure proper event ordering.
if( keyIsEscape )
flushPendingClicks();
if( KIUI::IsInputControlFocused( focus ) )
{
bool enabled = KIUI::IsInputControlEditable( focus );
+5
View File
@@ -81,6 +81,11 @@ private:
/// Handles mouse related events (click, motion, dragging).
bool handleMouseButton( wxEvent& aEvent, int aIndex, bool aMotion );
/// Processes any pending mouse clicks that have been physically completed but not yet
/// dispatched. This ensures clicks are processed before cancel events when both happen
/// in quick succession.
void flushPendingClicks();
/// Returns the instance of VIEW, used by the application.
KIGFX::VIEW* getView();