mirror of
https://github.com/DaedalusX64/daedalus.git
synced 2025-04-02 10:21:48 -04:00
366 lines
9.9 KiB
C++
366 lines
9.9 KiB
C++
/*
|
|
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 <SDL2/SDL.h>
|
|
|
|
#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 <iostream>
|
|
#include <Windows.h>
|
|
#include <Xinput.h>
|
|
|
|
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<IInputManager>();
|
|
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;
|
|
}
|