diff --git a/stepmania/src/GameLoop.cpp b/stepmania/src/GameLoop.cpp index 7c1c795d9c..6f22bac359 100644 --- a/stepmania/src/GameLoop.cpp +++ b/stepmania/src/GameLoop.cpp @@ -19,6 +19,7 @@ #include "LightsManager.h" #include "NetworkSyncManager.h" #include "RageTimer.h" +#include "RageInput.h" #include "StepMania.h" @@ -97,6 +98,13 @@ void GameLoop() /* Important: Process input AFTER updating game logic, or input will be acting on song beat from last frame */ HandleInputEvents( fDeltaTime ); + if( INPUTMAN->DevicesChanged() ) + { + SAFE_DELETE( INPUTMAN ); + INPUTMAN = new RageInput( PREFSMAN->GetInputDrivers() ); + StepMania::CheckForChangedInputDevicesAndRemap(); + } + LIGHTSMAN->Update( fDeltaTime ); /* diff --git a/stepmania/src/RageInput.cpp b/stepmania/src/RageInput.cpp index 7f973e2c7e..f471b760bc 100644 --- a/stepmania/src/RageInput.cpp +++ b/stepmania/src/RageInput.cpp @@ -34,6 +34,17 @@ void RageInput::Update( float fDeltaTime ) m_pDevices[i]->Update( fDeltaTime ); } +bool RageInput::DevicesChanged() +{ + /* Update optional devices. */ + for( unsigned i = 0; i < m_pDevices.size(); ++i ) + { + if( m_pDevices[i]->DevicesChanged() ) + return true; + } + return false; +} + void RageInput::GetDevicesAndDescriptions( vector& vDevicesOut, vector& vDescriptionsOut ) { for( unsigned i = 0; i < m_pDevices.size(); ++i ) diff --git a/stepmania/src/RageInput.h b/stepmania/src/RageInput.h index 3c5fa55a0d..6a06fd8038 100644 --- a/stepmania/src/RageInput.h +++ b/stepmania/src/RageInput.h @@ -15,6 +15,7 @@ public: ~RageInput(); void Update( float fDeltaTime ); + bool DevicesChanged(); void GetDevicesAndDescriptions( vector& vDevicesOut, vector& vsDescriptionsOut ); void WindowReset(); void AddHandler( InputHandler *pHandler ); diff --git a/stepmania/src/StepMania.cpp b/stepmania/src/StepMania.cpp index 616da58ba9..23de24dc69 100644 --- a/stepmania/src/StepMania.cpp +++ b/stepmania/src/StepMania.cpp @@ -289,6 +289,13 @@ void StepMania::ResetGame() TEXTUREMAN->DoDelayedDelete(); } + PREFSMAN->SavePrefsToDisk(); + + CheckForChangedInputDevicesAndRemap(); +} + +void StepMania::CheckForChangedInputDevicesAndRemap() +{ // // update last seen joysticks // @@ -299,22 +306,27 @@ void StepMania::ResetGame() if( PREFSMAN->m_sLastSeenInputDevices.Get() != sInputDevices ) { - LOG->Info( "Input devices changed from '%s' to '%s'.", PREFSMAN->m_sLastSeenInputDevices.Get().c_str(), sInputDevices.c_str() ); + CString sMessage = ssprintf( + "Input devices changed from '%s' to '%s'.", + PREFSMAN->m_sLastSeenInputDevices.Get().c_str(), + sInputDevices.c_str() ); if( PREFSMAN->m_bAutoMapOnJoyChange ) { - LOG->Info( "Remapping joysticks." ); + sMessage += "\nRemapping joysticks."; INPUTMAPPER->AutoMapJoysticksForCurrentGame(); INPUTMAPPER->SaveMappingsToDisk(); } + LOG->Info( sMessage ); + SCREENMAN->SystemMessage( sMessage ); + PREFSMAN->m_sLastSeenInputDevices.Set( sInputDevices ); } PREFSMAN->SavePrefsToDisk(); } - static bool ChangeAppPri() { if( PREFSMAN->m_BoostAppPriority.Get() == PrefsManager::BOOST_NO ) @@ -1100,6 +1112,8 @@ int main(int argc, char* argv[]) * dependencies on the SDL video subsystem, so it must be initialized after DISPLAY. */ INPUTMAN = new RageInput( PREFSMAN->GetInputDrivers() ); + StepMania::CheckForChangedInputDevicesAndRemap(); + // These things depend on the TextureManager, so do them after! FONT = new FontManager; SCREENMAN = new ScreenManager; diff --git a/stepmania/src/StepMania.h b/stepmania/src/StepMania.h index 25ab7572a0..07a28a9db0 100644 --- a/stepmania/src/StepMania.h +++ b/stepmania/src/StepMania.h @@ -16,6 +16,7 @@ namespace StepMania void ApplyGraphicOptions(); void NORETURN HandleException( CString error ); void ResetGame(); + void CheckForChangedInputDevicesAndRemap(); void ChangeCurrentGame( const Game* g ); void FocusChanged( bool bHasFocus ); bool AppHasFocus(); diff --git a/stepmania/src/arch/InputHandler/InputHandler.h b/stepmania/src/arch/InputHandler/InputHandler.h index c4ea4eed9a..22b0c9850c 100644 --- a/stepmania/src/arch/InputHandler/InputHandler.h +++ b/stepmania/src/arch/InputHandler/InputHandler.h @@ -28,6 +28,7 @@ public: InputHandler() { m_iInputsSinceUpdate = 0; } virtual ~InputHandler() { } virtual void Update( float fDeltaTime ) { } + virtual bool DevicesChanged() { return false; } virtual void GetDevicesAndDescriptions( vector& vDevicesOut, vector& vDescriptionsOut ) = 0; // Override to return a pretty string that's specific to the controller type. diff --git a/stepmania/src/arch/InputHandler/InputHandler_DirectInput.cpp b/stepmania/src/arch/InputHandler/InputHandler_DirectInput.cpp index ad68d327ab..53e8e55186 100644 --- a/stepmania/src/arch/InputHandler/InputHandler_DirectInput.cpp +++ b/stepmania/src/arch/InputHandler/InputHandler_DirectInput.cpp @@ -73,6 +73,7 @@ InputHandler_DInput::InputHandler_DInput() CheckForDirectInputDebugMode(); shutdown = false; + m_bDevicesChanged = false; g_NumJoysticks = 0; AppInstance inst; @@ -227,108 +228,116 @@ HRESULT GetDeviceState(LPDIRECTINPUTDEVICE2 dev, int size, void *ptr) * it out. Be sure to call InputHandler::Update() between each poll. */ void InputHandler_DInput::UpdatePolled(DIDevice &device, const RageTimer &tm) { - if( device.type == device.KEYBOARD ) + switch( device.type ) { - unsigned char keys[256]; - - HRESULT hr = GetDeviceState(device.Device, 256, keys); - if ( hr == DIERR_INPUTLOST || hr == DIERR_NOTACQUIRED ) - return; - - if ( hr != DI_OK ) + default: + ASSERT(0); + case device.KEYBOARD: { - LOG->MapLog( "UpdatePolled", hr_ssprintf(hr, "Failures on polled keyboard update") ); - return; - } + unsigned char keys[256]; - for( int k = 0; k < 256; ++k ) - { - const int key = device.Inputs[k].num; - ButtonPressed(DeviceInput(device.dev, key), !!(keys[k] & 0x80)); - } - return; - } + HRESULT hr = GetDeviceState(device.Device, 256, keys); + if ( hr == DIERR_INPUTLOST || hr == DIERR_NOTACQUIRED ) + return; - DIJOYSTATE state; - - HRESULT hr = GetDeviceState(device.Device, sizeof(state), &state); - if ( hr == DIERR_INPUTLOST || hr == DIERR_NOTACQUIRED ) - return; - - /* Set each known axis, button and POV. */ - for(unsigned i = 0; i < device.Inputs.size(); ++i) - { - const input_t &in = device.Inputs[i]; - const InputDevice dev = device.dev; - - switch(in.type) - { - case in.BUTTON: - { - DeviceInput di(dev, JOY_BUTTON_1 + in.num, -1, tm); - ButtonPressed(di, !!state.rgbButtons[in.ofs - DIJOFS_BUTTON0]); - break; - } - - case in.AXIS: - { - JoystickButton neg = NUM_JOYSTICK_BUTTONS, pos = NUM_JOYSTICK_BUTTONS; - int val = 0; - switch(in.ofs) + if ( hr != DI_OK ) { - case DIJOFS_X: neg = JOY_LEFT; pos = JOY_RIGHT; - val = state.lX; - break; - case DIJOFS_Y: neg = JOY_UP; pos = JOY_DOWN; - val = state.lY; - break; - case DIJOFS_Z: neg = JOY_Z_UP; pos = JOY_Z_DOWN; - val = state.lZ; - break; - case DIJOFS_RX: neg = JOY_ROT_LEFT; pos = JOY_ROT_RIGHT; - val = state.lRx; - break; - case DIJOFS_RY: neg = JOY_ROT_UP; pos = JOY_ROT_DOWN; - val = state.lRy; - break; - case DIJOFS_RZ: neg = JOY_ROT_Z_UP; pos = JOY_ROT_Z_DOWN; - val = state.lRz; - break; - case DIJOFS_SLIDER(0): - neg = JOY_AUX_1; pos = JOY_AUX_2; - val = state.rglSlider[0]; - break; - case DIJOFS_SLIDER(1): - neg = JOY_AUX_3; pos = JOY_AUX_4; - val = state.rglSlider[1]; - break; - default: LOG->MapLog("unknown input", - "Controller '%s' is returning an unknown joystick offset, %i", - device.JoystickInst.tszProductName, in.ofs ); - continue; - } - if( neg != NUM_JOYSTICK_BUTTONS ) - { - float l = SCALE( int(val), 0.0f, 100.0f, 0.0f, 1.0f ); - ButtonPressed(DeviceInput(dev, neg, max(-l,0), tm), val < -50); - ButtonPressed(DeviceInput(dev, pos, max(+l,0), tm), val > 50); + LOG->MapLog( "UpdatePolled", hr_ssprintf(hr, "Failures on polled keyboard update") ); + return; } - break; - } - - case in.HAT: - if( in.num == 0 ) + for( int k = 0; k < 256; ++k ) { - const int pos = TranslatePOV(state.rgdwPOV[in.ofs - DIJOFS_POV(0)]); - ButtonPressed(DeviceInput(dev, JOY_HAT_UP, -1, tm), !!(pos & HAT_UP_MASK)); - ButtonPressed(DeviceInput(dev, JOY_HAT_DOWN, -1, tm), !!(pos & HAT_DOWN_MASK)); - ButtonPressed(DeviceInput(dev, JOY_HAT_LEFT, -1, tm), !!(pos & HAT_LEFT_MASK)); - ButtonPressed(DeviceInput(dev, JOY_HAT_RIGHT, -1, tm), !!(pos & HAT_RIGHT_MASK)); + const int key = device.Inputs[k].num; + ButtonPressed(DeviceInput(device.dev, key), !!(keys[k] & 0x80)); } - - break; } + break; + case device.JOYSTICK: + { + DIJOYSTATE state; + + HRESULT hr = GetDeviceState(device.Device, sizeof(state), &state); + if ( hr == DIERR_INPUTLOST || hr == DIERR_NOTACQUIRED ) + return; + + /* Set each known axis, button and POV. */ + for(unsigned i = 0; i < device.Inputs.size(); ++i) + { + const input_t &in = device.Inputs[i]; + const InputDevice dev = device.dev; + + switch(in.type) + { + case in.BUTTON: + { + DeviceInput di(dev, JOY_BUTTON_1 + in.num, -1, tm); + ButtonPressed(di, !!state.rgbButtons[in.ofs - DIJOFS_BUTTON0]); + break; + } + + case in.AXIS: + { + JoystickButton neg = NUM_JOYSTICK_BUTTONS, pos = NUM_JOYSTICK_BUTTONS; + int val = 0; + switch(in.ofs) + { + case DIJOFS_X: neg = JOY_LEFT; pos = JOY_RIGHT; + val = state.lX; + break; + case DIJOFS_Y: neg = JOY_UP; pos = JOY_DOWN; + val = state.lY; + break; + case DIJOFS_Z: neg = JOY_Z_UP; pos = JOY_Z_DOWN; + val = state.lZ; + break; + case DIJOFS_RX: neg = JOY_ROT_LEFT; pos = JOY_ROT_RIGHT; + val = state.lRx; + break; + case DIJOFS_RY: neg = JOY_ROT_UP; pos = JOY_ROT_DOWN; + val = state.lRy; + break; + case DIJOFS_RZ: neg = JOY_ROT_Z_UP; pos = JOY_ROT_Z_DOWN; + val = state.lRz; + break; + case DIJOFS_SLIDER(0): + neg = JOY_AUX_1; pos = JOY_AUX_2; + val = state.rglSlider[0]; + break; + case DIJOFS_SLIDER(1): + neg = JOY_AUX_3; pos = JOY_AUX_4; + val = state.rglSlider[1]; + break; + default: LOG->MapLog("unknown input", + "Controller '%s' is returning an unknown joystick offset, %i", + device.JoystickInst.tszProductName, in.ofs ); + continue; + } + if( neg != NUM_JOYSTICK_BUTTONS ) + { + float l = SCALE( int(val), 0.0f, 100.0f, 0.0f, 1.0f ); + ButtonPressed(DeviceInput(dev, neg, max(-l,0), tm), val < -50); + ButtonPressed(DeviceInput(dev, pos, max(+l,0), tm), val > 50); + } + + break; + } + + case in.HAT: + if( in.num == 0 ) + { + const int pos = TranslatePOV(state.rgdwPOV[in.ofs - DIJOFS_POV(0)]); + ButtonPressed(DeviceInput(dev, JOY_HAT_UP, -1, tm), !!(pos & HAT_UP_MASK)); + ButtonPressed(DeviceInput(dev, JOY_HAT_DOWN, -1, tm), !!(pos & HAT_DOWN_MASK)); + ButtonPressed(DeviceInput(dev, JOY_HAT_LEFT, -1, tm), !!(pos & HAT_LEFT_MASK)); + ButtonPressed(DeviceInput(dev, JOY_HAT_RIGHT, -1, tm), !!(pos & HAT_RIGHT_MASK)); + } + + break; + } + } + } + break; } } @@ -430,7 +439,7 @@ void InputHandler_DInput::PollAndAcquireDevices() } } -void InputHandler_DInput::Update(float fDeltaTime) +void InputHandler_DInput::Update( float fDeltaTime ) { RageTimer zero; zero.SetZero(); @@ -451,6 +460,10 @@ void InputHandler_DInput::Update(float fDeltaTime) InputHandler::UpdateTimer(); } +bool InputHandler_DInput::DevicesChanged() +{ + return m_bDevicesChanged; +} void InputHandler_DInput::InputThreadMain() { diff --git a/stepmania/src/arch/InputHandler/InputHandler_DirectInput.h b/stepmania/src/arch/InputHandler/InputHandler_DirectInput.h index 3172ce6fcc..a9eca8c320 100644 --- a/stepmania/src/arch/InputHandler/InputHandler_DirectInput.h +++ b/stepmania/src/arch/InputHandler/InputHandler_DirectInput.h @@ -12,11 +12,13 @@ public: ~InputHandler_DInput(); void GetDevicesAndDescriptions( vector& vDevicesOut, vector& vDescriptionsOut ); void Update( float fDeltaTime ); + bool DevicesChanged(); void WindowReset(); private: RageThread InputThread; bool shutdown; + bool m_bDevicesChanged; void UpdatePolled( DIDevice &device, const RageTimer &tm ); void UpdateBuffered( DIDevice &device, const RageTimer &tm );