When explorer.exe restarts, the system menu handles for existing top-level windows become invalidated. Navigating past the menu bar bounds triggers WM_NEXTMENU, which attempts to switch to the stale system menu and permanently traps keyboard focus in the native menu loop. This fix re-initializes the system menu on TaskbarCreated and safely falls back on WM_NEXTMENU.
https://github.com/wxWidgets/wxWidgets/pull/26799
(1 file)
—
Reply to this email directly, view it on GitHub, or unsubscribe.
Triage notifications, keep track of coding agent tasks and review pull requests on the go with GitHub Mobile for iOS and Android. Download it today!
You are receiving this because you are subscribed to this thread.![]()
@vadz commented on this pull request.
Thanks for your contribution, but this looks very mysterious and it would be nice to have some more explanations in comments or the commit message or both.
Also, could you please describe how exactly can the problem be reproduced? TIA!
> @@ -892,6 +892,47 @@ WXLRESULT wxFrame::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lPara
WXLRESULT rc = 0;
bool processed = false;
+ static const UINT s_msgTaskbarCreated = ::RegisterWindowMessage(wxT("TaskbarCreated"));
We already do this in src/msw/taskbar.cpp, we probably need to reuse the same variable for both.
> @@ -892,6 +892,47 @@ WXLRESULT wxFrame::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lPara
WXLRESULT rc = 0;
bool processed = false;
+ static const UINT s_msgTaskbarCreated = ::RegisterWindowMessage(wxT("TaskbarCreated"));
+
+ if ( s_msgTaskbarCreated && message == s_msgTaskbarCreated )
+
+ {
+ // Re-initialize system menu and refresh menu bar when explorer restarts
+ // to prevent getting a stale system menu if the user tries to navigate
+ // the menu bar with the keyboard.
+ ::GetSystemMenu(GetHwnd(), TRUE);
+ ::GetSystemMenu(GetHwnd(), FALSE);
Sorry but why do we need this? Calling the function with TRUE should be enough to recreate the menu, why do we call it with FALSE and ignore the result?
> +
+ if ( !hSysMenu || !::IsMenu(hSysMenu) )
+ {
+ HMENU hMenuBar = ::GetMenu(GetHwnd());
+ if ( hMenuBar )
+ {
+ pNextMenu->hmenuNext = hMenuBar;
+ pNextMenu->hwndNext = GetHwnd();
+ processed = true;
+ rc = 0;
+ }
+ }
+ // else: Delegate to base class for full native wrap-around
+ }
+ }
+
#if wxUSE_MENUBAR
BTW, all the code above should probably be inside this #if.
> + // the menu bar with the keyboard
@aryanchoudharypro pushed 1 commit.
—
View it on GitHub or unsubscribe.
Triage notifications, keep track of coding agent tasks and review pull requests on the go with GitHub Mobile for iOS and Android. Download it today!
You are receiving this because you are subscribed to this thread.![]()
"Thanks for the review @vadz! I have pushed an update that addresses all your feedback, adds some explanatory comments, and moves the logic inside
#if wxUSE_MENUBAR."Steps to reproduce the bug:
- Run any wxMSW app with a menu bar
- Kill
explorer.exe(e.g., via Task Manager ortaskkill /f /im explorer.exe) and restart it. we are intentionally killing explorer, just to reproduce, but its mainly for cases where explorer crashes.- Press
Altto focus the application's menu bar.- Press
Left Arrowfrom the first menu item orRight Arrowfrom the last item- Result: The application becomes permanently trapped in the native menu loop. Keyboard focus is locked until Escape is pressed, because Windows attempts to hand off focus (
WM_NEXTMENU) to the system menu, but the system menu handle was invalidated when the shell restarted.
—
Reply to this email directly, view it on GitHub, or unsubscribe.
Triage notifications, keep track of coding agent tasks and review pull requests on the go with GitHub Mobile for iOS and Android. Download it today!
You are receiving this because you are subscribed to this thread.![]()
@aryanchoudharypro commented on this pull request.
> @@ -892,6 +892,47 @@ WXLRESULT wxFrame::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lPara
WXLRESULT rc = 0;
bool processed = false;
+ static const UINT s_msgTaskbarCreated = ::RegisterWindowMessage(wxT("TaskbarCreated"));
Since gs_msgRestartTaskbar is currently static inside `#if wxUSE_TASKBARICON in taskbar.cpp, I kept this one static local here as well, knowing RegisterWindowMessage is idempotent and returns the identical system-wide ID.
—
Reply to this email directly, view it on GitHub, or unsubscribe.
Triage notifications, keep track of coding agent tasks and review pull requests on the go with GitHub Mobile for iOS and Android. Download it today!
You are receiving this because you are subscribed to this thread.![]()
> @@ -892,6 +892,47 @@ WXLRESULT wxFrame::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lPara
WXLRESULT rc = 0;
bool processed = false;
+ static const UINT s_msgTaskbarCreated = ::RegisterWindowMessage(wxT("TaskbarCreated"));
+
+ if ( s_msgTaskbarCreated && message == s_msgTaskbarCreated )
+
+ {
+ // Re-initialize system menu and refresh menu bar when explorer restarts
+ // to prevent getting a stale system menu if the user tries to navigate
+ // the menu bar with the keyboard.
+ ::GetSystemMenu(GetHwnd(), TRUE);
+ ::GetSystemMenu(GetHwnd(), FALSE);
Calling with TRUE is completely sufficient to reset the menu. thanks for catching it, fixed.
—
Reply to this email directly, view it on GitHub, or unsubscribe.
Triage notifications, keep track of coding agent tasks and review pull requests on the go with GitHub Mobile for iOS and Android. Download it today!
You are receiving this because you are subscribed to this thread.![]()
> +
+ if ( !hSysMenu || !::IsMenu(hSysMenu) )
+ {
+ HMENU hMenuBar = ::GetMenu(GetHwnd());
+ if ( hMenuBar )
+ {
+ pNextMenu->hmenuNext = hMenuBar;
+ pNextMenu->hwndNext = GetHwnd();
+ processed = true;
+ rc = 0;
+ }
+ }
+ // else: Delegate to base class for full native wrap-around
+ }
+ }
+
#if wxUSE_MENUBAR
done
—
Reply to this email directly, view it on GitHub, or unsubscribe.
Triage notifications, keep track of coding agent tasks and review pull requests on the go with GitHub Mobile for iOS and Android. Download it today!
You are receiving this because you are subscribed to this thread.![]()
@aryanchoudharypro pushed 1 commit.
—
View it on GitHub or unsubscribe.
Triage notifications, keep track of coding agent tasks and review pull requests on the go with GitHub Mobile for iOS and Android. Download it today!
You are receiving this because you are subscribed to this thread.![]()
Thanks for the update, but I couldn't reproduce the bug following the instructions: I've tried killing Explorer (from Process Explorer, but it shouldn't matter how it is killed) or just existing it (Ctrl-Shift-right click on task bar, choose "Exit") and either starting it again or not, but in any case using keyboard keys to cycle through the menus continues to work.
Am I missing something or is the bug only present in some Windows versions? Which one do you see it under?
—
Reply to this email directly, view it on GitHub, or unsubscribe.
Triage notifications, keep track of coding agent tasks and review pull requests on the go with GitHub Mobile for iOS and Android. Download it today!
You are receiving this because you are subscribed to this thread.![]()
Thanks for the update, but I couldn't reproduce the bug following the instructions: I've tried killing Explorer (from Process Explorer, but it shouldn't matter how it is killed) or just existing it (Ctrl-Shift-right click on task bar, choose "Exit") and either starting it again or not, but in any case using keyboard keys to cycle through the menus continues to work.
Am I missing something or is the bug only present in some Windows versions? Which one do you see it under?
I think this bug triggers when explorer is not properly restarted, or crashes abruptly. for example, if you do taskkill /f /im explorer.exe, I think this should trigger at which point you may need to manualy start explorer. I'm not sure though if this only happens when NVDA is on.
—
Reply to this email directly, view it on GitHub, or unsubscribe.
Triage notifications, keep track of coding agent tasks and review pull requests on the go with GitHub Mobile for iOS and Android. Download it today!
You are receiving this because you are subscribed to this thread.![]()