Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/kicklib2/src/external/ois/mac/MacHIDManager.cpp @ 8655

Last change on this file since 8655 was 8284, checked in by rgrieder, 14 years ago

Merged revisions 7978 - 8096 from kicklib to kicklib2.

  • Property svn:eol-style set to native
File size: 12.7 KB
Line 
1/*
2 The zlib/libpng License
3 
4 Copyright (c) 2006 Phillip Castaneda
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                }
203        }
204       
205        IOObjectRelease(iterator);
206}
207
208//------------------------------------------------------------------------------------------------------//
209HidInfo* MacHIDManager::enumerateDeviceProperties(CFMutableDictionaryRef propertyMap)
210{
211        HidInfo* info = new HidInfo();
212       
213        info->type = OISJoyStick;
214       
215        CFStringRef str = getDictionaryItemAsRef<CFStringRef>(propertyMap, kIOHIDManufacturerKey);
216        if (str)
217                info->vendor = CFStringGetCStringPtr(str, CFStringGetSystemEncoding());
218       
219        str = getDictionaryItemAsRef<CFStringRef>(propertyMap, kIOHIDProductKey);
220        if (str)
221                info->productKey = CFStringGetCStringPtr(str, CFStringGetSystemEncoding());
222       
223        info->combinedKey = info->vendor + " " + info->productKey;
224       
225        //Go through all items in this device (i.e. buttons, hats, sticks, axes, etc)
226        CFArrayRef array = getDictionaryItemAsRef<CFArrayRef>(propertyMap, kIOHIDElementKey);
227        if (array)
228                for (int i = 0; i < CFArrayGetCount(array); i++)
229                        parseDeviceProperties(getArrayItemAsRef<CFDictionaryRef>(array, i));
230       
231        return info;
232}
233
234//------------------------------------------------------------------------------------------------------//
235void MacHIDManager::parseDeviceProperties(CFDictionaryRef properties)
236{
237        if(!properties)
238                return;
239       
240        CFArrayRef array = getDictionaryItemAsRef<CFArrayRef>(properties, kIOHIDElementKey);
241        if (array)
242        {
243                for (int i = 0; i < CFArrayGetCount(array); i++)
244                {
245                        CFDictionaryRef element = getArrayItemAsRef<CFDictionaryRef>(array, i);
246                        if (element)
247                        {
248                                if(getInt32(getDictionaryItemAsRef<CFNumberRef>(element, kIOHIDElementTypeKey)) == kIOHIDElementTypeCollection) 
249                                {       //Check if we need to recurse further intoi another collection
250                                        if(getInt32(getDictionaryItemAsRef<CFNumberRef>(element, kIOHIDElementUsagePageKey)) == kHIDPage_GenericDesktop)
251                                                parseDeviceProperties(element);
252                                }
253                                else
254                                {
255                                        switch(getInt32(getDictionaryItemAsRef<CFNumberRef>(element, kIOHIDElementUsagePageKey)))
256                                        {
257                                                case kHIDPage_GenericDesktop:
258                                                        switch(getInt32(getDictionaryItemAsRef<CFNumberRef>(element, kIOHIDElementUsageKey)))
259                                                {
260                                                        case kHIDUsage_GD_Pointer:
261                                                                cout << "\tkHIDUsage_GD_Pointer\n";
262                                                                parseDevicePropertiesGroup(element);
263                                                                break;
264                                                        case kHIDUsage_GD_X:
265                                                        case kHIDUsage_GD_Y:
266                                                        case kHIDUsage_GD_Z:
267                                                        case kHIDUsage_GD_Rx:
268                                                        case kHIDUsage_GD_Ry:
269                                                        case kHIDUsage_GD_Rz:
270                                                                cout << "\tAxis\n";
271                                                                break;
272                                                        case kHIDUsage_GD_Slider:
273                                                        case kHIDUsage_GD_Dial:
274                                                        case kHIDUsage_GD_Wheel:
275                                                                cout << "\tUnsupported kHIDUsage_GD_Wheel\n";
276                                                                break;
277                                                        case kHIDUsage_GD_Hatswitch:
278                                                                cout << "\tUnsupported - kHIDUsage_GD_Hatswitch\n";
279                                                                break;
280                                                }
281                                                        break;
282                                                case kHIDPage_Button:
283                                                        cout << "\tkHIDPage_Button\n";
284                                                        break;
285                                        }
286                                }
287                        }
288                }
289        }
290}
291
292//------------------------------------------------------------------------------------------------------//
293void MacHIDManager::parseDevicePropertiesGroup(CFDictionaryRef properties)
294{
295        if(!properties)
296                return;
297       
298        CFArrayRef array = getDictionaryItemAsRef<CFArrayRef>(properties, kIOHIDElementKey);
299        if(array)
300        {
301                for (int i = 0; i < CFArrayGetCount(array); i++)
302                {
303                        CFDictionaryRef element = getArrayItemAsRef<CFDictionaryRef>(array, i);
304                        if (element)
305                        {
306                                switch(getInt32(getDictionaryItemAsRef<CFNumberRef>(element, kIOHIDElementUsagePageKey)))
307                                {
308                                        case kHIDPage_GenericDesktop:
309                                                switch(getInt32(getDictionaryItemAsRef<CFNumberRef>(element, kIOHIDElementUsageKey)))
310                                        {
311                                                case kHIDUsage_GD_X:
312                                                case kHIDUsage_GD_Y:
313                                                case kHIDUsage_GD_Z:
314                                                case kHIDUsage_GD_Rx:
315                                                case kHIDUsage_GD_Ry:
316                                                case kHIDUsage_GD_Rz:
317                                                        cout << "\t\tAxis\n";
318                                                        break;
319                                                case kHIDUsage_GD_Slider:
320                                                case kHIDUsage_GD_Dial:
321                                                case kHIDUsage_GD_Wheel:
322                                                        cout << "\tUnsupported - kHIDUsage_GD_Wheel\n";
323                                                        break;
324                                                case kHIDUsage_GD_Hatswitch:
325                                                        cout << "\tUnsupported - kHIDUsage_GD_Hatswitch\n";
326                                                        break;
327                                        }
328                                                break;
329                                        case kHIDPage_Button:
330                                                break;
331                                }
332                        }
333                }
334        }
335}
336
337//--------------------------------------------------------------------------------//
338DeviceList MacHIDManager::freeDeviceList()
339{
340        DeviceList ret;
341        HidInfoList::iterator it = mDeviceList.begin(), end = mDeviceList.end();
342        for(; it != end; ++it)
343        {
344                if((*it)->inUse == false)
345                        ret.insert(std::make_pair((*it)->type, (*it)->combinedKey));
346        }
347       
348        return ret;
349}
350
351//--------------------------------------------------------------------------------//
352int MacHIDManager::totalDevices(Type iType)
353{
354        int ret = 0;
355        HidInfoList::iterator it = mDeviceList.begin(), end = mDeviceList.end();
356       
357        for(; it != end; ++it)
358        {
359                if((*it)->type == iType)
360                        ret++;
361        }
362       
363        return ret;
364}
365
366//--------------------------------------------------------------------------------//
367int MacHIDManager::freeDevices(Type iType)
368{
369        int ret = 0;
370        HidInfoList::iterator it = mDeviceList.begin(), end = mDeviceList.end();
371       
372        for(; it != end; ++it)
373        {
374                if((*it)->inUse == false && (*it)->type == iType)
375                        ret++;
376        }
377       
378        return ret;
379}
380
381//--------------------------------------------------------------------------------//
382bool MacHIDManager::vendorExist(Type iType, const std::string & vendor)
383{
384        HidInfoList::iterator it = mDeviceList.begin(), end = mDeviceList.end();
385       
386        for(; it != end; ++it)
387        {
388                if((*it)->type == iType && (*it)->combinedKey == vendor)
389                        return true;
390        }
391       
392        return false;
393}
394
395//--------------------------------------------------------------------------------//
396Object* MacHIDManager::createObject(InputManager* creator, Type iType, bool bufferMode, 
397                                                                        const std::string & vendor)
398{
399        Object *obj = 0;
400       
401        HidInfoList::iterator it = mDeviceList.begin(), end = mDeviceList.end();
402        for(; it != end; ++it)
403        {
404                if((*it)->inUse == false && (*it)->type == iType && (vendor == "" || (*it)->combinedKey == vendor))
405                {
406                        switch(iType)
407                        {
408                                case OISJoyStick:
409                {
410                                        int totalDevs = totalDevices(iType);
411                                        int freeDevs = freeDevices(iType);
412                                        int devID = totalDevs - freeDevs;
413                                       
414                                        obj = new MacJoyStick((*it)->combinedKey, bufferMode, *it, creator, devID);
415                                        (*it)->inUse = true;
416                                        return obj;
417                }
418                                case OISTablet:
419                                        //Create MacTablet
420                                        break;
421                                default:
422                                        break;
423                        }
424                }
425        }
426       
427        return obj;
428}
429
430//--------------------------------------------------------------------------------//
431void MacHIDManager::destroyObject(Object* obj)
432{
433        delete obj;
434}
Note: See TracBrowser for help on using the repository browser.