summaryrefslogtreecommitdiffstats
path: root/views/controls/menu/native_menu_win.cc
diff options
context:
space:
mode:
Diffstat (limited to 'views/controls/menu/native_menu_win.cc')
-rw-r--r--views/controls/menu/native_menu_win.cc94
1 files changed, 93 insertions, 1 deletions
diff --git a/views/controls/menu/native_menu_win.cc b/views/controls/menu/native_menu_win.cc
index 3470e27..0881ab5 100644
--- a/views/controls/menu/native_menu_win.cc
+++ b/views/controls/menu/native_menu_win.cc
@@ -306,7 +306,8 @@ NativeMenuWin::NativeMenuWin(menus::MenuModel* model, HWND system_menu_for)
owner_draw_(l10n_util::NeedOverrideDefaultUIFont(NULL, NULL) &&
!system_menu_for),
system_menu_for_(system_menu_for),
- first_item_index_(0) {
+ first_item_index_(0),
+ menu_action_(MENU_ACTION_NONE) {
}
NativeMenuWin::~NativeMenuWin() {
@@ -322,10 +323,28 @@ void NativeMenuWin::RunMenuAt(const gfx::Point& point, int alignment) {
UpdateStates();
UINT flags = TPM_LEFTBUTTON | TPM_RECURSE;
flags |= GetAlignmentFlags(alignment);
+ menu_action_ = MENU_ACTION_NONE;
+
+ // Set a hook function so we can listen for keyboard events while the
+ // menu is open, and store a pointer to this object in a static
+ // variable so the hook has access to it (ugly, but it's the
+ // only way).
+ open_native_menu_win_ = this;
+ HHOOK hhook = SetWindowsHookEx(WH_MSGFILTER, MenuMessageHook,
+ GetModuleHandle(NULL), ::GetCurrentThreadId());
+
+ // Mark that any registered listeners have not been called for this particular
+ // opening of the menu.
+ listeners_called_ = false;
+
// Command dispatch is done through WM_MENUCOMMAND, handled by the host
// window.
+ HWND hwnd = host_window_->hwnd();
TrackPopupMenuEx(menu_, flags, point.x(), point.y(), host_window_->hwnd(),
NULL);
+
+ UnhookWindowsHookEx(hhook);
+ open_native_menu_win_ = NULL;
}
void NativeMenuWin::CancelMenu() {
@@ -370,9 +389,82 @@ gfx::NativeMenu NativeMenuWin::GetNativeMenu() const {
return menu_;
}
+NativeMenuWin::MenuAction NativeMenuWin::GetMenuAction() const {
+ return menu_action_;
+}
+
+void NativeMenuWin::AddMenuListener(MenuListener* listener) {
+ listeners_.push_back(listener);
+}
+
+void NativeMenuWin::RemoveMenuListener(MenuListener* listener) {
+ for (std::vector<MenuListener*>::iterator iter = listeners_.begin();
+ iter != listeners_.end();
+ ++iter) {
+ if (*iter == listener) {
+ listeners_.erase(iter);
+ return;
+ }
+ }
+}
+
////////////////////////////////////////////////////////////////////////////////
// NativeMenuWin, private:
+// static
+NativeMenuWin* NativeMenuWin::open_native_menu_win_ = NULL;
+
+// static
+bool NativeMenuWin::GetHighlightedMenuItemInfo(
+ HMENU menu, bool* has_parent, bool* has_submenu) {
+ for (int i = 0; i < ::GetMenuItemCount(menu); i++) {
+ UINT state = ::GetMenuState(menu, i, MF_BYPOSITION);
+ if (state & MF_HILITE) {
+ if (state & MF_POPUP) {
+ HMENU submenu = GetSubMenu(menu, i);
+ if (GetHighlightedMenuItemInfo(submenu, has_parent, has_submenu))
+ *has_parent = true;
+ else
+ *has_submenu = true;
+ }
+ return true;
+ }
+ }
+ return false;
+}
+
+// static
+LRESULT CALLBACK NativeMenuWin::MenuMessageHook(
+ int n_code, WPARAM w_param, LPARAM l_param) {
+ LRESULT result = CallNextHookEx(NULL, n_code, w_param, l_param);
+
+ NativeMenuWin* this_ptr = open_native_menu_win_;
+ // The first time this hook is called, that means the menu has successfully
+ // opened, so call the callback function on all of our listeners.
+ if (!this_ptr->listeners_called_) {
+ for (unsigned int i = 0; i < this_ptr->listeners_.size(); ++i) {
+ this_ptr->listeners_[i]->OnMenuOpened();
+ }
+ this_ptr->listeners_called_ = true;
+ }
+
+ MSG* msg = reinterpret_cast<MSG*>(l_param);
+ if (msg->message == WM_KEYDOWN) {
+ bool has_parent = false;
+ bool has_submenu = false;
+ GetHighlightedMenuItemInfo(this_ptr->menu_, &has_parent, &has_submenu);
+ if (msg->wParam == VK_LEFT && !has_parent) {
+ this_ptr->menu_action_ = MENU_ACTION_PREVIOUS;
+ ::EndMenu();
+ } else if (msg->wParam == VK_RIGHT && !has_parent && !has_submenu) {
+ this_ptr->menu_action_ = MENU_ACTION_NEXT;
+ ::EndMenu();
+ }
+ }
+
+ return result;
+}
+
bool NativeMenuWin::IsSeparatorItemAt(int menu_index) const {
MENUITEMINFO mii = {0};
mii.cbSize = sizeof(mii);