summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ash/accelerators/accelerator_controller.cc5
-rw-r--r--ash/accelerators/accelerator_controller.h3
-rw-r--r--ash/accelerators/accelerator_controller_unittest.cc11
-rw-r--r--ash/accelerators/accelerator_filter.cc15
-rw-r--r--ash/accelerators/accelerator_filter_unittest.cc21
-rw-r--r--ash/accelerators/focus_manager_factory.cc40
-rw-r--r--ash/accelerators/focus_manager_factory.h43
-rw-r--r--ash/ash.gyp2
-rw-r--r--ash/shell.cc6
-rw-r--r--chrome/browser/ui/browser.cc23
-rw-r--r--chrome/browser/ui/views/frame/browser_view.cc52
-rw-r--r--ui/views/focus/focus_manager.cc105
-rw-r--r--ui/views/focus/focus_manager.h7
-rw-r--r--ui/views/focus/focus_manager_delegate.h40
-rw-r--r--ui/views/focus/focus_manager_factory.cc4
-rw-r--r--ui/views/focus/focus_manager_unittest.cc2
-rw-r--r--ui/views/views.gyp1
17 files changed, 284 insertions, 96 deletions
diff --git a/ash/accelerators/accelerator_controller.cc b/ash/accelerators/accelerator_controller.cc
index 8ad8a89..2762f94 100644
--- a/ash/accelerators/accelerator_controller.cc
+++ b/ash/accelerators/accelerator_controller.cc
@@ -224,6 +224,11 @@ bool AcceleratorController::Process(const ui::Accelerator& accelerator) {
return accelerator_manager_->Process(accelerator);
}
+bool AcceleratorController::IsRegistered(
+ const ui::Accelerator& accelerator) const {
+ return accelerator_manager_->GetCurrentTarget(accelerator) != NULL;
+}
+
void AcceleratorController::SetBrightnessControlDelegate(
scoped_ptr<BrightnessControlDelegate> brightness_control_delegate) {
brightness_control_delegate_.swap(brightness_control_delegate);
diff --git a/ash/accelerators/accelerator_controller.h b/ash/accelerators/accelerator_controller.h
index 45ca052..1c8193d 100644
--- a/ash/accelerators/accelerator_controller.h
+++ b/ash/accelerators/accelerator_controller.h
@@ -56,6 +56,9 @@ class ASH_EXPORT AcceleratorController : public ui::AcceleratorTarget {
// Returns true if an accelerator was activated.
bool Process(const ui::Accelerator& accelerator);
+ // Returns true if the |accelerator| is registered.
+ bool IsRegistered(const ui::Accelerator& accelerator) const;
+
// Overridden from ui::AcceleratorTarget:
virtual bool AcceleratorPressed(const ui::Accelerator& accelerator) OVERRIDE;
virtual bool CanHandleAccelerators() const OVERRIDE;
diff --git a/ash/accelerators/accelerator_controller_unittest.cc b/ash/accelerators/accelerator_controller_unittest.cc
index 80e9a4b..502aafc 100644
--- a/ash/accelerators/accelerator_controller_unittest.cc
+++ b/ash/accelerators/accelerator_controller_unittest.cc
@@ -363,6 +363,17 @@ TEST_F(AcceleratorControllerTest, Process) {
EXPECT_FALSE(GetController()->Process(accelerator_b));
}
+TEST_F(AcceleratorControllerTest, IsRegistered) {
+ const ui::Accelerator accelerator_a(ui::VKEY_A, false, false, false);
+ const ui::Accelerator accelerator_shift_a(ui::VKEY_A, true, false, false);
+ TestTarget target;
+ GetController()->Register(accelerator_a, &target);
+ EXPECT_TRUE(GetController()->IsRegistered(accelerator_a));
+ EXPECT_FALSE(GetController()->IsRegistered(accelerator_shift_a));
+ GetController()->UnregisterAll(&target);
+ EXPECT_FALSE(GetController()->IsRegistered(accelerator_a));
+}
+
#if defined(OS_WIN) || defined(USE_X11)
TEST_F(AcceleratorControllerTest, ProcessOnce) {
ui::Accelerator accelerator_a(ui::VKEY_A, false, false, false);
diff --git a/ash/accelerators/accelerator_filter.cc b/ash/accelerators/accelerator_filter.cc
index dcc95ba..bcecdfe2 100644
--- a/ash/accelerators/accelerator_filter.cc
+++ b/ash/accelerators/accelerator_filter.cc
@@ -12,9 +12,22 @@
#include "ui/base/accelerators/accelerator_manager.h"
namespace {
+
const int kModifierFlagMask = (ui::EF_SHIFT_DOWN |
ui::EF_CONTROL_DOWN |
ui::EF_ALT_DOWN);
+
+// Returns true if an Ash accelerator should be processed now.
+bool ShouldProcessAcceleratorsNow(aura::Window* target) {
+ if (!target)
+ return true;
+ if (target == ash::Shell::GetInstance()->GetRootWindow())
+ return true;
+ // Unless |target| is the root window, return false to let the custom focus
+ // manager (see ash/shell.cc) handle Ash accelerators.
+ return false;
+}
+
} // namespace
namespace ash {
@@ -39,6 +52,8 @@ bool AcceleratorFilter::PreHandleKeyEvent(aura::Window* target,
return false;
if (event->is_char())
return false;
+ if (!ShouldProcessAcceleratorsNow(target))
+ return false;
ui::Accelerator accelerator(event->key_code(),
event->flags() & kModifierFlagMask);
diff --git a/ash/accelerators/accelerator_filter_unittest.cc b/ash/accelerators/accelerator_filter_unittest.cc
index d2e9aa5..7f3e44b 100644
--- a/ash/accelerators/accelerator_filter_unittest.cc
+++ b/ash/accelerators/accelerator_filter_unittest.cc
@@ -75,7 +75,7 @@ TEST_F(AcceleratorFilterTest, TestFilterWithoutFocus) {
EXPECT_EQ(1, delegate->handle_take_screenshot_count());
}
-// Tests if AcceleratorFilter works with a focused window.
+// Tests if AcceleratorFilter works as expected with a focused window.
TEST_F(AcceleratorFilterTest, TestFilterWithFocus) {
aura::Window* default_container = Shell::GetInstance()->GetContainer(
internal::kShellWindowId_DefaultContainer);
@@ -92,11 +92,13 @@ TEST_F(AcceleratorFilterTest, TestFilterWithFocus) {
scoped_ptr<ScreenshotDelegate>(delegate).Pass());
EXPECT_EQ(0, delegate->handle_take_screenshot_count());
+ // AcceleratorFilter should ignore the key events since the root window is
+ // not focused.
aura::test::EventGenerator generator(Shell::GetRootWindow());
generator.PressKey(ui::VKEY_PRINT, 0);
- EXPECT_EQ(1, delegate->handle_take_screenshot_count());
+ EXPECT_EQ(0, delegate->handle_take_screenshot_count());
generator.ReleaseKey(ui::VKEY_PRINT, 0);
- EXPECT_EQ(1, delegate->handle_take_screenshot_count());
+ EXPECT_EQ(0, delegate->handle_take_screenshot_count());
// Reset window before |test_delegate| gets deleted.
window.reset();
@@ -104,16 +106,6 @@ TEST_F(AcceleratorFilterTest, TestFilterWithFocus) {
// Tests if AcceleratorFilter ignores the flag for Caps Lock.
TEST_F(AcceleratorFilterTest, TestCapsLockMask) {
- aura::Window* default_container = Shell::GetInstance()->GetContainer(
- internal::kShellWindowId_DefaultContainer);
- aura::test::TestWindowDelegate test_delegate;
- scoped_ptr<aura::Window> window(aura::test::CreateTestWindowWithDelegate(
- &test_delegate,
- -1,
- gfx::Rect(),
- default_container));
- wm::ActivateWindow(window.get());
-
DummyScreenshotDelegate* delegate = new DummyScreenshotDelegate;
GetController()->SetScreenshotDelegate(
scoped_ptr<ScreenshotDelegate>(delegate).Pass());
@@ -131,9 +123,6 @@ TEST_F(AcceleratorFilterTest, TestCapsLockMask) {
EXPECT_EQ(2, delegate->handle_take_screenshot_count());
generator.ReleaseKey(ui::VKEY_PRINT, ui::EF_CAPS_LOCK_DOWN);
EXPECT_EQ(2, delegate->handle_take_screenshot_count());
-
- // Reset window before |test_delegate| gets deleted.
- window.reset();
}
} // namespace test
diff --git a/ash/accelerators/focus_manager_factory.cc b/ash/accelerators/focus_manager_factory.cc
new file mode 100644
index 0000000..76dcd9f
--- /dev/null
+++ b/ash/accelerators/focus_manager_factory.cc
@@ -0,0 +1,40 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ash/accelerators/focus_manager_factory.h"
+
+#include "ash/accelerators/accelerator_controller.h"
+#include "ash/shell.h"
+#include "ui/views/focus/focus_manager.h"
+
+namespace ash {
+
+AshFocusManagerFactory::AshFocusManagerFactory() {}
+AshFocusManagerFactory::~AshFocusManagerFactory() {}
+
+views::FocusManager* AshFocusManagerFactory::CreateFocusManager(
+ views::Widget* widget) {
+ return new views::FocusManager(widget, new Delegate);
+}
+
+bool AshFocusManagerFactory::Delegate::ProcessAccelerator(
+ const ui::Accelerator& accelerator) {
+ AcceleratorController* controller =
+ Shell::GetInstance()->accelerator_controller();
+ if (controller)
+ return controller->Process(accelerator);
+ return false;
+}
+
+ui::AcceleratorTarget*
+AshFocusManagerFactory::Delegate::GetCurrentTargetForAccelerator(
+ const ui::Accelerator& accelerator) const {
+ AcceleratorController* controller =
+ Shell::GetInstance()->accelerator_controller();
+ if (controller && controller->IsRegistered(accelerator))
+ return controller;
+ return NULL;
+}
+
+} // namespace ash
diff --git a/ash/accelerators/focus_manager_factory.h b/ash/accelerators/focus_manager_factory.h
new file mode 100644
index 0000000..8469ff9
--- /dev/null
+++ b/ash/accelerators/focus_manager_factory.h
@@ -0,0 +1,43 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef ASH_ACCELERATORS_FOCUS_MANAGER_FACTORY_H_
+#define ASH_ACCELERATORS_FOCUS_MANAGER_FACTORY_H_
+#pragma once
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "ui/views/focus/focus_manager_delegate.h"
+#include "ui/views/focus/focus_manager_factory.h"
+
+namespace ash {
+
+// A factory class for creating a custom views::FocusManager object which
+// supports Ash shortcuts.
+class AshFocusManagerFactory : public views::FocusManagerFactory {
+ public:
+ AshFocusManagerFactory();
+ virtual ~AshFocusManagerFactory();
+
+ protected:
+ // views::FocusManagerFactory overrides:
+ virtual views::FocusManager* CreateFocusManager(
+ views::Widget* widget) OVERRIDE;
+
+ private:
+ class Delegate : public views::FocusManagerDelegate {
+ public:
+ // views::FocusManagerDelegate overrides:
+ virtual bool ProcessAccelerator(
+ const ui::Accelerator& accelerator) OVERRIDE;
+ virtual ui::AcceleratorTarget* GetCurrentTargetForAccelerator(
+ const ui::Accelerator& accelerator) const OVERRIDE;
+ };
+
+ DISALLOW_COPY_AND_ASSIGN(AshFocusManagerFactory);
+};
+
+} // namespace ash
+
+#endif // ASH_ACCELERATORS_FOCUS_MANAGER_FACTORY_H_
diff --git a/ash/ash.gyp b/ash/ash.gyp
index 91b3992..5768776 100644
--- a/ash/ash.gyp
+++ b/ash/ash.gyp
@@ -48,6 +48,8 @@
'accelerators/accelerator_filter.h',
'accelerators/accelerator_table.cc',
'accelerators/accelerator_table.h',
+ 'accelerators/focus_manager_factory.cc',
+ 'accelerators/focus_manager_factory.h',
'accelerators/nested_dispatcher_controller.cc',
'accelerators/nested_dispatcher_controller.h',
'ash_switches.cc',
diff --git a/ash/shell.cc b/ash/shell.cc
index 663d7e1..6d11117 100644
--- a/ash/shell.cc
+++ b/ash/shell.cc
@@ -7,6 +7,7 @@
#include <algorithm>
#include <string>
+#include "ash/accelerators/focus_manager_factory.h"
#include "ash/ash_switches.h"
#include "ash/desktop_background/desktop_background_controller.h"
#include "ash/desktop_background/desktop_background_resources.h"
@@ -77,6 +78,7 @@
#include "ui/gfx/screen.h"
#include "ui/gfx/size.h"
#include "ui/ui_controls/ui_controls.h"
+#include "ui/views/focus/focus_manager_factory.h"
#include "ui/views/widget/native_widget_aura.h"
#include "ui/views/widget/widget.h"
@@ -546,6 +548,8 @@ Shell::Shell(ShellDelegate* delegate)
}
Shell::~Shell() {
+ views::FocusManagerFactory::Install(NULL);
+
RemoveRootWindowEventFilter(key_rewriter_filter_.get());
RemoveRootWindowEventFilter(partial_screenshot_filter_.get());
RemoveRootWindowEventFilter(input_method_filter_.get());
@@ -752,6 +756,8 @@ void Shell::Init() {
window_cycle_controller_.reset(new WindowCycleController);
monitor_controller_.reset(new internal::MonitorController);
screen_dimmer_.reset(new internal::ScreenDimmer);
+
+ views::FocusManagerFactory::Install(new AshFocusManagerFactory);
}
aura::Window* Shell::GetContainer(int container_id) {
diff --git a/chrome/browser/ui/browser.cc b/chrome/browser/ui/browser.cc
index f596aa1..e348072 100644
--- a/chrome/browser/ui/browser.cc
+++ b/chrome/browser/ui/browser.cc
@@ -2622,32 +2622,25 @@ bool Browser::ExecuteCommandIfEnabled(int id) {
bool Browser::IsReservedCommandOrKey(int command_id,
const NativeWebKeyboardEvent& event) {
+ // In Apps mode, no keys are reserved.
+ if (is_app())
+ return false;
+
#if defined(OS_CHROMEOS)
// Chrome OS's top row of keys produces F1-10. Make sure that web pages
- // aren't able to block Chrome from performing the standard actions for F1-F4
- // (F5-7 are grabbed by other X clients and hence don't need this protection,
- // and F8-10 are handled separately in Chrome via a GDK event filter, but
- // let's future-proof this).
+ // aren't able to block Chrome from performing the standard actions for F1-F4.
+ // We should not handle F5-10 here since they are processed by Ash. See also:
+ // crbug.com/127333#c8
ui::KeyboardCode key_code =
static_cast<ui::KeyboardCode>(event.windowsKeyCode);
if (key_code == ui::VKEY_F1 ||
key_code == ui::VKEY_F2 ||
key_code == ui::VKEY_F3 ||
- key_code == ui::VKEY_F4 ||
- key_code == ui::VKEY_F5 ||
- key_code == ui::VKEY_F6 ||
- key_code == ui::VKEY_F7 ||
- key_code == ui::VKEY_F8 ||
- key_code == ui::VKEY_F9 ||
- key_code == ui::VKEY_F10) {
+ key_code == ui::VKEY_F4) {
return true;
}
#endif
- // In Apps mode, no keys are reserved.
- if (is_app())
- return false;
-
if (window_->IsFullscreen() && command_id == IDC_FULLSCREEN)
return true;
return command_id == IDC_CLOSE_TAB ||
diff --git a/chrome/browser/ui/views/frame/browser_view.cc b/chrome/browser/ui/views/frame/browser_view.cc
index 81ee794..934caa5 100644
--- a/chrome/browser/ui/views/frame/browser_view.cc
+++ b/chrome/browser/ui/views/frame/browser_view.cc
@@ -1145,13 +1145,18 @@ void BrowserView::ShowAppMenu() {
bool BrowserView::PreHandleKeyboardEvent(const NativeWebKeyboardEvent& event,
bool* is_keyboard_shortcut) {
- if (event.type != WebKit::WebInputEvent::RawKeyDown)
+ *is_keyboard_shortcut = false;
+
+ if ((event.type != WebKit::WebInputEvent::RawKeyDown) &&
+ (event.type != WebKit::WebInputEvent::KeyUp)) {
return false;
+ }
#if defined(OS_WIN) && !defined(USE_AURA)
// As Alt+F4 is the close-app keyboard shortcut, it needs processing
// immediately.
if (event.windowsKeyCode == ui::VKEY_F4 &&
+ event.type == WebKit::WebInputEvent::RawKeyDown &&
event.modifiers == NativeWebKeyboardEvent::AltKey) {
DefWindowProc(event.os_event.hwnd, event.os_event.message,
event.os_event.wParam, event.os_event.lParam);
@@ -1170,16 +1175,25 @@ bool BrowserView::PreHandleKeyboardEvent(const NativeWebKeyboardEvent& event,
NativeWebKeyboardEvent::ControlKey,
(event.modifiers & NativeWebKeyboardEvent::AltKey) ==
NativeWebKeyboardEvent::AltKey);
+ if (event.type == WebKit::WebInputEvent::KeyUp)
+ accelerator.set_type(ui::ET_KEY_RELEASED);
+
+ // What we have to do here is as follows:
+ // - If the |browser_| is for an app, do nothing.
+ // - If the |browser_| is not for an app, and the |accelerator| is not
+ // associated with the browser (e.g. an Ash shortcut), process it.
+ // - If the |browser_| is not for an app, and the |accelerator| is associated
+ // with the browser, and it is a reserved one (e.g. Ctrl-t), process it.
+ // - If the |browser_| is not for an app, and the |accelerator| is associated
+ // with the browser, and it is not a reserved one, do nothing.
- // We first find out the browser command associated to the |event|.
- // Then if the command is a reserved one, and should be processed
- // immediately according to the |event|, the command will be executed
- // immediately. Otherwise we just set |*is_keyboard_shortcut| properly and
- // return false.
+ if (browser_->is_app()) {
+ // We don't have to flip |is_keyboard_shortcut| here. If we do that, the app
+ // might not be able to see a subsequent Char event. See OnHandleInputEvent
+ // in content/renderer/render_widget.cc for details.
+ return false;
+ }
- // This piece of code is based on the fact that accelerators registered
- // into the |focus_manager| may only trigger a browser command execution.
- //
// Here we need to retrieve the command id (if any) associated to the
// keyboard event. Instead of looking up the command id in the
// |accelerator_table_| by ourselves, we block the command execution of
@@ -1187,21 +1201,27 @@ bool BrowserView::PreHandleKeyboardEvent(const NativeWebKeyboardEvent& event,
// |focus_manager| as if we are activating an accelerator key.
// Then we can retrieve the command id from the |browser_| object.
browser_->SetBlockCommandExecution(true);
- focus_manager->ProcessAccelerator(accelerator);
- int id = browser_->GetLastBlockedCommand(NULL);
+ // If the |accelerator| is a non-browser shortcut (e.g. Ash shortcut), the
+ // command execution cannot be blocked and true is returned. However, it is
+ // okay as long as is_app() is false. See comments in this function.
+ const bool processed = focus_manager->ProcessAccelerator(accelerator);
+ const int id = browser_->GetLastBlockedCommand(NULL);
browser_->SetBlockCommandExecution(false);
- if (id == -1)
- return false;
-
// Executing the command may cause |this| object to be destroyed.
if (browser_->IsReservedCommandOrKey(id, event)) {
UpdateAcceleratorMetrics(accelerator, id);
return browser_->ExecuteCommandIfEnabled(id);
}
- DCHECK(is_keyboard_shortcut != NULL);
- *is_keyboard_shortcut = true;
+ if (id != -1) {
+ // |accelerator| is a non-reserved browser shortcut (e.g. Ctrl+t).
+ if (event.type == WebKit::WebInputEvent::RawKeyDown)
+ *is_keyboard_shortcut = true;
+ } else if (processed) {
+ // |accelerator| is a non-browser shortcut (e.g. F5-F10 on Ash).
+ return true;
+ }
return false;
}
diff --git a/ui/views/focus/focus_manager.cc b/ui/views/focus/focus_manager.cc
index 1467f25..1799831 100644
--- a/ui/views/focus/focus_manager.cc
+++ b/ui/views/focus/focus_manager.cc
@@ -11,6 +11,7 @@
#include "build/build_config.h"
#include "ui/base/accelerators/accelerator.h"
#include "ui/base/keycodes/keyboard_codes.h"
+#include "ui/views/focus/focus_manager_delegate.h"
#include "ui/views/focus/focus_search.h"
#include "ui/views/focus/view_storage.h"
#include "ui/views/focus/widget_focus_manager.h"
@@ -20,8 +21,9 @@
namespace views {
-FocusManager::FocusManager(Widget* widget)
+FocusManager::FocusManager(Widget* widget, FocusManagerDelegate* delegate)
: widget_(widget),
+ delegate_(delegate),
focused_view_(NULL),
accelerator_manager_(new ui::AcceleratorManager),
focus_change_reason_(kReasonDirectFocusChange),
@@ -54,22 +56,23 @@ bool FocusManager::OnKeyEvent(const KeyEvent& event) {
if (event.type() == ui::ET_KEY_PRESSED) {
// VKEY_MENU is triggered by key release event.
// FocusManager::OnKeyEvent() returns false when the key has been consumed.
- if (key_code == ui::VKEY_MENU) {
+ if ((key_code == ui::VKEY_MENU) &&
+ (event.flags() & ~ui::EF_ALT_DOWN) == 0) {
should_handle_menu_key_release_ = true;
return false;
}
- // Pass through to the reset of OnKeyEvent.
+ // Pass through to the rest of OnKeyEvent.
} else if (key_code == ui::VKEY_MENU && should_handle_menu_key_release_ &&
(event.flags() & ~ui::EF_ALT_DOWN) == 0) {
// Trigger VKEY_MENU when only this key is pressed and released, and both
// press and release events are not handled by others.
ui::Accelerator accelerator(ui::VKEY_MENU, false, false, false);
return ProcessAccelerator(accelerator);
- } else {
+ } else if (event.type() != ui::ET_KEY_RELEASED) {
return false;
}
#else
- if (event.type() != ui::ET_KEY_PRESSED)
+ if (event.type() != ui::ET_KEY_PRESSED && event.type() != ui::ET_KEY_RELEASED)
return false;
#endif
@@ -77,53 +80,57 @@ bool FocusManager::OnKeyEvent(const KeyEvent& event) {
event.IsShiftDown(),
event.IsControlDown(),
event.IsAltDown());
+ accelerator.set_type(event.type());
+ if (event.type() == ui::ET_KEY_PRESSED) {
#if defined(OS_WIN)
- // If the focused view wants to process the key event as is, let it be.
- // This is not used for linux/aura.
- if (focused_view_ && focused_view_->SkipDefaultKeyEventProcessing(event) &&
- !accelerator_manager_->HasPriorityHandler(accelerator))
- return true;
+ // If the focused view wants to process the key event as is, let it be.
+ // This is not used for linux/aura.
+ if (focused_view_ && focused_view_->SkipDefaultKeyEventProcessing(event) &&
+ !accelerator_manager_->HasPriorityHandler(accelerator))
+ return true;
#endif
- // Intercept Tab related messages for focus traversal.
- // Note that we don't do focus traversal if the root window is not part of the
- // active window hierarchy as this would mean we have no focused view and
- // would focus the first focusable view.
+ // Intercept Tab related messages for focus traversal.
+ // Note that we don't do focus traversal if the root window is not part of
+ // the active window hierarchy as this would mean we have no focused view
+ // and would focus the first focusable view.
#if defined(OS_WIN) && !defined(USE_AURA)
- HWND top_window = widget_->GetNativeView();
- HWND active_window = ::GetActiveWindow();
- if ((active_window == top_window || ::IsChild(active_window, top_window)) &&
- IsTabTraversalKeyEvent(event)) {
- AdvanceFocus(event.IsShiftDown());
- return false;
- }
+ HWND top_window = widget_->GetNativeView();
+ HWND active_window = ::GetActiveWindow();
+ if ((active_window == top_window || ::IsChild(active_window, top_window)) &&
+ IsTabTraversalKeyEvent(event)) {
+ AdvanceFocus(event.IsShiftDown());
+ return false;
+ }
#else
- if (IsTabTraversalKeyEvent(event)) {
- AdvanceFocus(event.IsShiftDown());
- return false;
- }
+ if (IsTabTraversalKeyEvent(event)) {
+ AdvanceFocus(event.IsShiftDown());
+ return false;
+ }
#endif
- // Intercept arrow key messages to switch between grouped views.
- if (focused_view_ && focused_view_->GetGroup() != -1 &&
- (key_code == ui::VKEY_UP || key_code == ui::VKEY_DOWN ||
- key_code == ui::VKEY_LEFT || key_code == ui::VKEY_RIGHT)) {
- bool next = (key_code == ui::VKEY_RIGHT || key_code == ui::VKEY_DOWN);
- View::Views views;
- focused_view_->parent()->GetViewsInGroup(focused_view_->GetGroup(), &views);
- View::Views::const_iterator i(
- std::find(views.begin(), views.end(), focused_view_));
- DCHECK(i != views.end());
- int index = static_cast<int>(i - views.begin());
- index += next ? 1 : -1;
- if (index < 0) {
- index = static_cast<int>(views.size()) - 1;
- } else if (index >= static_cast<int>(views.size())) {
- index = 0;
+ // Intercept arrow key messages to switch between grouped views.
+ if (focused_view_ && focused_view_->GetGroup() != -1 &&
+ (key_code == ui::VKEY_UP || key_code == ui::VKEY_DOWN ||
+ key_code == ui::VKEY_LEFT || key_code == ui::VKEY_RIGHT)) {
+ bool next = (key_code == ui::VKEY_RIGHT || key_code == ui::VKEY_DOWN);
+ View::Views views;
+ focused_view_->parent()->GetViewsInGroup(focused_view_->GetGroup(),
+ &views);
+ View::Views::const_iterator i(
+ std::find(views.begin(), views.end(), focused_view_));
+ DCHECK(i != views.end());
+ int index = static_cast<int>(i - views.begin());
+ index += next ? 1 : -1;
+ if (index < 0) {
+ index = static_cast<int>(views.size()) - 1;
+ } else if (index >= static_cast<int>(views.size())) {
+ index = 0;
+ }
+ SetFocusedViewWithReason(views[index], kReasonFocusTraversal);
+ return false;
}
- SetFocusedViewWithReason(views[index], kReasonFocusTraversal);
- return false;
}
// Process keyboard accelerators.
@@ -420,7 +427,11 @@ void FocusManager::UnregisterAccelerators(ui::AcceleratorTarget* target) {
}
bool FocusManager::ProcessAccelerator(const ui::Accelerator& accelerator) {
- return accelerator_manager_->Process(accelerator);
+ if (accelerator_manager_->Process(accelerator))
+ return true;
+ if (delegate_.get())
+ return delegate_->ProcessAccelerator(accelerator);
+ return false;
}
void FocusManager::MaybeResetMenuKeyState(const KeyEvent& key) {
@@ -436,7 +447,11 @@ void FocusManager::MaybeResetMenuKeyState(const KeyEvent& key) {
ui::AcceleratorTarget* FocusManager::GetCurrentTargetForAccelerator(
const ui::Accelerator& accelerator) const {
- return accelerator_manager_->GetCurrentTarget(accelerator);
+ ui::AcceleratorTarget* target =
+ accelerator_manager_->GetCurrentTarget(accelerator);
+ if (!target && delegate_.get())
+ target = delegate_->GetCurrentTargetForAccelerator(accelerator);
+ return target;
}
bool FocusManager::HasPriorityHandler(
diff --git a/ui/views/focus/focus_manager.h b/ui/views/focus/focus_manager.h
index d8c60a6..cf6cb86 100644
--- a/ui/views/focus/focus_manager.h
+++ b/ui/views/focus/focus_manager.h
@@ -80,6 +80,7 @@ class AcceleratorManager;
namespace views {
+class FocusManagerDelegate;
class FocusSearch;
class RootView;
class View;
@@ -136,7 +137,7 @@ class VIEWS_EXPORT FocusManager {
kReasonDirectFocusChange
};
- explicit FocusManager(Widget* widget);
+ FocusManager(Widget* widget, FocusManagerDelegate* delegate);
virtual ~FocusManager();
// Processes the passed key event for accelerators and tab traversal.
@@ -270,6 +271,10 @@ class VIEWS_EXPORT FocusManager {
// The top-level Widget this FocusManager is associated with.
Widget* widget_;
+ // The object which handles an accelerator when |accelerator_manager_| doesn't
+ // handle it.
+ scoped_ptr<FocusManagerDelegate> delegate_;
+
// The view that currently is focused.
View* focused_view_;
diff --git a/ui/views/focus/focus_manager_delegate.h b/ui/views/focus/focus_manager_delegate.h
new file mode 100644
index 0000000..1763ed2
--- /dev/null
+++ b/ui/views/focus/focus_manager_delegate.h
@@ -0,0 +1,40 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_VIEWS_FOCUS_FOCUS_MANAGER_DELEGATE_H_
+#define UI_VIEWS_FOCUS_FOCUS_MANAGER_DELEGATE_H_
+#pragma once
+
+#include "ui/views/views_export.h"
+
+namespace ui {
+class Accelerator;
+class AcceleratorTarget;
+}
+
+namespace views {
+
+// Delegate interface for views::FocusManager.
+class VIEWS_EXPORT FocusManagerDelegate {
+ public:
+ virtual ~FocusManagerDelegate() {}
+
+ // Activate the target associated with the specified accelerator.
+ // First, AcceleratorPressed handler of the most recently registered target
+ // is called, and if that handler processes the event (i.e. returns true),
+ // this method immediately returns. If not, we do the same thing on the next
+ // target, and so on.
+ // Returns true if an accelerator was activated.
+ virtual bool ProcessAccelerator(const ui::Accelerator& accelerator) = 0;
+
+ // Returns the AcceleratorTarget that should be activated for the specified
+ // keyboard accelerator, or NULL if no view is registered for that keyboard
+ // accelerator.
+ virtual ui::AcceleratorTarget* GetCurrentTargetForAccelerator(
+ const ui::Accelerator& accelerator) const = 0;
+};
+
+} // namespace views
+
+#endif // UI_VIEWS_FOCUS_FOCUS_MANAGER_DELEGATE_H_
diff --git a/ui/views/focus/focus_manager_factory.cc b/ui/views/focus/focus_manager_factory.cc
index e3ec805..b8e1a7a 100644
--- a/ui/views/focus/focus_manager_factory.cc
+++ b/ui/views/focus/focus_manager_factory.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -18,7 +18,7 @@ class DefaultFocusManagerFactory : public views::FocusManagerFactory {
protected:
virtual FocusManager* CreateFocusManager(views::Widget* widget) OVERRIDE {
- return new FocusManager(widget);
+ return new FocusManager(widget, NULL /* delegate */);
}
private:
diff --git a/ui/views/focus/focus_manager_unittest.cc b/ui/views/focus/focus_manager_unittest.cc
index 01a33ab..06b8448 100644
--- a/ui/views/focus/focus_manager_unittest.cc
+++ b/ui/views/focus/focus_manager_unittest.cc
@@ -502,7 +502,7 @@ class FocusManagerDtorTest : public FocusManagerTest {
class FocusManagerDtorTracked : public FocusManager {
public:
FocusManagerDtorTracked(Widget* widget, DtorTrackVector* dtor_tracker)
- : FocusManager(widget),
+ : FocusManager(widget, NULL /* delegate */),
dtor_tracker_(dtor_tracker) {
}
diff --git a/ui/views/views.gyp b/ui/views/views.gyp
index 47c1099..7d52dec 100644
--- a/ui/views/views.gyp
+++ b/ui/views/views.gyp
@@ -249,6 +249,7 @@
'focus/external_focus_tracker.h',
'focus/focus_manager.cc',
'focus/focus_manager.h',
+ 'focus/focus_manager_delegate.h',
'focus/focus_manager_factory.cc',
'focus/focus_manager_factory.h',
'focus/focus_search.cc',