mouse_cursor_event_filter_unittest.cc revision cedac228d2dd51db4b79ea1e72c7f249408ee061
1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "ash/display/mouse_cursor_event_filter.h"
6
7#include "ash/shell.h"
8#include "ash/test/ash_test_base.h"
9#include "ash/test/cursor_manager_test_api.h"
10#include "ash/display/display_layout_store.h"
11#include "ash/display/display_manager.h"
12#include "ui/aura/env.h"
13#include "ui/aura/window_event_dispatcher.h"
14#include "ui/gfx/display.h"
15#include "ui/gfx/screen.h"
16
17namespace ash {
18
19class MouseCursorEventFilterTest : public test::AshTestBase {
20 public:
21  MouseCursorEventFilterTest() {}
22  virtual ~MouseCursorEventFilterTest() {}
23
24 protected:
25  MouseCursorEventFilter* event_filter() {
26    return Shell::GetInstance()->mouse_cursor_filter();
27  }
28
29  bool WarpMouseCursorIfNecessary(aura::Window* target_root,
30                                  gfx::Point point_in_screen) {
31    bool is_warped = event_filter()->WarpMouseCursorIfNecessaryForTest(
32        target_root, point_in_screen);
33    event_filter()->reset_was_mouse_warped_for_test();
34    return is_warped;
35  }
36
37  bool WarpMouseCursorIfNecessaryWithDragRoot(
38      aura::Window* drag_source_root,
39      aura::Window* target_root,
40      gfx::Point point_in_screen) {
41    gfx::Point location = drag_source_root->bounds().CenterPoint();
42    ui::MouseEvent pressed(ui::ET_MOUSE_PRESSED, location,
43                           location, 0, 0);
44    ui::Event::DispatcherApi(&pressed).set_target(drag_source_root);
45    event_filter()->OnMouseEvent(&pressed);
46    bool is_warped = event_filter()->WarpMouseCursorIfNecessaryForTest(
47        target_root, point_in_screen);
48    event_filter()->reset_was_mouse_warped_for_test();
49
50    ui::MouseEvent released(ui::ET_MOUSE_RELEASED, location,
51                            location, 0, 0);
52    ui::Event::DispatcherApi(&released).set_target(drag_source_root);
53    event_filter()->OnMouseEvent(&released);
54    return is_warped;
55  }
56
57 private:
58  MouseCursorEventFilter* event_filter_;
59
60  DISALLOW_COPY_AND_ASSIGN(MouseCursorEventFilterTest);
61};
62
63// Verifies if the mouse pointer correctly moves to another display when there
64// are two displays.
65TEST_F(MouseCursorEventFilterTest, WarpMouse) {
66  if (!SupportsMultipleDisplays())
67    return;
68
69  UpdateDisplay("500x500,500x500");
70
71  ASSERT_EQ(
72      DisplayLayout::RIGHT,
73      Shell::GetInstance()->display_manager()->layout_store()->
74          default_display_layout().position);
75
76  aura::Window::Windows root_windows = Shell::GetAllRootWindows();
77  EXPECT_FALSE(WarpMouseCursorIfNecessary(root_windows[0], gfx::Point(11, 11)));
78  EXPECT_FALSE(WarpMouseCursorIfNecessary(root_windows[1], gfx::Point(11, 11)));
79
80  // Touch the right edge of the primary root window. Pointer should warp.
81  EXPECT_TRUE(WarpMouseCursorIfNecessary(root_windows[0], gfx::Point(499, 11)));
82  EXPECT_EQ("501,11",  // by 2px.
83            aura::Env::GetInstance()->last_mouse_location().ToString());
84
85  // Touch the left edge of the secondary root window. Pointer should warp.
86  EXPECT_TRUE(WarpMouseCursorIfNecessary(root_windows[1], gfx::Point(500, 11)));
87  EXPECT_EQ("498,11",  // by 2px.
88            aura::Env::GetInstance()->last_mouse_location().ToString());
89
90  // Touch the left edge of the primary root window.
91  EXPECT_FALSE(WarpMouseCursorIfNecessary(root_windows[0], gfx::Point(0, 11)));
92  // Touch the top edge of the primary root window.
93  EXPECT_FALSE(WarpMouseCursorIfNecessary(root_windows[0], gfx::Point(11, 0)));
94  // Touch the bottom edge of the primary root window.
95  EXPECT_FALSE(WarpMouseCursorIfNecessary(root_windows[0],
96                                          gfx::Point(11, 499)));
97  // Touch the right edge of the secondary root window.
98  EXPECT_FALSE(WarpMouseCursorIfNecessary(root_windows[1],
99                                          gfx::Point(999, 11)));
100  // Touch the top edge of the secondary root window.
101  EXPECT_FALSE(WarpMouseCursorIfNecessary(root_windows[1], gfx::Point(11, 0)));
102  // Touch the bottom edge of the secondary root window.
103  EXPECT_FALSE(WarpMouseCursorIfNecessary(root_windows[1],
104                                          gfx::Point(11, 499)));
105}
106
107// Verifies if the mouse pointer correctly moves to another display even when
108// two displays are not the same size.
109TEST_F(MouseCursorEventFilterTest, WarpMouseDifferentSizeDisplays) {
110  if (!SupportsMultipleDisplays())
111    return;
112
113  UpdateDisplay("500x500,600x600");  // the second one is larger.
114
115  ASSERT_EQ(
116      DisplayLayout::RIGHT,
117      Shell::GetInstance()->display_manager()->
118          GetCurrentDisplayLayout().position);
119
120  aura::Window::Windows root_windows = Shell::GetAllRootWindows();
121  aura::Env::GetInstance()->set_last_mouse_location(gfx::Point(623, 123));
122
123  // Touch the left edge of the secondary root window. Pointer should NOT warp
124  // because 1px left of (0, 500) is outside the primary root window.
125  EXPECT_FALSE(WarpMouseCursorIfNecessary(root_windows[1], gfx::Point(0, 500)));
126  EXPECT_EQ("623,123",  // by 2px.
127            aura::Env::GetInstance()->last_mouse_location().ToString());
128
129  // Touch the left edge of the secondary root window. Pointer should warp
130  // because 1px left of (0, 480) is inside the primary root window.
131  EXPECT_TRUE(
132      WarpMouseCursorIfNecessary(root_windows[1], gfx::Point(500, 480)));
133  EXPECT_EQ("498,480",  // by 2px.
134            aura::Env::GetInstance()->last_mouse_location().ToString());
135}
136
137// Verifies if the mouse pointer correctly moves between displays with
138// different scale factors.
139TEST_F(MouseCursorEventFilterTest, WarpMouseDifferentScaleDisplays) {
140  if (MouseCursorEventFilter::IsMouseWarpInNativeCoordsEnabled())
141    return;
142
143  if (!SupportsMultipleDisplays())
144    return;
145
146  UpdateDisplay("500x500,600x600*2");
147
148  ASSERT_EQ(
149      DisplayLayout::RIGHT,
150      Shell::GetInstance()->display_manager()->
151          GetCurrentDisplayLayout().position);
152
153  aura::Window::Windows root_windows = Shell::GetAllRootWindows();
154  aura::Env::GetInstance()->set_last_mouse_location(gfx::Point(900, 123));
155
156  // This emulates the dragging to the 2nd display, which has
157  // higher scale factor, by having 2nd display's root as target
158  // but have the edge of 1st display.
159  EXPECT_TRUE(WarpMouseCursorIfNecessaryWithDragRoot(
160      root_windows[1], root_windows[1], gfx::Point(498, 123)));
161  EXPECT_EQ("502,123",
162            aura::Env::GetInstance()->last_mouse_location().ToString());
163
164  // Touch the edge of 2nd display again and make sure it warps to
165  // 1st dislay.
166  EXPECT_TRUE(WarpMouseCursorIfNecessaryWithDragRoot(
167      root_windows[1], root_windows[1], gfx::Point(500, 123)));
168  EXPECT_EQ("496,123",
169            aura::Env::GetInstance()->last_mouse_location().ToString());
170
171  // Draging back from 1x to 2x.
172  EXPECT_TRUE(WarpMouseCursorIfNecessaryWithDragRoot(
173      root_windows[1], root_windows[0], gfx::Point(500, 123)));
174  EXPECT_EQ("496,123",
175            aura::Env::GetInstance()->last_mouse_location().ToString());
176
177  UpdateDisplay("500x500*2,600x600");
178  // Draging back from 1x to 2x.
179  EXPECT_TRUE(WarpMouseCursorIfNecessaryWithDragRoot(
180      root_windows[0], root_windows[1], gfx::Point(250, 123)));
181  EXPECT_EQ("246,123",
182            aura::Env::GetInstance()->last_mouse_location().ToString());
183}
184
185// Verifies if the mouse pointer correctly moves between displays with
186// different scale factors. In native coords mode, there is no
187// difference between drag and move.
188TEST_F(MouseCursorEventFilterTest, WarpMouseDifferentScaleDisplaysInNative) {
189  if (!MouseCursorEventFilter::IsMouseWarpInNativeCoordsEnabled())
190    return;
191
192  if (!SupportsMultipleDisplays())
193    return;
194
195  UpdateDisplay("500x500,600x600*2");
196
197  ASSERT_EQ(DisplayLayout::RIGHT,
198            Shell::GetInstance()
199                ->display_manager()
200                ->GetCurrentDisplayLayout()
201                .position);
202
203  aura::Window::Windows root_windows = Shell::GetAllRootWindows();
204  aura::Env::GetInstance()->set_last_mouse_location(gfx::Point(900, 123));
205
206  EXPECT_TRUE(event_filter()->WarpMouseCursorIfNecessaryForTest(
207      root_windows[0], gfx::Point(499, 123)));
208  EXPECT_EQ("500,123",
209            aura::Env::GetInstance()->last_mouse_location().ToString());
210
211  event_filter()->reset_was_mouse_warped_for_test();
212
213  // Touch the edge of 2nd display again and make sure it warps to
214  // 1st dislay.
215  EXPECT_TRUE(event_filter()->WarpMouseCursorIfNecessaryForTest(
216      root_windows[1], gfx::Point(500, 123)));
217  EXPECT_EQ("498,123",
218            aura::Env::GetInstance()->last_mouse_location().ToString());
219}
220
221TEST_F(MouseCursorEventFilterTest, DoNotWarpTwice) {
222  if (MouseCursorEventFilter::IsMouseWarpInNativeCoordsEnabled())
223    return;
224
225  if (!SupportsMultipleDisplays())
226    return;
227
228  UpdateDisplay("500x500,600x600");
229
230  aura::Window::Windows root_windows = Shell::GetAllRootWindows();
231  aura::Env::GetInstance()->set_last_mouse_location(gfx::Point(623, 123));
232
233  // Touch the right edge of the primary root window. Pointer should warp.
234  EXPECT_TRUE(event_filter()->WarpMouseCursorIfNecessaryForTest(
235      root_windows[0], gfx::Point(499, 11)));
236  EXPECT_EQ("501,11",  // by 2px.
237            aura::Env::GetInstance()->last_mouse_location().ToString());
238
239  // Touch the left edge of the secondary root window immediately. This should
240  // be ignored.
241  EXPECT_FALSE(event_filter()->WarpMouseCursorIfNecessaryForTest(
242      root_windows[1], gfx::Point(500, 11)));
243
244  // Touch the left edge of the secondary root window again, pointer should
245  // warp for this time.
246  EXPECT_TRUE(event_filter()->WarpMouseCursorIfNecessaryForTest(
247      root_windows[1], gfx::Point(500, 11)));
248  EXPECT_EQ("498,11",  // by 2px.
249            aura::Env::GetInstance()->last_mouse_location().ToString());
250}
251
252// Verifies if MouseCursorEventFilter::set_mouse_warp_mode() works as expected.
253TEST_F(MouseCursorEventFilterTest, SetMouseWarpModeFlag) {
254  if (!SupportsMultipleDisplays())
255    return;
256
257  UpdateDisplay("500x500,500x500");
258
259  aura::Window::Windows root_windows = Shell::GetAllRootWindows();
260  aura::Env::GetInstance()->set_last_mouse_location(gfx::Point(1, 1));
261
262  event_filter()->set_mouse_warp_mode(MouseCursorEventFilter::WARP_NONE);
263  EXPECT_FALSE(WarpMouseCursorIfNecessary(root_windows[0],
264                                          gfx::Point(499, 11)));
265  EXPECT_EQ("1,1",
266            aura::Env::GetInstance()->last_mouse_location().ToString());
267
268  event_filter()->set_mouse_warp_mode(MouseCursorEventFilter::WARP_ALWAYS);
269  EXPECT_TRUE(WarpMouseCursorIfNecessary(root_windows[0], gfx::Point(499, 11)));
270  EXPECT_EQ("501,11",
271            aura::Env::GetInstance()->last_mouse_location().ToString());
272}
273
274// Verifies if MouseCursorEventFilter's bounds calculation works correctly.
275TEST_F(MouseCursorEventFilterTest, IndicatorBoundsTestOnRight) {
276  if (!SupportsMultipleDisplays())
277    return;
278
279  UpdateDisplay("360x360,700x700");
280  aura::Window::Windows root_windows = Shell::GetAllRootWindows();
281
282  DisplayManager* display_manager = Shell::GetInstance()->display_manager();
283  DisplayLayout layout(DisplayLayout::RIGHT, 0);
284  display_manager->SetLayoutForCurrentDisplays(layout);
285  event_filter()->ShowSharedEdgeIndicator(root_windows[0] /* primary */);
286  EXPECT_EQ("359,16 1x344", event_filter()->src_indicator_bounds_.ToString());
287  EXPECT_EQ("360,0 1x360", event_filter()->dst_indicator_bounds_.ToString());
288  event_filter()->ShowSharedEdgeIndicator(root_windows[1] /* secondary */);
289  EXPECT_EQ("360,16 1x344", event_filter()->src_indicator_bounds_.ToString());
290  EXPECT_EQ("359,0 1x360", event_filter()->dst_indicator_bounds_.ToString());
291
292  // Move 2nd display downwards a bit.
293  layout.offset = 5;
294  display_manager->SetLayoutForCurrentDisplays(layout);
295  event_filter()->ShowSharedEdgeIndicator(root_windows[0] /* primary */);
296  // This is same as before because the 2nd display's y is above
297  // the indicator's x.
298  EXPECT_EQ("359,16 1x344", event_filter()->src_indicator_bounds_.ToString());
299  EXPECT_EQ("360,5 1x355", event_filter()->dst_indicator_bounds_.ToString());
300  event_filter()->ShowSharedEdgeIndicator(root_windows[1] /* secondary */);
301  EXPECT_EQ("360,21 1x339", event_filter()->src_indicator_bounds_.ToString());
302  EXPECT_EQ("359,5 1x355", event_filter()->dst_indicator_bounds_.ToString());
303
304  // Move it down further so that the shared edge is shorter than
305  // minimum hole size (160).
306  layout.offset = 200;
307  display_manager->SetLayoutForCurrentDisplays(layout);
308  event_filter()->ShowSharedEdgeIndicator(root_windows[0] /* primary */);
309  EXPECT_EQ("359,200 1x160", event_filter()->src_indicator_bounds_.ToString());
310  EXPECT_EQ("360,200 1x160", event_filter()->dst_indicator_bounds_.ToString());
311  event_filter()->ShowSharedEdgeIndicator(root_windows[1] /* secondary */);
312  EXPECT_EQ("360,200 1x160", event_filter()->src_indicator_bounds_.ToString());
313  EXPECT_EQ("359,200 1x160", event_filter()->dst_indicator_bounds_.ToString());
314
315  // Now move 2nd display upwards
316  layout.offset = -5;
317  display_manager->SetLayoutForCurrentDisplays(layout);
318  event_filter()->ShowSharedEdgeIndicator(root_windows[0] /* primary */);
319  EXPECT_EQ("359,16 1x344", event_filter()->src_indicator_bounds_.ToString());
320  EXPECT_EQ("360,0 1x360", event_filter()->dst_indicator_bounds_.ToString());
321  event_filter()->ShowSharedEdgeIndicator(root_windows[1] /* secondary */);
322  // 16 px are reserved on 2nd display from top, so y must be
323  // (16 - 5) = 11
324  EXPECT_EQ("360,11 1x349", event_filter()->src_indicator_bounds_.ToString());
325  EXPECT_EQ("359,0 1x360", event_filter()->dst_indicator_bounds_.ToString());
326
327  event_filter()->HideSharedEdgeIndicator();
328}
329
330TEST_F(MouseCursorEventFilterTest, IndicatorBoundsTestOnLeft) {
331  if (!SupportsMultipleDisplays())
332    return;
333
334  UpdateDisplay("360x360,700x700");
335  aura::Window::Windows root_windows = Shell::GetAllRootWindows();
336
337  DisplayManager* display_manager = Shell::GetInstance()->display_manager();
338  DisplayLayout layout(DisplayLayout::LEFT, 0);
339  display_manager->SetLayoutForCurrentDisplays(layout);
340  event_filter()->ShowSharedEdgeIndicator(root_windows[0] /* primary */);
341  EXPECT_EQ("0,16 1x344", event_filter()->src_indicator_bounds_.ToString());
342  EXPECT_EQ("-1,0 1x360", event_filter()->dst_indicator_bounds_.ToString());
343  event_filter()->ShowSharedEdgeIndicator(root_windows[1] /* secondary */);
344  EXPECT_EQ("-1,16 1x344", event_filter()->src_indicator_bounds_.ToString());
345  EXPECT_EQ("0,0 1x360", event_filter()->dst_indicator_bounds_.ToString());
346
347  layout.offset = 250;
348  display_manager->SetLayoutForCurrentDisplays(layout);
349  event_filter()->ShowSharedEdgeIndicator(root_windows[0] /* primary */);
350  EXPECT_EQ("0,250 1x110", event_filter()->src_indicator_bounds_.ToString());
351  EXPECT_EQ("-1,250 1x110", event_filter()->dst_indicator_bounds_.ToString());
352  event_filter()->ShowSharedEdgeIndicator(root_windows[1] /* secondary */);
353  EXPECT_EQ("-1,250 1x110", event_filter()->src_indicator_bounds_.ToString());
354  EXPECT_EQ("0,250 1x110", event_filter()->dst_indicator_bounds_.ToString());
355  event_filter()->HideSharedEdgeIndicator();
356}
357
358TEST_F(MouseCursorEventFilterTest, IndicatorBoundsTestOnTopBottom) {
359  if (!SupportsMultipleDisplays())
360    return;
361
362  UpdateDisplay("360x360,700x700");
363  aura::Window::Windows root_windows = Shell::GetAllRootWindows();
364
365  DisplayManager* display_manager = Shell::GetInstance()->display_manager();
366  DisplayLayout layout(DisplayLayout::TOP, 0);
367  display_manager->SetLayoutForCurrentDisplays(layout);
368  event_filter()->ShowSharedEdgeIndicator(root_windows[0] /* primary */);
369  EXPECT_EQ("0,0 360x1", event_filter()->src_indicator_bounds_.ToString());
370  EXPECT_EQ("0,-1 360x1", event_filter()->dst_indicator_bounds_.ToString());
371  event_filter()->ShowSharedEdgeIndicator(root_windows[1] /* secondary */);
372  EXPECT_EQ("0,-1 360x1", event_filter()->src_indicator_bounds_.ToString());
373  EXPECT_EQ("0,0 360x1", event_filter()->dst_indicator_bounds_.ToString());
374
375  layout.offset = 250;
376  display_manager->SetLayoutForCurrentDisplays(layout);
377  event_filter()->ShowSharedEdgeIndicator(root_windows[0] /* primary */);
378  EXPECT_EQ("250,0 110x1", event_filter()->src_indicator_bounds_.ToString());
379  EXPECT_EQ("250,-1 110x1", event_filter()->dst_indicator_bounds_.ToString());
380  event_filter()->ShowSharedEdgeIndicator(root_windows[1] /* secondary */);
381  EXPECT_EQ("250,-1 110x1", event_filter()->src_indicator_bounds_.ToString());
382  EXPECT_EQ("250,0 110x1", event_filter()->dst_indicator_bounds_.ToString());
383
384  layout.position = DisplayLayout::BOTTOM;
385  layout.offset = 0;
386  display_manager->SetLayoutForCurrentDisplays(layout);
387  event_filter()->ShowSharedEdgeIndicator(root_windows[0] /* primary */);
388  EXPECT_EQ("0,359 360x1", event_filter()->src_indicator_bounds_.ToString());
389  EXPECT_EQ("0,360 360x1", event_filter()->dst_indicator_bounds_.ToString());
390  event_filter()->ShowSharedEdgeIndicator(root_windows[1] /* secondary */);
391  EXPECT_EQ("0,360 360x1", event_filter()->src_indicator_bounds_.ToString());
392  EXPECT_EQ("0,359 360x1", event_filter()->dst_indicator_bounds_.ToString());
393
394  event_filter()->HideSharedEdgeIndicator();
395}
396
397// Verifies cursor's device scale factor is updated when a cursor has moved
398// across root windows with different device scale factors
399// (http://crbug.com/154183).
400TEST_F(MouseCursorEventFilterTest, CursorDeviceScaleFactor) {
401  if (!SupportsMultipleDisplays())
402    return;
403
404  UpdateDisplay("400x400,800x800*2");
405  DisplayManager* display_manager = Shell::GetInstance()->display_manager();
406  display_manager->SetLayoutForCurrentDisplays(
407      DisplayLayout(DisplayLayout::RIGHT, 0));
408  aura::Window::Windows root_windows = Shell::GetAllRootWindows();
409  ASSERT_EQ(2U, root_windows.size());
410  test::CursorManagerTestApi cursor_test_api(
411      Shell::GetInstance()->cursor_manager());
412
413  EXPECT_EQ(1.0f, cursor_test_api.GetCurrentCursor().device_scale_factor());
414  WarpMouseCursorIfNecessary(root_windows[0], gfx::Point(399, 200));
415  EXPECT_EQ(2.0f, cursor_test_api.GetCurrentCursor().device_scale_factor());
416  WarpMouseCursorIfNecessary(root_windows[1], gfx::Point(400, 200));
417  EXPECT_EQ(1.0f, cursor_test_api.GetCurrentCursor().device_scale_factor());
418}
419
420}  // namespace ash
421