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/test_window_delegate.h"
9 #include "ui/aura/window.h"
10 #include "ui/aura/window_event_dispatcher.h"
11 #include "ui/events/event.h"
12 #include "ui/events/event_constants.h"
13 #include "ui/events/event_handler.h"
14 #include "ui/events/event_utils.h"
15 #include "ui/events/keycodes/keyboard_codes.h"
16 #include "ui/events/test/event_generator.h"
20 class MouseEventCapturer
: public ui::EventHandler
{
22 MouseEventCapturer() { Reset(); }
23 ~MouseEventCapturer() override
{}
29 void OnMouseEvent(ui::MouseEvent
* event
) override
{
30 if (!(event
->flags() & ui::EF_LEFT_MOUSE_BUTTON
))
32 // Filter out extraneous mouse events like mouse entered, exited,
33 // capture changed, etc.
34 ui::EventType type
= event
->type();
35 if (type
== ui::ET_MOUSE_MOVED
|| type
== ui::ET_MOUSE_PRESSED
||
36 type
== ui::ET_MOUSE_RELEASED
) {
37 events_
.push_back(ui::MouseEvent(event
->type(), event
->location(),
38 event
->root_location(),
39 ui::EventTimeForNow(), event
->flags(),
40 event
->changed_button_flags()));
41 // Stop event propagation so we don't click on random stuff that
42 // might break test assumptions.
43 event
->StopPropagation();
46 // If there is a possibility that we're in an infinite loop, we should
47 // exit early with a sensible error rather than letting the test time out.
48 ASSERT_LT(events_
.size(), 100u);
51 const std::vector
<ui::MouseEvent
>& captured_events() const {
56 std::vector
<ui::MouseEvent
> events_
;
58 DISALLOW_COPY_AND_ASSIGN(MouseEventCapturer
);
61 class AutoclickTest
: public test::AshTestBase
{
64 ~AutoclickTest() override
{}
66 void SetUp() override
{
67 test::AshTestBase::SetUp();
68 Shell::GetInstance()->AddPreTargetHandler(&mouse_event_capturer_
);
69 GetAutoclickController()->SetAutoclickDelay(0);
71 // Move mouse to deterministic location at the start of each test.
72 GetEventGenerator().MoveMouseTo(100, 100);
75 void TearDown() override
{
76 Shell::GetInstance()->RemovePreTargetHandler(&mouse_event_capturer_
);
77 test::AshTestBase::TearDown();
80 void MoveMouseWithFlagsTo(int x
, int y
, ui::EventFlags flags
) {
81 GetEventGenerator().set_flags(flags
);
82 GetEventGenerator().MoveMouseTo(x
, y
);
83 GetEventGenerator().set_flags(ui::EF_NONE
);
86 const std::vector
<ui::MouseEvent
>& WaitForMouseEvents() {
87 mouse_event_capturer_
.Reset();
88 RunAllPendingInMessageLoop();
89 return mouse_event_capturer_
.captured_events();
92 AutoclickController
* GetAutoclickController() {
93 return Shell::GetInstance()->autoclick_controller();
97 MouseEventCapturer mouse_event_capturer_
;
99 DISALLOW_COPY_AND_ASSIGN(AutoclickTest
);
102 TEST_F(AutoclickTest
, ToggleEnabled
) {
103 std::vector
<ui::MouseEvent
> events
;
105 // We should not see any events initially.
106 EXPECT_FALSE(GetAutoclickController()->IsEnabled());
107 events
= WaitForMouseEvents();
108 EXPECT_EQ(0u, events
.size());
110 // Enable autoclick, and we should see a mouse pressed and
111 // a mouse released event, simulating a click.
112 GetAutoclickController()->SetEnabled(true);
113 GetEventGenerator().MoveMouseTo(0, 0);
114 EXPECT_TRUE(GetAutoclickController()->IsEnabled());
115 events
= WaitForMouseEvents();
116 EXPECT_EQ(2u, events
.size());
117 EXPECT_EQ(ui::ET_MOUSE_PRESSED
, events
[0].type());
118 EXPECT_EQ(ui::ET_MOUSE_RELEASED
, events
[1].type());
120 // We should not get any more clicks until we move the mouse.
121 events
= WaitForMouseEvents();
122 EXPECT_EQ(0u, events
.size());
123 GetEventGenerator().MoveMouseTo(30, 30);
124 events
= WaitForMouseEvents();
125 EXPECT_EQ(2u, events
.size());
126 EXPECT_EQ(ui::ET_MOUSE_PRESSED
, events
[0].type());
127 EXPECT_EQ(ui::ET_MOUSE_RELEASED
, events
[1].type());
129 // Disable autoclick, and we should see the original behaviour.
130 GetAutoclickController()->SetEnabled(false);
131 EXPECT_FALSE(GetAutoclickController()->IsEnabled());
132 events
= WaitForMouseEvents();
133 EXPECT_EQ(0u, events
.size());
136 TEST_F(AutoclickTest
, MouseMovement
) {
137 std::vector
<ui::MouseEvent
> events
;
138 GetAutoclickController()->SetEnabled(true);
141 gfx::Point
p2(20, 20);
142 gfx::Point
p3(40, 40);
145 GetEventGenerator().MoveMouseTo(p1
);
146 events
= WaitForMouseEvents();
147 EXPECT_EQ(2u, events
.size());
148 EXPECT_EQ(p1
.ToString(), events
[0].root_location().ToString());
149 EXPECT_EQ(p1
.ToString(), events
[1].root_location().ToString());
151 // Move mouse to multiple locations and finally arrive at p3.
152 GetEventGenerator().MoveMouseTo(p2
);
153 GetEventGenerator().MoveMouseTo(p1
);
154 GetEventGenerator().MoveMouseTo(p3
);
155 events
= WaitForMouseEvents();
156 EXPECT_EQ(2u, events
.size());
157 EXPECT_EQ(p3
.ToString(), events
[0].root_location().ToString());
158 EXPECT_EQ(p3
.ToString(), events
[1].root_location().ToString());
161 TEST_F(AutoclickTest
, MovementThreshold
) {
162 UpdateDisplay("1280x1024,800x600");
163 RunAllPendingInMessageLoop();
164 aura::Window::Windows root_windows
= Shell::GetAllRootWindows();
165 EXPECT_EQ(2u, root_windows
.size());
167 // Run test for the secondary display too to test fix for crbug.com/449870.
168 for (const auto& root_window
: root_windows
) {
169 gfx::Point center
= root_window
->GetBoundsInScreen().CenterPoint();
171 GetAutoclickController()->SetEnabled(true);
172 GetEventGenerator().MoveMouseTo(center
);
173 EXPECT_EQ(2u, WaitForMouseEvents().size());
175 // Small mouse movements should not trigger an autoclick.
176 GetEventGenerator().MoveMouseTo(center
+ gfx::Vector2d(1, 1));
177 EXPECT_EQ(0u, WaitForMouseEvents().size());
178 GetEventGenerator().MoveMouseTo(center
+ gfx::Vector2d(2, 2));
179 EXPECT_EQ(0u, WaitForMouseEvents().size());
180 GetEventGenerator().MoveMouseTo(center
);
181 EXPECT_EQ(0u, WaitForMouseEvents().size());
183 // A large mouse movement should trigger an autoclick.
184 GetEventGenerator().MoveMouseTo(center
+ gfx::Vector2d(100, 100));
185 EXPECT_EQ(2u, WaitForMouseEvents().size());
189 TEST_F(AutoclickTest
, SingleKeyModifier
) {
190 GetAutoclickController()->SetEnabled(true);
191 MoveMouseWithFlagsTo(20, 20, ui::EF_SHIFT_DOWN
);
192 std::vector
<ui::MouseEvent
> events
= WaitForMouseEvents();
193 EXPECT_EQ(2u, events
.size());
194 EXPECT_EQ(ui::EF_SHIFT_DOWN
, events
[0].flags() & ui::EF_SHIFT_DOWN
);
195 EXPECT_EQ(ui::EF_SHIFT_DOWN
, events
[1].flags() & ui::EF_SHIFT_DOWN
);
198 TEST_F(AutoclickTest
, MultipleKeyModifiers
) {
199 GetAutoclickController()->SetEnabled(true);
200 ui::EventFlags modifier_flags
= static_cast<ui::EventFlags
>(
201 ui::EF_CONTROL_DOWN
| ui::EF_ALT_DOWN
| ui::EF_SHIFT_DOWN
);
202 MoveMouseWithFlagsTo(30, 30, modifier_flags
);
203 std::vector
<ui::MouseEvent
> events
= WaitForMouseEvents();
204 EXPECT_EQ(2u, events
.size());
205 EXPECT_EQ(modifier_flags
, events
[0].flags() & modifier_flags
);
206 EXPECT_EQ(modifier_flags
, events
[1].flags() & modifier_flags
);
209 TEST_F(AutoclickTest
, KeyModifiersReleased
) {
210 GetAutoclickController()->SetEnabled(true);
212 ui::EventFlags modifier_flags
= static_cast<ui::EventFlags
>(
213 ui::EF_CONTROL_DOWN
| ui::EF_ALT_DOWN
| ui::EF_SHIFT_DOWN
);
214 MoveMouseWithFlagsTo(12, 12, modifier_flags
);
216 // Simulate releasing key modifiers by sending key released events.
217 GetEventGenerator().ReleaseKey(ui::VKEY_CONTROL
,
218 static_cast<ui::EventFlags
>(ui::EF_ALT_DOWN
| ui::EF_SHIFT_DOWN
));
219 GetEventGenerator().ReleaseKey(ui::VKEY_SHIFT
, ui::EF_ALT_DOWN
);
221 std::vector
<ui::MouseEvent
> events
;
222 events
= WaitForMouseEvents();
223 EXPECT_EQ(2u, events
.size());
224 EXPECT_EQ(0, events
[0].flags() & ui::EF_CONTROL_DOWN
);
225 EXPECT_EQ(0, events
[0].flags() & ui::EF_SHIFT_DOWN
);
226 EXPECT_EQ(ui::EF_ALT_DOWN
, events
[0].flags() & ui::EF_ALT_DOWN
);
229 TEST_F(AutoclickTest
, UserInputCancelsAutoclick
) {
230 GetAutoclickController()->SetEnabled(true);
231 std::vector
<ui::MouseEvent
> events
;
233 // Pressing a normal key should cancel the autoclick.
234 GetEventGenerator().MoveMouseTo(200, 200);
235 GetEventGenerator().PressKey(ui::VKEY_K
, ui::EF_NONE
);
236 GetEventGenerator().ReleaseKey(ui::VKEY_K
, ui::EF_NONE
);
237 events
= WaitForMouseEvents();
238 EXPECT_EQ(0u, events
.size());
240 // Pressing a modifier key should NOT cancel the autoclick.
241 GetEventGenerator().MoveMouseTo(100, 100);
242 GetEventGenerator().PressKey(ui::VKEY_SHIFT
, ui::EF_SHIFT_DOWN
);
243 GetEventGenerator().ReleaseKey(ui::VKEY_SHIFT
, ui::EF_NONE
);
244 events
= WaitForMouseEvents();
245 EXPECT_EQ(2u, events
.size());
247 // Performing a gesture should cancel the autoclick.
248 GetEventGenerator().MoveMouseTo(200, 200);
249 GetEventGenerator().GestureTapDownAndUp(gfx::Point(100, 100));
250 events
= WaitForMouseEvents();
251 EXPECT_EQ(0u, events
.size());
253 // Test another gesture.
254 GetEventGenerator().MoveMouseTo(100, 100);
255 GetEventGenerator().GestureScrollSequence(
256 gfx::Point(100, 100),
257 gfx::Point(200, 200),
258 base::TimeDelta::FromMilliseconds(200),
260 events
= WaitForMouseEvents();
261 EXPECT_EQ(0u, events
.size());
263 // Test scroll events.
264 GetEventGenerator().MoveMouseTo(200, 200);
265 GetEventGenerator().ScrollSequence(
266 gfx::Point(100, 100), base::TimeDelta::FromMilliseconds(200),
268 events
= WaitForMouseEvents();
269 EXPECT_EQ(0u, events
.size());
272 TEST_F(AutoclickTest
, SynthesizedMouseMovesIgnored
) {
273 GetAutoclickController()->SetEnabled(true);
274 std::vector
<ui::MouseEvent
> events
;
275 GetEventGenerator().MoveMouseTo(100, 100);
276 events
= WaitForMouseEvents();
277 EXPECT_EQ(2u, events
.size());
279 // Show a window and make sure the new window is under the cursor. As a
280 // result, synthesized mouse events will be dispatched to the window, but it
281 // should not trigger an autoclick.
282 aura::test::EventCountDelegate delegate
;
283 scoped_ptr
<aura::Window
> window(CreateTestWindowInShellWithDelegate(
284 &delegate
, 123, gfx::Rect(50, 50, 100, 100)));
286 events
= WaitForMouseEvents();
287 EXPECT_EQ(0u, events
.size());
288 EXPECT_EQ("1 1 0", delegate
.GetMouseMotionCountsAndReset());