#include <pthread.h>
#include <CoreFoundation/CFRuntime.h>
#include "IOHIDManager.h"
#include <IOKit/IOKitLib.h>
#include "IOHIDLibPrivate.h"
#include "IOHIDDevice.h"
#include "IOHIDLib.h"
#include "IOHIDManagerPersistentProperties.h"
static IOHIDManagerRef __IOHIDManagerCreate(
CFAllocatorRef allocator,
CFAllocatorContext * context __unused);
static void __IOHIDManagerExtRelease( CFTypeRef object );
static void __IOHIDManagerIntRelease( CFTypeRef object );
static void __IOHIDManagerSetDeviceMatching(
IOHIDManagerRef manager,
CFDictionaryRef matching);
static void __IOHIDManagerDeviceAdded(
void * context,
io_iterator_t iterator);
static void __IOHIDManagerDeviceRemoved(
void * context,
IOReturn result,
void * sender);
static void __IOHIDManagerDeviceApplier(
const void * value,
void * context);
static void __IOHIDManagerInitialEnumCallback(
void * info);
static void __IOHIDManagerMergeDictionaries(
CFDictionaryRef srcDict,
CFMutableDictionaryRef dstDict);
enum {
kDeviceApplierOpen = 1 << 0,
kDeviceApplierClose = 1 << 1,
kDeviceApplierInitEnumCallback = 1 << 2,
kDeviceApplierSetInputMatching = 1 << 3,
kDeviceApplierSetInputCallback = 1 << 4,
kDeviceApplierSetInputReportCallback = 1 << 5,
kDeviceApplierScheduleRunLoop = 1 << 6,
kDeviceApplierUnscheduleRunLoop = 1 << 7
};
typedef struct __DeviceApplierArgs {
IOHIDManagerRef manager;
IOOptionBits options;
IOReturn retVal;
} DeviceApplierArgs;
typedef struct __IOHIDManager
{
IOHIDObjectBase hidBase;
CFMutableSetRef devices;
CFMutableSetRef iterators;
CFMutableDictionaryRef properties;
CFMutableDictionaryRef deviceInputBuffers;
IONotificationPortRef notifyPort;
CFRunLoopRef runLoop;
CFStringRef runLoopMode;
CFRunLoopSourceRef initEnumRunLoopSource;
CFMutableDictionaryRef initRetVals;
Boolean isOpen;
IOOptionBits openOptions;
IOOptionBits createOptions;
void * inputContext;
IOHIDValueCallback inputCallback;
void * reportContext;
IOHIDReportCallback reportCallback;
void * matchContext;
IOHIDDeviceCallback matchCallback;
void * removalContext;
IOHIDDeviceCallback removalCallback;
CFArrayRef inputMatchingMultiple;
Boolean isDirty;
} __IOHIDManager, *__IOHIDManagerRef;
static const IOHIDObjectClass __IOHIDManagerClass = {
{
_kCFRuntimeCustomRefCount, "IOHIDManager", NULL, NULL, __IOHIDManagerExtRelease, NULL, NULL, NULL, NULL, NULL, _IOHIDObjectExtRetainCount },
_IOHIDObjectIntRetainCount,
__IOHIDManagerIntRelease
};
static pthread_once_t __sessionTypeInit = PTHREAD_ONCE_INIT;
static CFTypeID __kIOHIDManagerTypeID = _kCFRuntimeNotATypeID;
void __IOHIDManagerRegister(void)
{
__kIOHIDManagerTypeID = _CFRuntimeRegisterClass(&__IOHIDManagerClass.cfClass);
}
IOHIDManagerRef __IOHIDManagerCreate(
CFAllocatorRef allocator,
CFAllocatorContext * context __unused)
{
uint32_t size;
size = sizeof(__IOHIDManager) - sizeof(CFRuntimeBase);
return (IOHIDManagerRef)_IOHIDObjectCreateInstance(allocator, IOHIDManagerGetTypeID(), size, NULL);
}
void __IOHIDManagerExtRelease( CFTypeRef object )
{
IOHIDManagerRef manager = (IOHIDManagerRef)object;
if ( (manager->createOptions & kIOHIDManagerOptionUsePersistentProperties) &&
!(manager->createOptions & kIOHIDManagerOptionDoNotSaveProperties)) {
__IOHIDManagerSaveProperties(manager, NULL);
}
if ( manager->isOpen ) {
IOHIDManagerClose(manager, manager->openOptions);
}
if ( manager->runLoop ) {
IOHIDManagerUnscheduleFromRunLoop(manager, manager->runLoop, manager->runLoopMode);
}
if (manager->notifyPort) {
CFRunLoopSourceRef source = IONotificationPortGetRunLoopSource(manager->notifyPort);
if (source) {
CFRunLoopSourceInvalidate(source);
if (manager->runLoop)
CFRunLoopRemoveSource(manager->runLoop,
source,
manager->runLoopMode);
}
}
if (manager->initEnumRunLoopSource) {
CFRunLoopSourceInvalidate(manager->initEnumRunLoopSource);
if (manager->runLoop)
CFRunLoopRemoveSource(manager->runLoop,
manager->initEnumRunLoopSource,
manager->runLoopMode);
}
}
void __IOHIDManagerIntRelease( CFTypeRef object )
{
IOHIDManagerRef manager = (IOHIDManagerRef)object;
if ( manager->notifyPort ) {
IONotificationPortDestroy(manager->notifyPort);
manager->notifyPort = NULL;
}
if ( manager->initEnumRunLoopSource ) {
CFRelease(manager->initEnumRunLoopSource);
manager->initEnumRunLoopSource = NULL;
}
if ( manager->devices ) {
CFRelease(manager->devices);
manager->devices = NULL;
}
if ( manager->deviceInputBuffers ) {
CFRelease(manager->deviceInputBuffers);
manager->deviceInputBuffers = NULL;
}
if ( manager->iterators ) {
CFRelease(manager->iterators);
manager->iterators = NULL;
}
if ( manager->properties ) {
CFRelease(manager->properties);
manager->properties = NULL;
}
if ( manager->initRetVals ) {
CFRelease(manager->initRetVals);
manager->initRetVals = NULL;
}
if ( manager->inputMatchingMultiple ) {
CFRelease(manager->inputMatchingMultiple);
manager->inputMatchingMultiple = NULL;
}
}
void __IOHIDManagerSetDeviceMatching(
IOHIDManagerRef manager,
CFDictionaryRef matching)
{
CFMutableDictionaryRef matchingDict = NULL;
io_iterator_t iterator;
IOReturn kr;
if (!manager->notifyPort) {
manager->notifyPort = IONotificationPortCreate(kIOMasterPortDefault);
if (manager->runLoop) {
CFRunLoopSourceRef source = IONotificationPortGetRunLoopSource(manager->notifyPort);
if (source) {
CFRunLoopAddSource(
manager->runLoop,
source,
manager->runLoopMode);
}
}
}
matchingDict = IOServiceMatching(kIOHIDDeviceKey);
if ( !matchingDict )
return;
__IOHIDManagerMergeDictionaries(matching, matchingDict);
kr = IOServiceAddMatchingNotification(manager->notifyPort,
kIOFirstMatchNotification,
matchingDict,
__IOHIDManagerDeviceAdded,
manager,
&iterator
);
if ( kr != kIOReturnSuccess )
return;
if ( !manager->iterators ) {
CFSetCallBacks callbacks;
bzero(&callbacks, sizeof(CFSetCallBacks));
callbacks.retain = _IOObjectCFRetain;
callbacks.release = _IOObjectCFRelease;
manager->iterators = CFSetCreateMutable(
CFGetAllocator(manager),
0,
&callbacks);
if ( !manager->iterators )
return;
}
intptr_t temp = iterator;
CFSetAddValue(manager->iterators, (void *)temp);
IOObjectRelease(iterator);
__IOHIDManagerDeviceAdded(manager, iterator);
}
void __IOHIDManagerDeviceAdded( void * refcon,
io_iterator_t iterator)
{
IOHIDManagerRef manager = (IOHIDManagerRef)refcon;
IOHIDDeviceRef device;
IOReturn retVal;
io_service_t service;
Boolean initial = FALSE;
while (( service = IOIteratorNext(iterator) )) {
device = IOHIDDeviceCreate(CFGetAllocator(manager), service);
if ( device ) {
if ( !manager->devices ) {
manager->devices = CFSetCreateMutable(
CFGetAllocator(manager),
0,
&kCFTypeSetCallBacks);
initial = TRUE;
if ( manager->isOpen )
manager->initRetVals = CFDictionaryCreateMutable(
CFGetAllocator(manager),
0,
&kCFTypeDictionaryKeyCallBacks,
NULL);
}
if ( manager->devices ) {
CFSetAddValue(manager->devices, device);
}
CFRelease(device);
DeviceApplierArgs args;
args.manager = manager;
args.options = 0;
IOHIDDeviceRegisterRemovalCallback(
device,
__IOHIDManagerDeviceRemoved,
manager);
retVal = kIOReturnSuccess;
if ( manager->isOpen )
args.options |= kDeviceApplierOpen;
if ( manager->inputMatchingMultiple )
args.options |= kDeviceApplierSetInputMatching;
if ( manager->inputCallback )
args.options |= kDeviceApplierSetInputCallback;
if ( manager->reportCallback )
args.options |= kDeviceApplierSetInputReportCallback;
if ( manager->runLoop ) {
args.options |= kDeviceApplierScheduleRunLoop;
if ( !initial && manager->matchCallback )
args.options |= kDeviceApplierInitEnumCallback;
}
__IOHIDManagerDeviceApplier((const void *)device, &args);
if ( (manager->createOptions & kIOHIDManagerOptionUsePersistentProperties) &&
!(manager->createOptions & kIOHIDManagerOptionDoNotLoadProperties)) {
__IOHIDDeviceLoadProperties(device);
}
if (manager->properties) {
CFDictionaryApplyFunction(manager->properties,
__IOHIDApplyPropertiesToDeviceFromDictionary,
device);
}
}
IOObjectRelease(service);
}
if ( initial ) {
CFRunLoopSourceContext context;
bzero(&context, sizeof(CFRunLoopSourceContext));
context.info = manager;
context.perform = __IOHIDManagerInitialEnumCallback;
manager->initEnumRunLoopSource = CFRunLoopSourceCreate(
CFGetAllocator(manager),
0,
&context);
if ( manager->runLoop && manager->initEnumRunLoopSource ) {
CFRunLoopAddSource(
manager->runLoop,
manager->initEnumRunLoopSource,
manager->runLoopMode);
CFRunLoopSourceSignal(manager->initEnumRunLoopSource);
}
}
}
void __IOHIDManagerDeviceRemoved( void * context,
IOReturn result __unused,
void * sender)
{
IOHIDManagerRef manager = (IOHIDManagerRef)context;
if ( manager->deviceInputBuffers )
CFDictionaryRemoveValue(manager->deviceInputBuffers, sender);
if ( (manager->createOptions & kIOHIDManagerOptionUsePersistentProperties) &&
!(manager->createOptions & kIOHIDManagerOptionDoNotSaveProperties)) {
if (CFSetContainsValue(manager->devices, sender))
__IOHIDDeviceSaveProperties((IOHIDDeviceRef)sender, NULL);
}
CFSetRemoveValue(manager->devices, sender);
if ( manager->removalCallback )
(*manager->removalCallback)(manager->removalContext,
kIOReturnSuccess,
manager,
sender);
}
void __IOHIDManagerInitialEnumCallback(void * info)
{
IOHIDManagerRef manager = (IOHIDManagerRef)info;
if ( manager->matchCallback && manager->devices ) {
DeviceApplierArgs args;
args.manager = manager;
args.options = kDeviceApplierInitEnumCallback;
CFSetApplyFunction( manager->devices,
__IOHIDManagerDeviceApplier,
&args);
}
if (manager->runLoop)
CFRunLoopRemoveSource(manager->runLoop,
manager->initEnumRunLoopSource,
manager->runLoopMode);
CFRelease(manager->initEnumRunLoopSource);
manager->initEnumRunLoopSource = NULL;
if ( manager->initRetVals ) {
CFRelease(manager->initRetVals);
manager->initRetVals = NULL;
}
}
void __IOHIDManagerDeviceApplier(
const void * value,
void * context)
{
DeviceApplierArgs * args = (DeviceApplierArgs*)context;
IOHIDDeviceRef device = (IOHIDDeviceRef)value;
intptr_t retVal = kIOReturnSuccess;
if ( args->options & kDeviceApplierOpen ) {
retVal = IOHIDDeviceOpen( device,
args->manager->openOptions);
if ( args->manager->initRetVals )
CFDictionarySetValue(args->manager->initRetVals, device, (void*)retVal);
}
if ( args->options & kDeviceApplierClose )
retVal = IOHIDDeviceClose( device,
args->manager->openOptions);
if ( args->options & kDeviceApplierInitEnumCallback ) {
if ( args->manager->initRetVals )
retVal = (intptr_t)CFDictionaryGetValue(
args->manager->initRetVals,
device);
(*args->manager->matchCallback)( args->manager->matchContext,
retVal,
args->manager,
device);
}
if ( args->options & kDeviceApplierSetInputMatching )
IOHIDDeviceSetInputValueMatchingMultiple(
device,
args->manager->inputMatchingMultiple);
if ( args->options & kDeviceApplierSetInputCallback )
IOHIDDeviceRegisterInputValueCallback(
device,
args->manager->inputCallback,
args->manager->inputContext);
if ( args->options & kDeviceApplierSetInputReportCallback ) {
CFMutableDataRef dataRef = NULL;
if ( !args->manager->deviceInputBuffers ) {
args->manager->deviceInputBuffers = CFDictionaryCreateMutable(CFGetAllocator(args->manager), 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
}
dataRef = (CFMutableDataRef)CFDictionaryGetValue(args->manager->deviceInputBuffers, device);
if ( !dataRef ) {
CFNumberRef number = IOHIDDeviceGetProperty(device, CFSTR(kIOHIDMaxInputReportSizeKey));
CFIndex length = 64;
if ( number ) {
CFNumberGetValue(number, kCFNumberCFIndexType, &length);
}
dataRef = CFDataCreateMutable(CFGetAllocator(args->manager), length);
if ( dataRef ) {
CFDataSetLength(dataRef, length);
CFDictionarySetValue(args->manager->deviceInputBuffers, device, dataRef);
CFRelease(dataRef);
}
}
IOHIDDeviceRegisterInputReportCallback(
device,
(uint8_t *)CFDataGetMutableBytePtr(dataRef),
CFDataGetLength(dataRef),
args->manager->reportCallback,
args->manager->reportContext);
}
if ( args->options & kDeviceApplierScheduleRunLoop )
IOHIDDeviceScheduleWithRunLoop( device,
args->manager->runLoop,
args->manager->runLoopMode);
if ( args->options & kDeviceApplierUnscheduleRunLoop )
IOHIDDeviceUnscheduleFromRunLoop( device,
args->manager->runLoop,
args->manager->runLoopMode);
if ( args->retVal == kIOReturnSuccess && retVal != kIOReturnSuccess )
args->retVal = retVal;
}
CFTypeID IOHIDManagerGetTypeID(void)
{
if ( _kCFRuntimeNotATypeID == __kIOHIDManagerTypeID )
pthread_once(&__sessionTypeInit, __IOHIDManagerRegister);
return __kIOHIDManagerTypeID;
}
IOHIDManagerRef IOHIDManagerCreate(
CFAllocatorRef allocator,
IOOptionBits options)
{
IOHIDManagerRef manager;
manager = __IOHIDManagerCreate(allocator, NULL);
if (!manager)
return (_Nonnull IOHIDManagerRef)NULL;
manager->createOptions = options;
if ( (manager->createOptions & kIOHIDManagerOptionUsePersistentProperties) &&
!(manager->createOptions & kIOHIDManagerOptionDoNotLoadProperties))
{
__IOHIDManagerLoadProperties(manager);
}
return manager;
}
IOReturn IOHIDManagerOpen(
IOHIDManagerRef manager,
IOOptionBits options)
{
IOReturn retVal = kIOReturnSuccess;
if ( !manager->isOpen ) {
manager->isOpen = TRUE;
manager->openOptions = options;
if ( manager->devices ) {
DeviceApplierArgs args;
args.manager = manager;
args.options = kDeviceApplierOpen;
args.retVal = kIOReturnSuccess;
if ( manager->inputMatchingMultiple )
args.options |= kDeviceApplierSetInputMatching;
if ( manager->inputCallback )
args.options |= kDeviceApplierSetInputCallback;
if ( manager->reportCallback )
args.options |= kDeviceApplierSetInputReportCallback;
CFSetApplyFunction( manager->devices,
__IOHIDManagerDeviceApplier,
&args);
retVal = args.retVal;
}
}
return retVal;
}
IOReturn IOHIDManagerClose(
IOHIDManagerRef manager,
IOOptionBits options)
{
IOReturn retVal = kIOReturnSuccess;
if (manager->runLoop) {
IOHIDManagerUnscheduleFromRunLoop(manager, manager->runLoop, manager->runLoopMode);
}
if ( manager->isOpen ) {
manager->isOpen = FALSE;
manager->openOptions = options;
if ( manager->devices ) {
DeviceApplierArgs args;
args.manager = manager;
args.options = kDeviceApplierClose;
args.retVal = kIOReturnSuccess;
CFSetApplyFunction( manager->devices,
__IOHIDManagerDeviceApplier,
&args);
retVal = args.retVal;
}
}
if ( (manager->createOptions & kIOHIDManagerOptionUsePersistentProperties) &&
!(manager->createOptions & kIOHIDManagerOptionDoNotSaveProperties)) {
__IOHIDManagerSaveProperties(manager, NULL);
}
return retVal;
}
CFTypeRef IOHIDManagerGetProperty(
IOHIDManagerRef manager,
CFStringRef key)
{
if ( !manager->properties )
return NULL;
return CFDictionaryGetValue(manager->properties, key);
}
Boolean IOHIDManagerSetProperty(
IOHIDManagerRef manager,
CFStringRef key,
CFTypeRef value)
{
__IOHIDApplyPropertyToSetContext context = {
key, value
};
if (!manager->properties) {
manager->properties = CFDictionaryCreateMutable(CFGetAllocator(manager),
0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
if (!manager->properties)
return FALSE;
}
manager->isDirty = TRUE;
CFDictionarySetValue(manager->properties, key, value);
if (manager->devices)
CFSetApplyFunction(manager->devices, __IOHIDApplyPropertyToDeviceSet, &context);
return TRUE;
}
void IOHIDManagerSetDeviceMatching(
IOHIDManagerRef manager,
CFDictionaryRef matching)
{
CFArrayRef multiple = NULL;
if ( matching )
multiple = CFArrayCreate(CFGetAllocator(manager),
(const void **)&matching,
1,
&kCFTypeArrayCallBacks);
IOHIDManagerSetDeviceMatchingMultiple(manager, multiple);
if ( multiple )
CFRelease(multiple);
}
void IOHIDManagerSetDeviceMatchingMultiple(
IOHIDManagerRef manager,
CFArrayRef multiple)
{
CFIndex i, count;
CFTypeRef value;
if ( manager->devices ) {
if ( (manager->createOptions & kIOHIDManagerOptionUsePersistentProperties) &&
!(manager->createOptions & kIOHIDManagerOptionDoNotSaveProperties)) {
__IOHIDManagerSaveProperties(manager, NULL);
}
CFSetRemoveAllValues(manager->devices);
}
if ( manager->iterators )
CFSetRemoveAllValues(manager->iterators);
if ( manager->deviceInputBuffers )
CFDictionaryRemoveAllValues(manager->deviceInputBuffers);
if ( multiple ) {
count = CFArrayGetCount(multiple);
for ( i=0; i<count; i++ ) {
value = CFArrayGetValueAtIndex(multiple, i);
if (CFDictionaryGetTypeID() == CFGetTypeID(value))
__IOHIDManagerSetDeviceMatching(manager, (CFDictionaryRef)value);
}
}
else
__IOHIDManagerSetDeviceMatching(manager, NULL);
}
CFSetRef IOHIDManagerCopyDevices(
IOHIDManagerRef manager)
{
return manager->devices ?
CFSetCreateCopy(CFGetAllocator(manager), manager->devices) : NULL;
}
void IOHIDManagerRegisterDeviceMatchingCallback(
IOHIDManagerRef manager,
IOHIDDeviceCallback callback,
void * context)
{
manager->matchCallback = callback;
manager->matchContext = context;
}
void IOHIDManagerRegisterDeviceRemovalCallback(
IOHIDManagerRef manager,
IOHIDDeviceCallback callback,
void * context)
{
manager->removalCallback = callback;
manager->removalContext = context;
}
void IOHIDManagerRegisterInputReportCallback(
IOHIDManagerRef manager,
IOHIDReportCallback callback,
void * context)
{
manager->reportCallback = callback;
manager->reportContext = context;
if ( manager->isOpen && manager->devices ) {
DeviceApplierArgs args;
args.manager = manager;
args.options = kDeviceApplierSetInputReportCallback;
CFSetApplyFunction( manager->devices,
__IOHIDManagerDeviceApplier,
&args);
}
}
void IOHIDManagerRegisterInputValueCallback(
IOHIDManagerRef manager,
IOHIDValueCallback callback,
void * context)
{
manager->inputCallback = callback;
manager->inputContext = context;
if ( manager->isOpen && manager->devices ) {
DeviceApplierArgs args;
args.manager = manager;
args.options = kDeviceApplierSetInputCallback;
CFSetApplyFunction( manager->devices,
__IOHIDManagerDeviceApplier,
&args);
}
}
void IOHIDManagerSetInputValueMatching(
IOHIDManagerRef manager,
CFDictionaryRef matching)
{
if ( matching ) {
CFArrayRef multiple = CFArrayCreate(CFGetAllocator(manager), (const void **)&matching, 1, &kCFTypeArrayCallBacks);
IOHIDManagerSetInputValueMatchingMultiple(manager, multiple);
CFRelease(multiple);
} else {
IOHIDManagerSetInputValueMatchingMultiple(manager, NULL);
}
}
void IOHIDManagerSetInputValueMatchingMultiple(
IOHIDManagerRef manager,
CFArrayRef multiple)
{
if ( manager->inputMatchingMultiple )
CFRelease(manager->inputMatchingMultiple);
if ( multiple )
CFRetain(multiple);
manager->inputMatchingMultiple = multiple;
if ( manager->isOpen && manager->devices ) {
DeviceApplierArgs args;
args.manager = manager;
args.options = kDeviceApplierSetInputMatching;
CFSetApplyFunction( manager->devices,
__IOHIDManagerDeviceApplier,
&args);
}
}
void IOHIDManagerScheduleWithRunLoop(
IOHIDManagerRef manager,
CFRunLoopRef runLoop,
CFStringRef runLoopMode)
{
manager->runLoop = runLoop;
manager->runLoopMode = runLoopMode;
if ( manager->runLoop ) {
if (manager->notifyPort) {
CFRunLoopSourceRef source = IONotificationPortGetRunLoopSource(manager->notifyPort);
if (source) {
CFRunLoopAddSource(
manager->runLoop,
source,
manager->runLoopMode);
}
}
if ( manager->initEnumRunLoopSource ) {
CFRunLoopAddSource(
manager->runLoop,
manager->initEnumRunLoopSource,
manager->runLoopMode);
CFRunLoopSourceSignal(manager->initEnumRunLoopSource);
}
if ( manager->devices ) {
DeviceApplierArgs args;
args.manager = manager;
args.options = kDeviceApplierScheduleRunLoop;
CFSetApplyFunction( manager->devices,
__IOHIDManagerDeviceApplier,
&args);
}
}
}
void IOHIDManagerUnscheduleFromRunLoop(
IOHIDManagerRef manager,
CFRunLoopRef runLoop,
CFStringRef runLoopMode)
{
if (!manager->runLoop)
return;
if (!CFEqual(manager->runLoop, runLoop) ||
!CFEqual(manager->runLoopMode, runLoopMode))
return;
if ( manager->devices ) {
DeviceApplierArgs args;
args.manager = manager;
args.options = kDeviceApplierUnscheduleRunLoop;
CFSetApplyFunction( manager->devices,
__IOHIDManagerDeviceApplier,
&args);
if (manager->initEnumRunLoopSource) {
CFRunLoopSourceInvalidate(manager->initEnumRunLoopSource);
CFRunLoopRemoveSource(manager->runLoop,
manager->initEnumRunLoopSource,
manager->runLoopMode);
CFRelease(manager->initEnumRunLoopSource);
manager->initEnumRunLoopSource = NULL;
}
}
manager->runLoop = NULL;
manager->runLoopMode = NULL;
}
void IOHIDManagerSaveToPropertyDomain(IOHIDManagerRef manager,
CFStringRef applicationID,
CFStringRef userName,
CFStringRef hostName,
IOOptionBits options)
{
__IOHIDPropertyContext context = {
applicationID, userName, hostName, options
};
if (manager && applicationID && userName && hostName) {
__IOHIDManagerSaveProperties(manager, &context);
}
else {
}
}
CFStringRef __IOHIDManagerGetRootKey()
{
return CFSTR(kIOHIDManagerKey);
}
void __IOHIDManagerSaveProperties(IOHIDManagerRef manager, __IOHIDPropertyContext *context)
{
if (manager->isDirty && manager->properties) {
__IOHIDPropertySaveToKeyWithSpecialKeys(manager->properties,
__IOHIDManagerGetRootKey(),
NULL,
context);
manager->isDirty = FALSE;
}
if (manager->devices)
CFSetApplyFunction(manager->devices, __IOHIDSaveDeviceSet, context);
}
void __IOHIDManagerLoadProperties(IOHIDManagerRef manager)
{
CFMutableDictionaryRef properties = __IOHIDPropertyLoadDictionaryFromKey(__IOHIDManagerGetRootKey());
if (properties) {
CFRELEASE_IF_NOT_NULL(manager->properties);
manager->properties = properties;
manager->isDirty = FALSE;
}
}
void __IOHIDPropertySaveWithContext(CFStringRef key, CFPropertyListRef value, __IOHIDPropertyContext *context)
{
if (key && value) {
if (context && context->applicationID && context->userName && context->hostName) {
CFPreferencesSetValue(key, value, context->applicationID, context->userName, context->hostName);
}
else {
CFPreferencesSetAppValue(key, value, kCFPreferencesCurrentApplication);
}
}
}
void __IOHIDPropertySaveToKeyWithSpecialKeys(CFDictionaryRef dictionary, CFStringRef key, CFStringRef *specialKeys, __IOHIDPropertyContext *context)
{
CFMutableDictionaryRef temp = CFDictionaryCreateMutableCopy(NULL, 0, dictionary);
if (specialKeys) {
while (*specialKeys) {
CFTypeRef value = CFDictionaryGetValue(temp, *specialKeys);
if (value) {
CFStringRef subKey = CFStringCreateWithFormat(NULL, NULL,
CFSTR("%@#%@"),
key,
*specialKeys);
__IOHIDPropertySaveWithContext(subKey, value, context);
CFDictionaryRemoveValue(temp, *specialKeys);
CFRelease(subKey);
}
specialKeys++;
}
}
CFAbsoluteTime time = CFAbsoluteTimeGetCurrent();
CFNumberRef timeNum = CFNumberCreate(NULL, kCFNumberDoubleType, &time);
CFDictionaryAddValue(temp, CFSTR("time of last save"), timeNum);
CFRelease(timeNum);
__IOHIDPropertySaveWithContext(key, temp, context);
CFRelease(temp);
}
CFMutableDictionaryRef __IOHIDPropertyLoadDictionaryFromKey(CFStringRef key)
{
CFMutableDictionaryRef result = NULL;
CFDictionaryRef baseProperties = CFPreferencesCopyAppValue(key, kCFPreferencesCurrentApplication);
if (baseProperties && (CFGetTypeID(baseProperties) == CFDictionaryGetTypeID())) {
result = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
CFDictionaryRef properties = CFPreferencesCopyValue(key, kCFPreferencesAnyApplication, kCFPreferencesAnyUser, kCFPreferencesAnyHost);
if (properties && (CFGetTypeID(properties) == CFDictionaryGetTypeID()))
__IOHIDManagerMergeDictionaries(properties, result);
if (properties)
CFRelease(properties);
properties = CFPreferencesCopyValue(key, kCFPreferencesAnyApplication, kCFPreferencesAnyUser, kCFPreferencesCurrentHost);
if (properties && (CFGetTypeID(properties) == CFDictionaryGetTypeID()))
__IOHIDManagerMergeDictionaries(properties, result);
if (properties)
CFRelease(properties);
properties = CFPreferencesCopyValue(key, kCFPreferencesAnyApplication, kCFPreferencesCurrentUser, kCFPreferencesAnyHost);
if (properties && (CFGetTypeID(properties) == CFDictionaryGetTypeID()))
__IOHIDManagerMergeDictionaries(properties, result);
if (properties)
CFRelease(properties);
properties = CFPreferencesCopyValue(key, kCFPreferencesAnyApplication, kCFPreferencesCurrentUser, kCFPreferencesCurrentHost);
if (properties && (CFGetTypeID(properties) == CFDictionaryGetTypeID()))
__IOHIDManagerMergeDictionaries(properties, result);
if (properties)
CFRelease(properties);
properties = CFPreferencesCopyValue(key, kCFPreferencesCurrentApplication, kCFPreferencesAnyUser, kCFPreferencesAnyHost);
if (properties && (CFGetTypeID(properties) == CFDictionaryGetTypeID()))
__IOHIDManagerMergeDictionaries(properties, result);
if (properties)
CFRelease(properties);
properties = CFPreferencesCopyValue(key, kCFPreferencesCurrentApplication, kCFPreferencesAnyUser, kCFPreferencesCurrentHost);
if (properties && (CFGetTypeID(properties) == CFDictionaryGetTypeID()))
__IOHIDManagerMergeDictionaries(properties, result);
if (properties)
CFRelease(properties);
properties = CFPreferencesCopyValue(key, kCFPreferencesCurrentApplication, kCFPreferencesCurrentUser, kCFPreferencesAnyHost);
if (properties && (CFGetTypeID(properties) == CFDictionaryGetTypeID()))
__IOHIDManagerMergeDictionaries(properties, result);
if (properties)
CFRelease(properties);
properties = CFPreferencesCopyValue(key, kCFPreferencesCurrentApplication, kCFPreferencesCurrentUser, kCFPreferencesCurrentHost);
if (properties && (CFGetTypeID(properties) == CFDictionaryGetTypeID()))
__IOHIDManagerMergeDictionaries(properties, result);
if (properties)
CFRelease(properties);
__IOHIDManagerMergeDictionaries(baseProperties, result);
}
if (baseProperties)
CFRelease(baseProperties);
return result;
}
CFMutableDictionaryRef __IOHIDPropertyLoadFromKeyWithSpecialKeys(CFStringRef key, CFStringRef *specialKeys)
{
CFMutableDictionaryRef result = __IOHIDPropertyLoadDictionaryFromKey(key);
if (!result)
result = CFDictionaryCreateMutable(NULL, 0, &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
while (*specialKeys) {
CFStringRef subKey = CFStringCreateWithFormat(NULL, NULL,
CFSTR("%@#%@"),
key,
*specialKeys);
CFPropertyListRef value = CFPreferencesCopyAppValue(subKey, kCFPreferencesCurrentApplication);
if (value) {
CFDictionarySetValue(result, *specialKeys, value);
CFRelease(value);
}
CFRelease(subKey);
specialKeys++;
}
return result;
}
void __IOHIDManagerMergeDictionaries(CFDictionaryRef srcDict,
CFMutableDictionaryRef dstDict)
{
uint32_t count;
CFTypeRef * values;
CFStringRef * keys;
if ( !dstDict || !srcDict || !(count = CFDictionaryGetCount(srcDict)))
return;
values = (CFTypeRef *)malloc(sizeof(CFTypeRef) * count);
keys = (CFStringRef *)malloc(sizeof(CFStringRef) * count);
if ( values && keys ) {
CFDictionaryGetKeysAndValues(srcDict, (const void **)keys, (const void **)values);
for ( uint32_t i=0; i<count; i++)
CFDictionarySetValue(dstDict, keys[i], values[i]);
}
if ( values )
free(values);
if ( keys )
free(keys);
}