@@ -877,11 +877,46 @@ bool Menu::Open(const PositioningStrategy& strategy, Placement placement) {
877877 // - WM_INITMENUPOPUP is sent when the menu opens (triggers MenuOpenedEvent)
878878 // - WM_UNINITMENUPOPUP is sent when the menu closes (triggers
879879 // MenuClosedEvent)
880+ // TPM_RETURNCMD: return the chosen item's id instead of posting WM_COMMAND.
881+ // A posted WM_COMMAND is dispatched after Open() has returned, from the
882+ // host's message loop, where no caller is on the stack; bindings whose
883+ // listeners must run synchronously inside a call (Dart's
884+ // NativeCallable.isolateLocal) then abort with "Cannot invoke native
885+ // callback outside an isolate". Emitting the click here, before Open()
886+ // returns, keeps every menu event inside the Open() call.
880887 pimpl_->opening_ = true ;
881- const BOOL result = TrackPopupMenu (pimpl_->hmenu_ , uFlags, pt.x , pt.y , 0 , host_window, nullptr );
888+ SetLastError (ERROR_SUCCESS );
889+ const UINT cmd = static_cast <UINT >(TrackPopupMenu (
890+ pimpl_->hmenu_ , uFlags | TPM_RETURNCMD , pt.x , pt.y , 0 , host_window, nullptr ));
891+ // With TPM_RETURNCMD, 0 means "dismissed" or "failed"; only the error code
892+ // tells them apart.
893+ const bool failed = cmd == 0 && GetLastError () != ERROR_SUCCESS ;
882894 pimpl_->opening_ = false ;
895+ if (failed) {
896+ return false ;
897+ }
883898
884- return result != FALSE ;
899+ if (cmd != 0 ) {
900+ // Find the item (searching submenus) and fire its click.
901+ std::function<bool (const Menu&)> dispatch = [&](const Menu& menu) -> bool {
902+ for (const auto & item : menu.pimpl_ ->items_ ) {
903+ if (item->GetId () == cmd) {
904+ if (item->pimpl_ ->clicked_callback_ ) {
905+ item->pimpl_ ->clicked_callback_ (item->pimpl_ ->id_ );
906+ }
907+ return true ;
908+ }
909+ if (auto submenu = item->GetSubmenu (); submenu && dispatch (*submenu)) {
910+ return true ;
911+ }
912+ }
913+ return false ;
914+ };
915+ dispatch (*this );
916+ }
917+
918+ // Shown (and possibly dismissed without a pick): success, as before.
919+ return true ;
885920}
886921
887922bool Menu::Close () {
0 commit comments