/src/ois/src/mac/MacHIDManager.cpp
C++ | 435 lines | 320 code | 62 blank | 53 comment | 75 complexity | 7f43ea4401f6c681f03fec82d59515d6 MD5 | raw file
1/* 2 The zlib/libpng License 3 4 Copyright (c) 2005-2007 Phillip Castaneda (pjcast -- www.wreckedgames.com) 5 6 This software is provided 'as-is', without any express or implied warranty. In no event will 7 the authors be held liable for any damages arising from the use of this software. 8 9 Permission is granted to anyone to use this software for any purpose, including commercial 10 applications, and to alter it and redistribute it freely, subject to the following 11 restrictions: 12 13 1. The origin of this software must not be misrepresented; you must not claim that 14 you wrote the original software. If you use this software in a product, 15 an acknowledgment in the product documentation would be appreciated but is 16 not required. 17 18 2. Altered source versions must be plainly marked as such, and must not be 19 misrepresented as being the original software. 20 21 3. This notice may not be removed or altered from any source distribution. 22 */ 23#include "mac/MacHIDManager.h" 24#include "mac/MacJoyStick.h" 25#include "OISException.h" 26#include "OISObject.h" 27 28#include <iostream> 29using namespace std; 30 31using namespace OIS; 32 33//------------------------------------------------------------------------------------------------------// 34//------------------------------------------------------------------------------------------------------// 35template<typename T> 36T getDictionaryItemAsRef(CFDictionaryRef dict, const char* keyName) 37{ 38 return CFDictionaryGetValue(dict, OIS_CFString(keyName)); 39} 40 41template<> 42CFArrayRef getDictionaryItemAsRef(CFDictionaryRef dict, const char* keyName) 43{ 44 CFTypeRef temp = CFDictionaryGetValue(dict, OIS_CFString(keyName)); 45 46 if(temp && CFGetTypeID(temp) == CFArrayGetTypeID()) 47 return (CFArrayRef)temp; 48 else 49 return 0; 50} 51 52template<> 53CFStringRef getDictionaryItemAsRef(CFDictionaryRef dict, const char* keyName) 54{ 55 CFTypeRef temp = CFDictionaryGetValue(dict, OIS_CFString(keyName)); 56 57 if(temp && CFGetTypeID(temp) == CFStringGetTypeID()) 58 return (CFStringRef)temp; 59 else 60 return 0; 61} 62 63template<> 64CFNumberRef getDictionaryItemAsRef(CFDictionaryRef dict, const char* keyName) 65{ 66 CFTypeRef temp = CFDictionaryGetValue(dict, OIS_CFString(keyName)); 67 68 if(temp && CFGetTypeID(temp) == CFNumberGetTypeID()) 69 return (CFNumberRef)temp; 70 else 71 return 0; 72} 73 74//------------------------------------------------------------------------------------------------------// 75//------------------------------------------------------------------------------------------------------// 76template<typename T> 77T getArrayItemAsRef(CFArrayRef array, CFIndex idx) 78{ 79 return CFArrayGetValueAtIndex(array, idx); 80} 81 82template<> 83CFDictionaryRef getArrayItemAsRef(CFArrayRef array, CFIndex idx) 84{ 85 CFTypeRef temp = CFArrayGetValueAtIndex(array, idx); 86 87 if(temp && CFGetTypeID(temp) == CFDictionaryGetTypeID()) 88 return (CFDictionaryRef)temp; 89 else 90 return 0; 91} 92 93//------------------------------------------------------------------------------------------------------// 94int getInt32(CFNumberRef ref) 95{ 96 int r = 0; 97 if (r) 98 CFNumberGetValue(ref, kCFNumberIntType, &r); 99 return r; 100} 101 102//--------------------------------------------------------------------------------// 103MacHIDManager::MacHIDManager() 104{ 105} 106 107//--------------------------------------------------------------------------------// 108MacHIDManager::~MacHIDManager() 109{ 110} 111 112//------------------------------------------------------------------------------------------------------// 113void MacHIDManager::initialize() 114{ 115 //Make the search more specific by adding usage flags 116 int usage = kHIDUsage_GD_Joystick; 117 int page = kHIDPage_GenericDesktop; 118 119 io_iterator_t iterator = lookUpDevices(usage, page); 120 121 if(iterator) 122 iterateAndOpenDevices(iterator); 123 124 //Doesn't support multiple usage flags, iterate twice 125 usage = kHIDUsage_GD_GamePad; 126 iterator = lookUpDevices(usage, page); 127 128 if(iterator) 129 iterateAndOpenDevices(iterator); 130} 131 132//------------------------------------------------------------------------------------------------------// 133io_iterator_t MacHIDManager::lookUpDevices(int usage, int page) 134{ 135 CFMutableDictionaryRef deviceLookupMap = IOServiceMatching(kIOHIDDeviceKey); 136 if(!deviceLookupMap) 137 OIS_EXCEPT(E_General, "Could not setup HID device search parameters"); 138 139 CFNumberRef usageRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &usage); 140 CFNumberRef pageRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &page); 141 142 CFDictionarySetValue(deviceLookupMap, CFSTR(kIOHIDPrimaryUsageKey), usageRef); 143 CFDictionarySetValue(deviceLookupMap, CFSTR(kIOHIDPrimaryUsagePageKey), pageRef); 144 145 //IOServiceGetMatchingServices consumes the map so we do not have to release it ourself 146 io_iterator_t iterator = 0; 147 IOReturn result = IOServiceGetMatchingServices(kIOMasterPortDefault, deviceLookupMap, &iterator); 148 149 CFRelease(usageRef); 150 CFRelease(pageRef); 151 152 if(result == kIOReturnSuccess) 153 { 154 return iterator; 155 } 156 //TODO: Throw exception instead? 157 else 158 { 159 return 0; 160 } 161} 162 163//------------------------------------------------------------------------------------------------------// 164void MacHIDManager::iterateAndOpenDevices(io_iterator_t iterator) 165{ 166 io_object_t hidDevice = 0; 167 while ((hidDevice = IOIteratorNext(iterator)) !=0) 168 { 169 //Get the current registry items property map 170 CFMutableDictionaryRef propertyMap = 0; 171 if (IORegistryEntryCreateCFProperties(hidDevice, &propertyMap, kCFAllocatorDefault, kNilOptions) == KERN_SUCCESS && propertyMap) 172 { 173 //Go through device to find all needed info 174 HidInfo* hid = enumerateDeviceProperties(propertyMap); 175 176 if(hid) 177 { 178 //todo - we need to hold an open interface so we do not have to enumerate again later 179 //should be able to watch for device removals also 180 181 // Testing opening / closing interface 182 IOCFPlugInInterface **pluginInterface = NULL; 183 SInt32 score = 0; 184 if (IOCreatePlugInInterfaceForService(hidDevice, kIOHIDDeviceUserClientTypeID, kIOCFPlugInInterfaceID, &pluginInterface, &score) == kIOReturnSuccess) 185 { 186 IOHIDDeviceInterface **interface; 187 188 HRESULT pluginResult = (*pluginInterface)->QueryInterface(pluginInterface, CFUUIDGetUUIDBytes(kIOHIDDeviceInterfaceID), (void **)&(interface)); 189 190 if(pluginResult != S_OK) 191 OIS_EXCEPT(E_General, "Not able to create plugin interface"); 192 193 IODestroyPlugInInterface(pluginInterface); 194 195 hid->interface = interface; 196 197 //Check for duplicates - some devices have multiple usage 198 if(std::find(mDeviceList.begin(), mDeviceList.end(), hid) == mDeviceList.end()) 199 mDeviceList.push_back(hid); 200 } 201 } 202 CFRelease(propertyMap); 203 } 204 } 205 206 IOObjectRelease(iterator); 207} 208 209//------------------------------------------------------------------------------------------------------// 210HidInfo* MacHIDManager::enumerateDeviceProperties(CFMutableDictionaryRef propertyMap) 211{ 212 HidInfo* info = new HidInfo(); 213 214 info->type = OISJoyStick; 215 216 CFStringRef str = getDictionaryItemAsRef<CFStringRef>(propertyMap, kIOHIDManufacturerKey); 217 if (str) 218 info->vendor = CFStringGetCStringPtr(str, CFStringGetSystemEncoding()); 219 220 str = getDictionaryItemAsRef<CFStringRef>(propertyMap, kIOHIDProductKey); 221 if (str) 222 info->productKey = CFStringGetCStringPtr(str, CFStringGetSystemEncoding()); 223 224 info->combinedKey = info->vendor + " " + info->productKey; 225 226 //Go through all items in this device (i.e. buttons, hats, sticks, axes, etc) 227 CFArrayRef array = getDictionaryItemAsRef<CFArrayRef>(propertyMap, kIOHIDElementKey); 228 if (array) 229 for (int i = 0; i < CFArrayGetCount(array); i++) 230 parseDeviceProperties(getArrayItemAsRef<CFDictionaryRef>(array, i)); 231 232 return info; 233} 234 235//------------------------------------------------------------------------------------------------------// 236void MacHIDManager::parseDeviceProperties(CFDictionaryRef properties) 237{ 238 if(!properties) 239 return; 240 241 CFArrayRef array = getDictionaryItemAsRef<CFArrayRef>(properties, kIOHIDElementKey); 242 if (array) 243 { 244 for (int i = 0; i < CFArrayGetCount(array); i++) 245 { 246 CFDictionaryRef element = getArrayItemAsRef<CFDictionaryRef>(array, i); 247 if (element) 248 { 249 if(getInt32(getDictionaryItemAsRef<CFNumberRef>(element, kIOHIDElementTypeKey)) == kIOHIDElementTypeCollection) 250 { //Check if we need to recurse further intoi another collection 251 if(getInt32(getDictionaryItemAsRef<CFNumberRef>(element, kIOHIDElementUsagePageKey)) == kHIDPage_GenericDesktop) 252 parseDeviceProperties(element); 253 } 254 else 255 { 256 switch(getInt32(getDictionaryItemAsRef<CFNumberRef>(element, kIOHIDElementUsagePageKey))) 257 { 258 case kHIDPage_GenericDesktop: 259 switch(getInt32(getDictionaryItemAsRef<CFNumberRef>(element, kIOHIDElementUsageKey))) 260 { 261 case kHIDUsage_GD_Pointer: 262 cout << "\tkHIDUsage_GD_Pointer\n"; 263 parseDevicePropertiesGroup(element); 264 break; 265 case kHIDUsage_GD_X: 266 case kHIDUsage_GD_Y: 267 case kHIDUsage_GD_Z: 268 case kHIDUsage_GD_Rx: 269 case kHIDUsage_GD_Ry: 270 case kHIDUsage_GD_Rz: 271 cout << "\tAxis\n"; 272 break; 273 case kHIDUsage_GD_Slider: 274 case kHIDUsage_GD_Dial: 275 case kHIDUsage_GD_Wheel: 276 cout << "\tUnsupported kHIDUsage_GD_Wheel\n"; 277 break; 278 case kHIDUsage_GD_Hatswitch: 279 cout << "\tUnsupported - kHIDUsage_GD_Hatswitch\n"; 280 break; 281 } 282 break; 283 case kHIDPage_Button: 284 cout << "\tkHIDPage_Button\n"; 285 break; 286 } 287 } 288 } 289 } 290 } 291} 292 293//------------------------------------------------------------------------------------------------------// 294void MacHIDManager::parseDevicePropertiesGroup(CFDictionaryRef properties) 295{ 296 if(!properties) 297 return; 298 299 CFArrayRef array = getDictionaryItemAsRef<CFArrayRef>(properties, kIOHIDElementKey); 300 if(array) 301 { 302 for (int i = 0; i < CFArrayGetCount(array); i++) 303 { 304 CFDictionaryRef element = getArrayItemAsRef<CFDictionaryRef>(array, i); 305 if (element) 306 { 307 switch(getInt32(getDictionaryItemAsRef<CFNumberRef>(element, kIOHIDElementUsagePageKey))) 308 { 309 case kHIDPage_GenericDesktop: 310 switch(getInt32(getDictionaryItemAsRef<CFNumberRef>(element, kIOHIDElementUsageKey))) 311 { 312 case kHIDUsage_GD_X: 313 case kHIDUsage_GD_Y: 314 case kHIDUsage_GD_Z: 315 case kHIDUsage_GD_Rx: 316 case kHIDUsage_GD_Ry: 317 case kHIDUsage_GD_Rz: 318 cout << "\t\tAxis\n"; 319 break; 320 case kHIDUsage_GD_Slider: 321 case kHIDUsage_GD_Dial: 322 case kHIDUsage_GD_Wheel: 323 cout << "\tUnsupported - kHIDUsage_GD_Wheel\n"; 324 break; 325 case kHIDUsage_GD_Hatswitch: 326 cout << "\tUnsupported - kHIDUsage_GD_Hatswitch\n"; 327 break; 328 } 329 break; 330 case kHIDPage_Button: 331 break; 332 } 333 } 334 } 335 } 336} 337 338//--------------------------------------------------------------------------------// 339DeviceList MacHIDManager::freeDeviceList() 340{ 341 DeviceList ret; 342 HidInfoList::iterator it = mDeviceList.begin(), end = mDeviceList.end(); 343 for(; it != end; ++it) 344 { 345 if((*it)->inUse == false) 346 ret.insert(std::make_pair((*it)->type, (*it)->combinedKey)); 347 } 348 349 return ret; 350} 351 352//--------------------------------------------------------------------------------// 353int MacHIDManager::totalDevices(Type iType) 354{ 355 int ret = 0; 356 HidInfoList::iterator it = mDeviceList.begin(), end = mDeviceList.end(); 357 358 for(; it != end; ++it) 359 { 360 if((*it)->type == iType) 361 ret++; 362 } 363 364 return ret; 365} 366 367//--------------------------------------------------------------------------------// 368int MacHIDManager::freeDevices(Type iType) 369{ 370 int ret = 0; 371 HidInfoList::iterator it = mDeviceList.begin(), end = mDeviceList.end(); 372 373 for(; it != end; ++it) 374 { 375 if((*it)->inUse == false && (*it)->type == iType) 376 ret++; 377 } 378 379 return ret; 380} 381 382//--------------------------------------------------------------------------------// 383bool MacHIDManager::vendorExist(Type iType, const std::string & vendor) 384{ 385 HidInfoList::iterator it = mDeviceList.begin(), end = mDeviceList.end(); 386 387 for(; it != end; ++it) 388 { 389 if((*it)->type == iType && (*it)->combinedKey == vendor) 390 return true; 391 } 392 393 return false; 394} 395 396//--------------------------------------------------------------------------------// 397Object* MacHIDManager::createObject(InputManager* creator, Type iType, bool bufferMode, 398 const std::string & vendor) 399{ 400 Object *obj = 0; 401 402 HidInfoList::iterator it = mDeviceList.begin(), end = mDeviceList.end(); 403 for(; it != end; ++it) 404 { 405 if((*it)->inUse == false && (*it)->type == iType && (vendor == "" || (*it)->combinedKey == vendor)) 406 { 407 switch(iType) 408 { 409 case OISJoyStick: 410 { 411 int totalDevs = totalDevices(iType); 412 int freeDevs = freeDevices(iType); 413 int devID = totalDevs - freeDevs; 414 415 obj = new MacJoyStick((*it)->combinedKey, bufferMode, *it, creator, devID); 416 (*it)->inUse = true; 417 return obj; 418 } 419 case OISTablet: 420 //Create MacTablet 421 break; 422 default: 423 break; 424 } 425 } 426 } 427 428 return obj; 429} 430 431//--------------------------------------------------------------------------------// 432void MacHIDManager::destroyObject(Object* obj) 433{ 434 delete obj; 435}