Implemented OSX/Joysticks and fixed some tabulations
This commit is contained in:
parent
61adc51d09
commit
535733f5c7
@ -47,7 +47,8 @@ namespace priv
|
||||
/// keyboard and mouse states. It's only purpose is
|
||||
/// to help sf::priv::InputImpl class.
|
||||
///
|
||||
/// sf::priv::JoystickImpl is not concerned by this class.
|
||||
/// HIDInputManager provides a function to get all connected joysticks
|
||||
/// to help sf::priv::JoystickImpl.
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
class HIDInputManager : NonCopyable
|
||||
@ -84,6 +85,27 @@ public :
|
||||
////////////////////////////////////////////////////////////
|
||||
bool IsMouseButtonPressed(Mouse::Button button);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief List all connected joysticks
|
||||
///
|
||||
/// \return a retained CFSetRef of IOHIDDeviceRef or NULL
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
CFSetRef CopyJoystickDevices();
|
||||
|
||||
public :
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Get the usb location ID of a given device
|
||||
///
|
||||
/// This location ID is unique and can be used a usb port identifier
|
||||
///
|
||||
/// \param device HID device to query
|
||||
/// \return the device's location ID or 0 if something went wrong
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
static long GetLocationID(IOHIDDeviceRef device);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// Try to convert a character into a SFML key code.
|
||||
///
|
||||
@ -199,7 +221,7 @@ private :
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Filter the devices and return them.
|
||||
///
|
||||
/// If something went wrong FreeUp is called
|
||||
/// FreeUp is _not_ called by this function.
|
||||
///
|
||||
/// \param page HID page like kHIDPage_GenericDesktop
|
||||
/// \param usage HID usage page like kHIDUsage_GD_Keyboard or kHIDUsage_GD_Mouse
|
||||
|
@ -84,7 +84,6 @@ bool HIDInputManager::IsKeyPressed(Keyboard::Key key)
|
||||
return state;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
bool HIDInputManager::IsMouseButtonPressed(Mouse::Button button)
|
||||
{
|
||||
@ -128,6 +127,35 @@ bool HIDInputManager::IsMouseButtonPressed(Mouse::Button button)
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
CFSetRef HIDInputManager::CopyJoystickDevices()
|
||||
{
|
||||
return CopyDevices(kHIDPage_GenericDesktop, kHIDUsage_GD_Joystick);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
long HIDInputManager::GetLocationID(IOHIDDeviceRef device)
|
||||
{
|
||||
long loc = 0;
|
||||
|
||||
// Get a unique ID : its usb location ID
|
||||
CFTypeRef typeRef = IOHIDDeviceGetProperty(device,
|
||||
CFSTR(kIOHIDLocationIDKey));
|
||||
if (!typeRef || CFGetTypeID(typeRef) != CFNumberGetTypeID()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
CFNumberRef locRef = (CFNumberRef)typeRef;
|
||||
|
||||
if (!CFNumberGetValue(locRef, kCFNumberLongType, &loc)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return loc;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
HIDInputManager::HIDInputManager()
|
||||
: amIValid(true)
|
||||
@ -198,8 +226,7 @@ void HIDInputManager::InitializeKeyboard()
|
||||
// Get only keyboards
|
||||
CFSetRef keyboards = CopyDevices(kHIDPage_GenericDesktop, kHIDUsage_GD_Keyboard);
|
||||
if (keyboards == NULL) {
|
||||
|
||||
// FreeUp was already called
|
||||
FreeUp();
|
||||
return;
|
||||
}
|
||||
|
||||
@ -234,8 +261,7 @@ void HIDInputManager::InitializeMouse()
|
||||
// Get only mouses
|
||||
CFSetRef mouses = CopyDevices(kHIDPage_GenericDesktop, kHIDUsage_GD_Mouse);
|
||||
if (mouses == NULL) {
|
||||
|
||||
// FreeUp was already called
|
||||
FreeUp();
|
||||
return;
|
||||
}
|
||||
|
||||
@ -525,17 +551,13 @@ CFSetRef HIDInputManager::CopyDevices(UInt32 page, UInt32 usage)
|
||||
|
||||
CFSetRef devices = IOHIDManagerCopyDevices(myManager);
|
||||
if (devices == NULL) {
|
||||
sf::Err() << "Cannot find any devices." << std::endl;
|
||||
FreeUp();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Is there at least one keyboard ?
|
||||
// Is there at least one device ?
|
||||
CFIndex deviceCount = CFSetGetCount(devices);
|
||||
if (deviceCount < 1) {
|
||||
sf::Err() << "Found no device." << std::endl;
|
||||
CFRelease(devices);
|
||||
FreeUp();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -27,48 +27,332 @@
|
||||
// Headers
|
||||
////////////////////////////////////////////////////////////
|
||||
#include <SFML/Window/JoystickImpl.hpp>
|
||||
|
||||
#include <SFML/Window/OSX/HIDInputManager.hpp>
|
||||
|
||||
namespace sf
|
||||
{
|
||||
namespace priv
|
||||
{
|
||||
////////////////////////////////////////////////////////////
|
||||
JoystickImpl::Location JoystickImpl::myLocationIDs[sf::Joystick::Count] = { 0 };
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
bool JoystickImpl::IsConnected(unsigned int index)
|
||||
{
|
||||
// @to be implemented
|
||||
return false;
|
||||
bool state = false; // Is the index-th joystick connected ?
|
||||
|
||||
// First, let's check if the device was previously detected :
|
||||
|
||||
if (myLocationIDs[index] != 0) {
|
||||
state = true;
|
||||
}
|
||||
|
||||
// Otherwise, let's check if it is now connected :
|
||||
else { // i.e., myLocationIDs[index] == 0
|
||||
|
||||
// Get all devices
|
||||
CFSetRef devices = HIDInputManager::GetInstance().CopyJoystickDevices();
|
||||
|
||||
if (devices != NULL) {
|
||||
|
||||
CFIndex size = CFSetGetCount(devices);
|
||||
|
||||
if (size > 0) {
|
||||
|
||||
CFTypeRef array[size]; // array of IOHIDDeviceRef
|
||||
CFSetGetValues(devices, array);
|
||||
|
||||
// If there exists a device d s.t. there is no j s.t.
|
||||
// myLocationIDs[j] == d's location then we have a new device.
|
||||
|
||||
for (CFIndex didx(0); didx < size; ++didx) {
|
||||
IOHIDDeviceRef d = (IOHIDDeviceRef)array[didx];
|
||||
Location dloc = HIDInputManager::GetLocationID(d);
|
||||
|
||||
bool foundJ = false;
|
||||
for (unsigned int j(0); j < Joystick::Count; ++j) {
|
||||
if (myLocationIDs[j] == dloc) {
|
||||
foundJ = true;
|
||||
break; // no need to loop again
|
||||
}
|
||||
}
|
||||
|
||||
if (foundJ) {
|
||||
// This is a known device
|
||||
// Nothing else to do
|
||||
} else {
|
||||
// This is a new device
|
||||
// We set it up for Open(..)
|
||||
myLocationIDs[index] = dloc;
|
||||
state = true;
|
||||
break; // We stop looking for a new device
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
CFRelease(devices);
|
||||
}
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
bool JoystickImpl::Open(unsigned int index)
|
||||
{
|
||||
// @to be implemented
|
||||
myIndex = index;
|
||||
Location deviceLoc = myLocationIDs[index]; // The device we need to load
|
||||
|
||||
// Get all devices
|
||||
CFSetRef devices = HIDInputManager::GetInstance().CopyJoystickDevices();
|
||||
if (devices == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get a usable copy of the joysticks devices.
|
||||
CFIndex joysticksCount = CFSetGetCount(devices);
|
||||
CFTypeRef devicesArray[joysticksCount];
|
||||
CFSetGetValues(devices, devicesArray);
|
||||
|
||||
// Get the desired joystick.
|
||||
IOHIDDeviceRef self = 0;
|
||||
for (CFIndex i(0); i < joysticksCount; ++i) {
|
||||
IOHIDDeviceRef d = (IOHIDDeviceRef)devicesArray[i];
|
||||
if (deviceLoc == HIDInputManager::GetLocationID(d)) {
|
||||
self = d;
|
||||
break; // We found it so we stop looping.
|
||||
}
|
||||
}
|
||||
|
||||
if (self == 0) {
|
||||
// This shouldn't happen!
|
||||
CFRelease(devices);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get a list of all elements attached to the device.
|
||||
CFArrayRef elements = IOHIDDeviceCopyMatchingElements(self,
|
||||
NULL,
|
||||
kIOHIDOptionsTypeNone);
|
||||
|
||||
if (elements == NULL) {
|
||||
CFRelease(devices);
|
||||
return false;
|
||||
}
|
||||
|
||||
// How many elements are there ?
|
||||
CFIndex elementsCount = CFArrayGetCount(elements);
|
||||
|
||||
if (elementsCount == 0) {
|
||||
// What is a joystick with no element ?
|
||||
CFRelease(elements);
|
||||
CFRelease(devices);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Go through all connected elements.
|
||||
for (int i = 0; i < elementsCount; ++i) {
|
||||
IOHIDElementRef element = (IOHIDElementRef) CFArrayGetValueAtIndex(elements, i);
|
||||
|
||||
switch (IOHIDElementGetType(element)) {
|
||||
|
||||
case kIOHIDElementTypeInput_Misc:
|
||||
switch (IOHIDElementGetUsage(element)) {
|
||||
|
||||
case kHIDUsage_GD_X:
|
||||
myAxis[Joystick::X] = element;
|
||||
break;
|
||||
|
||||
case kHIDUsage_GD_Y:
|
||||
myAxis[Joystick::Y] = element;
|
||||
break;
|
||||
|
||||
case kHIDUsage_GD_Z:
|
||||
myAxis[Joystick::Z] = element;
|
||||
break;
|
||||
|
||||
case kHIDUsage_GD_Rx:
|
||||
myAxis[Joystick::U] = element;
|
||||
break;
|
||||
|
||||
case kHIDUsage_GD_Ry:
|
||||
myAxis[Joystick::V] = element;
|
||||
break;
|
||||
|
||||
case kHIDUsage_GD_Rz:
|
||||
myAxis[Joystick::R] = element;
|
||||
break;
|
||||
|
||||
// kHIDUsage_GD_Vx, kHIDUsage_GD_Vy, kHIDUsage_GD_Vz are ignored.
|
||||
}
|
||||
break;
|
||||
|
||||
case kIOHIDElementTypeInput_Button:
|
||||
if (myButtons.size() < Joystick::ButtonCount) { // If we have free slot...
|
||||
myButtons.push_back(element); // ...we add this element to the list
|
||||
} else {
|
||||
// Too many buttons. We ignore this one.
|
||||
}
|
||||
break;
|
||||
|
||||
default: // Make compiler happy
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Note : Joy::AxisPovX/Y are not supported (yet).
|
||||
// Maybe kIOHIDElementTypeInput_Axis is the corresponding type but I can't test.
|
||||
|
||||
// Retain all these objets for personal use
|
||||
for (ButtonsVector::iterator it(myButtons.begin()); it != myButtons.end(); ++it) {
|
||||
CFRetain(*it);
|
||||
}
|
||||
for (AxisMap::iterator it(myAxis.begin()); it != myAxis.end(); ++it) {
|
||||
CFRetain(it->second);
|
||||
}
|
||||
|
||||
// Note : we didn't retain element in the switch because we might have multiple
|
||||
// Axis X (for example) and we want to keep only the last one. So to prevent
|
||||
// leaking we retain objects 'only' now.
|
||||
|
||||
CFRelease(devices);
|
||||
CFRelease(elements);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void JoystickImpl::Close()
|
||||
{
|
||||
// @to be implemented
|
||||
for (ButtonsVector::iterator it(myButtons.begin()); it != myButtons.end(); ++it) {
|
||||
CFRelease(*it);
|
||||
}
|
||||
myButtons.clear();
|
||||
|
||||
for (AxisMap::iterator it(myAxis.begin()); it != myAxis.end(); ++it) {
|
||||
CFRelease(it->second);
|
||||
}
|
||||
myAxis.clear();
|
||||
|
||||
// And we unregister this joystick
|
||||
myLocationIDs[myIndex] = 0;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
JoystickCaps JoystickImpl::GetCapabilities() const
|
||||
{
|
||||
// @to be implemented
|
||||
return JoystickCaps();
|
||||
JoystickCaps caps;
|
||||
|
||||
// Buttons :
|
||||
caps.ButtonCount = myButtons.size();
|
||||
|
||||
// Axis :
|
||||
for (AxisMap::const_iterator it(myAxis.begin()); it != myAxis.end(); ++it) {
|
||||
caps.Axes[it->first] = true;
|
||||
}
|
||||
|
||||
return caps;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
JoystickState JoystickImpl::Update()
|
||||
{
|
||||
// @to be implemented
|
||||
return JoystickState();
|
||||
static const JoystickState disconnectedState; // return this if joystick was disconnected
|
||||
JoystickState state; // otherwise return that
|
||||
state.Connected = true;
|
||||
|
||||
// Note : free up is done in Close() which is called, if required,
|
||||
// by the joystick manager. So we don't release buttons nor axes here.
|
||||
|
||||
// First, let's determine if the joystick is still connected
|
||||
Location selfLoc = myLocationIDs[myIndex];
|
||||
|
||||
// Get all devices
|
||||
CFSetRef devices = HIDInputManager::GetInstance().CopyJoystickDevices();
|
||||
if (devices == NULL) {
|
||||
return disconnectedState;
|
||||
}
|
||||
|
||||
// Get a usable copy of the joysticks devices.
|
||||
CFIndex joysticksCount = CFSetGetCount(devices);
|
||||
CFTypeRef devicesArray[joysticksCount];
|
||||
CFSetGetValues(devices, devicesArray);
|
||||
|
||||
// Search for it
|
||||
bool found = false;
|
||||
for (CFIndex i(0); i < joysticksCount; ++i) {
|
||||
IOHIDDeviceRef d = (IOHIDDeviceRef)devicesArray[i];
|
||||
if (selfLoc == HIDInputManager::GetLocationID(d)) {
|
||||
found = true;
|
||||
break; // Stop looping
|
||||
}
|
||||
}
|
||||
|
||||
// Release unused stuff
|
||||
CFRelease(devices);
|
||||
|
||||
// Was it found ?
|
||||
if (found) {
|
||||
// Yes, so we can continue.
|
||||
} else {
|
||||
// No, so we stop here
|
||||
return disconnectedState;
|
||||
}
|
||||
|
||||
// Update buttons' state
|
||||
unsigned int i = 0;
|
||||
for (ButtonsVector::iterator it(myButtons.begin()); it != myButtons.end(); ++it, ++i) {
|
||||
IOHIDValueRef value = 0;
|
||||
IOHIDDeviceGetValue(IOHIDElementGetDevice(*it), *it, &value);
|
||||
|
||||
// Check for plug out.
|
||||
if (!value) {
|
||||
// No value ? Hum... Seems like the joystick is gone
|
||||
return disconnectedState;
|
||||
}
|
||||
|
||||
// 1 means pressed, others mean released
|
||||
state.Buttons[i] = IOHIDValueGetIntegerValue(value) == 1;
|
||||
}
|
||||
|
||||
// Update axes' state
|
||||
for (AxisMap::iterator it = myAxis.begin(); it != myAxis.end(); ++it) {
|
||||
IOHIDValueRef value = 0;
|
||||
IOHIDDeviceGetValue(IOHIDElementGetDevice(it->second), it->second, &value);
|
||||
|
||||
// Check for plug out.
|
||||
if (!value) {
|
||||
// No value ? Hum... Seems like the joystick is gone
|
||||
return disconnectedState;
|
||||
}
|
||||
|
||||
// We want to bind [physicalMin,physicalMax] to [-100=min,100=max].
|
||||
//
|
||||
// General formula to bind [a,b] to [c,d] with a linear progression :
|
||||
//
|
||||
// f : [a, b] -> [c, d]
|
||||
// x |-> (x-a)(d-c)/(b-a)+c
|
||||
//
|
||||
// This method might not be very accurate (the "0 position" can be
|
||||
// slightly shift with some device) but we don't care because most
|
||||
// of devices are so sensitive that this is not relevant.
|
||||
double physicalMax = IOHIDElementGetPhysicalMax(it->second);
|
||||
double physicalMin = IOHIDElementGetPhysicalMin(it->second);
|
||||
double scaledMin = -100;
|
||||
double scaledMax = 100;
|
||||
double physicalValue = IOHIDValueGetScaledValue(value, kIOHIDValueScaleTypePhysical);
|
||||
float scaledValue = ((physicalValue - physicalMin) * (scaledMax - scaledMin) / (physicalMax - physicalMin)) + scaledMin;
|
||||
state.Axes[it->first] = scaledValue;
|
||||
}
|
||||
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
} // namespace priv
|
||||
|
@ -30,7 +30,9 @@
|
||||
// Headers
|
||||
////////////////////////////////////////////////////////////
|
||||
#include <SFML/Window/JoystickImpl.hpp>
|
||||
|
||||
#include <IOKit/hid/IOHIDDevice.h>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
namespace sf
|
||||
{
|
||||
@ -91,6 +93,17 @@ private :
|
||||
////////////////////////////////////////////////////////////
|
||||
// Member data
|
||||
////////////////////////////////////////////////////////////
|
||||
typedef long Location;
|
||||
typedef std::map<sf::Joystick::Axis, IOHIDElementRef> AxisMap;
|
||||
typedef std::vector<IOHIDElementRef> ButtonsVector;
|
||||
|
||||
AxisMap myAxis; ///< Axis (IOHIDElementRef) connected to the joystick
|
||||
ButtonsVector myButtons; ///< Buttons (IOHIDElementRef) connected to the joystick
|
||||
unsigned int myIndex; ///< SFML index
|
||||
|
||||
static Location myLocationIDs[sf::Joystick::Count]; ///< Global Joystick register
|
||||
/// For a corresponding SFML index, myLocationIDs is either some usb
|
||||
/// location or 0 if there isn't currently a connected joystick device
|
||||
};
|
||||
|
||||
} // namespace priv
|
||||
|
Loading…
Reference in New Issue
Block a user