PageRenderTime 55ms CodeModel.GetById 33ms app.highlight 18ms RepoModel.GetById 1ms app.codeStats 0ms

/src/ois/src/mac/MacJoyStick.cpp

https://bitbucket.org/cabalistic/ogredeps/
C++ | 332 lines | 229 code | 49 blank | 54 comment | 59 complexity | 0e4aa2ff573576f47df4fa0be65ed565 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
 24#include "mac/MacJoyStick.h"
 25#include "mac/MacHIDManager.h"
 26#include "mac/MacInputManager.h"
 27#include "OISEvents.h"
 28#include "OISException.h"
 29
 30#include <cassert>
 31
 32using namespace OIS;
 33
 34//--------------------------------------------------------------------------------------------------//
 35MacJoyStick::MacJoyStick(const std::string &vendor, bool buffered, HidInfo* info, InputManager* creator, int devID) : 
 36JoyStick(vendor, buffered, devID, creator), mInfo(info)
 37{
 38	
 39}
 40
 41//--------------------------------------------------------------------------------------------------//
 42MacJoyStick::~MacJoyStick()
 43{
 44	//TODO: check if the queue has been started first?
 45	//(*mQueue)->stop(mQueue); 
 46	(*mQueue)->dispose(mQueue); 
 47	(*mQueue)->Release(mQueue); 
 48	
 49	
 50	//TODO: check if the interface has been opened first?
 51	(*mInfo->interface)->close(mInfo->interface);
 52	(*mInfo->interface)->Release(mInfo->interface); 
 53}
 54
 55//--------------------------------------------------------------------------------------------------//
 56void MacJoyStick::_initialize()
 57{
 58	assert(mInfo && "Given HidInfo invalid");
 59	assert(mInfo->interface && "Joystick interface invalid");
 60	
 61	//TODO: Is this necessary?
 62	//Clear old state
 63	mState.mAxes.clear();
 64	
 65	if ((*mInfo->interface)->open(mInfo->interface, 0) != KERN_SUCCESS)
 66		OIS_EXCEPT(E_General, "MacJoyStick::_initialize() >> Could not initialize joy device!");
 67	
 68	mState.clear();
 69	
 70	_enumerateCookies();
 71	
 72	mState.mButtons.resize(mInfo->numButtons);
 73	mState.mAxes.resize(mInfo->numAxes);
 74	
 75	mQueue = _createQueue();
 76}
 77
 78class FindAxisCookie : public std::unary_function<std::pair<IOHIDElementCookie, AxisInfo>&, bool>
 79{
 80public:
 81	FindAxisCookie(IOHIDElementCookie cookie) : m_Cookie(cookie) {}
 82	bool operator()(const std::pair<IOHIDElementCookie, AxisInfo>& pair) const
 83	{
 84		return pair.first == m_Cookie;
 85	}
 86private:
 87	IOHIDElementCookie m_Cookie;
 88};
 89
 90//--------------------------------------------------------------------------------------------------//
 91void MacJoyStick::capture()
 92{
 93	assert(mQueue && "Queue must be initialized before calling MacJoyStick::capture()");
 94	
 95	AbsoluteTime zeroTime = {0,0}; 
 96	
 97	IOHIDEventStruct event; 
 98	IOReturn result = (*mQueue)->getNextEvent(mQueue, &event, zeroTime, 0); 
 99	while(result == kIOReturnSuccess)
100	{
101		switch(event.type)
102		{
103            default:
104            case kIOHIDElementTypeInput_ScanCodes:
105            case kIOHIDElementTypeOutput:
106            case kIOHIDElementTypeFeature:
107            case kIOHIDElementTypeCollection:
108                break;
109
110			case kIOHIDElementTypeInput_Button:
111			{
112				std::vector<IOHIDElementCookie>::iterator buttonIt = std::find(mCookies.buttonCookies.begin(), mCookies.buttonCookies.end(), event.elementCookie);
113				int button = std::distance(mCookies.buttonCookies.begin(), buttonIt);
114				mState.mButtons[button] = (event.value == 1);
115				
116				if(mBuffered && mListener)
117				{
118					if(event.value == 0)
119						mListener->buttonPressed(JoyStickEvent(this, mState), button);
120					else if(event.value == 1)
121						mListener->buttonReleased(JoyStickEvent(this, mState), button);
122				}
123				break;
124			}
125			case kIOHIDElementTypeInput_Misc:
126				//TODO: It's an axis! - kind of - for gamepads - or should this be a pov?
127			case kIOHIDElementTypeInput_Axis:
128				std::map<IOHIDElementCookie, AxisInfo>::iterator axisIt = std::find_if(mCookies.axisCookies.begin(), mCookies.axisCookies.end(), FindAxisCookie(event.elementCookie));
129				int axis = std::distance(mCookies.axisCookies.begin(), axisIt);
130				
131				//Copied from LinuxJoyStickEvents.cpp, line 149
132				const AxisInfo& axisInfo = axisIt->second;
133				float proportion = (float) (event.value - axisInfo.max) / (float) (axisInfo.min - axisInfo.max);
134				mState.mAxes[axis].abs = -JoyStick::MIN_AXIS - (JoyStick::MAX_AXIS * 2 * proportion);
135				
136				if(mBuffered && mListener) mListener->axisMoved(JoyStickEvent(this, mState), axis);
137				break;
138		}
139		
140		result = (*mQueue)->getNextEvent(mQueue, &event, zeroTime, 0);
141	}
142}
143
144//--------------------------------------------------------------------------------------------------//
145void MacJoyStick::setBuffered(bool buffered)
146{
147	mBuffered = buffered;
148}
149
150//--------------------------------------------------------------------------------------------------//
151Interface* MacJoyStick::queryInterface(Interface::IType type)
152{
153	//Thought about using covariant return type here.. however,
154	//some devices may allow LED light changing, or other interface stuff
155	
156	//f( ff_device && type == Interface::ForceFeedback )
157	//return ff_device;
158	//else
159	return 0;
160}
161
162//--------------------------------------------------------------------------------------------------//
163void MacJoyStick::_enumerateCookies()
164{
165	assert(mInfo && "Given HidInfo invalid");
166	assert(mInfo->interface && "Joystick interface invalid");
167	
168	CFTypeRef                               object; 
169	long                                    number; 
170	IOHIDElementCookie                      cookie; 
171	long                                    usage; 
172	long                                    usagePage;
173	int										min;
174	int										max;
175
176	CFDictionaryRef                         element; 
177	
178	// Copy all elements, since we're grabbing most of the elements 
179	// for this device anyway, and thus, it's faster to iterate them 
180	// ourselves. When grabbing only one or two elements, a matching 
181	// dictionary should be passed in here instead of NULL. 
182	CFArrayRef elements; 
183	IOReturn success = reinterpret_cast<IOHIDDeviceInterface122*>(*mInfo->interface)->copyMatchingElements(mInfo->interface, NULL, &elements); 
184	
185	if (success == kIOReturnSuccess)
186	{ 
187		const CFIndex numOfElements = CFArrayGetCount(elements);
188		for (CFIndex i = 0; i < numOfElements; ++i) 
189		{ 
190			element = static_cast<CFDictionaryRef>(CFArrayGetValueAtIndex(elements, i));
191			
192			//Get cookie 
193			object = (CFDictionaryGetValue(element, 
194										   CFSTR(kIOHIDElementCookieKey))); 
195			if (object == 0 || CFGetTypeID(object) != CFNumberGetTypeID()) 
196				continue; 
197			if(!CFNumberGetValue((CFNumberRef) object, kCFNumberLongType, 
198								 &number)) 
199				continue; 
200			cookie = (IOHIDElementCookie) number; 
201			
202			//Get usage 
203			object = CFDictionaryGetValue(element, 
204										  CFSTR(kIOHIDElementUsageKey)); 
205			if (object == 0 || CFGetTypeID(object) != CFNumberGetTypeID()) 
206				continue; 
207			if (!CFNumberGetValue((CFNumberRef) object, kCFNumberLongType, 
208								  &number)) 
209				continue; 
210			usage = number; 
211			
212			//Get min
213			object = CFDictionaryGetValue(element,
214										  CFSTR(kIOHIDElementMinKey)); // kIOHIDElementMinKey or kIOHIDElementScaledMinKey?, no idea ...
215			if (object == 0 || CFGetTypeID(object) != CFNumberGetTypeID())
216				continue;
217			if (!CFNumberGetValue((CFNumberRef) object, kCFNumberIntType,
218								  &number))
219				continue;
220			min = number;
221			
222			//Get max
223			object = CFDictionaryGetValue(element,
224										  CFSTR(kIOHIDElementMaxKey)); // kIOHIDElementMaxKey or kIOHIDElementScaledMaxKey?, no idea ...
225			if (object == 0 || CFGetTypeID(object) != CFNumberGetTypeID())
226				continue;
227			if (!CFNumberGetValue((CFNumberRef) object, kCFNumberIntType,
228								  &number))
229				continue;
230			max = number;			
231			
232			//Get usage page 
233			object = CFDictionaryGetValue(element, 
234										  CFSTR(kIOHIDElementUsagePageKey)); 
235			
236			if (object == 0 || CFGetTypeID(object) != CFNumberGetTypeID()) 
237				continue; 
238			
239			if (!CFNumberGetValue((CFNumberRef) object, kCFNumberLongType, 
240								  &number)) 
241				continue; 
242			
243			usagePage = number;
244			switch(usagePage)
245			{
246				case kHIDPage_GenericDesktop:
247					switch(usage)
248				{
249					case kHIDUsage_GD_Pointer:
250						break;
251					case kHIDUsage_GD_X:
252					case kHIDUsage_GD_Y:
253					case kHIDUsage_GD_Z:
254					case kHIDUsage_GD_Rx:
255					case kHIDUsage_GD_Ry:
256					case kHIDUsage_GD_Rz:
257						mCookies.axisCookies.insert(std::make_pair(cookie, AxisInfo(min, max)));
258						break;
259					case kHIDUsage_GD_Slider:
260					case kHIDUsage_GD_Dial:
261					case kHIDUsage_GD_Wheel:
262						break;
263					case kHIDUsage_GD_Hatswitch:
264						break;
265				}
266					break;
267				case kHIDPage_Button:
268					mCookies.buttonCookies.push_back(cookie);
269					break;
270			}		
271		}
272		
273		mInfo->numButtons = mCookies.buttonCookies.size();
274		mInfo->numAxes = mCookies.axisCookies.size();
275
276	} 
277	else 
278	{ 
279		OIS_EXCEPT(E_General, "JoyStick elements could not be copied: copyMatchingElements failed with error: " + success); 
280	}
281	
282}
283
284//--------------------------------------------------------------------------------------------------//
285IOHIDQueueInterface** MacJoyStick::_createQueue(unsigned int depth)
286{	
287	assert(mInfo && "Given HidInfo invalid");
288	assert(mInfo->interface && "Joystick interface invalid");
289	
290	IOHIDQueueInterface** queue = (*mInfo->interface)->allocQueue(mInfo->interface); 
291	
292	if (queue) 
293	{		
294		//create the queue 
295		IOReturn result = (*queue)->create(queue, 0, depth); 
296		
297		if(result == kIOReturnSuccess)
298		{		
299			//add elements to the queue
300			std::map<IOHIDElementCookie, AxisInfo>::iterator axisIt = mCookies.axisCookies.begin();
301			for(; axisIt != mCookies.axisCookies.end(); ++axisIt)
302			{
303				(*queue)->addElement(queue, axisIt->first, 0);
304			}
305			
306			std::vector<IOHIDElementCookie>::iterator buttonIt = mCookies.buttonCookies.begin();
307			for(; buttonIt != mCookies.buttonCookies.end(); ++buttonIt)
308			{
309				(*queue)->addElement(queue, (*buttonIt), 0);
310			}
311
312			//start data delivery to queue 
313			result = (*queue)->start(queue); 
314			if(result == kIOReturnSuccess)
315			{
316				return queue;
317			}
318			else
319			{
320				OIS_EXCEPT(E_General, "Queue could not be started.");
321			}
322		}
323		else
324		{
325			OIS_EXCEPT(E_General, "Queue could not be created.");
326		}
327	}
328	else
329	{
330		OIS_EXCEPT(E_General, "Queue allocation failed.");
331	}
332}