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