/* Copyright (C) 2012 StrmnNrmn This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include "BuildOptions.h" #include "Base/Types.h" #include "Input/InputManager.h" #include "Core/CPU.h" #include "SysGL/GL.h" //Windows Xinput support #ifdef DAEDALUS_WIN32 #include #include #include class CXBOXController { private: XINPUT_STATE _controllerState; int _controllerNum; public: CXBOXController(int playerNumber); XINPUT_STATE GetState(); bool IsConnected(); void Vibrate(int leftVal = 0, int rightVal = 0); }; CXBOXController::CXBOXController(int playerNumber) { // Set the Controller Number _controllerNum = playerNumber - 1; } XINPUT_STATE CXBOXController::GetState() { // Zeroise the state ZeroMemory(&_controllerState, sizeof(XINPUT_STATE)); // Get the state XInputGetState(_controllerNum, &_controllerState); return _controllerState; } bool CXBOXController::IsConnected() { // Zeroise the state ZeroMemory(&_controllerState, sizeof(XINPUT_STATE)); // Get the state DWORD Result = XInputGetState(_controllerNum, &_controllerState); if (Result == ERROR_SUCCESS) { return true; } else { return false; } } void CXBOXController::Vibrate(int leftVal, int rightVal) { // Create a Vibraton State XINPUT_VIBRATION Vibration; // Zeroise the Vibration ZeroMemory(&Vibration, sizeof(XINPUT_VIBRATION)); // Set the Vibration Values Vibration.wLeftMotorSpeed = leftVal; Vibration.wRightMotorSpeed = rightVal; // Vibrate the controller XInputSetState(_controllerNum, &Vibration); } #endif //TODO: Implement gamepad support with SDL //#define GAMEPAD_SUPPORT class IInputManager : public CInputManager { public: IInputManager(); virtual ~IInputManager(); virtual bool Initialise(); virtual void Finalise(); virtual void GetState( OSContPad pPad[4] ); virtual u32 GetNumConfigurations() const; virtual const char * GetConfigurationName( u32 configuration_idx ) const; virtual const char * GetConfigurationDescription( u32 configuration_idx ) const; virtual void SetConfiguration( u32 configuration_idx ); virtual u32 GetConfigurationFromName( const char * name ) const; #ifdef GAMEPAD_SUPPORT void GetGamePadStatus(); private: void GetJoyPad(OSContPad *pPad); bool mGamePadAvailable; #endif #ifdef DAEDALUS_WIN32 CXBOXController* Player1; CXBOXController* Player2; CXBOXController* Player3; CXBOXController* Player4; #endif }; IInputManager::~IInputManager() { } IInputManager::IInputManager() #ifdef GAMEPAD_SUPPORT : mGamePadAvailable(false) #endif { } #ifdef GAMEPAD_SUPPORT static void CheckPadStatusVblHandler( void * arg ) { IInputManager * manager = static_cast< IInputManager * >( arg ); // Only check the pad status every 60 vbls, otherwise it's too expensive. static u32 count = 0; if ((count % 60) == 0) { manager->GetGamePadStatus(); } ++count; } #endif bool IInputManager::Initialise() { #ifdef DAEDALUS_WIN32 Player1 = new CXBOXController(1); if (Player1->IsConnected()){ std::cout << "Xinput device detected! "; } else{ std::cout << "Xinput device not detected!"; } #endif #ifdef GAMEPAD_SUPPORT CPU_RegisterVblCallback( &CheckPadStatusVblHandler, this ); #endif return true; } void IInputManager::Finalise() { #ifdef GAMEPAD_SUPPORT CPU_UnregisterVblCallback( &CheckPadStatusVblHandler, this ); #endif } #ifdef GAMEPAD_SUPPORT void IInputManager::GetGamePadStatus() { mGamePadAvailable = glfwJoystickPresent(GLFW_JOYSTICK_1) ? true : false; } void InputManager::GetJoyPad(OSContPad *pPad) { static const s32 N64_ANALOGUE_STICK_RANGE = 80; int num_axes; const float * axes = glfwGetJoystickAxes(GLFW_JOYSTICK_1, &num_axes); if(!axes || num_axes < 2) { // gamepad was disconnected? DAEDALUS_ERROR("Couldn't read axes"); return; } int num_buttons; const u8 * buttons = glfwGetJoystickButtons(GLFW_JOYSTICK_1, &num_buttons); if(!buttons || num_buttons < 24) { // gamepad was disconnected? DAEDALUS_ERROR("Couldn't read buttons"); return; } //ToDo: Different gamepads will need different configuration, this is for PS3/PS2 controller if (buttons[11]) pPad->button |= START_BUTTON; if (buttons[9]) pPad->button |= START_BUTTON; if (buttons[2]) pPad->button |= A_BUTTON; if (buttons[3]) pPad->button |= B_BUTTON; if (buttons[6]) pPad->button |= Z_TRIG; if (buttons[4]) pPad->button |= L_TRIG; if (buttons[5]) pPad->button |= R_TRIG; if (buttons[20]) pPad->button |= U_JPAD; if (buttons[22]) pPad->button |= D_JPAD; if (buttons[23]) pPad->button |= L_JPAD; if (buttons[21]) pPad->button |= R_JPAD; // Hold O button and use hat buttons for N64 c buttons (same as the PSP) // We could use the second analog stick to map them, but will require to translate asix >=2 if(buttons[1]) { if (buttons[20]) pPad->button |= U_CBUTTONS; if (buttons[22]) pPad->button |= D_CBUTTONS; if (buttons[23]) pPad->button |= L_CBUTTONS; if (buttons[21]) pPad->button |= R_CBUTTONS; } // Used to see key presses, useful to add a different button configuration //for(int i = 0; i < num_buttons; i++) //{ // if(buttons[i]) // printf("%d\n",i); //} pPad->stick_x = s8(axes[0] * N64_ANALOGUE_STICK_RANGE); pPad->stick_y = s8(axes[1] * N64_ANALOGUE_STICK_RANGE); } #endif void IInputManager::GetState( OSContPad pPad[4] ) { // Clear the initial state for(u32 cont = 0; cont < 4; cont++) { pPad[cont].button = 0; pPad[cont].stick_x = 0; pPad[cont].stick_y = 0; } if(SDL_Window* window = gWindow) { const u8* keys = SDL_GetKeyboardState( NULL ); if (keys [ SDL_SCANCODE_UP ] ) {pPad[0].stick_y = +80;} if (keys [ SDL_SCANCODE_DOWN ] ) {pPad[0].stick_y = -80;} if (keys [ SDL_SCANCODE_LEFT ] ) {pPad[0].stick_x = -80;} if (keys [ SDL_SCANCODE_RIGHT ] ) {pPad[0].stick_x = +80;} if (keys [ SDL_SCANCODE_X ] ) {pPad[0].button |= A_BUTTON;} if (keys [ SDL_SCANCODE_C ] ) {pPad[0].button |= B_BUTTON;} if (keys [ SDL_SCANCODE_Z ] ) {pPad[0].button |= Z_TRIG;} if (keys [ SDL_SCANCODE_A ] ) {pPad[0].button |= L_TRIG;} if (keys [ SDL_SCANCODE_S ] ) {pPad[0].button |= R_TRIG;} if (keys [ SDL_SCANCODE_RETURN ] ) {pPad[0].button |= START_BUTTON;} if (keys [ SDL_SCANCODE_KP_8 ] ){ pPad[0].button |= U_JPAD;} if (keys [ SDL_SCANCODE_KP_2 ] ){ pPad[0].button |= D_JPAD;} if (keys [ SDL_SCANCODE_KP_4 ] ){ pPad[0].button |= L_JPAD;} if (keys [ SDL_SCANCODE_KP_6 ] ){ pPad[0].button |= R_JPAD;} if (keys [ SDL_SCANCODE_HOME ] ){ pPad[0].button |= U_CBUTTONS;} if (keys [ SDL_SCANCODE_END ] ){ pPad[0].button |= D_CBUTTONS;} if (keys [ SDL_SCANCODE_DELETE ] ){ pPad[0].button |= L_CBUTTONS;} if (keys [ SDL_SCANCODE_PAGEDOWN ] ){ pPad[0].button |= R_CBUTTONS;} } #ifdef DAEDALUS_WIN32 if (Player1->IsConnected()) { #define XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE 7849 #define XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE 8689 if (Player1->GetState().Gamepad.wButtons & XINPUT_GAMEPAD_A){ pPad[0].button |= A_BUTTON;} if (Player1->GetState().Gamepad.wButtons & XINPUT_GAMEPAD_B){ pPad[0].button |= B_BUTTON;} if (Player1->GetState().Gamepad.wButtons & XINPUT_GAMEPAD_START) { pPad[0].button |= START_BUTTON; } if (Player1->GetState().Gamepad.wButtons & XINPUT_GAMEPAD_LEFT_SHOULDER) { pPad[0].button |= L_TRIG; } if (Player1->GetState().Gamepad.wButtons & XINPUT_GAMEPAD_RIGHT_SHOULDER) { pPad[0].button |= R_TRIG; } if (Player1->GetState().Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_LEFT) { pPad[0].button |= L_JPAD; } if (Player1->GetState().Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_RIGHT) { pPad[0].button |= R_JPAD; } if (Player1->GetState().Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_UP) { pPad[0].button |= U_JPAD; } if (Player1->GetState().Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_DOWN) { pPad[0].button |= D_JPAD; } if (Player1->GetState().Gamepad.bLeftTrigger > 30) { pPad[0].button |= Z_TRIG; } if (Player1->GetState().Gamepad.bRightTrigger > 30 ) { pPad[0].button |= Z_TRIG; } pPad[0].stick_x = s8(Player1->GetState().Gamepad.sThumbLX / 500); pPad[0].stick_y = s8(Player1->GetState().Gamepad.sThumbLY / 500); //Xinput Righstick to C buttons if (s8(Player1->GetState().Gamepad.sThumbRX / 500 ) < -40) pPad[0].button |= L_CBUTTONS; if (s8(Player1->GetState().Gamepad.sThumbRX / 500 ) > 40) pPad[0].button |= R_CBUTTONS; if (s8(Player1->GetState().Gamepad.sThumbRY / 500 ) < -40) pPad[0].button |= D_CBUTTONS; if (s8(Player1->GetState().Gamepad.sThumbRY / 500 ) > 40) pPad[0].button |= U_CBUTTONS; } #endif #ifdef GAMEPAD_SUPPORT // Override the keyboard with the gamepad if it's available. if(mGamePadAvailable) { GetJoyPad(&pPad[0]); } #endif } template<> bool CSingleton< CInputManager >::Create() { DAEDALUS_ASSERT_Q(mpInstance == NULL); mpInstance = std::make_unique(); return mpInstance->Initialise(); } u32 IInputManager::GetNumConfigurations() const { return 0; } const char * IInputManager::GetConfigurationName( u32 configuration_idx ) const { DAEDALUS_ERROR( "Invalid controller config" ); return "?"; } const char * IInputManager::GetConfigurationDescription( u32 configuration_idx ) const { DAEDALUS_ERROR( "Invalid controller config" ); return "?"; } void IInputManager::SetConfiguration( u32 configuration_idx ) { DAEDALUS_ERROR( "Invalid controller config" ); } u32 IInputManager::GetConfigurationFromName( const char * name ) const { // Return the default controller config return 0; }