Merge branch 'bugfix/joystick'
This commit is contained in:
commit
dcba593e8f
@ -28,16 +28,10 @@
|
|||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
#include <SFML/Window/JoystickImpl.hpp>
|
#include <SFML/Window/JoystickImpl.hpp>
|
||||||
#include <SFML/System/Err.hpp>
|
#include <SFML/System/Err.hpp>
|
||||||
|
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
#include <errno.h>
|
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#include <cerrno>
|
|
||||||
#include <cstdio>
|
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <string>
|
#include <string>
|
||||||
@ -57,123 +51,107 @@
|
|||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
std::map<unsigned int, std::string> plugged;
|
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)
|
bool isJoystick(const char *name)
|
||||||
{
|
{
|
||||||
int fd, id;
|
int file = ::open(name, O_RDONLY | O_NONBLOCK);
|
||||||
bool ret;
|
|
||||||
report_desc_t desc = NULL;
|
if (file < 0)
|
||||||
hid_data_t data = NULL;
|
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;
|
hid_item_t item;
|
||||||
|
|
||||||
// Assume it isn't
|
// Assume it isn't
|
||||||
ret = false;
|
bool result = false;
|
||||||
|
|
||||||
if ((fd = ::open(name, O_RDONLY | O_NONBLOCK)) < 0)
|
while (hid_get_item(data, &item) > 0)
|
||||||
return false;
|
{
|
||||||
|
if ((item.kind == hid_collection) && (HID_PAGE(item.usage) == HUP_GENERIC_DESKTOP))
|
||||||
if ((desc = hid_get_report_desc(fd)) == NULL)
|
{
|
||||||
goto end;
|
if ((HID_USAGE(item.usage) == HUG_JOYSTICK) || (HID_USAGE(item.usage) == HUG_GAME_PAD))
|
||||||
|
{
|
||||||
id = hid_get_report_id(fd);
|
result = true;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
end:
|
hid_end_parse(data);
|
||||||
if (desc != NULL)
|
hid_dispose_report_desc(desc);
|
||||||
hid_dispose_report_desc(desc);
|
::close(file);
|
||||||
if (data != NULL)
|
|
||||||
hid_end_parse(data);
|
|
||||||
close(fd);
|
|
||||||
|
|
||||||
return ret;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void updatePluggedList()
|
void updatePluggedList()
|
||||||
{
|
{
|
||||||
DIR *dp;
|
|
||||||
struct dirent *entry;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Devices /dev/uhid<x> are shared between joystick and any other
|
* Devices /dev/uhid<x> are shared between joystick and any other
|
||||||
* human interface device. We need to iterate over all found devices
|
* human interface device. We need to iterate over all found devices
|
||||||
* and check if they are joysticks. The index of JoystickImpl::open
|
* and check if they are joysticks. The index of JoystickImpl::open
|
||||||
* does not match the /dev/uhid<index> device!
|
* does not match the /dev/uhid<index> device!
|
||||||
*/
|
*/
|
||||||
if ((dp = opendir("/dev")) != NULL) {
|
DIR* directory = opendir("/dev");
|
||||||
char name[FILENAME_MAX];
|
|
||||||
int jc = 0;
|
|
||||||
|
|
||||||
while ((entry = readdir(dp)) != NULL && jc < sf::Joystick::Count) {
|
if (directory)
|
||||||
if (strncmp(entry->d_name, "uhid", 4) == 0) {
|
{
|
||||||
std::sprintf(name, "/dev/%s", entry->d_name);
|
int joystickCount = 0;
|
||||||
|
struct dirent* directoryEntry = readdir(directory);
|
||||||
|
|
||||||
if (isJoystick(name))
|
while (directoryEntry && joystickCount < sf::Joystick::Count)
|
||||||
plugged[jc++] = std::string(name);
|
{
|
||||||
|
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 usageToAxis(int usage)
|
||||||
{
|
{
|
||||||
int axis;
|
switch (usage)
|
||||||
|
{
|
||||||
switch (usage) {
|
case HUG_X: return sf::Joystick::X;
|
||||||
case HUG_X:
|
case HUG_Y: return sf::Joystick::Y;
|
||||||
axis = sf::Joystick::X;
|
case HUG_Z: return sf::Joystick::Z;
|
||||||
break;
|
case HUG_RZ: return sf::Joystick::R;
|
||||||
case HUG_Y:
|
case HUG_RX: return sf::Joystick::U;
|
||||||
axis = sf::Joystick::Y;
|
case HUG_RY: return sf::Joystick::V;
|
||||||
break;
|
default: return -1;
|
||||||
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)
|
void hatValueToSfml(int value, sf::priv::JoystickState& state)
|
||||||
{
|
{
|
||||||
state.axes[sf::Joystick::PovX] = hatmap[value].first;
|
state.axes[sf::Joystick::PovX] = hatValueMap[value].first;
|
||||||
state.axes[sf::Joystick::PovY] = hatmap[value].second;
|
state.axes[sf::Joystick::PovY] = hatValueMap[value].second;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -191,17 +169,17 @@ void JoystickImpl::initialize()
|
|||||||
updatePluggedList();
|
updatePluggedList();
|
||||||
|
|
||||||
// Map of hat values
|
// Map of hat values
|
||||||
hatmap[0] = std::make_pair<int, int>(0, 0); // center
|
hatValueMap[0] = std::make_pair( 0, 0); // center
|
||||||
|
|
||||||
hatmap[1] = std::make_pair<int, int>(0, -100); // top
|
hatValueMap[1] = std::make_pair( 0, -100); // top
|
||||||
hatmap[3] = std::make_pair<int, int>(100, 0); // right
|
hatValueMap[3] = std::make_pair( 100, 0); // right
|
||||||
hatmap[5] = std::make_pair<int, int>(0, 100); // bottom
|
hatValueMap[5] = std::make_pair( 0, 100); // bottom
|
||||||
hatmap[7] = std::make_pair<int, int>(-100, 0); // left
|
hatValueMap[7] = std::make_pair(-100, 0); // left
|
||||||
|
|
||||||
hatmap[2] = std::make_pair<int, int>(100, -100); // top-right
|
hatValueMap[2] = std::make_pair( 100, -100); // top-right
|
||||||
hatmap[4] = std::make_pair<int, int>(100, 100); // bottom-right
|
hatValueMap[4] = std::make_pair( 100, 100); // bottom-right
|
||||||
hatmap[6] = std::make_pair<int, int>(-100, 100); // bottom-left
|
hatValueMap[6] = std::make_pair(-100, 100); // bottom-left
|
||||||
hatmap[8] = std::make_pair<int, int>(-100, -100); // top-left
|
hatValueMap[8] = std::make_pair(-100, -100); // top-left
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -232,7 +210,8 @@ bool JoystickImpl::open(unsigned int index)
|
|||||||
|
|
||||||
// Get the report descriptor
|
// Get the report descriptor
|
||||||
m_desc = hid_get_report_desc(m_file);
|
m_desc = hid_get_report_desc(m_file);
|
||||||
if (m_desc == NULL) {
|
if (!m_desc)
|
||||||
|
{
|
||||||
::close(m_file);
|
::close(m_file);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -242,26 +221,15 @@ bool JoystickImpl::open(unsigned int index)
|
|||||||
|
|
||||||
// Then allocate a buffer for data retrievement
|
// Then allocate a buffer for data retrievement
|
||||||
m_length = hid_report_size(m_desc, hid_input, m_id);
|
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) {
|
m_state.connected = true;
|
||||||
::close(m_file);
|
|
||||||
::hid_dispose_report_desc(m_desc);
|
|
||||||
|
|
||||||
return false;
|
return true;
|
||||||
}
|
|
||||||
|
|
||||||
return m_state.connected = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
return false;
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -269,8 +237,7 @@ bool JoystickImpl::open(unsigned int index)
|
|||||||
void JoystickImpl::close()
|
void JoystickImpl::close()
|
||||||
{
|
{
|
||||||
::close(m_file);
|
::close(m_file);
|
||||||
::hid_dispose_report_desc(m_desc);
|
hid_dispose_report_desc(m_desc);
|
||||||
::free(m_buffer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -278,38 +245,35 @@ void JoystickImpl::close()
|
|||||||
JoystickCaps JoystickImpl::getCapabilities() const
|
JoystickCaps JoystickImpl::getCapabilities() const
|
||||||
{
|
{
|
||||||
JoystickCaps caps;
|
JoystickCaps caps;
|
||||||
hid_data_t data;
|
|
||||||
hid_item_t item;
|
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)) {
|
while (hid_get_item(data, &item))
|
||||||
switch (item.kind) {
|
{
|
||||||
case hid_input:
|
if (item.kind == hid_input)
|
||||||
switch (HID_PAGE(item.usage)) {
|
{
|
||||||
case HUP_BUTTON:
|
int usage = HID_USAGE(item.usage);
|
||||||
caps.buttonCount ++;
|
|
||||||
break;
|
|
||||||
case HUP_GENERIC_DESKTOP:
|
|
||||||
{
|
|
||||||
int usage = HID_USAGE(item.usage);
|
|
||||||
int axis;
|
|
||||||
|
|
||||||
if (usage == HUG_HAT_SWITCH) {
|
if (usage == HUP_BUTTON)
|
||||||
caps.axes[Joystick::PovX] = true;
|
{
|
||||||
caps.axes[Joystick::PovY] = true;
|
caps.buttonCount++;
|
||||||
}
|
break;
|
||||||
else if ((axis = usageToAxis(usage)) != -1)
|
}
|
||||||
{
|
else if (usage == HUP_GENERIC_DESKTOP)
|
||||||
caps.axes[axis] = true;
|
{
|
||||||
}
|
int axis = usageToAxis(usage);
|
||||||
break;
|
|
||||||
}
|
if (usage == HUG_HAT_SWITCH)
|
||||||
default:
|
{
|
||||||
break;
|
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()
|
JoystickState JoystickImpl::JoystickImpl::update()
|
||||||
{
|
{
|
||||||
while (read(m_file, m_buffer, m_length) == m_length) {
|
while (read(m_file, &m_buffer[0], m_length) == m_length)
|
||||||
hid_data_t data;
|
{
|
||||||
hid_item_t item;
|
hid_data_t data = hid_start_parse(m_desc, 1 << hid_input, m_id);
|
||||||
|
|
||||||
data = hid_start_parse(m_desc, 1 << hid_input, m_id);
|
|
||||||
|
|
||||||
// No memory?
|
// No memory?
|
||||||
if (data == NULL)
|
if (!data)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
int but = 0;
|
int buttonIndex = 0;
|
||||||
while (hid_get_item(data, &item)) {
|
hid_item_t 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;
|
|
||||||
|
|
||||||
if (usage == HUG_HAT_SWITCH)
|
while (hid_get_item(data, &item))
|
||||||
hatvalToSFML(v, m_state);
|
{
|
||||||
else if ((axis = usageToAxis(usage)) != -1)
|
if (item.kind == hid_input)
|
||||||
{
|
{
|
||||||
int &min = item.logical_minimum;
|
int usage = HID_USAGE(item.usage);
|
||||||
int &max = item.logical_maximum;
|
|
||||||
|
|
||||||
v = (v - min) * (200) / (max - min) -100;
|
if (usage == HUP_BUTTON)
|
||||||
m_state.axes[axis] = v;
|
{
|
||||||
}
|
m_state.buttons[buttonIndex++] = hid_get_data(&m_buffer[0], &item);
|
||||||
|
}
|
||||||
break;
|
else if (usage == HUP_GENERIC_DESKTOP)
|
||||||
}
|
{
|
||||||
default:
|
int value = hid_get_data(&m_buffer[0], &item);
|
||||||
break;
|
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 priv
|
||||||
|
|
||||||
} // namespace sf
|
} // namespace sf
|
||||||
|
|
||||||
// vim: set expandtab tabstop=4 softtabstop=4 shiftwidth=4:
|
|
||||||
|
@ -28,9 +28,9 @@
|
|||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
// Headers
|
// Headers
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
#include <dev/usb/usbhid.h>
|
#include <dev/usb/usbhid.h>
|
||||||
#include <usbhid.h>
|
#include <usbhid.h>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
namespace sf
|
namespace sf
|
||||||
{
|
{
|
||||||
@ -112,16 +112,13 @@ private :
|
|||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
// Member data
|
// Member data
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
int m_file; ///< File descriptor of the joystick
|
int m_file; ///< File descriptor of the joystick
|
||||||
|
report_desc_t m_desc; ///< USB report descriptor
|
||||||
report_desc_t m_desc; ///< USB report descriptor
|
int m_id; ///< USB id
|
||||||
int m_id; ///< USB id
|
std::vector<char> m_buffer; ///< USB HID buffer
|
||||||
|
int m_length; ///< Buffer length
|
||||||
void *m_buffer; ///< USB HID buffer
|
|
||||||
int m_length; ///< Buffer length
|
|
||||||
Joystick::Identification m_identification; ///< Joystick identification
|
Joystick::Identification m_identification; ///< Joystick identification
|
||||||
|
JoystickState m_state; ///< Current state of the joystick
|
||||||
JoystickState m_state; ///< Current state of the joystick
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace priv
|
} // namespace priv
|
||||||
|
@ -77,8 +77,8 @@ void JoystickManager::update()
|
|||||||
if (!item.state.connected)
|
if (!item.state.connected)
|
||||||
{
|
{
|
||||||
item.joystick.close();
|
item.joystick.close();
|
||||||
item.capabilities = JoystickCaps();
|
item.capabilities = JoystickCaps();
|
||||||
item.state = JoystickState();
|
item.state = JoystickState();
|
||||||
item.identification = Joystick::Identification();
|
item.identification = Joystick::Identification();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -89,8 +89,8 @@ void JoystickManager::update()
|
|||||||
{
|
{
|
||||||
if (item.joystick.open(i))
|
if (item.joystick.open(i))
|
||||||
{
|
{
|
||||||
item.capabilities = item.joystick.getCapabilities();
|
item.capabilities = item.joystick.getCapabilities();
|
||||||
item.state = item.joystick.update();
|
item.state = item.joystick.update();
|
||||||
item.identification = item.joystick.getIdentification();
|
item.identification = item.joystick.getIdentification();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -109,9 +109,9 @@ private:
|
|||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
struct Item
|
struct Item
|
||||||
{
|
{
|
||||||
JoystickImpl joystick; ///< Joystick implementation
|
JoystickImpl joystick; ///< Joystick implementation
|
||||||
JoystickState state; ///< The current joystick state
|
JoystickState state; ///< The current joystick state
|
||||||
JoystickCaps capabilities; ///< The joystick capabilities
|
JoystickCaps capabilities; ///< The joystick capabilities
|
||||||
Joystick::Identification identification; ///< The joystick identification
|
Joystick::Identification identification; ///< The joystick identification
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -38,6 +38,46 @@ namespace
|
|||||||
{
|
{
|
||||||
return IOHIDElementGetUsage(b1) < IOHIDElementGetUsage(b2);
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_identification.name = getDeviceString(self, CFSTR(kIOHIDProductKey));
|
m_identification.name = getDeviceString(self, CFSTR(kIOHIDProductKey), m_index);
|
||||||
m_identification.vendorId = getDeviceUint(self, CFSTR(kIOHIDVendorIDKey));
|
m_identification.vendorId = getDeviceUint(self, CFSTR(kIOHIDVendorIDKey), m_index);
|
||||||
m_identification.productId = getDeviceUint(self, CFSTR(kIOHIDProductIDKey));
|
m_identification.productId = getDeviceUint(self, CFSTR(kIOHIDProductIDKey), m_index);
|
||||||
|
|
||||||
// Get a list of all elements attached to the device.
|
// Get a list of all elements attached to the device.
|
||||||
CFArrayRef elements = IOHIDDeviceCopyMatchingElements(self, NULL, kIOHIDOptionsTypeNone);
|
CFArrayRef elements = IOHIDDeviceCopyMatchingElements(self, NULL, kIOHIDOptionsTypeNone);
|
||||||
@ -389,48 +429,6 @@ JoystickState JoystickImpl::update()
|
|||||||
return state;
|
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 priv
|
||||||
|
|
||||||
} // namespace sf
|
} // namespace sf
|
||||||
|
@ -113,38 +113,6 @@ public :
|
|||||||
|
|
||||||
private :
|
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
|
// Member data
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
@ -152,9 +120,9 @@ private :
|
|||||||
typedef std::map<sf::Joystick::Axis, IOHIDElementRef> AxisMap;
|
typedef std::map<sf::Joystick::Axis, IOHIDElementRef> AxisMap;
|
||||||
typedef std::vector<IOHIDElementRef> ButtonsVector;
|
typedef std::vector<IOHIDElementRef> ButtonsVector;
|
||||||
|
|
||||||
AxisMap m_axis; ///< Axis (IOHIDElementRef) connected to the joystick
|
AxisMap m_axis; ///< Axis (IOHIDElementRef) connected to the joystick
|
||||||
ButtonsVector m_buttons; ///< Buttons (IOHIDElementRef) connected to the joystick
|
ButtonsVector m_buttons; ///< Buttons (IOHIDElementRef) connected to the joystick
|
||||||
unsigned int m_index; ///< SFML index
|
unsigned int m_index; ///< SFML index
|
||||||
Joystick::Identification m_identification; ///< Joystick identification
|
Joystick::Identification m_identification; ///< Joystick identification
|
||||||
|
|
||||||
static Location m_locationIDs[sf::Joystick::Count]; ///< Global Joystick register
|
static Location m_locationIDs[sf::Joystick::Count]; ///< Global Joystick register
|
||||||
|
@ -30,10 +30,11 @@
|
|||||||
#include <sys/inotify.h>
|
#include <sys/inotify.h>
|
||||||
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <unistd.h>
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <cstdio>
|
|
||||||
#include <libudev.h>
|
#include <libudev.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <cstdio>
|
||||||
|
#include <cstdlib>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
@ -44,39 +45,141 @@ namespace
|
|||||||
|
|
||||||
void updatePluggedList()
|
void updatePluggedList()
|
||||||
{
|
{
|
||||||
|
udev* udevContext = udev_new();
|
||||||
|
|
||||||
for (unsigned int i = 0; i < sf::Joystick::Count; ++i)
|
for (unsigned int i = 0; i < sf::Joystick::Count; ++i)
|
||||||
{
|
{
|
||||||
char name[32];
|
std::ostringstream name("js");
|
||||||
std::snprintf(name, sizeof(name), "/dev/input/js%u", i);
|
name << i;
|
||||||
|
std::string nameString = name.str();
|
||||||
|
|
||||||
int file = ::open(name, O_RDONLY);
|
int file = ::open(("/dev/input/" + nameString).c_str(), O_RDONLY);
|
||||||
if (file >= 0)
|
|
||||||
|
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;
|
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
|
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;
|
sf::err() << "Unable to get joystick attribute. "
|
||||||
FD_ZERO(&set);
|
<< "Could not find parent USB device for joystick at index " << index << "." << std::endl;
|
||||||
FD_SET(descriptor, &set);
|
return 0;
|
||||||
timeval timeout = {0, 0};
|
|
||||||
return select(descriptor + 1, &set, NULL, NULL, &timeout) > 0 &&
|
|
||||||
FD_ISSET(notifyFd, &set);
|
|
||||||
}
|
}
|
||||||
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<unsigned int>(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
|
// Reset the array of plugged joysticks
|
||||||
std::fill(plugged, plugged + Joystick::Count, false);
|
std::fill(plugged, plugged + Joystick::Count, false);
|
||||||
|
|
||||||
|
// Do an initial scan
|
||||||
|
updatePluggedList();
|
||||||
|
|
||||||
// Create the inotify instance
|
// Create the inotify instance
|
||||||
notifyFd = inotify_init();
|
notifyFd = inotify_init();
|
||||||
if (notifyFd < 0)
|
if (notifyFd < 0)
|
||||||
@ -104,11 +210,11 @@ void JoystickImpl::initialize()
|
|||||||
if (inputFd < 0)
|
if (inputFd < 0)
|
||||||
{
|
{
|
||||||
err() << "Failed to initialize inotify, joystick connections and disconnections won't be notified" << std::endl;
|
err() << "Failed to initialize inotify, joystick connections and disconnections won't be notified" << std::endl;
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Do an initial scan
|
// No need to hang on to the inotify handle in this case
|
||||||
updatePluggedList();
|
::close(notifyFd);
|
||||||
|
notifyFd = -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -128,18 +234,21 @@ void JoystickImpl::cleanup()
|
|||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
bool JoystickImpl::isConnected(unsigned int index)
|
bool JoystickImpl::isConnected(unsigned int index)
|
||||||
{
|
{
|
||||||
// First check if new joysticks were added/removed since last update
|
// See if we can skip scanning if inotify is available
|
||||||
if (canRead(notifyFd))
|
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
|
// Don't bother decomposing and interpreting the filename, just do a full scan
|
||||||
updatePluggedList();
|
updatePluggedList();
|
||||||
|
|
||||||
// Flush all the pending events
|
// Flush all the pending events
|
||||||
while (canRead(notifyFd))
|
if (lseek(notifyFd, 0, SEEK_END) < 0)
|
||||||
{
|
err() << "Failed to flush inotify of all pending joystick events." << std::endl;
|
||||||
char buffer[128];
|
|
||||||
(void)read(notifyFd, buffer, sizeof(buffer));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Then check if the joystick is connected
|
// Then check if the joystick is connected
|
||||||
@ -151,35 +260,29 @@ bool JoystickImpl::open(unsigned int index)
|
|||||||
{
|
{
|
||||||
if (plugged[index])
|
if (plugged[index])
|
||||||
{
|
{
|
||||||
char name[32];
|
std::ostringstream name("/dev/input/js");
|
||||||
std::snprintf(name, sizeof(name), "/dev/input/js%u", index);
|
name << index;
|
||||||
|
|
||||||
// Open the joystick's file descriptor (read-only and non-blocking)
|
// 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)
|
if (m_file >= 0)
|
||||||
{
|
{
|
||||||
// Retrieve the axes mapping
|
// Retrieve the axes mapping
|
||||||
ioctl(m_file, JSIOCGAXMAP, m_mapping);
|
ioctl(m_file, JSIOCGAXMAP, m_mapping);
|
||||||
|
|
||||||
// Get info
|
// Get info
|
||||||
m_identification.name = getJoystickName(index);
|
m_identification.name = getJoystickName(m_file, index);
|
||||||
m_identification.vendorId = getUdevAttributeUint(index, "idVendor");
|
m_identification.vendorId = getAttributeUint(index, "idVendor");
|
||||||
m_identification.productId = getUdevAttributeUint(index, "idProduct");
|
m_identification.productId = getAttributeUint(index, "idProduct");
|
||||||
|
|
||||||
// Reset the joystick state
|
// Reset the joystick state
|
||||||
m_state = JoystickState();
|
m_state = JoystickState();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -280,57 +383,6 @@ JoystickState JoystickImpl::JoystickImpl::update()
|
|||||||
return m_state;
|
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 priv
|
||||||
|
|
||||||
} // namespace sf
|
} // namespace sf
|
||||||
|
@ -109,34 +109,13 @@ public :
|
|||||||
|
|
||||||
private :
|
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
|
// Member data
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
int m_file; ///< File descriptor of the joystick
|
int m_file; ///< File descriptor of the joystick
|
||||||
char m_mapping[ABS_MAX + 1]; ///< Axes mapping (index to axis id)
|
char m_mapping[ABS_MAX + 1]; ///< Axes mapping (index to axis id)
|
||||||
JoystickState m_state; ///< Current state of the joystick
|
JoystickState m_state; ///< Current state of the joystick
|
||||||
sf::Joystick::Identification m_identification; ///< Identification of the joystick
|
sf::Joystick::Identification m_identification; ///< Identification of the joystick
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace priv
|
} // namespace priv
|
||||||
|
@ -25,19 +25,16 @@
|
|||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
// Headers
|
// Headers
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
#include <SFML/Window/JoystickImpl.hpp>
|
#include <SFML/Window/JoystickImpl.hpp>
|
||||||
#include <SFML/System/Clock.hpp>
|
#include <SFML/System/Clock.hpp>
|
||||||
#include <SFML/System/Err.hpp>
|
#include <SFML/System/Err.hpp>
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include <stdlib.h>
|
|
||||||
#include <cmath>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <regstr.h>
|
|
||||||
#include <tchar.h>
|
#include <tchar.h>
|
||||||
#include <string>
|
#include <regstr.h>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cmath>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <vector>
|
#include <string>
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
@ -50,6 +47,98 @@ namespace
|
|||||||
|
|
||||||
const sf::Time connectionRefreshDelay = sf::milliseconds(500);
|
const sf::Time connectionRefreshDelay = sf::milliseconds(500);
|
||||||
ConnectionCache connectionCache[sf::Joystick::Count];
|
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
|
namespace sf
|
||||||
@ -119,9 +208,9 @@ bool JoystickImpl::open(unsigned int index)
|
|||||||
|
|
||||||
if (success)
|
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.productId = m_caps.wPid;
|
||||||
m_identification.vendorId = m_caps.wMid;
|
m_identification.vendorId = m_caps.wMid;
|
||||||
}
|
}
|
||||||
|
|
||||||
return success;
|
return success;
|
||||||
@ -207,101 +296,6 @@ JoystickState JoystickImpl::update()
|
|||||||
return state;
|
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 priv
|
||||||
|
|
||||||
} // namespace sf
|
} // namespace sf
|
||||||
|
@ -41,7 +41,6 @@
|
|||||||
#include <SFML/System/String.hpp>
|
#include <SFML/System/String.hpp>
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include <mmsystem.h>
|
#include <mmsystem.h>
|
||||||
#include <cmath>
|
|
||||||
|
|
||||||
|
|
||||||
namespace sf
|
namespace sf
|
||||||
@ -120,32 +119,11 @@ public :
|
|||||||
|
|
||||||
private :
|
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
|
// Member data
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
unsigned int m_index; ///< Index of the joystick
|
unsigned int m_index; ///< Index of the joystick
|
||||||
JOYCAPS m_caps; ///< Joystick capabilities
|
JOYCAPS m_caps; ///< Joystick capabilities
|
||||||
Joystick::Identification m_identification; ///< Joystick identification
|
Joystick::Identification m_identification; ///< Joystick identification
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user