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 17namespace ash { 18 19class MouseEventCapturer : public ui::EventHandler { 20 public: 21 MouseEventCapturer() { Reset(); } 22 virtual ~MouseEventCapturer() {} 23 24 void Reset() { 25 events_.clear(); 26 } 27 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 52 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 62class AutoclickTest : public test::AshTestBase { 63 public: 64 AutoclickTest() {} 65 virtual ~AutoclickTest() {} 66 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 76 virtual void TearDown() OVERRIDE { 77 Shell::GetInstance()->RemovePreTargetHandler(&mouse_event_capturer_); 78 test::AshTestBase::TearDown(); 79 } 80 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 87 const std::vector<ui::MouseEvent>& WaitForMouseEvents() { 88 mouse_event_capturer_.Reset(); 89 RunAllPendingInMessageLoop(); 90 return mouse_event_capturer_.captured_events(); 91 } 92 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 103TEST_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 137TEST_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 162TEST_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 180TEST_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 189TEST_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 200TEST_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 220TEST_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 248TEST_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 291TEST_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