1 // Copyright 2013 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 "ash/autoclick/autoclick_controller.h"
7 #include "ash/test/ash_test_base.h"
8 #include "ui/aura/test/event_generator.h"
9 #include "ui/aura/test/test_window_delegate.h"
10 #include "ui/aura/window.h"
11 #include "ui/aura/window_event_dispatcher.h"
12 #include "ui/events/event.h"
13 #include "ui/events/event_constants.h"
14 #include "ui/events/event_handler.h"
15 #include "ui/events/keycodes/keyboard_codes.h"
19 class MouseEventCapturer
: public ui::EventHandler
{
21 MouseEventCapturer() { Reset(); }
22 virtual ~MouseEventCapturer() {}
28 virtual void OnMouseEvent(ui::MouseEvent
* event
) OVERRIDE
{
29 if (!(event
->flags() & ui::EF_LEFT_MOUSE_BUTTON
))
31 // Filter out extraneous mouse events like mouse entered, exited,
32 // capture changed, etc.
33 ui::EventType type
= event
->type();
34 if (type
== ui::ET_MOUSE_MOVED
|| type
== ui::ET_MOUSE_PRESSED
||
35 type
== ui::ET_MOUSE_RELEASED
) {
36 events_
.push_back(ui::MouseEvent(
39 event
->root_location(),
41 event
->changed_button_flags()));
42 // Stop event propagation so we don't click on random stuff that
43 // might break test assumptions.
44 event
->StopPropagation();
47 // If there is a possibility that we're in an infinite loop, we should
48 // exit early with a sensible error rather than letting the test time out.
49 ASSERT_LT(events_
.size(), 100u);
52 const std::vector
<ui::MouseEvent
>& captured_events() const {
57 std::vector
<ui::MouseEvent
> events_
;
59 DISALLOW_COPY_AND_ASSIGN(MouseEventCapturer
);
62 class AutoclickTest
: public test::AshTestBase
{
65 virtual ~AutoclickTest() {}
67 virtual void SetUp() OVERRIDE
{
68 test::AshTestBase::SetUp();
69 Shell::GetInstance()->AddPreTargetHandler(&mouse_event_capturer_
);
70 GetAutoclickController()->SetAutoclickDelay(0);
72 // Move mouse to deterministic location at the start of each test.
73 GetEventGenerator().MoveMouseTo(100, 100);
76 virtual void TearDown() OVERRIDE
{
77 Shell::GetInstance()->RemovePreTargetHandler(&mouse_event_capturer_
);
78 test::AshTestBase::TearDown();
81 void MoveMouseWithFlagsTo(int x
, int y
, ui::EventFlags flags
) {
82 GetEventGenerator().set_flags(flags
);
83 GetEventGenerator().MoveMouseTo(x
, y
);
84 GetEventGenerator().set_flags(ui::EF_NONE
);
87 const std::vector
<ui::MouseEvent
>& WaitForMouseEvents() {
88 mouse_event_capturer_
.Reset();
89 RunAllPendingInMessageLoop();
90 return mouse_event_capturer_
.captured_events();
93 AutoclickController
* GetAutoclickController() {
94 return Shell::GetInstance()->autoclick_controller();
98 MouseEventCapturer mouse_event_capturer_
;
100 DISALLOW_COPY_AND_ASSIGN(AutoclickTest
);
103 TEST_F(AutoclickTest
, ToggleEnabled
) {
104 std::vector
<ui::MouseEvent
> events
;
106 // We should not see any events initially.
107 EXPECT_FALSE(GetAutoclickController()->IsEnabled());
108 events
= WaitForMouseEvents();
109 EXPECT_EQ(0u, events
.size());
111 // Enable autoclick, and we should see a mouse pressed and
112 // a mouse released event, simulating a click.
113 GetAutoclickController()->SetEnabled(true);
114 GetEventGenerator().MoveMouseTo(0, 0);
115 EXPECT_TRUE(GetAutoclickController()->IsEnabled());
116 events
= WaitForMouseEvents();
117 EXPECT_EQ(2u, events
.size());
118 EXPECT_EQ(ui::ET_MOUSE_PRESSED
, events
[0].type());
119 EXPECT_EQ(ui::ET_MOUSE_RELEASED
, events
[1].type());
121 // We should not get any more clicks until we move the mouse.
122 events
= WaitForMouseEvents();
123 EXPECT_EQ(0u, events
.size());
124 GetEventGenerator().MoveMouseTo(30, 30);
125 events
= WaitForMouseEvents();
126 EXPECT_EQ(2u, events
.size());
127 EXPECT_EQ(ui::ET_MOUSE_PRESSED
, events
[0].type());
128 EXPECT_EQ(ui::ET_MOUSE_RELEASED
, events
[1].type());
130 // Disable autoclick, and we should see the original behaviour.
131 GetAutoclickController()->SetEnabled(false);
132 EXPECT_FALSE(GetAutoclickController()->IsEnabled());
133 events
= WaitForMouseEvents();
134 EXPECT_EQ(0u, events
.size());
137 TEST_F(AutoclickTest
, MouseMovement
) {
138 std::vector
<ui::MouseEvent
> events
;
139 GetAutoclickController()->SetEnabled(true);
142 gfx::Point
p2(20, 20);
143 gfx::Point
p3(40, 40);
146 GetEventGenerator().MoveMouseTo(p1
);
147 events
= WaitForMouseEvents();
148 EXPECT_EQ(2u, events
.size());
149 EXPECT_EQ(p1
.ToString(), events
[0].root_location().ToString());
150 EXPECT_EQ(p1
.ToString(), events
[1].root_location().ToString());
152 // Move mouse to multiple locations and finally arrive at p3.
153 GetEventGenerator().MoveMouseTo(p2
);
154 GetEventGenerator().MoveMouseTo(p1
);
155 GetEventGenerator().MoveMouseTo(p3
);
156 events
= WaitForMouseEvents();
157 EXPECT_EQ(2u, events
.size());
158 EXPECT_EQ(p3
.ToString(), events
[0].root_location().ToString());
159 EXPECT_EQ(p3
.ToString(), events
[1].root_location().ToString());
162 TEST_F(AutoclickTest
, MovementThreshold
) {
163 GetAutoclickController()->SetEnabled(true);
164 GetEventGenerator().MoveMouseTo(0, 0);
165 EXPECT_EQ(2u, WaitForMouseEvents().size());
167 // Small mouse movements should not trigger an autoclick.
168 GetEventGenerator().MoveMouseTo(1, 1);
169 EXPECT_EQ(0u, WaitForMouseEvents().size());
170 GetEventGenerator().MoveMouseTo(2, 2);
171 EXPECT_EQ(0u, WaitForMouseEvents().size());
172 GetEventGenerator().MoveMouseTo(0, 0);
173 EXPECT_EQ(0u, WaitForMouseEvents().size());
175 // A large mouse movement should trigger an autoclick.
176 GetEventGenerator().MoveMouseTo(100, 100);
177 EXPECT_EQ(2u, WaitForMouseEvents().size());
180 TEST_F(AutoclickTest
, SingleKeyModifier
) {
181 GetAutoclickController()->SetEnabled(true);
182 MoveMouseWithFlagsTo(20, 20, ui::EF_SHIFT_DOWN
);
183 std::vector
<ui::MouseEvent
> events
= WaitForMouseEvents();
184 EXPECT_EQ(2u, events
.size());
185 EXPECT_EQ(ui::EF_SHIFT_DOWN
, events
[0].flags() & ui::EF_SHIFT_DOWN
);
186 EXPECT_EQ(ui::EF_SHIFT_DOWN
, events
[1].flags() & ui::EF_SHIFT_DOWN
);
189 TEST_F(AutoclickTest
, MultipleKeyModifiers
) {
190 GetAutoclickController()->SetEnabled(true);
191 ui::EventFlags modifier_flags
= static_cast<ui::EventFlags
>(
192 ui::EF_CONTROL_DOWN
| ui::EF_ALT_DOWN
| ui::EF_SHIFT_DOWN
);
193 MoveMouseWithFlagsTo(30, 30, modifier_flags
);
194 std::vector
<ui::MouseEvent
> events
= WaitForMouseEvents();
195 EXPECT_EQ(2u, events
.size());
196 EXPECT_EQ(modifier_flags
, events
[0].flags() & modifier_flags
);
197 EXPECT_EQ(modifier_flags
, events
[1].flags() & modifier_flags
);
200 TEST_F(AutoclickTest
, KeyModifiersReleased
) {
201 GetAutoclickController()->SetEnabled(true);
203 ui::EventFlags modifier_flags
= static_cast<ui::EventFlags
>(
204 ui::EF_CONTROL_DOWN
| ui::EF_ALT_DOWN
| ui::EF_SHIFT_DOWN
);
205 MoveMouseWithFlagsTo(12, 12, modifier_flags
);
207 // Simulate releasing key modifiers by sending key released events.
208 GetEventGenerator().ReleaseKey(ui::VKEY_CONTROL
,
209 static_cast<ui::EventFlags
>(ui::EF_ALT_DOWN
| ui::EF_SHIFT_DOWN
));
210 GetEventGenerator().ReleaseKey(ui::VKEY_SHIFT
, ui::EF_ALT_DOWN
);
212 std::vector
<ui::MouseEvent
> events
;
213 events
= WaitForMouseEvents();
214 EXPECT_EQ(2u, events
.size());
215 EXPECT_EQ(0, events
[0].flags() & ui::EF_CONTROL_DOWN
);
216 EXPECT_EQ(0, events
[0].flags() & ui::EF_SHIFT_DOWN
);
217 EXPECT_EQ(ui::EF_ALT_DOWN
, events
[0].flags() & ui::EF_ALT_DOWN
);
220 TEST_F(AutoclickTest
, ExtendedDisplay
) {
221 UpdateDisplay("1280x1024,800x600");
222 RunAllPendingInMessageLoop();
223 aura::Window::Windows root_windows
= Shell::GetAllRootWindows();
224 EXPECT_EQ(2u, root_windows
.size());
226 GetAutoclickController()->SetEnabled(true);
227 std::vector
<ui::MouseEvent
> events
;
229 // Test first root window.
230 aura::test::EventGenerator
generator1(root_windows
[0]);
231 generator1
.MoveMouseTo(100, 200);
232 events
= WaitForMouseEvents();
233 EXPECT_EQ(2u, events
.size());
234 EXPECT_EQ(100, events
[0].root_location().x());
235 EXPECT_EQ(200, events
[0].root_location().y());
237 // Test second root window.
238 aura::test::EventGenerator
generator2(root_windows
[1]);
239 generator2
.MoveMouseTo(300, 400);
240 events
= WaitForMouseEvents();
241 EXPECT_EQ(2u, events
.size());
242 EXPECT_EQ(300, events
[0].root_location().x());
243 EXPECT_EQ(400, events
[0].root_location().y());
245 // Test movement threshold between displays.
248 TEST_F(AutoclickTest
, UserInputCancelsAutoclick
) {
249 GetAutoclickController()->SetEnabled(true);
250 std::vector
<ui::MouseEvent
> events
;
252 // Pressing a normal key should cancel the autoclick.
253 GetEventGenerator().MoveMouseTo(200, 200);
254 GetEventGenerator().PressKey(ui::VKEY_K
, ui::EF_NONE
);
255 GetEventGenerator().ReleaseKey(ui::VKEY_K
, ui::EF_NONE
);
256 events
= WaitForMouseEvents();
257 EXPECT_EQ(0u, events
.size());
259 // Pressing a modifier key should NOT cancel the autoclick.
260 GetEventGenerator().MoveMouseTo(100, 100);
261 GetEventGenerator().PressKey(ui::VKEY_SHIFT
, ui::EF_SHIFT_DOWN
);
262 GetEventGenerator().ReleaseKey(ui::VKEY_SHIFT
, ui::EF_NONE
);
263 events
= WaitForMouseEvents();
264 EXPECT_EQ(2u, events
.size());
266 // Performing a gesture should cancel the autoclick.
267 GetEventGenerator().MoveMouseTo(200, 200);
268 GetEventGenerator().GestureTapDownAndUp(gfx::Point(100, 100));
269 events
= WaitForMouseEvents();
270 EXPECT_EQ(0u, events
.size());
272 // Test another gesture.
273 GetEventGenerator().MoveMouseTo(100, 100);
274 GetEventGenerator().GestureScrollSequence(
275 gfx::Point(100, 100),
276 gfx::Point(200, 200),
277 base::TimeDelta::FromMilliseconds(200),
279 events
= WaitForMouseEvents();
280 EXPECT_EQ(0u, events
.size());
282 // Test scroll events.
283 GetEventGenerator().MoveMouseTo(200, 200);
284 GetEventGenerator().ScrollSequence(
285 gfx::Point(100, 100), base::TimeDelta::FromMilliseconds(200),
287 events
= WaitForMouseEvents();
288 EXPECT_EQ(0u, events
.size());
291 TEST_F(AutoclickTest
, SynthesizedMouseMovesIgnored
) {
292 GetAutoclickController()->SetEnabled(true);
293 std::vector
<ui::MouseEvent
> events
;
294 GetEventGenerator().MoveMouseTo(100, 100);
295 events
= WaitForMouseEvents();
296 EXPECT_EQ(2u, events
.size());
298 // Show a window and make sure the new window is under the cursor. As a
299 // result, synthesized mouse events will be dispatched to the window, but it
300 // should not trigger an autoclick.
301 aura::test::EventCountDelegate delegate
;
302 scoped_ptr
<aura::Window
> window(CreateTestWindowInShellWithDelegate(
303 &delegate
, 123, gfx::Rect(50, 50, 100, 100)));
305 events
= WaitForMouseEvents();
306 EXPECT_EQ(0u, events
.size());
307 EXPECT_EQ("1 1 0", delegate
.GetMouseMotionCountsAndReset());