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.
4
5 #include "ash/autoclick/autoclick_controller.h"
6 #include "ash/shell.h"
7 #include "ash/test/ash_test_base.h"
8 #include "ui/aura/root_window.h"
9 #include "ui/aura/test/event_generator.h"
10 #include "ui/aura/window.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/keycodes/keyboard_codes.h"
15
16 namespace ash {
17
18 class MouseEventCapturer : public ui::EventHandler {
19 public:
MouseEventCapturer()20 MouseEventCapturer() { Reset(); }
~MouseEventCapturer()21 virtual ~MouseEventCapturer() {}
22
Reset()23 void Reset() {
24 events_.clear();
25 }
26
OnMouseEvent(ui::MouseEvent * event)27 virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE {
28 if (!(event->flags() & ui::EF_LEFT_MOUSE_BUTTON))
29 return;
30 // Filter out extraneous mouse events like mouse entered, exited,
31 // capture changed, etc.
32 ui::EventType type = event->type();
33 if (type == ui::ET_MOUSE_MOVED || type == ui::ET_MOUSE_PRESSED ||
34 type == ui::ET_MOUSE_RELEASED) {
35 events_.push_back(ui::MouseEvent(
36 event->type(),
37 event->location(),
38 event->root_location(),
39 event->flags()));
40 // Stop event propagation so we don't click on random stuff that
41 // might break test assumptions.
42 event->StopPropagation();
43 }
44
45 // If there is a possibility that we're in an infinite loop, we should
46 // exit early with a sensible error rather than letting the test time out.
47 ASSERT_LT(events_.size(), 100u);
48 }
49
captured_events() const50 const std::vector<ui::MouseEvent>& captured_events() const {
51 return events_;
52 }
53
54 private:
55 std::vector<ui::MouseEvent> events_;
56
57 DISALLOW_COPY_AND_ASSIGN(MouseEventCapturer);
58 };
59
60 class AutoclickTest : public test::AshTestBase {
61 public:
AutoclickTest()62 AutoclickTest() {}
~AutoclickTest()63 virtual ~AutoclickTest() {}
64
SetUp()65 virtual void SetUp() OVERRIDE {
66 test::AshTestBase::SetUp();
67 Shell::GetInstance()->AddPreTargetHandler(&mouse_event_capturer_);
68 GetAutoclickController()->SetAutoclickDelay(0);
69
70 // Move mouse to deterministic location at the start of each test.
71 GetEventGenerator().MoveMouseTo(100, 100);
72 }
73
TearDown()74 virtual void TearDown() OVERRIDE {
75 Shell::GetInstance()->RemovePreTargetHandler(&mouse_event_capturer_);
76 test::AshTestBase::TearDown();
77 }
78
MoveMouseWithFlagsTo(int x,int y,ui::EventFlags flags)79 void MoveMouseWithFlagsTo(int x, int y, ui::EventFlags flags) {
80 GetEventGenerator().set_flags(flags);
81 GetEventGenerator().MoveMouseTo(x, y);
82 GetEventGenerator().set_flags(ui::EF_NONE);
83 }
84
WaitForMouseEvents()85 const std::vector<ui::MouseEvent>& WaitForMouseEvents() {
86 mouse_event_capturer_.Reset();
87 RunAllPendingInMessageLoop();
88 return mouse_event_capturer_.captured_events();
89 }
90
GetAutoclickController()91 AutoclickController* GetAutoclickController() {
92 return Shell::GetInstance()->autoclick_controller();
93 }
94
95 private:
96 MouseEventCapturer mouse_event_capturer_;
97
98 DISALLOW_COPY_AND_ASSIGN(AutoclickTest);
99 };
100
TEST_F(AutoclickTest,ToggleEnabled)101 TEST_F(AutoclickTest, ToggleEnabled) {
102 std::vector<ui::MouseEvent> events;
103
104 // We should not see any events initially.
105 EXPECT_FALSE(GetAutoclickController()->IsEnabled());
106 events = WaitForMouseEvents();
107 EXPECT_EQ(0u, events.size());
108
109 // Enable autoclick, and we should see a mouse pressed and
110 // a mouse released event, simulating a click.
111 GetAutoclickController()->SetEnabled(true);
112 GetEventGenerator().MoveMouseTo(0, 0);
113 EXPECT_TRUE(GetAutoclickController()->IsEnabled());
114 events = WaitForMouseEvents();
115 EXPECT_EQ(2u, events.size());
116 EXPECT_EQ(ui::ET_MOUSE_PRESSED, events[0].type());
117 EXPECT_EQ(ui::ET_MOUSE_RELEASED, events[1].type());
118
119 // We should not get any more clicks until we move the mouse.
120 events = WaitForMouseEvents();
121 EXPECT_EQ(0u, events.size());
122 GetEventGenerator().MoveMouseTo(30, 30);
123 events = WaitForMouseEvents();
124 EXPECT_EQ(2u, events.size());
125 EXPECT_EQ(ui::ET_MOUSE_PRESSED, events[0].type());
126 EXPECT_EQ(ui::ET_MOUSE_RELEASED, events[1].type());
127
128 // Disable autoclick, and we should see the original behaviour.
129 GetAutoclickController()->SetEnabled(false);
130 EXPECT_FALSE(GetAutoclickController()->IsEnabled());
131 events = WaitForMouseEvents();
132 EXPECT_EQ(0u, events.size());
133 }
134
TEST_F(AutoclickTest,MouseMovement)135 TEST_F(AutoclickTest, MouseMovement) {
136 std::vector<ui::MouseEvent> events;
137 GetAutoclickController()->SetEnabled(true);
138
139 gfx::Point p1(0, 0);
140 gfx::Point p2(20, 20);
141 gfx::Point p3(40, 40);
142
143 // Move mouse to p1.
144 GetEventGenerator().MoveMouseTo(p1);
145 events = WaitForMouseEvents();
146 EXPECT_EQ(2u, events.size());
147 EXPECT_EQ(p1.ToString(), events[0].root_location().ToString());
148 EXPECT_EQ(p1.ToString(), events[1].root_location().ToString());
149
150 // Move mouse to multiple locations and finally arrive at p3.
151 GetEventGenerator().MoveMouseTo(p2);
152 GetEventGenerator().MoveMouseTo(p1);
153 GetEventGenerator().MoveMouseTo(p3);
154 events = WaitForMouseEvents();
155 EXPECT_EQ(2u, events.size());
156 EXPECT_EQ(p3.ToString(), events[0].root_location().ToString());
157 EXPECT_EQ(p3.ToString(), events[1].root_location().ToString());
158 }
159
TEST_F(AutoclickTest,MovementThreshold)160 TEST_F(AutoclickTest, MovementThreshold) {
161 GetAutoclickController()->SetEnabled(true);
162 GetEventGenerator().MoveMouseTo(0, 0);
163 EXPECT_EQ(2u, WaitForMouseEvents().size());
164
165 // Small mouse movements should not trigger an autoclick.
166 GetEventGenerator().MoveMouseTo(1, 1);
167 EXPECT_EQ(0u, WaitForMouseEvents().size());
168 GetEventGenerator().MoveMouseTo(2, 2);
169 EXPECT_EQ(0u, WaitForMouseEvents().size());
170 GetEventGenerator().MoveMouseTo(0, 0);
171 EXPECT_EQ(0u, WaitForMouseEvents().size());
172
173 // A large mouse movement should trigger an autoclick.
174 GetEventGenerator().MoveMouseTo(100, 100);
175 EXPECT_EQ(2u, WaitForMouseEvents().size());
176 }
177
TEST_F(AutoclickTest,SingleKeyModifier)178 TEST_F(AutoclickTest, SingleKeyModifier) {
179 GetAutoclickController()->SetEnabled(true);
180 MoveMouseWithFlagsTo(20, 20, ui::EF_SHIFT_DOWN);
181 std::vector<ui::MouseEvent> events = WaitForMouseEvents();
182 EXPECT_EQ(2u, events.size());
183 EXPECT_EQ(ui::EF_SHIFT_DOWN, events[0].flags() & ui::EF_SHIFT_DOWN);
184 EXPECT_EQ(ui::EF_SHIFT_DOWN, events[1].flags() & ui::EF_SHIFT_DOWN);
185 }
186
TEST_F(AutoclickTest,MultipleKeyModifiers)187 TEST_F(AutoclickTest, MultipleKeyModifiers) {
188 GetAutoclickController()->SetEnabled(true);
189 ui::EventFlags modifier_flags = static_cast<ui::EventFlags>(
190 ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN | ui::EF_SHIFT_DOWN);
191 MoveMouseWithFlagsTo(30, 30, modifier_flags);
192 std::vector<ui::MouseEvent> events = WaitForMouseEvents();
193 EXPECT_EQ(2u, events.size());
194 EXPECT_EQ(modifier_flags, events[0].flags() & modifier_flags);
195 EXPECT_EQ(modifier_flags, events[1].flags() & modifier_flags);
196 }
197
TEST_F(AutoclickTest,KeyModifiersReleased)198 TEST_F(AutoclickTest, KeyModifiersReleased) {
199 GetAutoclickController()->SetEnabled(true);
200
201 ui::EventFlags modifier_flags = static_cast<ui::EventFlags>(
202 ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN | ui::EF_SHIFT_DOWN);
203 MoveMouseWithFlagsTo(12, 12, modifier_flags);
204
205 // Simulate releasing key modifiers by sending key released events.
206 GetEventGenerator().ReleaseKey(ui::VKEY_CONTROL,
207 static_cast<ui::EventFlags>(ui::EF_ALT_DOWN | ui::EF_SHIFT_DOWN));
208 GetEventGenerator().ReleaseKey(ui::VKEY_SHIFT, ui::EF_ALT_DOWN);
209
210 std::vector<ui::MouseEvent> events;
211 events = WaitForMouseEvents();
212 EXPECT_EQ(2u, events.size());
213 EXPECT_EQ(0, events[0].flags() & ui::EF_CONTROL_DOWN);
214 EXPECT_EQ(0, events[0].flags() & ui::EF_SHIFT_DOWN);
215 EXPECT_EQ(ui::EF_ALT_DOWN, events[0].flags() & ui::EF_ALT_DOWN);
216 }
217
TEST_F(AutoclickTest,ExtendedDisplay)218 TEST_F(AutoclickTest, ExtendedDisplay) {
219 UpdateDisplay("1280x1024,800x600");
220 RunAllPendingInMessageLoop();
221 aura::Window::Windows root_windows = Shell::GetAllRootWindows();
222 EXPECT_EQ(2u, root_windows.size());
223
224 GetAutoclickController()->SetEnabled(true);
225 std::vector<ui::MouseEvent> events;
226
227 // Test first root window.
228 aura::test::EventGenerator generator1(root_windows[0]);
229 generator1.MoveMouseTo(100, 200);
230 events = WaitForMouseEvents();
231 EXPECT_EQ(2u, events.size());
232 EXPECT_EQ(100, events[0].root_location().x());
233 EXPECT_EQ(200, events[0].root_location().y());
234
235 // Test second root window.
236 aura::test::EventGenerator generator2(root_windows[1]);
237 generator2.MoveMouseTo(300, 400);
238 events = WaitForMouseEvents();
239 EXPECT_EQ(2u, events.size());
240 EXPECT_EQ(300, events[0].root_location().x());
241 EXPECT_EQ(400, events[0].root_location().y());
242
243 // Test movement threshold between displays.
244 }
245
TEST_F(AutoclickTest,UserInputCancelsAutoclick)246 TEST_F(AutoclickTest, UserInputCancelsAutoclick) {
247 GetAutoclickController()->SetEnabled(true);
248 std::vector<ui::MouseEvent> events;
249
250 // Pressing a normal key should cancel the autoclick.
251 GetEventGenerator().MoveMouseTo(200, 200);
252 GetEventGenerator().PressKey(ui::VKEY_K, ui::EF_NONE);
253 GetEventGenerator().ReleaseKey(ui::VKEY_K, ui::EF_NONE);
254 events = WaitForMouseEvents();
255 EXPECT_EQ(0u, events.size());
256
257 // Pressing a modifier key should NOT cancel the autoclick.
258 GetEventGenerator().MoveMouseTo(100, 100);
259 GetEventGenerator().PressKey(ui::VKEY_SHIFT, ui::EF_SHIFT_DOWN);
260 GetEventGenerator().ReleaseKey(ui::VKEY_SHIFT, ui::EF_NONE);
261 events = WaitForMouseEvents();
262 EXPECT_EQ(2u, events.size());
263
264 // Performing a gesture should cancel the autoclick.
265 GetEventGenerator().MoveMouseTo(200, 200);
266 GetEventGenerator().GestureTapDownAndUp(gfx::Point(100, 100));
267 events = WaitForMouseEvents();
268 EXPECT_EQ(0u, events.size());
269
270 // Test another gesture.
271 GetEventGenerator().MoveMouseTo(100, 100);
272 GetEventGenerator().GestureScrollSequence(
273 gfx::Point(100, 100),
274 gfx::Point(200, 200),
275 base::TimeDelta::FromMilliseconds(200),
276 3);
277 events = WaitForMouseEvents();
278 EXPECT_EQ(0u, events.size());
279
280 // Test scroll events.
281 GetEventGenerator().MoveMouseTo(200, 200);
282 GetEventGenerator().ScrollSequence(
283 gfx::Point(100, 100), base::TimeDelta::FromMilliseconds(200),
284 0, 100, 3, 2);
285 events = WaitForMouseEvents();
286 EXPECT_EQ(0u, events.size());
287 }
288
289 } // namespace ash
290