From 85e0e3a1ec6e680dd34e644149072d5667b4e686 Mon Sep 17 00:00:00 2001 From: Steve Checkoway Date: Tue, 18 Oct 2005 09:00:53 +0000 Subject: [PATCH] Prepare code for adding a KeyboardDevice by putting common code into a Device abstract class. --- .../arch/InputHandler/InputHandler_Carbon.cpp | 406 ++++++++++-------- 1 file changed, 220 insertions(+), 186 deletions(-) diff --git a/stepmania/src/arch/InputHandler/InputHandler_Carbon.cpp b/stepmania/src/arch/InputHandler/InputHandler_Carbon.cpp index 9ed353248e..c211cdb8cd 100644 --- a/stepmania/src/arch/InputHandler/InputHandler_Carbon.cpp +++ b/stepmania/src/arch/InputHandler/InputHandler_Carbon.cpp @@ -19,8 +19,6 @@ using namespace std; using __gnu_cxx::hash_map; -static void AddElement( const void *value, void *context ); - // Simple helper, still need to release it static inline CFNumberRef CFInt( int n ) { @@ -64,154 +62,56 @@ Joystick::Joystick() : id( DEVICE_NONE ), { } -class JoystickDevice +class Device { private: - vector mSticks; IOHIDDeviceInterface **mInterface; IOHIDQueueInterface **mQueue; bool mRunning; CString mDescription; + + static void AddLogicalDevice( const void *value, void *context ); + static void AddElement( const void *value, void *context ); - static void AddJoystick( const void *value, void *context ); - +protected: + virtual bool AddLogicalDevice( int usagePage, int usage ) = 0; + virtual void AddElement( int usagePage, int usage, int cookie, const CFDictionaryRef dict ) = 0; + virtual void Open() = 0; + + inline void AddElementToQueue( int cookie ) + { CALL( mQueue, addElement, IOHIDElementCookie(cookie), 0 ); } public: - JoystickDevice(); - ~JoystickDevice(); - + Device(); + virtual ~Device(); + bool Open( io_object_t device ); - // returns the number of IDs assigned starting from startID - int AssignJoystickIDs( int startID ); - void StartQueue(CFRunLoopRef loopRef, int num, InputHandler_Carbon *handler); - inline int NumberOfSticks() const { return mSticks.size(); } - inline const Joystick& GetStick( int index ) const { return mSticks[index]; } + void StartQueue( CFRunLoopRef loopRef, IOHIDCallbackFunction callback, void *target, int refCon ); inline const CString& GetDescription() const { return mDescription; } }; -JoystickDevice::JoystickDevice() : mInterface(NULL), mQueue(NULL), mRunning(false) +Device::Device() : mInterface( NULL ), mQueue( NULL ), mRunning( false ) { } -bool JoystickDevice::Open( io_object_t device ) -{ - IOReturn ret; - CFMutableDictionaryRef properties; - kern_return_t result; - - result = IORegistryEntryCreateCFProperties( device, &properties, kCFAllocatorDefault, kNilOptions ); - if ( result != KERN_SUCCESS || !properties ) - { - LOG->Warn( "Couldn't get properties." ); - return false; - } - - // XXX Get Device Info - mDescription = "XXX Device Info"; - - CFArrayRef sticks; - - if ( !(sticks = (CFArrayRef)CFDictionaryGetValue(properties, CFSTR(kIOHIDElementKey))) ) - { - CFRelease( properties ); - return false; - } - size_t count = CFArrayGetCount( sticks ); - CFRange r = { 0, count }; - - mSticks.reserve( count ); - CFArrayApplyFunction( sticks, r, JoystickDevice::AddJoystick, this ); - - CFRelease( properties ); - - // Create the interface - IOCFPlugInInterface **plugInInterface; - HRESULT hresult; - SInt32 score; - - ret = IOCreatePlugInInterfaceForService( device, kIOHIDDeviceUserClientTypeID, - kIOCFPlugInInterfaceID, &plugInInterface, &score ); - if( ret != kIOReturnSuccess ) - { - PrintIOErr( ret, "Failed to create plugin interface." ); - return false; - } - - // Call a method of the plugin to create the device interface - CFUUIDBytes bytes = CFUUIDGetUUIDBytes( kIOHIDDeviceInterfaceID ); - - hresult = CALL( plugInInterface, QueryInterface, bytes, (void **)&mInterface ); - - CALL( plugInInterface, Release ); - - if( hresult != S_OK ) - { - LOG->Warn( "Couldn't get device interface from plugin interface." ); - mInterface = NULL; - return false; - } - - // open the interface - if( (ret = CALL(mInterface, open, 0)) != kIOReturnSuccess ) - { - PrintIOErr(ret, "Failed to open the interface."); - CALL(mInterface, Release); - mInterface = NULL; - return false; - } - - // alloc/create queue - mQueue = CALL( mInterface, allocQueue ); - if( !mQueue ) - { - LOG->Warn( "Couldn't allocate a queue." ); - return false; - } - - if( (ret = CALL(mQueue, create, 0, 32)) != kIOReturnSuccess ) - { - PrintIOErr(ret, "Failed to create the queue."); - CALL(mQueue, Release); - mQueue = NULL; - return false; - } - - // Add elements to the queue for each Joystick - FOREACH_CONST( Joystick, mSticks, i ) - { - const Joystick& js = *i; - - if( js.x_axis ) - CALL( mQueue, addElement, IOHIDElementCookie(js.x_axis), 0 ); - if( js.y_axis ) - CALL( mQueue, addElement, IOHIDElementCookie(js.y_axis), 0 ); - if( js.z_axis ) - CALL( mQueue, addElement, IOHIDElementCookie(js.z_axis), 0 ); - - for( hash_map::const_iterator j = js.mapping.begin(); j != js.mapping.end(); ++j ) - CALL( mQueue, addElement, IOHIDElementCookie(j->first), 0 ); - } - return true; -} - -JoystickDevice::~JoystickDevice() +Device::~Device() { if( mQueue ) { CFRunLoopSourceRef runLoopSource; - + if( mRunning ) CALL( mQueue, stop ); if( (runLoopSource = CALL(mQueue, getAsyncEventSource)) ) { CFRunLoopRef ref; - + ref = CFRunLoopRef( GetCFRunLoopFromEventLoop(GetMainEventLoop()) ); - + if( CFRunLoopContainsSource(ref, runLoopSource, kCFRunLoopDefaultMode) ) CFRunLoopRemoveSource( ref, runLoopSource, kCFRunLoopDefaultMode ); CFRelease( runLoopSource ); } - + CALL( mQueue, dispose ); CALL( mQueue, Release ); } @@ -222,50 +122,92 @@ JoystickDevice::~JoystickDevice() } } -void JoystickDevice::AddJoystick( const void *value, void *context ) +bool Device::Open( io_object_t device ) { - if( CFGetTypeID(CFTypeRef(value)) != CFDictionaryGetTypeID() ) - return; - - CFDictionaryRef dict = CFDictionaryRef( value ); - JoystickDevice *This = (JoystickDevice *)context; - CFArrayRef elements; - CFTypeRef object; - int usage, usagePage; - CFTypeID numID = CFNumberGetTypeID(); - - // Get usage page - object = CFDictionaryGetValue( dict, CFSTR(kIOHIDElementUsagePageKey) ); - if( !object || CFGetTypeID(object) != numID || !IntValue(object, &usagePage) ) - return; - - // Get usage - object = CFDictionaryGetValue( dict, CFSTR(kIOHIDElementUsageKey) ); - if( !object || CFGetTypeID(object) != numID || !IntValue(object, &usage) ) - return; - - if( usagePage != kHIDPage_GenericDesktop || usage != kHIDUsage_GD_Joystick ) - return; - - if( !(elements = (CFArrayRef)CFDictionaryGetValue(dict, CFSTR(kIOHIDElementKey))) ) - return; + IOReturn ret; + CFMutableDictionaryRef properties; + kern_return_t result; - Joystick js; - CFRange r = { 0, CFArrayGetCount(elements) }; - - CFArrayApplyFunction( elements, r, AddElement, &js ); - This->mSticks.push_back( js ); + result = IORegistryEntryCreateCFProperties( device, &properties, kCFAllocatorDefault, kNilOptions ); + if ( result != KERN_SUCCESS || !properties ) + { + LOG->Warn( "Couldn't get properties." ); + return false; + } + + // XXX Get Device Info + mDescription = "XXX Device Info"; + + CFArrayRef logicalDevices; + + if ( !(logicalDevices = (CFArrayRef)CFDictionaryGetValue(properties, CFSTR(kIOHIDElementKey))) ) + { + CFRelease( properties ); + return false; + } + CFRange r = { 0, CFArrayGetCount(logicalDevices) }; + + CFArrayApplyFunction( logicalDevices, r, Device::AddLogicalDevice, this ); + + CFRelease( properties ); + + // Create the interface + IOCFPlugInInterface **plugInInterface; + HRESULT hresult; + SInt32 score; + + ret = IOCreatePlugInInterfaceForService( device, kIOHIDDeviceUserClientTypeID, + kIOCFPlugInInterfaceID, &plugInInterface, &score ); + if( ret != kIOReturnSuccess ) + { + PrintIOErr( ret, "Failed to create plugin interface." ); + return false; + } + + // Call a method of the plugin to create the device interface + CFUUIDBytes bytes = CFUUIDGetUUIDBytes( kIOHIDDeviceInterfaceID ); + + hresult = CALL( plugInInterface, QueryInterface, bytes, (void **)&mInterface ); + + CALL( plugInInterface, Release ); + + if( hresult != S_OK ) + { + LOG->Warn( "Couldn't get device interface from plugin interface." ); + mInterface = NULL; + return false; + } + + // open the interface + if( (ret = CALL(mInterface, open, 0)) != kIOReturnSuccess ) + { + PrintIOErr(ret, "Failed to open the interface."); + CALL(mInterface, Release); + mInterface = NULL; + return false; + } + + // alloc/create queue + mQueue = CALL( mInterface, allocQueue ); + if( !mQueue ) + { + LOG->Warn( "Couldn't allocate a queue." ); + return false; + } + + if( (ret = CALL(mQueue, create, 0, 32)) != kIOReturnSuccess ) + { + PrintIOErr(ret, "Failed to create the queue."); + CALL(mQueue, Release); + mQueue = NULL; + return false; + } + + Open(); + return true; } - -int JoystickDevice::AssignJoystickIDs( int startID ) -{ - for( vector::iterator i = mSticks.begin(); i != mSticks.end(); ++i ) - i->id = InputDevice( startID++ ); - return mSticks.size(); -} - -void JoystickDevice::StartQueue( CFRunLoopRef loopRef, int num, InputHandler_Carbon *handler ) +void Device::StartQueue( CFRunLoopRef loopRef, IOHIDCallbackFunction callback, void *target, int refCon ) { CFRunLoopSourceRef runLoopSource; IOReturn ret = CALL( mQueue, createAsyncEventSource, &runLoopSource ); @@ -283,7 +225,7 @@ void JoystickDevice::StartQueue( CFRunLoopRef loopRef, int num, InputHandler_Car if( !CFRunLoopContainsSource(runLoop, runLoopSource, kCFRunLoopDefaultMode) ) CFRunLoopAddSource( runLoop, runLoopSource, kCFRunLoopDefaultMode ); - CALL( mQueue, setEventCallout, InputHandler_Carbon::QueueCallBack, handler, (void *)num ); + CALL( mQueue, setEventCallout, callback, target, (void *)refCon ); if( ret != kIOReturnSuccess ) { @@ -302,58 +244,124 @@ void JoystickDevice::StartQueue( CFRunLoopRef loopRef, int num, InputHandler_Car mRunning = true; } -// Callback -static void AddElement( const void *value, void *context ) +void Device::AddLogicalDevice( const void *value, void *context ) { if( CFGetTypeID(CFTypeRef(value)) != CFDictionaryGetTypeID() ) return; - + CFDictionaryRef dict = CFDictionaryRef( value ); - Joystick& js = *(Joystick *)context; - CFTypeRef object; - CFTypeID numID = CFNumberGetTypeID(); - int cookie, usage, usagePage; + Device *This = (Device *)context; CFArrayRef elements; - - // Recursively add elements - if( (elements = (CFArrayRef)CFDictionaryGetValue(dict, CFSTR(kIOHIDElementKey))) ) - { - CFRange r = { 0, CFArrayGetCount(elements) }; - - CFArrayApplyFunction( elements, r, AddElement, context ); - } - + CFTypeRef object; + int usage, usagePage; + CFTypeID numID = CFNumberGetTypeID(); + // Get usage page object = CFDictionaryGetValue( dict, CFSTR(kIOHIDElementUsagePageKey) ); if( !object || CFGetTypeID(object) != numID || !IntValue(object, &usagePage) ) return; - + // Get usage object = CFDictionaryGetValue( dict, CFSTR(kIOHIDElementUsageKey) ); if( !object || CFGetTypeID(object) != numID || !IntValue(object, &usage) ) return; + + if( !(elements = (CFArrayRef)CFDictionaryGetValue( dict, CFSTR(kIOHIDElementKey))) ) + return; + + if( !This->AddLogicalDevice(usagePage, usage) ) + return; + + CFRange r = { 0, CFArrayGetCount(elements) }; + + CFArrayApplyFunction( elements, r, Device::AddElement, This ); +} - +void Device::AddElement( const void *value, void *context ) +{ + if( CFGetTypeID(CFTypeRef(value)) != CFDictionaryGetTypeID() ) + return; + + CFDictionaryRef dict = CFDictionaryRef( value ); + Device *This = (Device *)context; + CFTypeRef object; + CFTypeID numID = CFNumberGetTypeID(); + int cookie, usage, usagePage; + CFArrayRef elements; + + // Recursively add elements + if( (elements = (CFArrayRef)CFDictionaryGetValue(dict, CFSTR(kIOHIDElementKey))) ) + { + CFRange r = { 0, CFArrayGetCount(elements) }; + + CFArrayApplyFunction( elements, r, AddElement, context ); + } + + // Get usage page + object = CFDictionaryGetValue( dict, CFSTR(kIOHIDElementUsagePageKey) ); + if( !object || CFGetTypeID(object) != numID || !IntValue(object, &usagePage) ) + return; + + // Get usage + object = CFDictionaryGetValue( dict, CFSTR(kIOHIDElementUsageKey) ); + if( !object || CFGetTypeID(object) != numID || !IntValue(object, &usage) ) + return; + + // Get cookie object = CFDictionaryGetValue( dict, CFSTR(kIOHIDElementCookieKey) ); if( !object || CFGetTypeID(object) != numID || !IntValue(object, &cookie) ) return; + This->AddElement( usagePage, usage, cookie, dict ); +} +class JoystickDevice : public Device +{ +private: + vector mSticks; + +protected: + bool AddLogicalDevice( int usagePage, int usage ); + void AddElement( int usagePage, int usage, int cookie, const CFDictionaryRef dict ); + void Open(); + +public: + // returns the number of IDs assigned starting from startID + int AssignJoystickIDs( int startID ); + inline int NumberOfSticks() const { return mSticks.size(); } + inline const Joystick& GetStick( int index ) const { return mSticks[index]; } +}; + +bool JoystickDevice::AddLogicalDevice( int usagePage, int usage ) +{ + if( usagePage != kHIDPage_GenericDesktop || usage != kHIDUsage_GD_Joystick ) + return false; + mSticks.push_back( Joystick() ); + return true; +} + +void JoystickDevice::AddElement( int usagePage, int usage, int cookie, const CFDictionaryRef dict ) +{ + CFTypeRef object; + CFTypeID numID = CFNumberGetTypeID(); + + Joystick& js = mSticks.back(); + switch( usagePage ) { case kHIDPage_GenericDesktop: { int min = 0; int max = 0; - + object = CFDictionaryGetValue( dict, CFSTR(kIOHIDElementMinKey) ); if( object && CFGetTypeID(object) == numID ) IntValue( object, &min ); - + object = CFDictionaryGetValue( dict, CFSTR(kIOHIDElementMaxKey) ); if( object && CFGetTypeID(object) == numID ) IntValue( object, &max ); - + switch( usage ) { case kHIDUsage_GD_X: @@ -393,7 +401,7 @@ static void AddElement( const void *value, void *context ) // button n has usage = n, subtract 1 to ensure // button 1 = JOY_BUTTON_1 const int buttonID = usage + JOY_BUTTON_1 - 1; - + if( buttonID < NUM_JOYSTICK_BUTTONS ) js.mapping[cookie] = buttonID; break; @@ -403,6 +411,32 @@ static void AddElement( const void *value, void *context ) } // end switch (usagePage) } +void JoystickDevice::Open() +{ + // Add elements to the queue for each Joystick + FOREACH_CONST( Joystick, mSticks, i ) + { + const Joystick& js = *i; + + if( js.x_axis ) + AddElementToQueue( js.x_axis ); + if( js.y_axis ) + AddElementToQueue( js.y_axis ); + if( js.z_axis ) + AddElementToQueue( js.z_axis ); + + for( hash_map::const_iterator j = js.mapping.begin(); j != js.mapping.end(); ++j ) + AddElementToQueue( j->first ); + } +} + +int JoystickDevice::AssignJoystickIDs( int startID ) +{ + for( vector::iterator i = mSticks.begin(); i != mSticks.end(); ++i ) + i->id = InputDevice( startID++ ); + return mSticks.size(); +} + void InputHandler_Carbon::QueueCallBack( void *target, int result, void *refcon, void *sender ) { // The result seems useless as you can't actually return anything... @@ -478,7 +512,7 @@ int InputHandler_Carbon::Run(void *data) CFRetain(loopRef); FOREACH( JoystickDevice *, This->mDevices, i ) - (*i)->StartQueue( loopRef, n++, This ); + (*i)->StartQueue( loopRef, InputHandler_Carbon::QueueCallBack, This, n++ ); This->mLoopRef = loopRef; /* The function copies the information out of the structure, so the memory pointed @@ -559,7 +593,7 @@ InputHandler_Carbon::InputHandler_Carbon() : mSem("Input thread started") { JoystickDevice *jd = new JoystickDevice; - if( jd->Open(device) ) + if( static_cast(jd)->Open(device) ) { id += jd->AssignJoystickIDs( id ); mDevices.push_back( jd );