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.
7 #include <linux/input.h>
12 #include "base/bind.h"
13 #include "base/memory/scoped_ptr.h"
14 #include "base/memory/scoped_vector.h"
15 #include "base/posix/eintr_wrapper.h"
16 #include "base/run_loop.h"
17 #include "base/time/time.h"
18 #include "testing/gtest/include/gtest/gtest.h"
19 #include "ui/events/event.h"
20 #include "ui/events/ozone/device/device_manager.h"
21 #include "ui/events/ozone/evdev/event_converter_test_util.h"
22 #include "ui/events/ozone/evdev/event_factory_evdev.h"
23 #include "ui/events/ozone/evdev/tablet_event_converter_evdev.h"
24 #include "ui/events/ozone/layout/keyboard_layout_engine_manager.h"
25 #include "ui/events/platform/platform_event_dispatcher.h"
26 #include "ui/events/platform/platform_event_source.h"
30 static int SetNonBlocking(int fd
) {
31 int flags
= fcntl(fd
, F_GETFL
, 0);
34 return fcntl(fd
, F_SETFL
, flags
| O_NONBLOCK
);
37 const char kTestDevicePath
[] = "/dev/input/test-device";
43 class MockTabletEventConverterEvdev
: public TabletEventConverterEvdev
{
45 MockTabletEventConverterEvdev(int fd
,
47 CursorDelegateEvdev
* cursor
,
48 DeviceEventDispatcherEvdev
* dispatcher
);
49 ~MockTabletEventConverterEvdev() override
{};
51 void ConfigureReadMock(struct input_event
* queue
,
55 // Actually dispatch the event reader code.
57 OnFileCanReadWithoutBlocking(read_pipe_
);
58 base::RunLoop().RunUntilIdle();
65 ScopedVector
<Event
> dispatched_events_
;
67 DISALLOW_COPY_AND_ASSIGN(MockTabletEventConverterEvdev
);
70 class MockTabletCursorEvdev
: public CursorDelegateEvdev
{
72 MockTabletCursorEvdev() { cursor_confined_bounds_
= gfx::Rect(1024, 768); }
73 ~MockTabletCursorEvdev() override
{}
75 // CursorDelegateEvdev:
76 void MoveCursorTo(gfx::AcceleratedWidget widget
,
77 const gfx::PointF
& location
) override
{
80 void MoveCursorTo(const gfx::PointF
& location
) override
{
81 cursor_location_
= location
;
83 void MoveCursor(const gfx::Vector2dF
& delta
) override
{ NOTREACHED(); }
84 bool IsCursorVisible() override
{ return 1; }
85 gfx::PointF
GetLocation() override
{ return cursor_location_
; }
86 gfx::Rect
GetCursorConfinedBounds() override
{
87 return cursor_confined_bounds_
;
91 gfx::PointF cursor_location_
;
92 gfx::Rect cursor_confined_bounds_
;
93 DISALLOW_COPY_AND_ASSIGN(MockTabletCursorEvdev
);
96 MockTabletEventConverterEvdev::MockTabletEventConverterEvdev(
99 CursorDelegateEvdev
* cursor
,
100 DeviceEventDispatcherEvdev
* dispatcher
)
101 : TabletEventConverterEvdev(fd
,
104 INPUT_DEVICE_UNKNOWN
,
108 // Real values taken from Wacom Intuos 4
110 x_abs_range_
= 65024;
112 y_abs_range_
= 40640;
117 PLOG(FATAL
) << "failed pipe";
119 EXPECT_FALSE(SetNonBlocking(fds
[0]) || SetNonBlocking(fds
[1]))
120 << "failed to set non-blocking: " << strerror(errno
);
123 write_pipe_
= fds
[1];
126 void MockTabletEventConverterEvdev::ConfigureReadMock(struct input_event
* queue
,
129 int nwrite
= HANDLE_EINTR(write(write_pipe_
, queue
+ queue_index
,
130 sizeof(struct input_event
) * read_this_many
));
132 static_cast<int>(sizeof(struct input_event
) * read_this_many
))
133 << "write() failed, errno: " << errno
;
139 class TabletEventConverterEvdevTest
: public testing::Test
{
141 TabletEventConverterEvdevTest() {}
143 // Overridden from testing::Test:
144 void SetUp() override
{
145 // Set up pipe to satisfy message pump (unused).
148 PLOG(FATAL
) << "failed pipe";
149 events_in_
= evdev_io
[0];
150 events_out_
= evdev_io
[1];
152 cursor_
.reset(new ui::MockTabletCursorEvdev());
153 device_manager_
= ui::CreateDeviceManagerForTest();
154 event_factory_
= ui::CreateEventFactoryEvdevForTest(
155 cursor_
.get(), device_manager_
.get(),
156 ui::KeyboardLayoutEngineManager::GetKeyboardLayoutEngine(),
157 base::Bind(&TabletEventConverterEvdevTest::DispatchEventForTest
,
158 base::Unretained(this)));
160 ui::CreateDeviceEventDispatcherEvdevForTest(event_factory_
.get());
161 device_
.reset(new ui::MockTabletEventConverterEvdev(
162 events_in_
, base::FilePath(kTestDevicePath
), cursor_
.get(),
166 void TearDown() override
{
171 ui::MockTabletEventConverterEvdev
* device() { return device_
.get(); }
172 ui::CursorDelegateEvdev
* cursor() { return cursor_
.get(); }
174 unsigned size() { return dispatched_events_
.size(); }
175 ui::MouseEvent
* dispatched_event(unsigned index
) {
176 DCHECK_GT(dispatched_events_
.size(), index
);
177 ui::Event
* ev
= dispatched_events_
[index
];
178 DCHECK(ev
->IsMouseEvent());
179 return static_cast<ui::MouseEvent
*>(ev
);
182 void DispatchEventForTest(ui::Event
* event
) {
183 scoped_ptr
<ui::Event
> cloned_event
= ui::Event::Clone(*event
);
184 dispatched_events_
.push_back(cloned_event
.release());
188 scoped_ptr
<ui::MockTabletCursorEvdev
> cursor_
;
189 scoped_ptr
<ui::DeviceManager
> device_manager_
;
190 scoped_ptr
<ui::EventFactoryEvdev
> event_factory_
;
191 scoped_ptr
<ui::DeviceEventDispatcherEvdev
> dispatcher_
;
192 scoped_ptr
<ui::MockTabletEventConverterEvdev
> device_
;
194 ScopedVector
<ui::Event
> dispatched_events_
;
199 DISALLOW_COPY_AND_ASSIGN(TabletEventConverterEvdevTest
);
204 // Uses real data captured from Wacom Intuos 4
205 TEST_F(TabletEventConverterEvdevTest
, MoveTopLeft
) {
206 ui::MockTabletEventConverterEvdev
* dev
= device();
208 struct input_event mock_kernel_queue
[] = {
209 {{0, 0}, EV_ABS
, ABS_Y
, 616},
210 {{0, 0}, EV_ABS
, ABS_DISTANCE
, 62},
211 {{0, 0}, EV_ABS
, ABS_TILT_X
, 50},
212 {{0, 0}, EV_ABS
, ABS_TILT_Y
, 7},
213 {{0, 0}, EV_ABS
, ABS_MISC
, 1050626},
214 {{0, 0}, EV_KEY
, BTN_TOOL_PEN
, 1},
215 {{0, 0}, EV_MSC
, MSC_SERIAL
, 159403517},
216 {{0, 0}, EV_SYN
, SYN_REPORT
, 0},
217 {{0, 0}, EV_ABS
, ABS_Y
, 0},
218 {{0, 0}, EV_ABS
, ABS_DISTANCE
, 0},
219 {{0, 0}, EV_ABS
, ABS_TILT_X
, 0},
220 {{0, 0}, EV_KEY
, BTN_TOOL_PEN
, 0},
221 {{0, 0}, EV_ABS
, ABS_MISC
, 0},
222 {{0, 0}, EV_MSC
, MSC_SERIAL
, 159403517},
223 {{0, 0}, EV_SYN
, SYN_REPORT
, 0},
226 dev
->ProcessEvents(mock_kernel_queue
, arraysize(mock_kernel_queue
));
227 EXPECT_EQ(1u, size());
229 ui::MouseEvent
* event
= dispatched_event(0);
230 EXPECT_EQ(ui::ET_MOUSE_MOVED
, event
->type());
232 EXPECT_LT(cursor()->GetLocation().x(), EPSILON
);
233 EXPECT_LT(cursor()->GetLocation().y(), EPSILON
);
236 TEST_F(TabletEventConverterEvdevTest
, MoveTopRight
) {
237 ui::MockTabletEventConverterEvdev
* dev
= device();
239 struct input_event mock_kernel_queue
[] = {
240 {{0, 0}, EV_ABS
, ABS_X
, 65024},
241 {{0, 0}, EV_ABS
, ABS_Y
, 33},
242 {{0, 0}, EV_ABS
, ABS_DISTANCE
, 62},
243 {{0, 0}, EV_ABS
, ABS_TILT_X
, 109},
244 {{0, 0}, EV_ABS
, ABS_TILT_Y
, 59},
245 {{0, 0}, EV_ABS
, ABS_MISC
, 1050626},
246 {{0, 0}, EV_KEY
, BTN_TOOL_PEN
, 1},
247 {{0, 0}, EV_MSC
, MSC_SERIAL
, 159403517},
248 {{0, 0}, EV_SYN
, SYN_REPORT
, 0},
249 {{0, 0}, EV_ABS
, ABS_X
, 0},
250 {{0, 0}, EV_ABS
, ABS_DISTANCE
, 0},
251 {{0, 0}, EV_ABS
, ABS_TILT_X
, 0},
252 {{0, 0}, EV_ABS
, ABS_TILT_Y
, 0},
253 {{0, 0}, EV_KEY
, BTN_TOOL_PEN
, 0},
254 {{0, 0}, EV_ABS
, ABS_MISC
, 0},
255 {{0, 0}, EV_MSC
, MSC_SERIAL
, 159403517},
256 {{0, 0}, EV_SYN
, SYN_REPORT
, 0},
259 dev
->ProcessEvents(mock_kernel_queue
, arraysize(mock_kernel_queue
));
260 EXPECT_EQ(1u, size());
262 ui::MouseEvent
* event
= dispatched_event(0);
263 EXPECT_EQ(ui::ET_MOUSE_MOVED
, event
->type());
265 EXPECT_GT(cursor()->GetLocation().x(),
266 cursor()->GetCursorConfinedBounds().width() - EPSILON
);
267 EXPECT_LT(cursor()->GetLocation().y(), EPSILON
);
270 TEST_F(TabletEventConverterEvdevTest
, MoveBottomLeft
) {
271 ui::MockTabletEventConverterEvdev
* dev
= device();
273 struct input_event mock_kernel_queue
[] = {
274 {{0, 0}, EV_ABS
, ABS_Y
, 40640},
275 {{0, 0}, EV_ABS
, ABS_DISTANCE
, 62},
276 {{0, 0}, EV_ABS
, ABS_TILT_X
, 95},
277 {{0, 0}, EV_ABS
, ABS_TILT_Y
, 44},
278 {{0, 0}, EV_ABS
, ABS_MISC
, 1050626},
279 {{0, 0}, EV_KEY
, BTN_TOOL_PEN
, 1},
280 {{0, 0}, EV_MSC
, MSC_SERIAL
, 159403517},
281 {{0, 0}, EV_SYN
, SYN_REPORT
, 0},
282 {{0, 0}, EV_ABS
, ABS_Y
, 0},
283 {{0, 0}, EV_ABS
, ABS_DISTANCE
, 0},
284 {{0, 0}, EV_ABS
, ABS_TILT_X
, 0},
285 {{0, 0}, EV_ABS
, ABS_TILT_Y
, 0},
286 {{0, 0}, EV_KEY
, BTN_TOOL_PEN
, 0},
287 {{0, 0}, EV_ABS
, ABS_MISC
, 0},
288 {{0, 0}, EV_MSC
, MSC_SERIAL
, 159403517},
289 {{0, 0}, EV_SYN
, SYN_REPORT
, 0},
292 dev
->ProcessEvents(mock_kernel_queue
, arraysize(mock_kernel_queue
));
293 EXPECT_EQ(1u, size());
295 ui::MouseEvent
* event
= dispatched_event(0);
296 EXPECT_EQ(ui::ET_MOUSE_MOVED
, event
->type());
298 EXPECT_LT(cursor()->GetLocation().x(), EPSILON
);
299 EXPECT_GT(cursor()->GetLocation().y(),
300 cursor()->GetCursorConfinedBounds().height() - EPSILON
);
303 TEST_F(TabletEventConverterEvdevTest
, MoveBottomRight
) {
304 ui::MockTabletEventConverterEvdev
* dev
= device();
306 struct input_event mock_kernel_queue
[] = {
307 {{0, 0}, EV_ABS
, ABS_X
, 65024},
308 {{0, 0}, EV_ABS
, ABS_Y
, 40640},
309 {{0, 0}, EV_ABS
, ABS_DISTANCE
, 62},
310 {{0, 0}, EV_ABS
, ABS_TILT_X
, 127},
311 {{0, 0}, EV_ABS
, ABS_TILT_Y
, 89},
312 {{0, 0}, EV_ABS
, ABS_MISC
, 1050626},
313 {{0, 0}, EV_KEY
, BTN_TOOL_PEN
, 1},
314 {{0, 0}, EV_MSC
, MSC_SERIAL
, 159403517},
315 {{0, 0}, EV_SYN
, SYN_REPORT
, 0},
316 {{0, 0}, EV_ABS
, ABS_X
, 0},
317 {{0, 0}, EV_ABS
, ABS_Y
, 0},
318 {{0, 0}, EV_ABS
, ABS_DISTANCE
, 0},
319 {{0, 0}, EV_ABS
, ABS_TILT_X
, 0},
320 {{0, 0}, EV_ABS
, ABS_TILT_Y
, 0},
321 {{0, 0}, EV_KEY
, BTN_TOOL_PEN
, 0},
322 {{0, 0}, EV_ABS
, ABS_MISC
, 0},
323 {{0, 0}, EV_MSC
, MSC_SERIAL
, 159403517},
324 {{0, 0}, EV_SYN
, SYN_REPORT
, 0},
327 dev
->ProcessEvents(mock_kernel_queue
, arraysize(mock_kernel_queue
));
328 EXPECT_EQ(1u, size());
330 ui::MouseEvent
* event
= dispatched_event(0);
331 EXPECT_EQ(ui::ET_MOUSE_MOVED
, event
->type());
333 EXPECT_GT(cursor()->GetLocation().x(),
334 cursor()->GetCursorConfinedBounds().height() - EPSILON
);
335 EXPECT_GT(cursor()->GetLocation().y(),
336 cursor()->GetCursorConfinedBounds().height() - EPSILON
);
339 TEST_F(TabletEventConverterEvdevTest
, Tap
) {
340 ui::MockTabletEventConverterEvdev
* dev
= device();
342 struct input_event mock_kernel_queue
[] = {
343 {{0, 0}, EV_ABS
, ABS_X
, 31628},
344 {{0, 0}, EV_ABS
, ABS_Y
, 21670},
345 {{0, 0}, EV_ABS
, ABS_DISTANCE
, 62},
346 {{0, 0}, EV_ABS
, ABS_TILT_X
, 114},
347 {{0, 0}, EV_ABS
, ABS_TILT_Y
, 85},
348 {{0, 0}, EV_ABS
, ABS_MISC
, 1050626},
349 {{0, 0}, EV_KEY
, BTN_TOOL_PEN
, 1},
350 {{0, 0}, EV_MSC
, MSC_SERIAL
, 159403517},
351 {{0, 0}, EV_SYN
, SYN_REPORT
, 0},
352 {{0, 0}, EV_ABS
, ABS_X
, 32094},
353 {{0, 0}, EV_ABS
, ABS_DISTANCE
, 17},
354 {{0, 0}, EV_ABS
, ABS_PRESSURE
, 883},
355 {{0, 0}, EV_ABS
, ABS_TILT_Y
, 68},
356 {{0, 0}, EV_KEY
, BTN_TOUCH
, 1},
357 {{0, 0}, EV_MSC
, MSC_SERIAL
, 159403517},
358 {{0, 0}, EV_SYN
, SYN_REPORT
, 0},
359 {{0, 0}, EV_ABS
, ABS_X
, 32036},
360 {{0, 0}, EV_ABS
, ABS_Y
, 21658},
361 {{0, 0}, EV_ABS
, ABS_DISTANCE
, 19},
362 {{0, 0}, EV_ABS
, ABS_PRESSURE
, 0},
363 {{0, 0}, EV_KEY
, BTN_TOUCH
, 0},
364 {{0, 0}, EV_MSC
, MSC_SERIAL
, 159403517},
365 {{0, 0}, EV_SYN
, SYN_REPORT
, 0},
366 {{0, 0}, EV_ABS
, ABS_X
, 0},
367 {{0, 0}, EV_ABS
, ABS_Y
, 0},
368 {{0, 0}, EV_ABS
, ABS_DISTANCE
, 0},
369 {{0, 0}, EV_ABS
, ABS_TILT_X
, 0},
370 {{0, 0}, EV_ABS
, ABS_TILT_Y
, 0},
371 {{0, 0}, EV_KEY
, BTN_TOOL_PEN
, 0},
372 {{0, 0}, EV_ABS
, ABS_MISC
, 0},
373 {{0, 0}, EV_MSC
, MSC_SERIAL
, 159403517},
374 {{0, 0}, EV_SYN
, SYN_REPORT
, 0},
377 dev
->ProcessEvents(mock_kernel_queue
, arraysize(mock_kernel_queue
));
378 EXPECT_EQ(3u, size());
380 ui::MouseEvent
* event
= dispatched_event(0);
381 EXPECT_EQ(ui::ET_MOUSE_MOVED
, event
->type());
382 event
= dispatched_event(1);
383 EXPECT_EQ(ui::ET_MOUSE_PRESSED
, event
->type());
384 EXPECT_EQ(true, event
->IsLeftMouseButton());
385 event
= dispatched_event(2);
386 EXPECT_EQ(ui::ET_MOUSE_RELEASED
, event
->type());
387 EXPECT_EQ(true, event
->IsLeftMouseButton());
390 TEST_F(TabletEventConverterEvdevTest
, StylusButtonPress
) {
391 ui::MockTabletEventConverterEvdev
* dev
= device();
393 struct input_event mock_kernel_queue
[] = {
394 {{0, 0}, EV_ABS
, ABS_X
, 30055},
395 {{0, 0}, EV_ABS
, ABS_Y
, 18094},
396 {{0, 0}, EV_ABS
, ABS_DISTANCE
, 62},
397 {{0, 0}, EV_ABS
, ABS_TILT_X
, 99},
398 {{0, 0}, EV_ABS
, ABS_TILT_Y
, 68},
399 {{0, 0}, EV_ABS
, ABS_MISC
, 1050626},
400 {{0, 0}, EV_KEY
, BTN_TOOL_PEN
, 1},
401 {{0, 0}, EV_MSC
, MSC_SERIAL
, 159403517},
402 {{0, 0}, EV_SYN
, SYN_REPORT
, 0},
403 {{0, 0}, EV_ABS
, ABS_X
, 29380},
404 {{0, 0}, EV_KEY
, BTN_STYLUS2
, 1},
405 {{0, 0}, EV_MSC
, MSC_SERIAL
, 159403517},
406 {{0, 0}, EV_SYN
, SYN_REPORT
, 0},
407 {{0, 0}, EV_ABS
, ABS_X
, 29355},
408 {{0, 0}, EV_ABS
, ABS_Y
, 20091},
409 {{0, 0}, EV_ABS
, ABS_DISTANCE
, 34},
410 {{0, 0}, EV_KEY
, BTN_STYLUS2
, 0},
411 {{0, 0}, EV_MSC
, MSC_SERIAL
, 159403517},
412 {{0, 0}, EV_SYN
, SYN_REPORT
, 0},
413 {{0, 0}, EV_ABS
, ABS_X
, 0},
414 {{0, 0}, EV_ABS
, ABS_Y
, 0},
415 {{0, 0}, EV_ABS
, ABS_DISTANCE
, 0},
416 {{0, 0}, EV_ABS
, ABS_TILT_X
, 0},
417 {{0, 0}, EV_ABS
, ABS_TILT_Y
, 0},
418 {{0, 0}, EV_KEY
, BTN_TOOL_PEN
, 0},
419 {{0, 0}, EV_ABS
, ABS_MISC
, 0},
420 {{0, 0}, EV_MSC
, MSC_SERIAL
, 159403517},
421 {{0, 0}, EV_SYN
, SYN_REPORT
, 0},
424 dev
->ProcessEvents(mock_kernel_queue
, arraysize(mock_kernel_queue
));
425 EXPECT_EQ(3u, size());
427 ui::MouseEvent
* event
= dispatched_event(0);
428 EXPECT_EQ(ui::ET_MOUSE_MOVED
, event
->type());
429 event
= dispatched_event(1);
430 EXPECT_EQ(ui::ET_MOUSE_PRESSED
, event
->type());
431 EXPECT_EQ(true, event
->IsRightMouseButton());
432 event
= dispatched_event(2);
433 EXPECT_EQ(ui::ET_MOUSE_RELEASED
, event
->type());
434 EXPECT_EQ(true, event
->IsRightMouseButton());
437 // Should only get an event if BTN_TOOL received
438 TEST_F(TabletEventConverterEvdevTest
, CheckStylusFiltering
) {
439 ui::MockTabletEventConverterEvdev
* dev
= device();
441 struct input_event mock_kernel_queue
[] = {
442 {{0, 0}, EV_ABS
, ABS_X
, 0},
443 {{0, 0}, EV_ABS
, ABS_Y
, 0},
444 {{0, 0}, EV_SYN
, SYN_REPORT
, 0},
447 dev
->ProcessEvents(mock_kernel_queue
, arraysize(mock_kernel_queue
));
448 EXPECT_EQ(0u, size());