From fd6b78bc2cac155f67f0bd09c184645353f7d6b9 Mon Sep 17 00:00:00 2001 From: spang Date: Thu, 11 Jun 2015 11:24:35 -0700 Subject: ozone: evdev: Add quirk to allow BTN_LEFT for single touch touchscreens This restores support for some older USB touchscreens that use the mouse HID usage class and use mouse button events to represent touches. Left clicks are converted to touch events, and although some devices support right clicks these are ignored. BUG=477695 TEST=Plug Elo TouchSystems 2700 into Chrome OS. Touch works. Review URL: https://codereview.chromium.org/1179623002 Cr-Commit-Position: refs/heads/master@{#333992} --- ui/events/ozone/evdev/event_device_info.cc | 2 +- .../ozone/evdev/event_device_info_unittest.cc | 12 +++ ui/events/ozone/evdev/event_device_test_util.cc | 30 +++++++ ui/events/ozone/evdev/event_device_test_util.h | 1 + .../ozone/evdev/touch_event_converter_evdev.cc | 22 ++++-- .../ozone/evdev/touch_event_converter_evdev.h | 3 + .../evdev/touch_event_converter_evdev_unittest.cc | 92 ++++++++++++++++++++++ 7 files changed, 155 insertions(+), 7 deletions(-) diff --git a/ui/events/ozone/evdev/event_device_info.cc b/ui/events/ozone/evdev/event_device_info.cc index e3c9f73..fba26d3 100644 --- a/ui/events/ozone/evdev/event_device_info.cc +++ b/ui/events/ozone/evdev/event_device_info.cc @@ -411,7 +411,7 @@ EventDeviceInfo::ProbeLegacyAbsoluteDevice() const { if (HasKeyEvent(BTN_TOOL_FINGER) && HasKeyEvent(BTN_TOUCH)) return LegacyAbsoluteDeviceType::LADT_TOUCHPAD; - if (HasKeyEvent(BTN_TOUCH)) + if (HasKeyEvent(BTN_TOUCH) || HasKeyEvent(BTN_LEFT)) return LegacyAbsoluteDeviceType::LADT_TOUCHSCREEN; return LegacyAbsoluteDeviceType::LADT_NONE; diff --git a/ui/events/ozone/evdev/event_device_info_unittest.cc b/ui/events/ozone/evdev/event_device_info_unittest.cc index cc7af80..63187a1 100644 --- a/ui/events/ozone/evdev/event_device_info_unittest.cc +++ b/ui/events/ozone/evdev/event_device_info_unittest.cc @@ -136,4 +136,16 @@ TEST_F(EventDeviceInfoTest, HybridKeyboardWithMouse) { EXPECT_FALSE(devinfo.HasTablet()); } +TEST_F(EventDeviceInfoTest, AbsoluteMouseTouchscreen) { + EventDeviceInfo devinfo; + EXPECT_TRUE(CapabilitiesToDeviceInfo(kElo_TouchSystems_2700, &devinfo)); + + // This touchscreen uses BTN_LEFT for touch contact. + EXPECT_FALSE(devinfo.HasKeyboard()); + EXPECT_FALSE(devinfo.HasMouse()); + EXPECT_FALSE(devinfo.HasTouchpad()); + EXPECT_TRUE(devinfo.HasTouchscreen()); + EXPECT_FALSE(devinfo.HasTablet()); +} + } // namespace ui diff --git a/ui/events/ozone/evdev/event_device_test_util.cc b/ui/events/ozone/evdev/event_device_test_util.cc index cb4116c..4d5407c 100644 --- a/ui/events/ozone/evdev/event_device_test_util.cc +++ b/ui/events/ozone/evdev/event_device_test_util.cc @@ -363,6 +363,36 @@ const DeviceCapabilities kLogitechTouchKeyboardK400 = { arraysize(kLogitechTouchKeyboardK400AbsAxes), }; +// Captured from Elo TouchSystems 2700 touchscreen. +const DeviceAbsoluteAxis kElo_TouchSystems_2700AbsAxes[] = { + {ABS_X, {0, 0, 4095, 0, 0, 0}}, + {ABS_Y, {0, 0, 4095, 0, 0, 0}}, + {ABS_MISC, {0, 0, 256, 0, 0, 0}}, +}; +const DeviceCapabilities kElo_TouchSystems_2700 = { + /* path */ "/sys/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.3/2-1.3:1.0/" + "input/input9/event9", + /* name */ "Elo TouchSystems, Inc. Elo TouchSystems 2700 IntelliTouch(r) " + "USB Touchmonitor Interface", + /* phys */ "usb-0000:00:1d.0-1.3/input0", + /* uniq */ "20A01347", + /* bustype */ "0003", + /* vendor */ "04e7", + /* product */ "0020", + /* version */ "0100", + /* prop */ "0", + /* ev */ "1b", + /* key */ "10000 0 0 0 0", + /* rel */ "0", + /* abs */ "10000000003", + /* msc */ "10", + /* sw */ "0", + /* led */ "0", + /* ff */ "0", + kElo_TouchSystems_2700AbsAxes, + arraysize(kElo_TouchSystems_2700AbsAxes), +}; + bool CapabilitiesToDeviceInfo(const DeviceCapabilities& capabilities, EventDeviceInfo* devinfo) { std::vector ev_bits; diff --git a/ui/events/ozone/evdev/event_device_test_util.h b/ui/events/ozone/evdev/event_device_test_util.h index 46afb6a..b02f74a 100644 --- a/ui/events/ozone/evdev/event_device_test_util.h +++ b/ui/events/ozone/evdev/event_device_test_util.h @@ -68,6 +68,7 @@ extern const DeviceCapabilities kMimoTouch2Touchscreen; extern const DeviceCapabilities kWacomIntuosPtS_Pen; extern const DeviceCapabilities kWacomIntuosPtS_Finger; extern const DeviceCapabilities kLogitechTouchKeyboardK400; +extern const DeviceCapabilities kElo_TouchSystems_2700; } // namspace ui diff --git a/ui/events/ozone/evdev/touch_event_converter_evdev.cc b/ui/events/ozone/evdev/touch_event_converter_evdev.cc index 2427f89..a5e9c19 100644 --- a/ui/events/ozone/evdev/touch_event_converter_evdev.cc +++ b/ui/events/ozone/evdev/touch_event_converter_evdev.cc @@ -137,6 +137,9 @@ void TouchEventConverterEvdev::Initialize(const EventDeviceInfo& info) { current_slot_ = 0; } + quirk_left_mouse_button_ = + !has_mt_ && !info.HasKeyEvent(BTN_TOUCH) && info.HasKeyEvent(BTN_LEFT); + // Apply --touch-calibration. if (type() == INPUT_DEVICE_INTERNAL) { TouchCalibration cal = {}; @@ -178,6 +181,7 @@ void TouchEventConverterEvdev::Initialize(const EventDeviceInfo& info) { } } else { // TODO(spang): Add key state to EventDeviceInfo to allow initial contact. + // (and make sure to take into account quirk_left_mouse_button_) events_[0].x = 0; events_[0].y = 0; events_[0].tracking_id = kTrackingIdForUnusedSlot; @@ -259,6 +263,8 @@ void TouchEventConverterEvdev::ProcessMultitouchEvent( } } else if (input.type == EV_KEY) { ProcessKey(input); + } else if (input.type == EV_MSC) { + // Ignored. } else { NOTIMPLEMENTED() << "invalid type: " << input.type; } @@ -272,18 +278,22 @@ void TouchEventConverterEvdev::EmulateMultitouchEvent( emulated_event.code = AbsCodeToMtCode(event.code); if (emulated_event.code >= 0) ProcessMultitouchEvent(emulated_event); - } else if (event.type == EV_KEY && event.code == BTN_TOUCH) { - emulated_event.type = EV_ABS; - emulated_event.code = ABS_MT_TRACKING_ID; - emulated_event.value = - event.value ? NextTrackingId() : kTrackingIdForUnusedSlot; - ProcessMultitouchEvent(emulated_event); + } else if (event.type == EV_KEY) { + if (event.code == BTN_TOUCH || + (quirk_left_mouse_button_ && event.code == BTN_LEFT)) { + emulated_event.type = EV_ABS; + emulated_event.code = ABS_MT_TRACKING_ID; + emulated_event.value = + event.value ? NextTrackingId() : kTrackingIdForUnusedSlot; + ProcessMultitouchEvent(emulated_event); + } } } void TouchEventConverterEvdev::ProcessKey(const input_event& input) { switch (input.code) { case BTN_TOUCH: + case BTN_LEFT: break; default: NOTIMPLEMENTED() << "invalid code for EV_KEY: " << input.code; diff --git a/ui/events/ozone/evdev/touch_event_converter_evdev.h b/ui/events/ozone/evdev/touch_event_converter_evdev.h index 7cd7576..edddea6 100644 --- a/ui/events/ozone/evdev/touch_event_converter_evdev.h +++ b/ui/events/ozone/evdev/touch_event_converter_evdev.h @@ -83,6 +83,9 @@ class EVENTS_OZONE_EVDEV_EXPORT TouchEventConverterEvdev // Device has multitouch capability. bool has_mt_; + // Use BTN_LEFT instead of BT_TOUCH. + bool quirk_left_mouse_button_ = false; + // Pressure values. int pressure_min_; int pressure_max_; // Used to normalize pressure values. diff --git a/ui/events/ozone/evdev/touch_event_converter_evdev_unittest.cc b/ui/events/ozone/evdev/touch_event_converter_evdev_unittest.cc index 77eeef6..96a1f32 100644 --- a/ui/events/ozone/evdev/touch_event_converter_evdev_unittest.cc +++ b/ui/events/ozone/evdev/touch_event_converter_evdev_unittest.cc @@ -47,6 +47,12 @@ void InitPixelTouchscreen(TouchEventConverterEvdev* device) { device->Initialize(devinfo); } +void InitEloTouchscreen(TouchEventConverterEvdev* device) { + EventDeviceInfo devinfo; + EXPECT_TRUE(CapabilitiesToDeviceInfo(kElo_TouchSystems_2700, &devinfo)); + device->Initialize(devinfo); +} + } // namespace class MockTouchEventConverterEvdev : public TouchEventConverterEvdev { @@ -541,6 +547,92 @@ TEST_F(TouchEventConverterEvdevTest, ShouldReleaseContactsOnStop) { EXPECT_EQ(0, ev2.slot); } +// crbug.com/477695 +TEST_F(TouchEventConverterEvdevTest, ShouldUseLeftButtonIfNoTouchButton) { + ui::MockTouchEventConverterEvdev* dev = device(); + + InitEloTouchscreen(dev); + + // Captured from Elo TouchSystems 2700. + timeval time; + time = {1433965490, 837958}; + struct input_event mock_kernel_queue_press[] = { + {time, EV_ABS, ABS_X, 3654}, + {time, EV_ABS, ABS_Y, 1054}, + {time, EV_ABS, ABS_MISC, 18}, + {time, EV_SYN, SYN_REPORT, 0}, + + {time, EV_MSC, MSC_SCAN, 90001}, + {time, EV_KEY, BTN_LEFT, 1}, + {time, EV_ABS, ABS_Y, 1055}, + {time, EV_ABS, ABS_MISC, 25}, + {time, EV_SYN, SYN_REPORT, 0}, + }; + time = {1433965491, 1953}; + struct input_event mock_kernel_queue_move[] = { + {time, EV_ABS, ABS_X, 3644}, + {time, EV_ABS, ABS_Y, 1059}, + {time, EV_ABS, ABS_MISC, 36}, + {time, EV_SYN, SYN_REPORT, 0}, + }; + time = {1433965491, 225959}; + struct input_event mock_kernel_queue_release[] = { + {time, EV_MSC, MSC_SCAN, 90001}, + {time, EV_KEY, BTN_LEFT, 0}, + {time, EV_ABS, ABS_MISC, 0}, + {time, EV_SYN, SYN_REPORT, 0}, + }; + + // Press. + dev->ConfigureReadMock(mock_kernel_queue_press, + arraysize(mock_kernel_queue_press), 0); + dev->ReadNow(); + EXPECT_EQ(1u, size()); + ui::TouchEventParams event = dispatched_event(0); + EXPECT_EQ(ui::ET_TOUCH_PRESSED, event.type); + EXPECT_EQ(base::TimeDelta::FromMicroseconds(1433965490837958), + event.timestamp); + EXPECT_EQ(3654, event.location.x()); + EXPECT_EQ(1055, event.location.y()); + EXPECT_EQ(0, event.slot); + EXPECT_FLOAT_EQ(0.f, event.radii.x()); + EXPECT_FLOAT_EQ(0.f, event.pressure); + + // Move. + dev->ConfigureReadMock(mock_kernel_queue_move, + arraysize(mock_kernel_queue_move), 0); + dev->ReadNow(); + EXPECT_EQ(2u, size()); + event = dispatched_event(1); + EXPECT_EQ(ui::ET_TOUCH_MOVED, event.type); + EXPECT_EQ(base::TimeDelta::FromMicroseconds(1433965491001953), + event.timestamp); + EXPECT_EQ(3644, event.location.x()); + EXPECT_EQ(1059, event.location.y()); + EXPECT_EQ(0, event.slot); + EXPECT_FLOAT_EQ(0.f, event.radii.x()); + EXPECT_FLOAT_EQ(0.f, event.pressure); + + // Release. + dev->ConfigureReadMock(mock_kernel_queue_release, + arraysize(mock_kernel_queue_release), 0); + dev->ReadNow(); + EXPECT_EQ(3u, size()); + event = dispatched_event(2); + EXPECT_EQ(ui::ET_TOUCH_RELEASED, event.type); + EXPECT_EQ(base::TimeDelta::FromMicroseconds(1433965491225959), + event.timestamp); + EXPECT_EQ(3644, event.location.x()); + EXPECT_EQ(1059, event.location.y()); + EXPECT_EQ(0, event.slot); + EXPECT_FLOAT_EQ(0.f, event.radii.x()); + EXPECT_FLOAT_EQ(0.f, event.pressure); + + // No dispatch on destruction. + DestroyDevice(); + EXPECT_EQ(3u, size()); +} + // crbug.com/407386 TEST_F(TouchEventConverterEvdevTest, DontChangeMultitouchPositionFromLegacyAxes) { -- cgit v1.1