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
30namespace wm {
31namespace test {
32
33namespace {
34
35class 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
57class 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
77void 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
100class 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
125class 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
159TEST_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
185TEST_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