1 // Copyright 2014 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/wm/core/nested_accelerator_controller.h" 6 7 #include "base/bind.h" 8 #include "base/event_types.h" 9 #include "base/message_loop/message_loop.h" 10 #include "ui/aura/test/aura_test_base.h" 11 #include "ui/aura/test/test_windows.h" 12 #include "ui/aura/window.h" 13 #include "ui/aura/window_event_dispatcher.h" 14 #include "ui/base/accelerators/accelerator.h" 15 #include "ui/base/accelerators/accelerator.h" 16 #include "ui/base/accelerators/accelerator_manager.h" 17 #include "ui/events/event_constants.h" 18 #include "ui/events/event_utils.h" 19 #include "ui/events/platform/platform_event_dispatcher.h" 20 #include "ui/events/platform/platform_event_source.h" 21 #include "ui/events/platform/scoped_event_dispatcher.h" 22 #include "ui/wm/core/nested_accelerator_delegate.h" 23 #include "ui/wm/public/dispatcher_client.h" 24 25 #if defined(USE_X11) 26 #include <X11/Xlib.h> 27 #include "ui/events/test/events_test_utils_x11.h" 28 #endif // USE_X11 29 30 namespace wm { 31 namespace test { 32 33 namespace { 34 35 class MockDispatcher : public ui::PlatformEventDispatcher { 36 public: 37 MockDispatcher() : num_key_events_dispatched_(0) {} 38 39 int num_key_events_dispatched() { return num_key_events_dispatched_; } 40 41 private: 42 // ui::PlatformEventDispatcher: 43 virtual bool CanDispatchEvent(const ui::PlatformEvent& event) OVERRIDE { 44 return true; 45 } 46 virtual uint32_t DispatchEvent(const ui::PlatformEvent& event) OVERRIDE { 47 if (ui::EventTypeFromNative(event) == ui::ET_KEY_RELEASED) 48 num_key_events_dispatched_++; 49 return ui::POST_DISPATCH_NONE; 50 } 51 52 int num_key_events_dispatched_; 53 54 DISALLOW_COPY_AND_ASSIGN(MockDispatcher); 55 }; 56 57 class TestTarget : public ui::AcceleratorTarget { 58 public: 59 TestTarget() : accelerator_pressed_count_(0) {} 60 virtual ~TestTarget() {} 61 62 int accelerator_pressed_count() const { return accelerator_pressed_count_; } 63 64 // Overridden from ui::AcceleratorTarget: 65 virtual bool AcceleratorPressed(const ui::Accelerator& accelerator) OVERRIDE { 66 accelerator_pressed_count_++; 67 return true; 68 } 69 virtual bool CanHandleAccelerators() const OVERRIDE { return true; } 70 71 private: 72 int accelerator_pressed_count_; 73 74 DISALLOW_COPY_AND_ASSIGN(TestTarget); 75 }; 76 77 void DispatchKeyReleaseA(aura::Window* root_window) { 78 // Sending both keydown and keyup is necessary here because the accelerator 79 // manager only checks a keyup event following a keydown event. See 80 // ShouldHandle() in ui/base/accelerators/accelerator_manager.cc for details. 81 #if defined(OS_WIN) 82 MSG native_event_down = {NULL, WM_KEYDOWN, ui::VKEY_A, 0}; 83 aura::WindowTreeHost* host = root_window->GetHost(); 84 host->PostNativeEvent(native_event_down); 85 MSG native_event_up = {NULL, WM_KEYUP, ui::VKEY_A, 0}; 86 host->PostNativeEvent(native_event_up); 87 #elif defined(USE_X11) 88 ui::ScopedXI2Event native_event; 89 native_event.InitKeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_A, 0); 90 aura::WindowTreeHost* host = root_window->GetHost(); 91 host->PostNativeEvent(native_event); 92 native_event.InitKeyEvent(ui::ET_KEY_RELEASED, ui::VKEY_A, 0); 93 host->PostNativeEvent(native_event); 94 #endif 95 // Make sure the inner message-loop terminates after dispatching the events. 96 base::MessageLoop::current()->PostTask( 97 FROM_HERE, base::MessageLoop::current()->QuitClosure()); 98 } 99 100 class MockNestedAcceleratorDelegate : public NestedAcceleratorDelegate { 101 public: 102 MockNestedAcceleratorDelegate() 103 : accelerator_manager_(new ui::AcceleratorManager) {} 104 virtual ~MockNestedAcceleratorDelegate() {} 105 106 // NestedAcceleratorDelegate: 107 virtual Result ProcessAccelerator( 108 const ui::Accelerator& accelerator) OVERRIDE { 109 return accelerator_manager_->Process(accelerator) ? 110 RESULT_PROCESSED : RESULT_NOT_PROCESSED; 111 } 112 113 void Register(const ui::Accelerator& accelerator, 114 ui::AcceleratorTarget* target) { 115 accelerator_manager_->Register( 116 accelerator, ui::AcceleratorManager::kNormalPriority, target); 117 } 118 119 private: 120 scoped_ptr<ui::AcceleratorManager> accelerator_manager_; 121 122 DISALLOW_COPY_AND_ASSIGN(MockNestedAcceleratorDelegate); 123 }; 124 125 class NestedAcceleratorTest : public aura::test::AuraTestBase { 126 public: 127 NestedAcceleratorTest() {} 128 virtual ~NestedAcceleratorTest() {} 129 130 virtual void SetUp() OVERRIDE { 131 AuraTestBase::SetUp(); 132 delegate_ = new MockNestedAcceleratorDelegate(); 133 nested_accelerator_controller_.reset( 134 new NestedAcceleratorController(delegate_)); 135 aura::client::SetDispatcherClient(root_window(), 136 nested_accelerator_controller_.get()); 137 } 138 139 virtual void TearDown() OVERRIDE { 140 aura::client::SetDispatcherClient(root_window(), NULL); 141 AuraTestBase::TearDown(); 142 delegate_ = NULL; 143 nested_accelerator_controller_.reset(); 144 } 145 146 MockNestedAcceleratorDelegate* delegate() { return delegate_; } 147 148 private: 149 scoped_ptr<NestedAcceleratorController> nested_accelerator_controller_; 150 MockNestedAcceleratorDelegate* delegate_; 151 152 DISALLOW_COPY_AND_ASSIGN(NestedAcceleratorTest); 153 }; 154 155 } // namespace 156 157 // Aura window above lock screen in z order. 158 // http://crbug.com/396494 159 TEST_F(NestedAcceleratorTest, DISABLED_AssociatedWindowAboveLockScreen) { 160 // TODO(oshima|sadrul): remove when Win implements PES. 161 if (!ui::PlatformEventSource::GetInstance()) 162 return; 163 MockDispatcher inner_dispatcher; 164 scoped_ptr<aura::Window> mock_lock_container( 165 CreateNormalWindow(0, root_window(), NULL)); 166 aura::test::CreateTestWindowWithId(1, mock_lock_container.get()); 167 168 scoped_ptr<aura::Window> associated_window( 169 CreateNormalWindow(2, root_window(), NULL)); 170 EXPECT_TRUE(aura::test::WindowIsAbove(associated_window.get(), 171 mock_lock_container.get())); 172 173 DispatchKeyReleaseA(root_window()); 174 scoped_ptr<ui::ScopedEventDispatcher> override_dispatcher = 175 ui::PlatformEventSource::GetInstance()->OverrideDispatcher( 176 &inner_dispatcher); 177 aura::client::DispatcherRunLoop run_loop( 178 aura::client::GetDispatcherClient(root_window()), NULL); 179 run_loop.Run(); 180 EXPECT_EQ(1, inner_dispatcher.num_key_events_dispatched()); 181 } 182 183 // Test that the nested dispatcher handles accelerators. 184 // http://crbug.com/396494 185 TEST_F(NestedAcceleratorTest, DISABLED_AcceleratorsHandled) { 186 // TODO(oshima|sadrul): remove when Win implements PES. 187 if (!ui::PlatformEventSource::GetInstance()) 188 return; 189 MockDispatcher inner_dispatcher; 190 ui::Accelerator accelerator(ui::VKEY_A, ui::EF_NONE); 191 accelerator.set_type(ui::ET_KEY_RELEASED); 192 TestTarget target; 193 delegate()->Register(accelerator, &target); 194 195 DispatchKeyReleaseA(root_window()); 196 scoped_ptr<ui::ScopedEventDispatcher> override_dispatcher = 197 ui::PlatformEventSource::GetInstance()->OverrideDispatcher( 198 &inner_dispatcher); 199 aura::client::DispatcherRunLoop run_loop( 200 aura::client::GetDispatcherClient(root_window()), NULL); 201 run_loop.Run(); 202 EXPECT_EQ(0, inner_dispatcher.num_key_events_dispatched()); 203 EXPECT_EQ(1, target.accelerator_pressed_count()); 204 } 205 206 } // namespace test 207 } // namespace wm 208