PageRenderTime 30ms CodeModel.GetById 1ms app.highlight 25ms RepoModel.GetById 1ms app.codeStats 0ms

/src/ois/src/mac/MacHIDManager.cpp

https://bitbucket.org/cabalistic/ogredeps/
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}