1cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved. 2cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 3cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// found in the LICENSE file. 4cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 51320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "ui/events/x/hotplug_event_handler_x11.h" 6cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 7cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include <X11/extensions/XInput.h> 8cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include <X11/extensions/XInput2.h> 9cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 10cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include <cmath> 11cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include <set> 12116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include <string> 13116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include <vector> 14116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 15116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "base/command_line.h" 16116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "base/files/file_enumerator.h" 17116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "base/logging.h" 18116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "base/process/launch.h" 19116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "base/strings/string_util.h" 20116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "base/sys_info.h" 211320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "ui/events/device_hotplug_event_observer.h" 221320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "ui/events/touchscreen_device.h" 23cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "ui/gfx/x/x11_types.h" 24cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 251320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccinamespace ui { 261320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 27116680a4aac90f2aa7413d9095a592090648e557Ben Murdochnamespace { 28116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 29116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch// We consider the touchscreen to be internal if it is an I2c device. 30116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch// With the device id, we can query X to get the device's dev input 31116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch// node eventXXX. Then we search all the dev input nodes registered 32116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch// by I2C devices to see if we can find eventXXX. 33116680a4aac90f2aa7413d9095a592090648e557Ben Murdochbool IsTouchscreenInternal(XDisplay* dpy, int device_id) { 34116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch using base::FileEnumerator; 35116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch using base::FilePath; 36116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 371320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#if !defined(CHROMEOS) 381320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return false; 391320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#else 40116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if (!base::SysInfo::IsRunningOnChromeOS()) 41116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return false; 421320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#endif 43116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 44116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch // Input device has a property "Device Node" pointing to its dev input node, 45116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch // e.g. Device Node (250): "/dev/input/event8" 46116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch Atom device_node = XInternAtom(dpy, "Device Node", False); 47116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if (device_node == None) 48116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return false; 49116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 50116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch Atom actual_type; 51116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch int actual_format; 52116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch unsigned long nitems, bytes_after; 53116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch unsigned char* data; 54116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch XDevice* dev = XOpenDevice(dpy, device_id); 55116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if (!dev) 56116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return false; 57116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 581320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (XGetDeviceProperty(dpy, 591320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci dev, 601320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci device_node, 611320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 0, 621320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 1000, 631320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci False, 641320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci AnyPropertyType, 651320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci &actual_type, 661320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci &actual_format, 671320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci &nitems, 681320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci &bytes_after, 691320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci &data) != Success) { 70116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch XCloseDevice(dpy, dev); 71116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return false; 72116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch } 73116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch base::FilePath dev_node_path(reinterpret_cast<char*>(data)); 74116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch XFree(data); 75116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch XCloseDevice(dpy, dev); 76116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 77116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch std::string event_node = dev_node_path.BaseName().value(); 781320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (event_node.empty() || !StartsWithASCII(event_node, "event", false)) 79116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return false; 80116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 81116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch // Extract id "XXX" from "eventXXX" 82116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch std::string event_node_id = event_node.substr(5); 83116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 84116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch // I2C input device registers its dev input node at 85116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch // /sys/bus/i2c/devices/*/input/inputXXX/eventXXX 86116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch FileEnumerator i2c_enum(FilePath(FILE_PATH_LITERAL("/sys/bus/i2c/devices/")), 87116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch false, 88116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch base::FileEnumerator::DIRECTORIES); 891320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci for (FilePath i2c_name = i2c_enum.Next(); !i2c_name.empty(); 90116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch i2c_name = i2c_enum.Next()) { 91116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch FileEnumerator input_enum(i2c_name.Append(FILE_PATH_LITERAL("input")), 92116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch false, 93116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch base::FileEnumerator::DIRECTORIES, 94116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch FILE_PATH_LITERAL("input*")); 951320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci for (base::FilePath input = input_enum.Next(); !input.empty(); 96116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch input = input_enum.Next()) { 97116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if (input.BaseName().value().substr(5) == event_node_id) 98116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return true; 99116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch } 100116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch } 101116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 102116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return false; 103116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch} 104116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 105116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch} // namespace 106116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 1071320f92c476a1ad9d19dba2a48c72b75566198e9Primiano TucciHotplugEventHandlerX11::HotplugEventHandlerX11( 1081320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci DeviceHotplugEventObserver* delegate) 1091320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci : delegate_(delegate) { 1101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci} 111cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 1121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano TucciHotplugEventHandlerX11::~HotplugEventHandlerX11() { 1131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci} 114cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 1151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid HotplugEventHandlerX11::OnHotplugEvent() { 1161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci const XIDeviceList& device_list = 1171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci DeviceListCacheX::GetInstance()->GetXI2DeviceList(gfx::GetXDisplay()); 1181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci HandleTouchscreenDevices(device_list); 1191320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci} 120cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 1211320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid HotplugEventHandlerX11::HandleTouchscreenDevices( 1221320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci const XIDeviceList& x11_devices) { 123cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) std::vector<TouchscreenDevice> devices; 1241320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci Display* display = gfx::GetXDisplay(); 1251320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci Atom valuator_x = XInternAtom(display, "Abs MT Position X", False); 1261320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci Atom valuator_y = XInternAtom(display, "Abs MT Position Y", False); 127cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (valuator_x == None || valuator_y == None) 1281320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return; 129cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 130cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) std::set<int> no_match_touchscreen; 1311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci for (int i = 0; i < x11_devices.count; i++) { 1321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (!x11_devices[i].enabled || x11_devices[i].use != XIFloatingSlave) 133cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) continue; // Assume all touchscreens are floating slaves 134cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 135cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) double width = -1.0; 136cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) double height = -1.0; 137cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) bool is_direct_touch = false; 138cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 1391320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci for (int j = 0; j < x11_devices[i].num_classes; j++) { 1401320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci XIAnyClassInfo* class_info = x11_devices[i].classes[j]; 141cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 142cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (class_info->type == XIValuatorClass) { 143cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) XIValuatorClassInfo* valuator_info = 144cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) reinterpret_cast<XIValuatorClassInfo*>(class_info); 145cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 146cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (valuator_x == valuator_info->label) { 147cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // Ignore X axis valuator with unexpected properties 148cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (valuator_info->number == 0 && valuator_info->mode == Absolute && 149cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) valuator_info->min == 0.0) { 150cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) width = valuator_info->max; 151cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 152cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } else if (valuator_y == valuator_info->label) { 153cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // Ignore Y axis valuator with unexpected properties 154cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (valuator_info->number == 1 && valuator_info->mode == Absolute && 155cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) valuator_info->min == 0.0) { 156cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) height = valuator_info->max; 157cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 158cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 159cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 160cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#if defined(USE_XI2_MT) 161cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (class_info->type == XITouchClass) { 162cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) XITouchClassInfo* touch_info = 163cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) reinterpret_cast<XITouchClassInfo*>(class_info); 164cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) is_direct_touch = touch_info->mode == XIDirectTouch; 165cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 166cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#endif 167cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 168cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 169cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // Touchscreens should have absolute X and Y axes, and be direct touch 170cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // devices. 171cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (width > 0.0 && height > 0.0 && is_direct_touch) { 1721320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci bool is_internal = 1731320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci IsTouchscreenInternal(display, x11_devices[i].deviceid); 1741320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci devices.push_back(TouchscreenDevice( 1751320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci x11_devices[i].deviceid, gfx::Size(width, height), is_internal)); 176cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 177cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 178cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 1791320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci delegate_->OnTouchscreenDevicesUpdated(devices); 180cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)} 181cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 182cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)} // namespace ui 183