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_device_test_util.h"
23 #include "ui/events/ozone/evdev/event_factory_evdev.h"
24 #include "ui/events/ozone/evdev/tablet_event_converter_evdev.h"
25 #include "ui/events/ozone/layout/keyboard_layout_engine_manager.h"
26 #include "ui/events/platform/platform_event_dispatcher.h"
27 #include "ui/events/platform/platform_event_source.h"
31 static int SetNonBlocking(int fd
) {
32 int flags
= fcntl(fd
, F_GETFL
, 0);
35 return fcntl(fd
, F_SETFL
, flags
| O_NONBLOCK
);
38 const char kTestDevicePath
[] = "/dev/input/test-device";
40 const ui::DeviceAbsoluteAxis kWacomIntuos5SPenAbsAxes
[] = {
41 {ABS_X
, {0, 0, 31496, 4, 0, 200}},
42 {ABS_Y
, {0, 0, 19685, 4, 0, 200}},
43 {ABS_Z
, {0, -900, 899, 0, 0, 0}},
44 {ABS_RZ
, {0, -900, 899, 0, 0, 0}},
45 {ABS_THROTTLE
, {0, -1023, 1023, 0, 0, 0}},
46 {ABS_WHEEL
, {0, 0, 1023, 0, 0, 0}},
47 {ABS_PRESSURE
, {0, 0, 2047, 0, 0, 0}},
48 {ABS_DISTANCE
, {0, 0, 63, 0, 0, 0}},
49 {ABS_TILT_X
, {0, 0, 127, 0, 0, 0}},
50 {ABS_TILT_Y
, {0, 0, 127, 0, 0, 0}},
51 {ABS_MISC
, {0, 0, 0, 0, 0, 0}},
54 const ui::DeviceCapabilities kWacomIntuos5SPen
= {
55 /* path */ "/sys/devices/pci0000:00/0000:00:14.0/usb1/"
56 "1-1/1-1:1.0/input/input19/event5",
57 /* name */ "Wacom Intuos5 touch S Pen",
66 /* key */ "1cdf 1f007f 0 0 0 0",
68 /* abs */ "1000f000167",
73 kWacomIntuos5SPenAbsAxes
,
74 arraysize(kWacomIntuos5SPenAbsAxes
),
81 class MockTabletEventConverterEvdev
: public TabletEventConverterEvdev
{
83 MockTabletEventConverterEvdev(int fd
,
85 CursorDelegateEvdev
* cursor
,
86 const EventDeviceInfo
& devinfo
,
87 DeviceEventDispatcherEvdev
* dispatcher
);
88 ~MockTabletEventConverterEvdev() override
{};
90 void ConfigureReadMock(struct input_event
* queue
,
94 // Actually dispatch the event reader code.
96 OnFileCanReadWithoutBlocking(read_pipe_
);
97 base::RunLoop().RunUntilIdle();
104 ScopedVector
<Event
> dispatched_events_
;
106 DISALLOW_COPY_AND_ASSIGN(MockTabletEventConverterEvdev
);
109 class MockTabletCursorEvdev
: public CursorDelegateEvdev
{
111 MockTabletCursorEvdev() { cursor_confined_bounds_
= gfx::Rect(1024, 768); }
112 ~MockTabletCursorEvdev() override
{}
114 // CursorDelegateEvdev:
115 void MoveCursorTo(gfx::AcceleratedWidget widget
,
116 const gfx::PointF
& location
) override
{
119 void MoveCursorTo(const gfx::PointF
& location
) override
{
120 cursor_location_
= location
;
122 void MoveCursor(const gfx::Vector2dF
& delta
) override
{ NOTREACHED(); }
123 bool IsCursorVisible() override
{ return 1; }
124 gfx::PointF
GetLocation() override
{ return cursor_location_
; }
125 gfx::Rect
GetCursorConfinedBounds() override
{
126 return cursor_confined_bounds_
;
130 gfx::PointF cursor_location_
;
131 gfx::Rect cursor_confined_bounds_
;
132 DISALLOW_COPY_AND_ASSIGN(MockTabletCursorEvdev
);
135 MockTabletEventConverterEvdev::MockTabletEventConverterEvdev(
138 CursorDelegateEvdev
* cursor
,
139 const EventDeviceInfo
& devinfo
,
140 DeviceEventDispatcherEvdev
* dispatcher
)
141 : TabletEventConverterEvdev(fd
,
150 PLOG(FATAL
) << "failed pipe";
152 EXPECT_FALSE(SetNonBlocking(fds
[0]) || SetNonBlocking(fds
[1]))
153 << "failed to set non-blocking: " << strerror(errno
);
156 write_pipe_
= fds
[1];
159 void MockTabletEventConverterEvdev::ConfigureReadMock(struct input_event
* queue
,
162 int nwrite
= HANDLE_EINTR(write(write_pipe_
, queue
+ queue_index
,
163 sizeof(struct input_event
) * read_this_many
));
165 static_cast<int>(sizeof(struct input_event
) * read_this_many
))
166 << "write() failed, errno: " << errno
;
172 class TabletEventConverterEvdevTest
: public testing::Test
{
174 TabletEventConverterEvdevTest() {}
176 // Overridden from testing::Test:
177 void SetUp() override
{
178 // Set up pipe to satisfy message pump (unused).
181 PLOG(FATAL
) << "failed pipe";
182 events_in_
= evdev_io
[0];
183 events_out_
= evdev_io
[1];
185 cursor_
.reset(new ui::MockTabletCursorEvdev());
186 device_manager_
= ui::CreateDeviceManagerForTest();
187 event_factory_
= ui::CreateEventFactoryEvdevForTest(
188 cursor_
.get(), device_manager_
.get(),
189 ui::KeyboardLayoutEngineManager::GetKeyboardLayoutEngine(),
190 base::Bind(&TabletEventConverterEvdevTest::DispatchEventForTest
,
191 base::Unretained(this)));
193 ui::CreateDeviceEventDispatcherEvdevForTest(event_factory_
.get());
196 void TearDown() override
{
200 ui::MockTabletEventConverterEvdev
* CreateDevice(
201 const ui::DeviceCapabilities
& caps
) {
202 ui::EventDeviceInfo devinfo
;
203 CapabilitiesToDeviceInfo(caps
, &devinfo
);
204 return new ui::MockTabletEventConverterEvdev(
205 events_in_
, base::FilePath(kTestDevicePath
), cursor_
.get(), devinfo
,
209 ui::CursorDelegateEvdev
* cursor() { return cursor_
.get(); }
211 unsigned size() { return dispatched_events_
.size(); }
212 ui::MouseEvent
* dispatched_event(unsigned index
) {
213 DCHECK_GT(dispatched_events_
.size(), index
);
214 ui::Event
* ev
= dispatched_events_
[index
];
215 DCHECK(ev
->IsMouseEvent());
216 return static_cast<ui::MouseEvent
*>(ev
);
219 void DispatchEventForTest(ui::Event
* event
) {
220 scoped_ptr
<ui::Event
> cloned_event
= ui::Event::Clone(*event
);
221 dispatched_events_
.push_back(cloned_event
.Pass());
225 scoped_ptr
<ui::MockTabletCursorEvdev
> cursor_
;
226 scoped_ptr
<ui::DeviceManager
> device_manager_
;
227 scoped_ptr
<ui::EventFactoryEvdev
> event_factory_
;
228 scoped_ptr
<ui::DeviceEventDispatcherEvdev
> dispatcher_
;
230 ScopedVector
<ui::Event
> dispatched_events_
;
235 DISALLOW_COPY_AND_ASSIGN(TabletEventConverterEvdevTest
);
240 // Uses real data captured from Wacom Intuos 5 Pen
241 TEST_F(TabletEventConverterEvdevTest
, MoveTopLeft
) {
242 scoped_ptr
<ui::MockTabletEventConverterEvdev
> dev
=
243 make_scoped_ptr(CreateDevice(kWacomIntuos5SPen
));
245 struct input_event mock_kernel_queue
[] = {
246 {{0, 0}, EV_ABS
, ABS_DISTANCE
, 63},
247 {{0, 0}, EV_ABS
, ABS_X
, 477},
248 {{0, 0}, EV_ABS
, ABS_TILT_X
, 66},
249 {{0, 0}, EV_ABS
, ABS_TILT_Y
, 62},
250 {{0, 0}, EV_ABS
, ABS_MISC
, 1050626},
251 {{0, 0}, EV_KEY
, BTN_TOOL_PEN
, 1},
252 {{0, 0}, EV_MSC
, MSC_SERIAL
, 897618290},
253 {{0, 0}, EV_SYN
, SYN_REPORT
, 0},
254 {{0, 0}, EV_ABS
, ABS_DISTANCE
, 0},
255 {{0, 0}, EV_ABS
, ABS_TILT_X
, 0},
256 {{0, 0}, EV_ABS
, ABS_TILT_Y
, 0},
257 {{0, 0}, EV_KEY
, BTN_TOOL_PEN
, 0},
258 {{0, 0}, EV_ABS
, ABS_MISC
, 0},
259 {{0, 0}, EV_MSC
, MSC_SERIAL
, 897618290},
260 {{0, 0}, EV_SYN
, SYN_REPORT
, 0},
263 dev
->ProcessEvents(mock_kernel_queue
, arraysize(mock_kernel_queue
));
264 EXPECT_EQ(1u, size());
266 ui::MouseEvent
* event
= dispatched_event(0);
267 EXPECT_EQ(ui::ET_MOUSE_MOVED
, event
->type());
269 EXPECT_LT(cursor()->GetLocation().x(), EPSILON
);
270 EXPECT_LT(cursor()->GetLocation().y(), EPSILON
);
273 TEST_F(TabletEventConverterEvdevTest
, MoveTopRight
) {
274 scoped_ptr
<ui::MockTabletEventConverterEvdev
> dev
=
275 make_scoped_ptr(CreateDevice(kWacomIntuos5SPen
));
277 struct input_event mock_kernel_queue
[] = {
278 {{0, 0}, EV_ABS
, ABS_DISTANCE
, 63},
279 {{0, 0}, EV_ABS
, ABS_X
, 31496},
280 {{0, 0}, EV_ABS
, ABS_Y
, 109},
281 {{0, 0}, EV_ABS
, ABS_TILT_X
, 66},
282 {{0, 0}, EV_ABS
, ABS_TILT_Y
, 61},
283 {{0, 0}, EV_ABS
, ABS_MISC
, 1050626},
284 {{0, 0}, EV_KEY
, BTN_TOOL_PEN
, 1},
285 {{0, 0}, EV_MSC
, MSC_SERIAL
, 897618290},
286 {{0, 0}, EV_SYN
, SYN_REPORT
, 0},
287 {{0, 0}, EV_ABS
, ABS_X
, 0},
288 {{0, 0}, EV_ABS
, ABS_DISTANCE
, 0},
289 {{0, 0}, EV_ABS
, ABS_TILT_X
, 0},
290 {{0, 0}, EV_ABS
, ABS_TILT_Y
, 0},
291 {{0, 0}, EV_KEY
, BTN_TOOL_PEN
, 0},
292 {{0, 0}, EV_ABS
, ABS_MISC
, 0},
293 {{0, 0}, EV_MSC
, MSC_SERIAL
, 897618290},
294 {{0, 0}, EV_SYN
, SYN_REPORT
, 0},
297 dev
->ProcessEvents(mock_kernel_queue
, arraysize(mock_kernel_queue
));
298 EXPECT_EQ(1u, size());
300 ui::MouseEvent
* event
= dispatched_event(0);
301 EXPECT_EQ(ui::ET_MOUSE_MOVED
, event
->type());
303 EXPECT_GT(cursor()->GetLocation().x(),
304 cursor()->GetCursorConfinedBounds().width() - EPSILON
);
305 EXPECT_LT(cursor()->GetLocation().y(), EPSILON
);
308 TEST_F(TabletEventConverterEvdevTest
, MoveBottomLeft
) {
309 scoped_ptr
<ui::MockTabletEventConverterEvdev
> dev
=
310 make_scoped_ptr(CreateDevice(kWacomIntuos5SPen
));
312 struct input_event mock_kernel_queue
[] = {
313 {{0, 0}, EV_ABS
, ABS_DISTANCE
, 63},
314 {{0, 0}, EV_ABS
, ABS_Y
, 19685},
315 {{0, 0}, EV_ABS
, ABS_TILT_X
, 64},
316 {{0, 0}, EV_ABS
, ABS_TILT_Y
, 61},
317 {{0, 0}, EV_ABS
, ABS_MISC
, 1050626},
318 {{0, 0}, EV_KEY
, BTN_TOOL_PEN
, 1},
319 {{0, 0}, EV_MSC
, MSC_SERIAL
, 897618290},
320 {{0, 0}, EV_SYN
, SYN_REPORT
, 0},
321 {{0, 0}, EV_ABS
, ABS_X
, 0},
322 {{0, 0}, EV_ABS
, ABS_Y
, 0},
323 {{0, 0}, EV_ABS
, ABS_DISTANCE
, 0},
324 {{0, 0}, EV_ABS
, ABS_TILT_X
, 0},
325 {{0, 0}, EV_ABS
, ABS_TILT_Y
, 0},
326 {{0, 0}, EV_KEY
, BTN_TOOL_PEN
, 0},
327 {{0, 0}, EV_ABS
, ABS_MISC
, 0},
328 {{0, 0}, EV_MSC
, MSC_SERIAL
, 897618290},
329 {{0, 0}, EV_SYN
, SYN_REPORT
, 0},
332 dev
->ProcessEvents(mock_kernel_queue
, arraysize(mock_kernel_queue
));
333 EXPECT_EQ(1u, size());
335 ui::MouseEvent
* event
= dispatched_event(0);
336 EXPECT_EQ(ui::ET_MOUSE_MOVED
, event
->type());
338 EXPECT_LT(cursor()->GetLocation().x(), EPSILON
);
339 EXPECT_GT(cursor()->GetLocation().y(),
340 cursor()->GetCursorConfinedBounds().height() - EPSILON
);
343 TEST_F(TabletEventConverterEvdevTest
, MoveBottomRight
) {
344 scoped_ptr
<ui::MockTabletEventConverterEvdev
> dev
=
345 make_scoped_ptr(CreateDevice(kWacomIntuos5SPen
));
347 struct input_event mock_kernel_queue
[] = {
348 {{0, 0}, EV_ABS
, ABS_DISTANCE
, 63},
349 {{0, 0}, EV_ABS
, ABS_X
, 31496},
350 {{0, 0}, EV_ABS
, ABS_Y
, 19685},
351 {{0, 0}, EV_ABS
, ABS_TILT_X
, 67},
352 {{0, 0}, EV_ABS
, ABS_TILT_Y
, 63},
353 {{0, 0}, EV_ABS
, ABS_MISC
, 1050626},
354 {{0, 0}, EV_KEY
, BTN_TOOL_PEN
, 1},
355 {{0, 0}, EV_MSC
, MSC_SERIAL
, 897618290},
356 {{0, 0}, EV_SYN
, SYN_REPORT
, 0},
357 {{0, 0}, EV_ABS
, ABS_X
, 0},
358 {{0, 0}, EV_ABS
, ABS_Y
, 0},
359 {{0, 0}, EV_ABS
, ABS_DISTANCE
, 0},
360 {{0, 0}, EV_ABS
, ABS_TILT_X
, 0},
361 {{0, 0}, EV_ABS
, ABS_TILT_Y
, 0},
362 {{0, 0}, EV_KEY
, BTN_TOOL_PEN
, 0},
363 {{0, 0}, EV_ABS
, ABS_MISC
, 0},
364 {{0, 0}, EV_MSC
, MSC_SERIAL
, 897618290},
365 {{0, 0}, EV_SYN
, SYN_REPORT
, 0},
368 dev
->ProcessEvents(mock_kernel_queue
, arraysize(mock_kernel_queue
));
369 EXPECT_EQ(1u, size());
371 ui::MouseEvent
* event
= dispatched_event(0);
372 EXPECT_EQ(ui::ET_MOUSE_MOVED
, event
->type());
374 EXPECT_GT(cursor()->GetLocation().x(),
375 cursor()->GetCursorConfinedBounds().height() - EPSILON
);
376 EXPECT_GT(cursor()->GetLocation().y(),
377 cursor()->GetCursorConfinedBounds().height() - EPSILON
);
380 TEST_F(TabletEventConverterEvdevTest
, Tap
) {
381 scoped_ptr
<ui::MockTabletEventConverterEvdev
> dev
=
382 make_scoped_ptr(CreateDevice(kWacomIntuos5SPen
));
384 struct input_event mock_kernel_queue
[] = {
385 {{0, 0}, EV_ABS
, ABS_X
, 15456},
386 {{0, 0}, EV_ABS
, ABS_Y
, 8605},
387 {{0, 0}, EV_ABS
, ABS_DISTANCE
, 49},
388 {{0, 0}, EV_ABS
, ABS_TILT_X
, 68},
389 {{0, 0}, EV_ABS
, ABS_TILT_Y
, 64},
390 {{0, 0}, EV_ABS
, ABS_MISC
, 1050626},
391 {{0, 0}, EV_KEY
, BTN_TOOL_PEN
, 1},
392 {{0, 0}, EV_MSC
, MSC_SERIAL
, 897618290},
393 {{0, 0}, EV_SYN
, SYN_REPORT
, 0},
394 {{0, 0}, EV_ABS
, ABS_X
, 15725},
395 {{0, 0}, EV_ABS
, ABS_Y
, 8755},
396 {{0, 0}, EV_ABS
, ABS_DISTANCE
, 29},
397 {{0, 0}, EV_ABS
, ABS_PRESSURE
, 992},
398 {{0, 0}, EV_KEY
, BTN_TOUCH
, 1},
399 {{0, 0}, EV_MSC
, MSC_SERIAL
, 897618290},
400 {{0, 0}, EV_SYN
, SYN_REPORT
, 0},
401 {{0, 0}, EV_ABS
, ABS_X
, 15922},
402 {{0, 0}, EV_ABS
, ABS_Y
, 8701},
403 {{0, 0}, EV_ABS
, ABS_DISTANCE
, 32},
404 {{0, 0}, EV_ABS
, ABS_PRESSURE
, 0},
405 {{0, 0}, EV_KEY
, BTN_TOUCH
, 0},
406 {{0, 0}, EV_MSC
, MSC_SERIAL
, 897618290},
407 {{0, 0}, EV_SYN
, SYN_REPORT
, 0},
408 {{0, 0}, EV_ABS
, ABS_X
, 0},
409 {{0, 0}, EV_ABS
, ABS_Y
, 0},
410 {{0, 0}, EV_ABS
, ABS_DISTANCE
, 0},
411 {{0, 0}, EV_ABS
, ABS_TILT_X
, 0},
412 {{0, 0}, EV_ABS
, ABS_TILT_Y
, 0},
413 {{0, 0}, EV_KEY
, BTN_TOOL_PEN
, 0},
414 {{0, 0}, EV_ABS
, ABS_MISC
, 0},
415 {{0, 0}, EV_MSC
, MSC_SERIAL
, 897618290},
416 {{0, 0}, EV_SYN
, SYN_REPORT
, 0},
419 dev
->ProcessEvents(mock_kernel_queue
, arraysize(mock_kernel_queue
));
420 EXPECT_EQ(3u, size());
422 ui::MouseEvent
* event
= dispatched_event(0);
423 EXPECT_EQ(ui::ET_MOUSE_MOVED
, event
->type());
424 event
= dispatched_event(1);
425 EXPECT_EQ(ui::ET_MOUSE_PRESSED
, event
->type());
426 EXPECT_EQ(true, event
->IsLeftMouseButton());
427 event
= dispatched_event(2);
428 EXPECT_EQ(ui::ET_MOUSE_RELEASED
, event
->type());
429 EXPECT_EQ(true, event
->IsLeftMouseButton());
432 TEST_F(TabletEventConverterEvdevTest
, StylusButtonPress
) {
433 scoped_ptr
<ui::MockTabletEventConverterEvdev
> dev
=
434 make_scoped_ptr(CreateDevice(kWacomIntuos5SPen
));
436 struct input_event mock_kernel_queue
[] = {
437 {{0, 0}, EV_ABS
, ABS_DISTANCE
, 63},
438 {{0, 0}, EV_ABS
, ABS_X
, 18372},
439 {{0, 0}, EV_ABS
, ABS_Y
, 9880},
440 {{0, 0}, EV_ABS
, ABS_DISTANCE
, 61},
441 {{0, 0}, EV_ABS
, ABS_TILT_X
, 60},
442 {{0, 0}, EV_ABS
, ABS_TILT_Y
, 63},
443 {{0, 0}, EV_ABS
, ABS_MISC
, 1050626},
444 {{0, 0}, EV_KEY
, BTN_TOOL_PEN
, 1},
445 {{0, 0}, EV_MSC
, MSC_SERIAL
, 897618290},
446 {{0, 0}, EV_SYN
, SYN_REPORT
, 0},
447 {{0, 0}, EV_ABS
, ABS_X
, 18294},
448 {{0, 0}, EV_ABS
, ABS_Y
, 9723},
449 {{0, 0}, EV_ABS
, ABS_DISTANCE
, 20},
450 {{0, 0}, EV_ABS
, ABS_PRESSURE
, 1015},
451 {{0, 0}, EV_KEY
, BTN_STYLUS2
, 1},
452 {{0, 0}, EV_MSC
, MSC_SERIAL
, 897618290},
453 {{0, 0}, EV_SYN
, SYN_REPORT
, 0},
454 {{0, 0}, EV_ABS
, ABS_X
, 18516},
455 {{0, 0}, EV_ABS
, ABS_Y
, 9723},
456 {{0, 0}, EV_ABS
, ABS_DISTANCE
, 23},
457 {{0, 0}, EV_KEY
, BTN_STYLUS2
, 0},
458 {{0, 0}, EV_MSC
, MSC_SERIAL
, 897618290},
459 {{0, 0}, EV_SYN
, SYN_REPORT
, 0},
460 {{0, 0}, EV_ABS
, ABS_X
, 0},
461 {{0, 0}, EV_ABS
, ABS_Y
, 0},
462 {{0, 0}, EV_ABS
, ABS_DISTANCE
, 0},
463 {{0, 0}, EV_ABS
, ABS_TILT_X
, 0},
464 {{0, 0}, EV_ABS
, ABS_TILT_Y
, 0},
465 {{0, 0}, EV_KEY
, BTN_TOOL_PEN
, 0},
466 {{0, 0}, EV_ABS
, ABS_MISC
, 0},
467 {{0, 0}, EV_MSC
, MSC_SERIAL
, 897618290},
468 {{0, 0}, EV_SYN
, SYN_REPORT
, 0},
471 dev
->ProcessEvents(mock_kernel_queue
, arraysize(mock_kernel_queue
));
472 EXPECT_EQ(3u, size());
474 ui::MouseEvent
* event
= dispatched_event(0);
475 EXPECT_EQ(ui::ET_MOUSE_MOVED
, event
->type());
476 event
= dispatched_event(1);
477 EXPECT_EQ(ui::ET_MOUSE_PRESSED
, event
->type());
478 EXPECT_EQ(true, event
->IsRightMouseButton());
479 event
= dispatched_event(2);
480 EXPECT_EQ(ui::ET_MOUSE_RELEASED
, event
->type());
481 EXPECT_EQ(true, event
->IsRightMouseButton());
484 // Should only get an event if BTN_TOOL received
485 TEST_F(TabletEventConverterEvdevTest
, CheckStylusFiltering
) {
486 scoped_ptr
<ui::MockTabletEventConverterEvdev
> dev
=
487 make_scoped_ptr(CreateDevice(kWacomIntuos5SPen
));
489 struct input_event mock_kernel_queue
[] = {
490 {{0, 0}, EV_ABS
, ABS_X
, 0},
491 {{0, 0}, EV_ABS
, ABS_Y
, 0},
492 {{0, 0}, EV_SYN
, SYN_REPORT
, 0},
495 dev
->ProcessEvents(mock_kernel_queue
, arraysize(mock_kernel_queue
));
496 EXPECT_EQ(0u, size());