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 DCHECK(SetNonBlocking(fds
[0]) == 0)
120 << "SetNonBlocking for pipe fd[0] failed, errno: " << errno
;
121 DCHECK(SetNonBlocking(fds
[1]) == 0)
122 << "SetNonBlocking for pipe fd[0] failed, errno: " << errno
;
124 write_pipe_
= fds
[1];
127 void MockTabletEventConverterEvdev::ConfigureReadMock(struct input_event
* queue
,
130 int nwrite
= HANDLE_EINTR(write(write_pipe_
, queue
+ queue_index
,
131 sizeof(struct input_event
) * read_this_many
));
133 static_cast<int>(sizeof(struct input_event
) * read_this_many
))
134 << "write() failed, errno: " << errno
;
140 class TabletEventConverterEvdevTest
: public testing::Test
{
142 TabletEventConverterEvdevTest() {}
144 // Overridden from testing::Test:
145 void SetUp() override
{
146 // Set up pipe to satisfy message pump (unused).
149 PLOG(FATAL
) << "failed pipe";
150 events_in_
= evdev_io
[0];
151 events_out_
= evdev_io
[1];
153 cursor_
.reset(new ui::MockTabletCursorEvdev());
154 device_manager_
= ui::CreateDeviceManagerForTest();
155 event_factory_
= ui::CreateEventFactoryEvdevForTest(
156 cursor_
.get(), device_manager_
.get(),
157 ui::KeyboardLayoutEngineManager::GetKeyboardLayoutEngine(),
158 base::Bind(&TabletEventConverterEvdevTest::DispatchEventForTest
,
159 base::Unretained(this)));
161 ui::CreateDeviceEventDispatcherEvdevForTest(event_factory_
.get());
162 device_
.reset(new ui::MockTabletEventConverterEvdev(
163 events_in_
, base::FilePath(kTestDevicePath
), cursor_
.get(),
167 void TearDown() override
{
172 ui::MockTabletEventConverterEvdev
* device() { return device_
.get(); }
173 ui::CursorDelegateEvdev
* cursor() { return cursor_
.get(); }
175 unsigned size() { return dispatched_events_
.size(); }
176 ui::MouseEvent
* dispatched_event(unsigned index
) {
177 DCHECK_GT(dispatched_events_
.size(), index
);
178 ui::Event
* ev
= dispatched_events_
[index
];
179 DCHECK(ev
->IsMouseEvent());
180 return static_cast<ui::MouseEvent
*>(ev
);
183 void DispatchEventForTest(ui::Event
* event
) {
184 scoped_ptr
<ui::Event
> cloned_event
= ui::Event::Clone(*event
);
185 dispatched_events_
.push_back(cloned_event
.release());
189 scoped_ptr
<ui::MockTabletCursorEvdev
> cursor_
;
190 scoped_ptr
<ui::DeviceManager
> device_manager_
;
191 scoped_ptr
<ui::EventFactoryEvdev
> event_factory_
;
192 scoped_ptr
<ui::DeviceEventDispatcherEvdev
> dispatcher_
;
193 scoped_ptr
<ui::MockTabletEventConverterEvdev
> device_
;
195 ScopedVector
<ui::Event
> dispatched_events_
;
200 DISALLOW_COPY_AND_ASSIGN(TabletEventConverterEvdevTest
);
205 // Uses real data captured from Wacom Intuos 4
206 TEST_F(TabletEventConverterEvdevTest
, MoveTopLeft
) {
207 ui::MockTabletEventConverterEvdev
* dev
= device();
209 struct input_event mock_kernel_queue
[] = {
210 {{0, 0}, EV_ABS
, ABS_Y
, 616},
211 {{0, 0}, EV_ABS
, ABS_DISTANCE
, 62},
212 {{0, 0}, EV_ABS
, ABS_TILT_X
, 50},
213 {{0, 0}, EV_ABS
, ABS_TILT_Y
, 7},
214 {{0, 0}, EV_ABS
, ABS_MISC
, 1050626},
215 {{0, 0}, EV_KEY
, BTN_TOOL_PEN
, 1},
216 {{0, 0}, EV_MSC
, MSC_SERIAL
, 159403517},
217 {{0, 0}, EV_SYN
, SYN_REPORT
, 0},
218 {{0, 0}, EV_ABS
, ABS_Y
, 0},
219 {{0, 0}, EV_ABS
, ABS_DISTANCE
, 0},
220 {{0, 0}, EV_ABS
, ABS_TILT_X
, 0},
221 {{0, 0}, EV_KEY
, BTN_TOOL_PEN
, 0},
222 {{0, 0}, EV_ABS
, ABS_MISC
, 0},
223 {{0, 0}, EV_MSC
, MSC_SERIAL
, 159403517},
224 {{0, 0}, EV_SYN
, SYN_REPORT
, 0},
227 dev
->ProcessEvents(mock_kernel_queue
, arraysize(mock_kernel_queue
));
228 EXPECT_EQ(1u, size());
230 ui::MouseEvent
* event
= dispatched_event(0);
231 EXPECT_EQ(ui::ET_MOUSE_MOVED
, event
->type());
233 EXPECT_LT(cursor()->GetLocation().x(), EPSILON
);
234 EXPECT_LT(cursor()->GetLocation().y(), EPSILON
);
237 TEST_F(TabletEventConverterEvdevTest
, MoveTopRight
) {
238 ui::MockTabletEventConverterEvdev
* dev
= device();
240 struct input_event mock_kernel_queue
[] = {
241 {{0, 0}, EV_ABS
, ABS_X
, 65024},
242 {{0, 0}, EV_ABS
, ABS_Y
, 33},
243 {{0, 0}, EV_ABS
, ABS_DISTANCE
, 62},
244 {{0, 0}, EV_ABS
, ABS_TILT_X
, 109},
245 {{0, 0}, EV_ABS
, ABS_TILT_Y
, 59},
246 {{0, 0}, EV_ABS
, ABS_MISC
, 1050626},
247 {{0, 0}, EV_KEY
, BTN_TOOL_PEN
, 1},
248 {{0, 0}, EV_MSC
, MSC_SERIAL
, 159403517},
249 {{0, 0}, EV_SYN
, SYN_REPORT
, 0},
250 {{0, 0}, EV_ABS
, ABS_X
, 0},
251 {{0, 0}, EV_ABS
, ABS_DISTANCE
, 0},
252 {{0, 0}, EV_ABS
, ABS_TILT_X
, 0},
253 {{0, 0}, EV_ABS
, ABS_TILT_Y
, 0},
254 {{0, 0}, EV_KEY
, BTN_TOOL_PEN
, 0},
255 {{0, 0}, EV_ABS
, ABS_MISC
, 0},
256 {{0, 0}, EV_MSC
, MSC_SERIAL
, 159403517},
257 {{0, 0}, EV_SYN
, SYN_REPORT
, 0},
260 dev
->ProcessEvents(mock_kernel_queue
, arraysize(mock_kernel_queue
));
261 EXPECT_EQ(1u, size());
263 ui::MouseEvent
* event
= dispatched_event(0);
264 EXPECT_EQ(ui::ET_MOUSE_MOVED
, event
->type());
266 EXPECT_GT(cursor()->GetLocation().x(),
267 cursor()->GetCursorConfinedBounds().width() - EPSILON
);
268 EXPECT_LT(cursor()->GetLocation().y(), EPSILON
);
271 TEST_F(TabletEventConverterEvdevTest
, MoveBottomLeft
) {
272 ui::MockTabletEventConverterEvdev
* dev
= device();
274 struct input_event mock_kernel_queue
[] = {
275 {{0, 0}, EV_ABS
, ABS_Y
, 40640},
276 {{0, 0}, EV_ABS
, ABS_DISTANCE
, 62},
277 {{0, 0}, EV_ABS
, ABS_TILT_X
, 95},
278 {{0, 0}, EV_ABS
, ABS_TILT_Y
, 44},
279 {{0, 0}, EV_ABS
, ABS_MISC
, 1050626},
280 {{0, 0}, EV_KEY
, BTN_TOOL_PEN
, 1},
281 {{0, 0}, EV_MSC
, MSC_SERIAL
, 159403517},
282 {{0, 0}, EV_SYN
, SYN_REPORT
, 0},
283 {{0, 0}, EV_ABS
, ABS_Y
, 0},
284 {{0, 0}, EV_ABS
, ABS_DISTANCE
, 0},
285 {{0, 0}, EV_ABS
, ABS_TILT_X
, 0},
286 {{0, 0}, EV_ABS
, ABS_TILT_Y
, 0},
287 {{0, 0}, EV_KEY
, BTN_TOOL_PEN
, 0},
288 {{0, 0}, EV_ABS
, ABS_MISC
, 0},
289 {{0, 0}, EV_MSC
, MSC_SERIAL
, 159403517},
290 {{0, 0}, EV_SYN
, SYN_REPORT
, 0},
293 dev
->ProcessEvents(mock_kernel_queue
, arraysize(mock_kernel_queue
));
294 EXPECT_EQ(1u, size());
296 ui::MouseEvent
* event
= dispatched_event(0);
297 EXPECT_EQ(ui::ET_MOUSE_MOVED
, event
->type());
299 EXPECT_LT(cursor()->GetLocation().x(), EPSILON
);
300 EXPECT_GT(cursor()->GetLocation().y(),
301 cursor()->GetCursorConfinedBounds().height() - EPSILON
);
304 TEST_F(TabletEventConverterEvdevTest
, MoveBottomRight
) {
305 ui::MockTabletEventConverterEvdev
* dev
= device();
307 struct input_event mock_kernel_queue
[] = {
308 {{0, 0}, EV_ABS
, ABS_X
, 65024},
309 {{0, 0}, EV_ABS
, ABS_Y
, 40640},
310 {{0, 0}, EV_ABS
, ABS_DISTANCE
, 62},
311 {{0, 0}, EV_ABS
, ABS_TILT_X
, 127},
312 {{0, 0}, EV_ABS
, ABS_TILT_Y
, 89},
313 {{0, 0}, EV_ABS
, ABS_MISC
, 1050626},
314 {{0, 0}, EV_KEY
, BTN_TOOL_PEN
, 1},
315 {{0, 0}, EV_MSC
, MSC_SERIAL
, 159403517},
316 {{0, 0}, EV_SYN
, SYN_REPORT
, 0},
317 {{0, 0}, EV_ABS
, ABS_X
, 0},
318 {{0, 0}, EV_ABS
, ABS_Y
, 0},
319 {{0, 0}, EV_ABS
, ABS_DISTANCE
, 0},
320 {{0, 0}, EV_ABS
, ABS_TILT_X
, 0},
321 {{0, 0}, EV_ABS
, ABS_TILT_Y
, 0},
322 {{0, 0}, EV_KEY
, BTN_TOOL_PEN
, 0},
323 {{0, 0}, EV_ABS
, ABS_MISC
, 0},
324 {{0, 0}, EV_MSC
, MSC_SERIAL
, 159403517},
325 {{0, 0}, EV_SYN
, SYN_REPORT
, 0},
328 dev
->ProcessEvents(mock_kernel_queue
, arraysize(mock_kernel_queue
));
329 EXPECT_EQ(1u, size());
331 ui::MouseEvent
* event
= dispatched_event(0);
332 EXPECT_EQ(ui::ET_MOUSE_MOVED
, event
->type());
334 EXPECT_GT(cursor()->GetLocation().x(),
335 cursor()->GetCursorConfinedBounds().height() - EPSILON
);
336 EXPECT_GT(cursor()->GetLocation().y(),
337 cursor()->GetCursorConfinedBounds().height() - EPSILON
);
340 TEST_F(TabletEventConverterEvdevTest
, Tap
) {
341 ui::MockTabletEventConverterEvdev
* dev
= device();
343 struct input_event mock_kernel_queue
[] = {
344 {{0, 0}, EV_ABS
, ABS_X
, 31628},
345 {{0, 0}, EV_ABS
, ABS_Y
, 21670},
346 {{0, 0}, EV_ABS
, ABS_DISTANCE
, 62},
347 {{0, 0}, EV_ABS
, ABS_TILT_X
, 114},
348 {{0, 0}, EV_ABS
, ABS_TILT_Y
, 85},
349 {{0, 0}, EV_ABS
, ABS_MISC
, 1050626},
350 {{0, 0}, EV_KEY
, BTN_TOOL_PEN
, 1},
351 {{0, 0}, EV_MSC
, MSC_SERIAL
, 159403517},
352 {{0, 0}, EV_SYN
, SYN_REPORT
, 0},
353 {{0, 0}, EV_ABS
, ABS_X
, 32094},
354 {{0, 0}, EV_ABS
, ABS_DISTANCE
, 17},
355 {{0, 0}, EV_ABS
, ABS_PRESSURE
, 883},
356 {{0, 0}, EV_ABS
, ABS_TILT_Y
, 68},
357 {{0, 0}, EV_KEY
, BTN_TOUCH
, 1},
358 {{0, 0}, EV_MSC
, MSC_SERIAL
, 159403517},
359 {{0, 0}, EV_SYN
, SYN_REPORT
, 0},
360 {{0, 0}, EV_ABS
, ABS_X
, 32036},
361 {{0, 0}, EV_ABS
, ABS_Y
, 21658},
362 {{0, 0}, EV_ABS
, ABS_DISTANCE
, 19},
363 {{0, 0}, EV_ABS
, ABS_PRESSURE
, 0},
364 {{0, 0}, EV_KEY
, BTN_TOUCH
, 0},
365 {{0, 0}, EV_MSC
, MSC_SERIAL
, 159403517},
366 {{0, 0}, EV_SYN
, SYN_REPORT
, 0},
367 {{0, 0}, EV_ABS
, ABS_X
, 0},
368 {{0, 0}, EV_ABS
, ABS_Y
, 0},
369 {{0, 0}, EV_ABS
, ABS_DISTANCE
, 0},
370 {{0, 0}, EV_ABS
, ABS_TILT_X
, 0},
371 {{0, 0}, EV_ABS
, ABS_TILT_Y
, 0},
372 {{0, 0}, EV_KEY
, BTN_TOOL_PEN
, 0},
373 {{0, 0}, EV_ABS
, ABS_MISC
, 0},
374 {{0, 0}, EV_MSC
, MSC_SERIAL
, 159403517},
375 {{0, 0}, EV_SYN
, SYN_REPORT
, 0},
378 dev
->ProcessEvents(mock_kernel_queue
, arraysize(mock_kernel_queue
));
379 EXPECT_EQ(3u, size());
381 ui::MouseEvent
* event
= dispatched_event(0);
382 EXPECT_EQ(ui::ET_MOUSE_MOVED
, event
->type());
383 event
= dispatched_event(1);
384 EXPECT_EQ(ui::ET_MOUSE_PRESSED
, event
->type());
385 EXPECT_EQ(true, event
->IsLeftMouseButton());
386 event
= dispatched_event(2);
387 EXPECT_EQ(ui::ET_MOUSE_RELEASED
, event
->type());
388 EXPECT_EQ(true, event
->IsLeftMouseButton());
391 TEST_F(TabletEventConverterEvdevTest
, StylusButtonPress
) {
392 ui::MockTabletEventConverterEvdev
* dev
= device();
394 struct input_event mock_kernel_queue
[] = {
395 {{0, 0}, EV_ABS
, ABS_X
, 30055},
396 {{0, 0}, EV_ABS
, ABS_Y
, 18094},
397 {{0, 0}, EV_ABS
, ABS_DISTANCE
, 62},
398 {{0, 0}, EV_ABS
, ABS_TILT_X
, 99},
399 {{0, 0}, EV_ABS
, ABS_TILT_Y
, 68},
400 {{0, 0}, EV_ABS
, ABS_MISC
, 1050626},
401 {{0, 0}, EV_KEY
, BTN_TOOL_PEN
, 1},
402 {{0, 0}, EV_MSC
, MSC_SERIAL
, 159403517},
403 {{0, 0}, EV_SYN
, SYN_REPORT
, 0},
404 {{0, 0}, EV_ABS
, ABS_X
, 29380},
405 {{0, 0}, EV_KEY
, BTN_STYLUS2
, 1},
406 {{0, 0}, EV_MSC
, MSC_SERIAL
, 159403517},
407 {{0, 0}, EV_SYN
, SYN_REPORT
, 0},
408 {{0, 0}, EV_ABS
, ABS_X
, 29355},
409 {{0, 0}, EV_ABS
, ABS_Y
, 20091},
410 {{0, 0}, EV_ABS
, ABS_DISTANCE
, 34},
411 {{0, 0}, EV_KEY
, BTN_STYLUS2
, 0},
412 {{0, 0}, EV_MSC
, MSC_SERIAL
, 159403517},
413 {{0, 0}, EV_SYN
, SYN_REPORT
, 0},
414 {{0, 0}, EV_ABS
, ABS_X
, 0},
415 {{0, 0}, EV_ABS
, ABS_Y
, 0},
416 {{0, 0}, EV_ABS
, ABS_DISTANCE
, 0},
417 {{0, 0}, EV_ABS
, ABS_TILT_X
, 0},
418 {{0, 0}, EV_ABS
, ABS_TILT_Y
, 0},
419 {{0, 0}, EV_KEY
, BTN_TOOL_PEN
, 0},
420 {{0, 0}, EV_ABS
, ABS_MISC
, 0},
421 {{0, 0}, EV_MSC
, MSC_SERIAL
, 159403517},
422 {{0, 0}, EV_SYN
, SYN_REPORT
, 0},
425 dev
->ProcessEvents(mock_kernel_queue
, arraysize(mock_kernel_queue
));
426 EXPECT_EQ(3u, size());
428 ui::MouseEvent
* event
= dispatched_event(0);
429 EXPECT_EQ(ui::ET_MOUSE_MOVED
, event
->type());
430 event
= dispatched_event(1);
431 EXPECT_EQ(ui::ET_MOUSE_PRESSED
, event
->type());
432 EXPECT_EQ(true, event
->IsRightMouseButton());
433 event
= dispatched_event(2);
434 EXPECT_EQ(ui::ET_MOUSE_RELEASED
, event
->type());
435 EXPECT_EQ(true, event
->IsRightMouseButton());
438 // Should only get an event if BTN_TOOL received
439 TEST_F(TabletEventConverterEvdevTest
, CheckStylusFiltering
) {
440 ui::MockTabletEventConverterEvdev
* dev
= device();
442 struct input_event mock_kernel_queue
[] = {
443 {{0, 0}, EV_ABS
, ABS_X
, 0},
444 {{0, 0}, EV_ABS
, ABS_Y
, 0},
445 {{0, 0}, EV_SYN
, SYN_REPORT
, 0},
448 dev
->ProcessEvents(mock_kernel_queue
, arraysize(mock_kernel_queue
));
449 EXPECT_EQ(0u, size());