• 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/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