Fixed memory leak in Unix JoystickImpl, refactored joystick code for all platforms, prevent accelerometers registering as joysticks on Unix.
This commit is contained in:
parent
e157e7a7a8
commit
86c81f7458
@ -28,16 +28,10 @@
|
||||
////////////////////////////////////////////////////////////
|
||||
#include <SFML/Window/JoystickImpl.hpp>
|
||||
#include <SFML/System/Err.hpp>
|
||||
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <cerrno>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <map>
|
||||
#include <string>
|
||||
@ -57,123 +51,107 @@
|
||||
namespace
|
||||
{
|
||||
std::map<unsigned int, std::string> plugged;
|
||||
std::map<int, std::pair<int, int> > hatmap;
|
||||
std::map<int, std::pair<int, int> > 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;
|
||||
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;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
end:
|
||||
if (desc != NULL)
|
||||
hid_dispose_report_desc(desc);
|
||||
if (data != NULL)
|
||||
hid_end_parse(data);
|
||||
close(fd);
|
||||
hid_dispose_report_desc(desc);
|
||||
::close(file);
|
||||
|
||||
return ret;
|
||||
return result;
|
||||
}
|
||||
|
||||
void updatePluggedList()
|
||||
{
|
||||
DIR *dp;
|
||||
struct dirent *entry;
|
||||
|
||||
/*
|
||||
* Devices /dev/uhid<x> 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<index> 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;
|
||||
}
|
||||
|
||||
closedir(dp);
|
||||
directoryEntry = readdir(directory);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
return axis;
|
||||
}
|
||||
|
||||
void hatvalToSFML(int value, sf::priv::JoystickState &state)
|
||||
switch (usage)
|
||||
{
|
||||
state.axes[sf::Joystick::PovX] = hatmap[value].first;
|
||||
state.axes[sf::Joystick::PovY] = hatmap[value].second;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
void hatValueToSfml(int value, sf::priv::JoystickState& state)
|
||||
{
|
||||
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<int, int>(0, 0); // center
|
||||
hatValueMap[0] = std::make_pair<int, int>(0, 0); // center
|
||||
|
||||
hatmap[1] = std::make_pair<int, int>(0, -100); // top
|
||||
hatmap[3] = std::make_pair<int, int>(100, 0); // right
|
||||
hatmap[5] = std::make_pair<int, int>(0, 100); // bottom
|
||||
hatmap[7] = std::make_pair<int, int>(-100, 0); // left
|
||||
hatValueMap[1] = std::make_pair<int, int>(0, -100); // top
|
||||
hatValueMap[3] = std::make_pair<int, int>(100, 0); // right
|
||||
hatValueMap[5] = std::make_pair<int, int>(0, 100); // bottom
|
||||
hatValueMap[7] = std::make_pair<int, int>(-100, 0); // left
|
||||
|
||||
hatmap[2] = std::make_pair<int, int>(100, -100); // top-right
|
||||
hatmap[4] = std::make_pair<int, int>(100, 100); // bottom-right
|
||||
hatmap[6] = std::make_pair<int, int>(-100, 100); // bottom-left
|
||||
hatmap[8] = std::make_pair<int, int>(-100, -100); // top-left
|
||||
hatValueMap[2] = std::make_pair<int, int>(100, -100); // top-right
|
||||
hatValueMap[4] = std::make_pair<int, int>(100, 100); // bottom-right
|
||||
hatValueMap[6] = std::make_pair<int, int>(-100, 100); // bottom-left
|
||||
hatValueMap[8] = std::make_pair<int, int>(-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,35 +221,23 @@ 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 true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return m_state.connected = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
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:
|
||||
while (hid_get_item(data, &item))
|
||||
{
|
||||
if (item.kind == hid_input)
|
||||
{
|
||||
int usage = HID_USAGE(item.usage);
|
||||
int axis;
|
||||
|
||||
if (usage == HUG_HAT_SWITCH) {
|
||||
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 = usageToAxis(usage)) != -1)
|
||||
else if (axis != -1)
|
||||
{
|
||||
caps.axes[axis] = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
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 buttonIndex = 0;
|
||||
hid_item_t item;
|
||||
|
||||
while (hid_get_item(data, &item))
|
||||
{
|
||||
if (item.kind == hid_input)
|
||||
{
|
||||
int usage = HID_USAGE(item.usage);
|
||||
int v = hid_get_data(m_buffer, &item);
|
||||
int axis;
|
||||
|
||||
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)
|
||||
hatvalToSFML(v, m_state);
|
||||
else if ((axis = usageToAxis(usage)) != -1)
|
||||
{
|
||||
int &min = item.logical_minimum;
|
||||
int &max = item.logical_maximum;
|
||||
hatValueToSfml(value, m_state);
|
||||
}
|
||||
else if (axis != -1)
|
||||
{
|
||||
int minimum = item.logical_minimum;
|
||||
int maximum = item.logical_maximum;
|
||||
|
||||
v = (v - min) * (200) / (max - min) -100;
|
||||
m_state.axes[axis] = v;
|
||||
value = (value - minimum) * 200 / (maximum - minimum) - 100;
|
||||
m_state.axes[axis] = value;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -383,5 +344,3 @@ JoystickState JoystickImpl::JoystickImpl::update()
|
||||
} // namespace priv
|
||||
|
||||
} // namespace sf
|
||||
|
||||
// vim: set expandtab tabstop=4 softtabstop=4 shiftwidth=4:
|
||||
|
@ -28,9 +28,9 @@
|
||||
////////////////////////////////////////////////////////////
|
||||
// Headers
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
#include <dev/usb/usbhid.h>
|
||||
#include <usbhid.h>
|
||||
#include <vector>
|
||||
|
||||
namespace sf
|
||||
{
|
||||
@ -113,14 +113,11 @@ 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
|
||||
std::vector<char> m_buffer; ///< USB HID buffer
|
||||
int m_length; ///< Buffer length
|
||||
Joystick::Identification m_identification; ///< Joystick identification
|
||||
|
||||
JoystickState m_state; ///< Current state of the joystick
|
||||
};
|
||||
|
||||
|
@ -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<char> 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<CFStringRef>(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<CFStringRef>(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<char> str(length);
|
||||
CFIndex maxSize = CFStringGetMaximumSizeForEncoding(length, kCFStringEncodingUTF8);
|
||||
CFStringGetCString(cfString, &str[0], maxSize, kCFStringEncodingUTF8);
|
||||
return &str[0];
|
||||
}
|
||||
|
||||
} // namespace priv
|
||||
|
||||
} // namespace sf
|
||||
|
@ -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
|
||||
////////////////////////////////////////////////////////////
|
||||
|
@ -30,10 +30,11 @@
|
||||
#include <sys/inotify.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <cstdio>
|
||||
#include <libudev.h>
|
||||
#include <unistd.h>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <sstream>
|
||||
|
||||
namespace
|
||||
@ -44,39 +45,131 @@ 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] = true;
|
||||
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;
|
||||
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)
|
||||
{
|
||||
if (descriptor >= 0)
|
||||
{
|
||||
fd_set set;
|
||||
FD_ZERO(&set);
|
||||
FD_SET(descriptor, &set);
|
||||
fd_set descriptorSet;
|
||||
FD_ZERO(&descriptorSet);
|
||||
FD_SET(descriptor, &descriptorSet);
|
||||
timeval timeout = {0, 0};
|
||||
return select(descriptor + 1, &set, NULL, NULL, &timeout) > 0 &&
|
||||
FD_ISSET(notifyFd, &set);
|
||||
|
||||
return (select(descriptor + 1, &descriptorSet, NULL, NULL, &timeout) > 0) &&
|
||||
FD_ISSET(notifyFd, &descriptorSet);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get the joystick name
|
||||
std::string getJoystickName(int file, unsigned int index)
|
||||
{
|
||||
// Get the name
|
||||
char joyname[128];
|
||||
|
||||
if (ioctl(file, JSIOCGNAME(sizeof(joyname)), joyname) >= 0)
|
||||
return std::string(joyname);
|
||||
|
||||
sf::err() << "Unable to get name for joystick at index " << index << std::endl;
|
||||
|
||||
return std::string("Unknown Joystick");
|
||||
}
|
||||
|
||||
|
||||
// Get a system attribute from udev as an unsigned int
|
||||
unsigned int getUdevAttributeUint(unsigned int index, std::string attributeName)
|
||||
{
|
||||
unsigned int attribute = 0;
|
||||
udev* udevContext = udev_new();
|
||||
|
||||
if (!udevContext)
|
||||
{
|
||||
sf::err() << "Unable to get attribute '" << attributeName << "'. Cannot create udev for reading info for joystick at index " << index << std::endl;
|
||||
return attribute;
|
||||
}
|
||||
|
||||
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 attribute '" << attributeName << "'. Could not find USB device for joystick at index " << index << std::endl;
|
||||
udev_unref(udevContext);
|
||||
return attribute;
|
||||
}
|
||||
|
||||
udev_device* udevDeviceParent = udev_device_get_parent_with_subsystem_devtype(udevDevice, "usb", "usb_device");
|
||||
|
||||
if (!udevDeviceParent)
|
||||
{
|
||||
sf::err() << "Unable to get attribute '" << attributeName << "'. Could not find parent USB device for joystick at index " << index << std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
attribute = static_cast<unsigned int>(strtoul(udev_device_get_sysattr_value(udevDeviceParent, attributeName.c_str()), NULL, 16));
|
||||
}
|
||||
|
||||
udev_device_unref(udevDevice);
|
||||
udev_unref(udevContext);
|
||||
return attribute;
|
||||
}
|
||||
}
|
||||
|
||||
@ -151,18 +244,18 @@ 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.name = getJoystickName(m_file, index);
|
||||
m_identification.vendorId = getUdevAttributeUint(index, "idVendor");
|
||||
m_identification.productId = getUdevAttributeUint(index, "idProduct");
|
||||
|
||||
@ -171,16 +264,10 @@ bool JoystickImpl::open(unsigned int index)
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -280,57 +367,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
|
||||
|
@ -109,27 +109,6 @@ 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
|
||||
////////////////////////////////////////////////////////////
|
||||
|
@ -25,19 +25,16 @@
|
||||
////////////////////////////////////////////////////////////
|
||||
// Headers
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
#include <SFML/Window/JoystickImpl.hpp>
|
||||
#include <SFML/System/Clock.hpp>
|
||||
#include <SFML/System/Err.hpp>
|
||||
#include <windows.h>
|
||||
#include <stdlib.h>
|
||||
#include <cmath>
|
||||
#include <stdio.h>
|
||||
#include <regstr.h>
|
||||
#include <tchar.h>
|
||||
#include <string>
|
||||
#include <regstr.h>
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
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<DWORD>(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<TCHAR> 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<TCHAR> 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<LPBYTE>(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<LPBYTE>(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
|
||||
@ -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<TCHAR, std::char_traits<TCHAR> > ss;
|
||||
ss << REGSTR_PATH_JOYCONFIG << "\\" << caps.szRegKey << "\\" << REGSTR_KEY_JOYCURR;
|
||||
std::basic_string<TCHAR> 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<TCHAR> 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<TCHAR> 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<TCHAR>(&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<TCHAR, std::char_traits<TCHAR> > 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
|
||||
|
@ -41,7 +41,6 @@
|
||||
#include <SFML/System/String.hpp>
|
||||
#include <windows.h>
|
||||
#include <mmsystem.h>
|
||||
#include <cmath>
|
||||
|
||||
|
||||
namespace sf
|
||||
@ -120,27 +119,6 @@ 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
|
||||
////////////////////////////////////////////////////////////
|
||||
|
Loading…
Reference in New Issue
Block a user