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 16namespace ash { 17 18class MouseEventCapturer : public ui::EventHandler { 19 public: 20 MouseEventCapturer() { Reset(); } 21 virtual ~MouseEventCapturer() {} 22 23 void Reset() { 24 events_.clear(); 25 } 26 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 50 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 60class AutoclickTest : public test::AshTestBase { 61 public: 62 AutoclickTest() {} 63 virtual ~AutoclickTest() {} 64 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 74 virtual void TearDown() OVERRIDE { 75 Shell::GetInstance()->RemovePreTargetHandler(&mouse_event_capturer_); 76 test::AshTestBase::TearDown(); 77 } 78 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 85 const std::vector<ui::MouseEvent>& WaitForMouseEvents() { 86 mouse_event_capturer_.Reset(); 87 RunAllPendingInMessageLoop(); 88 return mouse_event_capturer_.captured_events(); 89 } 90 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 101TEST_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 135TEST_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 160TEST_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 178TEST_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 187TEST_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 198TEST_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 218TEST_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 246TEST_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