From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Samuel Attard <marshallofsound@electronjs.org>
Date: Mon, 26 Jun 2023 00:50:45 -0700
Subject: fix: select the first menu item when opened via keyboard

This fixes an accessibility issue where the root view is 'focused' to the screen reader instead of the first menu item as with all other native menus. This patch will be upstreamed.

diff --git a/ui/views/controls/menu/menu_controller.cc b/ui/views/controls/menu/menu_controller.cc
index 4b753ff618598a27af7501811758d2501777830d..10934cd2f7a2cffd67483c9e344748653ab1532c 100644
--- a/ui/views/controls/menu/menu_controller.cc
+++ b/ui/views/controls/menu/menu_controller.cc
@@ -578,6 +578,7 @@ void MenuController::Run(Widget* parent,
                          MenuAnchorPosition position,
                          bool context_menu,
                          bool is_nested_drag,
+                         ui::MenuSourceType source_type,
                          gfx::NativeView native_view_for_gestures) {
   exit_type_ = ExitType::kNone;
   possible_drag_ = false;
@@ -642,6 +643,14 @@ void MenuController::Run(Widget* parent,
   // Set the selection, which opens the initial menu.
   SetSelection(root, SELECTION_OPEN_SUBMENU | SELECTION_UPDATE_IMMEDIATELY);
 
+  if (source_type == ui::MENU_SOURCE_KEYBOARD && context_menu && root->HasSubmenu()) {
+    // For context menus opened via the keyboard we select the first item by default
+    // to match accessibility expectations
+    MenuItemView* first_item = FindInitialSelectableMenuItem(root, INCREMENT_SELECTION_DOWN);
+    if (first_item)
+      SetSelection(first_item, SELECTION_UPDATE_IMMEDIATELY);
+  }
+
   if (button_controller) {
     pressed_lock_ = button_controller->TakeLock(
         false, ui::LocatedEvent::FromIfValid(event));
@@ -2283,19 +2292,15 @@ void MenuController::OpenMenuImpl(MenuItemView* item, bool show) {
     }
     item->GetSubmenu()->ShowAt(params);
 
-    // Figure out if the mouse is under the menu; if so, remember the mouse
-    // location so we can ignore the first mouse move event(s) with that
-    // location. We do this after `ShowAt` because `ConvertFromScreen` doesn't
-    // work correctly if the widget isn't shown.
+    // Remember the mouse location so we can ignore the first mouse move
+    // event(s) with that location. We do this after `ShowAt` because
+    // `ConvertFromScreen` doesn't work correctly if the widget isn't shown.
     if (item->GetSubmenu()->GetWidget()) {
       const gfx::Point mouse_pos = ConvertFromScreen(
           *item->submenu_,
           display::Screen::GetScreen()->GetCursorScreenPoint());
-      MenuPart part_under_mouse = GetMenuPart(item->submenu_.get(), mouse_pos);
-      if (part_under_mouse.type != MenuPartType::kNone) {
-        menu_open_mouse_loc_ =
-            GetLocationInRootMenu(*item->submenu_, mouse_pos);
-      }
+      menu_open_mouse_loc_ =
+          GetLocationInRootMenu(*item->submenu_, mouse_pos);
     }
 
     item->GetSubmenu()->GetWidget()->SetNativeWindowProperty(
diff --git a/ui/views/controls/menu/menu_controller.h b/ui/views/controls/menu/menu_controller.h
index e1c59fd911f71cf6e50201b6a683207f6924ab81..cba08b4ee0c6ea6cf991af2dc9ff8943b1bcf24b 100644
--- a/ui/views/controls/menu/menu_controller.h
+++ b/ui/views/controls/menu/menu_controller.h
@@ -137,6 +137,7 @@ class VIEWS_EXPORT MenuController final : public gfx::AnimationDelegate,
            MenuAnchorPosition position,
            bool context_menu,
            bool is_nested_drag,
+           ui::MenuSourceType source_type,
            gfx::NativeView native_view_for_gestures = gfx::NativeView());
 
   bool for_drop() const { return for_drop_; }
diff --git a/ui/views/controls/menu/menu_runner.cc b/ui/views/controls/menu/menu_runner.cc
index 9f746392f6d83831a22d0ce8b2bb647a069d8692..cb640f1ae930f610c7eed18e3655ac2e1b2b19fa 100644
--- a/ui/views/controls/menu/menu_runner.cc
+++ b/ui/views/controls/menu/menu_runner.cc
@@ -89,7 +89,7 @@ void MenuRunner::RunMenuAt(
   }
 
   impl_->RunMenuAt(parent, button_controller, bounds, anchor, run_types_,
-                   native_view_for_gestures, corners,
+                   source_type, native_view_for_gestures, corners,
                    std::move(show_menu_host_duration_histogram));
 }
 
diff --git a/ui/views/controls/menu/menu_runner_impl.cc b/ui/views/controls/menu/menu_runner_impl.cc
index 0ef0f5ed80dcdbc2047d878811b45fa92a4bc7fc..cc1e079afc74169c438977f727c28e0b8a0819e5 100644
--- a/ui/views/controls/menu/menu_runner_impl.cc
+++ b/ui/views/controls/menu/menu_runner_impl.cc
@@ -115,6 +115,7 @@ void MenuRunnerImpl::RunMenuAt(
     const gfx::Rect& bounds,
     MenuAnchorPosition anchor,
     int32_t run_types,
+    ui::MenuSourceType source_type,
     gfx::NativeView native_view_for_gestures,
     std::optional<gfx::RoundedCornersF> corners,
     std::optional<std::string> show_menu_host_duration_histogram) {
@@ -189,7 +190,7 @@ void MenuRunnerImpl::RunMenuAt(
   controller->Run(parent, button_controller, menu_.get(), bounds, anchor,
                   (run_types & MenuRunner::CONTEXT_MENU) != 0,
                   (run_types & MenuRunner::NESTED_DRAG) != 0,
-                  native_view_for_gestures);
+                  source_type, native_view_for_gestures);
 }
 
 void MenuRunnerImpl::Cancel() {
diff --git a/ui/views/controls/menu/menu_runner_impl.h b/ui/views/controls/menu/menu_runner_impl.h
index c36540ede44a1ce83fc9b411a7639f9379f21977..1c3464af16aad2df09530efd889edc2e80bdc098 100644
--- a/ui/views/controls/menu/menu_runner_impl.h
+++ b/ui/views/controls/menu/menu_runner_impl.h
@@ -52,6 +52,7 @@ class VIEWS_EXPORT MenuRunnerImpl : public MenuRunnerImplInterface,
                  const gfx::Rect& bounds,
                  MenuAnchorPosition anchor,
                  int32_t run_types,
+                 ui::MenuSourceType source_type,
                  gfx::NativeView native_view_for_gestures,
                  std::optional<gfx::RoundedCornersF> corners = std::nullopt,
                  std::optional<std::string> show_menu_host_duration_histogram =
diff --git a/ui/views/controls/menu/menu_runner_impl_adapter.cc b/ui/views/controls/menu/menu_runner_impl_adapter.cc
index 35f1542e2162d08b164dfdda0ac3b4f78221f105..59175a7b1ab31af9b393a33f706168157e74d9fd 100644
--- a/ui/views/controls/menu/menu_runner_impl_adapter.cc
+++ b/ui/views/controls/menu/menu_runner_impl_adapter.cc
@@ -35,11 +35,12 @@ void MenuRunnerImplAdapter::RunMenuAt(
     const gfx::Rect& bounds,
     MenuAnchorPosition anchor,
     int32_t types,
+    ui::MenuSourceType source_type,
     gfx::NativeView native_view_for_gestures,
     std::optional<gfx::RoundedCornersF> corners,
     std::optional<std::string> show_menu_host_duration_histogram) {
   impl_->RunMenuAt(parent, button_controller, bounds, anchor, types,
-                   native_view_for_gestures);
+                   source_type, native_view_for_gestures);
 }
 
 void MenuRunnerImplAdapter::Cancel() {
diff --git a/ui/views/controls/menu/menu_runner_impl_adapter.h b/ui/views/controls/menu/menu_runner_impl_adapter.h
index 546818cef0120746366547aa2470e35def534195..5a314986b6155c7a427c5e39947a5b5c546d3477 100644
--- a/ui/views/controls/menu/menu_runner_impl_adapter.h
+++ b/ui/views/controls/menu/menu_runner_impl_adapter.h
@@ -43,6 +43,7 @@ class VIEWS_EXPORT MenuRunnerImplAdapter : public MenuRunnerImplInterface {
                  const gfx::Rect& bounds,
                  MenuAnchorPosition anchor,
                  int32_t types,
+                 ui::MenuSourceType source_type,
                  gfx::NativeView native_view_for_gestures,
                  std::optional<gfx::RoundedCornersF> corners = std::nullopt,
                  std::optional<std::string> show_menu_host_duration_histogram =
diff --git a/ui/views/controls/menu/menu_runner_impl_cocoa.h b/ui/views/controls/menu/menu_runner_impl_cocoa.h
index b0d033493973054d3fb140c63da77eda46d60dce..fde5c729a80fbd513141c7d4db0d2e306aeb2cf2 100644
--- a/ui/views/controls/menu/menu_runner_impl_cocoa.h
+++ b/ui/views/controls/menu/menu_runner_impl_cocoa.h
@@ -42,6 +42,7 @@ class VIEWS_EXPORT MenuRunnerImplCocoa : public MenuRunnerImplInterface {
       const gfx::Rect& bounds,
       MenuAnchorPosition anchor,
       int32_t run_types,
+      ui::MenuSourceType source_type,
       gfx::NativeView native_view_for_gestures,
       std::optional<gfx::RoundedCornersF> corners,
       std::optional<std::string> show_menu_host_duration_histogram) override;
diff --git a/ui/views/controls/menu/menu_runner_impl_cocoa.mm b/ui/views/controls/menu/menu_runner_impl_cocoa.mm
index c585f056973e2f8b299e7af81c384b67ad74958b..ac9f99c986dec7cb5c4eb9fc6601eef5aa7c5eee 100644
--- a/ui/views/controls/menu/menu_runner_impl_cocoa.mm
+++ b/ui/views/controls/menu/menu_runner_impl_cocoa.mm
@@ -69,6 +69,7 @@
     const gfx::Rect& bounds,
     MenuAnchorPosition anchor,
     int32_t run_types,
+    ui::MenuSourceType source_type,
     gfx::NativeView native_view_for_gestures,
     std::optional<gfx::RoundedCornersF> corners,
     std::optional<std::string> show_menu_host_duration_histogram) {
diff --git a/ui/views/controls/menu/menu_runner_impl_interface.h b/ui/views/controls/menu/menu_runner_impl_interface.h
index 972abab3bf46f815f6713b2e2e5b4db78ac4a432..b52a55f4267171ff5a907e0f76b8172b1b972271 100644
--- a/ui/views/controls/menu/menu_runner_impl_interface.h
+++ b/ui/views/controls/menu/menu_runner_impl_interface.h
@@ -46,6 +46,7 @@ class MenuRunnerImplInterface {
       const gfx::Rect& bounds,
       MenuAnchorPosition anchor,
       int32_t run_types,
+      ui::MenuSourceType source_type,
       gfx::NativeView native_view_for_gestures,
       std::optional<gfx::RoundedCornersF> corners = std::nullopt,
       std::optional<std::string> show_menu_host_duration_histogram =
diff --git a/ui/views/controls/menu/menu_runner_impl_mac.h b/ui/views/controls/menu/menu_runner_impl_mac.h
index db81eab045142c73de4fd751ece93ed8d6d653f7..2852652a7989abf417f9406eed5cbd98dd6c37f8 100644
--- a/ui/views/controls/menu/menu_runner_impl_mac.h
+++ b/ui/views/controls/menu/menu_runner_impl_mac.h
@@ -39,6 +39,7 @@ class VIEWS_EXPORT MenuRunnerImplMac : public MenuRunnerImplInterface {
       const gfx::Rect& bounds,
       MenuAnchorPosition anchor,
       int32_t run_types,
+      ui::MenuSourceType source_type,
       gfx::NativeView native_view_for_gestures,
       std::optional<gfx::RoundedCornersF> corners,
       std::optional<std::string> show_menu_host_duration_histogram) override;
diff --git a/ui/views/controls/menu/menu_runner_impl_mac.mm b/ui/views/controls/menu/menu_runner_impl_mac.mm
index 27f83d5eece36ec1230fbb2d840614b309aa7408..6e41b2dc2c9a7cb4d30d2679afaf8b51f055d46a 100644
--- a/ui/views/controls/menu/menu_runner_impl_mac.mm
+++ b/ui/views/controls/menu/menu_runner_impl_mac.mm
@@ -46,6 +46,7 @@
     const gfx::Rect& bounds,
     MenuAnchorPosition anchor,
     int32_t run_types,
+    ui::MenuSourceType source_type,
     gfx::NativeView native_view_for_gestures,
     std::optional<gfx::RoundedCornersF> corners,
     std::optional<std::string> show_menu_host_duration_histogram) {
@@ -59,8 +60,8 @@
     }
   }
   implementation_->RunMenuAt(parent, button_controller, bounds, anchor,
-                             run_types, native_view_for_gestures, corners,
-                             show_menu_host_duration_histogram);
+                             run_types, source_type, native_view_for_gestures,
+                             corners, show_menu_host_duration_histogram);
 }
 
 void MenuRunnerImplMac::Cancel() {
diff --git a/ui/views/controls/menu/menu_runner_impl_remote_cocoa.h b/ui/views/controls/menu/menu_runner_impl_remote_cocoa.h
index 7aaf6d82e09d47db1a209ae074638ccf56afc7c9..c1b0f6bb3d4b7c2f85aacccf2323c23df0b89e7d 100644
--- a/ui/views/controls/menu/menu_runner_impl_remote_cocoa.h
+++ b/ui/views/controls/menu/menu_runner_impl_remote_cocoa.h
@@ -57,6 +57,7 @@ class VIEWS_EXPORT MenuRunnerImplRemoteCocoa
       const gfx::Rect& bounds,
       MenuAnchorPosition anchor,
       int32_t run_types,
+      ui::MenuSourceType source_type,
       gfx::NativeView native_view_for_gestures,
       std::optional<gfx::RoundedCornersF> corners,
       std::optional<std::string> show_menu_host_duration_histogram) override;
diff --git a/ui/views/controls/menu/menu_runner_impl_remote_cocoa.mm b/ui/views/controls/menu/menu_runner_impl_remote_cocoa.mm
index e171461e288365f85892d429aad4895b0929a61d..6faf66a503e2f1c37322d8613b290c0ce4348439 100644
--- a/ui/views/controls/menu/menu_runner_impl_remote_cocoa.mm
+++ b/ui/views/controls/menu/menu_runner_impl_remote_cocoa.mm
@@ -69,6 +69,7 @@
     const gfx::Rect& bounds,
     MenuAnchorPosition anchor,
     int32_t run_types,
+    ui::MenuSourceType source_type,
     gfx::NativeView native_view_for_gestures,
     std::optional<gfx::RoundedCornersF> corners,
     std::optional<std::string> show_menu_host_duration_histogram) {
