Added support for (some) Hat/POV axis
This commit is contained in:
parent
dd307cc23e
commit
883ec9391d
@ -147,19 +147,16 @@ bool JoystickImpl::isConnected(unsigned int index)
|
|||||||
// If there exists a device d s.t. there is no j s.t.
|
// If there exists a device d s.t. there is no j s.t.
|
||||||
// m_locationIDs[j] == d's location then we have a new device.
|
// m_locationIDs[j] == d's location then we have a new device.
|
||||||
|
|
||||||
for (CFIndex didx(0); didx < size; ++didx)
|
for (CFIndex didx(0); !state && didx < size; ++didx)
|
||||||
{
|
{
|
||||||
IOHIDDeviceRef d = (IOHIDDeviceRef)array[didx];
|
IOHIDDeviceRef d = (IOHIDDeviceRef)array[didx];
|
||||||
Location dloc = HIDInputManager::getLocationID(d);
|
Location dloc = HIDInputManager::getLocationID(d);
|
||||||
|
|
||||||
bool foundJ = false;
|
bool foundJ = false;
|
||||||
for (unsigned int j(0); j < Joystick::Count; ++j)
|
for (unsigned int j(0); !foundJ && j < Joystick::Count; ++j)
|
||||||
{
|
{
|
||||||
if (m_locationIDs[j] == dloc)
|
if (m_locationIDs[j] == dloc)
|
||||||
{
|
|
||||||
foundJ = true;
|
foundJ = true;
|
||||||
break; // no need to loop again
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!foundJ) {
|
if (!foundJ) {
|
||||||
@ -167,7 +164,6 @@ bool JoystickImpl::isConnected(unsigned int index)
|
|||||||
// We set it up for Open(..)
|
// We set it up for Open(..)
|
||||||
m_locationIDs[index] = dloc;
|
m_locationIDs[index] = dloc;
|
||||||
state = true;
|
state = true;
|
||||||
break; // We stop looking for a new device
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -185,6 +181,7 @@ bool JoystickImpl::isConnected(unsigned int index)
|
|||||||
bool JoystickImpl::open(unsigned int index)
|
bool JoystickImpl::open(unsigned int index)
|
||||||
{
|
{
|
||||||
m_index = index;
|
m_index = index;
|
||||||
|
m_hat = NULL;
|
||||||
Location deviceLoc = m_locationIDs[index]; // The device we need to load
|
Location deviceLoc = m_locationIDs[index]; // The device we need to load
|
||||||
|
|
||||||
// Get all devices
|
// Get all devices
|
||||||
@ -199,19 +196,15 @@ bool JoystickImpl::open(unsigned int index)
|
|||||||
|
|
||||||
// Get the desired joystick.
|
// Get the desired joystick.
|
||||||
IOHIDDeviceRef self = 0;
|
IOHIDDeviceRef self = 0;
|
||||||
for (CFIndex i(0); i < joysticksCount; ++i)
|
for (CFIndex i(0); self == 0 && i < joysticksCount; ++i)
|
||||||
{
|
{
|
||||||
IOHIDDeviceRef d = (IOHIDDeviceRef)devicesArray[i];
|
IOHIDDeviceRef d = (IOHIDDeviceRef)devicesArray[i];
|
||||||
if (deviceLoc == HIDInputManager::getLocationID(d))
|
if (deviceLoc == HIDInputManager::getLocationID(d))
|
||||||
{
|
|
||||||
self = d;
|
self = d;
|
||||||
break; // We found it so we stop looping.
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (self == 0)
|
if (self == 0)
|
||||||
{
|
{
|
||||||
// This shouldn't happen!
|
|
||||||
CFRelease(devices);
|
CFRelease(devices);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -229,24 +222,14 @@ bool JoystickImpl::open(unsigned int index)
|
|||||||
return false;
|
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.
|
// Go through all connected elements.
|
||||||
|
CFIndex elementsCount = CFArrayGetCount(elements);
|
||||||
for (int i = 0; i < elementsCount; ++i)
|
for (int i = 0; i < elementsCount; ++i)
|
||||||
{
|
{
|
||||||
IOHIDElementRef element = (IOHIDElementRef) CFArrayGetValueAtIndex(elements, i);
|
IOHIDElementRef element = (IOHIDElementRef) CFArrayGetValueAtIndex(elements, i);
|
||||||
switch (IOHIDElementGetType(element))
|
switch (IOHIDElementGetUsagePage(element))
|
||||||
{
|
{
|
||||||
case kIOHIDElementTypeInput_Misc:
|
case kHIDPage_GenericDesktop:
|
||||||
switch (IOHIDElementGetUsage(element))
|
switch (IOHIDElementGetUsage(element))
|
||||||
{
|
{
|
||||||
case kHIDUsage_GD_X: m_axis[Joystick::X] = element; break;
|
case kHIDUsage_GD_X: m_axis[Joystick::X] = element; break;
|
||||||
@ -255,19 +238,64 @@ bool JoystickImpl::open(unsigned int index)
|
|||||||
case kHIDUsage_GD_Rx: m_axis[Joystick::U] = element; break;
|
case kHIDUsage_GD_Rx: m_axis[Joystick::U] = element; break;
|
||||||
case kHIDUsage_GD_Ry: m_axis[Joystick::V] = element; break;
|
case kHIDUsage_GD_Ry: m_axis[Joystick::V] = element; break;
|
||||||
case kHIDUsage_GD_Rz: m_axis[Joystick::R] = element; break;
|
case kHIDUsage_GD_Rz: m_axis[Joystick::R] = element; break;
|
||||||
default: break;
|
|
||||||
// kHIDUsage_GD_Vx, kHIDUsage_GD_Vy, kHIDUsage_GD_Vz are ignored.
|
case kHIDUsage_GD_Hatswitch:
|
||||||
|
// From §4.3 MiscellaneousControls of HUT v1.12:
|
||||||
|
//
|
||||||
|
// > Hat Switch:
|
||||||
|
// > A typical example is four switches that are capable of generating
|
||||||
|
// > information about four possible directions in which the knob can be
|
||||||
|
// > tilted. Intermediate positions can also be decoded if the hardware
|
||||||
|
// > allows two switches to be reported simultaneously.
|
||||||
|
//
|
||||||
|
// We assume this model here as well. Hence, with 4 switches and intermediate
|
||||||
|
// positions we have 8 values (0-7) plus the "null" state (8).
|
||||||
|
{
|
||||||
|
CFIndex min = IOHIDElementGetLogicalMin(element);
|
||||||
|
CFIndex max = IOHIDElementGetLogicalMax(element);
|
||||||
|
|
||||||
|
if (min != 0 || max != 7)
|
||||||
|
{
|
||||||
|
sf::err() << std::hex
|
||||||
|
<< "Joystick (vendor/product id: 0x" << m_identification.vendorId
|
||||||
|
<< "/0x" << m_identification.productId << std::dec
|
||||||
|
<< ") range is an unexpected one: [" << min << ", " << max << "]"
|
||||||
|
<< std::endl;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_hat = element;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case kIOHIDElementTypeInput_Button:
|
case kHIDUsage_GD_GamePad:
|
||||||
|
// We assume a game pad is an application collection, meaning it doesn't hold
|
||||||
|
// any values per say. They kind of "emit" the joystick's usages.
|
||||||
|
// See §3.4.3 Usage Types (Collection) of HUT v1.12
|
||||||
|
if (IOHIDElementGetCollectionType(element) != kIOHIDElementCollectionTypeApplication)
|
||||||
|
{
|
||||||
|
sf::err() << std::hex << "Gamepage (vendor/product id: 0x" << m_identification.vendorId
|
||||||
|
<< "/0x" << m_identification.productId << ") is not an CA but a 0x"
|
||||||
|
<< IOHIDElementGetCollectionType(element) << std::dec << std::endl;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
#ifdef SFML_DEBUG
|
||||||
|
sf::err() << "Unexpected usage for element of Page Generic Desktop: 0x" << std::hex << IOHIDElementGetUsage(element) << std::dec << std::endl;
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case kHIDPage_Button:
|
||||||
if (m_buttons.size() < Joystick::ButtonCount) // If we have free slot...
|
if (m_buttons.size() < Joystick::ButtonCount) // If we have free slot...
|
||||||
m_buttons.push_back(element); // ...we add this element to the list
|
m_buttons.push_back(element); // ...we add this element to the list
|
||||||
// Else: too many buttons. We ignore this one.
|
// Else: too many buttons. We ignore this one.
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default: // Make compiler happy
|
default: /* No other page is expected because of the mask applied by the HID manager. */ break;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -275,17 +303,16 @@ bool JoystickImpl::open(unsigned int index)
|
|||||||
// HID Usage (assigned by manufacturer and/or a driver).
|
// HID Usage (assigned by manufacturer and/or a driver).
|
||||||
std::sort(m_buttons.begin(), m_buttons.end(), JoystickButtonSortPredicate);
|
std::sort(m_buttons.begin(), m_buttons.end(), JoystickButtonSortPredicate);
|
||||||
|
|
||||||
// Note: Joy::AxisPovX/Y are not supported (yet).
|
|
||||||
// Maybe kIOHIDElementTypeInput_Axis is the corresponding type but I can't test.
|
|
||||||
|
|
||||||
// Retain all these objects for personal use
|
// Retain all these objects for personal use
|
||||||
for (ButtonsVector::iterator it(m_buttons.begin()); it != m_buttons.end(); ++it)
|
for (ButtonsVector::iterator it(m_buttons.begin()); it != m_buttons.end(); ++it)
|
||||||
CFRetain(*it);
|
CFRetain(*it);
|
||||||
for (AxisMap::iterator it(m_axis.begin()); it != m_axis.end(); ++it)
|
for (AxisMap::iterator it(m_axis.begin()); it != m_axis.end(); ++it)
|
||||||
CFRetain(it->second);
|
CFRetain(it->second);
|
||||||
|
if (m_hat != NULL)
|
||||||
|
CFRetain(m_hat);
|
||||||
|
|
||||||
// Note: we didn't retain element in the switch because we might have multiple
|
// 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
|
// Axis X (for example) and we want to keep only the last one. To prevent
|
||||||
// leaking we retain objects 'only' now.
|
// leaking we retain objects 'only' now.
|
||||||
|
|
||||||
CFRelease(devices);
|
CFRelease(devices);
|
||||||
@ -306,6 +333,10 @@ void JoystickImpl::close()
|
|||||||
CFRelease(it->second);
|
CFRelease(it->second);
|
||||||
m_axis.clear();
|
m_axis.clear();
|
||||||
|
|
||||||
|
if (m_hat != NULL)
|
||||||
|
CFRelease(m_hat);
|
||||||
|
m_hat = NULL;
|
||||||
|
|
||||||
// And we unregister this joystick
|
// And we unregister this joystick
|
||||||
m_locationIDs[m_index] = 0;
|
m_locationIDs[m_index] = 0;
|
||||||
}
|
}
|
||||||
@ -320,9 +351,11 @@ JoystickCaps JoystickImpl::getCapabilities() const
|
|||||||
caps.buttonCount = m_buttons.size();
|
caps.buttonCount = m_buttons.size();
|
||||||
|
|
||||||
// Axis:
|
// Axis:
|
||||||
for (AxisMap::const_iterator it(m_axis.begin()); it != m_axis.end(); ++it) {
|
for (AxisMap::const_iterator it(m_axis.begin()); it != m_axis.end(); ++it)
|
||||||
caps.axes[it->first] = true;
|
caps.axes[it->first] = true;
|
||||||
}
|
|
||||||
|
if (m_hat != NULL)
|
||||||
|
caps.axes[Joystick::PovX] = caps.axes[Joystick::PovY] = true;
|
||||||
|
|
||||||
return caps;
|
return caps;
|
||||||
}
|
}
|
||||||
@ -360,14 +393,11 @@ JoystickState JoystickImpl::update()
|
|||||||
|
|
||||||
// Search for it
|
// Search for it
|
||||||
bool found = false;
|
bool found = false;
|
||||||
for (CFIndex i(0); i < joysticksCount; ++i)
|
for (CFIndex i(0); !found && i < joysticksCount; ++i)
|
||||||
{
|
{
|
||||||
IOHIDDeviceRef d = (IOHIDDeviceRef)devicesArray[i];
|
IOHIDDeviceRef d = (IOHIDDeviceRef)devicesArray[i];
|
||||||
if (selfLoc == HIDInputManager::getLocationID(d))
|
if (selfLoc == HIDInputManager::getLocationID(d))
|
||||||
{
|
|
||||||
found = true;
|
found = true;
|
||||||
break; // Stop looping
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Release unused stuff
|
// Release unused stuff
|
||||||
@ -387,7 +417,6 @@ JoystickState JoystickImpl::update()
|
|||||||
// Check for plug out.
|
// Check for plug out.
|
||||||
if (!value)
|
if (!value)
|
||||||
{
|
{
|
||||||
// No value? Hum... Seems like the joystick is gone
|
|
||||||
return disconnectedState;
|
return disconnectedState;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -404,7 +433,6 @@ JoystickState JoystickImpl::update()
|
|||||||
// Check for plug out.
|
// Check for plug out.
|
||||||
if (!value)
|
if (!value)
|
||||||
{
|
{
|
||||||
// No value? Hum... Seems like the joystick is gone
|
|
||||||
return disconnectedState;
|
return disconnectedState;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -427,9 +455,70 @@ JoystickState JoystickImpl::update()
|
|||||||
state.axes[it->first] = scaledValue;
|
state.axes[it->first] = scaledValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Update POV/Hat state. Assuming model described in `open`, values are:
|
||||||
|
//
|
||||||
|
// North-West / 7 North / 0 North-East / 1
|
||||||
|
// West / 6 Null / 8 East / 2
|
||||||
|
// South-West / 5 South / 4 South-East / 3
|
||||||
|
//
|
||||||
|
if (m_hat != NULL)
|
||||||
|
{
|
||||||
|
IOHIDValueRef value = 0;
|
||||||
|
IOHIDDeviceGetValue(IOHIDElementGetDevice(m_hat), m_hat, &value);
|
||||||
|
|
||||||
|
// Check for plug out.
|
||||||
|
if (!value)
|
||||||
|
{
|
||||||
|
return disconnectedState;
|
||||||
|
}
|
||||||
|
|
||||||
|
CFIndex raw = IOHIDValueGetIntegerValue(value);
|
||||||
|
|
||||||
|
// Load PovX
|
||||||
|
switch (raw)
|
||||||
|
{
|
||||||
|
case 1:
|
||||||
|
case 2:
|
||||||
|
case 3:
|
||||||
|
state.axes[Joystick::PovX] = +100;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 5:
|
||||||
|
case 6:
|
||||||
|
case 7:
|
||||||
|
state.axes[Joystick::PovX] = -100;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
state.axes[Joystick::PovX] = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load PovY
|
||||||
|
switch (raw)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
case 1:
|
||||||
|
case 7:
|
||||||
|
state.axes[Joystick::PovY] = +100;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 3:
|
||||||
|
case 4:
|
||||||
|
case 5:
|
||||||
|
state.axes[Joystick::PovY] = -100;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
state.axes[Joystick::PovY] = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace priv
|
} // namespace priv
|
||||||
|
|
||||||
} // namespace sf
|
} // namespace sf
|
||||||
|
|
||||||
|
@ -120,8 +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; ///< Axes (but not POV/Hat) of the joystick
|
||||||
ButtonsVector m_buttons; ///< Buttons (IOHIDElementRef) connected to the joystick
|
IOHIDElementRef m_hat; ///< POV/Hat axis of the joystick
|
||||||
|
ButtonsVector m_buttons; ///< Buttons of 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
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user