Ticket #31974: patch-src_mac_CocoaJoystick.mm.diff

File patch-src_mac_CocoaJoystick.mm.diff, 10.6 KB (added by marin.saric@…, 12 years ago)
  • src/mac/CocoaJoyStick.mm

     
     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/CocoaJoyStick.h"
     25#include "mac/MacHIDManager.h"
     26#include "mac/CocoaInputManager.h"
     27#include "OISEvents.h"
     28#include "OISException.h"
     29
     30#include <cassert>
     31
     32using namespace OIS;
     33
     34//--------------------------------------------------------------------------------------------------//
     35CocoaJoyStick::CocoaJoyStick(const std::string &vendor, bool buffered, HidInfo* info, InputManager* creator, int devID) :
     36JoyStick(vendor, buffered, devID, creator), mInfo(info)
     37{
     38       
     39}
     40
     41//--------------------------------------------------------------------------------------------------//
     42CocoaJoyStick::~CocoaJoyStick()
     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 CocoaJoyStick::_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, "CocoaJoyStick::_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 CocoaJoyStick::capture()
     92{
     93        assert(mQueue && "Queue must be initialized before calling CocoaJoyStick::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 CocoaJoyStick::setBuffered(bool buffered)
     139{
     140        mBuffered = buffered;
     141}
     142
     143//--------------------------------------------------------------------------------------------------//
     144Interface* CocoaJoyStick::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 CocoaJoyStick::_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** CocoaJoyStick::_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}