15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/browser/gamepad/gamepad_platform_data_fetcher_linux.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <fcntl.h> 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <libudev.h> 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <linux/joystick.h> 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <string.h> 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <sys/stat.h> 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <sys/types.h> 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <unistd.h> 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/debug/trace_event.h" 169ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch#include "base/message_loop/message_loop.h" 172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/posix/eintr_wrapper.h" 18868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/string_number_conversions.h" 19868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/string_util.h" 20868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/stringprintf.h" 21868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h" 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/browser/udev_linux.h" 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace { 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kInputSubsystem[] = "input"; 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kUsbSubsystem[] = "usb"; 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kUsbDeviceType[] = "usb_device"; 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const float kMaxLinuxAxisValue = 32767.0; 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CloseFileDescriptorIfValid(int fd) { 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (fd >= 0) 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) close(fd); 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool IsGamepad(udev_device* dev, int* index, std::string* path) { 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!udev_device_get_property_value(dev, "ID_INPUT_JOYSTICK")) 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char* node_path = udev_device_get_devnode(dev); 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!node_path) 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static const char kJoystickRoot[] = "/dev/input/js"; 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool is_gamepad = StartsWithASCII(node_path, kJoystickRoot, true); 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!is_gamepad) 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int tmp_idx = -1; 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int base_len = sizeof(kJoystickRoot) - 1; 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::StringPiece str(&node_path[base_len], strlen(node_path) - base_len); 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!base::StringToInt(str, &tmp_idx)) 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (tmp_idx < 0 || 55f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) tmp_idx >= static_cast<int>(blink::WebGamepads::itemsLengthCap)) { 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *index = tmp_idx; 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *path = node_path; 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace content { 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 67f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)using blink::WebGamepad; 68f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)using blink::WebGamepads; 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)GamepadPlatformDataFetcherLinux::GamepadPlatformDataFetcherLinux() { 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (size_t i = 0; i < arraysize(device_fds_); ++i) 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) device_fds_[i] = -1; 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) memset(mappers_, 0, sizeof(mappers_)); 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::vector<UdevLinux::UdevMonitorFilter> filters; 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) filters.push_back(UdevLinux::UdevMonitorFilter(kInputSubsystem, NULL)); 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) udev_.reset( 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) new UdevLinux(filters, 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Bind(&GamepadPlatformDataFetcherLinux::RefreshDevice, 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Unretained(this)))); 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EnumerateDevices(); 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)GamepadPlatformDataFetcherLinux::~GamepadPlatformDataFetcherLinux() { 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (size_t i = 0; i < WebGamepads::itemsLengthCap; ++i) 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CloseFileDescriptorIfValid(device_fds_[i]); 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void GamepadPlatformDataFetcherLinux::GetGamepadData(WebGamepads* pads, bool) { 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TRACE_EVENT0("GAMEPAD", "GetGamepadData"); 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) data_.length = WebGamepads::itemsLengthCap; 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Update our internal state. 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (size_t i = 0; i < WebGamepads::itemsLengthCap; ++i) { 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (device_fds_[i] >= 0) { 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ReadDeviceData(i); 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Copy to the current state to the output buffer, using the mapping 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // function, if there is one available. 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pads->length = data_.length; 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (size_t i = 0; i < WebGamepads::itemsLengthCap; ++i) { 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (mappers_[i]) 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mappers_[i](data_.items[i], &pads->items[i]); 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pads->items[i] = data_.items[i]; 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Used during enumeration, and monitor notifications. 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void GamepadPlatformDataFetcherLinux::RefreshDevice(udev_device* dev) { 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int index; 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string node_path; 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (IsGamepad(dev, &index, &node_path)) { 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int& device_fd = device_fds_[index]; 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) WebGamepad& pad = data_.items[index]; 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GamepadStandardMappingFunction& mapper = mappers_[index]; 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CloseFileDescriptorIfValid(device_fd); 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The device pointed to by dev contains information about the logical 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // joystick device. In order to get the information about the physical 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // hardware, get the parent device that is also in the "input" subsystem. 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This function should just walk up the tree one level. 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dev = udev_device_get_parent_with_subsystem_devtype( 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dev, 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kInputSubsystem, 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NULL); 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!dev) { 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Unable to get device information, don't use this device. 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) device_fd = -1; 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pad.connected = false; 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) device_fd = HANDLE_EINTR(open(node_path.c_str(), O_RDONLY | O_NONBLOCK)); 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (device_fd < 0) { 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Unable to open device, don't use. 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pad.connected = false; 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char* vendor_id = udev_device_get_sysattr_value(dev, "id/vendor"); 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char* product_id = udev_device_get_sysattr_value(dev, "id/product"); 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mapper = GetGamepadStandardMappingFunction(vendor_id, product_id); 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Driver returns utf-8 strings here, so combine in utf-8 first and 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // convert to WebUChar later once we've picked an id string. 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char* name = udev_device_get_sysattr_value(dev, "name"); 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string name_string = base::StringPrintf("%s", name); 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // In many cases the information the input subsystem contains isn't 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // as good as the information that the device bus has, walk up further 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // to the subsystem/device type "usb"/"usb_device" and if this device 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // has the same vendor/product id, prefer the description from that. 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct udev_device *usb_dev = udev_device_get_parent_with_subsystem_devtype( 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dev, 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kUsbSubsystem, 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kUsbDeviceType); 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (usb_dev) { 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char* usb_vendor_id = 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) udev_device_get_sysattr_value(usb_dev, "idVendor"); 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char* usb_product_id = 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) udev_device_get_sysattr_value(usb_dev, "idProduct"); 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (strcmp(vendor_id, usb_vendor_id) == 0 && 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) strcmp(product_id, usb_product_id) == 0) { 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char* manufacturer = 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) udev_device_get_sysattr_value(usb_dev, "manufacturer"); 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char* product = udev_device_get_sysattr_value(usb_dev, "product"); 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Replace the previous name string with one containing the better 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // information, again driver returns utf-8 strings here so combine 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // in utf-8 for conversion to WebUChar below. 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) name_string = base::StringPrintf("%s %s", manufacturer, product); 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Append the vendor and product information then convert the utf-8 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // id string to WebUChar. 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string id = name_string + base::StringPrintf( 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) " (%sVendor: %s Product: %s)", 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mapper ? "STANDARD GAMEPAD " : "", 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) vendor_id, 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) product_id); 189a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) base::TruncateUTF8ToByteSize(id, WebGamepad::idLengthCap - 1, &id); 1905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::string16 tmp16 = base::UTF8ToUTF16(id); 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) memset(pad.id, 0, sizeof(pad.id)); 1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tmp16.copy(pad.id, arraysize(pad.id) - 1); 1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 194a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (mapper) { 195a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) std::string mapping = "standard"; 196a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) base::TruncateUTF8ToByteSize(mapping, WebGamepad::mappingLengthCap - 1, 197a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) &mapping); 198a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) tmp16 = base::UTF8ToUTF16(mapping); 199a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) memset(pad.mapping, 0, sizeof(pad.mapping)); 200a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) tmp16.copy(pad.mapping, arraysize(pad.mapping) - 1); 201a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } else { 202a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) pad.mapping[0] = 0; 203a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 204a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pad.connected = true; 2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void GamepadPlatformDataFetcherLinux::EnumerateDevices() { 2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) udev_enumerate* enumerate = udev_enumerate_new(udev_->udev_handle()); 2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!enumerate) 2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int ret = udev_enumerate_add_match_subsystem(enumerate, kInputSubsystem); 2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (ret != 0) 2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ret = udev_enumerate_scan_devices(enumerate); 2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (ret != 0) 2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) udev_list_entry* devices = udev_enumerate_get_list_entry(enumerate); 2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (udev_list_entry* dev_list_entry = devices; 2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dev_list_entry != NULL; 2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dev_list_entry = udev_list_entry_get_next(dev_list_entry)) { 2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Get the filename of the /sys entry for the device and create a 2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // udev_device object (dev) representing it 2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char* path = udev_list_entry_get_name(dev_list_entry); 2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) udev_device* dev = udev_device_new_from_syspath(udev_->udev_handle(), path); 2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!dev) 2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) continue; 2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RefreshDevice(dev); 2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) udev_device_unref(dev); 2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Free the enumerator object 2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) udev_enumerate_unref(enumerate); 2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void GamepadPlatformDataFetcherLinux::ReadDeviceData(size_t index) { 2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Linker does not like CHECK_LT(index, WebGamepads::itemsLengthCap). =/ 2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (index >= WebGamepads::itemsLengthCap) { 2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHECK(false); 2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int& fd = device_fds_[index]; 2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) WebGamepad& pad = data_.items[index]; 2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_GE(fd, 0); 2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) js_event event; 2492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) while (HANDLE_EINTR(read(fd, &event, sizeof(struct js_event))) > 0) { 2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t item = event.number; 2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (event.type & JS_EVENT_AXIS) { 2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (item >= WebGamepad::axesLengthCap) 2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) continue; 2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pad.axes[item] = event.value / kMaxLinuxAxisValue; 2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (item >= pad.axesLength) 2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pad.axesLength = item + 1; 2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (event.type & JS_EVENT_BUTTON) { 2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (item >= WebGamepad::buttonsLengthCap) 2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) continue; 260a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) pad.buttons[item].pressed = event.value; 261a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) pad.buttons[item].value = event.value ? 1.0 : 0.0; 2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (item >= pad.buttonsLength) 2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pad.buttonsLength = item + 1; 2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pad.timestamp = event.time; 2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace content 270