You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
224 lines
5.3 KiB
224 lines
5.3 KiB
#pragma once
|
|
|
|
#ifdef WIN32
|
|
#include <windows.h>
|
|
#include <xinput.h>
|
|
|
|
typedef DWORD(WINAPI XInputGetState_t)(DWORD dwUserIndex, XINPUT_STATE* pState);
|
|
static XInputGetState_t* XInputStateGet;
|
|
|
|
typedef DWORD(WINAPI XInputSetState_t)(DWORD dwUserIndex, XINPUT_VIBRATION* pVibration);
|
|
static XInputSetState_t* XInputStateSet;
|
|
#endif
|
|
|
|
#define C_BUTTON_COUNT 14
|
|
enum CButton
|
|
{
|
|
UP,
|
|
DOWN,
|
|
LEFT,
|
|
RIGHT,
|
|
START,
|
|
BACK,
|
|
A,
|
|
B,
|
|
X,
|
|
Y,
|
|
LEFT_SHOULDER,
|
|
RIGHT_SHOULDER,
|
|
LEFT_THUMB,
|
|
RIGHT_THUMB
|
|
};
|
|
|
|
struct CBState
|
|
{
|
|
bool bPressed = false;
|
|
bool bReleased = false;
|
|
bool bHeld = false;
|
|
};
|
|
|
|
class ControllerManager
|
|
{
|
|
private:
|
|
bool buttonState[C_BUTTON_COUNT];
|
|
bool lastButtonState[C_BUTTON_COUNT];
|
|
|
|
// Trigger values are in the range of 0 to 1, where 0 is fully
|
|
// released and 1 is fully pressed.
|
|
float triggerLeft = 0;
|
|
float triggerRight = 0;
|
|
|
|
// Stick values are in the range of -1 to 1. For X values, -1 is
|
|
// all the way to the left while +1 is all the way to the right.
|
|
float leftStickX = 0;
|
|
float leftStickY = 0;
|
|
float rightStickX = 0;
|
|
float rightStickY = 0;
|
|
|
|
// Whether or not the controller is plugged in.
|
|
bool pluggedIn = true;
|
|
|
|
bool vibrating = false;
|
|
float vibrateTime = 0;
|
|
float vibrateCounter = 0;
|
|
|
|
public:
|
|
bool Initialize();
|
|
void Update(float dt);
|
|
|
|
void Vibrate(short amt, int timeMs);
|
|
|
|
CBState GetButton(CButton button);
|
|
|
|
float GetLeftTrigger() { return triggerLeft; }
|
|
float GetRightTrigger() { return triggerRight; }
|
|
|
|
float GetLeftStickX() { return leftStickX; }
|
|
float GetLeftStickY() { return leftStickY; }
|
|
|
|
float GetRightStickX() { return rightStickX; }
|
|
float GetRightStickY() { return rightStickY; }
|
|
|
|
bool IsVibrating() { return vibrating; }
|
|
bool IsPluggedIn() { return pluggedIn; }
|
|
|
|
private:
|
|
float NormalizeStickValue(short value);
|
|
};
|
|
|
|
bool ControllerManager::Initialize()
|
|
{
|
|
#ifdef WIN32
|
|
// TODO: Should we check for version 9.1.0 if we fail to find 1.4?
|
|
HMODULE lib = LoadLibraryA("xinput1_4.dll");
|
|
|
|
if (!lib) return false;
|
|
|
|
XInputStateGet = (XInputGetState_t*)GetProcAddress(lib, "XInputGetState");
|
|
XInputStateSet = (XInputSetState_t*)GetProcAddress(lib, "XInputSetState");
|
|
#endif
|
|
|
|
return true;
|
|
}
|
|
|
|
float ControllerManager::NormalizeStickValue(short value)
|
|
{
|
|
// The value we are given is in the range -32768 to 32767 with some deadzone around zero.
|
|
// We will assume all values in this dead zone to be a reading of zero (the stick is not moved).
|
|
if (value > -7000 && value < 7000) return 0;
|
|
|
|
// Otherwise, we are going to normalize the value.
|
|
return ((value + 32768.0f) / (32768.0f + 32767.0f) * 2) - 1;
|
|
}
|
|
|
|
void ControllerManager::Vibrate(short amt, int timeMs)
|
|
{
|
|
// If we are already vibrating, just ignore this, unless they say zero, in which case we will let them stop it.
|
|
if (vibrating && amt != 0) return;
|
|
|
|
// Only start the timer if we are actually vibrating.
|
|
if (amt != 0)
|
|
{
|
|
vibrateTime = timeMs / 1000.0f;
|
|
vibrating = true;
|
|
}
|
|
#ifdef WIN32
|
|
XINPUT_VIBRATION info =
|
|
{
|
|
amt,
|
|
amt
|
|
};
|
|
XInputStateSet(0, &info);
|
|
#endif
|
|
}
|
|
|
|
CBState ControllerManager::GetButton(CButton button)
|
|
{
|
|
return
|
|
{
|
|
!lastButtonState[button] && buttonState[button],
|
|
lastButtonState[button] && !buttonState[button],
|
|
lastButtonState[button] && buttonState[button]
|
|
};
|
|
}
|
|
|
|
void ControllerManager::Update(float dt)
|
|
{
|
|
#ifdef WIN32
|
|
if (vibrating)
|
|
{
|
|
vibrateCounter += dt;
|
|
if (vibrateCounter >= vibrateTime)
|
|
{
|
|
XINPUT_VIBRATION info =
|
|
{
|
|
0, 0
|
|
};
|
|
XInputStateSet(0, &info);
|
|
|
|
vibrating = false;
|
|
vibrateCounter = 0;
|
|
vibrateTime = 0;
|
|
}
|
|
}
|
|
|
|
for (int i = 0; i < C_BUTTON_COUNT; i++)
|
|
{
|
|
lastButtonState[i] = buttonState[i];
|
|
}
|
|
|
|
XINPUT_STATE state;
|
|
|
|
// Try and get the first controller. For now we will only support a single one.
|
|
DWORD res = XInputStateGet(0, &state);
|
|
|
|
// If the controller is plugged in, handle input.
|
|
if (res == ERROR_SUCCESS)
|
|
{
|
|
XINPUT_GAMEPAD* pad = &state.Gamepad;
|
|
|
|
buttonState[UP] = (pad->wButtons & XINPUT_GAMEPAD_DPAD_UP);
|
|
buttonState[DOWN] = (pad->wButtons & XINPUT_GAMEPAD_DPAD_DOWN);
|
|
buttonState[LEFT] = (pad->wButtons & XINPUT_GAMEPAD_DPAD_LEFT);
|
|
buttonState[RIGHT] = (pad->wButtons & XINPUT_GAMEPAD_DPAD_RIGHT);
|
|
buttonState[START] = (pad->wButtons & XINPUT_GAMEPAD_START);
|
|
buttonState[BACK] = (pad->wButtons & XINPUT_GAMEPAD_BACK);
|
|
buttonState[LEFT_SHOULDER] = (pad->wButtons & XINPUT_GAMEPAD_LEFT_SHOULDER);
|
|
buttonState[RIGHT_SHOULDER] = (pad->wButtons & XINPUT_GAMEPAD_RIGHT_SHOULDER);
|
|
buttonState[LEFT_THUMB] = (pad->wButtons & XINPUT_GAMEPAD_LEFT_THUMB);
|
|
buttonState[RIGHT_THUMB] = (pad->wButtons & XINPUT_GAMEPAD_RIGHT_THUMB);
|
|
buttonState[A] = (pad->wButtons & XINPUT_GAMEPAD_A);
|
|
buttonState[B] = (pad->wButtons & XINPUT_GAMEPAD_B);
|
|
buttonState[X] = (pad->wButtons & XINPUT_GAMEPAD_X);
|
|
buttonState[Y] = (pad->wButtons & XINPUT_GAMEPAD_Y);
|
|
|
|
triggerLeft = pad->bLeftTrigger / 255.0f;
|
|
triggerRight = pad->bRightTrigger / 255.0f;
|
|
leftStickX = NormalizeStickValue(pad->sThumbLX);
|
|
leftStickY = NormalizeStickValue(pad->sThumbLY);
|
|
rightStickX = NormalizeStickValue(pad->sThumbRX);
|
|
rightStickY = NormalizeStickValue(pad->sThumbRY);
|
|
|
|
if (!pluggedIn)
|
|
{
|
|
pluggedIn = true;
|
|
// Send callback.
|
|
// printf("Plugged in.\n");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (pluggedIn)
|
|
{
|
|
pluggedIn = false;
|
|
// Send callback.
|
|
// printf("Unplugged.\n");
|
|
}
|
|
}
|
|
#else
|
|
for (int i = 0; i < C_BUTTON_COUNT; i++)
|
|
{
|
|
lastButtonState[i] = buttonState[i] = false;
|
|
}
|
|
#endif
|
|
} |