Improved OSX/Joysticks performance

This commit is contained in:
Marco Antognini 2011-07-28 02:10:35 +02:00
parent b93e980e27
commit 732b789e2e
7 changed files with 340 additions and 86 deletions

View File

@ -71,6 +71,8 @@ else() # MACOSX
${SRCROOT}/OSX/InputImpl.hpp
${SRCROOT}/OSX/HIDInputManager.hpp
${SRCROOT}/OSX/HIDInputManager.mm
${SRCROOT}/OSX/HIDJoystickManager.hpp
${SRCROOT}/OSX/HIDJoystickManager.cpp
${SRCROOT}/OSX/JoystickImpl.cpp
${SRCROOT}/OSX/JoystickImpl.hpp
${SRCROOT}/OSX/SFApplication.h

View File

@ -47,9 +47,6 @@ namespace priv
/// keyboard and mouse states. It's only purpose is
/// to help sf::priv::InputImpl class.
///
/// HIDInputManager provides a function to get all connected joysticks
/// to help sf::priv::JoystickImpl.
///
////////////////////////////////////////////////////////////
class HIDInputManager : NonCopyable
{
@ -85,14 +82,6 @@ public :
////////////////////////////////////////////////////////////
bool IsMouseButtonPressed(Mouse::Button button);
////////////////////////////////////////////////////////////
/// \brief List all connected joysticks
///
/// \return a retained CFSetRef of IOHIDDeviceRef or NULL
///
////////////////////////////////////////////////////////////
CFSetRef CopyJoystickDevices();
public :
////////////////////////////////////////////////////////////
@ -106,6 +95,16 @@ public :
////////////////////////////////////////////////////////////
static long GetLocationID(IOHIDDeviceRef device);
////////////////////////////////////////////////////////////
/// \brief Create a mask (dictionary) for an IOHIDManager
///
/// \param page HID page
/// \param usage HID usage page
/// \return a retained CFDictionaryRef
///
////////////////////////////////////////////////////////////
static CFDictionaryRef CopyDevicesMask(UInt32 page, UInt32 usage);
////////////////////////////////////////////////////////////
/// Try to convert a character into a SFML key code.
///
@ -208,16 +207,6 @@ private :
////////////////////////////////////////////////////////////
void FreeUp();
////////////////////////////////////////////////////////////
/// \brief Create a mask (dictionary) for an IOHIDManager
///
/// \param page HID page
/// \param usage HID usage page
/// \return a retained CFDictionaryRef
///
////////////////////////////////////////////////////////////
static CFDictionaryRef CopyDevicesMaskForManager(UInt32 page, UInt32 usage);
////////////////////////////////////////////////////////////
/// \brief Filter the devices and return them.
///

View File

@ -127,13 +127,6 @@ bool HIDInputManager::IsMouseButtonPressed(Mouse::Button button)
}
////////////////////////////////////////////////////////////
CFSetRef HIDInputManager::CopyJoystickDevices()
{
return CopyDevices(kHIDPage_GenericDesktop, kHIDUsage_GD_Joystick);
}
////////////////////////////////////////////////////////////
long HIDInputManager::GetLocationID(IOHIDDeviceRef device)
{
@ -156,6 +149,28 @@ long HIDInputManager::GetLocationID(IOHIDDeviceRef device)
}
////////////////////////////////////////////////////////////
CFDictionaryRef HIDInputManager::CopyDevicesMask(UInt32 page, UInt32 usage)
{
// Create the dictionary.
CFMutableDictionaryRef dict = CFDictionaryCreateMutable(kCFAllocatorDefault, 2,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
// Add the page value.
CFNumberRef value = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &page);
CFDictionarySetValue(dict, CFSTR(kIOHIDDeviceUsagePageKey), value);
CFRelease(value);
// Add the usage value (which is only valid if page value exists).
value = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &usage);
CFDictionarySetValue(dict, CFSTR(kIOHIDDeviceUsageKey), value);
CFRelease(value);
return dict;
}
////////////////////////////////////////////////////////////
HIDInputManager::HIDInputManager()
: amIValid(true)
@ -516,33 +531,11 @@ void HIDInputManager::FreeUp()
}
////////////////////////////////////////////////////////////
CFDictionaryRef HIDInputManager::CopyDevicesMaskForManager(UInt32 page, UInt32 usage)
{
// Create the dictionary.
CFMutableDictionaryRef dict = CFDictionaryCreateMutable(kCFAllocatorDefault, 2,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
// Add the page value.
CFNumberRef value = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &page);
CFDictionarySetValue(dict, CFSTR(kIOHIDDeviceUsagePageKey), value);
CFRelease(value);
// Add the usage value (which is only valid if page value exists).
value = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &usage);
CFDictionarySetValue(dict, CFSTR(kIOHIDDeviceUsageKey), value);
CFRelease(value);
return dict;
}
////////////////////////////////////////////////////////////
CFSetRef HIDInputManager::CopyDevices(UInt32 page, UInt32 usage)
{
// Filter and keep only the requested devices
CFDictionaryRef mask = CopyDevicesMaskForManager(page, usage);
CFDictionaryRef mask = CopyDevicesMask(page, usage);
IOHIDManagerSetDeviceMatching(myManager, mask);

View File

@ -0,0 +1,127 @@
////////////////////////////////////////////////////////////
//
// SFML - Simple and Fast Multimedia Library
// Copyright (C) 2007-2011 Marco Antognini (antognini.marco@gmail.com),
// Laurent Gomila (laurent.gom@gmail.com),
//
// This software is provided 'as-is', without any express or implied warranty.
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it freely,
// subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented;
// you must not claim that you wrote the original software.
// If you use this software in a product, an acknowledgment
// in the product documentation would be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such,
// and must not be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source distribution.
//
////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////
// Headers
////////////////////////////////////////////////////////////
#include <SFML/Window/OSX/HIDJoystickManager.hpp>
#include <SFML/Window/OSX/HIDInputManager.hpp>
namespace sf
{
namespace priv
{
////////////////////////////////////////////////////////////
HIDJoystickManager& HIDJoystickManager::GetInstance()
{
static HIDJoystickManager manager;
return manager;
}
////////////////////////////////////////////////////////////
unsigned int HIDJoystickManager::GetJoystickCount()
{
Update();
return myJoystickCount;
}
////////////////////////////////////////////////////////////
CFSetRef HIDJoystickManager::CopyJoysticks()
{
CFSetRef devices = IOHIDManagerCopyDevices(myHIDManager);
return devices;
}
////////////////////////////////////////////////////////////
HIDJoystickManager::HIDJoystickManager()
: myHIDManager(0)
, myJoystickCount(0)
{
myHIDManager = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone);
CFDictionaryRef mask = HIDInputManager::CopyDevicesMask(kHIDPage_GenericDesktop,
kHIDUsage_GD_Joystick);
IOHIDManagerSetDeviceMatching(myHIDManager, mask);
CFRelease(mask);
IOHIDManagerRegisterDeviceMatchingCallback(myHIDManager, pluggedIn, this);
IOHIDManagerRegisterDeviceRemovalCallback(myHIDManager, pluggedOut, this);
IOHIDManagerScheduleWithRunLoop(myHIDManager,
CFRunLoopGetCurrent(),
kCFRunLoopDefaultMode);
IOHIDManagerOpen(myHIDManager, kIOHIDOptionsTypeNone);
}
////////////////////////////////////////////////////////////
HIDJoystickManager::~HIDJoystickManager()
{
IOHIDManagerUnscheduleFromRunLoop(myHIDManager,
CFRunLoopGetCurrent(),
kCFRunLoopDefaultMode);
IOHIDManagerRegisterDeviceMatchingCallback(myHIDManager, NULL, 0);
IOHIDManagerRegisterDeviceRemovalCallback(myHIDManager, NULL, 0);
IOHIDManagerClose(myHIDManager, kIOHIDOptionsTypeNone);
}
////////////////////////////////////////////////////////////
void HIDJoystickManager::Update()
{
SInt32 status = kCFRunLoopRunHandledSource;
while (status == kCFRunLoopRunHandledSource) {
status = CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, true);
}
}
////////////////////////////////////////////////////////////
void HIDJoystickManager::pluggedIn(void * context, IOReturn, void *, IOHIDDeviceRef)
{
HIDJoystickManager* manager = (HIDJoystickManager*)context;
manager->myJoystickCount++;
}
////////////////////////////////////////////////////////////
void HIDJoystickManager::pluggedOut(void * context, IOReturn, void *, IOHIDDeviceRef)
{
HIDJoystickManager* manager = (HIDJoystickManager*)context;
manager->myJoystickCount--;
}
} // namespace priv
} // namespace sf

View File

@ -0,0 +1,128 @@
////////////////////////////////////////////////////////////
//
// SFML - Simple and Fast Multimedia Library
// Copyright (C) 2007-2011 Marco Antognini (antognini.marco@gmail.com),
// Laurent Gomila (laurent.gom@gmail.com),
//
// This software is provided 'as-is', without any express or implied warranty.
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it freely,
// subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented;
// you must not claim that you wrote the original software.
// If you use this software in a product, an acknowledgment
// in the product documentation would be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such,
// and must not be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source distribution.
//
////////////////////////////////////////////////////////////
#ifndef SFML_HIDJOYSTICKMANAGER_HPP
#define SFML_HIDJOYSTICKMANAGER_HPP
////////////////////////////////////////////////////////////
// Headers
////////////////////////////////////////////////////////////
#include <SFML/System/NonCopyable.hpp>
#include <IOKit/hid/IOHIDManager.h>
#include <IOKit/hid/IOHIDDevice.h>
namespace sf
{
namespace priv
{
////////////////////////////////////////////////////////////
/// \brief This class manage as a singleton instance the
/// joysticks. It's only purpose is
/// to help sf::priv::JoystickImpl class.
///
////////////////////////////////////////////////////////////
class HIDJoystickManager : NonCopyable
{
public:
////////////////////////////////////////////////////////////
/// \brief Get the unique instance of the class
///
/// \note Private use only
///
/// \return Reference to the HIDJoystickManager instance
///
////////////////////////////////////////////////////////////
static HIDJoystickManager& GetInstance();
public:
////////////////////////////////////////////////////////////
/// \brief Get the number of currently connected joystick
///
////////////////////////////////////////////////////////////
unsigned int GetJoystickCount();
////////////////////////////////////////////////////////////
/// \brief Copy the devices assosiated with this HID manager
///
/// \return a retained CFSetRef of IOHIDDeviceRef or NULL
///
////////////////////////////////////////////////////////////
CFSetRef CopyJoysticks();
private:
////////////////////////////////////////////////////////////
/// \brief Default constructor
///
////////////////////////////////////////////////////////////
HIDJoystickManager();
////////////////////////////////////////////////////////////
/// \brief Destructor
///
////////////////////////////////////////////////////////////
~HIDJoystickManager();
////////////////////////////////////////////////////////////
/// \brief Make sur all event have been processed in the run loop
///
////////////////////////////////////////////////////////////
void Update();
private:
////////////////////////////////////////////////////////////
/// \brief Private "plug-in" callback
/// \note Only 'context' parametre is used.
/// \see IOHIDDeviceCallback
///
////////////////////////////////////////////////////////////
static void pluggedIn(void * context, IOReturn, void *, IOHIDDeviceRef);
////////////////////////////////////////////////////////////
/// \brief Private "plug-out" callback
/// \note Only 'context' parametre is used.
/// \see IOHIDDeviceCallback
///
////////////////////////////////////////////////////////////
static void pluggedOut(void * context, IOReturn, void *, IOHIDDeviceRef);
private:
////////////////////////////////////////////////////////////
// Member data
////////////////////////////////////////////////////////////
IOHIDManagerRef myHIDManager; ///< HID Manager
unsigned int myJoystickCount;///< Number of joysticks currently connected
};
} // namespace priv
} // namespace sf
#endif

View File

@ -28,6 +28,8 @@
////////////////////////////////////////////////////////////
#include <SFML/Window/JoystickImpl.hpp>
#include <SFML/Window/OSX/HIDInputManager.hpp>
#include <SFML/Window/OSX/HIDJoystickManager.hpp>
namespace sf
{
@ -51,48 +53,61 @@ bool JoystickImpl::IsConnected(unsigned int index)
// Otherwise, let's check if it is now connected :
else { // i.e., myLocationIDs[index] == 0
// Get all devices
CFSetRef devices = HIDInputManager::GetInstance().CopyJoystickDevices();
// if there is more connected joystick to the HID manager than
// opened joystick devices then we find the new one.
if (devices != NULL) {
unsigned int openedCount = 0;
for (unsigned int i(0); i < sf::Joystick::Count; ++i) {
if (myLocationIDs[i] != 0) openedCount++;
}
CFIndex size = CFSetGetCount(devices);
unsigned int connectedCount = HIDJoystickManager::GetInstance().GetJoystickCount();
if (size > 0) {
if (connectedCount > openedCount) {
CFTypeRef array[size]; // array of IOHIDDeviceRef
CFSetGetValues(devices, array);
// Get all devices
CFSetRef devices = HIDJoystickManager::GetInstance().CopyJoysticks();
// 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.
if (devices != NULL) {
for (CFIndex didx(0); didx < size; ++didx) {
IOHIDDeviceRef d = (IOHIDDeviceRef)array[didx];
Location dloc = HIDInputManager::GetLocationID(d);
CFIndex size = CFSetGetCount(devices);
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 (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
}
}
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);
}
CFRelease(devices);
}
}
@ -107,7 +122,7 @@ bool JoystickImpl::Open(unsigned int index)
Location deviceLoc = myLocationIDs[index]; // The device we need to load
// Get all devices
CFSetRef devices = HIDInputManager::GetInstance().CopyJoystickDevices();
CFSetRef devices = HIDJoystickManager::GetInstance().CopyJoysticks();
if (devices == NULL) {
return false;
}
@ -274,7 +289,7 @@ JoystickState JoystickImpl::Update()
Location selfLoc = myLocationIDs[myIndex];
// Get all devices
CFSetRef devices = HIDInputManager::GetInstance().CopyJoystickDevices();
CFSetRef devices = HIDJoystickManager::GetInstance().CopyJoysticks();
if (devices == NULL) {
return disconnectedState;
}

View File

@ -93,7 +93,7 @@ private :
////////////////////////////////////////////////////////////
// Member data
////////////////////////////////////////////////////////////
typedef long Location;
typedef long Location;
typedef std::map<sf::Joystick::Axis, IOHIDElementRef> AxisMap;
typedef std::vector<IOHIDElementRef> ButtonsVector;