diff --git a/src/CsvFile.cpp b/src/CsvFile.cpp index 68fc44b100..e7d3a5d331 100644 --- a/src/CsvFile.cpp +++ b/src/CsvFile.cpp @@ -114,12 +114,11 @@ bool CsvFile::WriteFile( const RString &sPath ) const bool CsvFile::WriteFile( RageFileBasic &f ) const { - FOREACH_CONST( StringVector, m_vvs, line ) + for (StringVector &line : m_vvs) { RString sLine; - FOREACH_CONST( RString, *line, value ) + for (RString sVal : line) // explicitly don't use a reference. { - RString sVal = *value; sVal.Replace( "\"", "\"\"" ); // escape quotes to double-quotes sLine += "\"" + sVal + "\""; if( value != line->end()-1 ) diff --git a/src/arch/InputHandler/InputHandler_MacOSX_HID.cpp b/src/arch/InputHandler/InputHandler_MacOSX_HID.cpp index ee7072e93e..fdf9735f0d 100644 --- a/src/arch/InputHandler/InputHandler_MacOSX_HID.cpp +++ b/src/arch/InputHandler/InputHandler_MacOSX_HID.cpp @@ -1,499 +1,499 @@ -#include "global.h" -#include "RageLog.h" -#include "InputHandler_MacOSX_HID.h" -#include "Foreach.h" -#include "PrefsManager.h" -#include "InputFilter.h" -#include "archutils/Darwin/DarwinThreadHelpers.h" -#include "archutils/Darwin/KeyboardDevice.h" -#include "archutils/Darwin/MouseDevice.h" -#include "archutils/Darwin/JoystickDevice.h" -#include "archutils/Darwin/PumpDevice.h" - -#include -#include - -REGISTER_INPUT_HANDLER_CLASS2( HID, MacOSX_HID ); - -void InputHandler_MacOSX_HID::QueueCallback( void *target, int result, void *refcon, void *sender ) -{ - // The result seems useless as you can't actually return anything... - // refcon is the Device number - - RageTimer now; - InputHandler_MacOSX_HID *This = (InputHandler_MacOSX_HID *)target; - IOHIDQueueInterface **queue = (IOHIDQueueInterface **)sender; - IOHIDEventStruct event; - AbsoluteTime zeroTime = { 0, 0 }; - HIDDevice *dev = This->m_vDevices[int( refcon )]; - vector vPresses; - - while( (result = CALL(queue, getNextEvent, &event, zeroTime, 0)) == kIOReturnSuccess ) - { - if( event.longValueSize != 0 && event.longValue != NULL ) - { - free( event.longValue ); - continue; - } - //LOG->Trace( "Got event with cookie %p, value %d", event.elementCookie, int(event.value) ); - dev->GetButtonPresses( vPresses, event.elementCookie, event.value, now ); - } - FOREACH_CONST( DeviceInput, vPresses, i ) - INPUTFILTER->ButtonPressed( *i ); -} - -static void RunLoopStarted( CFRunLoopObserverRef o, CFRunLoopActivity a, void *sem ) -{ - CFRunLoopObserverInvalidate( o ); - CFRelease( o ); // we don't need this any longer - ((RageSemaphore *)sem)->Post(); -} - -int InputHandler_MacOSX_HID::Run( void *data ) -{ - InputHandler_MacOSX_HID *This = (InputHandler_MacOSX_HID *)data; - - This->m_LoopRef = CFRunLoopGetCurrent(); - CFRetain( This->m_LoopRef ); - - This->StartDevices(); - { - const RString sError = SetThreadPrecedence( 1.0f ); - if( !sError.empty() ) - LOG->Warn( "Could not set precedence of the input thread: %s", sError.c_str() ); - } - // Add an observer for the start of the run loop - { - /* The function copies the information out of the structure, so the memory - * pointed to by context does not need to persist beyond the function call. */ - CFRunLoopObserverContext context = { 0, &This->m_Sem, NULL, NULL, NULL }; - CFRunLoopObserverRef o = CFRunLoopObserverCreate( kCFAllocatorDefault, kCFRunLoopEntry, - false, 0, RunLoopStarted, &context); - CFRunLoopAddObserver( This->m_LoopRef, o, kCFRunLoopDefaultMode ); - } - - /* Add a source for ending the run loop. This serves two purposes: - * 1. it provides a way to terminate the run loop when IH_MacOSX_HID exists, - * and 2. it ensures that CFRunLoopRun() doesn't return immediately if - * there are no other sources. */ - { - /* Being a little tricky here, the perform callback takes a void* and - * returns nothing. CFRunLoopStop takes a CFRunLoopRef (a pointer) so - * cast the function and pass the loop ref. */ - void *info = This->m_LoopRef; - void (*perform)(void *) = (void (*)(void *))CFRunLoopStop; - // { version, info, retain, release, copyDescription, equal, hash, schedule, cancel, perform } - CFRunLoopSourceContext context = { 0, info, NULL, NULL, NULL, NULL, NULL, NULL, NULL, perform }; - - // Pass 1 so that it is called after all inputs have been handled (they will have order = 0) - This->m_SourceRef = CFRunLoopSourceCreate( kCFAllocatorDefault, 1, &context ); - - CFRunLoopAddSource( This->m_LoopRef, This->m_SourceRef, kCFRunLoopDefaultMode ); - } - CFRunLoopRun(); - LOG->Trace( "Shutting down input handler thread..." ); - return 0; -} - -void InputHandler_MacOSX_HID::DeviceAdded( void *refCon, io_iterator_t ) -{ - InputHandler_MacOSX_HID *This = (InputHandler_MacOSX_HID *)refCon; - - LockMut( This->m_ChangeLock ); - This->m_bChanged = true; -} - -void InputHandler_MacOSX_HID::DeviceChanged( void *refCon, io_service_t service, natural_t messageType, void *arg ) -{ - if( messageType == kIOMessageServiceIsTerminated ) - { - InputHandler_MacOSX_HID *This = (InputHandler_MacOSX_HID *)refCon; - - LockMut( This->m_ChangeLock ); - This->m_bChanged = true; - } -} - -// m_LoopRef needs to be set before this is called -void InputHandler_MacOSX_HID::StartDevices() -{ - int n = 0; - - ASSERT( m_LoopRef ); - FOREACH( HIDDevice *, m_vDevices, i ) - (*i)->StartQueue( m_LoopRef, InputHandler_MacOSX_HID::QueueCallback, this, n++ ); - - CFRunLoopSourceRef runLoopSource = IONotificationPortGetRunLoopSource( m_NotifyPort ); - - CFRunLoopAddSource( m_LoopRef, runLoopSource, kCFRunLoopDefaultMode ); -} - -InputHandler_MacOSX_HID::~InputHandler_MacOSX_HID() -{ - FOREACH( HIDDevice *, m_vDevices, i ) - delete *i; - if( PREFSMAN->m_bThreadedInput ) - { - CFRunLoopSourceSignal( m_SourceRef ); - CFRunLoopWakeUp( m_LoopRef ); - m_InputThread.Wait(); - CFRelease( m_SourceRef ); - CFRelease( m_LoopRef ); - LOG->Trace( "Input handler thread shut down." ); - } - - FOREACH( io_iterator_t, m_vIters, i ) - IOObjectRelease( *i ); - IONotificationPortDestroy( m_NotifyPort ); -} - -static CFDictionaryRef GetMatchingDictionary( int usagePage, int usage ) -{ - // Build the matching dictionary. - CFMutableDictionaryRef dict; - - if( (dict = IOServiceMatching(kIOHIDDeviceKey)) == NULL ) - FAIL_M( "Couldn't create a matching dictionary." ); - // Refine the search by only looking for joysticks - CFNumberRef usagePageRef = CFInt( usagePage ); - CFNumberRef usageRef = CFInt( usage ); - - CFDictionarySetValue( dict, CFSTR(kIOHIDPrimaryUsagePageKey), usagePageRef ); - CFDictionarySetValue( dict, CFSTR(kIOHIDPrimaryUsageKey), usageRef ); - - // Cleanup after ourselves - CFRelease( usagePageRef ); - CFRelease( usageRef ); - - return dict; -} - -// Factor this out because nothing else in IH_C::AddDevices() needs to know the type of the device. -static HIDDevice *MakeDevice( InputDevice id ) -{ - if( id == DEVICE_KEYBOARD ) - return new KeyboardDevice; - /* - if( id == DEVICE_MOUSE ) - return new MouseDevice; - */ - if( IsJoystick(id) ) - return new JoystickDevice; - if( IsPump(id) ) - return new PumpDevice; - return NULL; -} - -void InputHandler_MacOSX_HID::AddDevices( int usagePage, int usage, InputDevice &id ) -{ - io_iterator_t iter; - CFDictionaryRef dict = GetMatchingDictionary( usagePage, usage ); - kern_return_t ret = IOServiceAddMatchingNotification( m_NotifyPort, kIOFirstMatchNotification, dict, - InputHandler_MacOSX_HID::DeviceAdded, this, &iter ); - io_object_t device; - - if( ret != KERN_SUCCESS ) - return; - - m_vIters.push_back( iter ); - - // Iterate over the devices and add them - while( (device = IOIteratorNext(iter)) ) - { - LOG->Trace( "\tFound device %d", id ); - HIDDevice *dev = MakeDevice( id ); - int num; - - if( !dev ) - { - LOG->Trace( "\t\tInvalid id, deleting device" ); - IOObjectRelease( device ); - continue; - } - - if( !dev->Open(device) || (num = dev->AssignIDs(id)) == -1 ) - { - LOG->Trace( "\tFailed top open or assign id, deleting device" ); - delete dev; - IOObjectRelease( device ); - continue; - } - io_iterator_t i; - - enum_add( id, num ); - m_vDevices.push_back( dev ); - - ret = IOServiceAddInterestNotification( - m_NotifyPort, device, kIOGeneralInterest, - InputHandler_MacOSX_HID::DeviceChanged, - this, &i - ); - - if( ret == KERN_SUCCESS ) - m_vIters.push_back( i ); - else - LOG->Trace( "\t\tFailed to add device changed notification, deleting device" ); - IOObjectRelease( device ); - } -} - -InputHandler_MacOSX_HID::InputHandler_MacOSX_HID() : m_Sem( "Input thread started" ), m_ChangeLock( "Input handler change lock" ) -{ - InputDevice id = DEVICE_KEYBOARD; - - // Set up the notify ports. - m_NotifyPort = IONotificationPortCreate( kIOMasterPortDefault ); - - // Add devices. - LOG->Trace( "Finding keyboards" ); - AddDevices( kHIDPage_GenericDesktop, kHIDUsage_GD_Keyboard, id ); - - LOG->Trace( "Finding mice" ); - AddDevices( kHIDPage_GenericDesktop, kHIDUsage_GD_Mouse, id ); - - LOG->Trace( "Finding joysticks" ); - id = DEVICE_JOY1; - AddDevices( kHIDPage_GenericDesktop, kHIDUsage_GD_Joystick, id ); - AddDevices( kHIDPage_GenericDesktop, kHIDUsage_GD_GamePad, id ); - LOG->Trace( "Finding pump" ); - id = DEVICE_PUMP1; - AddDevices( kHIDPage_VendorDefinedStart, 0x0001, id ); // Pump pads use the first vendor specific usage page. - m_bChanged = false; - - if( PREFSMAN->m_bThreadedInput ) - { - m_InputThread.SetName( "Input thread" ); - m_InputThread.Create( InputHandler_MacOSX_HID::Run, this ); - // Wait for the run loop to start before returning. - m_Sem.Wait(); - } - else - { - m_LoopRef = CFRunLoopRef( GetCFRunLoopFromEventLoop(GetMainEventLoop()) ); - CFRetain( m_LoopRef ); - StartDevices(); - } -} - -void InputHandler_MacOSX_HID::GetDevicesAndDescriptions( vector& vDevices ) -{ - FOREACH_CONST( HIDDevice *, m_vDevices, i ) - (*i)->GetDevicesAndDescriptions( vDevices ); -} - -RString InputHandler_MacOSX_HID::GetDeviceSpecificInputString( const DeviceInput &di ) -{ - if( di.device == DEVICE_KEYBOARD ) - { -#define OTHER(n) (KEY_OTHER_0 + (n)) - switch( di.button ) - { - case KEY_DEL: return "del"; - case KEY_BACK: return "delete"; - case KEY_ENTER: return "return"; - case KEY_LALT: return "left option"; - case KEY_RALT: return "right option"; - case KEY_LMETA: return "left cmd"; - case KEY_RMETA: return "right cmd"; - case KEY_INSERT: return "help"; - case OTHER(0): return "F17"; - case OTHER(1): return "F18"; - case OTHER(2): return "F19"; - case OTHER(3): return "F20"; - case OTHER(4): return "F21"; - case OTHER(5): return "F22"; - case OTHER(6): return "F23"; - case OTHER(7): return "F25"; - case OTHER(8): return "execute"; - case OTHER(9): return "select"; - case OTHER(10): return "stop"; - case OTHER(11): return "again"; - case OTHER(12): return "undo"; - case OTHER(13): return "cut"; - case OTHER(14): return "copy"; - case OTHER(15): return "paste"; - case OTHER(16): return "find"; - case OTHER(17): return "mute"; - case OTHER(18): return "volume up"; - case OTHER(19): return "volume down"; - case OTHER(20): return "AS/400 equal"; - case OTHER(21): return "international 1"; - case OTHER(22): return "international 2"; - case OTHER(23): return "international 3"; - case OTHER(24): return "international 4"; - case OTHER(25): return "international 5"; - case OTHER(26): return "international 6"; - case OTHER(27): return "international 7"; - case OTHER(28): return "international 8"; - case OTHER(29): return "international 9"; - case OTHER(30): return "lang 1"; - case OTHER(31): return "lang 2"; - case OTHER(32): return "lang 3"; - case OTHER(33): return "lang 4"; - case OTHER(34): return "lang 5"; - case OTHER(35): return "lang 6"; - case OTHER(36): return "lang 7"; - case OTHER(37): return "lang 8"; - case OTHER(38): return "lang 9"; - case OTHER(39): return "alt erase"; - case OTHER(40): return "sys req"; - case OTHER(41): return "cancel"; - case OTHER(42): return "separator"; - case OTHER(43): return "out"; - case OTHER(44): return "oper"; - case OTHER(45): return "clear/again"; // XXX huh? - case OTHER(46): return "cr sel/props"; // XXX - case OTHER(47): return "ex sel"; - case OTHER(48): return "non US backslash"; - case OTHER(49): return "application"; - case OTHER(50): return "prior"; - default: break; - } -#undef OTHER - } - if( di.device == DEVICE_PUMP1 || di.device == DEVICE_PUMP2 ) - { - switch( di.button ) - { - case JOY_BUTTON_1: return "UL"; - case JOY_BUTTON_2: return "UR"; - case JOY_BUTTON_3: return "MID"; - case JOY_BUTTON_4: return "DL"; - case JOY_BUTTON_5: return "DR"; - case JOY_BUTTON_6: return "Esc"; - case JOY_BUTTON_7: return "P2 UL"; - case JOY_BUTTON_8: return "P2 UR"; - case JOY_BUTTON_9: return "P2 MID"; - case JOY_BUTTON_10: return "P2 DL"; - case JOY_BUTTON_11: return "P2 DR"; - default: break; - } - } - - return InputHandler::GetDeviceSpecificInputString( di ); -} - -wchar_t InputHandler_MacOSX_HID::DeviceButtonToChar( DeviceButton button, bool bUseCurrentKeyModifiers ) -{ - // KeyTranslate maps these keys to a character. They shouldn't be mapped to any character. - switch( button ) - { - default: - if( (button >= KEY_F1 && button <= KEY_F16) ) - return L'\0'; - break; - case KEY_UP: - case KEY_DOWN: - case KEY_LEFT: - case KEY_RIGHT: - case KEY_ESC: - case KEY_TAB: - case KEY_ENTER: - case KEY_PRTSC: - case KEY_SCRLLOCK: - case KEY_PAUSE: - case KEY_DEL: - case KEY_HOME: - case KEY_END: - case KEY_PGUP: - case KEY_PGDN: - case KEY_NUMLOCK: - case KEY_KP_ENTER: - return L'\0'; - } - - // Find the USB key code for this DeviceButton - UInt8 iMacVirtualKey; - if( KeyboardDevice::DeviceButtonToMacVirtualKey( button, iMacVirtualKey ) ) - { - UInt32 modifiers = 0; - if( bUseCurrentKeyModifiers ) - modifiers = GetCurrentKeyModifiers(); - - // todo: handle Caps Lock -freem - - SInt16 iCurrentKeyScript = GetScriptManagerVariable( smKeyScript ); - SInt16 iCurrentKeyLayoutID = GetScriptVariable( iCurrentKeyScript, smScriptKeys ); - static SInt16 iLastKeyLayoutID = !iCurrentKeyLayoutID; // Just be different. - static UInt32 iDeadKeyState; - static UCKeyboardLayout **KeyLayout; - - if( iCurrentKeyLayoutID != iLastKeyLayoutID ) - { - iDeadKeyState = 0; - KeyLayout = (UCKeyboardLayout **)GetResource( 'uchr', iCurrentKeyLayoutID ); - iLastKeyLayoutID = iCurrentKeyLayoutID; - } - if( KeyLayout ) - { - UInt32 keyboardType = LMGetKbdType(); - UInt32 nModifiers = bUseCurrentKeyModifiers ? GetCurrentKeyModifiers() : 0; - UniChar unicodeInputString[4]; - UniCharCount length; - OSStatus status = UCKeyTranslate( *KeyLayout, iMacVirtualKey, kUCKeyActionDown, nModifiers, - keyboardType, 0, &iDeadKeyState, ARRAYLEN(unicodeInputString), - &length, unicodeInputString ); - - if( status ) - return L'\0'; - - CFStringRef inputString = CFStringCreateWithCharacters( NULL, unicodeInputString, length ); - char utf8InputString[7]; // Max size is 6 (although really only 4 are used) + null. - - if( !CFStringGetCString(inputString, utf8InputString, 7, kCFStringEncodingUTF8) ) - { - CFRelease( inputString ); - return L'\0'; - } - - wchar_t ch = utf8_get_char( utf8InputString ); - - CFRelease( inputString ); - return ch == INVALID_CHAR ? L'\0' : ch; - - } - else - { - // Fall back on the 'KCHR' resource. - static unsigned long state = 0; - static Ptr keymap = NULL; - Ptr new_keymap; - - new_keymap = (Ptr)GetScriptManagerVariable(smKCHRCache); - if( new_keymap != keymap ) - { - keymap = new_keymap; - state = 0; - } - // XXX: Only returns ascii. é will be returned as e. - return KeyTranslate( keymap, UInt16(iMacVirtualKey)|modifiers, &state ) & 0xFF; - } - } - - return InputHandler::DeviceButtonToChar( button, bUseCurrentKeyModifiers ); -} - -/* - * (c) 2005, 2006 Steve Checkoway - * All rights reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, and/or sell copies of the Software, and to permit persons to - * whom the Software is furnished to do so, provided that the above - * copyright notice(s) and this permission notice appear in all copies of - * the Software and that both the above copyright notice(s) and this - * permission notice appear in supporting documentation. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF - * THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS - * INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT - * OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS - * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR - * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - * PERFORMANCE OF THIS SOFTWARE. - */ +#include "global.h" +#include "RageLog.h" +#include "InputHandler_MacOSX_HID.h" +#include "Foreach.h" +#include "PrefsManager.h" +#include "InputFilter.h" +#include "archutils/Darwin/DarwinThreadHelpers.h" +#include "archutils/Darwin/KeyboardDevice.h" +#include "archutils/Darwin/MouseDevice.h" +#include "archutils/Darwin/JoystickDevice.h" +#include "archutils/Darwin/PumpDevice.h" + +#include +#include + +REGISTER_INPUT_HANDLER_CLASS2( HID, MacOSX_HID ); + +void InputHandler_MacOSX_HID::QueueCallback( void *target, int result, void *refcon, void *sender ) +{ + // The result seems useless as you can't actually return anything... + // refcon is the Device number + + RageTimer now; + InputHandler_MacOSX_HID *This = (InputHandler_MacOSX_HID *)target; + IOHIDQueueInterface **queue = (IOHIDQueueInterface **)sender; + IOHIDEventStruct event; + AbsoluteTime zeroTime = { 0, 0 }; + HIDDevice *dev = This->m_vDevices[int( refcon )]; + vector vPresses; + + while( (result = CALL(queue, getNextEvent, &event, zeroTime, 0)) == kIOReturnSuccess ) + { + if( event.longValueSize != 0 && event.longValue != NULL ) + { + free( event.longValue ); + continue; + } + //LOG->Trace( "Got event with cookie %p, value %d", event.elementCookie, int(event.value) ); + dev->GetButtonPresses( vPresses, event.elementCookie, event.value, now ); + } + for (DeviceInput &i : vPresses) + INPUTFILTER->ButtonPressed( i ); +} + +static void RunLoopStarted( CFRunLoopObserverRef o, CFRunLoopActivity a, void *sem ) +{ + CFRunLoopObserverInvalidate( o ); + CFRelease( o ); // we don't need this any longer + ((RageSemaphore *)sem)->Post(); +} + +int InputHandler_MacOSX_HID::Run( void *data ) +{ + InputHandler_MacOSX_HID *This = (InputHandler_MacOSX_HID *)data; + + This->m_LoopRef = CFRunLoopGetCurrent(); + CFRetain( This->m_LoopRef ); + + This->StartDevices(); + { + const RString sError = SetThreadPrecedence( 1.0f ); + if( !sError.empty() ) + LOG->Warn( "Could not set precedence of the input thread: %s", sError.c_str() ); + } + // Add an observer for the start of the run loop + { + /* The function copies the information out of the structure, so the memory + * pointed to by context does not need to persist beyond the function call. */ + CFRunLoopObserverContext context = { 0, &This->m_Sem, NULL, NULL, NULL }; + CFRunLoopObserverRef o = CFRunLoopObserverCreate( kCFAllocatorDefault, kCFRunLoopEntry, + false, 0, RunLoopStarted, &context); + CFRunLoopAddObserver( This->m_LoopRef, o, kCFRunLoopDefaultMode ); + } + + /* Add a source for ending the run loop. This serves two purposes: + * 1. it provides a way to terminate the run loop when IH_MacOSX_HID exists, + * and 2. it ensures that CFRunLoopRun() doesn't return immediately if + * there are no other sources. */ + { + /* Being a little tricky here, the perform callback takes a void* and + * returns nothing. CFRunLoopStop takes a CFRunLoopRef (a pointer) so + * cast the function and pass the loop ref. */ + void *info = This->m_LoopRef; + void (*perform)(void *) = (void (*)(void *))CFRunLoopStop; + // { version, info, retain, release, copyDescription, equal, hash, schedule, cancel, perform } + CFRunLoopSourceContext context = { 0, info, NULL, NULL, NULL, NULL, NULL, NULL, NULL, perform }; + + // Pass 1 so that it is called after all inputs have been handled (they will have order = 0) + This->m_SourceRef = CFRunLoopSourceCreate( kCFAllocatorDefault, 1, &context ); + + CFRunLoopAddSource( This->m_LoopRef, This->m_SourceRef, kCFRunLoopDefaultMode ); + } + CFRunLoopRun(); + LOG->Trace( "Shutting down input handler thread..." ); + return 0; +} + +void InputHandler_MacOSX_HID::DeviceAdded( void *refCon, io_iterator_t ) +{ + InputHandler_MacOSX_HID *This = (InputHandler_MacOSX_HID *)refCon; + + LockMut( This->m_ChangeLock ); + This->m_bChanged = true; +} + +void InputHandler_MacOSX_HID::DeviceChanged( void *refCon, io_service_t service, natural_t messageType, void *arg ) +{ + if( messageType == kIOMessageServiceIsTerminated ) + { + InputHandler_MacOSX_HID *This = (InputHandler_MacOSX_HID *)refCon; + + LockMut( This->m_ChangeLock ); + This->m_bChanged = true; + } +} + +// m_LoopRef needs to be set before this is called +void InputHandler_MacOSX_HID::StartDevices() +{ + int n = 0; + + ASSERT( m_LoopRef ); + FOREACH( HIDDevice *, m_vDevices, i ) + (*i)->StartQueue( m_LoopRef, InputHandler_MacOSX_HID::QueueCallback, this, n++ ); + + CFRunLoopSourceRef runLoopSource = IONotificationPortGetRunLoopSource( m_NotifyPort ); + + CFRunLoopAddSource( m_LoopRef, runLoopSource, kCFRunLoopDefaultMode ); +} + +InputHandler_MacOSX_HID::~InputHandler_MacOSX_HID() +{ + FOREACH( HIDDevice *, m_vDevices, i ) + delete *i; + if( PREFSMAN->m_bThreadedInput ) + { + CFRunLoopSourceSignal( m_SourceRef ); + CFRunLoopWakeUp( m_LoopRef ); + m_InputThread.Wait(); + CFRelease( m_SourceRef ); + CFRelease( m_LoopRef ); + LOG->Trace( "Input handler thread shut down." ); + } + + FOREACH( io_iterator_t, m_vIters, i ) + IOObjectRelease( *i ); + IONotificationPortDestroy( m_NotifyPort ); +} + +static CFDictionaryRef GetMatchingDictionary( int usagePage, int usage ) +{ + // Build the matching dictionary. + CFMutableDictionaryRef dict; + + if( (dict = IOServiceMatching(kIOHIDDeviceKey)) == NULL ) + FAIL_M( "Couldn't create a matching dictionary." ); + // Refine the search by only looking for joysticks + CFNumberRef usagePageRef = CFInt( usagePage ); + CFNumberRef usageRef = CFInt( usage ); + + CFDictionarySetValue( dict, CFSTR(kIOHIDPrimaryUsagePageKey), usagePageRef ); + CFDictionarySetValue( dict, CFSTR(kIOHIDPrimaryUsageKey), usageRef ); + + // Cleanup after ourselves + CFRelease( usagePageRef ); + CFRelease( usageRef ); + + return dict; +} + +// Factor this out because nothing else in IH_C::AddDevices() needs to know the type of the device. +static HIDDevice *MakeDevice( InputDevice id ) +{ + if( id == DEVICE_KEYBOARD ) + return new KeyboardDevice; + /* + if( id == DEVICE_MOUSE ) + return new MouseDevice; + */ + if( IsJoystick(id) ) + return new JoystickDevice; + if( IsPump(id) ) + return new PumpDevice; + return NULL; +} + +void InputHandler_MacOSX_HID::AddDevices( int usagePage, int usage, InputDevice &id ) +{ + io_iterator_t iter; + CFDictionaryRef dict = GetMatchingDictionary( usagePage, usage ); + kern_return_t ret = IOServiceAddMatchingNotification( m_NotifyPort, kIOFirstMatchNotification, dict, + InputHandler_MacOSX_HID::DeviceAdded, this, &iter ); + io_object_t device; + + if( ret != KERN_SUCCESS ) + return; + + m_vIters.push_back( iter ); + + // Iterate over the devices and add them + while( (device = IOIteratorNext(iter)) ) + { + LOG->Trace( "\tFound device %d", id ); + HIDDevice *dev = MakeDevice( id ); + int num; + + if( !dev ) + { + LOG->Trace( "\t\tInvalid id, deleting device" ); + IOObjectRelease( device ); + continue; + } + + if( !dev->Open(device) || (num = dev->AssignIDs(id)) == -1 ) + { + LOG->Trace( "\tFailed top open or assign id, deleting device" ); + delete dev; + IOObjectRelease( device ); + continue; + } + io_iterator_t i; + + enum_add( id, num ); + m_vDevices.push_back( dev ); + + ret = IOServiceAddInterestNotification( + m_NotifyPort, device, kIOGeneralInterest, + InputHandler_MacOSX_HID::DeviceChanged, + this, &i + ); + + if( ret == KERN_SUCCESS ) + m_vIters.push_back( i ); + else + LOG->Trace( "\t\tFailed to add device changed notification, deleting device" ); + IOObjectRelease( device ); + } +} + +InputHandler_MacOSX_HID::InputHandler_MacOSX_HID() : m_Sem( "Input thread started" ), m_ChangeLock( "Input handler change lock" ) +{ + InputDevice id = DEVICE_KEYBOARD; + + // Set up the notify ports. + m_NotifyPort = IONotificationPortCreate( kIOMasterPortDefault ); + + // Add devices. + LOG->Trace( "Finding keyboards" ); + AddDevices( kHIDPage_GenericDesktop, kHIDUsage_GD_Keyboard, id ); + + LOG->Trace( "Finding mice" ); + AddDevices( kHIDPage_GenericDesktop, kHIDUsage_GD_Mouse, id ); + + LOG->Trace( "Finding joysticks" ); + id = DEVICE_JOY1; + AddDevices( kHIDPage_GenericDesktop, kHIDUsage_GD_Joystick, id ); + AddDevices( kHIDPage_GenericDesktop, kHIDUsage_GD_GamePad, id ); + LOG->Trace( "Finding pump" ); + id = DEVICE_PUMP1; + AddDevices( kHIDPage_VendorDefinedStart, 0x0001, id ); // Pump pads use the first vendor specific usage page. + m_bChanged = false; + + if( PREFSMAN->m_bThreadedInput ) + { + m_InputThread.SetName( "Input thread" ); + m_InputThread.Create( InputHandler_MacOSX_HID::Run, this ); + // Wait for the run loop to start before returning. + m_Sem.Wait(); + } + else + { + m_LoopRef = CFRunLoopRef( GetCFRunLoopFromEventLoop(GetMainEventLoop()) ); + CFRetain( m_LoopRef ); + StartDevices(); + } +} + +void InputHandler_MacOSX_HID::GetDevicesAndDescriptions( vector& vDevices ) +{ + for (HIDDevice *i : m_vDevices) + i->GetDevicesAndDescriptions( vDevices ); +} + +RString InputHandler_MacOSX_HID::GetDeviceSpecificInputString( const DeviceInput &di ) +{ + if( di.device == DEVICE_KEYBOARD ) + { +#define OTHER(n) (KEY_OTHER_0 + (n)) + switch( di.button ) + { + case KEY_DEL: return "del"; + case KEY_BACK: return "delete"; + case KEY_ENTER: return "return"; + case KEY_LALT: return "left option"; + case KEY_RALT: return "right option"; + case KEY_LMETA: return "left cmd"; + case KEY_RMETA: return "right cmd"; + case KEY_INSERT: return "help"; + case OTHER(0): return "F17"; + case OTHER(1): return "F18"; + case OTHER(2): return "F19"; + case OTHER(3): return "F20"; + case OTHER(4): return "F21"; + case OTHER(5): return "F22"; + case OTHER(6): return "F23"; + case OTHER(7): return "F25"; + case OTHER(8): return "execute"; + case OTHER(9): return "select"; + case OTHER(10): return "stop"; + case OTHER(11): return "again"; + case OTHER(12): return "undo"; + case OTHER(13): return "cut"; + case OTHER(14): return "copy"; + case OTHER(15): return "paste"; + case OTHER(16): return "find"; + case OTHER(17): return "mute"; + case OTHER(18): return "volume up"; + case OTHER(19): return "volume down"; + case OTHER(20): return "AS/400 equal"; + case OTHER(21): return "international 1"; + case OTHER(22): return "international 2"; + case OTHER(23): return "international 3"; + case OTHER(24): return "international 4"; + case OTHER(25): return "international 5"; + case OTHER(26): return "international 6"; + case OTHER(27): return "international 7"; + case OTHER(28): return "international 8"; + case OTHER(29): return "international 9"; + case OTHER(30): return "lang 1"; + case OTHER(31): return "lang 2"; + case OTHER(32): return "lang 3"; + case OTHER(33): return "lang 4"; + case OTHER(34): return "lang 5"; + case OTHER(35): return "lang 6"; + case OTHER(36): return "lang 7"; + case OTHER(37): return "lang 8"; + case OTHER(38): return "lang 9"; + case OTHER(39): return "alt erase"; + case OTHER(40): return "sys req"; + case OTHER(41): return "cancel"; + case OTHER(42): return "separator"; + case OTHER(43): return "out"; + case OTHER(44): return "oper"; + case OTHER(45): return "clear/again"; // XXX huh? + case OTHER(46): return "cr sel/props"; // XXX + case OTHER(47): return "ex sel"; + case OTHER(48): return "non US backslash"; + case OTHER(49): return "application"; + case OTHER(50): return "prior"; + default: break; + } +#undef OTHER + } + if( di.device == DEVICE_PUMP1 || di.device == DEVICE_PUMP2 ) + { + switch( di.button ) + { + case JOY_BUTTON_1: return "UL"; + case JOY_BUTTON_2: return "UR"; + case JOY_BUTTON_3: return "MID"; + case JOY_BUTTON_4: return "DL"; + case JOY_BUTTON_5: return "DR"; + case JOY_BUTTON_6: return "Esc"; + case JOY_BUTTON_7: return "P2 UL"; + case JOY_BUTTON_8: return "P2 UR"; + case JOY_BUTTON_9: return "P2 MID"; + case JOY_BUTTON_10: return "P2 DL"; + case JOY_BUTTON_11: return "P2 DR"; + default: break; + } + } + + return InputHandler::GetDeviceSpecificInputString( di ); +} + +wchar_t InputHandler_MacOSX_HID::DeviceButtonToChar( DeviceButton button, bool bUseCurrentKeyModifiers ) +{ + // KeyTranslate maps these keys to a character. They shouldn't be mapped to any character. + switch( button ) + { + default: + if( (button >= KEY_F1 && button <= KEY_F16) ) + return L'\0'; + break; + case KEY_UP: + case KEY_DOWN: + case KEY_LEFT: + case KEY_RIGHT: + case KEY_ESC: + case KEY_TAB: + case KEY_ENTER: + case KEY_PRTSC: + case KEY_SCRLLOCK: + case KEY_PAUSE: + case KEY_DEL: + case KEY_HOME: + case KEY_END: + case KEY_PGUP: + case KEY_PGDN: + case KEY_NUMLOCK: + case KEY_KP_ENTER: + return L'\0'; + } + + // Find the USB key code for this DeviceButton + UInt8 iMacVirtualKey; + if( KeyboardDevice::DeviceButtonToMacVirtualKey( button, iMacVirtualKey ) ) + { + UInt32 modifiers = 0; + if( bUseCurrentKeyModifiers ) + modifiers = GetCurrentKeyModifiers(); + + // todo: handle Caps Lock -freem + + SInt16 iCurrentKeyScript = GetScriptManagerVariable( smKeyScript ); + SInt16 iCurrentKeyLayoutID = GetScriptVariable( iCurrentKeyScript, smScriptKeys ); + static SInt16 iLastKeyLayoutID = !iCurrentKeyLayoutID; // Just be different. + static UInt32 iDeadKeyState; + static UCKeyboardLayout **KeyLayout; + + if( iCurrentKeyLayoutID != iLastKeyLayoutID ) + { + iDeadKeyState = 0; + KeyLayout = (UCKeyboardLayout **)GetResource( 'uchr', iCurrentKeyLayoutID ); + iLastKeyLayoutID = iCurrentKeyLayoutID; + } + if( KeyLayout ) + { + UInt32 keyboardType = LMGetKbdType(); + UInt32 nModifiers = bUseCurrentKeyModifiers ? GetCurrentKeyModifiers() : 0; + UniChar unicodeInputString[4]; + UniCharCount length; + OSStatus status = UCKeyTranslate( *KeyLayout, iMacVirtualKey, kUCKeyActionDown, nModifiers, + keyboardType, 0, &iDeadKeyState, ARRAYLEN(unicodeInputString), + &length, unicodeInputString ); + + if( status ) + return L'\0'; + + CFStringRef inputString = CFStringCreateWithCharacters( NULL, unicodeInputString, length ); + char utf8InputString[7]; // Max size is 6 (although really only 4 are used) + null. + + if( !CFStringGetCString(inputString, utf8InputString, 7, kCFStringEncodingUTF8) ) + { + CFRelease( inputString ); + return L'\0'; + } + + wchar_t ch = utf8_get_char( utf8InputString ); + + CFRelease( inputString ); + return ch == INVALID_CHAR ? L'\0' : ch; + + } + else + { + // Fall back on the 'KCHR' resource. + static unsigned long state = 0; + static Ptr keymap = NULL; + Ptr new_keymap; + + new_keymap = (Ptr)GetScriptManagerVariable(smKCHRCache); + if( new_keymap != keymap ) + { + keymap = new_keymap; + state = 0; + } + // XXX: Only returns ascii. é will be returned as e. + return KeyTranslate( keymap, UInt16(iMacVirtualKey)|modifiers, &state ) & 0xFF; + } + } + + return InputHandler::DeviceButtonToChar( button, bUseCurrentKeyModifiers ); +} + +/* + * (c) 2005, 2006 Steve Checkoway + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, and/or sell copies of the Software, and to permit persons to + * whom the Software is furnished to do so, provided that the above + * copyright notice(s) and this permission notice appear in all copies of + * the Software and that both the above copyright notice(s) and this + * permission notice appear in supporting documentation. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF + * THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS + * INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT + * OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS + * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ diff --git a/src/arch/arch.cpp b/src/arch/arch.cpp index be0e2e3e65..69e5d189da 100644 --- a/src/arch/arch.cpp +++ b/src/arch/arch.cpp @@ -1,330 +1,330 @@ -/* - * This file provides functions to create driver objects. - */ - -#include "global.h" -#include "RageLog.h" -#include "RageUtil.h" -#include "PrefsManager.h" -#include "arch.h" -#include "arch_platform.h" -#include "Foreach.h" -#include "LocalizedString.h" -#include "arch/arch_default.h" - -#include "InputHandler/Selector_InputHandler.h" -static LocalizedString INPUT_HANDLERS_EMPTY( "Arch", "Input Handlers cannot be empty." ); -void MakeInputHandlers( const RString &drivers, vector &Add ) -{ - vector DriversToTry; - split( drivers, ",", DriversToTry, true ); - - if( DriversToTry.empty() ) - RageException::Throw( INPUT_HANDLERS_EMPTY.GetValue() ); - - RString Driver; - - FOREACH_CONST( RString, DriversToTry, s ) - { - InputHandler *ret = NULL; - -#ifdef USE_INPUT_HANDLER_DIRECTINPUT - if( !s->CompareNoCase("DirectInput") ) ret = new InputHandler_DInput; -#endif -#ifdef USE_INPUT_HANDLER_PIUIO - if( !s->CompareNoCase("PIUIO") ) ret = new InputHandler_Linux_PIUIO; -#endif -#ifdef USE_INPUT_HANDLER_LINUX_JOYSTICK - if( !s->CompareNoCase("Joystick") ) ret = new InputHandler_Linux_Joystick; -#endif -#ifdef USE_INPUT_HANDLER_LINUX_TTY - if( !s->CompareNoCase("tty") ) ret = new InputHandler_Linux_tty; -#endif -#ifdef USE_INPUT_HANDLER_SDL - if( !s->CompareNoCase("SDL") ) ret = new InputHandler_SDL; -#endif -#ifdef USE_INPUT_HANDLER_WIN32_PARA - if( !s->CompareNoCase("Para") ) ret = new InputHandler_Win32_Para; -#endif -#ifdef USE_INPUT_HANDLER_WIN32_PUMP - if( !s->CompareNoCase("Pump") ) ret = new InputHandler_Win32_Pump; -#endif -#ifdef USE_INPUT_HANDLER_WIN32_MIDI - if( !s->CompareNoCase("MIDI") ) ret = new InputHandler_Win32_MIDI; -#endif -#ifdef USE_INPUT_HANDLER_X11 - if( !s->CompareNoCase("X11") ) ret = new InputHandler_X11; -#endif -#ifdef USE_INPUT_HANDLER_MACOSX_HID - if( !s->CompareNoCase("MacOSX") ) ret = new InputHandler_MacOSX_HID; -#endif - - if( ret == NULL ) - LOG->Trace( "Unknown Input Handler name: %s", s->c_str() ); - else - Add.push_back( ret ); - } - - // Always add - Add.push_back( new InputHandler_MonkeyKeyboard ); - -} - -#include "Lights/Selector_LightsDriver.h" -void MakeLightsDrivers( const RString &driver, vector &Add ) -{ - LOG->Trace( "Initializing lights driver: %s", driver.c_str() ); - - LightsDriver *ret = NULL; - -#ifdef USE_LIGHTS_DRIVER_LINUX_PIUIO - if( !driver.CompareNoCase("PIUIO") ) ret = new LightsDriver_Linux_PIUIO; -#endif -#ifdef USE_LIGHTS_DRIVER_LINUX_PARALLEL - if( !driver.CompareNoCase("LinuxParallel") ) ret = new LightsDriver_LinuxParallel; -#endif -#ifdef USE_LIGHTS_DRIVER_LINUX_WEEDTECH - if( !driver.CompareNoCase("WeedTech") ) ret = new LightsDriver_LinuxWeedTech; -#endif -#ifdef USE_LIGHTS_DRIVER_WIN32_PARALLEL - if( !driver.CompareNoCase("Parallel") ) ret = new LightsDriver_Win32Parallel; -#endif - - if( ret == NULL && driver.CompareNoCase("Null") ) - LOG->Trace( "Unknown lights driver name: %s", driver.c_str() ); - else if( ret != NULL ) - Add.push_back( ret ); - - Add.push_back( new LightsDriver_SystemMessage ); -} - -#include "LoadingWindow/Selector_LoadingWindow.h" -LoadingWindow *MakeLoadingWindow() -{ - if( !PREFSMAN->m_bShowLoadingWindow ) - return new LoadingWindow_Null; -#if defined(LINUX) && !defined(HAVE_GTK) - return new LoadingWindow_Null; -#endif - // Don't load NULL by default. - const RString drivers = "win32,cocoa,gtk"; - vector DriversToTry; - split( drivers, ",", DriversToTry, true ); - - ASSERT( DriversToTry.size() != 0 ); - - RString Driver; - LoadingWindow *ret = NULL; - - for( unsigned i = 0; ret == NULL && i < DriversToTry.size(); ++i ) - { - Driver = DriversToTry[i]; - -#ifdef USE_LOADING_WINDOW_COCOA - if( !DriversToTry[i].CompareNoCase("Cocoa") ) ret = new LoadingWindow_Cocoa; -#endif -#ifdef USE_LOADING_WINDOW_GTK - if( !DriversToTry[i].CompareNoCase("Gtk") ) ret = new LoadingWindow_Gtk; -#endif -#ifdef USE_LOADING_WINDOW_NULL - if( !DriversToTry[i].CompareNoCase("Null") ) ret = new LoadingWindow_Null; -#endif -#ifdef USE_LOADING_WINDOW_WIN32 - if( !DriversToTry[i].CompareNoCase("Win32") ) ret = new LoadingWindow_Win32; -#endif - - if( ret == NULL ) - continue; - - RString sError = ret->Init(); - if( sError != "" ) - { - LOG->Info( "Couldn't load driver %s: %s", DriversToTry[i].c_str(), sError.c_str() ); - SAFE_DELETE( ret ); - } - } - - if(ret) - LOG->Info( "Loading window: %s", Driver.c_str() ); - - return ret; -} - -#if defined(SUPPORT_OPENGL) -#include "LowLevelWindow/Selector_LowLevelWindow.h" -LowLevelWindow *MakeLowLevelWindow() -{ - return new ARCH_LOW_LEVEL_WINDOW; -} -#endif - -#include "MemoryCard/MemoryCardDriver_Null.h" -#include "MemoryCard/Selector_MemoryCardDriver.h" -MemoryCardDriver *MakeMemoryCardDriver() -{ - MemoryCardDriver *ret = NULL; - -#ifdef ARCH_MEMORY_CARD_DRIVER - ret = new ARCH_MEMORY_CARD_DRIVER; -#endif - - if( !ret ) - ret = new MemoryCardDriver_Null; - - return ret; -} - -static Preference g_sMovieDrivers( "MovieDrivers", "" ); // "" == default -#include "MovieTexture/Selector_MovieTexture.h" -static void DumpAVIDebugInfo( const RString& fn ); -// Try drivers in order of preference until we find one that works. -static LocalizedString MOVIE_DRIVERS_EMPTY ( "Arch", "Movie Drivers cannot be empty." ); -static LocalizedString COULDNT_CREATE_MOVIE_DRIVER ( "Arch", "Couldn't create a movie driver." ); -RageMovieTexture *MakeRageMovieTexture( RageTextureID ID ) -{ - DumpAVIDebugInfo( ID.filename ); - - RString sDrivers = g_sMovieDrivers; - if( sDrivers.empty() ) - sDrivers = DEFAULT_MOVIE_DRIVER_LIST; - - vector DriversToTry; - split( sDrivers, ",", DriversToTry, true ); - - if( DriversToTry.empty() ) - RageException::Throw( MOVIE_DRIVERS_EMPTY.GetValue() ); - - RString Driver; - RageMovieTexture *ret = NULL; - - for( unsigned i=0; ret==NULL && iTrace( "Initializing driver: %s", Driver.c_str() ); -#ifdef USE_MOVIE_TEXTURE_DSHOW - if( !Driver.CompareNoCase("DShow") ) ret = new MovieTexture_DShow(ID); -#endif -#ifdef USE_MOVIE_TEXTURE_FFMPEG - if( !Driver.CompareNoCase("FFMpeg") ) ret = new MovieTexture_FFMpeg(ID); -#endif -#ifdef USE_MOVIE_TEXTURE_NULL - if( !Driver.CompareNoCase("Null") ) ret = new MovieTexture_Null(ID); -#endif - if( ret == NULL ) - { - LOG->Trace( "Unknown movie driver name: %s", Driver.c_str() ); - continue; - } - - RString sError = ret->Init(); - if( sError != "" ) - { - LOG->Info( "Couldn't load driver %s: %s", Driver.c_str(), sError.c_str() ); - SAFE_DELETE( ret ); - } - } - if ( !ret ) - RageException::Throw( COULDNT_CREATE_MOVIE_DRIVER.GetValue() ); - - LOG->Trace( "Created movie texture \"%s\" with driver \"%s\"", - ID.filename.c_str(), Driver.c_str() ); - return ret; -} - -#include "Sound/Selector_RageSoundDriver.h" -static LocalizedString SOUND_DRIVERS_CANNOT_EMPTY( "Arch", "Sound Drivers cannot be empty." ); -RageSoundDriver *MakeRageSoundDriver( const RString &drivers ) -{ - vector DriversToTry; - split( drivers, ",", DriversToTry, true ); - - if( DriversToTry.empty() ) - RageException::Throw( SOUND_DRIVERS_CANNOT_EMPTY.GetValue() ); - - RString Driver; - RageSoundDriver *ret = NULL; - - for( unsigned i = 0; ret == NULL && i < DriversToTry.size(); ++i ) - { - Driver = DriversToTry[i]; - LOG->Trace( "Initializing driver: %s", DriversToTry[i].c_str() ); - -#ifdef USE_RAGE_SOUND_ALSA9 - if( !DriversToTry[i].CompareNoCase("ALSA") ) ret = new RageSound_ALSA9; -#endif -#ifdef USE_RAGE_SOUND_ALSA9_SOFTWARE - if( !DriversToTry[i].CompareNoCase("ALSA-sw") ) ret = new RageSound_ALSA9_Software; -#endif -#ifdef USE_RAGE_SOUND_AU - if( !DriversToTry[i].CompareNoCase("AudioUnit") ) ret = new RageSoundDriver_AU; -#endif -#ifdef USE_RAGE_SOUND_DSOUND - if( !DriversToTry[i].CompareNoCase("DirectSound") ) ret = new RageSound_DSound; -#endif -#ifdef USE_RAGE_SOUND_DSOUND_SOFTWARE - if( !DriversToTry[i].CompareNoCase("DirectSound-sw") ) ret = new RageSound_DSound_Software; -#endif -#ifdef USE_RAGE_SOUND_NULL - if( !DriversToTry[i].CompareNoCase("Null") ) ret = new RageSound_Null; -#endif -#ifdef USE_RAGE_SOUND_OSS - if( !DriversToTry[i].CompareNoCase("OSS") ) ret = new RageSound_OSS; -#endif -#ifdef USE_RAGE_SOUND_WAVE_OUT - if( !DriversToTry[i].CompareNoCase("WaveOut") ) ret = new RageSound_WaveOut; -#endif - - if( ret == NULL ) - { - LOG->Trace( "Unknown sound driver name: %s", DriversToTry[i].c_str() ); - continue; - } - - RString sError = ret->Init(); - if( sError != "" ) - { - LOG->Info( "Couldn't load driver %s: %s", DriversToTry[i].c_str(), sError.c_str() ); - SAFE_DELETE( ret ); - } - } - - if( ret ) - LOG->Info( "Sound driver: %s", Driver.c_str() ); - - return ret; -} - -// Helper for MakeRageMovieTexture() -static void DumpAVIDebugInfo( const RString& fn ) -{ - RString type, handler; - if( !RageMovieTexture::GetFourCC( fn, handler, type ) ) - return; - - LOG->Trace( "Movie %s has handler '%s', type '%s'", fn.c_str(), handler.c_str(), type.c_str() ); -} - -/* - * (c) 2002-2005 Glenn Maynard, Ben Anderson - * All rights reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, and/or sell copies of the Software, and to permit persons to - * whom the Software is furnished to do so, provided that the above - * copyright notice(s) and this permission notice appear in all copies of - * the Software and that both the above copyright notice(s) and this - * permission notice appear in supporting documentation. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF - * THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS - * INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT - * OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS - * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR - * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - * PERFORMANCE OF THIS SOFTWARE. - */ +/* + * This file provides functions to create driver objects. + */ + +#include "global.h" +#include "RageLog.h" +#include "RageUtil.h" +#include "PrefsManager.h" +#include "arch.h" +#include "arch_platform.h" +#include "Foreach.h" +#include "LocalizedString.h" +#include "arch/arch_default.h" + +#include "InputHandler/Selector_InputHandler.h" +static LocalizedString INPUT_HANDLERS_EMPTY( "Arch", "Input Handlers cannot be empty." ); +void MakeInputHandlers( const RString &drivers, vector &Add ) +{ + vector DriversToTry; + split( drivers, ",", DriversToTry, true ); + + if( DriversToTry.empty() ) + RageException::Throw( INPUT_HANDLERS_EMPTY.GetValue() ); + + RString Driver; + + for (RString const &s: DriversToTry) + { + InputHandler *ret = NULL; + +#ifdef USE_INPUT_HANDLER_DIRECTINPUT + if( !s.CompareNoCase("DirectInput") ) ret = new InputHandler_DInput; +#endif +#ifdef USE_INPUT_HANDLER_PIUIO + if( !s.CompareNoCase("PIUIO") ) ret = new InputHandler_Linux_PIUIO; +#endif +#ifdef USE_INPUT_HANDLER_LINUX_JOYSTICK + if( !s.CompareNoCase("Joystick") ) ret = new InputHandler_Linux_Joystick; +#endif +#ifdef USE_INPUT_HANDLER_LINUX_TTY + if( !s.CompareNoCase("tty") ) ret = new InputHandler_Linux_tty; +#endif +#ifdef USE_INPUT_HANDLER_SDL + if( !s.CompareNoCase("SDL") ) ret = new InputHandler_SDL; +#endif +#ifdef USE_INPUT_HANDLER_WIN32_PARA + if( !s.CompareNoCase("Para") ) ret = new InputHandler_Win32_Para; +#endif +#ifdef USE_INPUT_HANDLER_WIN32_PUMP + if( !s.CompareNoCase("Pump") ) ret = new InputHandler_Win32_Pump; +#endif +#ifdef USE_INPUT_HANDLER_WIN32_MIDI + if( !s.CompareNoCase("MIDI") ) ret = new InputHandler_Win32_MIDI; +#endif +#ifdef USE_INPUT_HANDLER_X11 + if( !s.CompareNoCase("X11") ) ret = new InputHandler_X11; +#endif +#ifdef USE_INPUT_HANDLER_MACOSX_HID + if( !s.CompareNoCase("MacOSX") ) ret = new InputHandler_MacOSX_HID; +#endif + + if( ret == NULL ) + LOG->Trace( "Unknown Input Handler name: %s", s.c_str() ); + else + Add.push_back( ret ); + } + + // Always add + Add.push_back( new InputHandler_MonkeyKeyboard ); + +} + +#include "Lights/Selector_LightsDriver.h" +void MakeLightsDrivers( const RString &driver, vector &Add ) +{ + LOG->Trace( "Initializing lights driver: %s", driver.c_str() ); + + LightsDriver *ret = NULL; + +#ifdef USE_LIGHTS_DRIVER_LINUX_PIUIO + if( !driver.CompareNoCase("PIUIO") ) ret = new LightsDriver_Linux_PIUIO; +#endif +#ifdef USE_LIGHTS_DRIVER_LINUX_PARALLEL + if( !driver.CompareNoCase("LinuxParallel") ) ret = new LightsDriver_LinuxParallel; +#endif +#ifdef USE_LIGHTS_DRIVER_LINUX_WEEDTECH + if( !driver.CompareNoCase("WeedTech") ) ret = new LightsDriver_LinuxWeedTech; +#endif +#ifdef USE_LIGHTS_DRIVER_WIN32_PARALLEL + if( !driver.CompareNoCase("Parallel") ) ret = new LightsDriver_Win32Parallel; +#endif + + if( ret == NULL && driver.CompareNoCase("Null") ) + LOG->Trace( "Unknown lights driver name: %s", driver.c_str() ); + else if( ret != NULL ) + Add.push_back( ret ); + + Add.push_back( new LightsDriver_SystemMessage ); +} + +#include "LoadingWindow/Selector_LoadingWindow.h" +LoadingWindow *MakeLoadingWindow() +{ + if( !PREFSMAN->m_bShowLoadingWindow ) + return new LoadingWindow_Null; +#if defined(LINUX) && !defined(HAVE_GTK) + return new LoadingWindow_Null; +#endif + // Don't load NULL by default. + const RString drivers = "win32,cocoa,gtk"; + vector DriversToTry; + split( drivers, ",", DriversToTry, true ); + + ASSERT( DriversToTry.size() != 0 ); + + RString Driver; + LoadingWindow *ret = NULL; + + for( unsigned i = 0; ret == NULL && i < DriversToTry.size(); ++i ) + { + Driver = DriversToTry[i]; + +#ifdef USE_LOADING_WINDOW_COCOA + if( !DriversToTry[i].CompareNoCase("Cocoa") ) ret = new LoadingWindow_Cocoa; +#endif +#ifdef USE_LOADING_WINDOW_GTK + if( !DriversToTry[i].CompareNoCase("Gtk") ) ret = new LoadingWindow_Gtk; +#endif +#ifdef USE_LOADING_WINDOW_NULL + if( !DriversToTry[i].CompareNoCase("Null") ) ret = new LoadingWindow_Null; +#endif +#ifdef USE_LOADING_WINDOW_WIN32 + if( !DriversToTry[i].CompareNoCase("Win32") ) ret = new LoadingWindow_Win32; +#endif + + if( ret == NULL ) + continue; + + RString sError = ret->Init(); + if( sError != "" ) + { + LOG->Info( "Couldn't load driver %s: %s", DriversToTry[i].c_str(), sError.c_str() ); + SAFE_DELETE( ret ); + } + } + + if(ret) + LOG->Info( "Loading window: %s", Driver.c_str() ); + + return ret; +} + +#if defined(SUPPORT_OPENGL) +#include "LowLevelWindow/Selector_LowLevelWindow.h" +LowLevelWindow *MakeLowLevelWindow() +{ + return new ARCH_LOW_LEVEL_WINDOW; +} +#endif + +#include "MemoryCard/MemoryCardDriver_Null.h" +#include "MemoryCard/Selector_MemoryCardDriver.h" +MemoryCardDriver *MakeMemoryCardDriver() +{ + MemoryCardDriver *ret = NULL; + +#ifdef ARCH_MEMORY_CARD_DRIVER + ret = new ARCH_MEMORY_CARD_DRIVER; +#endif + + if( !ret ) + ret = new MemoryCardDriver_Null; + + return ret; +} + +static Preference g_sMovieDrivers( "MovieDrivers", "" ); // "" == default +#include "MovieTexture/Selector_MovieTexture.h" +static void DumpAVIDebugInfo( const RString& fn ); +// Try drivers in order of preference until we find one that works. +static LocalizedString MOVIE_DRIVERS_EMPTY ( "Arch", "Movie Drivers cannot be empty." ); +static LocalizedString COULDNT_CREATE_MOVIE_DRIVER ( "Arch", "Couldn't create a movie driver." ); +RageMovieTexture *MakeRageMovieTexture( RageTextureID ID ) +{ + DumpAVIDebugInfo( ID.filename ); + + RString sDrivers = g_sMovieDrivers; + if( sDrivers.empty() ) + sDrivers = DEFAULT_MOVIE_DRIVER_LIST; + + vector DriversToTry; + split( sDrivers, ",", DriversToTry, true ); + + if( DriversToTry.empty() ) + RageException::Throw( MOVIE_DRIVERS_EMPTY.GetValue() ); + + RString Driver; + RageMovieTexture *ret = NULL; + + for( unsigned i=0; ret==NULL && iTrace( "Initializing driver: %s", Driver.c_str() ); +#ifdef USE_MOVIE_TEXTURE_DSHOW + if( !Driver.CompareNoCase("DShow") ) ret = new MovieTexture_DShow(ID); +#endif +#ifdef USE_MOVIE_TEXTURE_FFMPEG + if( !Driver.CompareNoCase("FFMpeg") ) ret = new MovieTexture_FFMpeg(ID); +#endif +#ifdef USE_MOVIE_TEXTURE_NULL + if( !Driver.CompareNoCase("Null") ) ret = new MovieTexture_Null(ID); +#endif + if( ret == NULL ) + { + LOG->Trace( "Unknown movie driver name: %s", Driver.c_str() ); + continue; + } + + RString sError = ret->Init(); + if( sError != "" ) + { + LOG->Info( "Couldn't load driver %s: %s", Driver.c_str(), sError.c_str() ); + SAFE_DELETE( ret ); + } + } + if ( !ret ) + RageException::Throw( COULDNT_CREATE_MOVIE_DRIVER.GetValue() ); + + LOG->Trace( "Created movie texture \"%s\" with driver \"%s\"", + ID.filename.c_str(), Driver.c_str() ); + return ret; +} + +#include "Sound/Selector_RageSoundDriver.h" +static LocalizedString SOUND_DRIVERS_CANNOT_EMPTY( "Arch", "Sound Drivers cannot be empty." ); +RageSoundDriver *MakeRageSoundDriver( const RString &drivers ) +{ + vector DriversToTry; + split( drivers, ",", DriversToTry, true ); + + if( DriversToTry.empty() ) + RageException::Throw( SOUND_DRIVERS_CANNOT_EMPTY.GetValue() ); + + RString Driver; + RageSoundDriver *ret = NULL; + + for( unsigned i = 0; ret == NULL && i < DriversToTry.size(); ++i ) + { + Driver = DriversToTry[i]; + LOG->Trace( "Initializing driver: %s", DriversToTry[i].c_str() ); + +#ifdef USE_RAGE_SOUND_ALSA9 + if( !DriversToTry[i].CompareNoCase("ALSA") ) ret = new RageSound_ALSA9; +#endif +#ifdef USE_RAGE_SOUND_ALSA9_SOFTWARE + if( !DriversToTry[i].CompareNoCase("ALSA-sw") ) ret = new RageSound_ALSA9_Software; +#endif +#ifdef USE_RAGE_SOUND_AU + if( !DriversToTry[i].CompareNoCase("AudioUnit") ) ret = new RageSoundDriver_AU; +#endif +#ifdef USE_RAGE_SOUND_DSOUND + if( !DriversToTry[i].CompareNoCase("DirectSound") ) ret = new RageSound_DSound; +#endif +#ifdef USE_RAGE_SOUND_DSOUND_SOFTWARE + if( !DriversToTry[i].CompareNoCase("DirectSound-sw") ) ret = new RageSound_DSound_Software; +#endif +#ifdef USE_RAGE_SOUND_NULL + if( !DriversToTry[i].CompareNoCase("Null") ) ret = new RageSound_Null; +#endif +#ifdef USE_RAGE_SOUND_OSS + if( !DriversToTry[i].CompareNoCase("OSS") ) ret = new RageSound_OSS; +#endif +#ifdef USE_RAGE_SOUND_WAVE_OUT + if( !DriversToTry[i].CompareNoCase("WaveOut") ) ret = new RageSound_WaveOut; +#endif + + if( ret == NULL ) + { + LOG->Trace( "Unknown sound driver name: %s", DriversToTry[i].c_str() ); + continue; + } + + RString sError = ret->Init(); + if( sError != "" ) + { + LOG->Info( "Couldn't load driver %s: %s", DriversToTry[i].c_str(), sError.c_str() ); + SAFE_DELETE( ret ); + } + } + + if( ret ) + LOG->Info( "Sound driver: %s", Driver.c_str() ); + + return ret; +} + +// Helper for MakeRageMovieTexture() +static void DumpAVIDebugInfo( const RString& fn ) +{ + RString type, handler; + if( !RageMovieTexture::GetFourCC( fn, handler, type ) ) + return; + + LOG->Trace( "Movie %s has handler '%s', type '%s'", fn.c_str(), handler.c_str(), type.c_str() ); +} + +/* + * (c) 2002-2005 Glenn Maynard, Ben Anderson + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, and/or sell copies of the Software, and to permit persons to + * whom the Software is furnished to do so, provided that the above + * copyright notice(s) and this permission notice appear in all copies of + * the Software and that both the above copyright notice(s) and this + * permission notice appear in supporting documentation. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF + * THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS + * INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT + * OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS + * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ diff --git a/src/archutils/Darwin/JoystickDevice.cpp b/src/archutils/Darwin/JoystickDevice.cpp index 67ddbe96c4..3bdfabc277 100644 --- a/src/archutils/Darwin/JoystickDevice.cpp +++ b/src/archutils/Darwin/JoystickDevice.cpp @@ -128,9 +128,8 @@ void JoystickDevice::AddElement( int usagePage, int usage, IOHIDElementCookie co void JoystickDevice::Open() { // Add elements to the queue for each Joystick - FOREACH_CONST( Joystick, m_vSticks, i ) + for (Joystick const &js : m_vSticks) { - const Joystick& js = *i; #define ADD(x) if( js.x ) AddElementToQueue( js.x ) ADD( x_axis ); ADD( y_axis ); ADD( z_axis ); ADD( x_rot ); ADD( y_rot ); ADD( z_rot ); @@ -156,10 +155,8 @@ bool JoystickDevice::InitDevice( int vid, int pid ) void JoystickDevice::GetButtonPresses( vector& vPresses, IOHIDElementCookie cookie, int value, const RageTimer& now ) const { - FOREACH_CONST( Joystick, m_vSticks, i ) + for (Joystick const &js : m_vSticks) { - const Joystick& js = *i; - if( js.x_axis == cookie ) { float level = SCALE( value, js.x_min, js.x_max, -1.0f, 1.0f ); @@ -266,8 +263,8 @@ int JoystickDevice::AssignIDs( InputDevice startID ) void JoystickDevice::GetDevicesAndDescriptions( vector& vDevices ) const { - FOREACH_CONST( Joystick, m_vSticks, i ) - vDevices.push_back( InputDeviceInfo(i->id,GetDescription()) ); + for (Joystick &i : m_vSticks) + vDevices.push_back( InputDeviceInfo(i.id,GetDescription()) ); } /*