Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/mac_osx/src/external/ois/mac/MacJoyStick.cpp @ 7944

Last change on this file since 7944 was 7506, checked in by rgrieder, 14 years ago

Updated OIS source files to its current SVN trunk (r26).

  • Property svn:eol-style set to native
File size: 10.2 KB
Line 
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                        case kIOHIDElementTypeInput_Button:
104                        {
105                                std::vector<IOHIDElementCookie>::iterator buttonIt = std::find(mCookies.buttonCookies.begin(), mCookies.buttonCookies.end(), event.elementCookie);
106                                int button = std::distance(mCookies.buttonCookies.begin(), buttonIt);
107                                mState.mButtons[button] = (event.value == 1);
108                               
109                                if(mBuffered && mListener)
110                                {
111                                        if(event.value == 0)
112                                                mListener->buttonPressed(JoyStickEvent(this, mState), button);
113                                        else if(event.value == 1)
114                                                mListener->buttonReleased(JoyStickEvent(this, mState), button);
115                                }
116                                break;
117                        }
118                        case kIOHIDElementTypeInput_Misc:
119                                //TODO: It's an axis! - kind of - for gamepads - or should this be a pov?
120                        case kIOHIDElementTypeInput_Axis:
121                                std::map<IOHIDElementCookie, AxisInfo>::iterator axisIt = std::find_if(mCookies.axisCookies.begin(), mCookies.axisCookies.end(), FindAxisCookie(event.elementCookie));
122                                int axis = std::distance(mCookies.axisCookies.begin(), axisIt);
123                               
124                                //Copied from LinuxJoyStickEvents.cpp, line 149
125                                const AxisInfo& axisInfo = axisIt->second;
126                                float proportion = (float) (event.value - axisInfo.max) / (float) (axisInfo.min - axisInfo.max);
127                                mState.mAxes[axis].abs = -JoyStick::MIN_AXIS - (JoyStick::MAX_AXIS * 2 * proportion);
128                               
129                                if(mBuffered && mListener) mListener->axisMoved(JoyStickEvent(this, mState), axis);
130                                break;
131                }
132               
133                result = (*mQueue)->getNextEvent(mQueue, &event, zeroTime, 0);
134        }
135}
136
137//--------------------------------------------------------------------------------------------------//
138void MacJoyStick::setBuffered(bool buffered)
139{
140        mBuffered = buffered;
141}
142
143//--------------------------------------------------------------------------------------------------//
144Interface* MacJoyStick::queryInterface(Interface::IType type)
145{
146        //Thought about using covariant return type here.. however,
147        //some devices may allow LED light changing, or other interface stuff
148       
149        //f( ff_device && type == Interface::ForceFeedback )
150        //return ff_device;
151        //else
152        return 0;
153}
154
155//--------------------------------------------------------------------------------------------------//
156void MacJoyStick::_enumerateCookies()
157{
158        assert(mInfo && "Given HidInfo invalid");
159        assert(mInfo->interface && "Joystick interface invalid");
160       
161        CFTypeRef                               object; 
162        long                                    number; 
163        IOHIDElementCookie                      cookie; 
164        long                                    usage; 
165        long                                    usagePage;
166        int                                                                             min;
167        int                                                                             max;
168
169        CFDictionaryRef                         element; 
170       
171        // Copy all elements, since we're grabbing most of the elements
172        // for this device anyway, and thus, it's faster to iterate them
173        // ourselves. When grabbing only one or two elements, a matching
174        // dictionary should be passed in here instead of NULL.
175        CFArrayRef elements; 
176        IOReturn success = reinterpret_cast<IOHIDDeviceInterface122*>(*mInfo->interface)->copyMatchingElements(mInfo->interface, NULL, &elements); 
177       
178        if (success == kIOReturnSuccess)
179        { 
180                const CFIndex numOfElements = CFArrayGetCount(elements);
181                for (CFIndex i = 0; i < numOfElements; ++i) 
182                { 
183                        element = static_cast<CFDictionaryRef>(CFArrayGetValueAtIndex(elements, i));
184                       
185                        //Get cookie
186                        object = (CFDictionaryGetValue(element, 
187                                                                                   CFSTR(kIOHIDElementCookieKey))); 
188                        if (object == 0 || CFGetTypeID(object) != CFNumberGetTypeID()) 
189                                continue; 
190                        if(!CFNumberGetValue((CFNumberRef) object, kCFNumberLongType, 
191                                                                 &number)) 
192                                continue; 
193                        cookie = (IOHIDElementCookie) number; 
194                       
195                        //Get usage
196                        object = CFDictionaryGetValue(element, 
197                                                                                  CFSTR(kIOHIDElementUsageKey)); 
198                        if (object == 0 || CFGetTypeID(object) != CFNumberGetTypeID()) 
199                                continue; 
200                        if (!CFNumberGetValue((CFNumberRef) object, kCFNumberLongType, 
201                                                                  &number)) 
202                                continue; 
203                        usage = number; 
204                       
205                        //Get min
206                        object = CFDictionaryGetValue(element,
207                                                                                  CFSTR(kIOHIDElementMinKey)); // kIOHIDElementMinKey or kIOHIDElementScaledMinKey?, no idea ...
208                        if (object == 0 || CFGetTypeID(object) != CFNumberGetTypeID())
209                                continue;
210                        if (!CFNumberGetValue((CFNumberRef) object, kCFNumberIntType,
211                                                                  &number))
212                                continue;
213                        min = number;
214                       
215                        //Get max
216                        object = CFDictionaryGetValue(element,
217                                                                                  CFSTR(kIOHIDElementMaxKey)); // kIOHIDElementMaxKey or kIOHIDElementScaledMaxKey?, no idea ...
218                        if (object == 0 || CFGetTypeID(object) != CFNumberGetTypeID())
219                                continue;
220                        if (!CFNumberGetValue((CFNumberRef) object, kCFNumberIntType,
221                                                                  &number))
222                                continue;
223                        max = number;                   
224                       
225                        //Get usage page
226                        object = CFDictionaryGetValue(element, 
227                                                                                  CFSTR(kIOHIDElementUsagePageKey)); 
228                       
229                        if (object == 0 || CFGetTypeID(object) != CFNumberGetTypeID()) 
230                                continue; 
231                       
232                        if (!CFNumberGetValue((CFNumberRef) object, kCFNumberLongType, 
233                                                                  &number)) 
234                                continue; 
235                       
236                        usagePage = number;
237                        switch(usagePage)
238                        {
239                                case kHIDPage_GenericDesktop:
240                                        switch(usage)
241                                {
242                                        case kHIDUsage_GD_Pointer:
243                                                break;
244                                        case kHIDUsage_GD_X:
245                                        case kHIDUsage_GD_Y:
246                                        case kHIDUsage_GD_Z:
247                                        case kHIDUsage_GD_Rx:
248                                        case kHIDUsage_GD_Ry:
249                                        case kHIDUsage_GD_Rz:
250                                                mCookies.axisCookies.insert(std::make_pair(cookie, AxisInfo(min, max)));
251                                                break;
252                                        case kHIDUsage_GD_Slider:
253                                        case kHIDUsage_GD_Dial:
254                                        case kHIDUsage_GD_Wheel:
255                                                break;
256                                        case kHIDUsage_GD_Hatswitch:
257                                                break;
258                                }
259                                        break;
260                                case kHIDPage_Button:
261                                        mCookies.buttonCookies.push_back(cookie);
262                                        break;
263                        }               
264                }
265               
266                mInfo->numButtons = mCookies.buttonCookies.size();
267                mInfo->numAxes = mCookies.axisCookies.size();
268
269        } 
270        else 
271        { 
272                OIS_EXCEPT(E_General, "JoyStick elements could not be copied: copyMatchingElements failed with error: " + success); 
273        }
274       
275}
276
277//--------------------------------------------------------------------------------------------------//
278IOHIDQueueInterface** MacJoyStick::_createQueue(unsigned int depth)
279{       
280        assert(mInfo && "Given HidInfo invalid");
281        assert(mInfo->interface && "Joystick interface invalid");
282       
283        IOHIDQueueInterface** queue = (*mInfo->interface)->allocQueue(mInfo->interface); 
284       
285        if (queue) 
286        {               
287                //create the queue
288                IOReturn result = (*queue)->create(queue, 0, depth); 
289               
290                if(result == kIOReturnSuccess)
291                {               
292                        //add elements to the queue
293                        std::map<IOHIDElementCookie, AxisInfo>::iterator axisIt = mCookies.axisCookies.begin();
294                        for(; axisIt != mCookies.axisCookies.end(); ++axisIt)
295                        {
296                                result = (*queue)->addElement(queue, axisIt->first, 0);
297                        }
298                       
299                        std::vector<IOHIDElementCookie>::iterator buttonIt = mCookies.buttonCookies.begin();
300                        for(; buttonIt != mCookies.buttonCookies.end(); ++buttonIt)
301                        {
302                                result = (*queue)->addElement(queue, (*buttonIt), 0);
303                        }
304
305                        //start data delivery to queue
306                        result = (*queue)->start(queue); 
307                        if(result == kIOReturnSuccess)
308                        {
309                                return queue;
310                        }
311                        else
312                        {
313                                OIS_EXCEPT(E_General, "Queue could not be started.");
314                        }
315                }
316                else
317                {
318                        OIS_EXCEPT(E_General, "Queue could not be created.");
319                }
320        }
321        else
322        {
323                OIS_EXCEPT(E_General, "Queue allocation failed.");
324        }
325}
Note: See TracBrowser for help on using the repository browser.