#include "global.h" #include "InputMapper.h" #include "IniFile.h" #include "GameManager.h" #include "GameState.h" #include "RageLog.h" #include "InputFilter.h" #include "RageUtil.h" #include "PrefsManager.h" #include "RageInput.h" #include "Game.h" #include "Style.h" #include "SpecialFiles.h" #include "LocalizedString.h" static Preference g_sLastSeenInputDevices( "LastSeenInputDevices", "" ); static Preference g_bAutoMapOnJoyChange( "AutoMapOnJoyChange", true ); namespace { // lookup for efficiency from a DeviceInput to a GameInput // This is repopulated every time m_PItoDI changes by calling UpdateTempDItoPI(). map g_tempDItoGI; }; InputMapper* INPUTMAPPER = NULL; // global and accessable from anywhere in our program InputMapper::InputMapper() { ReadMappingsFromDisk(); } InputMapper::~InputMapper() { SaveMappingsToDisk(); g_tempDItoGI.clear(); } void InputMapper::ClearAllMappings() { for( int i=0; iGetCurrentGame(); for( int c=0; cm_iButtonsPerController; b++ ) { DeviceButton key = pGame->m_iDefaultKeyboardKey[c][b]; if( key == NO_DEFAULT_KEY ) continue; DeviceInput DeviceI( DEVICE_KEYBOARD, key ); GameInput GameI( (GameController)c, (GameButton)b ); if( !IsMapped(DeviceI) ) // if this key isn't already being used by another user-made mapping SetInputMap( DeviceI, GameI, 2 ); } } } struct AutoJoyMapping { const char *szGame; const char *szDriverRegex; // reported by InputHandler const char *szControllerName; // the product name of the controller struct InputMapper::Mapping maps[32]; }; #define END_MARKER {-1, DeviceButton_Invalid, -1, false }, // end marker const AutoJoyMapping g_AutoJoyMappings[] = { { "dance", "GIC USB Joystick", "Boom USB convertor (black/gray)", { { 0, JOY_BUTTON_16, DANCE_BUTTON_LEFT, false }, { 0, JOY_BUTTON_14, DANCE_BUTTON_RIGHT, false }, { 0, JOY_BUTTON_13, DANCE_BUTTON_UP, false }, { 0, JOY_BUTTON_15, DANCE_BUTTON_DOWN, false }, { 1, JOY_BUTTON_4, DANCE_BUTTON_LEFT, false }, { 1, JOY_BUTTON_2, DANCE_BUTTON_RIGHT, false }, { 1, JOY_BUTTON_1, DANCE_BUTTON_UP, false }, { 1, JOY_BUTTON_3, DANCE_BUTTON_DOWN, false }, { 0, JOY_BUTTON_7, DANCE_BUTTON_UPLEFT, false }, { 0, JOY_BUTTON_8, DANCE_BUTTON_UPRIGHT, false }, { 0, JOY_BUTTON_9, DANCE_BUTTON_BACK, false }, { 0, JOY_BUTTON_12, DANCE_BUTTON_START, false }, END_MARKER } }, { "dance", "4 axis 16 button joystick", "EMS USB2", { { 0, JOY_BUTTON_16, DANCE_BUTTON_LEFT, false }, { 0, JOY_BUTTON_14, DANCE_BUTTON_RIGHT, false }, { 0, JOY_BUTTON_13, DANCE_BUTTON_UP, false }, { 0, JOY_BUTTON_15, DANCE_BUTTON_DOWN, false }, { 1, JOY_BUTTON_4, DANCE_BUTTON_LEFT, false }, { 1, JOY_BUTTON_2, DANCE_BUTTON_RIGHT, false }, { 1, JOY_BUTTON_1, DANCE_BUTTON_UP, false }, { 1, JOY_BUTTON_3, DANCE_BUTTON_DOWN, false }, { 0, JOY_BUTTON_7, DANCE_BUTTON_UPLEFT, false }, { 0, JOY_BUTTON_8, DANCE_BUTTON_UPRIGHT, false }, { 0, JOY_BUTTON_9, DANCE_BUTTON_BACK, false }, { 0, JOY_BUTTON_10, DANCE_BUTTON_START, false }, END_MARKER } }, { "dance", "GamePad Pro USB ", // yes, there is a space at the end "GamePad Pro USB", { { 0, JOY_LEFT, DANCE_BUTTON_LEFT, false }, { 0, JOY_RIGHT, DANCE_BUTTON_RIGHT, false }, { 0, JOY_UP, DANCE_BUTTON_UP, false }, { 0, JOY_DOWN, DANCE_BUTTON_DOWN, false }, { 1, JOY_BUTTON_1, DANCE_BUTTON_LEFT, false }, { 1, JOY_BUTTON_3, DANCE_BUTTON_RIGHT, false }, { 1, JOY_BUTTON_4, DANCE_BUTTON_UP, false }, { 1, JOY_BUTTON_2, DANCE_BUTTON_DOWN, false }, { 0, JOY_BUTTON_5, DANCE_BUTTON_UPLEFT, false }, { 0, JOY_BUTTON_6, DANCE_BUTTON_UPRIGHT, false }, { 0, JOY_BUTTON_9, DANCE_BUTTON_BACK, false }, { 0, JOY_BUTTON_10, DANCE_BUTTON_START, false }, END_MARKER } }, { "dance", "SideWinder Game Pad USB version 1.0", "SideWinder Game Pad USB", { { 0, JOY_LEFT, DANCE_BUTTON_LEFT, false }, { 0, JOY_RIGHT, DANCE_BUTTON_RIGHT, false }, { 0, JOY_UP, DANCE_BUTTON_UP, false }, { 0, JOY_DOWN, DANCE_BUTTON_DOWN, false }, { 1, JOY_BUTTON_4, DANCE_BUTTON_LEFT, false }, { 1, JOY_BUTTON_2, DANCE_BUTTON_RIGHT, false }, { 1, JOY_BUTTON_5, DANCE_BUTTON_UP, false }, { 1, JOY_BUTTON_1, DANCE_BUTTON_DOWN, false }, { 0, JOY_BUTTON_7, DANCE_BUTTON_UPLEFT, false }, { 0, JOY_BUTTON_8, DANCE_BUTTON_UPRIGHT, false }, { 0, JOY_BUTTON_9, DANCE_BUTTON_BACK, false }, { 0, JOY_BUTTON_10, DANCE_BUTTON_START, false }, END_MARKER } }, { "dance", "4 axis 12 button joystick with hat switch", "Super Joy Box 5", { { 0, JOY_LEFT, DANCE_BUTTON_LEFT, false }, { 0, JOY_RIGHT, DANCE_BUTTON_RIGHT, false }, { 0, JOY_UP, DANCE_BUTTON_UP, false }, { 0, JOY_DOWN, DANCE_BUTTON_DOWN, false }, { 1, JOY_BUTTON_4, DANCE_BUTTON_LEFT, false }, { 1, JOY_BUTTON_2, DANCE_BUTTON_RIGHT, false }, { 1, JOY_BUTTON_1, DANCE_BUTTON_UP, false }, { 1, JOY_BUTTON_3, DANCE_BUTTON_DOWN, false }, { 0, JOY_BUTTON_7, DANCE_BUTTON_UPLEFT, false }, { 0, JOY_BUTTON_8, DANCE_BUTTON_UPRIGHT, false }, { 0, JOY_BUTTON_10, DANCE_BUTTON_BACK, false }, { 0, JOY_BUTTON_9, DANCE_BUTTON_START, false }, END_MARKER } }, { "dance", "MP-8866 Dual USB Joypad", "Super Dual Box", { { 0, JOY_LEFT, DANCE_BUTTON_LEFT, false }, { 0, JOY_RIGHT, DANCE_BUTTON_RIGHT, false }, { 0, JOY_UP, DANCE_BUTTON_UP, false }, { 0, JOY_DOWN, DANCE_BUTTON_DOWN, false }, { 1, JOY_BUTTON_4, DANCE_BUTTON_LEFT, false }, { 1, JOY_BUTTON_2, DANCE_BUTTON_RIGHT, false }, { 1, JOY_BUTTON_1, DANCE_BUTTON_UP, false }, { 1, JOY_BUTTON_3, DANCE_BUTTON_DOWN, false }, { 0, JOY_BUTTON_5, DANCE_BUTTON_UPLEFT, false }, { 0, JOY_BUTTON_6, DANCE_BUTTON_UPRIGHT, false }, { 1, JOY_BUTTON_7, DANCE_BUTTON_UPLEFT, false }, { 1, JOY_BUTTON_8, DANCE_BUTTON_UPRIGHT, false }, { 0, JOY_BUTTON_10, DANCE_BUTTON_BACK, false }, { 0, JOY_BUTTON_9, DANCE_BUTTON_START, false }, END_MARKER } }, { "dance", "NTPAD", "NTPAD", { { 0, JOY_BUTTON_13, DANCE_BUTTON_LEFT, false }, { 0, JOY_BUTTON_15, DANCE_BUTTON_RIGHT, false }, { 0, JOY_BUTTON_16, DANCE_BUTTON_UP, false }, { 0, JOY_BUTTON_14, DANCE_BUTTON_DOWN, false }, { 1, JOY_BUTTON_1, DANCE_BUTTON_LEFT, false }, { 1, JOY_BUTTON_3, DANCE_BUTTON_RIGHT, false }, { 1, JOY_BUTTON_4, DANCE_BUTTON_UP, false }, { 1, JOY_BUTTON_2, DANCE_BUTTON_DOWN, false }, { 0, JOY_BUTTON_5, DANCE_BUTTON_UPLEFT, false }, { 0, JOY_BUTTON_6, DANCE_BUTTON_UPRIGHT, false }, { 1, JOY_BUTTON_7, DANCE_BUTTON_UPLEFT, false }, { 1, JOY_BUTTON_8, DANCE_BUTTON_UPRIGHT, false }, { 0, JOY_BUTTON_9, DANCE_BUTTON_BACK, false }, { 0, JOY_BUTTON_10, DANCE_BUTTON_START, false }, END_MARKER } }, { "dance", "Psx Gamepad", "PSXPAD", { { 0, JOY_LEFT, DANCE_BUTTON_LEFT, false }, { 0, JOY_RIGHT, DANCE_BUTTON_RIGHT, false }, { 0, JOY_UP, DANCE_BUTTON_UP, false }, { 0, JOY_DOWN, DANCE_BUTTON_DOWN, false }, { 1, JOY_BUTTON_2, DANCE_BUTTON_LEFT, false }, { 1, JOY_BUTTON_1, DANCE_BUTTON_RIGHT, false }, { 1, JOY_BUTTON_4, DANCE_BUTTON_UP, false }, { 1, JOY_BUTTON_3, DANCE_BUTTON_DOWN, false }, { 0, JOY_BUTTON_7, DANCE_BUTTON_UPLEFT, false }, { 0, JOY_BUTTON_5, DANCE_BUTTON_UPRIGHT, false }, { 1, JOY_BUTTON_8, DANCE_BUTTON_UPLEFT, false }, { 1, JOY_BUTTON_6, DANCE_BUTTON_UPRIGHT, false }, { 0, JOY_BUTTON_10, DANCE_BUTTON_BACK, false }, { 0, JOY_BUTTON_9, DANCE_BUTTON_START, false }, END_MARKER } }, { "dance", "XBOX Gamepad Plugin V0.01", "X-Box gamepad", { { 0, JOY_LEFT, DANCE_BUTTON_LEFT, false }, { 0, JOY_RIGHT, DANCE_BUTTON_RIGHT, false }, { 0, JOY_UP, DANCE_BUTTON_UP, false }, { 0, JOY_DOWN, DANCE_BUTTON_DOWN, false }, { 1, JOY_BUTTON_1, DANCE_BUTTON_DOWN, false }, // A { 1, JOY_BUTTON_2, DANCE_BUTTON_RIGHT, false }, // B { 1, JOY_BUTTON_3, DANCE_BUTTON_LEFT, false }, // X { 1, JOY_BUTTON_4, DANCE_BUTTON_UP, false }, // Y { 0, JOY_BUTTON_7, DANCE_BUTTON_UPLEFT, false }, // L shoulder { 0, JOY_BUTTON_8, DANCE_BUTTON_UPRIGHT, false }, // R shoulder { 0, JOY_BUTTON_9, DANCE_BUTTON_START, false }, { 0, JOY_BUTTON_10, DANCE_BUTTON_BACK, false }, END_MARKER } }, { "dance", "0b43:0003", // The EMS USB2 doesn't provide a model string, so Linux // just gives us the VendorID and ModelID in hex. "EMS USB2", { // Player 1. { 0, JOY_BUTTON_16, DANCE_BUTTON_LEFT, false }, { 0, JOY_BUTTON_14, DANCE_BUTTON_RIGHT, false }, { 0, JOY_BUTTON_13, DANCE_BUTTON_UP, false }, { 0, JOY_BUTTON_15, DANCE_BUTTON_DOWN, false }, { 1, JOY_BUTTON_4, DANCE_BUTTON_LEFT, false }, { 1, JOY_BUTTON_2, DANCE_BUTTON_RIGHT, false }, { 1, JOY_BUTTON_1, DANCE_BUTTON_UP, false }, { 1, JOY_BUTTON_3, DANCE_BUTTON_DOWN, false }, { 0, JOY_BUTTON_7, DANCE_BUTTON_UPLEFT, false }, { 0, JOY_BUTTON_8, DANCE_BUTTON_UPRIGHT, false }, { 0, JOY_BUTTON_9, DANCE_BUTTON_SELECT, false }, { 0, JOY_BUTTON_10, DANCE_BUTTON_START, false }, { 0, JOY_BUTTON_5, DANCE_BUTTON_BACK, false }, { 0, JOY_BUTTON_6, DANCE_BUTTON_COIN, false }, // Player 2. { 0, JOY_BUTTON_32, DANCE_BUTTON_LEFT, true }, { 0, JOY_BUTTON_30, DANCE_BUTTON_RIGHT, true }, { 0, JOY_BUTTON_29, DANCE_BUTTON_UP, true }, { 0, JOY_BUTTON_31, DANCE_BUTTON_DOWN, true }, { 1, JOY_BUTTON_20, DANCE_BUTTON_LEFT, true }, { 1, JOY_BUTTON_18, DANCE_BUTTON_RIGHT, true }, { 1, JOY_BUTTON_17, DANCE_BUTTON_UP, true }, { 1, JOY_BUTTON_19, DANCE_BUTTON_DOWN, true }, { 0, JOY_BUTTON_23, DANCE_BUTTON_UPRIGHT, true }, { 0, JOY_BUTTON_24, DANCE_BUTTON_UPLEFT, true }, { 0, JOY_BUTTON_25, DANCE_BUTTON_SELECT, true }, { 0, JOY_BUTTON_26, DANCE_BUTTON_START, true }, { 0, JOY_BUTTON_21, DANCE_BUTTON_BACK, true }, { 0, JOY_BUTTON_22, DANCE_BUTTON_COIN, true }, END_MARKER } }, { "dance", "Dance ", //Notice extra space at end "LevelSix USB Pad (DDR638)", // "DDR638" is the model number of the pad { { 0, JOY_BUTTON_1, DANCE_BUTTON_UP, false }, { 0, JOY_BUTTON_2, DANCE_BUTTON_DOWN, false }, { 0, JOY_BUTTON_3, DANCE_BUTTON_LEFT, false }, { 0, JOY_BUTTON_4, DANCE_BUTTON_RIGHT, false }, { 0, JOY_BUTTON_7, DANCE_BUTTON_UPRIGHT, false }, { 0, JOY_BUTTON_8, DANCE_BUTTON_UPLEFT, false }, { 0, JOY_BUTTON_9, DANCE_BUTTON_BACK, false }, { 0, JOY_BUTTON_10, DANCE_BUTTON_START, false }, END_MARKER } }, { "dance", "SmartJoy PLUS Adapter", "SmartJoy PLUS Adapter", { { 0, JOY_LEFT, /* dpad L */ DANCE_BUTTON_LEFT, false }, { 0, JOY_RIGHT, /* dpad R */ DANCE_BUTTON_RIGHT, false }, { 0, JOY_UP, /* dpad U */ DANCE_BUTTON_UP, false }, { 0, JOY_DOWN, /* dpad D */ DANCE_BUTTON_DOWN, false }, { 1, JOY_BUTTON_4, /* Square */ DANCE_BUTTON_LEFT, false }, { 1, JOY_BUTTON_2, /* Circle */ DANCE_BUTTON_RIGHT, false }, { 1, JOY_BUTTON_1, /* Tri */ DANCE_BUTTON_UP, false }, { 1, JOY_BUTTON_3, /* X */ DANCE_BUTTON_DOWN, false }, { 0, JOY_BUTTON_7, /* L1 */ DANCE_BUTTON_UPLEFT, false }, { 0, JOY_BUTTON_8, /* R1 */ DANCE_BUTTON_UPRIGHT, false }, { 0, JOY_BUTTON_10, /* Select */ DANCE_BUTTON_BACK, false }, { 0, JOY_BUTTON_9, /* Start */ DANCE_BUTTON_START, false }, { 0, JOY_BUTTON_5, /* R1 */ DANCE_BUTTON_SELECT, false }, { 0, JOY_BUTTON_6, /* R2 */ DANCE_BUTTON_COIN, false }, END_MARKER } }, { "dance", "RedOctane USB Pad|XBOX DDR", // "RedOctane USB Pad" is Ignition 3s and newer Afterburners. "XBOX DDR" is older Afterburners. "RedOctane Ignition 3 or Afterburner", { { 0, JOY_BUTTON_1, /* dpad L */ DANCE_BUTTON_LEFT, false }, { 0, JOY_BUTTON_4, /* dpad R */ DANCE_BUTTON_RIGHT, false }, { 0, JOY_BUTTON_3, /* dpad U */ DANCE_BUTTON_UP, false }, { 0, JOY_BUTTON_2, /* dpad D */ DANCE_BUTTON_DOWN, false }, //{ 0, JOY_BUTTON_5, /* Tri */ DANCE_BUTTON_BACK, false }, //{ 0, JOY_BUTTON_6, /* Square */ DANCE_BUTTON_BACK, false }, //{ 1, JOY_BUTTON_7, /* X */ DANCE_BUTTON_START, false }, { 0, JOY_BUTTON_8, /* O */ DANCE_BUTTON_START, false }, { 1, JOY_BUTTON_9, /* Start */ DANCE_BUTTON_START, false }, { 0, JOY_BUTTON_10, /* Sel */ DANCE_BUTTON_BACK, false }, END_MARKER } }, { "dance", "Joypad to USB converter", "EMS Trio Linker", { { 0, JOY_BUTTON_16, /* dpad L */ DANCE_BUTTON_LEFT, false }, { 0, JOY_BUTTON_14, /* dpad R */ DANCE_BUTTON_RIGHT, false }, { 0, JOY_BUTTON_13, /* dpad U */ DANCE_BUTTON_UP, false }, { 0, JOY_BUTTON_15, /* dpad D */ DANCE_BUTTON_DOWN, false }, //{ 0, JOY_BUTTON_5, /* Tri */ DANCE_BUTTON_BACK, false }, //{ 0, JOY_BUTTON_6, /* Square */ DANCE_BUTTON_BACK, false }, //{ 1, JOY_BUTTON_7, /* X */ DANCE_BUTTON_START, false }, { 0, JOY_BUTTON_2, /* O */ DANCE_BUTTON_START, false }, { 1, JOY_BUTTON_10, /* Start */ DANCE_BUTTON_START, false }, { 0, JOY_BUTTON_9, /* Sel */ DANCE_BUTTON_BACK, false }, END_MARKER } }, { "dance", "Positive Gaming Impact USB pad", "Positive Gaming Impact USB pad", { { 0, JOY_BUTTON_1, /* dpad L */ DANCE_BUTTON_LEFT, false }, { 0, JOY_BUTTON_4, /* dpad R */ DANCE_BUTTON_RIGHT, false }, { 0, JOY_BUTTON_3, /* dpad U */ DANCE_BUTTON_UP, false }, { 0, JOY_BUTTON_2, /* dpad D */ DANCE_BUTTON_DOWN, false }, //{ 0, JOY_BUTTON_5, /* Tri */ DANCE_BUTTON_BACK, false }, //{ 0, JOY_BUTTON_6, /* Square */ DANCE_BUTTON_BACK, false }, //{ 1, JOY_BUTTON_7, /* X */ DANCE_BUTTON_START, false }, { 0, JOY_BUTTON_8, /* O */ DANCE_BUTTON_START, false }, { 1, JOY_BUTTON_9, /* Start */ DANCE_BUTTON_START, false }, { 0, JOY_BUTTON_10, /* Sel */ DANCE_BUTTON_BACK, false }, END_MARKER } }, { "pump", "Pump USB", "Pump USB pad", { { 0, JOY_BUTTON_1, PUMP_BUTTON_UPLEFT, false }, { 0, JOY_BUTTON_2, PUMP_BUTTON_UPRIGHT, false }, { 0, JOY_BUTTON_3, PUMP_BUTTON_CENTER, false }, { 0, JOY_BUTTON_4, PUMP_BUTTON_DOWNLEFT, false }, { 0, JOY_BUTTON_5, PUMP_BUTTON_DOWNRIGHT, false }, { 0, JOY_BUTTON_6, PUMP_BUTTON_BACK, false }, { 0, JOY_BUTTON_7, PUMP_BUTTON_UPLEFT, true }, { 0, JOY_BUTTON_8, PUMP_BUTTON_UPRIGHT, true }, { 0, JOY_BUTTON_9, PUMP_BUTTON_CENTER, true }, { 0, JOY_BUTTON_10, PUMP_BUTTON_DOWNLEFT, true }, { 0, JOY_BUTTON_11, PUMP_BUTTON_DOWNRIGHT, true }, END_MARKER } }, { "para", "ParaParaParadise Controller", "ParaParaParadise Controller", { { 0, JOY_BUTTON_5, PARA_BUTTON_LEFT, false }, { 0, JOY_BUTTON_4, PARA_BUTTON_UPLEFT, false }, { 0, JOY_BUTTON_3, PARA_BUTTON_UP, false }, { 0, JOY_BUTTON_2, PARA_BUTTON_UPRIGHT, false }, { 0, JOY_BUTTON_1, PARA_BUTTON_RIGHT, false }, { 0, JOY_BUTTON_10, PARA_BUTTON_START, false }, { 0, JOY_BUTTON_11, PARA_BUTTON_BACK, false }, { 0, JOY_BUTTON_12, PARA_BUTTON_MENULEFT, false }, { 0, JOY_BUTTON_9, PARA_BUTTON_MENURIGHT, false }, END_MARKER } }, { "techno", "Dance ", //Notice the extra space at end "LevelSix USB Pad (DDR638)", // "DDR638" is the model number of the pad { { 0, JOY_BUTTON_1, TECHNO_BUTTON_UP, false }, { 0, JOY_BUTTON_2, TECHNO_BUTTON_DOWN, false }, { 0, JOY_BUTTON_3, TECHNO_BUTTON_LEFT, false }, { 0, JOY_BUTTON_4, TECHNO_BUTTON_RIGHT, false }, { 0, JOY_BUTTON_5, TECHNO_BUTTON_DOWNRIGHT,false }, { 0, JOY_BUTTON_6, TECHNO_BUTTON_DOWNLEFT, false }, { 0, JOY_BUTTON_7, TECHNO_BUTTON_UPRIGHT, false }, { 0, JOY_BUTTON_8, TECHNO_BUTTON_UPLEFT, false }, { 0, JOY_BUTTON_9, TECHNO_BUTTON_BACK, false }, { 0, JOY_BUTTON_10, TECHNO_BUTTON_START, false }, END_MARKER } }, }; void InputMapper::Unmap( InputDevice id ) { for( int i=0; i= MAX_GAME_CONTROLLERS ) continue; } DeviceInput di( id, maps[k].deviceButton ); GameInput gi( map_gc, maps[k].gb ); SetInputMap( di, gi, maps[k].iSlotIndex ); } } void InputMapper::AutoMapJoysticksForCurrentGame() { vector vDevices; INPUTMAN->GetDevicesAndDescriptions(vDevices); int iNumJoysticksMapped = 0; const Game* pGame = GAMESTATE->m_pCurGame; for( unsigned i=0; iStringToGameType(mapping.szGame) ) continue; // games don't match RString sDriverRegex = mapping.szDriverRegex; Regex regex( sDriverRegex ); if( !regex.Compare(sDescription) ) continue; // driver names don't match // // We have a mapping for this joystick // GameController gc = (GameController)iNumJoysticksMapped; if( gc >= MAX_GAME_CONTROLLERS ) break; // stop mapping. We already mapped one device for each game controller. LOG->Info( "Applying default joystick mapping #%d for device '%s' (%s)", iNumJoysticksMapped+1, mapping.szDriverRegex, mapping.szControllerName ); Unmap( id ); ApplyMapping( mapping.maps, gc, id ); iNumJoysticksMapped++; } } } static const RString DEVICE_INPUT_SEPARATOR = ":"; // this isn't used in any key names void InputMapper::ReadMappingsFromDisk() { ASSERT( GAMEMAN != NULL ); ClearAllMappings(); IniFile ini; if( !ini.ReadFile( SpecialFiles::KEYMAPS_PATH ) ) LOG->Trace( "Couldn't open mapping file \"%s\": %s.", SpecialFiles::KEYMAPS_PATH.c_str(), ini.GetError().c_str() ); const Game *pGame = GAMESTATE->GetCurrentGame(); const XNode *Key = ini.GetChild( pGame->m_szName ); if( Key ) { FOREACH_CONST_Attr( Key, i ) { const RString &name = i->first; const RString &value = i->second; GameInput GameI; GameI.FromString( pGame, name ); vector sDeviceInputStrings; split( value, DEVICE_INPUT_SEPARATOR, sDeviceInputStrings, false ); for( unsigned i=0; iGetCurrentGame(); // erase the key so that we overwrite everything for this game ini.DeleteKey( pGame->m_szName ); // iterate over our input map and write all mappings to the ini file FOREACH_GameController( i ) { for( int j=0; jm_iButtonsPerController; j++ ) { GameInput GameI( i, (GameButton)j ); RString sNameString = GameI.ToString( pGame ); vector asValues; for( int slot = 0; slot < NUM_USER_GAME_TO_DEVICE_SLOTS; ++slot ) // don't save data from the last (keyboard automap) slot asValues.push_back( m_GItoDI[i][j][slot].ToString() ); while( asValues.size() && asValues.back() == "" ) asValues.erase( asValues.begin()+asValues.size()-1 ); RString sValueString = join( DEVICE_INPUT_SEPARATOR, asValues ); ini.SetValue( pGame->m_szName, sNameString, sValueString ); } } ini.WriteFile( SpecialFiles::KEYMAPS_PATH ); } static LocalizedString CONNECTED ( "InputMapper", "Connected" ); static LocalizedString DISCONNECTED ( "InputMapper", "Disconnected" ); static LocalizedString AUTOMAPPING_ALL_JOYSTICKS ( "InputMapper", "Auto-mapping all joysticks." ); bool InputMapper::CheckForChangedInputDevicesAndRemap( RString &sMessageOut ) { // Only check for changes in joysticks since that's all we know how to remap. // update last seen joysticks vector vDevices; INPUTMAN->GetDevicesAndDescriptions( vDevices ); // Strip non-joysticks. vector vsLastSeenJoysticks; split( g_sLastSeenInputDevices, ",", vsLastSeenJoysticks ); vector vsCurrent; vector vsCurrentJoysticks; for( int i=vDevices.size()-1; i>=0; i-- ) { vsCurrent.push_back( vDevices[i].sDesc ); if( IsJoystick(vDevices[i].id) ) { vsCurrentJoysticks.push_back( vDevices[i].sDesc ); } else { vector::iterator iter = find( vsLastSeenJoysticks.begin(), vsLastSeenJoysticks.end(), vDevices[i].sDesc ); if( iter != vsLastSeenJoysticks.end() ) vsLastSeenJoysticks.erase( iter ); } } bool bJoysticksChanged = vsCurrentJoysticks != vsLastSeenJoysticks; if( !bJoysticksChanged ) return false; vector vsConnects, vsDisconnects; GetConnectsDisconnects( vsLastSeenJoysticks, vsCurrentJoysticks, vsDisconnects, vsConnects ); sMessageOut = RString(); if( !vsConnects.empty() ) sMessageOut += CONNECTED.GetValue()+": " + join( "\n", vsConnects ) + "\n"; if( !vsDisconnects.empty() ) sMessageOut += DISCONNECTED.GetValue()+": " + join( "\n", vsDisconnects ) + "\n"; if( g_bAutoMapOnJoyChange ) { sMessageOut += AUTOMAPPING_ALL_JOYSTICKS.GetValue(); AutoMapJoysticksForCurrentGame(); SaveMappingsToDisk(); MESSAGEMAN->Broadcast( Message_AutoJoyMappingApplied ); } LOG->Info( sMessageOut ); g_sLastSeenInputDevices.Set( join(",",vsCurrent) ); PREFSMAN->SavePrefsToDisk(); return true; } void InputMapper::SetInputMap( const DeviceInput &DeviceI, const GameInput &GameI, int iSlotIndex ) { // remove the old input ClearFromInputMap( DeviceI ); ClearFromInputMap( GameI, iSlotIndex ); ASSERT_M( GameI.controller < MAX_GAME_CONTROLLERS, ssprintf("controller: %u >= %u", GameI.controller, MAX_GAME_CONTROLLERS) ); ASSERT_M( GameI.button < MAX_GAME_BUTTONS, ssprintf("button: %u >= %u", GameI.button, MAX_GAME_BUTTONS) ); ASSERT_M( iSlotIndex < NUM_GAME_TO_DEVICE_SLOTS, ssprintf("slot: %u >= %u", iSlotIndex, NUM_GAME_TO_DEVICE_SLOTS) ); m_GItoDI[GameI.controller][GameI.button][iSlotIndex] = DeviceI; UpdateTempDItoGI(); } void InputMapper::ClearFromInputMap( const DeviceInput &DeviceI ) { // search for where this DeviceI maps to for( int p=0; pGetCurrentStyle() ) return GAMESTATE->GetCurrentStyle()->ControllerToPlayerNumber(controller); else return (PlayerNumber) controller; } MenuButton InputMapper::GameToMenu( const GameInput &GameI ) { const Game* pGame = GAMESTATE->GetCurrentGame(); return pGame->GameInputToMenuButton( GameI ); } void InputMapper::MenuToGame( MenuButton MenuI, PlayerNumber pn, GameInput GameIout[4] ) { const Game* pGame = GAMESTATE->GetCurrentGame(); pGame->MenuButtonToGameInputs( MenuI, pn, GameIout ); } bool InputMapper::IsBeingPressed( const GameInput &GameI, MultiPlayer mp, const DeviceInputList *pButtonState ) { for( int i=0; iIsBeingPressed(DeviceI, pButtonState) ) return true; } } return false; } bool InputMapper::IsBeingPressed( MenuButton MenuI, PlayerNumber pn ) { GameInput GameI[4]; MenuToGame( MenuI, pn, GameI ); for( int i=0; i<4; i++ ) if( GameI[i].IsValid() && IsBeingPressed(GameI[i]) ) return true; return false; } void InputMapper::RepeatStopKey( const GameInput &GameI ) { for( int i=0; iRepeatStopKey( DeviceI ); } } void InputMapper::RepeatStopKey( MenuButton MenuI, PlayerNumber pn ) { GameInput GameI[4]; MenuToGame( MenuI, pn, GameI ); for( int i=0; i<4; i++ ) if( GameI[i].IsValid() ) RepeatStopKey( GameI[i] ); } float InputMapper::GetSecsHeld( const GameInput &GameI, MultiPlayer mp ) { float fMaxSecsHeld = 0; for( int i=0; iGetSecsHeld(DeviceI) ); } } return fMaxSecsHeld; } float InputMapper::GetSecsHeld( MenuButton MenuI, PlayerNumber pn ) { float fMaxSecsHeld = 0; GameInput GameI[4]; MenuToGame( MenuI, pn, GameI ); for( int i=0; i<4; i++ ) if( GameI[i].IsValid() ) fMaxSecsHeld = max( fMaxSecsHeld, GetSecsHeld(GameI[i]) ); return fMaxSecsHeld; } void InputMapper::ResetKeyRepeat( const GameInput &GameI ) { for( int i=0; iResetKeyRepeat( DeviceI ); } } void InputMapper::ResetKeyRepeat( MenuButton MenuI, PlayerNumber pn ) { GameInput GameI[4]; MenuToGame( MenuI, pn, GameI ); for( int i=0; i<4; i++ ) if( GameI[i].IsValid() ) ResetKeyRepeat( GameI[i] ); } InputDevice InputMapper::MultiPlayerToInputDevice( MultiPlayer mp ) { if( mp == MultiPlayer_INVALID ) return DEVICE_NONE; return enum_add2( DEVICE_JOY1, mp ); } MultiPlayer InputMapper::InputDeviceToMultiPlayer( InputDevice id ) { if( id == DEVICE_NONE ) return MultiPlayer_INVALID; return enum_add2( MultiPlayer_1, id - DEVICE_JOY1 ); } /* * (c) 2001-2003 Chris Danford * 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. */