1 // Copyright 2014 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 "ui/events/ozone/evdev/input_injector_evdev.h"
6 
7 #include "base/bind.h"
8 #include "base/macros.h"
9 #include "base/run_loop.h"
10 #include "base/test/task_environment.h"
11 #include "testing/gmock/include/gmock/gmock.h"
12 #include "testing/gtest/include/gtest/gtest.h"
13 #include "ui/events/ozone/device/device_manager.h"
14 #include "ui/events/ozone/evdev/event_converter_test_util.h"
15 #include "ui/events/ozone/evdev/event_factory_evdev.h"
16 #include "ui/events/ozone/evdev/testing/fake_cursor_delegate_evdev.h"
17 #include "ui/events/ozone/events_ozone.h"
18 #include "ui/events/ozone/layout/stub/stub_keyboard_layout_engine.h"
19 
20 namespace ui {
21 
22 using testing::AllOf;
23 using testing::InSequence;
24 using testing::Property;
25 
26 class EventObserver {
27  public:
EventDispatchCallback(Event * event)28   void EventDispatchCallback(Event* event) {
29     DispatchEventFromNativeUiEvent(
30         event, base::BindOnce(&EventObserver::OnEvent, base::Unretained(this)));
31   }
32 
OnEvent(Event * event)33   void OnEvent(Event* event) {
34     if (event->IsMouseEvent()) {
35       if (event->type() == ET_MOUSEWHEEL) {
36         OnMouseWheelEvent(event->AsMouseWheelEvent());
37       } else {
38         OnMouseEvent(event->AsMouseEvent());
39       }
40     }
41   }
42 
43   // Mock functions for intercepting mouse events.
44   MOCK_METHOD1(OnMouseEvent, void(MouseEvent* event));
45   MOCK_METHOD1(OnMouseWheelEvent, void(MouseWheelEvent* event));
46 };
47 
48 MATCHER_P4(MatchesMouseEvent, type, button, x, y, "") {
49   if (arg->type() != type) {
50     *result_listener << "Expected type: " << type << " actual: " << arg->type()
51                      << " (" << arg->GetName() << ")";
52     return false;
53   }
54   if (button == EF_LEFT_MOUSE_BUTTON && !arg->IsLeftMouseButton()) {
55     *result_listener << "Expected the left button flag is set.";
56     return false;
57   }
58   if (button == EF_RIGHT_MOUSE_BUTTON && !arg->IsRightMouseButton()) {
59     *result_listener << "Expected the right button flag is set.";
60     return false;
61   }
62   if (button == EF_MIDDLE_MOUSE_BUTTON && !arg->IsMiddleMouseButton()) {
63     *result_listener << "Expected the middle button flag is set.";
64     return false;
65   }
66   if (arg->x() != x || arg->y() != y) {
67     *result_listener << "Expected location: (" << x << ", " << y
68                      << ") actual: (" << arg->x() << ", " << arg->y() << ")";
69     return false;
70   }
71   return true;
72 }
73 
74 class InputInjectorEvdevTest : public testing::Test {
75  public:
76   InputInjectorEvdevTest();
77 
78  protected:
79   void SimulateMouseClick(int x, int y, EventFlags button, int count);
80   void ExpectClick(int x, int y, int button, int count);
81 
82   EventObserver event_observer_;
83   const EventDispatchCallback dispatch_callback_;
84   FakeCursorDelegateEvdev cursor_;
85 
86   std::unique_ptr<DeviceManager> device_manager_;
87   std::unique_ptr<StubKeyboardLayoutEngine> keyboard_layout_engine_;
88   std::unique_ptr<EventFactoryEvdev> event_factory_;
89 
90   InputInjectorEvdev injector_;
91 
92   base::test::SingleThreadTaskEnvironment task_environment_;
93   base::RunLoop run_loop_;
94 
95  private:
96   DISALLOW_COPY_AND_ASSIGN(InputInjectorEvdevTest);
97 };
98 
InputInjectorEvdevTest()99 InputInjectorEvdevTest::InputInjectorEvdevTest()
100     : dispatch_callback_(
101           base::BindRepeating(&EventObserver::EventDispatchCallback,
102                               base::Unretained(&event_observer_))),
103       device_manager_(CreateDeviceManagerForTest()),
104       keyboard_layout_engine_(std::make_unique<ui::StubKeyboardLayoutEngine>()),
105       event_factory_(
106           CreateEventFactoryEvdevForTest(&cursor_,
107                                          device_manager_.get(),
108                                          keyboard_layout_engine_.get(),
109                                          dispatch_callback_)),
110       injector_(CreateDeviceEventDispatcherEvdevForTest(event_factory_.get()),
111                 &cursor_) {}
112 
SimulateMouseClick(int x,int y,EventFlags button,int count)113 void InputInjectorEvdevTest::SimulateMouseClick(int x,
114                                                 int y,
115                                                 EventFlags button,
116                                                 int count) {
117   injector_.MoveCursorTo(gfx::PointF(x, y));
118   for (int i = 0; i < count; i++) {
119     injector_.InjectMouseButton(button, true);
120     injector_.InjectMouseButton(button, false);
121   }
122 }
123 
ExpectClick(int x,int y,int button,int count)124 void InputInjectorEvdevTest::ExpectClick(int x, int y, int button, int count) {
125   InSequence dummy;
126   EXPECT_CALL(event_observer_,
127               OnMouseEvent(MatchesMouseEvent(ET_MOUSE_MOVED, EF_NONE, x, y)));
128 
129   for (int i = 0; i < count; i++) {
130     EXPECT_CALL(event_observer_, OnMouseEvent(MatchesMouseEvent(
131                                      ET_MOUSE_PRESSED, button, x, y)));
132     EXPECT_CALL(event_observer_, OnMouseEvent(MatchesMouseEvent(
133                                      ET_MOUSE_RELEASED, button, x, y)));
134   }
135 }
136 
TEST_F(InputInjectorEvdevTest,LeftClick)137 TEST_F(InputInjectorEvdevTest, LeftClick) {
138   ExpectClick(12, 13, EF_LEFT_MOUSE_BUTTON, 1);
139   SimulateMouseClick(12, 13, EF_LEFT_MOUSE_BUTTON, 1);
140   run_loop_.RunUntilIdle();
141 }
142 
TEST_F(InputInjectorEvdevTest,RightClick)143 TEST_F(InputInjectorEvdevTest, RightClick) {
144   ExpectClick(12, 13, EF_RIGHT_MOUSE_BUTTON, 1);
145   SimulateMouseClick(12, 13, EF_RIGHT_MOUSE_BUTTON, 1);
146   run_loop_.RunUntilIdle();
147 }
148 
TEST_F(InputInjectorEvdevTest,MiddleClick)149 TEST_F(InputInjectorEvdevTest, MiddleClick) {
150   ExpectClick(12, 13, EF_MIDDLE_MOUSE_BUTTON, 1);
151   SimulateMouseClick(12, 13, EF_MIDDLE_MOUSE_BUTTON, 1);
152   run_loop_.RunUntilIdle();
153 }
154 
TEST_F(InputInjectorEvdevTest,DoubleClick)155 TEST_F(InputInjectorEvdevTest, DoubleClick) {
156   ExpectClick(12, 13, EF_LEFT_MOUSE_BUTTON, 2);
157   SimulateMouseClick(12, 13, EF_LEFT_MOUSE_BUTTON, 2);
158   run_loop_.RunUntilIdle();
159 }
160 
TEST_F(InputInjectorEvdevTest,MouseMoved)161 TEST_F(InputInjectorEvdevTest, MouseMoved) {
162   injector_.MoveCursorTo(gfx::PointF(1, 1));
163   run_loop_.RunUntilIdle();
164   EXPECT_EQ(cursor_.GetLocation(), gfx::PointF(1, 1));
165 }
166 
TEST_F(InputInjectorEvdevTest,MouseDragged)167 TEST_F(InputInjectorEvdevTest, MouseDragged) {
168   InSequence dummy;
169   EXPECT_CALL(event_observer_,
170               OnMouseEvent(MatchesMouseEvent(ET_MOUSE_PRESSED,
171                                              EF_LEFT_MOUSE_BUTTON, 0, 0)));
172   EXPECT_CALL(event_observer_,
173               OnMouseEvent(MatchesMouseEvent(ET_MOUSE_DRAGGED,
174                                              EF_LEFT_MOUSE_BUTTON, 1, 1)));
175   EXPECT_CALL(event_observer_,
176               OnMouseEvent(MatchesMouseEvent(ET_MOUSE_DRAGGED,
177                                              EF_LEFT_MOUSE_BUTTON, 2, 3)));
178   EXPECT_CALL(event_observer_,
179               OnMouseEvent(MatchesMouseEvent(ET_MOUSE_RELEASED,
180                                              EF_LEFT_MOUSE_BUTTON, 2, 3)));
181   injector_.InjectMouseButton(EF_LEFT_MOUSE_BUTTON, true);
182   injector_.MoveCursorTo(gfx::PointF(1, 1));
183   injector_.MoveCursorTo(gfx::PointF(2, 3));
184   injector_.InjectMouseButton(EF_LEFT_MOUSE_BUTTON, false);
185   run_loop_.RunUntilIdle();
186 }
187 
TEST_F(InputInjectorEvdevTest,MouseWheel)188 TEST_F(InputInjectorEvdevTest, MouseWheel) {
189   InSequence dummy;
190   EXPECT_CALL(event_observer_, OnMouseWheelEvent(AllOf(
191                                    MatchesMouseEvent(ET_MOUSEWHEEL, 0, 10, 20),
192                                    Property(&MouseWheelEvent::x_offset, 0),
193                                    Property(&MouseWheelEvent::y_offset, 100))));
194   EXPECT_CALL(event_observer_, OnMouseWheelEvent(AllOf(
195                                    MatchesMouseEvent(ET_MOUSEWHEEL, 0, 10, 20),
196                                    Property(&MouseWheelEvent::x_offset, 100),
197                                    Property(&MouseWheelEvent::y_offset, 0))));
198   injector_.MoveCursorTo(gfx::PointF(10, 20));
199   injector_.InjectMouseWheel(0, 100);
200   injector_.InjectMouseWheel(100, 0);
201   run_loop_.RunUntilIdle();
202 }
203 
204 }  // namespace ui
205