1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "ui/views/controls/menu/menu_key_event_handler.h"
7 #include "ui/aura/env.h"
8 #include "ui/events/keycodes/keyboard_code_conversion.h"
9 #include "ui/views/controls/menu/menu_controller.h"
10 #include "ui/views/views_delegate.h"
16 const int kKeyFlagsMask
= ui::EF_CONTROL_DOWN
| ui::EF_ALT_DOWN
;
20 MenuKeyEventHandler::MenuKeyEventHandler() {
21 aura::Env::GetInstanceDontCreate()->PrependPreTargetHandler(this);
24 MenuKeyEventHandler::~MenuKeyEventHandler() {
25 aura::Env::GetInstanceDontCreate()->RemovePreTargetHandler(this);
28 void MenuKeyEventHandler::OnKeyEvent(ui::KeyEvent
* event
) {
29 MenuController
* menu_controller
= MenuController::GetActiveInstance();
30 DCHECK(menu_controller
);
32 if (menu_controller
->exit_type() == MenuController::EXIT_ALL
||
33 menu_controller
->exit_type() == MenuController::EXIT_DESTROYED
) {
34 // If the event has arrived after the menu's exit type had changed but
35 // before its message loop terminated, the event will continue its normal
36 // propagation for the following reason:
37 // If the user accepts a menu item in a nested menu, the menu item action is
38 // run after the base::RunLoop for the innermost menu has quit but before
39 // the base::RunLoop for the outermost menu has quit. If the menu item
40 // action starts a base::RunLoop, the outermost menu's base::RunLoop will
41 // not quit till the action's base::RunLoop ends. IDC_BOOKMARK_BAR_OPEN_ALL
42 // sometimes opens a modal dialog. The modal dialog starts a base::RunLoop
43 // and keeps the base::RunLoop running for the duration of its lifetime.
44 menu_controller
->TerminateNestedMessageLoop();
48 if (event
->type() == ui::ET_KEY_PRESSED
) {
49 menu_controller
->OnKeyDown(event
->key_code());
51 // Do not check mnemonics if the Alt or Ctrl modifiers are pressed. For
52 // example Ctrl+<T> is an accelerator, but <T> only is a mnemonic.
53 const int flags
= event
->flags();
54 if (menu_controller
->exit_type() == MenuController::EXIT_NONE
&&
55 (flags
& kKeyFlagsMask
) == 0) {
56 char c
= ui::DomCodeToUsLayoutCharacter(event
->code(), flags
);
57 menu_controller
->SelectByChar(c
);
61 if (menu_controller
->exit_type() != MenuController::EXIT_NONE
) {
62 menu_controller
->TerminateNestedMessageLoop();
64 ui::Accelerator
accelerator(*event
);
65 ViewsDelegate::ProcessMenuAcceleratorResult result
=
66 ViewsDelegate::GetInstance()->ProcessAcceleratorWhileMenuShowing(
68 if (result
== ViewsDelegate::ProcessMenuAcceleratorResult::CLOSE_MENU
)
69 menu_controller
->CancelAll();
72 event
->StopPropagation();