autoclick_unittest.cc 54 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359
  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. #include "ash/accessibility/accessibility_controller_impl.h"
  5. #include "ash/accessibility/autoclick/autoclick_controller.h"
  6. #include "ash/shelf/shelf.h"
  7. #include "ash/shell.h"
  8. #include "ash/system/accessibility/accessibility_feature_disable_dialog.h"
  9. #include "ash/system/accessibility/autoclick_menu_bubble_controller.h"
  10. #include "ash/system/accessibility/autoclick_menu_view.h"
  11. #include "ash/system/accessibility/autoclick_scroll_bubble_controller.h"
  12. #include "ash/system/accessibility/autoclick_scroll_view.h"
  13. #include "ash/system/unified/unified_system_tray.h"
  14. #include "ash/test/ash_test_base.h"
  15. #include "ash/wm/collision_detection/collision_detection_utils.h"
  16. #include "ash/wm/desks/desks_util.h"
  17. #include "ash/wm/window_state.h"
  18. #include "ash/wm/wm_event.h"
  19. #include "base/run_loop.h"
  20. #include "base/test/task_environment.h"
  21. #include "ui/aura/test/test_window_delegate.h"
  22. #include "ui/aura/window.h"
  23. #include "ui/aura/window_event_dispatcher.h"
  24. #include "ui/base/cursor/mojom/cursor_type.mojom-shared.h"
  25. #include "ui/display/manager/display_manager.h"
  26. #include "ui/events/event.h"
  27. #include "ui/events/event_constants.h"
  28. #include "ui/events/event_handler.h"
  29. #include "ui/events/event_utils.h"
  30. #include "ui/events/keycodes/keyboard_codes.h"
  31. #include "ui/events/test/event_generator.h"
  32. #include "ui/events/types/event_type.h"
  33. namespace ash {
  34. namespace {
  35. const int kScrollToMenuBoundsBuffer = 18;
  36. }
  37. class MouseEventCapturer : public ui::EventHandler {
  38. public:
  39. MouseEventCapturer() { Reset(); }
  40. MouseEventCapturer(const MouseEventCapturer&) = delete;
  41. MouseEventCapturer& operator=(const MouseEventCapturer&) = delete;
  42. ~MouseEventCapturer() override = default;
  43. void Reset() {
  44. events_.clear();
  45. wheel_events_.clear();
  46. }
  47. void OnMouseEvent(ui::MouseEvent* event) override {
  48. bool save_event = false;
  49. bool stop_event = false;
  50. // Filter out extraneous mouse events like mouse entered, exited,
  51. // capture changed, etc.
  52. ui::EventType type = event->type();
  53. if (type == ui::ET_MOUSE_PRESSED || type == ui::ET_MOUSE_RELEASED) {
  54. // Only track left and right mouse button events, ensuring that we get
  55. // left-click, right-click and double-click.
  56. if (!(event->flags() & ui::EF_LEFT_MOUSE_BUTTON) &&
  57. (!(event->flags() & ui::EF_RIGHT_MOUSE_BUTTON)))
  58. return;
  59. save_event = true;
  60. // Stop event propagation so we don't click on random stuff that
  61. // might break test assumptions.
  62. stop_event = true;
  63. } else if (type == ui::ET_MOUSE_DRAGGED) {
  64. save_event = true;
  65. stop_event = false;
  66. } else if (type == ui::ET_MOUSEWHEEL) {
  67. // Save it immediately as a MouseWheelEvent.
  68. wheel_events_.push_back(ui::MouseWheelEvent(
  69. event->AsMouseWheelEvent()->offset(), event->location(),
  70. event->root_location(), ui::EventTimeForNow(), event->flags(),
  71. event->changed_button_flags()));
  72. }
  73. if (save_event) {
  74. events_.push_back(ui::MouseEvent(event->type(), event->location(),
  75. event->root_location(),
  76. ui::EventTimeForNow(), event->flags(),
  77. event->changed_button_flags()));
  78. }
  79. if (stop_event)
  80. event->StopPropagation();
  81. // If there is a possibility that we're in an infinite loop, we should
  82. // exit early with a sensible error rather than letting the test time out.
  83. ASSERT_LT(events_.size(), 100u);
  84. }
  85. const std::vector<ui::MouseEvent>& captured_events() const { return events_; }
  86. const std::vector<ui::MouseWheelEvent>& captured_mouse_wheel_events() const {
  87. return wheel_events_;
  88. }
  89. private:
  90. std::vector<ui::MouseEvent> events_;
  91. std::vector<ui::MouseWheelEvent> wheel_events_;
  92. };
  93. class AutoclickTest : public AshTestBase {
  94. public:
  95. AutoclickTest()
  96. : AshTestBase(base::test::TaskEnvironment::TimeSource::MOCK_TIME) {}
  97. AutoclickTest(const AutoclickTest&) = delete;
  98. AutoclickTest& operator=(const AutoclickTest&) = delete;
  99. ~AutoclickTest() override = default;
  100. void SetUp() override {
  101. AshTestBase::SetUp();
  102. Shell::Get()->AddPreTargetHandler(&mouse_event_capturer_);
  103. GetAutoclickController()->SetAutoclickDelay(base::TimeDelta());
  104. // Move mouse to deterministic location at the start of each test.
  105. GetEventGenerator()->MoveMouseTo(100, 100);
  106. // Make sure the display is initialized so we don't fail the test due to any
  107. // input events caused from creating the display.
  108. Shell::Get()->display_manager()->UpdateDisplays();
  109. base::RunLoop().RunUntilIdle();
  110. }
  111. void TearDown() override {
  112. Shell::Get()->RemovePreTargetHandler(&mouse_event_capturer_);
  113. AshTestBase::TearDown();
  114. }
  115. void MoveMouseWithFlagsTo(int x, int y, ui::EventFlags flags) {
  116. GetEventGenerator()->set_flags(flags);
  117. GetEventGenerator()->MoveMouseTo(x, y);
  118. GetEventGenerator()->set_flags(ui::EF_NONE);
  119. }
  120. const std::vector<ui::MouseEvent>& WaitForMouseEvents() {
  121. ClearMouseEvents();
  122. // TODO(katie): Consider using quit closure instead of RunUntilIdle.
  123. base::RunLoop().RunUntilIdle();
  124. return GetMouseEvents();
  125. }
  126. void FastForwardBy(int milliseconds) {
  127. task_environment()->FastForwardBy(base::Milliseconds(milliseconds));
  128. }
  129. AutoclickController* GetAutoclickController() {
  130. return Shell::Get()->autoclick_controller();
  131. }
  132. // Calculates and returns full delay from the animation delay, after setting
  133. // that delay on the autoclick controller.
  134. int UpdateAnimationDelayAndGetFullDelay(float animation_delay) {
  135. float ratio =
  136. GetAutoclickController()->GetStartGestureDelayRatioForTesting();
  137. int full_delay = ceil(1.0 / ratio) * animation_delay;
  138. GetAutoclickController()->SetAutoclickDelay(base::Milliseconds(full_delay));
  139. return full_delay;
  140. }
  141. AutoclickMenuView* GetAutoclickMenuView() {
  142. return GetAutoclickController()
  143. ->GetMenuBubbleControllerForTesting()
  144. ->menu_view_;
  145. }
  146. AutoclickScrollView* GetAutoclickScrollView() {
  147. AutoclickScrollBubbleController* controller =
  148. GetAutoclickController()
  149. ->GetMenuBubbleControllerForTesting()
  150. ->scroll_bubble_controller_.get();
  151. return controller ? controller->scroll_view_ : nullptr;
  152. }
  153. views::Widget* GetAutoclickBubbleWidget() {
  154. return GetAutoclickController()
  155. ->GetMenuBubbleControllerForTesting()
  156. ->bubble_widget_;
  157. }
  158. views::View* GetMenuButton(AutoclickMenuView::ButtonId view_id) {
  159. AutoclickMenuView* menu_view = GetAutoclickMenuView();
  160. if (!menu_view)
  161. return nullptr;
  162. return menu_view->GetViewByID(static_cast<int>(view_id));
  163. }
  164. views::View* GetScrollButton(AutoclickScrollView::ButtonId view_id) {
  165. AutoclickScrollView* scroll_view = GetAutoclickScrollView();
  166. if (!scroll_view)
  167. return nullptr;
  168. return scroll_view->GetViewByID(static_cast<int>(view_id));
  169. }
  170. void ClearMouseEvents() { mouse_event_capturer_.Reset(); }
  171. const std::vector<ui::MouseEvent>& GetMouseEvents() {
  172. return mouse_event_capturer_.captured_events();
  173. }
  174. const std::vector<ui::MouseWheelEvent>& GetMouseWheelEvents() {
  175. return mouse_event_capturer_.captured_mouse_wheel_events();
  176. }
  177. private:
  178. MouseEventCapturer mouse_event_capturer_;
  179. };
  180. TEST_F(AutoclickTest, ToggleEnabled) {
  181. std::vector<ui::MouseEvent> events;
  182. // We should not see any events initially.
  183. EXPECT_FALSE(GetAutoclickController()->IsEnabled());
  184. events = WaitForMouseEvents();
  185. EXPECT_EQ(0u, events.size());
  186. // Enable autoclick, and we should see a mouse pressed and
  187. // a mouse released event, simulating a click.
  188. GetAutoclickController()->SetEnabled(true, false /* do not show dialog */);
  189. GetEventGenerator()->MoveMouseTo(0, 0);
  190. EXPECT_TRUE(GetAutoclickController()->IsEnabled());
  191. events = WaitForMouseEvents();
  192. ASSERT_EQ(2u, events.size());
  193. EXPECT_EQ(ui::ET_MOUSE_PRESSED, events[0].type());
  194. EXPECT_TRUE(ui::EF_LEFT_MOUSE_BUTTON & events[0].flags());
  195. EXPECT_EQ(ui::ET_MOUSE_RELEASED, events[1].type());
  196. EXPECT_TRUE(ui::EF_LEFT_MOUSE_BUTTON & events[1].flags());
  197. // We should not get any more clicks until we move the mouse.
  198. events = WaitForMouseEvents();
  199. EXPECT_EQ(0u, events.size());
  200. GetEventGenerator()->MoveMouseTo(30, 30);
  201. events = WaitForMouseEvents();
  202. ASSERT_EQ(2u, events.size());
  203. EXPECT_EQ(ui::ET_MOUSE_PRESSED, events[0].type());
  204. EXPECT_TRUE(ui::EF_LEFT_MOUSE_BUTTON & events[0].flags());
  205. EXPECT_EQ(ui::ET_MOUSE_RELEASED, events[1].type());
  206. EXPECT_TRUE(ui::EF_LEFT_MOUSE_BUTTON & events[1].flags());
  207. // Disable autoclick, and we should see the original behaviour.
  208. GetAutoclickController()->SetEnabled(false, false /* do not show dialog */);
  209. EXPECT_FALSE(GetAutoclickController()->IsEnabled());
  210. events = WaitForMouseEvents();
  211. EXPECT_EQ(0u, events.size());
  212. // After disable, autoclick should be set back to left click.
  213. EXPECT_EQ(AutoclickEventType::kLeftClick,
  214. Shell::Get()->accessibility_controller()->GetAutoclickEventType());
  215. }
  216. TEST_F(AutoclickTest, MouseMovement) {
  217. std::vector<ui::MouseEvent> events;
  218. GetAutoclickController()->SetEnabled(true, false /* do not show dialog */);
  219. gfx::Point p1(0, 0);
  220. gfx::Point p2(20, 20);
  221. gfx::Point p3(40, 40);
  222. // Move mouse to p1.
  223. GetEventGenerator()->MoveMouseTo(p1);
  224. events = WaitForMouseEvents();
  225. EXPECT_EQ(2u, events.size());
  226. EXPECT_EQ(p1.ToString(), events[0].root_location().ToString());
  227. EXPECT_EQ(p1.ToString(), events[1].root_location().ToString());
  228. // Move mouse to multiple locations and finally arrive at p3.
  229. GetEventGenerator()->MoveMouseTo(p2);
  230. GetEventGenerator()->MoveMouseTo(p1);
  231. GetEventGenerator()->MoveMouseTo(p3);
  232. events = WaitForMouseEvents();
  233. EXPECT_EQ(2u, events.size());
  234. EXPECT_EQ(p3.ToString(), events[0].root_location().ToString());
  235. EXPECT_EQ(p3.ToString(), events[1].root_location().ToString());
  236. }
  237. TEST_F(AutoclickTest, MovementThreshold) {
  238. UpdateDisplay("1280x1024,800x600");
  239. base::RunLoop().RunUntilIdle();
  240. aura::Window::Windows root_windows = Shell::GetAllRootWindows();
  241. EXPECT_EQ(2u, root_windows.size());
  242. int animation_delay = 5;
  243. const struct {
  244. int movement_threshold;
  245. bool stabilize_click_position;
  246. } kTestCases[] = {
  247. {10, false}, {20, false}, {30, false}, {40, false}, {50, false},
  248. {10, true}, {20, true}, {30, true}, {40, true}, {50, true},
  249. };
  250. for (const auto& test : kTestCases) {
  251. GetAutoclickController()->set_stabilize_click_position(
  252. test.stabilize_click_position);
  253. int movement_threshold = test.movement_threshold;
  254. GetAutoclickController()->SetMovementThreshold(movement_threshold);
  255. // Run test for the secondary display too to test fix for crbug.com/449870.
  256. for (auto* root_window : root_windows) {
  257. gfx::Point center = root_window->GetBoundsInScreen().CenterPoint();
  258. GetAutoclickController()->SetEnabled(true,
  259. false /* do not show dialog */);
  260. GetEventGenerator()->MoveMouseTo(center);
  261. ClearMouseEvents();
  262. EXPECT_EQ(2u, WaitForMouseEvents().size());
  263. // Small mouse movements should not trigger an autoclick, i.e. movements
  264. // within the radius of the movement_threshold.
  265. GetEventGenerator()->MoveMouseTo(
  266. center + gfx::Vector2d(std::sqrt(movement_threshold) - 1,
  267. std::sqrt(movement_threshold) - 1));
  268. EXPECT_EQ(0u, WaitForMouseEvents().size());
  269. GetEventGenerator()->MoveMouseTo(
  270. center + gfx::Vector2d(movement_threshold - 1, 0));
  271. EXPECT_EQ(0u, WaitForMouseEvents().size());
  272. GetEventGenerator()->MoveMouseTo(
  273. center + gfx::Vector2d(0, -movement_threshold + 1));
  274. EXPECT_EQ(0u, WaitForMouseEvents().size());
  275. GetEventGenerator()->MoveMouseTo(center);
  276. EXPECT_EQ(0u, WaitForMouseEvents().size());
  277. // A larger mouse movement should trigger an autoclick.
  278. GetEventGenerator()->MoveMouseTo(
  279. center +
  280. gfx::Vector2d(movement_threshold + 1, movement_threshold + 1));
  281. EXPECT_EQ(2u, WaitForMouseEvents().size());
  282. // Moving outside the threshold after the gesture begins should cancel
  283. // the autoclick. Update the delay so we can do events between the initial
  284. // trigger of the feature and the click.
  285. int full_delay = UpdateAnimationDelayAndGetFullDelay(animation_delay);
  286. GetEventGenerator()->MoveMouseTo(
  287. center - gfx::Vector2d(movement_threshold, movement_threshold));
  288. FastForwardBy(animation_delay + 1);
  289. GetEventGenerator()->MoveMouseTo(center);
  290. ClearMouseEvents();
  291. // After a time, a new click will occur at the second location. The first
  292. // location should never get a click.
  293. FastForwardBy(full_delay * 2);
  294. EXPECT_EQ(2u, GetMouseEvents().size());
  295. gfx::Rect display_bounds = display::Screen::GetScreen()
  296. ->GetDisplayNearestWindow(root_window)
  297. .bounds();
  298. EXPECT_EQ(center - gfx::Vector2d(display_bounds.origin().x(),
  299. display_bounds.origin().y()),
  300. GetMouseEvents()[0].location());
  301. // Move it out of the way so the next cycle starts properly.
  302. GetEventGenerator()->MoveMouseTo(gfx::Point(0, 0));
  303. GetAutoclickController()->SetAutoclickDelay(base::TimeDelta());
  304. }
  305. }
  306. // Reset to defaults.
  307. GetAutoclickController()->SetMovementThreshold(20);
  308. GetAutoclickController()->set_stabilize_click_position(false);
  309. }
  310. TEST_F(AutoclickTest, MovementWithinThresholdWhileTimerRunning) {
  311. GetAutoclickController()->SetEnabled(true, false /* do not show dialog */);
  312. GetAutoclickController()->SetMovementThreshold(20);
  313. int animation_delay = 5;
  314. int full_delay = UpdateAnimationDelayAndGetFullDelay(animation_delay);
  315. GetAutoclickController()->set_stabilize_click_position(true);
  316. GetEventGenerator()->MoveMouseTo(100, 100);
  317. FastForwardBy(animation_delay + 1);
  318. // Move the mouse within the threshold. It shouldn't change the eventual
  319. // target of the event, or cancel the click.
  320. GetEventGenerator()->MoveMouseTo(110, 110);
  321. ClearMouseEvents();
  322. FastForwardBy(full_delay);
  323. std::vector<ui::MouseEvent> events = GetMouseEvents();
  324. EXPECT_EQ(2u, events.size());
  325. EXPECT_EQ(gfx::Point(100, 100), events[0].location());
  326. EXPECT_EQ(ui::ET_MOUSE_PRESSED, events[0].type());
  327. EXPECT_EQ(ui::EF_LEFT_MOUSE_BUTTON, events[0].flags());
  328. EXPECT_EQ(gfx::Point(100, 100), events[1].location());
  329. EXPECT_EQ(ui::ET_MOUSE_RELEASED, events[1].type());
  330. EXPECT_EQ(ui::EF_LEFT_MOUSE_BUTTON, events[1].flags());
  331. // When the click position is not stabilized, the mouse movement should
  332. // translate into the target of the event, but not cancel the click.
  333. GetAutoclickController()->set_stabilize_click_position(false);
  334. GetEventGenerator()->MoveMouseTo(200, 200);
  335. FastForwardBy(animation_delay + 1);
  336. GetEventGenerator()->MoveMouseTo(210, 210);
  337. ClearMouseEvents();
  338. FastForwardBy(full_delay);
  339. events = GetMouseEvents();
  340. EXPECT_EQ(2u, events.size());
  341. EXPECT_EQ(gfx::Point(210, 210), events[0].location());
  342. EXPECT_EQ(ui::ET_MOUSE_PRESSED, events[0].type());
  343. EXPECT_EQ(ui::EF_LEFT_MOUSE_BUTTON, events[0].flags());
  344. EXPECT_EQ(gfx::Point(210, 210), events[1].location());
  345. EXPECT_EQ(ui::ET_MOUSE_RELEASED, events[1].type());
  346. EXPECT_EQ(ui::EF_LEFT_MOUSE_BUTTON, events[1].flags());
  347. // Reset delay.
  348. GetAutoclickController()->SetAutoclickDelay(base::TimeDelta());
  349. }
  350. TEST_F(AutoclickTest, SingleKeyModifier) {
  351. GetAutoclickController()->SetEnabled(true, false /* do not show dialog */);
  352. MoveMouseWithFlagsTo(20, 20, ui::EF_SHIFT_DOWN);
  353. std::vector<ui::MouseEvent> events = WaitForMouseEvents();
  354. EXPECT_EQ(2u, events.size());
  355. EXPECT_EQ(ui::EF_SHIFT_DOWN, events[0].flags() & ui::EF_SHIFT_DOWN);
  356. EXPECT_EQ(ui::EF_SHIFT_DOWN, events[1].flags() & ui::EF_SHIFT_DOWN);
  357. }
  358. TEST_F(AutoclickTest, MultipleKeyModifiers) {
  359. GetAutoclickController()->SetEnabled(true, false /* do not show dialog */);
  360. ui::EventFlags modifier_flags = static_cast<ui::EventFlags>(
  361. ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN | ui::EF_SHIFT_DOWN);
  362. MoveMouseWithFlagsTo(30, 30, modifier_flags);
  363. std::vector<ui::MouseEvent> events = WaitForMouseEvents();
  364. EXPECT_EQ(2u, events.size());
  365. EXPECT_EQ(modifier_flags, events[0].flags() & modifier_flags);
  366. EXPECT_EQ(modifier_flags, events[1].flags() & modifier_flags);
  367. }
  368. TEST_F(AutoclickTest, KeyModifiersReleased) {
  369. GetAutoclickController()->SetEnabled(true, false /* do not show dialog */);
  370. ui::EventFlags modifier_flags = static_cast<ui::EventFlags>(
  371. ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN | ui::EF_SHIFT_DOWN);
  372. MoveMouseWithFlagsTo(12, 12, modifier_flags);
  373. // Simulate releasing key modifiers by sending key released events.
  374. GetEventGenerator()->ReleaseKey(
  375. ui::VKEY_CONTROL,
  376. static_cast<ui::EventFlags>(ui::EF_ALT_DOWN | ui::EF_SHIFT_DOWN));
  377. GetEventGenerator()->ReleaseKey(ui::VKEY_SHIFT, ui::EF_ALT_DOWN);
  378. std::vector<ui::MouseEvent> events;
  379. events = WaitForMouseEvents();
  380. EXPECT_EQ(2u, events.size());
  381. EXPECT_EQ(0, events[0].flags() & ui::EF_CONTROL_DOWN);
  382. EXPECT_EQ(0, events[0].flags() & ui::EF_SHIFT_DOWN);
  383. EXPECT_EQ(ui::EF_ALT_DOWN, events[0].flags() & ui::EF_ALT_DOWN);
  384. }
  385. TEST_F(AutoclickTest, UserInputCancelsAutoclick) {
  386. GetAutoclickController()->SetEnabled(true, false /* do not show dialog */);
  387. std::vector<ui::MouseEvent> events;
  388. // Pressing a normal key should cancel the autoclick.
  389. GetEventGenerator()->MoveMouseTo(200, 200);
  390. GetEventGenerator()->PressKey(ui::VKEY_K, ui::EF_NONE);
  391. GetEventGenerator()->ReleaseKey(ui::VKEY_K, ui::EF_NONE);
  392. events = WaitForMouseEvents();
  393. EXPECT_EQ(0u, events.size());
  394. // Pressing a modifier key should NOT cancel the autoclick.
  395. GetEventGenerator()->MoveMouseTo(100, 100);
  396. GetEventGenerator()->PressKey(ui::VKEY_SHIFT, ui::EF_SHIFT_DOWN);
  397. GetEventGenerator()->ReleaseKey(ui::VKEY_SHIFT, ui::EF_NONE);
  398. events = WaitForMouseEvents();
  399. EXPECT_EQ(2u, events.size());
  400. // Mouse-wheel scroll events should cancel the autoclick.
  401. GetEventGenerator()->MoveMouseTo(300, 300);
  402. GetEventGenerator()->MoveMouseWheel(0, 20);
  403. events = WaitForMouseEvents();
  404. EXPECT_EQ(0u, events.size());
  405. // Performing a gesture should cancel the autoclick.
  406. GetEventGenerator()->MoveMouseTo(200, 200);
  407. GetEventGenerator()->GestureTapDownAndUp(gfx::Point(100, 100));
  408. events = WaitForMouseEvents();
  409. EXPECT_EQ(0u, events.size());
  410. // Test another gesture.
  411. GetEventGenerator()->MoveMouseTo(100, 100);
  412. GetEventGenerator()->GestureScrollSequence(
  413. gfx::Point(100, 100), gfx::Point(200, 200), base::Milliseconds(200), 3);
  414. events = WaitForMouseEvents();
  415. EXPECT_EQ(0u, events.size());
  416. // Test scroll events.
  417. GetEventGenerator()->MoveMouseTo(200, 200);
  418. GetEventGenerator()->ScrollSequence(gfx::Point(100, 100),
  419. base::Milliseconds(200), 0, 100, 3, 2);
  420. events = WaitForMouseEvents();
  421. EXPECT_EQ(0u, events.size());
  422. // However, just starting a scroll doesn't cancel. If you tap a touchpad on
  423. // an Eve chromebook, for example, it can send an ET_SCROLL_FLING_CANCEL
  424. // event, which shouldn't actually cancel autoclick.
  425. GetEventGenerator()->MoveMouseTo(100, 100);
  426. GetEventGenerator()->ScrollSequence(gfx::Point(100, 100), base::TimeDelta(),
  427. 0, 0, 0, 1);
  428. events = WaitForMouseEvents();
  429. EXPECT_EQ(2u, events.size());
  430. }
  431. TEST_F(AutoclickTest, SynthesizedMouseMovesIgnored) {
  432. GetAutoclickController()->SetEnabled(true, false /* do not show dialog */);
  433. std::vector<ui::MouseEvent> events;
  434. GetEventGenerator()->MoveMouseTo(100, 100);
  435. events = WaitForMouseEvents();
  436. EXPECT_EQ(2u, events.size());
  437. // Show a window and make sure the new window is under the cursor. As a
  438. // result, synthesized mouse events will be dispatched to the window, but it
  439. // should not trigger an autoclick.
  440. aura::test::EventCountDelegate delegate;
  441. std::unique_ptr<aura::Window> window(CreateTestWindowInShellWithDelegate(
  442. &delegate, 123, gfx::Rect(50, 50, 100, 100)));
  443. window->Show();
  444. events = WaitForMouseEvents();
  445. EXPECT_EQ(0u, events.size());
  446. EXPECT_EQ("1 1 0", delegate.GetMouseMotionCountsAndReset());
  447. }
  448. TEST_F(AutoclickTest, AutoclickChangeEventTypes) {
  449. GetAutoclickController()->SetEnabled(true, false /* do not show dialog */);
  450. GetAutoclickController()->set_revert_to_left_click(false);
  451. GetAutoclickController()->SetAutoclickEventType(
  452. AutoclickEventType::kRightClick);
  453. std::vector<ui::MouseEvent> events;
  454. GetEventGenerator()->MoveMouseTo(30, 30);
  455. events = WaitForMouseEvents();
  456. ASSERT_EQ(2u, events.size());
  457. EXPECT_EQ(ui::ET_MOUSE_PRESSED, events[0].type());
  458. EXPECT_TRUE(ui::EF_RIGHT_MOUSE_BUTTON & events[0].flags());
  459. EXPECT_EQ(ui::ET_MOUSE_RELEASED, events[1].type());
  460. EXPECT_TRUE(ui::EF_RIGHT_MOUSE_BUTTON & events[1].flags());
  461. // Changing the event type cancels the event
  462. GetEventGenerator()->MoveMouseTo(60, 60);
  463. GetAutoclickController()->SetAutoclickEventType(
  464. AutoclickEventType::kLeftClick);
  465. events = WaitForMouseEvents();
  466. EXPECT_EQ(0u, events.size());
  467. // Changing the event type to the same thing does not cancel the event.
  468. // kLeftClick type does not produce a double-click.
  469. GetEventGenerator()->MoveMouseTo(90, 90);
  470. GetAutoclickController()->SetAutoclickEventType(
  471. AutoclickEventType::kLeftClick);
  472. events = WaitForMouseEvents();
  473. ASSERT_EQ(2u, events.size());
  474. EXPECT_EQ(ui::ET_MOUSE_PRESSED, events[0].type());
  475. EXPECT_TRUE(ui::EF_LEFT_MOUSE_BUTTON & events[0].flags());
  476. EXPECT_FALSE(ui::EF_IS_DOUBLE_CLICK & events[0].flags());
  477. EXPECT_EQ(ui::ET_MOUSE_RELEASED, events[1].type());
  478. EXPECT_TRUE(ui::EF_LEFT_MOUSE_BUTTON & events[1].flags());
  479. EXPECT_FALSE(ui::EF_IS_DOUBLE_CLICK & events[1].flags());
  480. // Double-click works as expected.
  481. GetAutoclickController()->SetAutoclickEventType(
  482. AutoclickEventType::kDoubleClick);
  483. GetEventGenerator()->MoveMouseTo(120, 120);
  484. events = WaitForMouseEvents();
  485. ASSERT_EQ(4u, events.size());
  486. EXPECT_EQ(ui::ET_MOUSE_PRESSED, events[0].type());
  487. EXPECT_TRUE(ui::EF_LEFT_MOUSE_BUTTON & events[0].flags());
  488. EXPECT_FALSE(ui::EF_IS_DOUBLE_CLICK & events[0].flags());
  489. EXPECT_EQ(ui::ET_MOUSE_RELEASED, events[1].type());
  490. EXPECT_TRUE(ui::EF_LEFT_MOUSE_BUTTON & events[1].flags());
  491. EXPECT_FALSE(ui::EF_IS_DOUBLE_CLICK & events[1].flags());
  492. EXPECT_EQ(ui::ET_MOUSE_PRESSED, events[2].type());
  493. EXPECT_TRUE(ui::EF_LEFT_MOUSE_BUTTON & events[2].flags());
  494. EXPECT_TRUE(ui::EF_IS_DOUBLE_CLICK & events[2].flags());
  495. EXPECT_EQ(ui::ET_MOUSE_RELEASED, events[3].type());
  496. EXPECT_TRUE(ui::EF_LEFT_MOUSE_BUTTON & events[3].flags());
  497. EXPECT_TRUE(ui::EF_IS_DOUBLE_CLICK & events[3].flags());
  498. // Pause / no action does not cause events to be generated even when the
  499. // mouse moves.
  500. GetAutoclickController()->SetAutoclickEventType(
  501. AutoclickEventType::kNoAction);
  502. GetEventGenerator()->MoveMouseTo(120, 120);
  503. events = WaitForMouseEvents();
  504. EXPECT_EQ(0u, events.size());
  505. }
  506. TEST_F(AutoclickTest, AutoclickDragAndDropEvents) {
  507. GetAutoclickController()->SetEnabled(true, false /* do not show dialog */);
  508. GetAutoclickController()->set_revert_to_left_click(false);
  509. GetAutoclickController()->SetAutoclickEventType(
  510. AutoclickEventType::kDragAndDrop);
  511. std::vector<ui::MouseEvent> events;
  512. GetEventGenerator()->MoveMouseTo(30, 30);
  513. events = WaitForMouseEvents();
  514. ASSERT_EQ(1u, events.size());
  515. EXPECT_EQ(ui::ET_MOUSE_PRESSED, events[0].type());
  516. EXPECT_TRUE(ui::EF_LEFT_MOUSE_BUTTON & events[0].flags());
  517. ClearMouseEvents();
  518. GetEventGenerator()->MoveMouseTo(60, 60);
  519. events = GetMouseEvents();
  520. ASSERT_EQ(1u, events.size());
  521. EXPECT_EQ(ui::ET_MOUSE_DRAGGED, events[0].type());
  522. // Another move creates a drag
  523. ClearMouseEvents();
  524. GetEventGenerator()->MoveMouseTo(90, 90);
  525. events = GetMouseEvents();
  526. ASSERT_EQ(1u, events.size());
  527. EXPECT_EQ(ui::ET_MOUSE_DRAGGED, events[0].type());
  528. // Waiting in place creates the released event.
  529. events = WaitForMouseEvents();
  530. ASSERT_EQ(1u, events.size());
  531. EXPECT_EQ(ui::ET_MOUSE_RELEASED, events[0].type());
  532. }
  533. TEST_F(AutoclickTest, AutoclickScrollEvents) {
  534. UpdateDisplay("800x600");
  535. GetAutoclickController()->SetEnabled(true, false /* do not show dialog */);
  536. GetAutoclickController()->SetAutoclickEventType(AutoclickEventType::kScroll);
  537. std::vector<ui::MouseEvent> events;
  538. std::vector<ui::MouseWheelEvent> wheel_events;
  539. // Expect that the first scroll action occurs at the middle of the screen,
  540. // since the position has not been set by the user.
  541. GetAutoclickController()->DoScrollAction(
  542. AutoclickController::ScrollPadAction::kScrollUp);
  543. events = GetMouseEvents();
  544. wheel_events = GetMouseWheelEvents();
  545. EXPECT_EQ(0u, events.size());
  546. ASSERT_EQ(1u, wheel_events.size());
  547. EXPECT_EQ(ui::ET_MOUSEWHEEL, wheel_events[0].type());
  548. EXPECT_EQ(gfx::Point(400, 300), wheel_events[0].location());
  549. EXPECT_GT(wheel_events[0].y_offset(), 0);
  550. ClearMouseEvents();
  551. // Expect that a dwell will set the scroll location.
  552. GetEventGenerator()->MoveMouseTo(90, 90);
  553. base::RunLoop().RunUntilIdle();
  554. GetAutoclickController()->DoScrollAction(
  555. AutoclickController::ScrollPadAction::kScrollUp);
  556. events = GetMouseEvents();
  557. wheel_events = GetMouseWheelEvents();
  558. EXPECT_EQ(0u, events.size());
  559. ASSERT_EQ(1u, wheel_events.size());
  560. EXPECT_EQ(ui::ET_MOUSEWHEEL, wheel_events[0].type());
  561. EXPECT_EQ(gfx::Point(90, 90), wheel_events[0].location());
  562. EXPECT_GT(wheel_events[0].y_offset(), 0);
  563. ClearMouseEvents();
  564. GetAutoclickController()->DoScrollAction(
  565. AutoclickController::ScrollPadAction::kScrollLeft);
  566. events = GetMouseEvents();
  567. wheel_events = GetMouseWheelEvents();
  568. EXPECT_EQ(0u, events.size());
  569. ASSERT_EQ(1u, wheel_events.size());
  570. EXPECT_EQ(ui::ET_MOUSEWHEEL, wheel_events[0].type());
  571. EXPECT_EQ(gfx::Point(90, 90), wheel_events[0].location());
  572. EXPECT_GT(wheel_events[0].x_offset(), 0);
  573. ClearMouseEvents();
  574. // Try another position, and the other two types of scroll action.
  575. GetEventGenerator()->MoveMouseTo(200, 200);
  576. base::RunLoop().RunUntilIdle();
  577. GetAutoclickController()->DoScrollAction(
  578. AutoclickController::ScrollPadAction::kScrollDown);
  579. events = GetMouseEvents();
  580. wheel_events = GetMouseWheelEvents();
  581. EXPECT_EQ(0u, events.size());
  582. ASSERT_EQ(1u, wheel_events.size());
  583. EXPECT_EQ(ui::ET_MOUSEWHEEL, wheel_events[0].type());
  584. EXPECT_EQ(gfx::Point(200, 200), wheel_events[0].location());
  585. EXPECT_LT(wheel_events[0].y_offset(), 0);
  586. ClearMouseEvents();
  587. GetAutoclickController()->DoScrollAction(
  588. AutoclickController::ScrollPadAction::kScrollRight);
  589. events = GetMouseEvents();
  590. wheel_events = GetMouseWheelEvents();
  591. EXPECT_EQ(0u, events.size());
  592. ASSERT_EQ(1u, wheel_events.size());
  593. EXPECT_EQ(ui::ET_MOUSEWHEEL, wheel_events[0].type());
  594. EXPECT_EQ(gfx::Point(200, 200), wheel_events[0].location());
  595. EXPECT_LT(wheel_events[0].x_offset(), 0);
  596. ClearMouseEvents();
  597. }
  598. TEST_F(AutoclickTest, AutoclickRevertsToLeftClick) {
  599. GetAutoclickController()->SetEnabled(true, false /* do not show dialog */);
  600. GetAutoclickController()->set_revert_to_left_click(true);
  601. GetAutoclickController()->SetAutoclickEventType(
  602. AutoclickEventType::kRightClick);
  603. std::vector<ui::MouseEvent> events;
  604. GetEventGenerator()->MoveMouseTo(30, 30);
  605. events = WaitForMouseEvents();
  606. ASSERT_EQ(2u, events.size());
  607. EXPECT_TRUE(ui::EF_RIGHT_MOUSE_BUTTON & events[0].flags());
  608. EXPECT_TRUE(ui::EF_RIGHT_MOUSE_BUTTON & events[1].flags());
  609. // Another event is now left-click; we've reverted to left click.
  610. GetEventGenerator()->MoveMouseTo(90, 90);
  611. GetAutoclickController()->SetAutoclickEventType(
  612. AutoclickEventType::kLeftClick);
  613. events = WaitForMouseEvents();
  614. ASSERT_EQ(2u, events.size());
  615. EXPECT_TRUE(ui::EF_LEFT_MOUSE_BUTTON & events[0].flags());
  616. EXPECT_TRUE(ui::EF_LEFT_MOUSE_BUTTON & events[1].flags());
  617. // The next event is also a left click.
  618. GetEventGenerator()->MoveMouseTo(120, 120);
  619. GetAutoclickController()->SetAutoclickEventType(
  620. AutoclickEventType::kLeftClick);
  621. events = WaitForMouseEvents();
  622. ASSERT_EQ(2u, events.size());
  623. EXPECT_TRUE(ui::EF_LEFT_MOUSE_BUTTON & events[0].flags());
  624. EXPECT_TRUE(ui::EF_LEFT_MOUSE_BUTTON & events[1].flags());
  625. // Changing revert to false doesn't change that we are on left click at
  626. // present.
  627. GetAutoclickController()->set_revert_to_left_click(false);
  628. GetEventGenerator()->MoveMouseTo(150, 150);
  629. GetAutoclickController()->SetAutoclickEventType(
  630. AutoclickEventType::kLeftClick);
  631. events = WaitForMouseEvents();
  632. ASSERT_EQ(2u, events.size());
  633. EXPECT_TRUE(ui::EF_LEFT_MOUSE_BUTTON & events[0].flags());
  634. EXPECT_TRUE(ui::EF_LEFT_MOUSE_BUTTON & events[1].flags());
  635. // But we should no longer revert to left click if the type is something else.
  636. GetAutoclickController()->SetAutoclickEventType(
  637. AutoclickEventType::kRightClick);
  638. GetEventGenerator()->MoveMouseTo(180, 180);
  639. events = WaitForMouseEvents();
  640. ASSERT_EQ(2u, events.size());
  641. EXPECT_TRUE(ui::EF_RIGHT_MOUSE_BUTTON & events[0].flags());
  642. EXPECT_TRUE(ui::EF_RIGHT_MOUSE_BUTTON & events[1].flags());
  643. // Should still be right click.
  644. GetEventGenerator()->MoveMouseTo(210, 210);
  645. events = WaitForMouseEvents();
  646. ASSERT_EQ(2u, events.size());
  647. EXPECT_TRUE(ui::EF_RIGHT_MOUSE_BUTTON & events[0].flags());
  648. EXPECT_TRUE(ui::EF_RIGHT_MOUSE_BUTTON & events[1].flags());
  649. }
  650. TEST_F(AutoclickTest, WaitsToDrawAnimationAfterDwellBegins) {
  651. int animation_delay = 5;
  652. int full_delay = UpdateAnimationDelayAndGetFullDelay(animation_delay);
  653. GetAutoclickController()->SetEnabled(true, false /* do not show dialog */);
  654. std::vector<ui::MouseEvent> events;
  655. // Start a dwell at (210, 210).
  656. GetEventGenerator()->MoveMouseTo(210, 210);
  657. // The center should change to (205, 205) if the adjustment is made before
  658. // the animation starts.
  659. FastForwardBy(animation_delay - 1);
  660. GetEventGenerator()->MoveMouseTo(205, 205);
  661. // Now wait the full delay to ensure the click has happened, then check
  662. // the result.
  663. FastForwardBy(full_delay);
  664. events = GetMouseEvents();
  665. ASSERT_EQ(2u, events.size());
  666. EXPECT_EQ(gfx::Point(205, 205), events[0].location());
  667. // Start another dwell at (100, 100).
  668. ClearMouseEvents();
  669. GetEventGenerator()->MoveMouseTo(100, 100);
  670. // Move the mouse a little to (105, 105), which should become the center.
  671. FastForwardBy(animation_delay - 1);
  672. GetEventGenerator()->MoveMouseTo(105, 105);
  673. // Moving the mouse during the animation changes the center point.
  674. FastForwardBy(animation_delay);
  675. GetEventGenerator()->MoveMouseTo(110, 110);
  676. // Now wait until the click. It should be at the center point from before
  677. // the animation started.
  678. FastForwardBy(full_delay);
  679. events = GetMouseEvents();
  680. ASSERT_EQ(2u, events.size());
  681. EXPECT_EQ(gfx::Point(110, 110), events[0].location());
  682. // Turn off stabilize_click_position and try again, the position should update
  683. // with the cursor's new position until the click occurs.
  684. GetAutoclickController()->set_stabilize_click_position(true);
  685. ClearMouseEvents();
  686. GetEventGenerator()->MoveMouseTo(200, 200);
  687. // (205, 205) will become the center of the animation.
  688. FastForwardBy(animation_delay - 1);
  689. GetEventGenerator()->MoveMouseTo(205, 205);
  690. // Fast forward until the animation would have started. Now moving the mouse
  691. // a little does not change the center point because we have stabilize on.
  692. FastForwardBy(animation_delay);
  693. GetEventGenerator()->MoveMouseTo(210, 210);
  694. FastForwardBy(full_delay);
  695. events = GetMouseEvents();
  696. ASSERT_EQ(2u, events.size());
  697. EXPECT_EQ(gfx::Point(205, 205), events[0].location());
  698. // Reset state.
  699. GetAutoclickController()->set_stabilize_click_position(false);
  700. }
  701. TEST_F(AutoclickTest, DoesActionOnBubbleWhenInDifferentModes) {
  702. AccessibilityControllerImpl* accessibility_controller =
  703. Shell::Get()->accessibility_controller();
  704. // Enable autoclick from the accessibility controller so that the bubble is
  705. // constructed too.
  706. accessibility_controller->autoclick().SetEnabled(true);
  707. GetAutoclickController()->set_revert_to_left_click(false);
  708. std::vector<ui::MouseEvent> events;
  709. // Test at different screen sizes and densities because the fake click on
  710. // the button involves coordinating between dips and pixels. Try two different
  711. // positions to ensure offsets are calculated correctly.
  712. const struct {
  713. const std::string display_spec;
  714. float scale;
  715. FloatingMenuPosition position;
  716. } kTestCases[] = {
  717. {"800x600", 1.0f, FloatingMenuPosition::kBottomRight},
  718. {"1024x800*2.0", 2.0f, FloatingMenuPosition::kBottomRight},
  719. {"800x600", 1.0f, FloatingMenuPosition::kTopLeft},
  720. {"1024x800*2.0", 2.0f, FloatingMenuPosition::kTopLeft},
  721. };
  722. for (const auto& test : kTestCases) {
  723. UpdateDisplay(test.display_spec);
  724. accessibility_controller->SetAutoclickMenuPosition(test.position);
  725. accessibility_controller->SetAutoclickEventType(
  726. AutoclickEventType::kRightClick);
  727. AutoclickMenuView* menu = GetAutoclickMenuView();
  728. ASSERT_TRUE(menu);
  729. // Outside of the bubble, a right-click still occurs.
  730. // Move to a central position which will not have any menu but will still be
  731. // on-screen.
  732. GetEventGenerator()->MoveMouseTo(200 * test.scale, 200 * test.scale);
  733. events = WaitForMouseEvents();
  734. ASSERT_EQ(2u, events.size());
  735. EXPECT_TRUE(ui::EF_RIGHT_MOUSE_BUTTON & events[0].flags());
  736. EXPECT_TRUE(ui::EF_RIGHT_MOUSE_BUTTON & events[1].flags());
  737. // Over the bubble, we get no real click, although the autoclick event
  738. // type does get changed properly over a button.
  739. gfx::Point button_location = gfx::ScaleToRoundedPoint(
  740. GetMenuButton(AutoclickMenuView::ButtonId::kDoubleClick)
  741. ->GetBoundsInScreen()
  742. .CenterPoint(),
  743. test.scale);
  744. GetEventGenerator()->MoveMouseTo(button_location);
  745. events = WaitForMouseEvents();
  746. EXPECT_EQ(0u, events.size());
  747. // But the event type did change with a the hover on the button.
  748. EXPECT_EQ(AutoclickEventType::kDoubleClick,
  749. accessibility_controller->GetAutoclickEventType());
  750. // Change to a pause action type.
  751. accessibility_controller->SetAutoclickEventType(
  752. AutoclickEventType::kNoAction);
  753. // Outside the bubble, no action occurs.
  754. GetEventGenerator()->MoveMouseTo(200 * test.scale, 200 * test.scale);
  755. events = WaitForMouseEvents();
  756. EXPECT_EQ(0u, events.size());
  757. // If we move over the bubble but not over any button than no real click
  758. // occurs. There is no button at the top of the bubble.
  759. button_location = gfx::ScaleToRoundedPoint(
  760. GetAutoclickMenuView()->GetBoundsInScreen().top_center() +
  761. gfx::Vector2d(0, 1),
  762. test.scale);
  763. GetEventGenerator()->MoveMouseTo(button_location);
  764. events = WaitForMouseEvents();
  765. EXPECT_EQ(0u, events.size());
  766. // The event type did not change because we were not over any button.
  767. EXPECT_EQ(AutoclickEventType::kNoAction,
  768. accessibility_controller->GetAutoclickEventType());
  769. // Leaving the bubble we are still paused.
  770. GetEventGenerator()->MoveMouseTo(200 * test.scale, 200 * test.scale);
  771. events = WaitForMouseEvents();
  772. EXPECT_EQ(0u, events.size());
  773. // Moving over another button takes an action.
  774. button_location = gfx::ScaleToRoundedPoint(
  775. GetMenuButton(AutoclickMenuView::ButtonId::kLeftClick)
  776. ->GetBoundsInScreen()
  777. .CenterPoint(),
  778. test.scale);
  779. GetEventGenerator()->MoveMouseTo(button_location);
  780. events = WaitForMouseEvents();
  781. EXPECT_EQ(0u, events.size());
  782. EXPECT_EQ(AutoclickEventType::kLeftClick,
  783. accessibility_controller->GetAutoclickEventType());
  784. }
  785. }
  786. TEST_F(AutoclickTest,
  787. StartsGestureOnBubbleButDoesNotClickIfMouseMovedWhenPaused) {
  788. Shell::Get()->accessibility_controller()->autoclick().SetEnabled(true);
  789. GetAutoclickController()->set_revert_to_left_click(false);
  790. GetAutoclickController()->SetAutoclickEventType(
  791. AutoclickEventType::kNoAction);
  792. Shell::Get()->accessibility_controller()->SetAutoclickMenuPosition(
  793. FloatingMenuPosition::kBottomRight);
  794. int animation_delay = 5;
  795. int full_delay = UpdateAnimationDelayAndGetFullDelay(animation_delay);
  796. std::vector<ui::MouseEvent> events;
  797. AutoclickMenuView* menu = GetAutoclickMenuView();
  798. ASSERT_TRUE(menu);
  799. // Start a dwell over the bubble.
  800. GetEventGenerator()->MoveMouseTo(menu->GetBoundsInScreen().origin());
  801. // Move back off the bubble before anything happens.
  802. FastForwardBy(animation_delay - 1);
  803. GetEventGenerator()->MoveMouseTo(30, 30);
  804. // Now wait the full delay to ensure pause could have happened.
  805. FastForwardBy(full_delay);
  806. events = GetMouseEvents();
  807. ASSERT_EQ(0u, events.size());
  808. // This time, dwell over the bubble long enough for the animation to begin.
  809. // No action should occur if we move off during the dwell.
  810. GetEventGenerator()->MoveMouseTo(menu->GetBoundsInScreen().origin());
  811. // Move back off the bubble after the animation begins, but before a click
  812. // would occur.
  813. FastForwardBy(animation_delay + 1);
  814. GetEventGenerator()->MoveMouseTo(30, 30);
  815. // Now wait the full delay to ensure pause could have happened.
  816. FastForwardBy(full_delay);
  817. events = GetMouseEvents();
  818. ASSERT_EQ(0u, events.size());
  819. }
  820. // The autoclick tray shouldn't stop the shelf from auto-hiding.
  821. TEST_F(AutoclickTest, ShelfAutohidesWithAutoclickBubble) {
  822. Shelf* shelf = GetPrimaryShelf();
  823. // Create a visible window so auto-hide behavior is enforced.
  824. std::unique_ptr<views::Widget> widget =
  825. CreateTestWidget(nullptr, desks_util::GetActiveDeskContainerId(),
  826. gfx::Rect(0, 0, 200, 200), true /* show */);
  827. // Turn on auto-hide for the shelf.
  828. shelf->SetAutoHideBehavior(ShelfAutoHideBehavior::kAlways);
  829. EXPECT_EQ(SHELF_AUTO_HIDE, shelf->GetVisibilityState());
  830. EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->GetAutoHideState());
  831. // Enable autoclick. The shelf should remain invisible.
  832. Shell::Get()->accessibility_controller()->autoclick().SetEnabled(true);
  833. AutoclickMenuView* menu = GetAutoclickMenuView();
  834. ASSERT_TRUE(menu);
  835. EXPECT_EQ(SHELF_AUTO_HIDE, shelf->GetVisibilityState());
  836. EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->GetAutoHideState());
  837. }
  838. TEST_F(AutoclickTest, BubbleMovesWithShelfPositionChange) {
  839. UpdateDisplay("800x600");
  840. int screen_width = 800;
  841. int screen_height = 600;
  842. // Create a visible window so WMEvents occur.
  843. std::unique_ptr<views::Widget> widget =
  844. CreateTestWidget(nullptr, desks_util::GetActiveDeskContainerId(),
  845. gfx::Rect(0, 0, 200, 200), true /* show */);
  846. // Set up autoclick and the shelf.
  847. Shell::Get()->accessibility_controller()->autoclick().SetEnabled(true);
  848. Shell::Get()->accessibility_controller()->SetAutoclickMenuPosition(
  849. FloatingMenuPosition::kBottomRight);
  850. Shelf* shelf = GetPrimaryShelf();
  851. shelf->SetAutoHideBehavior(ShelfAutoHideBehavior::kNever);
  852. EXPECT_EQ(shelf->GetVisibilityState(), SHELF_VISIBLE);
  853. AutoclickMenuView* menu = GetAutoclickMenuView();
  854. ASSERT_TRUE(menu);
  855. shelf->SetAlignment(ShelfAlignment::kBottom);
  856. // The menu should be positioned above the shelf, not overlapping.
  857. EXPECT_EQ(menu->GetBoundsInScreen().bottom_right().y(),
  858. screen_height - shelf->GetIdealBounds().height() -
  859. kCollisionWindowWorkAreaInsetsDp);
  860. // And all the way to the right.
  861. EXPECT_EQ(menu->GetBoundsInScreen().bottom_right().x(),
  862. screen_width - kCollisionWindowWorkAreaInsetsDp);
  863. shelf->SetAlignment(ShelfAlignment::kLeft);
  864. // The menu should move to the bottom of the screen.
  865. EXPECT_EQ(menu->GetBoundsInScreen().bottom_right().y(),
  866. screen_height - kCollisionWindowWorkAreaInsetsDp);
  867. // Still be at the far right.
  868. EXPECT_EQ(menu->GetBoundsInScreen().bottom_right().x(),
  869. screen_width - kCollisionWindowWorkAreaInsetsDp);
  870. shelf->SetAlignment(ShelfAlignment::kRight);
  871. // The menu should stay at the bottom of the screen.
  872. EXPECT_EQ(menu->GetBoundsInScreen().bottom_right().y(),
  873. screen_height - kCollisionWindowWorkAreaInsetsDp);
  874. // And should be offset from the far right by the shelf width.
  875. EXPECT_EQ(menu->GetBoundsInScreen().bottom_right().x(),
  876. screen_width - kCollisionWindowWorkAreaInsetsDp -
  877. shelf->GetIdealBounds().width());
  878. // Reset state.
  879. shelf->SetAlignment(ShelfAlignment::kBottom);
  880. }
  881. TEST_F(AutoclickTest, AvoidsShelfBubble) {
  882. const struct {
  883. session_manager::SessionState session_state;
  884. } kTestCases[]{
  885. {session_manager::SessionState::OOBE},
  886. {session_manager::SessionState::LOGIN_PRIMARY},
  887. {session_manager::SessionState::ACTIVE},
  888. {session_manager::SessionState::LOCKED},
  889. };
  890. for (auto test : kTestCases) {
  891. GetSessionControllerClient()->SetSessionState(test.session_state);
  892. // Set up autoclick and the shelf.
  893. Shell::Get()->accessibility_controller()->autoclick().SetEnabled(true);
  894. Shell::Get()->accessibility_controller()->SetAutoclickMenuPosition(
  895. FloatingMenuPosition::kBottomRight);
  896. auto* unified_system_tray = GetPrimaryUnifiedSystemTray();
  897. EXPECT_FALSE(unified_system_tray->IsBubbleShown());
  898. AutoclickMenuView* menu = GetAutoclickMenuView();
  899. ASSERT_TRUE(menu);
  900. gfx::Rect menu_bounds = menu->GetBoundsInScreen();
  901. unified_system_tray->ShowBubble();
  902. gfx::Rect new_menu_bounds = menu->GetBoundsInScreen();
  903. const int dx = abs(menu_bounds.x() - new_menu_bounds.x());
  904. const int dy = abs(menu_bounds.y() - new_menu_bounds.y());
  905. const gfx::Rect bubble_bounds =
  906. unified_system_tray->GetBubbleBoundsInScreen();
  907. // The height of the system tray bubble is dependent on the number of
  908. // feature pods, and whether the a11y widget goes above or to the side of
  909. // the system tray is dependent on the height of the system tray. Test that
  910. // one and only one of these situations is applicable.
  911. EXPECT_TRUE((dx < 5 && dy > bubble_bounds.height()) ||
  912. (dy < 5 && dx > bubble_bounds.width()));
  913. unified_system_tray->CloseBubble();
  914. new_menu_bounds = menu->GetBoundsInScreen();
  915. EXPECT_EQ(menu_bounds, new_menu_bounds);
  916. }
  917. }
  918. TEST_F(AutoclickTest, ConfirmationDialogShownWhenDisablingFeature) {
  919. // Enable and disable with the AccessibilityController to get real use-case
  920. // of the dialog.
  921. // No dialog shown at start-up.
  922. EXPECT_FALSE(GetAutoclickController()->GetDisableDialogForTesting());
  923. // No dialog shown when enabling the feature.
  924. Shell::Get()->accessibility_controller()->autoclick().SetEnabled(true);
  925. EXPECT_FALSE(GetAutoclickController()->GetDisableDialogForTesting());
  926. // A dialog should be shown when disabling the feature.
  927. Shell::Get()->accessibility_controller()->autoclick().SetEnabled(false);
  928. AccessibilityFeatureDisableDialog* dialog =
  929. GetAutoclickController()->GetDisableDialogForTesting();
  930. ASSERT_TRUE(dialog);
  931. // Canceling the dialog will cause the feature to continue to be enabled.
  932. dialog->CancelDialog();
  933. base::RunLoop().RunUntilIdle();
  934. EXPECT_FALSE(GetAutoclickController()->GetDisableDialogForTesting());
  935. EXPECT_TRUE(Shell::Get()->accessibility_controller()->autoclick().enabled());
  936. EXPECT_TRUE(GetAutoclickController()->IsEnabled());
  937. // Try to disable it again, and this time accept the dialog to actually
  938. // disable the feature.
  939. Shell::Get()->accessibility_controller()->autoclick().SetEnabled(false);
  940. dialog = GetAutoclickController()->GetDisableDialogForTesting();
  941. ASSERT_TRUE(dialog);
  942. dialog->AcceptDialog();
  943. base::RunLoop().RunUntilIdle();
  944. EXPECT_FALSE(GetAutoclickController()->GetDisableDialogForTesting());
  945. EXPECT_FALSE(Shell::Get()->accessibility_controller()->autoclick().enabled());
  946. EXPECT_FALSE(GetAutoclickController()->IsEnabled());
  947. }
  948. TEST_F(AutoclickTest, HidesBubbleInFullscreenWhenCursorHides) {
  949. Shell::Get()->accessibility_controller()->autoclick().SetEnabled(true);
  950. ::wm::CursorManager* cursor_manager = Shell::Get()->cursor_manager();
  951. cursor_manager->SetCursor(ui::mojom::CursorType::kPointer);
  952. const struct {
  953. const std::string display_spec;
  954. gfx::Rect widget_position;
  955. } kTestCases[] = {
  956. {"800x600", gfx::Rect(0, 0, 200, 200)},
  957. {"800x600,800x600", gfx::Rect(0, 0, 200, 200)},
  958. {"800x600,800x600", gfx::Rect(1000, 0, 200, 200)},
  959. };
  960. for (const auto& test : kTestCases) {
  961. SCOPED_TRACE(test.display_spec);
  962. UpdateDisplay(test.display_spec);
  963. std::unique_ptr<views::Widget> widget = CreateTestWidget(
  964. nullptr, desks_util::GetActiveDeskContainerId(), test.widget_position,
  965. /*show=*/true);
  966. EXPECT_TRUE(GetAutoclickBubbleWidget()->IsVisible());
  967. // Move the mouse over the widget, so it's on the same screen as the widget.
  968. GetEventGenerator()->MoveMouseTo(test.widget_position.origin());
  969. // When the widget is not fullscreen, hiding the cursor does not cause
  970. // the bubble to be hidden.
  971. cursor_manager->HideCursor();
  972. EXPECT_TRUE(GetAutoclickBubbleWidget()->IsVisible());
  973. cursor_manager->ShowCursor();
  974. EXPECT_TRUE(GetAutoclickBubbleWidget()->IsVisible());
  975. // Bubble is visible in fullscreen mode because the mouse cursor is visible.
  976. widget->SetFullscreen(true);
  977. EXPECT_TRUE(GetAutoclickBubbleWidget()->IsVisible());
  978. // Bubble is hidden when the cursor is hidden in fullscreen mode, and shown
  979. // when the cursor is shown.
  980. cursor_manager->HideCursor();
  981. EXPECT_FALSE(GetAutoclickBubbleWidget()->IsVisible());
  982. cursor_manager->ShowCursor();
  983. EXPECT_TRUE(GetAutoclickBubbleWidget()->IsVisible());
  984. // Changing the type to another visible type doesn't cause the bubble to
  985. // hide.
  986. cursor_manager->SetCursor(ui::mojom::CursorType::kHand);
  987. EXPECT_TRUE(GetAutoclickBubbleWidget()->IsVisible());
  988. // Changing the type to an kNone causes the bubble to hide.
  989. cursor_manager->SetCursor(ui::mojom::CursorType::kNone);
  990. EXPECT_FALSE(GetAutoclickBubbleWidget()->IsVisible());
  991. // Hiding and showing don't re-show the bubble because the type is still
  992. // kNone.
  993. cursor_manager->HideCursor();
  994. EXPECT_FALSE(GetAutoclickBubbleWidget()->IsVisible());
  995. cursor_manager->ShowCursor();
  996. EXPECT_FALSE(GetAutoclickBubbleWidget()->IsVisible());
  997. // The bubble is shown when the cursor is a visible type again.
  998. cursor_manager->SetCursor(ui::mojom::CursorType::kPointer);
  999. EXPECT_TRUE(GetAutoclickBubbleWidget()->IsVisible());
  1000. }
  1001. }
  1002. TEST_F(AutoclickTest, DoesNotHideBubbleWhenNotOverFullscreenWindow) {
  1003. UpdateDisplay("800x600,800x600");
  1004. Shell::Get()->accessibility_controller()->autoclick().SetEnabled(true);
  1005. ::wm::CursorManager* cursor_manager = Shell::Get()->cursor_manager();
  1006. cursor_manager->SetCursor(ui::mojom::CursorType::kPointer);
  1007. std::unique_ptr<views::Widget> widget =
  1008. CreateTestWidget(nullptr, desks_util::GetActiveDeskContainerId(),
  1009. gfx::Rect(1000, 0, 200, 200), true);
  1010. EXPECT_TRUE(GetAutoclickBubbleWidget()->IsVisible());
  1011. // Move the mouse over the other display.
  1012. GetEventGenerator()->MoveMouseTo(gfx::Point(10, 10));
  1013. // When the widget is fullscreen, hiding the cursor does not hide the bubble
  1014. // because the cursor is on a different display.
  1015. widget->SetFullscreen(true);
  1016. cursor_manager->HideCursor();
  1017. EXPECT_TRUE(GetAutoclickBubbleWidget()->IsVisible());
  1018. }
  1019. TEST_F(AutoclickTest, DoesNotHideBubbleWhenOverInactiveFullscreenWindow) {
  1020. Shell::Get()->accessibility_controller()->autoclick().SetEnabled(true);
  1021. ::wm::CursorManager* cursor_manager = Shell::Get()->cursor_manager();
  1022. cursor_manager->SetCursor(ui::mojom::CursorType::kPointer);
  1023. std::unique_ptr<views::Widget> widget =
  1024. CreateTestWidget(nullptr, desks_util::GetActiveDeskContainerId(),
  1025. gfx::Rect(0, 0, 200, 200), true);
  1026. GetEventGenerator()->MoveMouseTo(gfx::Point(10, 10));
  1027. widget->SetFullscreen(true);
  1028. EXPECT_TRUE(widget->IsActive());
  1029. views::Widget* popup_widget = views::Widget::CreateWindowWithContext(
  1030. nullptr, GetContext(), gfx::Rect(200, 200, 200, 200));
  1031. popup_widget->Show();
  1032. cursor_manager->HideCursor();
  1033. EXPECT_FALSE(widget->IsActive());
  1034. EXPECT_TRUE(popup_widget->IsActive());
  1035. EXPECT_TRUE(GetAutoclickBubbleWidget()->IsVisible());
  1036. }
  1037. TEST_F(AutoclickTest, ScrollClosesWhenHoveredOverScrollButton) {
  1038. GetAutoclickController()->SetEnabled(true, false /* do not show dialog */);
  1039. GetAutoclickController()->SetAutoclickEventType(
  1040. AutoclickEventType::kLeftClick);
  1041. EXPECT_FALSE(GetAutoclickScrollView());
  1042. // Enable scroll.
  1043. GetAutoclickController()->SetAutoclickEventType(AutoclickEventType::kScroll);
  1044. ASSERT_TRUE(GetAutoclickScrollView());
  1045. views::View* close_button =
  1046. GetScrollButton(AutoclickScrollView::ButtonId::kCloseScroll);
  1047. ASSERT_TRUE(close_button);
  1048. gfx::Point button_location = close_button->GetBoundsInScreen().CenterPoint();
  1049. GetEventGenerator()->MoveMouseTo(button_location);
  1050. // No mouse event.
  1051. std::vector<ui::MouseEvent> events = WaitForMouseEvents();
  1052. EXPECT_EQ(0u, events.size());
  1053. // Reset to left click and scroll view is gone.
  1054. EXPECT_EQ(AutoclickEventType::kLeftClick,
  1055. Shell::Get()->accessibility_controller()->GetAutoclickEventType());
  1056. EXPECT_FALSE(GetAutoclickScrollView());
  1057. }
  1058. TEST_F(AutoclickTest, ScrollOccursWhenHoveredOverScrollButtons) {
  1059. UpdateDisplay("800x600");
  1060. GetAutoclickController()->SetEnabled(true, false /* do not show dialog */);
  1061. // Enable scroll.
  1062. GetAutoclickController()->SetAutoclickEventType(AutoclickEventType::kScroll);
  1063. ASSERT_TRUE(GetAutoclickScrollView());
  1064. // TODO: Do for all four buttons, wait a few scrolls each.
  1065. const struct {
  1066. AutoclickScrollView::ButtonId button_id;
  1067. int scroll_x;
  1068. int scroll_y;
  1069. } kTestCases[] = {
  1070. {AutoclickScrollView::ButtonId::kScrollUp, 0, 10},
  1071. {AutoclickScrollView::ButtonId::kScrollDown, 0, -10},
  1072. {AutoclickScrollView::ButtonId::kScrollLeft, 10, 0},
  1073. {AutoclickScrollView::ButtonId::kScrollRight, -10, 0},
  1074. };
  1075. for (auto& test : kTestCases) {
  1076. views::View* button = GetScrollButton(test.button_id);
  1077. ASSERT_TRUE(button);
  1078. gfx::Point button_location = button->GetBoundsInScreen().CenterPoint();
  1079. GetEventGenerator()->MoveMouseTo(button_location);
  1080. // No mouse event during hover, no wheel events yet.
  1081. FastForwardBy(AutoclickScrollView::kAutoclickScrollDelayMs - 1);
  1082. std::vector<ui::MouseEvent> events = GetMouseEvents();
  1083. EXPECT_EQ(0u, events.size());
  1084. std::vector<ui::MouseWheelEvent> wheel_events = GetMouseWheelEvents();
  1085. EXPECT_EQ(0u, wheel_events.size());
  1086. // But we should get a scroll event after kAutoclickScrollDelayMs.
  1087. FastForwardBy(2);
  1088. wheel_events = GetMouseWheelEvents();
  1089. EXPECT_EQ(1u, wheel_events.size());
  1090. EXPECT_EQ(gfx::Point(400, 300), wheel_events[0].location());
  1091. EXPECT_EQ(test.scroll_x, wheel_events[0].x_offset());
  1092. EXPECT_EQ(test.scroll_y, wheel_events[0].y_offset());
  1093. // No other events expected.
  1094. events = GetMouseEvents();
  1095. EXPECT_EQ(0u, events.size());
  1096. ClearMouseEvents();
  1097. // Wait until another kAutoclickScrollDelayMs has elapsed and expect another
  1098. // scroll to have occurred.
  1099. FastForwardBy(AutoclickScrollView::kAutoclickScrollDelayMs);
  1100. wheel_events = GetMouseWheelEvents();
  1101. EXPECT_EQ(1u, wheel_events.size());
  1102. EXPECT_EQ(gfx::Point(400, 300), wheel_events[0].location());
  1103. EXPECT_EQ(test.scroll_x, wheel_events[0].x_offset());
  1104. EXPECT_EQ(test.scroll_y, wheel_events[0].y_offset());
  1105. // No other events expected.
  1106. events = GetMouseEvents();
  1107. EXPECT_EQ(0u, events.size());
  1108. ClearMouseEvents();
  1109. }
  1110. }
  1111. TEST_F(AutoclickTest, ScrollMenuBubblePostioning) {
  1112. UpdateDisplay("800x600");
  1113. GetAutoclickController()->SetEnabled(true, false /* do not show dialog */);
  1114. Shell::Get()->accessibility_controller()->SetAutoclickMenuPosition(
  1115. FloatingMenuPosition::kBottomRight);
  1116. GetAutoclickController()->SetAutoclickEventType(AutoclickEventType::kScroll);
  1117. ASSERT_TRUE(GetAutoclickScrollView());
  1118. // Set the bounds to be the entire window.
  1119. gfx::Rect display_bounds = gfx::Rect(0, 0, 800, 600);
  1120. GetAutoclickController()->HandleAutoclickScrollableBoundsFound(
  1121. display_bounds);
  1122. // The scroll bubble should start near the autoclick menu.
  1123. gfx::Rect scroll_bounds = GetAutoclickScrollView()->GetBoundsInScreen();
  1124. gfx::Rect menu_bounds = GetAutoclickMenuView()->GetBoundsInScreen();
  1125. EXPECT_LT(menu_bounds.ManhattanInternalDistance(scroll_bounds),
  1126. kScrollToMenuBoundsBuffer);
  1127. // Moving the autoclick menu around the screen moves the scroll bubble too.
  1128. Shell::Get()->accessibility_controller()->SetAutoclickMenuPosition(
  1129. FloatingMenuPosition::kBottomLeft);
  1130. scroll_bounds = GetAutoclickScrollView()->GetBoundsInScreen();
  1131. menu_bounds = GetAutoclickMenuView()->GetBoundsInScreen();
  1132. EXPECT_LT(menu_bounds.ManhattanInternalDistance(scroll_bounds),
  1133. kScrollToMenuBoundsBuffer);
  1134. Shell::Get()->accessibility_controller()->SetAutoclickMenuPosition(
  1135. FloatingMenuPosition::kTopLeft);
  1136. scroll_bounds = GetAutoclickScrollView()->GetBoundsInScreen();
  1137. menu_bounds = GetAutoclickMenuView()->GetBoundsInScreen();
  1138. EXPECT_LT(menu_bounds.ManhattanInternalDistance(scroll_bounds),
  1139. kScrollToMenuBoundsBuffer);
  1140. Shell::Get()->accessibility_controller()->SetAutoclickMenuPosition(
  1141. FloatingMenuPosition::kTopRight);
  1142. scroll_bounds = GetAutoclickScrollView()->GetBoundsInScreen();
  1143. menu_bounds = GetAutoclickMenuView()->GetBoundsInScreen();
  1144. EXPECT_LT(menu_bounds.ManhattanInternalDistance(scroll_bounds),
  1145. kScrollToMenuBoundsBuffer);
  1146. // However, if we dwell somewhere else, the autoclick scroll menu will now
  1147. // move out of the corner and near that point when the display bounds are
  1148. // found.
  1149. gfx::Point scroll_point = gfx::Point(0, 0);
  1150. GetEventGenerator()->MoveMouseTo(scroll_point);
  1151. base::RunLoop().RunUntilIdle();
  1152. GetAutoclickController()->HandleAutoclickScrollableBoundsFound(
  1153. display_bounds);
  1154. scroll_bounds = GetAutoclickScrollView()->GetBoundsInScreen();
  1155. EXPECT_GT(menu_bounds.ManhattanInternalDistance(scroll_bounds),
  1156. kScrollToMenuBoundsBuffer);
  1157. // Moving the bubble menu now does not change the scroll bubble's position,
  1158. // it remains near its point.
  1159. Shell::Get()->accessibility_controller()->SetAutoclickMenuPosition(
  1160. FloatingMenuPosition::kBottomRight);
  1161. EXPECT_EQ(GetAutoclickScrollView()->GetBoundsInScreen(), scroll_bounds);
  1162. }
  1163. } // namespace ash