• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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