Modernize memory management of Core Foundation pointers

This commit is contained in:
Chris Thrasher 2024-07-06 13:26:41 -06:00
parent 3c084bf661
commit 7f43eb888a
No known key found for this signature in database
GPG Key ID: 56FB686C9DFC8E2C
10 changed files with 153 additions and 173 deletions

View File

@ -30,6 +30,7 @@
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
#include <SFML/Window/JoystickImpl.hpp> #include <SFML/Window/JoystickImpl.hpp>
#include <SFML/Window/Keyboard.hpp> #include <SFML/Window/Keyboard.hpp>
#include <SFML/Window/macOS/Utils.hpp>
#include <IOKit/hid/IOHIDDevice.h> #include <IOKit/hid/IOHIDDevice.h>
#include <IOKit/hid/IOHIDManager.h> #include <IOKit/hid/IOHIDManager.h>
@ -40,7 +41,7 @@
namespace sf::priv namespace sf::priv
{ {
using IOHIDElements = std::vector<IOHIDElementRef>; using IOHIDElements = std::vector<CFPtr<IOHIDElementRef>>;
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
/// \brief sf::priv::InputImpl helper /// \brief sf::priv::InputImpl helper
@ -93,7 +94,7 @@ public:
/// \return a retained CFDictionaryRef /// \return a retained CFDictionaryRef
/// ///
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
static CFDictionaryRef copyDevicesMask(std::uint32_t page, std::uint32_t usage); static CFPtr<CFDictionaryRef> copyDevicesMask(std::uint32_t page, std::uint32_t usage);
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
/// \brief Try to convert a character into a SFML key code /// \brief Try to convert a character into a SFML key code
@ -243,10 +244,10 @@ private:
/// ///
/// \param page HID page like kHIDPage_GenericDesktop /// \param page HID page like kHIDPage_GenericDesktop
/// \param usage HID usage page like kHIDUsage_GD_Keyboard or kHIDUsage_GD_Mouse /// \param usage HID usage page like kHIDUsage_GD_Keyboard or kHIDUsage_GD_Mouse
/// \return a retained, non-empty CFSetRef of IOHIDDeviceRef or a null pointer /// \return a retained, non-empty __CFSet pointer of IOHIDDeviceRef or a null pointer
/// ///
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
CFSetRef copyDevices(std::uint32_t page, std::uint32_t usage); CFPtr<CFSetRef> copyDevices(std::uint32_t page, std::uint32_t usage);
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
/// \brief Check if a key is pressed /// \brief Check if a key is pressed
@ -286,8 +287,8 @@ private:
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
// Member data // Member data
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
IOHIDManagerRef m_manager{}; ///< Underlying HID Manager CFPtr<IOHIDManagerRef> m_manager; ///< Underlying HID Manager
bool m_keysInitialized{}; ///< Has initializeKeyboard been called at least once? bool m_keysInitialized{}; ///< Has initializeKeyboard been called at least once?
EnumArray<Keyboard::Scancode, IOHIDElements, Keyboard::ScancodeCount> m_keys; ///< All the keys on any connected keyboard EnumArray<Keyboard::Scancode, IOHIDElements, Keyboard::ScancodeCount> m_keys; ///< All the keys on any connected keyboard
EnumArray<Keyboard::Key, Keyboard::Scancode, Keyboard::KeyCount> m_keyToScancodeMapping{}; ///< Mapping from Key to Scancode EnumArray<Keyboard::Key, Keyboard::Scancode, Keyboard::KeyCount> m_keyToScancodeMapping{}; ///< Mapping from Key to Scancode
EnumArray<Keyboard::Scancode, Keyboard::Key, Keyboard::ScancodeCount> m_scancodeToKeyMapping{}; ///< Mapping from Scancode to Key EnumArray<Keyboard::Scancode, Keyboard::Key, Keyboard::ScancodeCount> m_scancodeToKeyMapping{}; ///< Mapping from Scancode to Key

View File

@ -70,23 +70,19 @@ long HIDInputManager::getLocationID(IOHIDDeviceRef device)
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
CFDictionaryRef HIDInputManager::copyDevicesMask(std::uint32_t page, std::uint32_t usage) CFPtr<CFDictionaryRef> HIDInputManager::copyDevicesMask(std::uint32_t page, std::uint32_t usage)
{ {
// Create the dictionary. // Create the dictionary.
CFMutableDictionaryRef dict = CFDictionaryCreateMutable(kCFAllocatorDefault, auto dict = CFPtr<CFMutableDictionaryRef>(
2, CFDictionaryCreateMutable(kCFAllocatorDefault, 2, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
// Add the page value. // Add the page value.
CFNumberRef value = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &page); auto value = CFPtr<CFNumberRef>(CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &page));
CFDictionarySetValue(dict, CFSTR(kIOHIDDeviceUsagePageKey), value); CFDictionarySetValue(dict.get(), CFSTR(kIOHIDDeviceUsagePageKey), value.get());
CFRelease(value);
// Add the usage value (which is only valid if page value exists). // Add the usage value (which is only valid if page value exists).
value = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &usage); value = CFPtr<CFNumberRef>(CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &usage));
CFDictionarySetValue(dict, CFSTR(kIOHIDDeviceUsageKey), value); CFDictionarySetValue(dict.get(), CFSTR(kIOHIDDeviceUsageKey), value.get());
CFRelease(value);
return dict; return dict;
} }
@ -713,8 +709,8 @@ String HIDInputManager::getDescription(Keyboard::Scancode code)
HIDInputManager::HIDInputManager() HIDInputManager::HIDInputManager()
{ {
// Create an HID Manager reference // Create an HID Manager reference
m_manager = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone); m_manager = CFPtr<IOHIDManagerRef>(IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone));
const IOReturn openStatus = IOHIDManagerOpen(m_manager, kIOHIDOptionsTypeNone); const IOReturn openStatus = IOHIDManagerOpen(m_manager.get(), kIOHIDOptionsTypeNone);
if (openStatus != kIOReturnSuccess) if (openStatus != kIOReturnSuccess)
{ {
@ -753,7 +749,7 @@ void HIDInputManager::initializeKeyboard()
// in approximately constant time. // in approximately constant time.
// Get only keyboards // Get only keyboards
CFSetRef underlying = copyDevices(kHIDPage_GenericDesktop, kHIDUsage_GD_Keyboard); const auto underlying = copyDevices(kHIDPage_GenericDesktop, kHIDUsage_GD_Keyboard);
if (underlying == nullptr) if (underlying == nullptr)
{ {
err() << "No keyboard detected by the HID manager!" << std::endl; err() << "No keyboard detected by the HID manager!" << std::endl;
@ -761,12 +757,10 @@ void HIDInputManager::initializeKeyboard()
return; return;
} }
auto* const keyboards = static_cast<NSSet*>(underlying); // Toll-Free Bridge auto* const keyboards = static_cast<NSSet*>(underlying.get()); // Toll-Free Bridge
for (id keyboard in keyboards) // NOLINT(cppcoreguidelines-init-variables) for (id keyboard in keyboards) // NOLINT(cppcoreguidelines-init-variables)
loadKeyboard(static_cast<IOHIDDeviceRef>(keyboard)); loadKeyboard(static_cast<IOHIDDeviceRef>(keyboard));
CFRelease(underlying);
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
// At this point m_keys is filled with as many IOHIDElementRef as possible // At this point m_keys is filled with as many IOHIDElementRef as possible
} }
@ -775,22 +769,20 @@ void HIDInputManager::initializeKeyboard()
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
void HIDInputManager::loadKeyboard(IOHIDDeviceRef keyboard) void HIDInputManager::loadKeyboard(IOHIDDeviceRef keyboard)
{ {
CFArrayRef underlying = IOHIDDeviceCopyMatchingElements(keyboard, nullptr, kIOHIDOptionsTypeNone); const auto underlying = CFPtr<CFArrayRef>(IOHIDDeviceCopyMatchingElements(keyboard, nullptr, kIOHIDOptionsTypeNone));
if ((underlying == nullptr) || (CFArrayGetCount(underlying) == 0)) if ((underlying == nullptr) || (CFArrayGetCount(underlying.get()) == 0))
{ {
err() << "Detected a keyboard without any keys." << std::endl; err() << "Detected a keyboard without any keys." << std::endl;
return; return;
} }
auto* const keys = static_cast<NSArray*>(underlying); // Toll-Free Bridge auto* const keys = static_cast<NSArray*>(underlying.get()); // Toll-Free Bridge
for (id key in keys) // NOLINT(cppcoreguidelines-init-variables) for (id key in keys) // NOLINT(cppcoreguidelines-init-variables)
{ {
auto* elem = static_cast<IOHIDElementRef>(key); auto* elem = static_cast<IOHIDElementRef>(key);
if (IOHIDElementGetUsagePage(elem) == kHIDPage_KeyboardOrKeypad) if (IOHIDElementGetUsagePage(elem) == kHIDPage_KeyboardOrKeypad)
loadKey(elem); loadKey(elem);
} }
CFRelease(underlying);
} }
@ -802,7 +794,7 @@ void HIDInputManager::loadKey(IOHIDElementRef key)
if (code != Keyboard::Scan::Unknown) if (code != Keyboard::Scan::Unknown)
{ {
CFRetain(key); CFRetain(key);
m_keys[code].push_back(key); m_keys[code].emplace_back(key);
} }
} }
@ -815,13 +807,12 @@ void HIDInputManager::buildMappings()
m_scancodeToKeyMapping.fill(Keyboard::Key::Unknown); m_scancodeToKeyMapping.fill(Keyboard::Key::Unknown);
// Get the current keyboard layout // Get the current keyboard layout
TISInputSourceRef tis = TISCopyCurrentKeyboardLayoutInputSource(); const auto tis = CFPtr<TISInputSourceRef>(TISCopyCurrentKeyboardLayoutInputSource());
const auto* layoutData = static_cast<CFDataRef>(TISGetInputSourceProperty(tis, kTISPropertyUnicodeKeyLayoutData)); const auto* layoutData = static_cast<CFDataRef>(TISGetInputSourceProperty(tis.get(), kTISPropertyUnicodeKeyLayoutData));
if (layoutData == nullptr) if (layoutData == nullptr)
{ {
err() << "Cannot get the keyboard layout\n"; err() << "Cannot get the keyboard layout\n";
CFRelease(tis);
return; return;
} }
@ -905,8 +896,6 @@ void HIDInputManager::buildMappings()
m_keyToScancodeMapping[code] = scan; m_keyToScancodeMapping[code] = scan;
m_scancodeToKeyMapping[scan] = code; m_scancodeToKeyMapping[scan] = code;
} }
CFRelease(tis);
} }
@ -925,46 +914,30 @@ void HIDInputManager::keyboardChanged(CFNotificationCenterRef /* center */,
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
void HIDInputManager::freeUp() void HIDInputManager::freeUp()
{ {
if (m_manager != nil) m_manager.reset();
CFRelease(m_manager);
m_manager = nil;
if (m_keysInitialized) if (m_keysInitialized)
{
for (auto& key : m_keys) for (auto& key : m_keys)
{
for (IOHIDElementRef iohidElementRef : key)
CFRelease(iohidElementRef);
key.clear(); key.clear();
}
}
m_keysInitialized = false; m_keysInitialized = false;
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
CFSetRef HIDInputManager::copyDevices(std::uint32_t page, std::uint32_t usage) CFPtr<CFSetRef> HIDInputManager::copyDevices(std::uint32_t page, std::uint32_t usage)
{ {
// Filter and keep only the requested devices // Filter and keep only the requested devices
CFDictionaryRef mask = copyDevicesMask(page, usage); const auto mask = copyDevicesMask(page, usage);
IOHIDManagerSetDeviceMatching(m_manager, mask); IOHIDManagerSetDeviceMatching(m_manager.get(), mask.get());
CFRelease(mask); auto devices = CFPtr<CFSetRef>(IOHIDManagerCopyDevices(m_manager.get()));
mask = nil;
CFSetRef devices = IOHIDManagerCopyDevices(m_manager);
if (devices == nullptr) if (devices == nullptr)
return nullptr; return nullptr;
// Is there at least one device? // Is there at least one device?
if (CFSetGetCount(devices) < 1) if (CFSetGetCount(devices.get()) < 1)
{
CFRelease(devices);
return nullptr; return nullptr;
}
return devices; return devices;
} }
@ -978,13 +951,12 @@ bool HIDInputManager::isPressed(IOHIDElements& elements) const
{ {
IOHIDValueRef value = nil; IOHIDValueRef value = nil;
IOHIDDeviceRef device = IOHIDElementGetDevice(*it); IOHIDDeviceRef device = IOHIDElementGetDevice(it->get());
IOHIDDeviceGetValue(device, *it, &value); IOHIDDeviceGetValue(device, it->get(), &value);
if (!value) if (!value)
{ {
// This means some kind of error / disconnection so we remove this element from our database. // This means some kind of error / disconnection so we remove this element from our database.
CFRelease(*it);
it = elements.erase(it); it = elements.erase(it);
} }
else else

View File

@ -61,10 +61,9 @@ unsigned int HIDJoystickManager::getJoystickCount()
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
CFSetRef HIDJoystickManager::copyJoysticks() CFPtr<CFSetRef> HIDJoystickManager::copyJoysticks()
{ {
CFSetRef devices = IOHIDManagerCopyDevices(m_manager); return CFPtr<CFSetRef>(IOHIDManagerCopyDevices(m_manager));
return devices;
} }
@ -73,17 +72,15 @@ HIDJoystickManager::HIDJoystickManager()
{ {
m_manager = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone); m_manager = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone);
CFDictionaryRef mask0 = HIDInputManager::copyDevicesMask(kHIDPage_GenericDesktop, kHIDUsage_GD_Joystick); const auto mask0 = HIDInputManager::copyDevicesMask(kHIDPage_GenericDesktop, kHIDUsage_GD_Joystick);
CFDictionaryRef mask1 = HIDInputManager::copyDevicesMask(kHIDPage_GenericDesktop, kHIDUsage_GD_GamePad); const auto mask1 = HIDInputManager::copyDevicesMask(kHIDPage_GenericDesktop, kHIDUsage_GD_GamePad);
std::array maskArray = {mask0, mask1}; std::array maskArray = {mask0.get(), mask1.get()};
CFArrayRef mask = CFArrayCreate(nullptr, reinterpret_cast<const void**>(maskArray.data()), maskArray.size(), nullptr); const auto mask = CFPtr<CFArrayRef>(
CFArrayCreate(nullptr, reinterpret_cast<const void**>(maskArray.data()), maskArray.size(), nullptr));
IOHIDManagerSetDeviceMatchingMultiple(m_manager, mask); IOHIDManagerSetDeviceMatchingMultiple(m_manager, mask.get());
CFRelease(mask);
CFRelease(mask1);
CFRelease(mask0);
IOHIDManagerRegisterDeviceMatchingCallback(m_manager, pluggedIn, this); IOHIDManagerRegisterDeviceMatchingCallback(m_manager, pluggedIn, this);

View File

@ -75,10 +75,10 @@ public:
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
/// \brief Copy the devices associated with this HID manager /// \brief Copy the devices associated with this HID manager
/// ///
/// \return a retained CFSetRef of IOHIDDeviceRef or a null pointer /// \return a retained __CFSet pointer of IOHIDDeviceRef or a null pointer
/// ///
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
CFSetRef copyJoysticks(); CFPtr<CFSetRef> copyJoysticks();
private: private:
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////

View File

@ -212,12 +212,12 @@ void setMousePosition(Vector2i position)
const CGPoint pos = CGPointMake(position.x / scale, position.y / scale); const CGPoint pos = CGPointMake(position.x / scale, position.y / scale);
// Place the cursor. // Place the cursor.
CGEventRef event = CGEventCreateMouseEvent(nullptr, const auto event = CFPtr<CGEventRef>(
kCGEventMouseMoved, CGEventCreateMouseEvent(nullptr,
pos, kCGEventMouseMoved,
/* we don't care about this: */ kCGMouseButtonLeft); pos,
CGEventPost(kCGHIDEventTap, event); /* we don't care about this: */ kCGMouseButtonLeft));
CFRelease(event); CGEventPost(kCGHIDEventTap, event.get());
// This is a workaround to deprecated CGSetLocalEventsSuppressionInterval. // This is a workaround to deprecated CGSetLocalEventsSuppressionInterval.
} }

View File

@ -132,15 +132,15 @@ bool JoystickImpl::isConnected(unsigned int index)
if (connectedCount > openedCount) if (connectedCount > openedCount)
{ {
// Get all devices // Get all devices
CFSetRef devices = HIDJoystickManager::getInstance().copyJoysticks(); const auto devices = CFPtr<CFSetRef>(HIDJoystickManager::getInstance().copyJoysticks());
if (devices != nullptr) if (devices != nullptr)
{ {
const CFIndex size = CFSetGetCount(devices); const CFIndex size = CFSetGetCount(devices.get());
if (size > 0) if (size > 0)
{ {
std::vector<CFTypeRef> array(static_cast<std::size_t>(size)); // array of IOHIDDeviceRef std::vector<CFTypeRef> array(static_cast<std::size_t>(size)); // array of IOHIDDeviceRef
CFSetGetValues(devices, array.data()); CFSetGetValues(devices.get(), array.data());
// 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.
@ -166,8 +166,6 @@ bool JoystickImpl::isConnected(unsigned int index)
} }
} }
} }
CFRelease(devices);
} }
} }
} }
@ -185,14 +183,14 @@ bool JoystickImpl::open(unsigned int index)
const Location deviceLoc = m_locationIDs[index]; // The device we need to load const Location deviceLoc = m_locationIDs[index]; // The device we need to load
// Get all devices // Get all devices
CFSetRef devices = HIDJoystickManager::getInstance().copyJoysticks(); const auto devices = HIDJoystickManager::getInstance().copyJoysticks();
if (devices == nullptr) if (devices == nullptr)
return false; return false;
// Get a usable copy of the joysticks devices. // Get a usable copy of the joysticks devices.
const CFIndex joysticksCount = CFSetGetCount(devices); const CFIndex joysticksCount = CFSetGetCount(devices.get());
std::vector<CFTypeRef> devicesArray(static_cast<std::size_t>(joysticksCount)); std::vector<CFTypeRef> devicesArray(static_cast<std::size_t>(joysticksCount));
CFSetGetValues(devices, devicesArray.data()); CFSetGetValues(devices.get(), devicesArray.data());
// Get the desired joystick. // Get the desired joystick.
IOHIDDeviceRef self = nil; IOHIDDeviceRef self = nil;
@ -204,33 +202,28 @@ bool JoystickImpl::open(unsigned int index)
} }
if (self == nil) if (self == nil)
{
CFRelease(devices);
return false; return false;
}
m_identification.name = getDeviceString(self, CFSTR(kIOHIDProductKey), m_index); m_identification.name = getDeviceString(self, CFSTR(kIOHIDProductKey), m_index);
m_identification.vendorId = getDeviceUint(self, CFSTR(kIOHIDVendorIDKey), m_index); m_identification.vendorId = getDeviceUint(self, CFSTR(kIOHIDVendorIDKey), m_index);
m_identification.productId = getDeviceUint(self, CFSTR(kIOHIDProductIDKey), m_index); m_identification.productId = getDeviceUint(self, CFSTR(kIOHIDProductIDKey), m_index);
// Get a list of all elements attached to the device. // Get a list of all elements attached to the device.
CFArrayRef elements = IOHIDDeviceCopyMatchingElements(self, nullptr, kIOHIDOptionsTypeNone); const auto elements = CFPtr<CFArrayRef>(IOHIDDeviceCopyMatchingElements(self, nullptr, kIOHIDOptionsTypeNone));
if (elements == nullptr) if (elements == nullptr)
{
CFRelease(devices);
return false; return false;
}
// Go through all connected elements. // Go through all connected elements.
const CFIndex elementsCount = CFArrayGetCount(elements); const CFIndex elementsCount = CFArrayGetCount(elements.get());
for (int i = 0; i < elementsCount; ++i) for (int i = 0; i < elementsCount; ++i)
{ {
auto* element = static_cast<IOHIDElementRef>(const_cast<void*>(CFArrayGetValueAtIndex(elements, i))); auto element = std::shared_ptr(CFPtr<IOHIDElementRef>(
switch (IOHIDElementGetUsagePage(element)) static_cast<IOHIDElementRef>(const_cast<void*>(CFArrayGetValueAtIndex(elements.get(), i)))));
switch (IOHIDElementGetUsagePage(element.get()))
{ {
case kHIDPage_GenericDesktop: case kHIDPage_GenericDesktop:
switch (IOHIDElementGetUsage(element)) switch (IOHIDElementGetUsage(element.get()))
{ {
case kHIDUsage_GD_X: case kHIDUsage_GD_X:
m_axis[Joystick::Axis::X] = element; m_axis[Joystick::Axis::X] = element;
@ -263,8 +256,8 @@ bool JoystickImpl::open(unsigned int index)
// We assume this model here as well. Hence, with 4 switches and intermediate // 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). // positions we have 8 values (0-7) plus the "null" state (8).
{ {
const CFIndex min = IOHIDElementGetLogicalMin(element); const CFIndex min = IOHIDElementGetLogicalMin(element.get());
const CFIndex max = IOHIDElementGetLogicalMax(element); const CFIndex max = IOHIDElementGetLogicalMax(element.get());
if (min != 0 || max != 7) if (min != 0 || max != 7)
{ {
@ -283,18 +276,18 @@ bool JoystickImpl::open(unsigned int index)
// We assume a game pad is an application collection, meaning it doesn't hold // 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. // any values per say. They kind of "emit" the joystick's usages.
// See §3.4.3 Usage Types (Collection) of HUT v1.12 // See §3.4.3 Usage Types (Collection) of HUT v1.12
if (IOHIDElementGetCollectionType(element) != kIOHIDElementCollectionTypeApplication) if (IOHIDElementGetCollectionType(element.get()) != kIOHIDElementCollectionTypeApplication)
{ {
sf::err() << std::hex << "Gamepage (vendor/product id: 0x" << m_identification.vendorId sf::err() << std::hex << "Gamepage (vendor/product id: 0x" << m_identification.vendorId
<< "/0x" << m_identification.productId << ") is not an CA but a 0x" << "/0x" << m_identification.productId << ") is not an CA but a 0x"
<< IOHIDElementGetCollectionType(element) << std::dec << std::endl; << IOHIDElementGetCollectionType(element.get()) << std::dec << std::endl;
} }
break; break;
default: default:
#ifdef SFML_DEBUG #ifdef SFML_DEBUG
sf::err() << "Unexpected usage for element of Page Generic Desktop: 0x" << std::hex sf::err() << "Unexpected usage for element of Page Generic Desktop: 0x" << std::hex
<< IOHIDElementGetUsage(element) << std::dec << std::endl; << IOHIDElementGetUsage(element.get()) << std::dec << std::endl;
#endif #endif
break; break;
} }
@ -315,24 +308,7 @@ 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(), std::sort(m_buttons.begin(),
m_buttons.end(), m_buttons.end(),
[](IOHIDElementRef b1, IOHIDElementRef b2) { return IOHIDElementGetUsage(b1) < IOHIDElementGetUsage(b2); }); [](auto b1, auto b2) { return IOHIDElementGetUsage(b1.get()) < IOHIDElementGetUsage(b2.get()); });
// Retain all these objects for personal use
for (IOHIDElementRef iohidElementRef : m_buttons)
CFRetain(iohidElementRef);
for (const auto& [axis, iohidElementRef] : m_axis)
CFRetain(iohidElementRef);
if (m_hat != nullptr)
CFRetain(m_hat);
// 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. To prevent
// leaking we retain objects 'only' now.
CFRelease(devices);
CFRelease(elements);
return true; return true;
} }
@ -343,20 +319,9 @@ void JoystickImpl::close()
{ {
const AutoreleasePool pool; const AutoreleasePool pool;
for (IOHIDElementRef iohidElementRef : m_buttons)
CFRelease(iohidElementRef);
m_buttons.clear(); m_buttons.clear();
for (const auto& [axis, iohidElementRef] : m_axis)
CFRelease(iohidElementRef);
m_axis.clear(); m_axis.clear();
m_hat.reset();
if (m_hat != nullptr)
CFRelease(m_hat);
m_hat = nullptr;
// And we unregister this joystick // And we unregister this joystick
m_locationIDs[m_index] = 0; m_locationIDs[m_index] = 0;
@ -406,14 +371,14 @@ JoystickState JoystickImpl::update()
const Location selfLoc = m_locationIDs[m_index]; const Location selfLoc = m_locationIDs[m_index];
// Get all devices // Get all devices
CFSetRef devices = HIDJoystickManager::getInstance().copyJoysticks(); auto devices = HIDJoystickManager::getInstance().copyJoysticks();
if (devices == nullptr) if (devices == nullptr)
return disconnectedState; return disconnectedState;
// Get a usable copy of the joysticks devices. // Get a usable copy of the joysticks devices.
const CFIndex joysticksCount = CFSetGetCount(devices); const CFIndex joysticksCount = CFSetGetCount(devices.get());
std::vector<CFTypeRef> devicesArray(static_cast<std::size_t>(joysticksCount)); std::vector<CFTypeRef> devicesArray(static_cast<std::size_t>(joysticksCount));
CFSetGetValues(devices, devicesArray.data()); CFSetGetValues(devices.get(), devicesArray.data());
// Search for it // Search for it
bool found = false; bool found = false;
@ -424,19 +389,15 @@ JoystickState JoystickImpl::update()
found = true; found = true;
} }
// Release unused stuff
CFRelease(devices);
// If not found we consider it disconnected // If not found we consider it disconnected
if (!found) if (!found)
return disconnectedState; return disconnectedState;
// Update buttons' state // Update buttons' state
unsigned int i = 0; for (std::size_t i = 0; i < m_buttons.size(); ++i)
for (auto it = m_buttons.begin(); it != m_buttons.end(); ++it, ++i)
{ {
IOHIDValueRef value = nil; IOHIDValueRef value = nil;
IOHIDDeviceGetValue(IOHIDElementGetDevice(*it), *it, &value); IOHIDDeviceGetValue(IOHIDElementGetDevice(m_buttons[i].get()), m_buttons[i].get(), &value);
// Check for plug out. // Check for plug out.
if (!value) if (!value)
@ -452,7 +413,7 @@ JoystickState JoystickImpl::update()
for (const auto& [axis, iohidElementRef] : m_axis) for (const auto& [axis, iohidElementRef] : m_axis)
{ {
IOHIDValueRef value = nil; IOHIDValueRef value = nil;
IOHIDDeviceGetValue(IOHIDElementGetDevice(iohidElementRef), iohidElementRef, &value); IOHIDDeviceGetValue(IOHIDElementGetDevice(iohidElementRef.get()), iohidElementRef.get(), &value);
// Check for plug out. // Check for plug out.
if (!value) if (!value)
@ -470,8 +431,8 @@ JoystickState JoystickImpl::update()
// This method might not be very accurate (the "0 position" can be // This method might not be very accurate (the "0 position" can be
// slightly shift with some device) but we don't care because most // slightly shift with some device) but we don't care because most
// of devices are so sensitive that this is not relevant. // of devices are so sensitive that this is not relevant.
const auto physicalMax = static_cast<double>(IOHIDElementGetPhysicalMax(iohidElementRef)); const auto physicalMax = static_cast<double>(IOHIDElementGetPhysicalMax(iohidElementRef.get()));
const auto physicalMin = static_cast<double>(IOHIDElementGetPhysicalMin(iohidElementRef)); const auto physicalMin = static_cast<double>(IOHIDElementGetPhysicalMin(iohidElementRef.get()));
const double scaledMin = -100; const double scaledMin = -100;
const double scaledMax = 100; const double scaledMax = 100;
const double physicalValue = IOHIDValueGetScaledValue(value, kIOHIDValueScaleTypePhysical); const double physicalValue = IOHIDValueGetScaledValue(value, kIOHIDValueScaleTypePhysical);
@ -489,7 +450,7 @@ JoystickState JoystickImpl::update()
if (m_hat != nullptr) if (m_hat != nullptr)
{ {
IOHIDValueRef value = nil; IOHIDValueRef value = nil;
IOHIDDeviceGetValue(IOHIDElementGetDevice(m_hat), m_hat, &value); IOHIDDeviceGetValue(IOHIDElementGetDevice(m_hat.get()), m_hat.get(), &value);
// Check for plug out. // Check for plug out.
if (!value) if (!value)

View File

@ -111,14 +111,14 @@ private:
// Member data // Member data
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
using Location = long; using Location = long;
using AxisMap = std::unordered_map<Joystick::Axis, IOHIDElementRef>; using AxisMap = std::unordered_map<Joystick::Axis, std::shared_ptr<__IOHIDElement>>;
using ButtonsVector = std::vector<IOHIDElementRef>; using ButtonsVector = std::vector<std::shared_ptr<__IOHIDElement>>;
AxisMap m_axis; ///< Axes (but not POV/Hat) of the joystick AxisMap m_axis; ///< Axes (but not POV/Hat) of the joystick
IOHIDElementRef m_hat{}; ///< POV/Hat axis of the joystick std::shared_ptr<__IOHIDElement> m_hat; ///< POV/Hat axis of the joystick
ButtonsVector m_buttons; ///< Buttons 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
// NOLINTNEXTLINE(readability-identifier-naming) // NOLINTNEXTLINE(readability-identifier-naming)
static inline std::array<Location, Joystick::Count> m_locationIDs{}; ///< Global Joystick register static inline std::array<Location, Joystick::Count> m_locationIDs{}; ///< Global Joystick register

View File

@ -0,0 +1,55 @@
////////////////////////////////////////////////////////////
//
// SFML - Simple and Fast Multimedia Library
// Copyright (C) 2007-2024 Laurent Gomila (laurent@sfml-dev.org)
//
// 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.
//
////////////////////////////////////////////////////////////
#pragma once
////////////////////////////////////////////////////////////
// Headers
////////////////////////////////////////////////////////////
#include <memory>
#include <type_traits>
namespace sf::priv
{
////////////////////////////////////////////////////////////
/// \brief Class for freeing Core Foundation pointers
///
////////////////////////////////////////////////////////////
struct CFDeleter
{
template <typename T>
void operator()(T* data) const
{
CFRelease(data);
}
};
////////////////////////////////////////////////////////////
/// \brief Class template for wrapping owning raw pointers from Core Foundation
///
////////////////////////////////////////////////////////////
template <typename T>
using CFPtr = std::unique_ptr<std::remove_pointer_t<T>, CFDeleter>;
} // namespace sf::priv

View File

@ -27,6 +27,7 @@
// Headers // Headers
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
#include <SFML/Window/VideoModeImpl.hpp> #include <SFML/Window/VideoModeImpl.hpp>
#include <SFML/Window/macOS/Utils.hpp>
#include <SFML/Window/macOS/cg_sf_conversion.hpp> #include <SFML/Window/macOS/cg_sf_conversion.hpp>
#include <SFML/System/Err.hpp> #include <SFML/System/Err.hpp>
@ -41,7 +42,7 @@ namespace sf::priv
std::vector<VideoMode> VideoModeImpl::getFullscreenModes() std::vector<VideoMode> VideoModeImpl::getFullscreenModes()
{ {
// Retrieve all modes available for main screen only. // Retrieve all modes available for main screen only.
CFArrayRef cgmodes = CGDisplayCopyAllDisplayModes(CGMainDisplayID(), nullptr); const auto cgmodes = CFPtr<CFArrayRef>(CGDisplayCopyAllDisplayModes(CGMainDisplayID(), nullptr));
if (cgmodes == nullptr) if (cgmodes == nullptr)
{ {
@ -53,10 +54,10 @@ std::vector<VideoMode> VideoModeImpl::getFullscreenModes()
std::vector<VideoMode> modes = {desktop}; std::vector<VideoMode> modes = {desktop};
// Loop on each mode and convert it into a sf::VideoMode object. // Loop on each mode and convert it into a sf::VideoMode object.
const CFIndex modesCount = CFArrayGetCount(cgmodes); const CFIndex modesCount = CFArrayGetCount(cgmodes.get());
for (CFIndex i = 0; i < modesCount; ++i) for (CFIndex i = 0; i < modesCount; ++i)
{ {
auto* cgmode = static_cast<CGDisplayModeRef>(const_cast<void*>(CFArrayGetValueAtIndex(cgmodes, i))); auto* cgmode = static_cast<CGDisplayModeRef>(const_cast<void*>(CFArrayGetValueAtIndex(cgmodes.get(), i)));
const VideoMode mode = convertCGModeToSFMode(cgmode); const VideoMode mode = convertCGModeToSFMode(cgmode);
@ -69,9 +70,6 @@ std::vector<VideoMode> VideoModeImpl::getFullscreenModes()
modes.push_back(mode); modes.push_back(mode);
} }
// Clean up memory.
CFRelease(cgmodes);
return modes; return modes;
} }

View File

@ -27,6 +27,7 @@
// Headers // Headers
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
#import <SFML/Window/macOS/Scaling.h> #import <SFML/Window/macOS/Scaling.h>
#include <SFML/Window/macOS/Utils.hpp>
#include <SFML/Window/macOS/cg_sf_conversion.hpp> #include <SFML/Window/macOS/cg_sf_conversion.hpp>
#pragma GCC diagnostic ignored "-Wdeprecated-declarations" #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
@ -37,21 +38,16 @@ namespace sf::priv
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
unsigned int modeBitsPerPixel(CGDisplayModeRef mode) unsigned int modeBitsPerPixel(CGDisplayModeRef mode)
{ {
unsigned int bpp = 0; // no match
// Compare encoding. // Compare encoding.
CFStringRef pixEnc = CGDisplayModeCopyPixelEncoding(mode); const auto pixEnc = CFPtr<CFStringRef>(CGDisplayModeCopyPixelEncoding(mode));
if (CFStringCompare(pixEnc, CFSTR(IO32BitDirectPixels), kCFCompareCaseInsensitive) == kCFCompareEqualTo) if (CFStringCompare(pixEnc.get(), CFSTR(IO32BitDirectPixels), kCFCompareCaseInsensitive) == kCFCompareEqualTo)
bpp = 32; return 32;
else if (CFStringCompare(pixEnc, CFSTR(IO16BitDirectPixels), kCFCompareCaseInsensitive) == kCFCompareEqualTo) if (CFStringCompare(pixEnc.get(), CFSTR(IO16BitDirectPixels), kCFCompareCaseInsensitive) == kCFCompareEqualTo)
bpp = 16; return 16;
else if (CFStringCompare(pixEnc, CFSTR(IO8BitIndexedPixels), kCFCompareCaseInsensitive) == kCFCompareEqualTo) if (CFStringCompare(pixEnc.get(), CFSTR(IO8BitIndexedPixels), kCFCompareCaseInsensitive) == kCFCompareEqualTo)
bpp = 8; return 8;
// Clean up memory. return 0;
CFRelease(pixEnc);
return bpp;
} }