Files
FC1/CryInput/XGamepad.cpp
romkazvo 34d6c5d489 123
2023-08-07 19:29:24 +08:00

549 lines
14 KiB
C++

#include "stdafx.h"
#include "Input.h"
#include <ILog.h>
#include <Xtl.h>
#include "XGamepad.h"
namespace{
const DWORD g_dwNumToPort[] = {XDEVICE_PORT0, XDEVICE_PORT1, XDEVICE_PORT2, XDEVICE_PORT3};
}
#define NumToPort(X) g_dwNumToPort[X]
CXGamepad::CXGamepad()
{
memset(m_hGamepads, NULL, sizeof(HANDLE) * MAX_XBOX_CONTROLLERS);
memset(m_xbStatus, NULL, sizeof(XINPUT_STATE) * MAX_XBOX_CONTROLLERS);
memset(m_xbLastStatus, NULL, sizeof(XINPUT_STATE) * MAX_XBOX_CONTROLLERS);
//memset(m_bKeys, false, sizeof(bool) * 256);
//m_hDebugKeyboard = NULL;
m_bExponentialStick = true;
m_fLX = m_fLY = m_fRX = m_fRY = 0.0f;
}
CXGamepad::~CXGamepad()
{
ShutDown();
}
bool CXGamepad::Init(ILog *pLog)
{
XDEVICE_PREALLOC_TYPE sDeviceTypes[] =
{
{ XDEVICE_TYPE_GAMEPAD, MAX_XBOX_CONTROLLERS },
#ifdef DEBUG_KEYBOARD
{ XDEVICE_TYPE_DEBUG_KEYBOARD, 1 },
#endif //DEBUG_KEYBOARD
};
// Initialize all four gamepads and the debug keyboard
XInitDevices(sizeof(sDeviceTypes) / sizeof(XDEVICE_PREALLOC_TYPE), sDeviceTypes);
return true;
}
void CXGamepad::ShutDown()
{
unsigned int i;
// Close all opened gamepad handles
for (i=0; i<sizeof(m_hGamepads) / sizeof(HANDLE); i++)
{
if (m_hGamepads[i])
XInputClose(m_hGamepads[i]);
}
}
void CXGamepad::Update()
{
BOOL bReturn;
DWORD dwInsertions = 0, dwRemovals = 0;
unsigned int i;
#ifdef _DEBUG
char szBuffer[10024 /*256*/];
#endif
DWORD dwReturn;
// Query controller changes
bReturn = XGetDeviceChanges(XDEVICE_TYPE_GAMEPAD, &dwInsertions, &dwRemovals);
// Detect controler insertion
for (i=0; i<MAX_XBOX_CONTROLLERS; i++)
{
if (dwInsertions & (1 << i))
{
// A controller was inserted
#ifdef _DEBUG
sprintf(szBuffer, "INPUT: Controller %i inserted\n", i);
OutputDebugString(szBuffer);
#endif
// Open the device on the port
m_hGamepads[i] = XInputOpen(XDEVICE_TYPE_GAMEPAD, NumToPort(i), XDEVICE_NO_SLOT, NULL);
#ifdef _DEBUG
if (m_hGamepads[i] != NULL)
{
sprintf(szBuffer, "INPUT: Controller %i successfully opened\n", i);
OutputDebugString(szBuffer);
}
else
{
sprintf(szBuffer, "INPUT: ERROR: Can't open controller %i\n", i);
OutputDebugString(szBuffer);
}
#endif
}
}
// Detect controller removal
for (i=0; i<MAX_XBOX_CONTROLLERS; i++)
{
if (dwRemovals & (1 << i))
{
// A controller was removed
#ifdef _DEBUG
sprintf(szBuffer, "INPUT: Controller %i removed\n", i);
OutputDebugString(szBuffer);
#endif
// Close the controller
XInputClose(m_hGamepads[i]);
m_hGamepads[i] = NULL;
}
}
// Retrieve the state
for (i=0; i<MAX_XBOX_CONTROLLERS; i++)
{
if (IsControllerReady(i))
{
// Save the old state
m_xbLastStatus[i] = m_xbStatus[i];
// Get the new one
dwReturn = XInputGetState(m_hGamepads[i], &m_xbStatus[i]);
#ifdef _DEBUG
if (dwReturn == ERROR_DEVICE_NOT_CONNECTED)
{
sprintf(szBuffer, "INPUT: Can't get state of controller %i because it was" \
" removed and the removal has not been handled yet\n", i);
OutputDebugString(szBuffer);
}
else if (dwReturn != ERROR_SUCCESS)
{
sprintf(szBuffer, "INPUT: ERROR: Can't get state of controller %i" \
", error %i\n", i, dwReturn);
OutputDebugString(szBuffer);
}
/*
if (m_xbLastStatus[i].dwPacketNumber != m_xbStatus[i].dwPacketNumber)
{
//ASH: get rid of this.
sprintf(szBuffer, "packet: %d\n"
"got input: controller - %d\n"
"up: %d, down: %d, left: %d, right: %d\n"
"start: %d, back: %d, left thumb: %d, right thumb: %d\n"
"a: %d, b: %d, x: %d, y: %d, black: %d, white: %d\n"
"left trigger: %d, right trigger: %d\n"
"LX: %d, LY: %d, RX: %d, RY: %d\n",
(int) (m_xbStatus[i].dwPacketNumber),
i,
(int) (m_xbStatus[i].Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_UP),
(int) (m_xbStatus[i].Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_DOWN),
(int) (m_xbStatus[i].Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_LEFT),
(int) (m_xbStatus[i].Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_RIGHT),
(int) (m_xbStatus[i].Gamepad.wButtons & XINPUT_GAMEPAD_START),
(int) (m_xbStatus[i].Gamepad.wButtons & XINPUT_GAMEPAD_BACK),
(int) (m_xbStatus[i].Gamepad.wButtons & XINPUT_GAMEPAD_LEFT_THUMB),
(int) (m_xbStatus[i].Gamepad.wButtons & XINPUT_GAMEPAD_RIGHT_THUMB),
(int) (m_xbStatus[i].Gamepad.bAnalogButtons[XINPUT_GAMEPAD_A]),
(int) (m_xbStatus[i].Gamepad.bAnalogButtons[XINPUT_GAMEPAD_B]),
(int) (m_xbStatus[i].Gamepad.bAnalogButtons[XINPUT_GAMEPAD_X]),
(int) (m_xbStatus[i].Gamepad.bAnalogButtons[XINPUT_GAMEPAD_Y]),
(int) (m_xbStatus[i].Gamepad.bAnalogButtons[XINPUT_GAMEPAD_BLACK]),
(int) (m_xbStatus[i].Gamepad.bAnalogButtons[XINPUT_GAMEPAD_WHITE]),
(int) (m_xbStatus[i].Gamepad.bAnalogButtons[XINPUT_GAMEPAD_LEFT_TRIGGER]),
(int) (m_xbStatus[i].Gamepad.bAnalogButtons[XINPUT_GAMEPAD_RIGHT_TRIGGER]),
(int) (m_xbStatus[i].Gamepad.sThumbLX),
(int) (m_xbStatus[i].Gamepad.sThumbLY),
(int) (m_xbStatus[i].Gamepad.sThumbRX),
(int) (m_xbStatus[i].Gamepad.sThumbRY));
OutputDebugString(szBuffer);
}
*/
#endif
}
}
}
bool CXGamepad::IsDigitalButtonPressed(const eDigitalButton eWhichButton, const bool bOnce,
const eController eWhichController) const
{
//////////////////////////////////////////////////////////////////////
// Returns the status of a digital button
//////////////////////////////////////////////////////////////////////
unsigned int i, iLastController = eWhichController;
bool bPressed = false;
if (!AnyControllersReady())
return false;
if (eWhichButton == NULL)
return false;
// Should we check all controllers ?
if (eWhichController == eAll)
{
for (i=0; i<MAX_XBOX_CONTROLLERS; i++)
{
if (IsControllerReady(i))
{
// Button eWhichButton pressed on controller i ?
if (m_xbStatus[i].Gamepad.wButtons & eWhichButton)
{
// Button pressed, save the current controller as the last one
iLastController = i;
bPressed = true;
break;
}
}
}
}
// Should we check the primary controller ?
if (eWhichController == ePrimary)
{
// Query the key state on the primary controller and prepare to check
// if the key was already pressed during the last update
iLastController = GetPrimaryController();
bPressed = (m_xbStatus[GetPrimaryController()].Gamepad.wButtons & eWhichButton) != NULL;
}
else if (eWhichController != eAll)
{
// Check the specified controller
if (IsControllerReady(eWhichController))
bPressed = (m_xbStatus[eWhichController].Gamepad.wButtons & eWhichButton) != NULL;
else
// Specified controller not ready
bPressed = false;
}
// We can just return if we are not in single trigger mode or the value is false
if (bPressed == false || bOnce == false)
return bPressed;
if (bOnce)
{
// Key is pressed and we are in single trigger mode
if ((m_xbLastStatus[iLastController].Gamepad.wButtons & eWhichButton) != NULL)
// Button press already processed
bPressed = false;
}
return bPressed;
}
float CXGamepad::GetAnalogButtonValue(const eAnalogButton eWhichButton,
const eController eWhichController) const
{
//////////////////////////////////////////////////////////////////////
// Returns the status of an analog button as a value between 0 and 1
//////////////////////////////////////////////////////////////////////
unsigned int i;
float fAccumValue = 0.0f;
if (!AnyControllersReady())
return 0.0f;
// Should we check all controllers ?
if (eWhichController == eAll)
{
for (i=0; i<MAX_XBOX_CONTROLLERS; i++)
{
// Add the value of the button if the controller is ready
if (IsControllerReady(i))
fAccumValue += (float) m_xbStatus[i].Gamepad.bAnalogButtons[eWhichButton] / 255.0f;
}
// Return clamped value
return __min(fAccumValue, 1.0f);
}
// Should we check the primary controller ?
if (eWhichController == ePrimary)
return m_xbStatus[GetPrimaryController()].Gamepad.bAnalogButtons[eWhichButton] / 255.0f;
// Check the specified controller
if (IsControllerReady(eWhichController))
return m_xbStatus[eWhichController].Gamepad.bAnalogButtons[eWhichButton] / 255.0f;
else
// Specified controller not ready
return 0.0f;
}
void CXGamepad::GetAnalogStickValue(float& fX, float& fY, const eSide eWhichStick,
const eController eWhichController) const
{
//////////////////////////////////////////////////////////////////////
// Check the axis of an analog stick, value is between -1 and +1
//////////////////////////////////////////////////////////////////////
unsigned int i;
float fAccumValueX = 0.0f;
float fAccumValueY = 0.0f;
//float fValX, fValY;
if (!AnyControllersReady())
{
fX = 0.0f;
fY = 0.0f;
return;
}
// Should we check all controllers ?
if (eWhichController == eAll)
{
for (i=0; i<MAX_XBOX_CONTROLLERS; i++)
{
// Add the value of the button if the controller is ready
if (IsControllerReady(i))
{
if (eWhichStick == eLeft)
{
// Left stick
fAccumValueX += Ignore(m_xbStatus[i].Gamepad.sThumbLX) / 32768.0f;
fAccumValueY += Ignore(m_xbStatus[i].Gamepad.sThumbLY) / 32768.0f;
}
else if (eWhichStick == eRight)
{
// Right stick
fAccumValueX += Ignore(m_xbStatus[i].Gamepad.sThumbRX) / 32768.0f;
fAccumValueY += Ignore(m_xbStatus[i].Gamepad.sThumbRY) / 32768.0f;
}
}
}
// Clamp
if (fAccumValueX < -1.0f)
fAccumValueX = -1.0;
if (fAccumValueX > 1.0f)
fAccumValueX = 1.0;
if (fAccumValueY < -1.0f)
fAccumValueY = -1.0;
if (fAccumValueY > 1.0f)
fAccumValueY = 1.0;
// Return clamped value
fX = fAccumValueX;
fY = fAccumValueY;
return;
}
// Should we check the primary controller ?
if (eWhichController == ePrimary)
{
// Read out the controller
ReadAnalogStickValue(GetPrimaryController(), eWhichStick,
m_bExponentialStick, fX, fY);
return;
}
// Check the specified controller
if (IsControllerReady(eWhichController))
{
if (eWhichStick == eLeft)
{
// Left stick
fX = Ignore(m_xbStatus[eWhichController].Gamepad.sThumbLX) / 32768.0f;
fY = Ignore(m_xbStatus[eWhichController].Gamepad.sThumbLY) / 32768.0f;
}
else if (eWhichStick == eRight)
{
// Right stick
fX = Ignore(m_xbStatus[eWhichController].Gamepad.sThumbRX) / 32768.0f;
fY = Ignore(m_xbStatus[eWhichController].Gamepad.sThumbRY) / 32768.0f;
}
return;
}
else
{
// Specified controller not ready
fX = 0.0f;
fY = 0.0f;
}
}
void CXGamepad::ReadAnalogStickValue(const unsigned __int8 iControllerID,
const eSide eWhichSide,
const bool bExponential,
float& fX, float& fY) const
{
//////////////////////////////////////////////////////////////////////
// Read the axis values of one of the analog sticks. Perform linear
// or exponential attenuation, take deadzone into account
//////////////////////////////////////////////////////////////////////
float fValX, fValY;
// Abort when controller is not inserted / opened
if (iControllerID + 1 >= MAX_XBOX_CONTROLLERS || IsControllerReady(iControllerID) == false)
{
fX = 0.0f;
fY = 0.0f;
return;
}
if (bExponential)
{
// Exponential change of intensity
if (eWhichSide == eRight)
{
// Read values from the right stick and scale to 0 - 50
fValX = Ignore(m_xbStatus[iControllerID].Gamepad.sThumbRX) / 32768.0f * 50.0f;
fValY = Ignore(m_xbStatus[iControllerID].Gamepad.sThumbRY) / 32768.0f * 50.0f;
}
else
{
// Read values from the left stick and scale to 0 - 50
fValX = Ignore(m_xbStatus[iControllerID].Gamepad.sThumbLX) / 32768.0f * 50.0f;
fValY = Ignore(m_xbStatus[iControllerID].Gamepad.sThumbLY) / 32768.0f * 50.0f;
}
// Attenuate
fX = fValX * fValX / 2500.0f;
fY = fValY * fValY / 2500.0f;
// Restore sign
if (fValX < 0.0f)
fX = -fX;
if (fValY < 0.0f)
fY = -fY;
}
else
{
// Linear change of intensity
if (eWhichSide == eRight)
{
// Read from the right side
fX = Ignore(m_xbStatus[iControllerID].Gamepad.sThumbRX) / 32768.0f;
fY = Ignore(m_xbStatus[iControllerID].Gamepad.sThumbRY) / 32768.0f;
}
else
{
// Read from the left side
fX = Ignore(m_xbStatus[iControllerID].Gamepad.sThumbLX) / 32768.0f;
fY = Ignore(m_xbStatus[iControllerID].Gamepad.sThumbLY) / 32768.0f;
}
}
}
namespace{
eDigitalButton but_dig[] = { eDigitalUp, eDigitalDown, eDigitalLeft, eDigitalRight, eStart, eBack, eLeftStick, eRightStick };
eAnalogButton but_an[] = {eA,eB,eX,eY, eBlack, eWhite, eLeftTrigger, eRightTrigger };
}
bool CXGamepad::KeyDown(int p_key)
{
if(p_key == XKEY_MAXIS_X || p_key == XKEY_MAXIS_Y)
return true;
if(XKEY_GP_A <= p_key && p_key <= XKEY_GP_RIGHT_TRIGGER)
{
int b = ( p_key>> 24) - (XKEY_GP_A >> 24);
return (GetAnalogButtonValue(but_an[b], eAll) > 0.4f);
}
if(XKEY_GP_DPAD_UP <= p_key && p_key <= XKEY_GP_RIGHT_THUMB)
{
int b = ( p_key>> 24) - (XKEY_GP_DPAD_UP >> 24);
return IsDigitalButtonPressed(but_dig[b], false, eAll);
}
if(XKEY_GP_STHUMBLUP <= p_key && p_key <= XKEY_GP_STHUMBLRIGHT)
{
if (m_xbLastStatus[0].dwPacketNumber != m_xbStatus[0].dwPacketNumber)
GetAnalogStickValue(m_fRX, m_fRY, eLeft, eAll);
switch(p_key)
{
case XKEY_GP_STHUMBLUP:
return (m_fRY > 0.4f);
case XKEY_GP_STHUMBLDOWN:
return (m_fRY < -0.4f);
case XKEY_GP_STHUMBLLEFT:
return (m_fRX < -0.4f);
case XKEY_GP_STHUMBLRIGHT:
return (m_fRX > 0.4f);
}
}
return false;
}
bool CXGamepad::KeyPressed(int p_key)
{
if(XKEY_GP_A <= p_key && p_key <= XKEY_GP_RIGHT_TRIGGER)
{
int b = ( p_key>> 24) - (XKEY_GP_A >> 24);
return (GetAnalogButtonValue(but_an[b], eAll) > 0.4f);
}
if(XKEY_GP_DPAD_UP <= p_key && p_key <= XKEY_GP_RIGHT_THUMB)
{
int b = ( p_key>> 24) - (XKEY_GP_DPAD_UP >> 24);
return IsDigitalButtonPressed(but_dig[b], true, eAll);
}
return false;
}
bool CXGamepad::KeyReleased(int p_key)
{
return false;
}
float CXGamepad::GetDeltaX()
{
if (m_xbLastStatus[0].dwPacketNumber != m_xbStatus[0].dwPacketNumber)
GetAnalogStickValue(m_fLX, m_fLY, eRight, eAll);
return m_fLX * 5;
}
float CXGamepad::GetDeltaY()
{
if (m_xbLastStatus[0].dwPacketNumber != m_xbStatus[0].dwPacketNumber)
GetAnalogStickValue(m_fLX, m_fLY, eRight, eAll);
return m_fLY * 5;
}