diff --git a/src/SFML/Window/FreeBSD/JoystickImpl.cpp b/src/SFML/Window/FreeBSD/JoystickImpl.cpp index f6638d47..4255b5b8 100644 --- a/src/SFML/Window/FreeBSD/JoystickImpl.cpp +++ b/src/SFML/Window/FreeBSD/JoystickImpl.cpp @@ -28,16 +28,10 @@ //////////////////////////////////////////////////////////// #include #include - #include - #include -#include #include #include - -#include -#include #include #include #include @@ -57,123 +51,107 @@ namespace { std::map plugged; - std::map > hatmap; + std::map > hatValueMap; bool isJoystick(const char *name) { - int fd, id; - bool ret; - report_desc_t desc = NULL; - hid_data_t data = NULL; + int file = ::open(name, O_RDONLY | O_NONBLOCK); + + if (file < 0) + return false; + + report_desc_t desc = hid_get_report_desc(file); + + if (!desc) + { + ::close(file); + return false; + } + + int id = hid_get_report_id(file); + hid_data_t data = hid_start_parse(desc, 1 << hid_input, id); + + if (!data) + { + hid_dispose_report_desc(desc); + ::close(file); + return false; + } + hid_item_t item; // Assume it isn't - ret = false; + bool result = false; - if ((fd = ::open(name, O_RDONLY | O_NONBLOCK)) < 0) - return false; - - if ((desc = hid_get_report_desc(fd)) == NULL) - goto end; - - id = hid_get_report_id(fd); - if ((data = hid_start_parse(desc, 1 << hid_input, id)) == NULL) - goto end; - - while (hid_get_item(data, &item) > 0) { - switch (item.kind) { - case hid_collection: - switch (HID_PAGE(item.usage)) { - case HUP_GENERIC_DESKTOP: - switch (HID_USAGE(item.usage)) { - case HUG_JOYSTICK: - case HUG_GAME_PAD: - ret = true; - break; - default: - break; - } - default: - break; + while (hid_get_item(data, &item) > 0) + { + if ((item.kind == hid_collection) && (HID_PAGE(item.usage) == HUP_GENERIC_DESKTOP)) + { + if ((HID_USAGE(item.usage) == HUG_JOYSTICK) || (HID_USAGE(item.usage) == HUG_GAME_PAD)) + { + result = true; } - default: - break; } } -end: - if (desc != NULL) - hid_dispose_report_desc(desc); - if (data != NULL) - hid_end_parse(data); - close(fd); + hid_end_parse(data); + hid_dispose_report_desc(desc); + ::close(file); - return ret; + return result; } void updatePluggedList() { - DIR *dp; - struct dirent *entry; - /* * Devices /dev/uhid are shared between joystick and any other * human interface device. We need to iterate over all found devices * and check if they are joysticks. The index of JoystickImpl::open * does not match the /dev/uhid device! */ - if ((dp = opendir("/dev")) != NULL) { - char name[FILENAME_MAX]; - int jc = 0; + DIR* directory = opendir("/dev"); - while ((entry = readdir(dp)) != NULL && jc < sf::Joystick::Count) { - if (strncmp(entry->d_name, "uhid", 4) == 0) { - std::sprintf(name, "/dev/%s", entry->d_name); + if (directory) + { + int joystickCount = 0; + struct dirent* directoryEntry = readdir(directory); - if (isJoystick(name)) - plugged[jc++] = std::string(name); + while (directoryEntry && joystickCount < sf::Joystick::Count) + { + if (!std::strncmp(directoryEntry->d_name, "uhid", 4)) + { + std::string name("/dev/"); + name += directoryEntry->d_name; + + if (isJoystick(name.c_str())) + plugged[joystickCount++] = name; } + + directoryEntry = readdir(directory); } - closedir(dp); + closedir(directory); } } int usageToAxis(int usage) { - int axis; - - switch (usage) { - case HUG_X: - axis = sf::Joystick::X; - break; - case HUG_Y: - axis = sf::Joystick::Y; - break; - case HUG_Z: - axis = sf::Joystick::Z; - break; - case HUG_RZ: - axis = sf::Joystick::R; - break; - case HUG_RX: - axis = sf::Joystick::U; - break; - case HUG_RY: - axis = sf::Joystick::V; - break; - default: - axis = -1; - break; + switch (usage) + { + case HUG_X: return sf::Joystick::X; + case HUG_Y: return sf::Joystick::Y; + case HUG_Z: return sf::Joystick::Z; + case HUG_RZ: return sf::Joystick::R; + case HUG_RX: return sf::Joystick::U; + case HUG_RY: return sf::Joystick::V; + default: return -1; } - - return axis; } - void hatvalToSFML(int value, sf::priv::JoystickState &state) + void hatValueToSfml(int value, sf::priv::JoystickState& state) { - state.axes[sf::Joystick::PovX] = hatmap[value].first; - state.axes[sf::Joystick::PovY] = hatmap[value].second; + state.axes[sf::Joystick::PovX] = hatValueMap[value].first; + state.axes[sf::Joystick::PovY] = hatValueMap[value].second; } } @@ -191,17 +169,17 @@ void JoystickImpl::initialize() updatePluggedList(); // Map of hat values - hatmap[0] = std::make_pair(0, 0); // center + hatValueMap[0] = std::make_pair( 0, 0); // center - hatmap[1] = std::make_pair(0, -100); // top - hatmap[3] = std::make_pair(100, 0); // right - hatmap[5] = std::make_pair(0, 100); // bottom - hatmap[7] = std::make_pair(-100, 0); // left + hatValueMap[1] = std::make_pair( 0, -100); // top + hatValueMap[3] = std::make_pair( 100, 0); // right + hatValueMap[5] = std::make_pair( 0, 100); // bottom + hatValueMap[7] = std::make_pair(-100, 0); // left - hatmap[2] = std::make_pair(100, -100); // top-right - hatmap[4] = std::make_pair(100, 100); // bottom-right - hatmap[6] = std::make_pair(-100, 100); // bottom-left - hatmap[8] = std::make_pair(-100, -100); // top-left + hatValueMap[2] = std::make_pair( 100, -100); // top-right + hatValueMap[4] = std::make_pair( 100, 100); // bottom-right + hatValueMap[6] = std::make_pair(-100, 100); // bottom-left + hatValueMap[8] = std::make_pair(-100, -100); // top-left } @@ -232,7 +210,8 @@ bool JoystickImpl::open(unsigned int index) // Get the report descriptor m_desc = hid_get_report_desc(m_file); - if (m_desc == NULL) { + if (!m_desc) + { ::close(m_file); return false; } @@ -242,26 +221,15 @@ bool JoystickImpl::open(unsigned int index) // Then allocate a buffer for data retrievement m_length = hid_report_size(m_desc, hid_input, m_id); - m_buffer = std::calloc(1, m_length); + m_buffer.resize(m_length); - if (m_buffer == NULL) { - ::close(m_file); - ::hid_dispose_report_desc(m_desc); + m_state.connected = true; - return false; - } - - return m_state.connected = true; - } - else - { - return false; + return true; } } - else - { - return false; - } + + return false; } @@ -269,8 +237,7 @@ bool JoystickImpl::open(unsigned int index) void JoystickImpl::close() { ::close(m_file); - ::hid_dispose_report_desc(m_desc); - ::free(m_buffer); + hid_dispose_report_desc(m_desc); } @@ -278,38 +245,35 @@ void JoystickImpl::close() JoystickCaps JoystickImpl::getCapabilities() const { JoystickCaps caps; - hid_data_t data; hid_item_t item; - data = hid_start_parse(m_desc, 1 << hid_input, m_id); + hid_data_t data = hid_start_parse(m_desc, 1 << hid_input, m_id); - while (hid_get_item(data, &item)) { - switch (item.kind) { - case hid_input: - switch (HID_PAGE(item.usage)) { - case HUP_BUTTON: - caps.buttonCount ++; - break; - case HUP_GENERIC_DESKTOP: - { - int usage = HID_USAGE(item.usage); - int axis; + while (hid_get_item(data, &item)) + { + if (item.kind == hid_input) + { + int usage = HID_USAGE(item.usage); - if (usage == HUG_HAT_SWITCH) { - caps.axes[Joystick::PovX] = true; - caps.axes[Joystick::PovY] = true; - } - else if ((axis = usageToAxis(usage)) != -1) - { - caps.axes[axis] = true; - } - break; - } - default: - break; + if (usage == HUP_BUTTON) + { + caps.buttonCount++; + break; + } + else if (usage == HUP_GENERIC_DESKTOP) + { + int axis = usageToAxis(usage); + + if (usage == HUG_HAT_SWITCH) + { + caps.axes[Joystick::PovX] = true; + caps.axes[Joystick::PovY] = true; + } + else if (axis != -1) + { + caps.axes[axis] = true; + } } - default: - break; } } @@ -329,48 +293,45 @@ Joystick::Identification JoystickImpl::getIdentification() const //////////////////////////////////////////////////////////// JoystickState JoystickImpl::JoystickImpl::update() { - while (read(m_file, m_buffer, m_length) == m_length) { - hid_data_t data; - hid_item_t item; - - data = hid_start_parse(m_desc, 1 << hid_input, m_id); + while (read(m_file, &m_buffer[0], m_length) == m_length) + { + hid_data_t data = hid_start_parse(m_desc, 1 << hid_input, m_id); // No memory? - if (data == NULL) + if (!data) continue; - int but = 0; - while (hid_get_item(data, &item)) { - switch (item.kind) { - case hid_input: - switch (HID_PAGE(item.usage)) { - case HUP_BUTTON: - m_state.buttons[but++] = hid_get_data(m_buffer, &item); - break; - case HUP_GENERIC_DESKTOP: - { - int usage = HID_USAGE(item.usage); - int v = hid_get_data(m_buffer, &item); - int axis; + int buttonIndex = 0; + hid_item_t item; - if (usage == HUG_HAT_SWITCH) - hatvalToSFML(v, m_state); - else if ((axis = usageToAxis(usage)) != -1) - { - int &min = item.logical_minimum; - int &max = item.logical_maximum; + while (hid_get_item(data, &item)) + { + if (item.kind == hid_input) + { + int usage = HID_USAGE(item.usage); - v = (v - min) * (200) / (max - min) -100; - m_state.axes[axis] = v; - } - - break; - } - default: - break; + if (usage == HUP_BUTTON) + { + m_state.buttons[buttonIndex++] = hid_get_data(&m_buffer[0], &item); + } + else if (usage == HUP_GENERIC_DESKTOP) + { + int value = hid_get_data(&m_buffer[0], &item); + int axis = usageToAxis(usage); + + if (usage == HUG_HAT_SWITCH) + { + hatValueToSfml(value, m_state); + } + else if (axis != -1) + { + int minimum = item.logical_minimum; + int maximum = item.logical_maximum; + + value = (value - minimum) * 200 / (maximum - minimum) - 100; + m_state.axes[axis] = value; + } } - default: - break; } } @@ -383,5 +344,3 @@ JoystickState JoystickImpl::JoystickImpl::update() } // namespace priv } // namespace sf - -// vim: set expandtab tabstop=4 softtabstop=4 shiftwidth=4: diff --git a/src/SFML/Window/FreeBSD/JoystickImpl.hpp b/src/SFML/Window/FreeBSD/JoystickImpl.hpp index e00f1610..19ae180e 100644 --- a/src/SFML/Window/FreeBSD/JoystickImpl.hpp +++ b/src/SFML/Window/FreeBSD/JoystickImpl.hpp @@ -28,9 +28,9 @@ //////////////////////////////////////////////////////////// // Headers //////////////////////////////////////////////////////////// - #include #include +#include namespace sf { @@ -112,16 +112,13 @@ private : //////////////////////////////////////////////////////////// // Member data //////////////////////////////////////////////////////////// - int m_file; ///< File descriptor of the joystick - - report_desc_t m_desc; ///< USB report descriptor - int m_id; ///< USB id - - void *m_buffer; ///< USB HID buffer - int m_length; ///< Buffer length + int m_file; ///< File descriptor of the joystick + report_desc_t m_desc; ///< USB report descriptor + int m_id; ///< USB id + std::vector m_buffer; ///< USB HID buffer + int m_length; ///< Buffer length Joystick::Identification m_identification; ///< Joystick identification - - JoystickState m_state; ///< Current state of the joystick + JoystickState m_state; ///< Current state of the joystick }; } // namespace priv diff --git a/src/SFML/Window/JoystickManager.cpp b/src/SFML/Window/JoystickManager.cpp index 92bfa004..1f3b9ec0 100644 --- a/src/SFML/Window/JoystickManager.cpp +++ b/src/SFML/Window/JoystickManager.cpp @@ -77,8 +77,8 @@ void JoystickManager::update() if (!item.state.connected) { item.joystick.close(); - item.capabilities = JoystickCaps(); - item.state = JoystickState(); + item.capabilities = JoystickCaps(); + item.state = JoystickState(); item.identification = Joystick::Identification(); } } @@ -89,8 +89,8 @@ void JoystickManager::update() { if (item.joystick.open(i)) { - item.capabilities = item.joystick.getCapabilities(); - item.state = item.joystick.update(); + item.capabilities = item.joystick.getCapabilities(); + item.state = item.joystick.update(); item.identification = item.joystick.getIdentification(); } } diff --git a/src/SFML/Window/JoystickManager.hpp b/src/SFML/Window/JoystickManager.hpp index 2bb7cc2e..22f2d9f7 100644 --- a/src/SFML/Window/JoystickManager.hpp +++ b/src/SFML/Window/JoystickManager.hpp @@ -109,9 +109,9 @@ private: //////////////////////////////////////////////////////////// struct Item { - JoystickImpl joystick; ///< Joystick implementation - JoystickState state; ///< The current joystick state - JoystickCaps capabilities; ///< The joystick capabilities + JoystickImpl joystick; ///< Joystick implementation + JoystickState state; ///< The current joystick state + JoystickCaps capabilities; ///< The joystick capabilities Joystick::Identification identification; ///< The joystick identification }; diff --git a/src/SFML/Window/OSX/JoystickImpl.cpp b/src/SFML/Window/OSX/JoystickImpl.cpp index e0f3576b..8a34fe19 100644 --- a/src/SFML/Window/OSX/JoystickImpl.cpp +++ b/src/SFML/Window/OSX/JoystickImpl.cpp @@ -38,6 +38,46 @@ namespace { return IOHIDElementGetUsage(b1) < IOHIDElementGetUsage(b2); } + + // Convert a CFStringRef to std::string + std::string stringFromCFString(CFStringRef cfString) + { + CFIndex length = CFStringGetLength(cfString); + std::vector str(length); + CFIndex maxSize = CFStringGetMaximumSizeForEncoding(length, kCFStringEncodingUTF8); + CFStringGetCString(cfString, &str[0], maxSize, kCFStringEncodingUTF8); + return &str[0]; + } + + // Get HID device property key as a string + std::string getDeviceString(IOHIDDeviceRef ref, CFStringRef prop, unsigned int index) + { + CFTypeRef typeRef = IOHIDDeviceGetProperty(ref, prop); + if (ref && (CFGetTypeID(typeRef) == CFStringGetTypeID())) + { + CFStringRef str = static_cast(typeRef); + return stringFromCFString(str); + } + + sf::err() << "Unable to read string value for property '" << stringFromCFString(prop) << "' for joystick at index " << index << std::endl; + return "Unknown Joystick"; + } + + + // Get HID device property key as an unsigned int + unsigned int getDeviceUint(IOHIDDeviceRef ref, CFStringRef prop, unsigned int index) + { + CFTypeRef typeRef = IOHIDDeviceGetProperty(ref, prop); + if (ref && (CFGetTypeID(typeRef) == CFNumberGetTypeID())) + { + SInt32 value; + CFNumberGetValue((CFNumberRef)typeRef, kCFNumberSInt32Type, &value); + return value; + } + + sf::err() << "Unable to read uint value for property '" << stringFromCFString(prop) << "' for joystick at index " << index << std::endl; + return 0; + } } @@ -176,9 +216,9 @@ bool JoystickImpl::open(unsigned int index) return false; } - m_identification.name = getDeviceString(self, CFSTR(kIOHIDProductKey)); - m_identification.vendorId = getDeviceUint(self, CFSTR(kIOHIDVendorIDKey)); - m_identification.productId = getDeviceUint(self, CFSTR(kIOHIDProductIDKey)); + m_identification.name = getDeviceString(self, CFSTR(kIOHIDProductKey), m_index); + m_identification.vendorId = getDeviceUint(self, CFSTR(kIOHIDVendorIDKey), m_index); + m_identification.productId = getDeviceUint(self, CFSTR(kIOHIDProductIDKey), m_index); // Get a list of all elements attached to the device. CFArrayRef elements = IOHIDDeviceCopyMatchingElements(self, NULL, kIOHIDOptionsTypeNone); @@ -389,48 +429,6 @@ JoystickState JoystickImpl::update() return state; } - -//////////////////////////////////////////////////////////// -std::string JoystickImpl::getDeviceString(IOHIDDeviceRef ref, CFStringRef prop) -{ - CFTypeRef typeRef = IOHIDDeviceGetProperty(ref, prop); - if (ref && (CFGetTypeID(typeRef) == CFStringGetTypeID())) - { - CFStringRef str = static_cast(typeRef); - return stringFromCFString(str); - } - - sf::err() << "Unable to read string value for property '" << stringFromCFString(prop) << "' for joystick at index " << m_index << std::endl; - return "Unknown Joystick"; -} - - -//////////////////////////////////////////////////////////// -unsigned int JoystickImpl::getDeviceUint(IOHIDDeviceRef ref, CFStringRef prop) -{ - CFTypeRef typeRef = IOHIDDeviceGetProperty(ref, prop); - if (ref && (CFGetTypeID(typeRef) == CFNumberGetTypeID())) - { - SInt32 value; - CFNumberGetValue((CFNumberRef)typeRef, kCFNumberSInt32Type, &value); - return value; - } - - sf::err() << "Unable to read uint value for property '" << stringFromCFString(prop) << "' for joystick at index " << m_index << std::endl; - return 0; -} - - -//////////////////////////////////////////////////////////// -std::string JoystickImpl::stringFromCFString(CFStringRef cfString) -{ - CFIndex length = CFStringGetLength(cfString); - std::vector str(length); - CFIndex maxSize = CFStringGetMaximumSizeForEncoding(length, kCFStringEncodingUTF8); - CFStringGetCString(cfString, &str[0], maxSize, kCFStringEncodingUTF8); - return &str[0]; -} - } // namespace priv } // namespace sf diff --git a/src/SFML/Window/OSX/JoystickImpl.hpp b/src/SFML/Window/OSX/JoystickImpl.hpp index e317535a..c8f3d8b9 100644 --- a/src/SFML/Window/OSX/JoystickImpl.hpp +++ b/src/SFML/Window/OSX/JoystickImpl.hpp @@ -113,38 +113,6 @@ public : private : - //////////////////////////////////////////////////////////// - /// Get HID device property key as a string - /// - /// \param ref HID device - /// \param prop Property to retrieve from the device - /// - /// \return Value of the property - /// - //////////////////////////////////////////////////////////// - std::string getDeviceString(IOHIDDeviceRef ref, CFStringRef prop); - - //////////////////////////////////////////////////////////// - /// Get HID device property key as an unsigned int - /// - /// \param ref HID device - /// \param prop Property to retrieve from the device - /// - /// \return Value of the property - /// - //////////////////////////////////////////////////////////// - unsigned int getDeviceUint(IOHIDDeviceRef ref, CFStringRef prop); - - //////////////////////////////////////////////////////////// - /// Convert a CFStringRef to std::string - /// - /// \param cfString CFStringRef to convert - /// - /// \return std::string - /// - //////////////////////////////////////////////////////////// - std::string stringFromCFString(CFStringRef cfString); - //////////////////////////////////////////////////////////// // Member data //////////////////////////////////////////////////////////// @@ -152,9 +120,9 @@ private : typedef std::map AxisMap; typedef std::vector ButtonsVector; - AxisMap m_axis; ///< Axis (IOHIDElementRef) connected to the joystick - ButtonsVector m_buttons; ///< Buttons (IOHIDElementRef) connected to the joystick - unsigned int m_index; ///< SFML index + AxisMap m_axis; ///< Axis (IOHIDElementRef) connected to the joystick + ButtonsVector m_buttons; ///< Buttons (IOHIDElementRef) connected to the joystick + unsigned int m_index; ///< SFML index Joystick::Identification m_identification; ///< Joystick identification static Location m_locationIDs[sf::Joystick::Count]; ///< Global Joystick register diff --git a/src/SFML/Window/Unix/JoystickImpl.cpp b/src/SFML/Window/Unix/JoystickImpl.cpp index 4f1ed6ca..a4e4d6a7 100644 --- a/src/SFML/Window/Unix/JoystickImpl.cpp +++ b/src/SFML/Window/Unix/JoystickImpl.cpp @@ -30,10 +30,11 @@ #include #include #include -#include #include -#include #include +#include +#include +#include #include namespace @@ -44,39 +45,141 @@ namespace void updatePluggedList() { + udev* udevContext = udev_new(); + for (unsigned int i = 0; i < sf::Joystick::Count; ++i) { - char name[32]; - std::snprintf(name, sizeof(name), "/dev/input/js%u", i); + std::ostringstream name("js"); + name << i; + std::string nameString = name.str(); - int file = ::open(name, O_RDONLY); - if (file >= 0) + int file = ::open(("/dev/input/" + nameString).c_str(), O_RDONLY); + + if (file < 0) { + plugged[i] = false; + continue; + } + + ::close(file); + + // Check if the device is really a joystick or an + // accelerometer by inspecting whether + // ID_INPUT_ACCELEROMETER is present + if (!udevContext) + { + // Go safe and assume it is if udev isn't available plugged[i] = true; - ::close(file); + continue; + } + + udev_device* udevDevice = udev_device_new_from_subsystem_sysname(udevContext, "input", nameString.c_str()); + + if (!udevDevice) + { + // Go safe and assume it is if we can't get the device + plugged[i] = true; + continue; + } + + if (udev_device_get_property_value(udevDevice, "ID_INPUT_ACCELEROMETER")) + { + // This device is an accelerometer + plugged[i] = false; } else { - plugged[i] = false; + // This device is not an accelerometer + // Assume it's a joystick + plugged[i] = true; } + + udev_device_unref(udevDevice); } + + if (udevContext) + udev_unref(udevContext); } - bool canRead(int descriptor) + bool hasInotifyEvent() { - if (descriptor >= 0) + fd_set descriptorSet; + FD_ZERO(&descriptorSet); + FD_SET(notifyFd, &descriptorSet); + timeval timeout = {0, 0}; + + return (select(notifyFd + 1, &descriptorSet, NULL, NULL, &timeout) > 0) && + FD_ISSET(notifyFd, &descriptorSet); + } + + // Get the joystick name + std::string getJoystickName(int file, unsigned int index) + { + // Get the name + char name[128]; + + if (ioctl(file, JSIOCGNAME(sizeof(name)), name) >= 0) + return std::string(name); + + sf::err() << "Unable to get name for joystick at index " << index << std::endl; + + return std::string("Unknown Joystick"); + } + + // Get a system attribute from a udev device as an unsigned int + unsigned int getUdevAttributeUint(udev_device* device, unsigned int index, const std::string& attributeName) + { + udev_device* udevDeviceParent = udev_device_get_parent_with_subsystem_devtype(device, "usb", "usb_device"); + + if (!udevDeviceParent) { - fd_set set; - FD_ZERO(&set); - FD_SET(descriptor, &set); - timeval timeout = {0, 0}; - return select(descriptor + 1, &set, NULL, NULL, &timeout) > 0 && - FD_ISSET(notifyFd, &set); + sf::err() << "Unable to get joystick attribute. " + << "Could not find parent USB device for joystick at index " << index << "." << std::endl; + return 0; } - else + + const char* attributeString = udev_device_get_sysattr_value(udevDeviceParent, attributeName.c_str()); + + if (!attributeString) { - return false; + sf::err() << "Unable to get joystick attribute '" << attributeName << "'. " + << "Attribute does not exist for joystick at index " << index << "." << std::endl; + return 0; } + + return static_cast(std::strtoul(attributeString, NULL, 16)); + } + + // Get a system attribute for a joystick at index as an unsigned int + unsigned int getAttributeUint(unsigned int index, const std::string& attributeName) + { + udev* udevContext = udev_new(); + + if (!udevContext) + { + sf::err() << "Unable to get joystick attribute. " + << "Could not create udev context." << std::endl; + return 0; + } + + std::ostringstream sysname("js"); + sysname << index; + + udev_device* udevDevice = udev_device_new_from_subsystem_sysname(udevContext, "input", sysname.str().c_str()); + + if (!udevDevice) + { + sf::err() << "Unable to get joystick attribute. " + << "Could not find USB device for joystick at index " << index << "." << std::endl; + udev_unref(udevContext); + return 0; + } + + unsigned int attribute = getUdevAttributeUint(udevDevice, index, attributeName); + + udev_device_unref(udevDevice); + udev_unref(udevContext); + return attribute; } } @@ -91,6 +194,9 @@ void JoystickImpl::initialize() // Reset the array of plugged joysticks std::fill(plugged, plugged + Joystick::Count, false); + // Do an initial scan + updatePluggedList(); + // Create the inotify instance notifyFd = inotify_init(); if (notifyFd < 0) @@ -104,11 +210,11 @@ void JoystickImpl::initialize() if (inputFd < 0) { err() << "Failed to initialize inotify, joystick connections and disconnections won't be notified" << std::endl; - return; - } - // Do an initial scan - updatePluggedList(); + // No need to hang on to the inotify handle in this case + ::close(notifyFd); + notifyFd = -1; + } } @@ -128,18 +234,21 @@ void JoystickImpl::cleanup() //////////////////////////////////////////////////////////// bool JoystickImpl::isConnected(unsigned int index) { - // First check if new joysticks were added/removed since last update - if (canRead(notifyFd)) + // See if we can skip scanning if inotify is available + if (notifyFd < 0) { + // inotify is not available, perform a scan every query + updatePluggedList(); + } + else if (hasInotifyEvent()) + { + // Check if new joysticks were added/removed since last update // Don't bother decomposing and interpreting the filename, just do a full scan updatePluggedList(); // Flush all the pending events - while (canRead(notifyFd)) - { - char buffer[128]; - (void)read(notifyFd, buffer, sizeof(buffer)); - } + if (lseek(notifyFd, 0, SEEK_END) < 0) + err() << "Failed to flush inotify of all pending joystick events." << std::endl; } // Then check if the joystick is connected @@ -151,35 +260,29 @@ bool JoystickImpl::open(unsigned int index) { if (plugged[index]) { - char name[32]; - std::snprintf(name, sizeof(name), "/dev/input/js%u", index); + std::ostringstream name("/dev/input/js"); + name << index; // Open the joystick's file descriptor (read-only and non-blocking) - m_file = ::open(name, O_RDONLY | O_NONBLOCK); + m_file = ::open(name.str().c_str(), O_RDONLY | O_NONBLOCK); if (m_file >= 0) { // Retrieve the axes mapping ioctl(m_file, JSIOCGAXMAP, m_mapping); // Get info - m_identification.name = getJoystickName(index); - m_identification.vendorId = getUdevAttributeUint(index, "idVendor"); - m_identification.productId = getUdevAttributeUint(index, "idProduct"); + m_identification.name = getJoystickName(m_file, index); + m_identification.vendorId = getAttributeUint(index, "idVendor"); + m_identification.productId = getAttributeUint(index, "idProduct"); // Reset the joystick state m_state = JoystickState(); return true; } - else - { - return false; - } - } - else - { - return false; } + + return false; } @@ -280,57 +383,6 @@ JoystickState JoystickImpl::JoystickImpl::update() return m_state; } - -//////////////////////////////////////////////////////////// -std::string JoystickImpl::getJoystickName(unsigned int index) -{ - // Get the name - char joyname[128]; - if (ioctl(m_file, JSIOCGNAME(sizeof(joyname)), joyname) >= 0) - { - return std::string(joyname); - } - - err() << "Unable to get name for joystick at index " << index << std::endl; - return std::string("Unknown Joystick"); -} - - -//////////////////////////////////////////////////////////// -unsigned int JoystickImpl::getUdevAttributeUint(unsigned int index, std::string attributeName) -{ - unsigned int attr = 0; - udev* udevContext = udev_new(); - if (udevContext) - { - char sysname[32]; - std::snprintf(sysname, sizeof(sysname), "js%u", index); - udev_device* dev = udev_device_new_from_subsystem_sysname(udevContext, "input", sysname); - - dev = udev_device_get_parent_with_subsystem_devtype(dev, "usb", "usb_device"); - if (dev) - { - std::stringstream ss; - ss << std::hex << udev_device_get_sysattr_value(dev, attributeName.c_str()); - - ss >> attr; - } - else - { - err() << "Unable to get attribute '" << attributeName << "'. Could not find parent USB device for joystick at index " << index << std::endl; - } - - udev_device_unref(dev); - udev_unref(udevContext); - } - else - { - err() << "Unable to get attribute '" << attributeName << "'. Cannot create udev for reading info for joystick at index " << index << std::endl; - } - - return attr; -} - } // namespace priv } // namespace sf diff --git a/src/SFML/Window/Unix/JoystickImpl.hpp b/src/SFML/Window/Unix/JoystickImpl.hpp index 7f566b39..9620231e 100644 --- a/src/SFML/Window/Unix/JoystickImpl.hpp +++ b/src/SFML/Window/Unix/JoystickImpl.hpp @@ -109,34 +109,13 @@ public : private : - //////////////////////////////////////////////////////////// - /// Get the joystick name - /// - /// \param index Index of the joystick - /// - /// \return Joystick name - /// - //////////////////////////////////////////////////////////// - std::string getJoystickName(unsigned int index); - - //////////////////////////////////////////////////////////// - /// Get a system attribute from udev as an unsigned int - /// - /// \param index Index of the joystick - /// \param attributeName Name of the attribute to retrieve - /// - /// \return Attribute value as unsigned int - /// - //////////////////////////////////////////////////////////// - unsigned int getUdevAttributeUint(unsigned int index, std::string attributeName); - //////////////////////////////////////////////////////////// // Member data //////////////////////////////////////////////////////////// - int m_file; ///< File descriptor of the joystick - char m_mapping[ABS_MAX + 1]; ///< Axes mapping (index to axis id) - JoystickState m_state; ///< Current state of the joystick - sf::Joystick::Identification m_identification; ///< Identification of the joystick + int m_file; ///< File descriptor of the joystick + char m_mapping[ABS_MAX + 1]; ///< Axes mapping (index to axis id) + JoystickState m_state; ///< Current state of the joystick + sf::Joystick::Identification m_identification; ///< Identification of the joystick }; } // namespace priv diff --git a/src/SFML/Window/Win32/JoystickImpl.cpp b/src/SFML/Window/Win32/JoystickImpl.cpp index 76fb27a6..46ee3dea 100644 --- a/src/SFML/Window/Win32/JoystickImpl.cpp +++ b/src/SFML/Window/Win32/JoystickImpl.cpp @@ -25,19 +25,16 @@ //////////////////////////////////////////////////////////// // Headers //////////////////////////////////////////////////////////// - #include #include #include #include -#include -#include -#include -#include #include -#include +#include +#include +#include #include -#include +#include namespace { @@ -50,6 +47,98 @@ namespace const sf::Time connectionRefreshDelay = sf::milliseconds(500); ConnectionCache connectionCache[sf::Joystick::Count]; + + // Get a system error string from an error code + std::string getErrorString(DWORD error) + { + TCHAR errorMessage[256]; + DWORD messageLength = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, error, 0, errorMessage, 256, NULL); + errorMessage[std::min(messageLength, 255)] = 0; + return sf::String(errorMessage).toAnsiString(); + } + + // Get the joystick's name + sf::String getDeviceName(unsigned int index, JOYCAPS caps) + { + // Give the joystick a default name + sf::String joystickDescription = "Unknown Joystick"; + + LONG result; + HKEY rootKey; + HKEY currentKey; + std::basic_string subkey; + + subkey = REGSTR_PATH_JOYCONFIG; + subkey += TEXT("\\"); + subkey += caps.szRegKey; + subkey += TEXT("\\"); + subkey += REGSTR_KEY_JOYCURR; + subkey.erase(256); + + rootKey = HKEY_LOCAL_MACHINE; + result = RegOpenKeyEx(rootKey, subkey.c_str(), 0, KEY_READ, ¤tKey); + + if (result != ERROR_SUCCESS) + { + rootKey = HKEY_CURRENT_USER; + result = RegOpenKeyEx(rootKey, subkey.c_str(), 0, KEY_READ, ¤tKey); + + if (result != ERROR_SUCCESS) + { + sf::err() << "Unable to open registry for joystick at index " << index << ": " << getErrorString(result) << std::endl; + return joystickDescription; + } + } + + std::basic_ostringstream indexString; + indexString << index + 1; + + subkey = TEXT("Joystick"); + subkey += indexString.str(); + subkey += REGSTR_VAL_JOYOEMNAME; + subkey.erase(256); + + TCHAR keyData[256]; + DWORD keyDataSize = sizeof(keyData); + + result = RegQueryValueEx(currentKey, subkey.c_str(), NULL, NULL, reinterpret_cast(keyData), &keyDataSize); + RegCloseKey(currentKey); + + if (result != ERROR_SUCCESS) + { + sf::err() << "Unable to query registry key for joystick at index " << index << ": " << getErrorString(result) << std::endl; + return joystickDescription; + } + + subkey = REGSTR_PATH_JOYOEM; + subkey += TEXT("\\"); + subkey.append(keyData, keyDataSize / sizeof(TCHAR)); + subkey.erase(256); + + result = RegOpenKeyEx(rootKey, subkey.c_str(), 0, KEY_READ, ¤tKey); + + if (result != ERROR_SUCCESS) + { + sf::err() << "Unable to open registry key for joystick at index " << index << ": " << getErrorString(result) << std::endl; + return joystickDescription; + } + + keyDataSize = sizeof(keyData); + + result = RegQueryValueEx(currentKey, REGSTR_VAL_JOYOEMNAME, NULL, NULL, reinterpret_cast(keyData), &keyDataSize); + RegCloseKey(currentKey); + + if (result != ERROR_SUCCESS) + { + sf::err() << "Unable to query name for joystick at index " << index << ": " << getErrorString(result) << std::endl; + return joystickDescription; + } + + keyData[_tcsnlen(keyData, 255)] = 0; + joystickDescription = keyData; + + return joystickDescription; + } } namespace sf @@ -119,9 +208,9 @@ bool JoystickImpl::open(unsigned int index) if (success) { - m_identification.name = getDeviceName(m_index, m_caps); + m_identification.name = getDeviceName(m_index, m_caps); m_identification.productId = m_caps.wPid; - m_identification.vendorId = m_caps.wMid; + m_identification.vendorId = m_caps.wMid; } return success; @@ -207,101 +296,6 @@ JoystickState JoystickImpl::update() return state; } - -//////////////////////////////////////////////////////////// -sf::String JoystickImpl::getDeviceName(unsigned int index, JOYCAPS caps) -{ - // Give the joystick a default name - sf::String joystickDescription = "Unknown Joystick"; - - std::basic_ostringstream > ss; - ss << REGSTR_PATH_JOYCONFIG << "\\" << caps.szRegKey << "\\" << REGSTR_KEY_JOYCURR; - std::basic_string subkey = ss.str().substr(0, 255); - - HKEY currentKey; - LONG result; - HKEY rootKey = HKEY_LOCAL_MACHINE; - - result = RegOpenKeyEx(rootKey, subkey.c_str(), 0, KEY_READ, ¤tKey); - if (result != ERROR_SUCCESS) - { - rootKey = HKEY_CURRENT_USER; - result = RegOpenKeyEx(rootKey, subkey.c_str(), 0, KEY_READ, ¤tKey); - } - - if (result == ERROR_SUCCESS) - { - ss.clear(); - ss.str(_T("")); - ss << "Joystick" << index + 1 << REGSTR_VAL_JOYOEMNAME; - std::basic_string keyName = ss.str().substr(0, 255); - - TCHAR keyData[256]; - DWORD keyNameSize = sizeof(keyData); - result = RegQueryValueEx(currentKey, keyName.c_str(), NULL, NULL, (LPBYTE)keyData, &keyNameSize); - RegCloseKey(currentKey); - - if (result == ERROR_SUCCESS) - { - ss.clear(); - ss.str(_T("")); - ss << REGSTR_PATH_JOYOEM << "\\" << keyData; - subkey = ss.str().substr(0, 255); - - result = RegOpenKeyEx(rootKey, subkey.c_str(), 0, KEY_READ, ¤tKey); - if (result == ERROR_SUCCESS) - { - keyNameSize = sizeof(keyData); - unsigned int productKeyLength = keyNameSize / sizeof(TCHAR); - std::vector productKey(productKeyLength); - - result = RegQueryValueEx(currentKey, REGSTR_VAL_JOYOEMNAME, NULL, NULL, (LPBYTE) &productKey[0], &keyNameSize); - if (result == ERROR_SUCCESS) - { - while (productKeyLength > 0 && productKey[productKeyLength - 1] == 0) - { - --productKeyLength; - } - - joystickDescription = std::basic_string(&productKey[0], productKeyLength); - } - else - { - err() << "Unable to query name for joystick at index " << index << ": " << getErrorString(GetLastError()).toAnsiString() << std::endl; - } - RegCloseKey(currentKey); - } - else - { - err() << "Unable to open registry key for joystick at index " << index << ": " << getErrorString(GetLastError()).toAnsiString() << std::endl; - } - } - else - { - err() << "Unable to query registry key for joystick at index " << index << ": " << getErrorString(GetLastError()).toAnsiString() << std::endl; - } - } - else - { - err() << "Unable to open registry for joystick at index " << index << ": " << getErrorString(GetLastError()).toAnsiString() << std::endl; - } - - return joystickDescription; -} - - -//////////////////////////////////////////////////////////// -sf::String JoystickImpl::getErrorString(DWORD /*errorCode*/) -{ - std::basic_ostringstream > ss; - TCHAR errBuff[256]; - FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), 0, errBuff, sizeof(errBuff), NULL); - ss << errBuff; - sf::String errMsg(ss.str()); - - return errMsg; -} - } // namespace priv } // namespace sf diff --git a/src/SFML/Window/Win32/JoystickImpl.hpp b/src/SFML/Window/Win32/JoystickImpl.hpp index 53411e4c..87cb3894 100644 --- a/src/SFML/Window/Win32/JoystickImpl.hpp +++ b/src/SFML/Window/Win32/JoystickImpl.hpp @@ -41,7 +41,6 @@ #include #include #include -#include namespace sf @@ -120,32 +119,11 @@ public : private : - //////////////////////////////////////////////////////////// - /// Get the joystick's name - /// - /// \param index Index of the joystick - /// \param caps JOYCAPS - /// - /// \return Joystick name - /// - //////////////////////////////////////////////////////////// - sf::String getDeviceName(unsigned int index, JOYCAPS caps); - - //////////////////////////////////////////////////////////// - /// Get a system error string from an error code - /// - /// \param errorCode Error code - /// - /// \return Error message string - /// - //////////////////////////////////////////////////////////// - sf::String getErrorString(DWORD errorCode); - //////////////////////////////////////////////////////////// // Member data //////////////////////////////////////////////////////////// - unsigned int m_index; ///< Index of the joystick - JOYCAPS m_caps; ///< Joystick capabilities + unsigned int m_index; ///< Index of the joystick + JOYCAPS m_caps; ///< Joystick capabilities Joystick::Identification m_identification; ///< Joystick identification };