From 732b789e2e8e38bbca6c3f97b4e3b4fc933ee872 Mon Sep 17 00:00:00 2001 From: Marco Antognini Date: Thu, 28 Jul 2011 02:10:35 +0200 Subject: [PATCH] Improved OSX/Joysticks performance --- src/SFML/Window/CMakeLists.txt | 2 + src/SFML/Window/OSX/HIDInputManager.hpp | 31 ++--- src/SFML/Window/OSX/HIDInputManager.mm | 53 ++++----- src/SFML/Window/OSX/HIDJoystickManager.cpp | 127 ++++++++++++++++++++ src/SFML/Window/OSX/HIDJoystickManager.hpp | 128 +++++++++++++++++++++ src/SFML/Window/OSX/JoystickImpl.cpp | 83 +++++++------ src/SFML/Window/OSX/JoystickImpl.hpp | 2 +- 7 files changed, 340 insertions(+), 86 deletions(-) create mode 100644 src/SFML/Window/OSX/HIDJoystickManager.cpp create mode 100644 src/SFML/Window/OSX/HIDJoystickManager.hpp diff --git a/src/SFML/Window/CMakeLists.txt b/src/SFML/Window/CMakeLists.txt index c74367012..ab8b1edf5 100644 --- a/src/SFML/Window/CMakeLists.txt +++ b/src/SFML/Window/CMakeLists.txt @@ -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 diff --git a/src/SFML/Window/OSX/HIDInputManager.hpp b/src/SFML/Window/OSX/HIDInputManager.hpp index 81befac89..3ae33ff01 100644 --- a/src/SFML/Window/OSX/HIDInputManager.hpp +++ b/src/SFML/Window/OSX/HIDInputManager.hpp @@ -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 { @@ -84,14 +81,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. /// diff --git a/src/SFML/Window/OSX/HIDInputManager.mm b/src/SFML/Window/OSX/HIDInputManager.mm index 84b51db9e..3e6fc657a 100644 --- a/src/SFML/Window/OSX/HIDInputManager.mm +++ b/src/SFML/Window/OSX/HIDInputManager.mm @@ -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) @@ -514,35 +529,13 @@ void HIDInputManager::FreeUp() myButtons[i].clear(); } } - - -//////////////////////////////////////////////////////////// -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); diff --git a/src/SFML/Window/OSX/HIDJoystickManager.cpp b/src/SFML/Window/OSX/HIDJoystickManager.cpp new file mode 100644 index 000000000..aaab48424 --- /dev/null +++ b/src/SFML/Window/OSX/HIDJoystickManager.cpp @@ -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 +#include + +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 + diff --git a/src/SFML/Window/OSX/HIDJoystickManager.hpp b/src/SFML/Window/OSX/HIDJoystickManager.hpp new file mode 100644 index 000000000..52711cd91 --- /dev/null +++ b/src/SFML/Window/OSX/HIDJoystickManager.hpp @@ -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 +#include +#include + +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 \ No newline at end of file diff --git a/src/SFML/Window/OSX/JoystickImpl.cpp b/src/SFML/Window/OSX/JoystickImpl.cpp index becb38578..a144e2077 100644 --- a/src/SFML/Window/OSX/JoystickImpl.cpp +++ b/src/SFML/Window/OSX/JoystickImpl.cpp @@ -28,6 +28,8 @@ //////////////////////////////////////////////////////////// #include #include +#include + namespace sf { @@ -50,49 +52,62 @@ 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 (devices != NULL) { + // if there is more connected joystick to the HID manager than + // opened joystick devices then we find the new one. + + unsigned int openedCount = 0; + for (unsigned int i(0); i < sf::Joystick::Count; ++i) { + if (myLocationIDs[i] != 0) openedCount++; + } + + unsigned int connectedCount = HIDJoystickManager::GetInstance().GetJoystickCount(); + + if (connectedCount > openedCount) { + + // Get all devices + CFSetRef devices = HIDJoystickManager::GetInstance().CopyJoysticks(); - CFIndex size = CFSetGetCount(devices); - - if (size > 0) { - - CFTypeRef array[size]; // array of IOHIDDeviceRef - CFSetGetValues(devices, array); + if (devices != NULL) { - // 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. + CFIndex size = CFSetGetCount(devices); - for (CFIndex didx(0); didx < size; ++didx) { - IOHIDDeviceRef d = (IOHIDDeviceRef)array[didx]; - Location dloc = HIDInputManager::GetLocationID(d); + if (size > 0) { - bool foundJ = false; - for (unsigned int j(0); j < Joystick::Count; ++j) { - if (myLocationIDs[j] == dloc) { - foundJ = true; - break; // no need to loop again + 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; } diff --git a/src/SFML/Window/OSX/JoystickImpl.hpp b/src/SFML/Window/OSX/JoystickImpl.hpp index e0c0add8c..f178de9f3 100644 --- a/src/SFML/Window/OSX/JoystickImpl.hpp +++ b/src/SFML/Window/OSX/JoystickImpl.hpp @@ -93,7 +93,7 @@ private : //////////////////////////////////////////////////////////// // Member data //////////////////////////////////////////////////////////// - typedef long Location; + typedef long Location; typedef std::map AxisMap; typedef std::vector ButtonsVector;