Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/trunk/src/ois/mac/MacHIDManager.cpp @ 5681

Last change on this file since 5681 was 1505, checked in by rgrieder, 17 years ago

f* svn: It doesn't even inform you if you attempt to set a non existing property. It is svn:eol-style and not eol-style when using the command by the way…

  • Property svn:eol-style set to native
File size: 11.7 KB
RevLine 
[1505]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 "OISException.h"
25#include "OISObject.h"
26
27#include <iostream>
28using namespace std;
29
30using namespace OIS;
31
32//------------------------------------------------------------------------------------------------------//
33//------------------------------------------------------------------------------------------------------//
34template<typename T>
35T getDictionaryItemAsRef(CFDictionaryRef dict, const char* keyName)
36{
37        return CFDictionaryGetValue(dict, OIS_CFString(keyName));
38}
39
40template<>
41CFArrayRef getDictionaryItemAsRef(CFDictionaryRef dict, const char* keyName)
42{
43        CFTypeRef temp = CFDictionaryGetValue(dict, OIS_CFString(keyName));
44
45        if(temp && CFGetTypeID(temp) == CFArrayGetTypeID())
46                return (CFArrayRef)temp;
47        else
48                return 0;
49}
50
51template<>
52CFStringRef getDictionaryItemAsRef(CFDictionaryRef dict, const char* keyName)
53{
54        CFTypeRef temp = CFDictionaryGetValue(dict, OIS_CFString(keyName));
55
56        if(temp && CFGetTypeID(temp) == CFStringGetTypeID())
57                return (CFStringRef)temp;
58        else
59                return 0;
60}
61
62template<>
63CFNumberRef getDictionaryItemAsRef(CFDictionaryRef dict, const char* keyName)
64{
65        CFTypeRef temp = CFDictionaryGetValue(dict, OIS_CFString(keyName));
66
67        if(temp && CFGetTypeID(temp) == CFNumberGetTypeID())
68                return (CFNumberRef)temp;
69        else
70                return 0;
71}
72
73//------------------------------------------------------------------------------------------------------//
74//------------------------------------------------------------------------------------------------------//
75template<typename T>
76T getArrayItemAsRef(CFArrayRef array, CFIndex idx)
77{
78        return CFArrayGetValueAtIndex(array, idx);
79}
80
81template<>
82CFDictionaryRef getArrayItemAsRef(CFArrayRef array, CFIndex idx)
83{
84        CFTypeRef temp = CFArrayGetValueAtIndex(array, idx);
85
86        if(temp && CFGetTypeID(temp) == CFDictionaryGetTypeID())
87                return (CFDictionaryRef)temp;
88        else
89                return 0;
90}
91
92//------------------------------------------------------------------------------------------------------//
93int getInt32(CFNumberRef ref)
94{
95   int r = 0;
96   if (r) 
97      CFNumberGetValue(ref, kCFNumberIntType, &r);
98   return r;
99}
100
101//--------------------------------------------------------------------------------//
102MacHIDManager::MacHIDManager()
103{
104}
105
106//--------------------------------------------------------------------------------//
107MacHIDManager::~MacHIDManager()
108{
109}
110
111//------------------------------------------------------------------------------------------------------//
112void MacHIDManager::initialize()
113{
114        CFMutableDictionaryRef deviceLookupMap = IOServiceMatching(kIOHIDDeviceKey);
115        if(!deviceLookupMap)
116                OIS_EXCEPT(E_General, "Could not setup HID device search parameters");
117
118        //Make the search more specific by adding usage flags
119        int usage = kHIDUsage_GD_GamePad | kHIDUsage_GD_Joystick,
120            page  = kHIDPage_GenericDesktop;
121
122        CFNumberRef usageRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &usage),
123                                pageRef  = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &page);
124
125        CFDictionarySetValue(deviceLookupMap, CFSTR(kIOHIDPrimaryUsageKey), usageRef);
126        CFDictionarySetValue(deviceLookupMap, CFSTR(kIOHIDPrimaryUsagePageKey), pageRef);
127
128        //IOServiceGetMatchingServices consumes the map so we do not have to release it ourself
129        io_iterator_t iterator = 0;
130        IOReturn result = IOServiceGetMatchingServices(kIOMasterPortDefault, deviceLookupMap, &iterator);
131        if (result == kIOReturnSuccess && iterator)
132        {
133                io_object_t hidDevice = 0;
134                while ((hidDevice = IOIteratorNext(iterator)) !=0)
135                {
136                        //Get the current registry items property map
137                        CFMutableDictionaryRef propertyMap = 0;
138                        if (IORegistryEntryCreateCFProperties(hidDevice, &propertyMap, kCFAllocatorDefault, kNilOptions) == KERN_SUCCESS && propertyMap)
139                        {
140                                //Go through device to find all needed info
141                                HidInfo* hid = enumerateDeviceProperties(propertyMap);
142                                if(hid)
143                                        mDeviceList.push_back(hid);
144                                       
145                                //todo - we need to hold an open interface so we do not have to enumerate again later
146                                //should be able to watch for device removals also
147
148                                /// Testing opening / closing interface
149                                //IOCFPlugInInterface **pluginInterface = NULL;
150                                //SInt32 score = 0;
151                                //if (IOCreatePlugInInterfaceForService(hidDevice, kIOHIDDeviceUserClientTypeID, kIOCFPlugInInterfaceID, &pluginInterface, &score) == kIOReturnSuccess)
152                                //{
153                                //      IOHIDDeviceInterface **interface;
154                                //      HRESULT pluginResult = (*pluginInterface)->QueryInterface(pluginInterface, CFUUIDGetUUIDBytes(kIOHIDDeviceInterfaceID), (void **)&(interface));
155                                //      if(pluginResult == S_OK)
156                                //              cout << "Successfully created plugin interface for device\n";
157                                //      else
158                                //              cout << "Not able to create plugin interface\n";
159
160                                //      IODestroyPlugInInterface(pluginInterface);
161
162                                //      if ((*interface)->open(interface, 0) == KERN_SUCCESS)
163                                //              cout << "Opened interface.\n";
164                                //      else
165                                //              cout << "Failed to open\n";
166
167                                //      (*interface)->close(interface);
168                                //}
169                                //
170                        }
171                }
172
173                IOObjectRelease(iterator);
174        }
175
176        CFRelease(usageRef);
177        CFRelease(pageRef);
178}
179
180//------------------------------------------------------------------------------------------------------//
181HidInfo* MacHIDManager::enumerateDeviceProperties(CFMutableDictionaryRef propertyMap)
182{
183        HidInfo* info = new HidInfo();
184       
185        info->type = OISJoyStick;
186       
187        CFStringRef str = getDictionaryItemAsRef<CFStringRef>(propertyMap, kIOHIDManufacturerKey);
188        if (str)
189                info->vendor = CFStringGetCStringPtr(str, CFStringGetSystemEncoding());
190
191        str = getDictionaryItemAsRef<CFStringRef>(propertyMap, kIOHIDProductKey);
192        if (str)
193                info->productKey = CFStringGetCStringPtr(str, CFStringGetSystemEncoding());
194               
195        info->combinedKey = info->vendor + " " + info->productKey;
196
197        //Go through all items in this device (i.e. buttons, hats, sticks, axes, etc)
198        CFArrayRef array = getDictionaryItemAsRef<CFArrayRef>(propertyMap, kIOHIDElementKey);
199        if (array)
200                for (int i = 0; i < CFArrayGetCount(array); i++)
201                        parseDeviceProperties(getArrayItemAsRef<CFDictionaryRef>(array, i));
202
203        return info;
204}
205
206//------------------------------------------------------------------------------------------------------//
207void MacHIDManager::parseDeviceProperties(CFDictionaryRef properties)
208{
209        if(!properties)
210                return;
211
212        CFArrayRef array = getDictionaryItemAsRef<CFArrayRef>(properties, kIOHIDElementKey);
213        if (array)
214        {
215                for (int i = 0; i < CFArrayGetCount(array); i++)
216                {
217                        CFDictionaryRef element = getArrayItemAsRef<CFDictionaryRef>(array, i);
218                        if (element)
219                        {
220                                if(getInt32(getDictionaryItemAsRef<CFNumberRef>(element, kIOHIDElementTypeKey)) == kIOHIDElementTypeCollection) 
221                                {       //Check if we need to recurse further intoi another collection
222                                        if(getInt32(getDictionaryItemAsRef<CFNumberRef>(element, kIOHIDElementUsagePageKey)) == kHIDPage_GenericDesktop)
223                                                parseDeviceProperties(element);
224                                }
225                                else
226                                {
227                                        switch(getInt32(getDictionaryItemAsRef<CFNumberRef>(element, kIOHIDElementUsagePageKey)))
228                                        {
229                                        case kHIDPage_GenericDesktop:
230                                                switch(getInt32(getDictionaryItemAsRef<CFNumberRef>(element, kIOHIDElementUsageKey)))
231                                                {
232                                                case kHIDUsage_GD_Pointer:
233                                                        cout << "\tkHIDUsage_GD_Pointer\n";
234                                                        parseDevicePropertiesGroup(element);
235                                                        break;
236                                                case kHIDUsage_GD_X:
237                                                case kHIDUsage_GD_Y:
238                                                case kHIDUsage_GD_Z:
239                                                case kHIDUsage_GD_Rx:
240                                                case kHIDUsage_GD_Ry:
241                                                case kHIDUsage_GD_Rz:
242                                                        cout << "\tAxis\n";
243                                                        break;
244                                                case kHIDUsage_GD_Slider:
245                                                case kHIDUsage_GD_Dial:
246                                                case kHIDUsage_GD_Wheel:
247                                                        cout << "\tUnsupported kHIDUsage_GD_Wheel\n";
248                                                        break;
249                                                case kHIDUsage_GD_Hatswitch:
250                                                        cout << "\tUnsupported - kHIDUsage_GD_Hatswitch\n";
251                                                        break;
252                                                }
253                                                break;
254                                        case kHIDPage_Button:
255                                                cout << "\tkHIDPage_Button\n";
256                                                break;
257                                        }
258                                }
259                        }
260                }
261        }
262}
263
264//------------------------------------------------------------------------------------------------------//
265void MacHIDManager::parseDevicePropertiesGroup(CFDictionaryRef properties)
266{
267        if(!properties)
268                return;
269
270        CFArrayRef array = getDictionaryItemAsRef<CFArrayRef>(properties, kIOHIDElementKey);
271        if(array)
272        {
273                for (int i = 0; i < CFArrayGetCount(array); i++)
274                {
275                        CFDictionaryRef element = getArrayItemAsRef<CFDictionaryRef>(array, i);
276                        if (element)
277                        {
278                                switch(getInt32(getDictionaryItemAsRef<CFNumberRef>(element, kIOHIDElementUsagePageKey)))
279                                {
280                                case kHIDPage_GenericDesktop:
281                                        switch(getInt32(getDictionaryItemAsRef<CFNumberRef>(element, kIOHIDElementUsageKey)))
282                                        {
283                                        case kHIDUsage_GD_X:
284                                        case kHIDUsage_GD_Y:
285                                        case kHIDUsage_GD_Z:
286                                        case kHIDUsage_GD_Rx:
287                                        case kHIDUsage_GD_Ry:
288                                        case kHIDUsage_GD_Rz:
289                                                cout << "\t\tAxis\n";
290                                                break;
291                                        case kHIDUsage_GD_Slider:
292                                        case kHIDUsage_GD_Dial:
293                                        case kHIDUsage_GD_Wheel:
294                                                cout << "\tUnsupported - kHIDUsage_GD_Wheel\n";
295                                                break;
296                                        case kHIDUsage_GD_Hatswitch:
297                                                cout << "\tUnsupported - kHIDUsage_GD_Hatswitch\n";
298                                                break;
299                                        }
300                                        break;
301                                case kHIDPage_Button:
302                                        break;
303                                }
304                        }
305                }
306        }
307}
308
309//--------------------------------------------------------------------------------//
310DeviceList MacHIDManager::freeDeviceList()
311{
312        DeviceList ret;
313        HidInfoList::iterator it = mDeviceList.begin(), end = mDeviceList.end();
314        for(; it != end; ++it)
315        {
316                if((*it)->inUse == false)
317                        ret.insert(std::make_pair((*it)->type, (*it)->combinedKey));
318        }
319
320        return ret;
321}
322
323//--------------------------------------------------------------------------------//
324int MacHIDManager::totalDevices(Type iType)
325{
326        int ret = 0;
327        HidInfoList::iterator it = mDeviceList.begin(), end = mDeviceList.end();
328
329        for(; it != end; ++it)
330        {
331                if((*it)->type == iType)
332                        ret++;
333        }
334       
335        return ret;
336}
337
338//--------------------------------------------------------------------------------//
339int MacHIDManager::freeDevices(Type iType)
340{
341        int ret = 0;
342        HidInfoList::iterator it = mDeviceList.begin(), end = mDeviceList.end();
343
344        for(; it != end; ++it)
345        {
346                if((*it)->inUse == false && (*it)->type == iType)
347                        ret++;
348        }
349
350        return ret;
351}
352
353//--------------------------------------------------------------------------------//
354bool MacHIDManager::vendorExist(Type iType, const std::string & vendor)
355{
356        HidInfoList::iterator it = mDeviceList.begin(), end = mDeviceList.end();
357
358        for(; it != end; ++it)
359        {
360                if((*it)->type == iType && (*it)->combinedKey == vendor)
361                        return true;
362        }
363       
364        return false;
365}
366
367//--------------------------------------------------------------------------------//
368Object* MacHIDManager::createObject(InputManager* creator, Type iType, bool bufferMode, 
369                                                                          const std::string & vendor)
370{
371        Object *obj = 0;
372
373        HidInfoList::iterator it = mDeviceList.begin(), end = mDeviceList.end();
374        for(; it != end; ++it)
375        {
376                if((*it)->inUse == false && (*it)->type == iType && (vendor == "" || (*it)->combinedKey == vendor))
377                {
378                        //create device
379                }
380        }
381
382        if( obj == 0 )
383                OIS_EXCEPT(E_InputDeviceNonExistant, "No devices match requested type.");
384
385        return obj;
386}
387
388//--------------------------------------------------------------------------------//
389void MacHIDManager::destroyObject(Object* obj)
390{
391        delete obj;
392}
Note: See TracBrowser for help on using the repository browser.