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/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/keycodes/keyboard_codes.h"
15 #include "ui/events/test/event_generator.h"
16
17 namespace ash {
18
19 class MouseEventCapturer : public ui::EventHandler {
20 public:
MouseEventCapturer()21 MouseEventCapturer() { Reset(); }
~MouseEventCapturer()22 virtual ~MouseEventCapturer() {}
23
Reset()24 void Reset() {
25 events_.clear();
26 }
27
OnMouseEvent(ui::MouseEvent * event)28 virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE {
29 if (!(event->flags() & ui::EF_LEFT_MOUSE_BUTTON))
30 return;
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(
37 event->type(),
38 event->location(),
39 event->root_location(),
40 event->flags(),
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();
45 }
46
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);
50 }
51
captured_events() const52 const std::vector<ui::MouseEvent>& captured_events() const {
53 return events_;
54 }
55
56 private:
57 std::vector<ui::MouseEvent> events_;
58
59 DISALLOW_COPY_AND_ASSIGN(MouseEventCapturer);
60 };
61
62 class AutoclickTest : public test::AshTestBase {
63 public:
AutoclickTest()64 AutoclickTest() {}
~AutoclickTest()65 virtual ~AutoclickTest() {}
66
SetUp()67 virtual void SetUp() OVERRIDE {
68 test::AshTestBase::SetUp();
69 Shell::GetInstance()->AddPreTargetHandler(&mouse_event_capturer_);
70 GetAutoclickController()->SetAutoclickDelay(0);
71
72 // Move mouse to deterministic location at the start of each test.
73 GetEventGenerator().MoveMouseTo(100, 100);
74 }
75
TearDown()76 virtual void TearDown() OVERRIDE {
77 Shell::GetInstance()->RemovePreTargetHandler(&mouse_event_capturer_);
78 test::AshTestBase::TearDown();
79 }
80
MoveMouseWithFlagsTo(int x,int y,ui::EventFlags flags)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);
85 }
86
WaitForMouseEvents()87 const std::vector<ui::MouseEvent>& WaitForMouseEvents() {
88 mouse_event_capturer_.Reset();
89 RunAllPendingInMessageLoop();
90 return mouse_event_capturer_.captured_events();
91 }
92
GetAutoclickController()93 AutoclickController* GetAutoclickController() {
94 return Shell::GetInstance()->autoclick_controller();
95 }
96
97 private:
98 MouseEventCapturer mouse_event_capturer_;
99
100 DISALLOW_COPY_AND_ASSIGN(AutoclickTest);
101 };
102
TEST_F(AutoclickTest,ToggleEnabled)103 TEST_F(AutoclickTest, ToggleEnabled) {
104 std::vector<ui::MouseEvent> events;
105
106 // We should not see any events initially.
107 EXPECT_FALSE(GetAutoclickController()->IsEnabled());
108 events = WaitForMouseEvents();
109 EXPECT_EQ(0u, events.size());
110
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());
120
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());
129
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());
135 }
136
TEST_F(AutoclickTest,MouseMovement)137 TEST_F(AutoclickTest, MouseMovement) {
138 std::vector<ui::MouseEvent> events;
139 GetAutoclickController()->SetEnabled(true);
140
141 gfx::Point p1(0, 0);
142 gfx::Point p2(20, 20);
143 gfx::Point p3(40, 40);
144
145 // Move mouse to p1.
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());
151
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());
160 }
161
TEST_F(AutoclickTest,MovementThreshold)162 TEST_F(AutoclickTest, MovementThreshold) {
163 GetAutoclickController()->SetEnabled(true);
164 GetEventGenerator().MoveMouseTo(0, 0);
165 EXPECT_EQ(2u, WaitForMouseEvents().size());
166
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());
174
175 // A large mouse movement should trigger an autoclick.
176 GetEventGenerator().MoveMouseTo(100, 100);
177 EXPECT_EQ(2u, WaitForMouseEvents().size());
178 }
179
TEST_F(AutoclickTest,SingleKeyModifier)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);
187 }
188
TEST_F(AutoclickTest,MultipleKeyModifiers)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);
198 }
199
TEST_F(AutoclickTest,KeyModifiersReleased)200 TEST_F(AutoclickTest, KeyModifiersReleased) {
201 GetAutoclickController()->SetEnabled(true);
202
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);
206
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);
211
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);
218 }
219
TEST_F(AutoclickTest,ExtendedDisplay)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());
225
226 GetAutoclickController()->SetEnabled(true);
227 std::vector<ui::MouseEvent> events;
228
229 // Test first root window.
230 ui::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());
236
237 // Test second root window.
238 ui::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());
244
245 // Test movement threshold between displays.
246 }
247
TEST_F(AutoclickTest,UserInputCancelsAutoclick)248 TEST_F(AutoclickTest, UserInputCancelsAutoclick) {
249 GetAutoclickController()->SetEnabled(true);
250 std::vector<ui::MouseEvent> events;
251
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());
258
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());
265
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());
271
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),
278 3);
279 events = WaitForMouseEvents();
280 EXPECT_EQ(0u, events.size());
281
282 // Test scroll events.
283 GetEventGenerator().MoveMouseTo(200, 200);
284 GetEventGenerator().ScrollSequence(
285 gfx::Point(100, 100), base::TimeDelta::FromMilliseconds(200),
286 0, 100, 3, 2);
287 events = WaitForMouseEvents();
288 EXPECT_EQ(0u, events.size());
289 }
290
TEST_F(AutoclickTest,SynthesizedMouseMovesIgnored)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());
297
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)));
304 window->Show();
305 events = WaitForMouseEvents();
306 EXPECT_EQ(0u, events.size());
307 EXPECT_EQ("1 1 0", delegate.GetMouseMotionCountsAndReset());
308 }
309
310 } // namespace ash
311