Adds name, vendor ID and product ID for joysticks.

- Implemented on Windows, Mac OS and Linux.
- Adds sf::Joystick::Identification structure to hold
  name, vendor ID and product ID.
This commit is contained in:
NoobsArePeople2 2014-01-03 18:12:26 -08:00
parent a8ba35171a
commit 29c0f14911
14 changed files with 447 additions and 27 deletions

View File

@ -29,6 +29,7 @@
// Headers
////////////////////////////////////////////////////////////
#include <SFML/Window/Export.hpp>
#include <SFML/System/String.hpp>
namespace sf
@ -68,6 +69,19 @@ public :
PovY ///< The Y axis of the point-of-view hat
};
////////////////////////////////////////////////////////////
/// \brief Structure holding a joystick's identification
///
////////////////////////////////////////////////////////////
struct Identification
{
Identification();
sf::String name; ///< Name of the joystick
unsigned int vendorId; ///< Manufacturer identifier
unsigned int productId; ///< Product identifier
};
////////////////////////////////////////////////////////////
/// \brief Check if a joystick is connected
///
@ -129,6 +143,16 @@ public :
////////////////////////////////////////////////////////////
static float getAxisPosition(unsigned int joystick, Axis axis);
////////////////////////////////////////////////////////////
/// \brief Get the joystick information
///
/// \param joystick Index of the joystick
///
/// \return Structure containing joystick information.
///
////////////////////////////////////////////////////////////
static Identification getIdentification(unsigned int joystick);
////////////////////////////////////////////////////////////
/// \brief Update the states of all joysticks
///

View File

@ -51,7 +51,7 @@ if(SFML_OS_WINDOWS)
source_group("windows" FILES ${PLATFORM_SRC})
# make sure that we use the Unicode version of the Win API functions
add_definitions(-DUNICODE)
add_definitions(-DUNICODE -D_UNICODE)
elseif(SFML_OS_LINUX OR SFML_OS_FREEBSD)
set(PLATFORM_SRC
${SRCROOT}/Unix/Display.cpp
@ -136,7 +136,7 @@ set(WINDOW_EXT_LIBS ${OPENGL_gl_LIBRARY})
if(SFML_OS_WINDOWS)
set(WINDOW_EXT_LIBS ${WINDOW_EXT_LIBS} winmm gdi32)
elseif(SFML_OS_LINUX OR SFML_OS_FREEBSD)
set(WINDOW_EXT_LIBS ${WINDOW_EXT_LIBS} ${X11_X11_LIB} ${X11_Xrandr_LIB})
set(WINDOW_EXT_LIBS ${WINDOW_EXT_LIBS} ${X11_X11_LIB} ${X11_Xrandr_LIB} udev)
if(SFML_OS_FREEBSD)
set(WINDOW_EXT_LIBS ${WINDOW_EXT_LIBS} usbhid)
endif()

View File

@ -319,6 +319,13 @@ JoystickCaps JoystickImpl::getCapabilities() const
}
////////////////////////////////////////////////////////////
Identifcation JoystickImpl::getIdentification() const
{
return m_identification;
}
////////////////////////////////////////////////////////////
JoystickState JoystickImpl::JoystickImpl::update()
{

View File

@ -91,6 +91,14 @@ public :
////////////////////////////////////////////////////////////
JoystickCaps getCapabilities() const;
////////////////////////////////////////////////////////////
/// \brief Get the joystick identification
///
/// \return Joystick identification
///
////////////////////////////////////////////////////////////
Identification getIdentification() const;
////////////////////////////////////////////////////////////
/// \brief Update the joystick and get its new state
///
@ -111,6 +119,7 @@ private :
void *m_buffer; ///< USB HID buffer
int m_length; ///< Buffer length
Identification m_identificaion; ///< Joystick identification
JoystickState m_state; ///< Current state of the joystick
};

View File

@ -66,10 +66,27 @@ float Joystick::getAxisPosition(unsigned int joystick, Axis axis)
}
////////////////////////////////////////////////////////////
Joystick::Identification Joystick::getIdentification(unsigned int joystick)
{
return priv::JoystickManager::getInstance().getIdentification(joystick);
}
////////////////////////////////////////////////////////////
void Joystick::update()
{
return priv::JoystickManager::getInstance().update();
}
////////////////////////////////////////////////////////////
Joystick::Identification::Identification() :
name ("No Joystick"),
vendorId (0),
productId(0)
{
}
} // namespace sf

View File

@ -30,6 +30,7 @@
////////////////////////////////////////////////////////////
#include <SFML/Config.hpp>
#include <SFML/Window/Joystick.hpp>
#include <SFML/System/String.hpp>
#include <algorithm>
@ -38,7 +39,7 @@ namespace sf
namespace priv
{
////////////////////////////////////////////////////////////
/// \brief Structure holding a joystick's capabilities
/// \brief Structure holding a joystick's information
///
////////////////////////////////////////////////////////////
struct JoystickCaps

View File

@ -54,6 +54,13 @@ const JoystickState& JoystickManager::getState(unsigned int joystick) const
}
////////////////////////////////////////////////////////////
const Joystick::Identification& JoystickManager::getIdentification(unsigned int joystick) const
{
return m_joysticks[joystick].identification;
}
////////////////////////////////////////////////////////////
void JoystickManager::update()
{
@ -72,6 +79,7 @@ void JoystickManager::update()
item.joystick.close();
item.capabilities = JoystickCaps();
item.state = JoystickState();
item.identification = Joystick::Identification();
}
}
else
@ -83,6 +91,7 @@ void JoystickManager::update()
{
item.capabilities = item.joystick.getCapabilities();
item.state = item.joystick.update();
item.identification = item.joystick.getIdentification();
}
}
}

View File

@ -54,7 +54,7 @@ public :
static JoystickManager& getInstance();
////////////////////////////////////////////////////////////
/// \brief Get the capabilities of an open joystick
/// \brief Get the capabilities for an open joystick
///
/// \param joystick Index of the joystick
///
@ -73,6 +73,16 @@ public :
////////////////////////////////////////////////////////////
const JoystickState& getState(unsigned int joystick) const;
////////////////////////////////////////////////////////////
/// \brief Get the identification for an open joystick
///
/// \param joystick Index of the joystick
///
/// \return Identification for the joystick
///
////////////////////////////////////////////////////////////
const Joystick::Identification& getIdentification(unsigned int joystick) const;
////////////////////////////////////////////////////////////
/// \brief Update the state of all the joysticks
///
@ -102,6 +112,7 @@ private:
JoystickImpl joystick; ///< Joystick implementation
JoystickState state; ///< The current joystick state
JoystickCaps capabilities; ///< The joystick capabilities
Joystick::Identification identification; ///< The joystick identification
};
////////////////////////////////////////////////////////////

View File

@ -29,6 +29,7 @@
#include <SFML/Window/JoystickImpl.hpp>
#include <SFML/Window/OSX/HIDInputManager.hpp>
#include <SFML/Window/OSX/HIDJoystickManager.hpp>
#include <SFML/System/Err.hpp>
namespace
@ -171,6 +172,10 @@ 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));
// Get a list of all elements attached to the device.
CFArrayRef elements = IOHIDDeviceCopyMatchingElements(self,
NULL,
@ -302,6 +307,13 @@ JoystickCaps JoystickImpl::getCapabilities() const
}
////////////////////////////////////////////////////////////
Joystick::Identification JoystickImpl::getIdentification() const
{
return m_identification;
}
////////////////////////////////////////////////////////////
JoystickState JoystickImpl::update()
{
@ -397,6 +409,48 @@ 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);
}
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;
}
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

View File

@ -30,7 +30,10 @@
// Headers
////////////////////////////////////////////////////////////
#include <SFML/Window/JoystickImpl.hpp>
#include <SFML/System/String.hpp>
#include <CoreFoundation/CoreFoundation.h>
#include <IOKit/hid/IOHIDDevice.h>
#include <IOKit/hid/IOHIDKeys.h>
#include <map>
#include <vector>
@ -92,6 +95,14 @@ public :
////////////////////////////////////////////////////////////
JoystickCaps getCapabilities() const;
////////////////////////////////////////////////////////////
/// \brief Get the joystick identification
///
/// \return Joystick identification
///
////////////////////////////////////////////////////////////
Joystick::Identification getIdentification() const;
////////////////////////////////////////////////////////////
/// \brief Update the joystick and get its new state
///
@ -102,6 +113,37 @@ public :
private :
////////////////////////////////////////////////////////////
/// Get HID device property key as a string
///
/// \param ref HID device
/// \param prop Property to retrieve from the device
///
/// \return Value for the property as a string
///
////////////////////////////////////////////////////////////
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 for the propery as an unsigned int
///
////////////////////////////////////////////////////////////
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
////////////////////////////////////////////////////////////
@ -112,6 +154,7 @@ private :
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
/// For a corresponding SFML index, m_locationIDs is either some usb

View File

@ -28,11 +28,13 @@
#include <SFML/Window/JoystickImpl.hpp>
#include <SFML/System/Err.hpp>
#include <sys/inotify.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <unistd.h>
#include <errno.h>
#include <cstdio>
#include <libudev.h>
#include <sstream>
namespace
{
@ -144,7 +146,6 @@ bool JoystickImpl::isConnected(unsigned int index)
return plugged[index];
}
////////////////////////////////////////////////////////////
bool JoystickImpl::open(unsigned int index)
{
@ -160,6 +161,11 @@ bool JoystickImpl::open(unsigned int index)
// 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");
// Reset the joystick state
m_state = JoystickState();
@ -221,6 +227,13 @@ JoystickCaps JoystickImpl::getCapabilities() const
}
////////////////////////////////////////////////////////////
Joystick::Identification JoystickImpl::getIdentification() const
{
return m_identification;
}
////////////////////////////////////////////////////////////
JoystickState JoystickImpl::JoystickImpl::update()
{
@ -267,6 +280,57 @@ 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

View File

@ -30,6 +30,7 @@
////////////////////////////////////////////////////////////
#include <linux/joystick.h>
#include <fcntl.h>
#include <string>
namespace sf
@ -90,6 +91,14 @@ public :
////////////////////////////////////////////////////////////
JoystickCaps getCapabilities() const;
////////////////////////////////////////////////////////////
/// \brief Get the joystick identification
///
/// \return Joystick identification
///
////////////////////////////////////////////////////////////
Joystick::Identification getIdentification() const;
////////////////////////////////////////////////////////////
/// \brief Update the joystick and get its new state
///
@ -100,12 +109,34 @@ 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
};
} // namespace priv

View File

@ -25,11 +25,19 @@
////////////////////////////////////////////////////////////
// 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 <sstream>
#include <vector>
namespace
{
@ -107,7 +115,16 @@ bool JoystickImpl::open(unsigned int index)
m_index = JOYSTICKID1 + index;
// Store the joystick capabilities
return joyGetDevCaps(m_index, &m_caps, sizeof(m_caps)) == JOYERR_NOERROR;
bool success = joyGetDevCaps(m_index, &m_caps, sizeof(m_caps)) == JOYERR_NOERROR;
if (success)
{
m_identification.name = getDeviceName(m_index, m_caps);
m_identification.productId = m_caps.wPid;
m_identification.vendorId = m_caps.wMid;
}
return success;
}
@ -117,7 +134,6 @@ void JoystickImpl::close()
// Nothing to do
}
////////////////////////////////////////////////////////////
JoystickCaps JoystickImpl::getCapabilities() const
{
@ -140,6 +156,13 @@ JoystickCaps JoystickImpl::getCapabilities() const
}
////////////////////////////////////////////////////////////
Joystick::Identification JoystickImpl::getIdentification() const
{
return m_identification;
}
////////////////////////////////////////////////////////////
JoystickState JoystickImpl::update()
{
@ -184,6 +207,101 @@ 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, &currentKey);
if (result != ERROR_SUCCESS)
{
rootKey = HKEY_CURRENT_USER;
result = RegOpenKeyEx(rootKey, subkey.c_str(), 0, KEY_READ, &currentKey);
}
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, &currentKey);
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

View File

@ -36,7 +36,9 @@
#endif
#define _WIN32_WINDOWS 0x0501
#define _WIN32_WINNT 0x0501
#include <SFML/Window/Joystick.hpp>
#include <SFML/Window/JoystickImpl.hpp>
#include <SFML/System/String.hpp>
#include <windows.h>
#include <mmsystem.h>
#include <cmath>
@ -100,6 +102,14 @@ public :
////////////////////////////////////////////////////////////
JoystickCaps getCapabilities() const;
////////////////////////////////////////////////////////////
/// \brief Get the joystick identification
///
/// \return Joystick identification
///
////////////////////////////////////////////////////////////
Joystick::Identification getIdentification() const;
////////////////////////////////////////////////////////////
/// \brief Update the joystick and get its new state
///
@ -110,11 +120,33 @@ 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
Joystick::Identification m_identification; ///< Joystick identification
};
} // namespace priv