// Copyright 2015 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/display/unified_mouse_warp_controller.h" #include "ash/display/display_manager.h" #include "ash/display/display_util.h" #include "ash/display/mirror_window_controller.h" #include "ash/display/mouse_cursor_event_filter.h" #include "ash/host/ash_window_tree_host.h" #include "ash/shell.h" #include "ash/test/ash_test_base.h" #include "ash/test/display_manager_test_api.h" #include "ui/aura/env.h" #include "ui/aura/window_tree_host.h" #include "ui/events/test/event_generator.h" #include "ui/gfx/display.h" #include "ui/gfx/screen.h" #include "ui/wm/core/coordinate_conversion.h" namespace ash { class UnifiedMouseWarpControllerTest : public test::AshTestBase { public: UnifiedMouseWarpControllerTest() {} ~UnifiedMouseWarpControllerTest() override {} void SetUp() override { test::AshTestBase::SetUp(); Shell::GetInstance()->display_manager()->SetUnifiedDesktopEnabled(true); } protected: bool FindMirrroingDisplayIdContainingNativePoint( const gfx::Point& point_in_native, int64_t* display_id, gfx::Point* point_in_mirroring_host, gfx::Point* point_in_unified_host) { DisplayManager* display_manager = Shell::GetInstance()->display_manager(); for (auto display : display_manager->software_mirroring_display_list()) { DisplayInfo info = display_manager->GetDisplayInfo(display.id()); if (info.bounds_in_native().Contains(point_in_native)) { *display_id = info.id(); *point_in_unified_host = point_in_native; const gfx::Point& origin = info.bounds_in_native().origin(); // Convert to mirroring host. point_in_unified_host->Offset(-origin.x(), -origin.y()); *point_in_mirroring_host = *point_in_unified_host; // Convert from mirroring host to unified host. AshWindowTreeHost* ash_host = Shell::GetInstance() ->window_tree_host_manager() ->mirror_window_controller() ->GetAshWindowTreeHostForDisplayId(info.id()); ash_host->AsWindowTreeHost()->ConvertPointFromHost( point_in_unified_host); return true; } } return false; } bool TestIfMouseWarpsAt(const gfx::Point& point_in_native) { static_cast( Shell::GetInstance() ->mouse_cursor_filter() ->mouse_warp_controller_for_test()) ->update_location_for_test(); DisplayManager* display_manager = Shell::GetInstance()->display_manager(); int64_t orig_mirroring_display_id; gfx::Point point_in_unified_host; gfx::Point point_in_mirroring_host; if (!FindMirrroingDisplayIdContainingNativePoint( point_in_native, &orig_mirroring_display_id, &point_in_mirroring_host, &point_in_unified_host)) { return false; } #if defined(USE_OZONE) // The location of the ozone's native event is relative to the host. GetEventGenerator().MoveMouseToWithNative(point_in_unified_host, point_in_mirroring_host); #else GetEventGenerator().MoveMouseToWithNative(point_in_unified_host, point_in_native); #endif aura::Window* root = Shell::GetPrimaryRootWindow(); gfx::Point new_location_in_unified_host = aura::Env::GetInstance()->last_mouse_location(); // Convert screen to the host. root->GetHost()->ConvertPointToHost(&new_location_in_unified_host); int new_index = FindDisplayIndexContainingPoint( display_manager->software_mirroring_display_list(), new_location_in_unified_host); if (new_index < 0) return false; return orig_mirroring_display_id != display_manager->software_mirroring_display_list()[new_index].id(); } MouseCursorEventFilter* event_filter() { return Shell::GetInstance()->mouse_cursor_filter(); } UnifiedMouseWarpController* mouse_warp_controller() { return static_cast( event_filter()->mouse_warp_controller_for_test()); } void BoundaryTestBody(const std::string& displays_with_same_height, const std::string& displays_with_different_heights) { UpdateDisplay(displays_with_same_height); aura::Window::Windows root_windows = Shell::GetAllRootWindows(); // Let the UnifiedMouseWarpController compute the bounds by // generating a mouse move event. GetEventGenerator().MoveMouseTo(gfx::Point(0, 0)); EXPECT_EQ("399,0 1x400", mouse_warp_controller()->first_edge_bounds_in_native_.ToString()); EXPECT_EQ( "0,450 1x400", mouse_warp_controller()->second_edge_bounds_in_native_.ToString()); // Scaled. UpdateDisplay(displays_with_different_heights); root_windows = Shell::GetAllRootWindows(); // Let the UnifiedMouseWarpController compute the bounds by // generating a mouse move event. GetEventGenerator().MoveMouseTo(gfx::Point(1, 1)); EXPECT_EQ("399,0 1x400", mouse_warp_controller()->first_edge_bounds_in_native_.ToString()); EXPECT_EQ( "0,450 1x600", mouse_warp_controller()->second_edge_bounds_in_native_.ToString()); } void NoWarpTestBody() { // Touch the left edge of the first display. EXPECT_FALSE(TestIfMouseWarpsAt(gfx::Point(0, 10))); // Touch the top edge of the first display. EXPECT_FALSE(TestIfMouseWarpsAt(gfx::Point(10, 0))); // Touch the bottom edge of the first display. EXPECT_FALSE(TestIfMouseWarpsAt(gfx::Point(10, 499))); // Touch the right edge of the second display. EXPECT_FALSE(TestIfMouseWarpsAt(gfx::Point(1099, 10))); // Touch the top edge of the second display. EXPECT_FALSE(TestIfMouseWarpsAt(gfx::Point(610, 0))); // Touch the bottom edge of the second display. EXPECT_FALSE(TestIfMouseWarpsAt(gfx::Point(610, 499))); } private: DISALLOW_COPY_AND_ASSIGN(UnifiedMouseWarpControllerTest); }; // Verifies if MouseCursorEventFilter's bounds calculation works correctly. TEST_F(UnifiedMouseWarpControllerTest, BoundaryTest) { if (!SupportsMultipleDisplays()) return; { SCOPED_TRACE("1x1"); BoundaryTestBody("400x400,0+450-700x400", "400x400,0+450-700x600"); } { SCOPED_TRACE("2x1"); BoundaryTestBody("400x400*2,0+450-700x400", "400x400*2,0+450-700x600"); } { SCOPED_TRACE("1x2"); BoundaryTestBody("400x400,0+450-700x400*2", "400x400,0+450-700x600*2"); } { SCOPED_TRACE("2x2"); BoundaryTestBody("400x400*2,0+450-700x400*2", "400x400*2,0+450-700x600*2"); } } // Verifies if the mouse pointer correctly moves to another display in // unified desktop mode. TEST_F(UnifiedMouseWarpControllerTest, WarpMouse) { if (!SupportsMultipleDisplays()) return; UpdateDisplay("500x500,600+0-500x500"); ASSERT_EQ(1, gfx::Screen::GetScreen()->GetNumDisplays()); EXPECT_FALSE(TestIfMouseWarpsAt(gfx::Point(10, 10))); // Touch the right edge of the first display. Pointer should warp. EXPECT_TRUE(TestIfMouseWarpsAt(gfx::Point(499, 10))); EXPECT_EQ("501,10", // by 2px. aura::Env::GetInstance()->last_mouse_location().ToString()); // Touch the left edge of the second display. Pointer should warp. EXPECT_TRUE(TestIfMouseWarpsAt(gfx::Point(600, 10))); EXPECT_EQ("498,10", // by 2px. aura::Env::GetInstance()->last_mouse_location().ToString()); { SCOPED_TRACE("1x1 NO WARP"); NoWarpTestBody(); } // With 2X and 1X displays UpdateDisplay("500x500*2,600+0-500x500"); ASSERT_EQ(1, gfx::Screen::GetScreen()->GetNumDisplays()); EXPECT_FALSE(TestIfMouseWarpsAt(gfx::Point(10, 10))); // Touch the right edge of the first display. Pointer should warp. EXPECT_TRUE(TestIfMouseWarpsAt(gfx::Point(499, 10))); EXPECT_EQ("250,5", // moved to 501 by 2px, devided by 2 (dsf). aura::Env::GetInstance()->last_mouse_location().ToString()); // Touch the left edge of the second display. Pointer should warp. EXPECT_TRUE(TestIfMouseWarpsAt(gfx::Point(600, 10))); EXPECT_EQ("249,5", // moved to 498 by 2px, divided by 2 (dsf). aura::Env::GetInstance()->last_mouse_location().ToString()); { SCOPED_TRACE("2x1 NO WARP"); NoWarpTestBody(); } // With 1X and 2X displays UpdateDisplay("500x500,600+0-500x500*2"); ASSERT_EQ(1, gfx::Screen::GetScreen()->GetNumDisplays()); EXPECT_FALSE(TestIfMouseWarpsAt(gfx::Point(10, 10))); // Touch the right edge of the first display. Pointer should warp. EXPECT_TRUE(TestIfMouseWarpsAt(gfx::Point(499, 10))); EXPECT_EQ("501,10", // by 2px. aura::Env::GetInstance()->last_mouse_location().ToString()); // Touch the left edge of the second display. Pointer should warp. EXPECT_TRUE(TestIfMouseWarpsAt(gfx::Point(600, 10))); EXPECT_EQ("498,10", // by 2px. aura::Env::GetInstance()->last_mouse_location().ToString()); { SCOPED_TRACE("1x2 NO WARP"); NoWarpTestBody(); } // With two 2X displays UpdateDisplay("500x500*2,600+0-500x500*2"); ASSERT_EQ(1, gfx::Screen::GetScreen()->GetNumDisplays()); EXPECT_FALSE(TestIfMouseWarpsAt(gfx::Point(10, 10))); // Touch the right edge of the first display. Pointer should warp. EXPECT_TRUE(TestIfMouseWarpsAt(gfx::Point(499, 10))); EXPECT_EQ("250,5", // by 2px. aura::Env::GetInstance()->last_mouse_location().ToString()); // Touch the left edge of the second display. Pointer should warp. EXPECT_TRUE(TestIfMouseWarpsAt(gfx::Point(600, 10))); EXPECT_EQ("249,5", // moved to 498 by 2px, divided by 2 (dsf). aura::Env::GetInstance()->last_mouse_location().ToString()); { SCOPED_TRACE("1x2 NO WARP"); NoWarpTestBody(); } } } // namespace aura