1 // Copyright (c) 2012 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/focus/focus_manager.h"
7 #include "base/memory/scoped_ptr.h"
8 #include "base/run_loop.h"
9 #include "base/strings/utf_string_conversions.h"
10 #include "ui/events/event.h"
11 #include "ui/views/controls/button/label_button.h"
12 #include "ui/views/focus/focus_manager_test.h"
13 #include "ui/views/widget/widget.h"
19 class MessageTrackingView : public View {
21 MessageTrackingView() : accelerator_pressed_(false) {
25 accelerator_pressed_ = false;
26 keys_pressed_.clear();
27 keys_released_.clear();
30 const std::vector<ui::KeyboardCode>& keys_pressed() const {
34 const std::vector<ui::KeyboardCode>& keys_released() const {
35 return keys_released_;
38 bool accelerator_pressed() const {
39 return accelerator_pressed_;
42 // Overridden from View:
43 virtual bool OnKeyPressed(const ui::KeyEvent& e) OVERRIDE {
44 keys_pressed_.push_back(e.key_code());
47 virtual bool OnKeyReleased(const ui::KeyEvent& e) OVERRIDE {
48 keys_released_.push_back(e.key_code());
51 virtual bool AcceleratorPressed(const ui::Accelerator& accelerator) OVERRIDE {
52 accelerator_pressed_ = true;
57 bool accelerator_pressed_;
58 std::vector<ui::KeyboardCode> keys_pressed_;
59 std::vector<ui::KeyboardCode> keys_released_;
61 DISALLOW_COPY_AND_ASSIGN(MessageTrackingView);
66 // Test that when activating/deactivating the top window, the focus is stored/
68 TEST_F(FocusManagerTest, FocusStoreRestore) {
69 // Simulate an activate, otherwise the deactivate isn't going to do anything.
70 SimulateActivateWindow();
72 LabelButton* button = new LabelButton(NULL, base::ASCIIToUTF16("Press me"));
73 button->SetStyle(Button::STYLE_BUTTON);
74 View* view = new View();
75 view->SetFocusable(true);
77 GetContentsView()->AddChildView(button);
78 button->SetBounds(10, 10, 200, 30);
79 GetContentsView()->AddChildView(view);
82 TestFocusChangeListener listener;
83 AddFocusChangeListener(&listener);
88 // Required for VS2010: http://connect.microsoft.com/VisualStudio/feedback/details/520043/error-converting-from-null-to-a-pointer-type-in-std-pair
89 views::View* null_view = NULL;
91 // Deacivate the window, it should store its focus.
92 SimulateDeactivateWindow();
93 EXPECT_EQ(NULL, GetFocusManager()->GetFocusedView());
94 ASSERT_EQ(2, static_cast<int>(listener.focus_changes().size()));
95 EXPECT_TRUE(listener.focus_changes()[0] == ViewPair(null_view, view));
96 EXPECT_TRUE(listener.focus_changes()[1] == ViewPair(view, null_view));
97 listener.ClearFocusChanges();
99 // Reactivate, focus should come-back to the previously focused view.
100 SimulateActivateWindow();
101 EXPECT_EQ(view, GetFocusManager()->GetFocusedView());
102 ASSERT_EQ(1, static_cast<int>(listener.focus_changes().size()));
103 EXPECT_TRUE(listener.focus_changes()[0] == ViewPair(null_view, view));
104 listener.ClearFocusChanges();
106 // Same test with a NativeControl.
107 button->RequestFocus();
108 SimulateDeactivateWindow();
109 EXPECT_EQ(NULL, GetFocusManager()->GetFocusedView());
110 ASSERT_EQ(2, static_cast<int>(listener.focus_changes().size()));
111 EXPECT_TRUE(listener.focus_changes()[0] == ViewPair(view, button));
112 EXPECT_TRUE(listener.focus_changes()[1] == ViewPair(button, null_view));
113 listener.ClearFocusChanges();
115 SimulateActivateWindow();
116 EXPECT_EQ(button, GetFocusManager()->GetFocusedView());
117 ASSERT_EQ(1, static_cast<int>(listener.focus_changes().size()));
118 EXPECT_TRUE(listener.focus_changes()[0] == ViewPair(null_view, button));
119 listener.ClearFocusChanges();
122 // Now test that while the window is inactive we can change the focused view
123 // (we do that in several places).
124 SimulateDeactivateWindow();
125 // TODO: would have to mock the window being inactive (with a TestWidgetWin
126 // that would return false on IsActive()).
127 GetFocusManager()->SetFocusedView(view);
128 ::SendMessage(window_->GetNativeWindow(), WM_ACTIVATE, WA_ACTIVE, NULL);
130 EXPECT_EQ(view, GetFocusManager()->GetFocusedView());
131 ASSERT_EQ(2, static_cast<int>(listener.focus_changes().size()));
132 EXPECT_TRUE(listener.focus_changes()[0] == ViewPair(button, null_view));
133 EXPECT_TRUE(listener.focus_changes()[1] == ViewPair(null_view, view));
137 // Test that the focus manager is created successfully for the first view
138 // window parented to a native dialog.
139 TEST_F(FocusManagerTest, CreationForNativeRoot) {
140 // Create a window class.
142 memset(&class_ex, 0, sizeof(class_ex));
143 class_ex.cbSize = sizeof(WNDCLASSEX);
144 class_ex.lpfnWndProc = &DefWindowProc;
145 class_ex.lpszClassName = L"TestWindow";
146 ATOM atom = RegisterClassEx(&class_ex);
149 // Create a native dialog window.
150 HWND hwnd = CreateWindowEx(0, class_ex.lpszClassName, NULL,
151 WS_OVERLAPPEDWINDOW, 0, 0, 200, 200,
152 NULL, NULL, NULL, NULL);
155 // Create a view window parented to native dialog.
156 scoped_ptr<Widget> widget1(new Widget);
157 Widget::InitParams params(Widget::InitParams::TYPE_CONTROL);
158 params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
159 params.parent = hwnd;
160 params.bounds = gfx::Rect(0, 0, 100, 100);
161 params.top_level = true; // This is top level in views hierarchy.
162 widget1->Init(params);
164 // Get the focus manager directly from the first window. Should exist
165 // because the first window is the root widget.
166 views::FocusManager* focus_manager1 = widget1->GetFocusManager();
167 EXPECT_TRUE(focus_manager1);
169 // Create another view window parented to the first view window.
170 scoped_ptr<Widget> widget2(new Widget);
171 params.parent = widget1->GetNativeView();
172 params.top_level = false; // This is child widget.
173 widget2->Init(params);
175 // Access the shared focus manager directly from the second window.
176 views::FocusManager* focus_manager2 = widget2->GetFocusManager();
177 EXPECT_EQ(focus_manager2, focus_manager1);
179 // Access the shared focus manager indirectly from the first window handle.
180 gfx::NativeWindow native_window = widget1->GetNativeWindow();
181 views::Widget* widget =
182 views::Widget::GetWidgetForNativeWindow(native_window);
183 EXPECT_EQ(widget->GetFocusManager(), focus_manager1);
185 // Access the shared focus manager indirectly from the second window handle.
186 native_window = widget2->GetNativeWindow();
187 widget = views::Widget::GetWidgetForNativeWindow(native_window);
188 EXPECT_EQ(widget->GetFocusManager(), focus_manager1);
190 // Access the shared focus manager indirectly from the first view handle.
191 gfx::NativeView native_view = widget1->GetNativeView();
192 widget = views::Widget::GetTopLevelWidgetForNativeView(native_view);
193 EXPECT_EQ(widget->GetFocusManager(), focus_manager1);
195 // Access the shared focus manager indirectly from the second view handle.
196 native_view = widget2->GetNativeView();
197 widget = views::Widget::GetTopLevelWidgetForNativeView(native_view);
198 EXPECT_EQ(widget->GetFocusManager(), focus_manager1);
203 // Tests that the keyup messages are eaten for accelerators.
204 // Windows-only, Windows is the only platform that handles accelerators in
205 // AcceleratorHandler. NativeWidgetAura::OnKeyEvent handles them in other
207 TEST_F(FocusManagerTest, IgnoreKeyupForAccelerators) {
208 FocusManager* focus_manager = GetFocusManager();
209 MessageTrackingView* mtv = new MessageTrackingView();
210 mtv->AddAccelerator(ui::Accelerator(ui::VKEY_0, ui::EF_NONE));
211 mtv->AddAccelerator(ui::Accelerator(ui::VKEY_1, ui::EF_NONE));
212 GetContentsView()->AddChildView(mtv);
213 focus_manager->SetFocusedView(mtv);
215 // First send a non-accelerator key sequence.
216 PostKeyDown(ui::VKEY_9);
217 PostKeyUp(ui::VKEY_9);
218 scoped_ptr<base::RunLoop> run_loop(new base::RunLoop());
219 run_loop->RunUntilIdle();
220 // Make sure we get a key-up and key-down.
221 ASSERT_EQ(1U, mtv->keys_pressed().size());
222 EXPECT_EQ(ui::VKEY_9, mtv->keys_pressed()[0]);
223 ASSERT_EQ(1U, mtv->keys_released().size());
224 EXPECT_EQ(ui::VKEY_9, mtv->keys_released()[0]);
225 EXPECT_FALSE(mtv->accelerator_pressed());
228 // Same thing with repeat and more than one key at once.
229 PostKeyDown(ui::VKEY_9);
230 PostKeyDown(ui::VKEY_9);
231 PostKeyDown(ui::VKEY_8);
232 PostKeyDown(ui::VKEY_9);
233 PostKeyDown(ui::VKEY_7);
234 PostKeyUp(ui::VKEY_9);
235 PostKeyUp(ui::VKEY_7);
236 PostKeyUp(ui::VKEY_8);
237 run_loop.reset(new base::RunLoop());
238 run_loop->RunUntilIdle();
239 // Make sure we get a key-up and key-down.
240 ASSERT_EQ(5U, mtv->keys_pressed().size());
241 EXPECT_EQ(ui::VKEY_9, mtv->keys_pressed()[0]);
242 EXPECT_EQ(ui::VKEY_9, mtv->keys_pressed()[1]);
243 EXPECT_EQ(ui::VKEY_8, mtv->keys_pressed()[2]);
244 EXPECT_EQ(ui::VKEY_9, mtv->keys_pressed()[3]);
245 EXPECT_EQ(ui::VKEY_7, mtv->keys_pressed()[4]);
246 ASSERT_EQ(3U, mtv->keys_released().size());
247 EXPECT_EQ(ui::VKEY_9, mtv->keys_released()[0]);
248 EXPECT_EQ(ui::VKEY_7, mtv->keys_released()[1]);
249 EXPECT_EQ(ui::VKEY_8, mtv->keys_released()[2]);
250 EXPECT_FALSE(mtv->accelerator_pressed());
253 // Now send an accelerator key sequence.
254 PostKeyDown(ui::VKEY_0);
255 PostKeyUp(ui::VKEY_0);
256 run_loop.reset(new base::RunLoop());
257 run_loop->RunUntilIdle();
258 EXPECT_TRUE(mtv->keys_pressed().empty());
259 EXPECT_TRUE(mtv->keys_released().empty());
260 EXPECT_TRUE(mtv->accelerator_pressed());
263 // Same thing with repeat and more than one key at once.
264 PostKeyDown(ui::VKEY_0);
265 PostKeyDown(ui::VKEY_1);
266 PostKeyDown(ui::VKEY_1);
267 PostKeyDown(ui::VKEY_0);
268 PostKeyDown(ui::VKEY_0);
269 PostKeyUp(ui::VKEY_1);
270 PostKeyUp(ui::VKEY_0);
271 run_loop.reset(new base::RunLoop());
272 run_loop->RunUntilIdle();
273 EXPECT_TRUE(mtv->keys_pressed().empty());
274 EXPECT_TRUE(mtv->keys_released().empty());
275 EXPECT_TRUE(mtv->accelerator_pressed());