123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359 |
- // Copyright 2013 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include "ash/accessibility/accessibility_controller_impl.h"
- #include "ash/accessibility/autoclick/autoclick_controller.h"
- #include "ash/shelf/shelf.h"
- #include "ash/shell.h"
- #include "ash/system/accessibility/accessibility_feature_disable_dialog.h"
- #include "ash/system/accessibility/autoclick_menu_bubble_controller.h"
- #include "ash/system/accessibility/autoclick_menu_view.h"
- #include "ash/system/accessibility/autoclick_scroll_bubble_controller.h"
- #include "ash/system/accessibility/autoclick_scroll_view.h"
- #include "ash/system/unified/unified_system_tray.h"
- #include "ash/test/ash_test_base.h"
- #include "ash/wm/collision_detection/collision_detection_utils.h"
- #include "ash/wm/desks/desks_util.h"
- #include "ash/wm/window_state.h"
- #include "ash/wm/wm_event.h"
- #include "base/run_loop.h"
- #include "base/test/task_environment.h"
- #include "ui/aura/test/test_window_delegate.h"
- #include "ui/aura/window.h"
- #include "ui/aura/window_event_dispatcher.h"
- #include "ui/base/cursor/mojom/cursor_type.mojom-shared.h"
- #include "ui/display/manager/display_manager.h"
- #include "ui/events/event.h"
- #include "ui/events/event_constants.h"
- #include "ui/events/event_handler.h"
- #include "ui/events/event_utils.h"
- #include "ui/events/keycodes/keyboard_codes.h"
- #include "ui/events/test/event_generator.h"
- #include "ui/events/types/event_type.h"
- namespace ash {
- namespace {
- const int kScrollToMenuBoundsBuffer = 18;
- }
- class MouseEventCapturer : public ui::EventHandler {
- public:
- MouseEventCapturer() { Reset(); }
- MouseEventCapturer(const MouseEventCapturer&) = delete;
- MouseEventCapturer& operator=(const MouseEventCapturer&) = delete;
- ~MouseEventCapturer() override = default;
- void Reset() {
- events_.clear();
- wheel_events_.clear();
- }
- void OnMouseEvent(ui::MouseEvent* event) override {
- bool save_event = false;
- bool stop_event = false;
- // Filter out extraneous mouse events like mouse entered, exited,
- // capture changed, etc.
- ui::EventType type = event->type();
- if (type == ui::ET_MOUSE_PRESSED || type == ui::ET_MOUSE_RELEASED) {
- // Only track left and right mouse button events, ensuring that we get
- // left-click, right-click and double-click.
- if (!(event->flags() & ui::EF_LEFT_MOUSE_BUTTON) &&
- (!(event->flags() & ui::EF_RIGHT_MOUSE_BUTTON)))
- return;
- save_event = true;
- // Stop event propagation so we don't click on random stuff that
- // might break test assumptions.
- stop_event = true;
- } else if (type == ui::ET_MOUSE_DRAGGED) {
- save_event = true;
- stop_event = false;
- } else if (type == ui::ET_MOUSEWHEEL) {
- // Save it immediately as a MouseWheelEvent.
- wheel_events_.push_back(ui::MouseWheelEvent(
- event->AsMouseWheelEvent()->offset(), event->location(),
- event->root_location(), ui::EventTimeForNow(), event->flags(),
- event->changed_button_flags()));
- }
- if (save_event) {
- events_.push_back(ui::MouseEvent(event->type(), event->location(),
- event->root_location(),
- ui::EventTimeForNow(), event->flags(),
- event->changed_button_flags()));
- }
- if (stop_event)
- event->StopPropagation();
- // If there is a possibility that we're in an infinite loop, we should
- // exit early with a sensible error rather than letting the test time out.
- ASSERT_LT(events_.size(), 100u);
- }
- const std::vector<ui::MouseEvent>& captured_events() const { return events_; }
- const std::vector<ui::MouseWheelEvent>& captured_mouse_wheel_events() const {
- return wheel_events_;
- }
- private:
- std::vector<ui::MouseEvent> events_;
- std::vector<ui::MouseWheelEvent> wheel_events_;
- };
- class AutoclickTest : public AshTestBase {
- public:
- AutoclickTest()
- : AshTestBase(base::test::TaskEnvironment::TimeSource::MOCK_TIME) {}
- AutoclickTest(const AutoclickTest&) = delete;
- AutoclickTest& operator=(const AutoclickTest&) = delete;
- ~AutoclickTest() override = default;
- void SetUp() override {
- AshTestBase::SetUp();
- Shell::Get()->AddPreTargetHandler(&mouse_event_capturer_);
- GetAutoclickController()->SetAutoclickDelay(base::TimeDelta());
- // Move mouse to deterministic location at the start of each test.
- GetEventGenerator()->MoveMouseTo(100, 100);
- // Make sure the display is initialized so we don't fail the test due to any
- // input events caused from creating the display.
- Shell::Get()->display_manager()->UpdateDisplays();
- base::RunLoop().RunUntilIdle();
- }
- void TearDown() override {
- Shell::Get()->RemovePreTargetHandler(&mouse_event_capturer_);
- AshTestBase::TearDown();
- }
- void MoveMouseWithFlagsTo(int x, int y, ui::EventFlags flags) {
- GetEventGenerator()->set_flags(flags);
- GetEventGenerator()->MoveMouseTo(x, y);
- GetEventGenerator()->set_flags(ui::EF_NONE);
- }
- const std::vector<ui::MouseEvent>& WaitForMouseEvents() {
- ClearMouseEvents();
- // TODO(katie): Consider using quit closure instead of RunUntilIdle.
- base::RunLoop().RunUntilIdle();
- return GetMouseEvents();
- }
- void FastForwardBy(int milliseconds) {
- task_environment()->FastForwardBy(base::Milliseconds(milliseconds));
- }
- AutoclickController* GetAutoclickController() {
- return Shell::Get()->autoclick_controller();
- }
- // Calculates and returns full delay from the animation delay, after setting
- // that delay on the autoclick controller.
- int UpdateAnimationDelayAndGetFullDelay(float animation_delay) {
- float ratio =
- GetAutoclickController()->GetStartGestureDelayRatioForTesting();
- int full_delay = ceil(1.0 / ratio) * animation_delay;
- GetAutoclickController()->SetAutoclickDelay(base::Milliseconds(full_delay));
- return full_delay;
- }
- AutoclickMenuView* GetAutoclickMenuView() {
- return GetAutoclickController()
- ->GetMenuBubbleControllerForTesting()
- ->menu_view_;
- }
- AutoclickScrollView* GetAutoclickScrollView() {
- AutoclickScrollBubbleController* controller =
- GetAutoclickController()
- ->GetMenuBubbleControllerForTesting()
- ->scroll_bubble_controller_.get();
- return controller ? controller->scroll_view_ : nullptr;
- }
- views::Widget* GetAutoclickBubbleWidget() {
- return GetAutoclickController()
- ->GetMenuBubbleControllerForTesting()
- ->bubble_widget_;
- }
- views::View* GetMenuButton(AutoclickMenuView::ButtonId view_id) {
- AutoclickMenuView* menu_view = GetAutoclickMenuView();
- if (!menu_view)
- return nullptr;
- return menu_view->GetViewByID(static_cast<int>(view_id));
- }
- views::View* GetScrollButton(AutoclickScrollView::ButtonId view_id) {
- AutoclickScrollView* scroll_view = GetAutoclickScrollView();
- if (!scroll_view)
- return nullptr;
- return scroll_view->GetViewByID(static_cast<int>(view_id));
- }
- void ClearMouseEvents() { mouse_event_capturer_.Reset(); }
- const std::vector<ui::MouseEvent>& GetMouseEvents() {
- return mouse_event_capturer_.captured_events();
- }
- const std::vector<ui::MouseWheelEvent>& GetMouseWheelEvents() {
- return mouse_event_capturer_.captured_mouse_wheel_events();
- }
- private:
- MouseEventCapturer mouse_event_capturer_;
- };
- TEST_F(AutoclickTest, ToggleEnabled) {
- std::vector<ui::MouseEvent> events;
- // We should not see any events initially.
- EXPECT_FALSE(GetAutoclickController()->IsEnabled());
- events = WaitForMouseEvents();
- EXPECT_EQ(0u, events.size());
- // Enable autoclick, and we should see a mouse pressed and
- // a mouse released event, simulating a click.
- GetAutoclickController()->SetEnabled(true, false /* do not show dialog */);
- GetEventGenerator()->MoveMouseTo(0, 0);
- EXPECT_TRUE(GetAutoclickController()->IsEnabled());
- events = WaitForMouseEvents();
- ASSERT_EQ(2u, events.size());
- EXPECT_EQ(ui::ET_MOUSE_PRESSED, events[0].type());
- EXPECT_TRUE(ui::EF_LEFT_MOUSE_BUTTON & events[0].flags());
- EXPECT_EQ(ui::ET_MOUSE_RELEASED, events[1].type());
- EXPECT_TRUE(ui::EF_LEFT_MOUSE_BUTTON & events[1].flags());
- // We should not get any more clicks until we move the mouse.
- events = WaitForMouseEvents();
- EXPECT_EQ(0u, events.size());
- GetEventGenerator()->MoveMouseTo(30, 30);
- events = WaitForMouseEvents();
- ASSERT_EQ(2u, events.size());
- EXPECT_EQ(ui::ET_MOUSE_PRESSED, events[0].type());
- EXPECT_TRUE(ui::EF_LEFT_MOUSE_BUTTON & events[0].flags());
- EXPECT_EQ(ui::ET_MOUSE_RELEASED, events[1].type());
- EXPECT_TRUE(ui::EF_LEFT_MOUSE_BUTTON & events[1].flags());
- // Disable autoclick, and we should see the original behaviour.
- GetAutoclickController()->SetEnabled(false, false /* do not show dialog */);
- EXPECT_FALSE(GetAutoclickController()->IsEnabled());
- events = WaitForMouseEvents();
- EXPECT_EQ(0u, events.size());
- // After disable, autoclick should be set back to left click.
- EXPECT_EQ(AutoclickEventType::kLeftClick,
- Shell::Get()->accessibility_controller()->GetAutoclickEventType());
- }
- TEST_F(AutoclickTest, MouseMovement) {
- std::vector<ui::MouseEvent> events;
- GetAutoclickController()->SetEnabled(true, false /* do not show dialog */);
- gfx::Point p1(0, 0);
- gfx::Point p2(20, 20);
- gfx::Point p3(40, 40);
- // Move mouse to p1.
- GetEventGenerator()->MoveMouseTo(p1);
- events = WaitForMouseEvents();
- EXPECT_EQ(2u, events.size());
- EXPECT_EQ(p1.ToString(), events[0].root_location().ToString());
- EXPECT_EQ(p1.ToString(), events[1].root_location().ToString());
- // Move mouse to multiple locations and finally arrive at p3.
- GetEventGenerator()->MoveMouseTo(p2);
- GetEventGenerator()->MoveMouseTo(p1);
- GetEventGenerator()->MoveMouseTo(p3);
- events = WaitForMouseEvents();
- EXPECT_EQ(2u, events.size());
- EXPECT_EQ(p3.ToString(), events[0].root_location().ToString());
- EXPECT_EQ(p3.ToString(), events[1].root_location().ToString());
- }
- TEST_F(AutoclickTest, MovementThreshold) {
- UpdateDisplay("1280x1024,800x600");
- base::RunLoop().RunUntilIdle();
- aura::Window::Windows root_windows = Shell::GetAllRootWindows();
- EXPECT_EQ(2u, root_windows.size());
- int animation_delay = 5;
- const struct {
- int movement_threshold;
- bool stabilize_click_position;
- } kTestCases[] = {
- {10, false}, {20, false}, {30, false}, {40, false}, {50, false},
- {10, true}, {20, true}, {30, true}, {40, true}, {50, true},
- };
- for (const auto& test : kTestCases) {
- GetAutoclickController()->set_stabilize_click_position(
- test.stabilize_click_position);
- int movement_threshold = test.movement_threshold;
- GetAutoclickController()->SetMovementThreshold(movement_threshold);
- // Run test for the secondary display too to test fix for crbug.com/449870.
- for (auto* root_window : root_windows) {
- gfx::Point center = root_window->GetBoundsInScreen().CenterPoint();
- GetAutoclickController()->SetEnabled(true,
- false /* do not show dialog */);
- GetEventGenerator()->MoveMouseTo(center);
- ClearMouseEvents();
- EXPECT_EQ(2u, WaitForMouseEvents().size());
- // Small mouse movements should not trigger an autoclick, i.e. movements
- // within the radius of the movement_threshold.
- GetEventGenerator()->MoveMouseTo(
- center + gfx::Vector2d(std::sqrt(movement_threshold) - 1,
- std::sqrt(movement_threshold) - 1));
- EXPECT_EQ(0u, WaitForMouseEvents().size());
- GetEventGenerator()->MoveMouseTo(
- center + gfx::Vector2d(movement_threshold - 1, 0));
- EXPECT_EQ(0u, WaitForMouseEvents().size());
- GetEventGenerator()->MoveMouseTo(
- center + gfx::Vector2d(0, -movement_threshold + 1));
- EXPECT_EQ(0u, WaitForMouseEvents().size());
- GetEventGenerator()->MoveMouseTo(center);
- EXPECT_EQ(0u, WaitForMouseEvents().size());
- // A larger mouse movement should trigger an autoclick.
- GetEventGenerator()->MoveMouseTo(
- center +
- gfx::Vector2d(movement_threshold + 1, movement_threshold + 1));
- EXPECT_EQ(2u, WaitForMouseEvents().size());
- // Moving outside the threshold after the gesture begins should cancel
- // the autoclick. Update the delay so we can do events between the initial
- // trigger of the feature and the click.
- int full_delay = UpdateAnimationDelayAndGetFullDelay(animation_delay);
- GetEventGenerator()->MoveMouseTo(
- center - gfx::Vector2d(movement_threshold, movement_threshold));
- FastForwardBy(animation_delay + 1);
- GetEventGenerator()->MoveMouseTo(center);
- ClearMouseEvents();
- // After a time, a new click will occur at the second location. The first
- // location should never get a click.
- FastForwardBy(full_delay * 2);
- EXPECT_EQ(2u, GetMouseEvents().size());
- gfx::Rect display_bounds = display::Screen::GetScreen()
- ->GetDisplayNearestWindow(root_window)
- .bounds();
- EXPECT_EQ(center - gfx::Vector2d(display_bounds.origin().x(),
- display_bounds.origin().y()),
- GetMouseEvents()[0].location());
- // Move it out of the way so the next cycle starts properly.
- GetEventGenerator()->MoveMouseTo(gfx::Point(0, 0));
- GetAutoclickController()->SetAutoclickDelay(base::TimeDelta());
- }
- }
- // Reset to defaults.
- GetAutoclickController()->SetMovementThreshold(20);
- GetAutoclickController()->set_stabilize_click_position(false);
- }
- TEST_F(AutoclickTest, MovementWithinThresholdWhileTimerRunning) {
- GetAutoclickController()->SetEnabled(true, false /* do not show dialog */);
- GetAutoclickController()->SetMovementThreshold(20);
- int animation_delay = 5;
- int full_delay = UpdateAnimationDelayAndGetFullDelay(animation_delay);
- GetAutoclickController()->set_stabilize_click_position(true);
- GetEventGenerator()->MoveMouseTo(100, 100);
- FastForwardBy(animation_delay + 1);
- // Move the mouse within the threshold. It shouldn't change the eventual
- // target of the event, or cancel the click.
- GetEventGenerator()->MoveMouseTo(110, 110);
- ClearMouseEvents();
- FastForwardBy(full_delay);
- std::vector<ui::MouseEvent> events = GetMouseEvents();
- EXPECT_EQ(2u, events.size());
- EXPECT_EQ(gfx::Point(100, 100), events[0].location());
- EXPECT_EQ(ui::ET_MOUSE_PRESSED, events[0].type());
- EXPECT_EQ(ui::EF_LEFT_MOUSE_BUTTON, events[0].flags());
- EXPECT_EQ(gfx::Point(100, 100), events[1].location());
- EXPECT_EQ(ui::ET_MOUSE_RELEASED, events[1].type());
- EXPECT_EQ(ui::EF_LEFT_MOUSE_BUTTON, events[1].flags());
- // When the click position is not stabilized, the mouse movement should
- // translate into the target of the event, but not cancel the click.
- GetAutoclickController()->set_stabilize_click_position(false);
- GetEventGenerator()->MoveMouseTo(200, 200);
- FastForwardBy(animation_delay + 1);
- GetEventGenerator()->MoveMouseTo(210, 210);
- ClearMouseEvents();
- FastForwardBy(full_delay);
- events = GetMouseEvents();
- EXPECT_EQ(2u, events.size());
- EXPECT_EQ(gfx::Point(210, 210), events[0].location());
- EXPECT_EQ(ui::ET_MOUSE_PRESSED, events[0].type());
- EXPECT_EQ(ui::EF_LEFT_MOUSE_BUTTON, events[0].flags());
- EXPECT_EQ(gfx::Point(210, 210), events[1].location());
- EXPECT_EQ(ui::ET_MOUSE_RELEASED, events[1].type());
- EXPECT_EQ(ui::EF_LEFT_MOUSE_BUTTON, events[1].flags());
- // Reset delay.
- GetAutoclickController()->SetAutoclickDelay(base::TimeDelta());
- }
- TEST_F(AutoclickTest, SingleKeyModifier) {
- GetAutoclickController()->SetEnabled(true, false /* do not show dialog */);
- MoveMouseWithFlagsTo(20, 20, ui::EF_SHIFT_DOWN);
- std::vector<ui::MouseEvent> events = WaitForMouseEvents();
- EXPECT_EQ(2u, events.size());
- EXPECT_EQ(ui::EF_SHIFT_DOWN, events[0].flags() & ui::EF_SHIFT_DOWN);
- EXPECT_EQ(ui::EF_SHIFT_DOWN, events[1].flags() & ui::EF_SHIFT_DOWN);
- }
- TEST_F(AutoclickTest, MultipleKeyModifiers) {
- GetAutoclickController()->SetEnabled(true, false /* do not show dialog */);
- ui::EventFlags modifier_flags = static_cast<ui::EventFlags>(
- ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN | ui::EF_SHIFT_DOWN);
- MoveMouseWithFlagsTo(30, 30, modifier_flags);
- std::vector<ui::MouseEvent> events = WaitForMouseEvents();
- EXPECT_EQ(2u, events.size());
- EXPECT_EQ(modifier_flags, events[0].flags() & modifier_flags);
- EXPECT_EQ(modifier_flags, events[1].flags() & modifier_flags);
- }
- TEST_F(AutoclickTest, KeyModifiersReleased) {
- GetAutoclickController()->SetEnabled(true, false /* do not show dialog */);
- ui::EventFlags modifier_flags = static_cast<ui::EventFlags>(
- ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN | ui::EF_SHIFT_DOWN);
- MoveMouseWithFlagsTo(12, 12, modifier_flags);
- // Simulate releasing key modifiers by sending key released events.
- GetEventGenerator()->ReleaseKey(
- ui::VKEY_CONTROL,
- static_cast<ui::EventFlags>(ui::EF_ALT_DOWN | ui::EF_SHIFT_DOWN));
- GetEventGenerator()->ReleaseKey(ui::VKEY_SHIFT, ui::EF_ALT_DOWN);
- std::vector<ui::MouseEvent> events;
- events = WaitForMouseEvents();
- EXPECT_EQ(2u, events.size());
- EXPECT_EQ(0, events[0].flags() & ui::EF_CONTROL_DOWN);
- EXPECT_EQ(0, events[0].flags() & ui::EF_SHIFT_DOWN);
- EXPECT_EQ(ui::EF_ALT_DOWN, events[0].flags() & ui::EF_ALT_DOWN);
- }
- TEST_F(AutoclickTest, UserInputCancelsAutoclick) {
- GetAutoclickController()->SetEnabled(true, false /* do not show dialog */);
- std::vector<ui::MouseEvent> events;
- // Pressing a normal key should cancel the autoclick.
- GetEventGenerator()->MoveMouseTo(200, 200);
- GetEventGenerator()->PressKey(ui::VKEY_K, ui::EF_NONE);
- GetEventGenerator()->ReleaseKey(ui::VKEY_K, ui::EF_NONE);
- events = WaitForMouseEvents();
- EXPECT_EQ(0u, events.size());
- // Pressing a modifier key should NOT cancel the autoclick.
- GetEventGenerator()->MoveMouseTo(100, 100);
- GetEventGenerator()->PressKey(ui::VKEY_SHIFT, ui::EF_SHIFT_DOWN);
- GetEventGenerator()->ReleaseKey(ui::VKEY_SHIFT, ui::EF_NONE);
- events = WaitForMouseEvents();
- EXPECT_EQ(2u, events.size());
- // Mouse-wheel scroll events should cancel the autoclick.
- GetEventGenerator()->MoveMouseTo(300, 300);
- GetEventGenerator()->MoveMouseWheel(0, 20);
- events = WaitForMouseEvents();
- EXPECT_EQ(0u, events.size());
- // Performing a gesture should cancel the autoclick.
- GetEventGenerator()->MoveMouseTo(200, 200);
- GetEventGenerator()->GestureTapDownAndUp(gfx::Point(100, 100));
- events = WaitForMouseEvents();
- EXPECT_EQ(0u, events.size());
- // Test another gesture.
- GetEventGenerator()->MoveMouseTo(100, 100);
- GetEventGenerator()->GestureScrollSequence(
- gfx::Point(100, 100), gfx::Point(200, 200), base::Milliseconds(200), 3);
- events = WaitForMouseEvents();
- EXPECT_EQ(0u, events.size());
- // Test scroll events.
- GetEventGenerator()->MoveMouseTo(200, 200);
- GetEventGenerator()->ScrollSequence(gfx::Point(100, 100),
- base::Milliseconds(200), 0, 100, 3, 2);
- events = WaitForMouseEvents();
- EXPECT_EQ(0u, events.size());
- // However, just starting a scroll doesn't cancel. If you tap a touchpad on
- // an Eve chromebook, for example, it can send an ET_SCROLL_FLING_CANCEL
- // event, which shouldn't actually cancel autoclick.
- GetEventGenerator()->MoveMouseTo(100, 100);
- GetEventGenerator()->ScrollSequence(gfx::Point(100, 100), base::TimeDelta(),
- 0, 0, 0, 1);
- events = WaitForMouseEvents();
- EXPECT_EQ(2u, events.size());
- }
- TEST_F(AutoclickTest, SynthesizedMouseMovesIgnored) {
- GetAutoclickController()->SetEnabled(true, false /* do not show dialog */);
- std::vector<ui::MouseEvent> events;
- GetEventGenerator()->MoveMouseTo(100, 100);
- events = WaitForMouseEvents();
- EXPECT_EQ(2u, events.size());
- // Show a window and make sure the new window is under the cursor. As a
- // result, synthesized mouse events will be dispatched to the window, but it
- // should not trigger an autoclick.
- aura::test::EventCountDelegate delegate;
- std::unique_ptr<aura::Window> window(CreateTestWindowInShellWithDelegate(
- &delegate, 123, gfx::Rect(50, 50, 100, 100)));
- window->Show();
- events = WaitForMouseEvents();
- EXPECT_EQ(0u, events.size());
- EXPECT_EQ("1 1 0", delegate.GetMouseMotionCountsAndReset());
- }
- TEST_F(AutoclickTest, AutoclickChangeEventTypes) {
- GetAutoclickController()->SetEnabled(true, false /* do not show dialog */);
- GetAutoclickController()->set_revert_to_left_click(false);
- GetAutoclickController()->SetAutoclickEventType(
- AutoclickEventType::kRightClick);
- std::vector<ui::MouseEvent> events;
- GetEventGenerator()->MoveMouseTo(30, 30);
- events = WaitForMouseEvents();
- ASSERT_EQ(2u, events.size());
- EXPECT_EQ(ui::ET_MOUSE_PRESSED, events[0].type());
- EXPECT_TRUE(ui::EF_RIGHT_MOUSE_BUTTON & events[0].flags());
- EXPECT_EQ(ui::ET_MOUSE_RELEASED, events[1].type());
- EXPECT_TRUE(ui::EF_RIGHT_MOUSE_BUTTON & events[1].flags());
- // Changing the event type cancels the event
- GetEventGenerator()->MoveMouseTo(60, 60);
- GetAutoclickController()->SetAutoclickEventType(
- AutoclickEventType::kLeftClick);
- events = WaitForMouseEvents();
- EXPECT_EQ(0u, events.size());
- // Changing the event type to the same thing does not cancel the event.
- // kLeftClick type does not produce a double-click.
- GetEventGenerator()->MoveMouseTo(90, 90);
- GetAutoclickController()->SetAutoclickEventType(
- AutoclickEventType::kLeftClick);
- events = WaitForMouseEvents();
- ASSERT_EQ(2u, events.size());
- EXPECT_EQ(ui::ET_MOUSE_PRESSED, events[0].type());
- EXPECT_TRUE(ui::EF_LEFT_MOUSE_BUTTON & events[0].flags());
- EXPECT_FALSE(ui::EF_IS_DOUBLE_CLICK & events[0].flags());
- EXPECT_EQ(ui::ET_MOUSE_RELEASED, events[1].type());
- EXPECT_TRUE(ui::EF_LEFT_MOUSE_BUTTON & events[1].flags());
- EXPECT_FALSE(ui::EF_IS_DOUBLE_CLICK & events[1].flags());
- // Double-click works as expected.
- GetAutoclickController()->SetAutoclickEventType(
- AutoclickEventType::kDoubleClick);
- GetEventGenerator()->MoveMouseTo(120, 120);
- events = WaitForMouseEvents();
- ASSERT_EQ(4u, events.size());
- EXPECT_EQ(ui::ET_MOUSE_PRESSED, events[0].type());
- EXPECT_TRUE(ui::EF_LEFT_MOUSE_BUTTON & events[0].flags());
- EXPECT_FALSE(ui::EF_IS_DOUBLE_CLICK & events[0].flags());
- EXPECT_EQ(ui::ET_MOUSE_RELEASED, events[1].type());
- EXPECT_TRUE(ui::EF_LEFT_MOUSE_BUTTON & events[1].flags());
- EXPECT_FALSE(ui::EF_IS_DOUBLE_CLICK & events[1].flags());
- EXPECT_EQ(ui::ET_MOUSE_PRESSED, events[2].type());
- EXPECT_TRUE(ui::EF_LEFT_MOUSE_BUTTON & events[2].flags());
- EXPECT_TRUE(ui::EF_IS_DOUBLE_CLICK & events[2].flags());
- EXPECT_EQ(ui::ET_MOUSE_RELEASED, events[3].type());
- EXPECT_TRUE(ui::EF_LEFT_MOUSE_BUTTON & events[3].flags());
- EXPECT_TRUE(ui::EF_IS_DOUBLE_CLICK & events[3].flags());
- // Pause / no action does not cause events to be generated even when the
- // mouse moves.
- GetAutoclickController()->SetAutoclickEventType(
- AutoclickEventType::kNoAction);
- GetEventGenerator()->MoveMouseTo(120, 120);
- events = WaitForMouseEvents();
- EXPECT_EQ(0u, events.size());
- }
- TEST_F(AutoclickTest, AutoclickDragAndDropEvents) {
- GetAutoclickController()->SetEnabled(true, false /* do not show dialog */);
- GetAutoclickController()->set_revert_to_left_click(false);
- GetAutoclickController()->SetAutoclickEventType(
- AutoclickEventType::kDragAndDrop);
- std::vector<ui::MouseEvent> events;
- GetEventGenerator()->MoveMouseTo(30, 30);
- events = WaitForMouseEvents();
- ASSERT_EQ(1u, events.size());
- EXPECT_EQ(ui::ET_MOUSE_PRESSED, events[0].type());
- EXPECT_TRUE(ui::EF_LEFT_MOUSE_BUTTON & events[0].flags());
- ClearMouseEvents();
- GetEventGenerator()->MoveMouseTo(60, 60);
- events = GetMouseEvents();
- ASSERT_EQ(1u, events.size());
- EXPECT_EQ(ui::ET_MOUSE_DRAGGED, events[0].type());
- // Another move creates a drag
- ClearMouseEvents();
- GetEventGenerator()->MoveMouseTo(90, 90);
- events = GetMouseEvents();
- ASSERT_EQ(1u, events.size());
- EXPECT_EQ(ui::ET_MOUSE_DRAGGED, events[0].type());
- // Waiting in place creates the released event.
- events = WaitForMouseEvents();
- ASSERT_EQ(1u, events.size());
- EXPECT_EQ(ui::ET_MOUSE_RELEASED, events[0].type());
- }
- TEST_F(AutoclickTest, AutoclickScrollEvents) {
- UpdateDisplay("800x600");
- GetAutoclickController()->SetEnabled(true, false /* do not show dialog */);
- GetAutoclickController()->SetAutoclickEventType(AutoclickEventType::kScroll);
- std::vector<ui::MouseEvent> events;
- std::vector<ui::MouseWheelEvent> wheel_events;
- // Expect that the first scroll action occurs at the middle of the screen,
- // since the position has not been set by the user.
- GetAutoclickController()->DoScrollAction(
- AutoclickController::ScrollPadAction::kScrollUp);
- events = GetMouseEvents();
- wheel_events = GetMouseWheelEvents();
- EXPECT_EQ(0u, events.size());
- ASSERT_EQ(1u, wheel_events.size());
- EXPECT_EQ(ui::ET_MOUSEWHEEL, wheel_events[0].type());
- EXPECT_EQ(gfx::Point(400, 300), wheel_events[0].location());
- EXPECT_GT(wheel_events[0].y_offset(), 0);
- ClearMouseEvents();
- // Expect that a dwell will set the scroll location.
- GetEventGenerator()->MoveMouseTo(90, 90);
- base::RunLoop().RunUntilIdle();
- GetAutoclickController()->DoScrollAction(
- AutoclickController::ScrollPadAction::kScrollUp);
- events = GetMouseEvents();
- wheel_events = GetMouseWheelEvents();
- EXPECT_EQ(0u, events.size());
- ASSERT_EQ(1u, wheel_events.size());
- EXPECT_EQ(ui::ET_MOUSEWHEEL, wheel_events[0].type());
- EXPECT_EQ(gfx::Point(90, 90), wheel_events[0].location());
- EXPECT_GT(wheel_events[0].y_offset(), 0);
- ClearMouseEvents();
- GetAutoclickController()->DoScrollAction(
- AutoclickController::ScrollPadAction::kScrollLeft);
- events = GetMouseEvents();
- wheel_events = GetMouseWheelEvents();
- EXPECT_EQ(0u, events.size());
- ASSERT_EQ(1u, wheel_events.size());
- EXPECT_EQ(ui::ET_MOUSEWHEEL, wheel_events[0].type());
- EXPECT_EQ(gfx::Point(90, 90), wheel_events[0].location());
- EXPECT_GT(wheel_events[0].x_offset(), 0);
- ClearMouseEvents();
- // Try another position, and the other two types of scroll action.
- GetEventGenerator()->MoveMouseTo(200, 200);
- base::RunLoop().RunUntilIdle();
- GetAutoclickController()->DoScrollAction(
- AutoclickController::ScrollPadAction::kScrollDown);
- events = GetMouseEvents();
- wheel_events = GetMouseWheelEvents();
- EXPECT_EQ(0u, events.size());
- ASSERT_EQ(1u, wheel_events.size());
- EXPECT_EQ(ui::ET_MOUSEWHEEL, wheel_events[0].type());
- EXPECT_EQ(gfx::Point(200, 200), wheel_events[0].location());
- EXPECT_LT(wheel_events[0].y_offset(), 0);
- ClearMouseEvents();
- GetAutoclickController()->DoScrollAction(
- AutoclickController::ScrollPadAction::kScrollRight);
- events = GetMouseEvents();
- wheel_events = GetMouseWheelEvents();
- EXPECT_EQ(0u, events.size());
- ASSERT_EQ(1u, wheel_events.size());
- EXPECT_EQ(ui::ET_MOUSEWHEEL, wheel_events[0].type());
- EXPECT_EQ(gfx::Point(200, 200), wheel_events[0].location());
- EXPECT_LT(wheel_events[0].x_offset(), 0);
- ClearMouseEvents();
- }
- TEST_F(AutoclickTest, AutoclickRevertsToLeftClick) {
- GetAutoclickController()->SetEnabled(true, false /* do not show dialog */);
- GetAutoclickController()->set_revert_to_left_click(true);
- GetAutoclickController()->SetAutoclickEventType(
- AutoclickEventType::kRightClick);
- std::vector<ui::MouseEvent> events;
- GetEventGenerator()->MoveMouseTo(30, 30);
- events = WaitForMouseEvents();
- ASSERT_EQ(2u, events.size());
- EXPECT_TRUE(ui::EF_RIGHT_MOUSE_BUTTON & events[0].flags());
- EXPECT_TRUE(ui::EF_RIGHT_MOUSE_BUTTON & events[1].flags());
- // Another event is now left-click; we've reverted to left click.
- GetEventGenerator()->MoveMouseTo(90, 90);
- GetAutoclickController()->SetAutoclickEventType(
- AutoclickEventType::kLeftClick);
- events = WaitForMouseEvents();
- ASSERT_EQ(2u, events.size());
- EXPECT_TRUE(ui::EF_LEFT_MOUSE_BUTTON & events[0].flags());
- EXPECT_TRUE(ui::EF_LEFT_MOUSE_BUTTON & events[1].flags());
- // The next event is also a left click.
- GetEventGenerator()->MoveMouseTo(120, 120);
- GetAutoclickController()->SetAutoclickEventType(
- AutoclickEventType::kLeftClick);
- events = WaitForMouseEvents();
- ASSERT_EQ(2u, events.size());
- EXPECT_TRUE(ui::EF_LEFT_MOUSE_BUTTON & events[0].flags());
- EXPECT_TRUE(ui::EF_LEFT_MOUSE_BUTTON & events[1].flags());
- // Changing revert to false doesn't change that we are on left click at
- // present.
- GetAutoclickController()->set_revert_to_left_click(false);
- GetEventGenerator()->MoveMouseTo(150, 150);
- GetAutoclickController()->SetAutoclickEventType(
- AutoclickEventType::kLeftClick);
- events = WaitForMouseEvents();
- ASSERT_EQ(2u, events.size());
- EXPECT_TRUE(ui::EF_LEFT_MOUSE_BUTTON & events[0].flags());
- EXPECT_TRUE(ui::EF_LEFT_MOUSE_BUTTON & events[1].flags());
- // But we should no longer revert to left click if the type is something else.
- GetAutoclickController()->SetAutoclickEventType(
- AutoclickEventType::kRightClick);
- GetEventGenerator()->MoveMouseTo(180, 180);
- events = WaitForMouseEvents();
- ASSERT_EQ(2u, events.size());
- EXPECT_TRUE(ui::EF_RIGHT_MOUSE_BUTTON & events[0].flags());
- EXPECT_TRUE(ui::EF_RIGHT_MOUSE_BUTTON & events[1].flags());
- // Should still be right click.
- GetEventGenerator()->MoveMouseTo(210, 210);
- events = WaitForMouseEvents();
- ASSERT_EQ(2u, events.size());
- EXPECT_TRUE(ui::EF_RIGHT_MOUSE_BUTTON & events[0].flags());
- EXPECT_TRUE(ui::EF_RIGHT_MOUSE_BUTTON & events[1].flags());
- }
- TEST_F(AutoclickTest, WaitsToDrawAnimationAfterDwellBegins) {
- int animation_delay = 5;
- int full_delay = UpdateAnimationDelayAndGetFullDelay(animation_delay);
- GetAutoclickController()->SetEnabled(true, false /* do not show dialog */);
- std::vector<ui::MouseEvent> events;
- // Start a dwell at (210, 210).
- GetEventGenerator()->MoveMouseTo(210, 210);
- // The center should change to (205, 205) if the adjustment is made before
- // the animation starts.
- FastForwardBy(animation_delay - 1);
- GetEventGenerator()->MoveMouseTo(205, 205);
- // Now wait the full delay to ensure the click has happened, then check
- // the result.
- FastForwardBy(full_delay);
- events = GetMouseEvents();
- ASSERT_EQ(2u, events.size());
- EXPECT_EQ(gfx::Point(205, 205), events[0].location());
- // Start another dwell at (100, 100).
- ClearMouseEvents();
- GetEventGenerator()->MoveMouseTo(100, 100);
- // Move the mouse a little to (105, 105), which should become the center.
- FastForwardBy(animation_delay - 1);
- GetEventGenerator()->MoveMouseTo(105, 105);
- // Moving the mouse during the animation changes the center point.
- FastForwardBy(animation_delay);
- GetEventGenerator()->MoveMouseTo(110, 110);
- // Now wait until the click. It should be at the center point from before
- // the animation started.
- FastForwardBy(full_delay);
- events = GetMouseEvents();
- ASSERT_EQ(2u, events.size());
- EXPECT_EQ(gfx::Point(110, 110), events[0].location());
- // Turn off stabilize_click_position and try again, the position should update
- // with the cursor's new position until the click occurs.
- GetAutoclickController()->set_stabilize_click_position(true);
- ClearMouseEvents();
- GetEventGenerator()->MoveMouseTo(200, 200);
- // (205, 205) will become the center of the animation.
- FastForwardBy(animation_delay - 1);
- GetEventGenerator()->MoveMouseTo(205, 205);
- // Fast forward until the animation would have started. Now moving the mouse
- // a little does not change the center point because we have stabilize on.
- FastForwardBy(animation_delay);
- GetEventGenerator()->MoveMouseTo(210, 210);
- FastForwardBy(full_delay);
- events = GetMouseEvents();
- ASSERT_EQ(2u, events.size());
- EXPECT_EQ(gfx::Point(205, 205), events[0].location());
- // Reset state.
- GetAutoclickController()->set_stabilize_click_position(false);
- }
- TEST_F(AutoclickTest, DoesActionOnBubbleWhenInDifferentModes) {
- AccessibilityControllerImpl* accessibility_controller =
- Shell::Get()->accessibility_controller();
- // Enable autoclick from the accessibility controller so that the bubble is
- // constructed too.
- accessibility_controller->autoclick().SetEnabled(true);
- GetAutoclickController()->set_revert_to_left_click(false);
- std::vector<ui::MouseEvent> events;
- // Test at different screen sizes and densities because the fake click on
- // the button involves coordinating between dips and pixels. Try two different
- // positions to ensure offsets are calculated correctly.
- const struct {
- const std::string display_spec;
- float scale;
- FloatingMenuPosition position;
- } kTestCases[] = {
- {"800x600", 1.0f, FloatingMenuPosition::kBottomRight},
- {"1024x800*2.0", 2.0f, FloatingMenuPosition::kBottomRight},
- {"800x600", 1.0f, FloatingMenuPosition::kTopLeft},
- {"1024x800*2.0", 2.0f, FloatingMenuPosition::kTopLeft},
- };
- for (const auto& test : kTestCases) {
- UpdateDisplay(test.display_spec);
- accessibility_controller->SetAutoclickMenuPosition(test.position);
- accessibility_controller->SetAutoclickEventType(
- AutoclickEventType::kRightClick);
- AutoclickMenuView* menu = GetAutoclickMenuView();
- ASSERT_TRUE(menu);
- // Outside of the bubble, a right-click still occurs.
- // Move to a central position which will not have any menu but will still be
- // on-screen.
- GetEventGenerator()->MoveMouseTo(200 * test.scale, 200 * test.scale);
- events = WaitForMouseEvents();
- ASSERT_EQ(2u, events.size());
- EXPECT_TRUE(ui::EF_RIGHT_MOUSE_BUTTON & events[0].flags());
- EXPECT_TRUE(ui::EF_RIGHT_MOUSE_BUTTON & events[1].flags());
- // Over the bubble, we get no real click, although the autoclick event
- // type does get changed properly over a button.
- gfx::Point button_location = gfx::ScaleToRoundedPoint(
- GetMenuButton(AutoclickMenuView::ButtonId::kDoubleClick)
- ->GetBoundsInScreen()
- .CenterPoint(),
- test.scale);
- GetEventGenerator()->MoveMouseTo(button_location);
- events = WaitForMouseEvents();
- EXPECT_EQ(0u, events.size());
- // But the event type did change with a the hover on the button.
- EXPECT_EQ(AutoclickEventType::kDoubleClick,
- accessibility_controller->GetAutoclickEventType());
- // Change to a pause action type.
- accessibility_controller->SetAutoclickEventType(
- AutoclickEventType::kNoAction);
- // Outside the bubble, no action occurs.
- GetEventGenerator()->MoveMouseTo(200 * test.scale, 200 * test.scale);
- events = WaitForMouseEvents();
- EXPECT_EQ(0u, events.size());
- // If we move over the bubble but not over any button than no real click
- // occurs. There is no button at the top of the bubble.
- button_location = gfx::ScaleToRoundedPoint(
- GetAutoclickMenuView()->GetBoundsInScreen().top_center() +
- gfx::Vector2d(0, 1),
- test.scale);
- GetEventGenerator()->MoveMouseTo(button_location);
- events = WaitForMouseEvents();
- EXPECT_EQ(0u, events.size());
- // The event type did not change because we were not over any button.
- EXPECT_EQ(AutoclickEventType::kNoAction,
- accessibility_controller->GetAutoclickEventType());
- // Leaving the bubble we are still paused.
- GetEventGenerator()->MoveMouseTo(200 * test.scale, 200 * test.scale);
- events = WaitForMouseEvents();
- EXPECT_EQ(0u, events.size());
- // Moving over another button takes an action.
- button_location = gfx::ScaleToRoundedPoint(
- GetMenuButton(AutoclickMenuView::ButtonId::kLeftClick)
- ->GetBoundsInScreen()
- .CenterPoint(),
- test.scale);
- GetEventGenerator()->MoveMouseTo(button_location);
- events = WaitForMouseEvents();
- EXPECT_EQ(0u, events.size());
- EXPECT_EQ(AutoclickEventType::kLeftClick,
- accessibility_controller->GetAutoclickEventType());
- }
- }
- TEST_F(AutoclickTest,
- StartsGestureOnBubbleButDoesNotClickIfMouseMovedWhenPaused) {
- Shell::Get()->accessibility_controller()->autoclick().SetEnabled(true);
- GetAutoclickController()->set_revert_to_left_click(false);
- GetAutoclickController()->SetAutoclickEventType(
- AutoclickEventType::kNoAction);
- Shell::Get()->accessibility_controller()->SetAutoclickMenuPosition(
- FloatingMenuPosition::kBottomRight);
- int animation_delay = 5;
- int full_delay = UpdateAnimationDelayAndGetFullDelay(animation_delay);
- std::vector<ui::MouseEvent> events;
- AutoclickMenuView* menu = GetAutoclickMenuView();
- ASSERT_TRUE(menu);
- // Start a dwell over the bubble.
- GetEventGenerator()->MoveMouseTo(menu->GetBoundsInScreen().origin());
- // Move back off the bubble before anything happens.
- FastForwardBy(animation_delay - 1);
- GetEventGenerator()->MoveMouseTo(30, 30);
- // Now wait the full delay to ensure pause could have happened.
- FastForwardBy(full_delay);
- events = GetMouseEvents();
- ASSERT_EQ(0u, events.size());
- // This time, dwell over the bubble long enough for the animation to begin.
- // No action should occur if we move off during the dwell.
- GetEventGenerator()->MoveMouseTo(menu->GetBoundsInScreen().origin());
- // Move back off the bubble after the animation begins, but before a click
- // would occur.
- FastForwardBy(animation_delay + 1);
- GetEventGenerator()->MoveMouseTo(30, 30);
- // Now wait the full delay to ensure pause could have happened.
- FastForwardBy(full_delay);
- events = GetMouseEvents();
- ASSERT_EQ(0u, events.size());
- }
- // The autoclick tray shouldn't stop the shelf from auto-hiding.
- TEST_F(AutoclickTest, ShelfAutohidesWithAutoclickBubble) {
- Shelf* shelf = GetPrimaryShelf();
- // Create a visible window so auto-hide behavior is enforced.
- std::unique_ptr<views::Widget> widget =
- CreateTestWidget(nullptr, desks_util::GetActiveDeskContainerId(),
- gfx::Rect(0, 0, 200, 200), true /* show */);
- // Turn on auto-hide for the shelf.
- shelf->SetAutoHideBehavior(ShelfAutoHideBehavior::kAlways);
- EXPECT_EQ(SHELF_AUTO_HIDE, shelf->GetVisibilityState());
- EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->GetAutoHideState());
- // Enable autoclick. The shelf should remain invisible.
- Shell::Get()->accessibility_controller()->autoclick().SetEnabled(true);
- AutoclickMenuView* menu = GetAutoclickMenuView();
- ASSERT_TRUE(menu);
- EXPECT_EQ(SHELF_AUTO_HIDE, shelf->GetVisibilityState());
- EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->GetAutoHideState());
- }
- TEST_F(AutoclickTest, BubbleMovesWithShelfPositionChange) {
- UpdateDisplay("800x600");
- int screen_width = 800;
- int screen_height = 600;
- // Create a visible window so WMEvents occur.
- std::unique_ptr<views::Widget> widget =
- CreateTestWidget(nullptr, desks_util::GetActiveDeskContainerId(),
- gfx::Rect(0, 0, 200, 200), true /* show */);
- // Set up autoclick and the shelf.
- Shell::Get()->accessibility_controller()->autoclick().SetEnabled(true);
- Shell::Get()->accessibility_controller()->SetAutoclickMenuPosition(
- FloatingMenuPosition::kBottomRight);
- Shelf* shelf = GetPrimaryShelf();
- shelf->SetAutoHideBehavior(ShelfAutoHideBehavior::kNever);
- EXPECT_EQ(shelf->GetVisibilityState(), SHELF_VISIBLE);
- AutoclickMenuView* menu = GetAutoclickMenuView();
- ASSERT_TRUE(menu);
- shelf->SetAlignment(ShelfAlignment::kBottom);
- // The menu should be positioned above the shelf, not overlapping.
- EXPECT_EQ(menu->GetBoundsInScreen().bottom_right().y(),
- screen_height - shelf->GetIdealBounds().height() -
- kCollisionWindowWorkAreaInsetsDp);
- // And all the way to the right.
- EXPECT_EQ(menu->GetBoundsInScreen().bottom_right().x(),
- screen_width - kCollisionWindowWorkAreaInsetsDp);
- shelf->SetAlignment(ShelfAlignment::kLeft);
- // The menu should move to the bottom of the screen.
- EXPECT_EQ(menu->GetBoundsInScreen().bottom_right().y(),
- screen_height - kCollisionWindowWorkAreaInsetsDp);
- // Still be at the far right.
- EXPECT_EQ(menu->GetBoundsInScreen().bottom_right().x(),
- screen_width - kCollisionWindowWorkAreaInsetsDp);
- shelf->SetAlignment(ShelfAlignment::kRight);
- // The menu should stay at the bottom of the screen.
- EXPECT_EQ(menu->GetBoundsInScreen().bottom_right().y(),
- screen_height - kCollisionWindowWorkAreaInsetsDp);
- // And should be offset from the far right by the shelf width.
- EXPECT_EQ(menu->GetBoundsInScreen().bottom_right().x(),
- screen_width - kCollisionWindowWorkAreaInsetsDp -
- shelf->GetIdealBounds().width());
- // Reset state.
- shelf->SetAlignment(ShelfAlignment::kBottom);
- }
- TEST_F(AutoclickTest, AvoidsShelfBubble) {
- const struct {
- session_manager::SessionState session_state;
- } kTestCases[]{
- {session_manager::SessionState::OOBE},
- {session_manager::SessionState::LOGIN_PRIMARY},
- {session_manager::SessionState::ACTIVE},
- {session_manager::SessionState::LOCKED},
- };
- for (auto test : kTestCases) {
- GetSessionControllerClient()->SetSessionState(test.session_state);
- // Set up autoclick and the shelf.
- Shell::Get()->accessibility_controller()->autoclick().SetEnabled(true);
- Shell::Get()->accessibility_controller()->SetAutoclickMenuPosition(
- FloatingMenuPosition::kBottomRight);
- auto* unified_system_tray = GetPrimaryUnifiedSystemTray();
- EXPECT_FALSE(unified_system_tray->IsBubbleShown());
- AutoclickMenuView* menu = GetAutoclickMenuView();
- ASSERT_TRUE(menu);
- gfx::Rect menu_bounds = menu->GetBoundsInScreen();
- unified_system_tray->ShowBubble();
- gfx::Rect new_menu_bounds = menu->GetBoundsInScreen();
- const int dx = abs(menu_bounds.x() - new_menu_bounds.x());
- const int dy = abs(menu_bounds.y() - new_menu_bounds.y());
- const gfx::Rect bubble_bounds =
- unified_system_tray->GetBubbleBoundsInScreen();
- // The height of the system tray bubble is dependent on the number of
- // feature pods, and whether the a11y widget goes above or to the side of
- // the system tray is dependent on the height of the system tray. Test that
- // one and only one of these situations is applicable.
- EXPECT_TRUE((dx < 5 && dy > bubble_bounds.height()) ||
- (dy < 5 && dx > bubble_bounds.width()));
- unified_system_tray->CloseBubble();
- new_menu_bounds = menu->GetBoundsInScreen();
- EXPECT_EQ(menu_bounds, new_menu_bounds);
- }
- }
- TEST_F(AutoclickTest, ConfirmationDialogShownWhenDisablingFeature) {
- // Enable and disable with the AccessibilityController to get real use-case
- // of the dialog.
- // No dialog shown at start-up.
- EXPECT_FALSE(GetAutoclickController()->GetDisableDialogForTesting());
- // No dialog shown when enabling the feature.
- Shell::Get()->accessibility_controller()->autoclick().SetEnabled(true);
- EXPECT_FALSE(GetAutoclickController()->GetDisableDialogForTesting());
- // A dialog should be shown when disabling the feature.
- Shell::Get()->accessibility_controller()->autoclick().SetEnabled(false);
- AccessibilityFeatureDisableDialog* dialog =
- GetAutoclickController()->GetDisableDialogForTesting();
- ASSERT_TRUE(dialog);
- // Canceling the dialog will cause the feature to continue to be enabled.
- dialog->CancelDialog();
- base::RunLoop().RunUntilIdle();
- EXPECT_FALSE(GetAutoclickController()->GetDisableDialogForTesting());
- EXPECT_TRUE(Shell::Get()->accessibility_controller()->autoclick().enabled());
- EXPECT_TRUE(GetAutoclickController()->IsEnabled());
- // Try to disable it again, and this time accept the dialog to actually
- // disable the feature.
- Shell::Get()->accessibility_controller()->autoclick().SetEnabled(false);
- dialog = GetAutoclickController()->GetDisableDialogForTesting();
- ASSERT_TRUE(dialog);
- dialog->AcceptDialog();
- base::RunLoop().RunUntilIdle();
- EXPECT_FALSE(GetAutoclickController()->GetDisableDialogForTesting());
- EXPECT_FALSE(Shell::Get()->accessibility_controller()->autoclick().enabled());
- EXPECT_FALSE(GetAutoclickController()->IsEnabled());
- }
- TEST_F(AutoclickTest, HidesBubbleInFullscreenWhenCursorHides) {
- Shell::Get()->accessibility_controller()->autoclick().SetEnabled(true);
- ::wm::CursorManager* cursor_manager = Shell::Get()->cursor_manager();
- cursor_manager->SetCursor(ui::mojom::CursorType::kPointer);
- const struct {
- const std::string display_spec;
- gfx::Rect widget_position;
- } kTestCases[] = {
- {"800x600", gfx::Rect(0, 0, 200, 200)},
- {"800x600,800x600", gfx::Rect(0, 0, 200, 200)},
- {"800x600,800x600", gfx::Rect(1000, 0, 200, 200)},
- };
- for (const auto& test : kTestCases) {
- SCOPED_TRACE(test.display_spec);
- UpdateDisplay(test.display_spec);
- std::unique_ptr<views::Widget> widget = CreateTestWidget(
- nullptr, desks_util::GetActiveDeskContainerId(), test.widget_position,
- /*show=*/true);
- EXPECT_TRUE(GetAutoclickBubbleWidget()->IsVisible());
- // Move the mouse over the widget, so it's on the same screen as the widget.
- GetEventGenerator()->MoveMouseTo(test.widget_position.origin());
- // When the widget is not fullscreen, hiding the cursor does not cause
- // the bubble to be hidden.
- cursor_manager->HideCursor();
- EXPECT_TRUE(GetAutoclickBubbleWidget()->IsVisible());
- cursor_manager->ShowCursor();
- EXPECT_TRUE(GetAutoclickBubbleWidget()->IsVisible());
- // Bubble is visible in fullscreen mode because the mouse cursor is visible.
- widget->SetFullscreen(true);
- EXPECT_TRUE(GetAutoclickBubbleWidget()->IsVisible());
- // Bubble is hidden when the cursor is hidden in fullscreen mode, and shown
- // when the cursor is shown.
- cursor_manager->HideCursor();
- EXPECT_FALSE(GetAutoclickBubbleWidget()->IsVisible());
- cursor_manager->ShowCursor();
- EXPECT_TRUE(GetAutoclickBubbleWidget()->IsVisible());
- // Changing the type to another visible type doesn't cause the bubble to
- // hide.
- cursor_manager->SetCursor(ui::mojom::CursorType::kHand);
- EXPECT_TRUE(GetAutoclickBubbleWidget()->IsVisible());
- // Changing the type to an kNone causes the bubble to hide.
- cursor_manager->SetCursor(ui::mojom::CursorType::kNone);
- EXPECT_FALSE(GetAutoclickBubbleWidget()->IsVisible());
- // Hiding and showing don't re-show the bubble because the type is still
- // kNone.
- cursor_manager->HideCursor();
- EXPECT_FALSE(GetAutoclickBubbleWidget()->IsVisible());
- cursor_manager->ShowCursor();
- EXPECT_FALSE(GetAutoclickBubbleWidget()->IsVisible());
- // The bubble is shown when the cursor is a visible type again.
- cursor_manager->SetCursor(ui::mojom::CursorType::kPointer);
- EXPECT_TRUE(GetAutoclickBubbleWidget()->IsVisible());
- }
- }
- TEST_F(AutoclickTest, DoesNotHideBubbleWhenNotOverFullscreenWindow) {
- UpdateDisplay("800x600,800x600");
- Shell::Get()->accessibility_controller()->autoclick().SetEnabled(true);
- ::wm::CursorManager* cursor_manager = Shell::Get()->cursor_manager();
- cursor_manager->SetCursor(ui::mojom::CursorType::kPointer);
- std::unique_ptr<views::Widget> widget =
- CreateTestWidget(nullptr, desks_util::GetActiveDeskContainerId(),
- gfx::Rect(1000, 0, 200, 200), true);
- EXPECT_TRUE(GetAutoclickBubbleWidget()->IsVisible());
- // Move the mouse over the other display.
- GetEventGenerator()->MoveMouseTo(gfx::Point(10, 10));
- // When the widget is fullscreen, hiding the cursor does not hide the bubble
- // because the cursor is on a different display.
- widget->SetFullscreen(true);
- cursor_manager->HideCursor();
- EXPECT_TRUE(GetAutoclickBubbleWidget()->IsVisible());
- }
- TEST_F(AutoclickTest, DoesNotHideBubbleWhenOverInactiveFullscreenWindow) {
- Shell::Get()->accessibility_controller()->autoclick().SetEnabled(true);
- ::wm::CursorManager* cursor_manager = Shell::Get()->cursor_manager();
- cursor_manager->SetCursor(ui::mojom::CursorType::kPointer);
- std::unique_ptr<views::Widget> widget =
- CreateTestWidget(nullptr, desks_util::GetActiveDeskContainerId(),
- gfx::Rect(0, 0, 200, 200), true);
- GetEventGenerator()->MoveMouseTo(gfx::Point(10, 10));
- widget->SetFullscreen(true);
- EXPECT_TRUE(widget->IsActive());
- views::Widget* popup_widget = views::Widget::CreateWindowWithContext(
- nullptr, GetContext(), gfx::Rect(200, 200, 200, 200));
- popup_widget->Show();
- cursor_manager->HideCursor();
- EXPECT_FALSE(widget->IsActive());
- EXPECT_TRUE(popup_widget->IsActive());
- EXPECT_TRUE(GetAutoclickBubbleWidget()->IsVisible());
- }
- TEST_F(AutoclickTest, ScrollClosesWhenHoveredOverScrollButton) {
- GetAutoclickController()->SetEnabled(true, false /* do not show dialog */);
- GetAutoclickController()->SetAutoclickEventType(
- AutoclickEventType::kLeftClick);
- EXPECT_FALSE(GetAutoclickScrollView());
- // Enable scroll.
- GetAutoclickController()->SetAutoclickEventType(AutoclickEventType::kScroll);
- ASSERT_TRUE(GetAutoclickScrollView());
- views::View* close_button =
- GetScrollButton(AutoclickScrollView::ButtonId::kCloseScroll);
- ASSERT_TRUE(close_button);
- gfx::Point button_location = close_button->GetBoundsInScreen().CenterPoint();
- GetEventGenerator()->MoveMouseTo(button_location);
- // No mouse event.
- std::vector<ui::MouseEvent> events = WaitForMouseEvents();
- EXPECT_EQ(0u, events.size());
- // Reset to left click and scroll view is gone.
- EXPECT_EQ(AutoclickEventType::kLeftClick,
- Shell::Get()->accessibility_controller()->GetAutoclickEventType());
- EXPECT_FALSE(GetAutoclickScrollView());
- }
- TEST_F(AutoclickTest, ScrollOccursWhenHoveredOverScrollButtons) {
- UpdateDisplay("800x600");
- GetAutoclickController()->SetEnabled(true, false /* do not show dialog */);
- // Enable scroll.
- GetAutoclickController()->SetAutoclickEventType(AutoclickEventType::kScroll);
- ASSERT_TRUE(GetAutoclickScrollView());
- // TODO: Do for all four buttons, wait a few scrolls each.
- const struct {
- AutoclickScrollView::ButtonId button_id;
- int scroll_x;
- int scroll_y;
- } kTestCases[] = {
- {AutoclickScrollView::ButtonId::kScrollUp, 0, 10},
- {AutoclickScrollView::ButtonId::kScrollDown, 0, -10},
- {AutoclickScrollView::ButtonId::kScrollLeft, 10, 0},
- {AutoclickScrollView::ButtonId::kScrollRight, -10, 0},
- };
- for (auto& test : kTestCases) {
- views::View* button = GetScrollButton(test.button_id);
- ASSERT_TRUE(button);
- gfx::Point button_location = button->GetBoundsInScreen().CenterPoint();
- GetEventGenerator()->MoveMouseTo(button_location);
- // No mouse event during hover, no wheel events yet.
- FastForwardBy(AutoclickScrollView::kAutoclickScrollDelayMs - 1);
- std::vector<ui::MouseEvent> events = GetMouseEvents();
- EXPECT_EQ(0u, events.size());
- std::vector<ui::MouseWheelEvent> wheel_events = GetMouseWheelEvents();
- EXPECT_EQ(0u, wheel_events.size());
- // But we should get a scroll event after kAutoclickScrollDelayMs.
- FastForwardBy(2);
- wheel_events = GetMouseWheelEvents();
- EXPECT_EQ(1u, wheel_events.size());
- EXPECT_EQ(gfx::Point(400, 300), wheel_events[0].location());
- EXPECT_EQ(test.scroll_x, wheel_events[0].x_offset());
- EXPECT_EQ(test.scroll_y, wheel_events[0].y_offset());
- // No other events expected.
- events = GetMouseEvents();
- EXPECT_EQ(0u, events.size());
- ClearMouseEvents();
- // Wait until another kAutoclickScrollDelayMs has elapsed and expect another
- // scroll to have occurred.
- FastForwardBy(AutoclickScrollView::kAutoclickScrollDelayMs);
- wheel_events = GetMouseWheelEvents();
- EXPECT_EQ(1u, wheel_events.size());
- EXPECT_EQ(gfx::Point(400, 300), wheel_events[0].location());
- EXPECT_EQ(test.scroll_x, wheel_events[0].x_offset());
- EXPECT_EQ(test.scroll_y, wheel_events[0].y_offset());
- // No other events expected.
- events = GetMouseEvents();
- EXPECT_EQ(0u, events.size());
- ClearMouseEvents();
- }
- }
- TEST_F(AutoclickTest, ScrollMenuBubblePostioning) {
- UpdateDisplay("800x600");
- GetAutoclickController()->SetEnabled(true, false /* do not show dialog */);
- Shell::Get()->accessibility_controller()->SetAutoclickMenuPosition(
- FloatingMenuPosition::kBottomRight);
- GetAutoclickController()->SetAutoclickEventType(AutoclickEventType::kScroll);
- ASSERT_TRUE(GetAutoclickScrollView());
- // Set the bounds to be the entire window.
- gfx::Rect display_bounds = gfx::Rect(0, 0, 800, 600);
- GetAutoclickController()->HandleAutoclickScrollableBoundsFound(
- display_bounds);
- // The scroll bubble should start near the autoclick menu.
- gfx::Rect scroll_bounds = GetAutoclickScrollView()->GetBoundsInScreen();
- gfx::Rect menu_bounds = GetAutoclickMenuView()->GetBoundsInScreen();
- EXPECT_LT(menu_bounds.ManhattanInternalDistance(scroll_bounds),
- kScrollToMenuBoundsBuffer);
- // Moving the autoclick menu around the screen moves the scroll bubble too.
- Shell::Get()->accessibility_controller()->SetAutoclickMenuPosition(
- FloatingMenuPosition::kBottomLeft);
- scroll_bounds = GetAutoclickScrollView()->GetBoundsInScreen();
- menu_bounds = GetAutoclickMenuView()->GetBoundsInScreen();
- EXPECT_LT(menu_bounds.ManhattanInternalDistance(scroll_bounds),
- kScrollToMenuBoundsBuffer);
- Shell::Get()->accessibility_controller()->SetAutoclickMenuPosition(
- FloatingMenuPosition::kTopLeft);
- scroll_bounds = GetAutoclickScrollView()->GetBoundsInScreen();
- menu_bounds = GetAutoclickMenuView()->GetBoundsInScreen();
- EXPECT_LT(menu_bounds.ManhattanInternalDistance(scroll_bounds),
- kScrollToMenuBoundsBuffer);
- Shell::Get()->accessibility_controller()->SetAutoclickMenuPosition(
- FloatingMenuPosition::kTopRight);
- scroll_bounds = GetAutoclickScrollView()->GetBoundsInScreen();
- menu_bounds = GetAutoclickMenuView()->GetBoundsInScreen();
- EXPECT_LT(menu_bounds.ManhattanInternalDistance(scroll_bounds),
- kScrollToMenuBoundsBuffer);
- // However, if we dwell somewhere else, the autoclick scroll menu will now
- // move out of the corner and near that point when the display bounds are
- // found.
- gfx::Point scroll_point = gfx::Point(0, 0);
- GetEventGenerator()->MoveMouseTo(scroll_point);
- base::RunLoop().RunUntilIdle();
- GetAutoclickController()->HandleAutoclickScrollableBoundsFound(
- display_bounds);
- scroll_bounds = GetAutoclickScrollView()->GetBoundsInScreen();
- EXPECT_GT(menu_bounds.ManhattanInternalDistance(scroll_bounds),
- kScrollToMenuBoundsBuffer);
- // Moving the bubble menu now does not change the scroll bubble's position,
- // it remains near its point.
- Shell::Get()->accessibility_controller()->SetAutoclickMenuPosition(
- FloatingMenuPosition::kBottomRight);
- EXPECT_EQ(GetAutoclickScrollView()->GetBoundsInScreen(), scroll_bounds);
- }
- } // namespace ash
|