input: add Xbox one controller support

This commit is contained in:
oziphantom 2021-10-25 20:13:16 +11:00 committed by GitHub
parent 72c3693af8
commit a7f1e56c21
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 268 additions and 0 deletions

View file

@ -76,6 +76,20 @@ Not all options are turned on by default. Refer to `Tomb1Main.json5` for details
- added save game crystals game mode (enabled via gameflow)
- added pause screen
- added movable camera on W,A,S,D
- added Xbox One Controller support
- Per Axis Dead Zone
- Left Stick = movement
- A = Jump/Select
- B = Roll/Deselect
- X = Action/Select
- Y = Look/Select
- LB = Walk
- RB = Draw Weapons
- Dpad Up = Draw Weapons
- Back = Option
- Start = Pause
- Right Stick = Camera Movement
- R3 = Reset Camera
- changed internal game memory limit from 3.5 MB to 16 MB
- changed moveable limit from 256 to 10240
- changed input method to DirectInput

View file

@ -157,6 +157,10 @@
"resolution_width": -1,
"resolution_height": -1,
// Enable XBox One Controller with PS1 layout and Per Axis Dead Zone
"enable_xbox_one_controller": true,
// Overrides ingame brightness.
"brightness": 1.0,
}

View file

@ -152,6 +152,7 @@ int8_t T1MReadConfigFromJson(const char *cfg_data)
READ_BOOL(disable_fmv, 0);
READ_BOOL(disable_cine, 0);
READ_BOOL(disable_music_in_menu, 0);
READ_BOOL(enable_xbox_one_controller, 0);
READ_FLOAT(brightness, 1.0);
READ_BAR_SHOWING_MODE(healthbar_showing_mode, T1M_BSM_FLASHING_OR_DEFAULT);

View file

@ -67,6 +67,7 @@ typedef struct {
int8_t disable_music_in_menu;
int32_t resolution_width;
int32_t resolution_height;
int8_t enable_xbox_one_controller;
float brightness;
} T1MConfigStruct;

View file

@ -74,6 +74,8 @@ static LPDIRECTINPUT8 DInput;
static LPDIRECTINPUTDEVICE8 IDID_SysKeyboard;
static uint8_t DIKeys[256];
static LPDIRECTINPUTDEVICE8 IDID_Joystick;
static int32_t MedipackCoolDown = 0;
static void DInputCreate();
@ -83,15 +85,30 @@ static void DInputKeyboardRelease();
static void DInputKeyboardRead();
static int8_t Key_(KEY_NUMBER number);
static HRESULT DInputJoystickCreate();
static void DInputJoystickRelease();
static BOOL CALLBACK
EnumAxesCallback(const LPDIDEVICEOBJECTINSTANCE instance, LPVOID context);
static BOOL CALLBACK
EnumCallback(const LPDIDEVICEINSTANCE instance, LPVOID context);
void InputInit()
{
DInputCreate();
DInputKeyboardCreate();
if (T1MConfig.enable_xbox_one_controller) {
DInputJoystickCreate();
} else {
IDID_Joystick = NULL;
}
}
void InputShutdown()
{
DInputKeyboardRelease();
if (T1MConfig.enable_xbox_one_controller) {
DInputJoystickRelease();
}
DInputShutdown();
}
@ -212,6 +229,168 @@ int16_t KeyGet()
return -1;
}
static HRESULT DInputJoystickCreate()
{
HRESULT result;
// Look for the first simple joystick we can find.
if (FAILED(
result = IDirectInput8_EnumDevices(
DInput, DI8DEVCLASS_GAMECTRL, EnumCallback, NULL,
DIEDFL_ATTACHEDONLY))) {
LOG_ERROR(
"Error while calling IDirectInput8_EnumDevices: 0x%lx", result);
return result;
}
// Make sure we got a joystick
if (IDID_Joystick == NULL) {
LOG_ERROR("Joystick not found.\n");
return E_FAIL;
}
LOG_INFO("Joystick found.\n");
DIDEVCAPS capabilities;
// request simple joystick format 2
if (FAILED(
result = IDirectInputDevice_SetDataFormat(
IDID_Joystick, &c_dfDIJoystick2))) {
LOG_ERROR(
"Error while calling IDirectInputDevice_SetDataFormat: 0x%lx",
result);
DInputJoystickRelease();
return result;
}
// don't request exclusive access
if (FAILED(
result = IDirectInputDevice_SetCooperativeLevel(
IDID_Joystick, NULL, DISCL_NONEXCLUSIVE | DISCL_BACKGROUND))) {
LOG_ERROR(
"Error while calling IDirectInputDevice_SetCooperativeLevel: 0x%lx",
result);
DInputJoystickRelease();
return result;
}
// get axis count, we should know what it is but best to ask
capabilities.dwSize = sizeof(DIDEVCAPS);
if (FAILED(
result = IDirectInputDevice_GetCapabilities(
IDID_Joystick, &capabilities))) {
LOG_ERROR(
"Error while calling IDirectInputDevice_GetCapabilities: 0x%lx",
result);
DInputJoystickRelease();
return result;
}
// set the range we expect each axis to report back in
if (FAILED(
result = IDirectInputDevice_EnumObjects(
IDID_Joystick, EnumAxesCallback, NULL, DIDFT_AXIS))) {
LOG_ERROR(
"Error while calling IDirectInputDevice_EnumObjects: 0x%lx",
result);
DInputJoystickRelease();
return result;
}
return result;
}
static void DInputJoystickRelease()
{
if (IDID_Joystick) {
IDirectInputDevice_Unacquire(IDID_Joystick);
IDirectInputDevice_Release(IDID_Joystick);
IDID_Joystick = NULL;
}
}
static BOOL CALLBACK
EnumAxesCallback(const LPDIDEVICEOBJECTINSTANCE instance, LPVOID context)
{
DIPROPRANGE propRange;
propRange.diph.dwSize = sizeof(DIPROPRANGE);
propRange.diph.dwHeaderSize = sizeof(DIPROPHEADER);
propRange.diph.dwHow = DIPH_BYID;
propRange.diph.dwObj = instance->dwType;
propRange.lMin = -1024;
propRange.lMax = 1024;
// Set the range for the axis
if (FAILED(IDirectInputDevice8_SetProperty(
IDID_Joystick, DIPROP_RANGE, &propRange.diph))) {
LOG_ERROR(
"Error while calling IDirectInputDevice8_SetProperty: 0x%lx",
result);
return DIENUM_STOP;
}
return DIENUM_CONTINUE;
}
static BOOL CALLBACK
EnumCallback(const LPDIDEVICEINSTANCE instance, LPVOID context)
{
HRESULT result;
// Obtain an interface to the enumerated joystick.
result = IDirectInput8_CreateDevice(
DInput, &instance->guidInstance, &IDID_Joystick, NULL);
if (FAILED(result)) {
LOG_ERROR(
"Error while calling IDirectInput8_CreateDevice: 0x%lx", result);
return DIENUM_CONTINUE;
}
// we got one, it will do.
return DIENUM_STOP;
}
static HRESULT DInputJoystickPoll(DIJOYSTATE2 *joystate)
{
HRESULT result;
if (!IDID_Joystick) {
return S_OK;
}
// Poll the device to read the current state
result = IDirectInputDevice8_Poll(IDID_Joystick);
if (FAILED(result)) {
// focus was lost, try to reaquire the device
result = IDirectInputDevice8_Acquire(IDID_Joystick);
while (result == DIERR_INPUTLOST) {
result = IDirectInputDevice8_Acquire(IDID_Joystick);
}
// A fatal error? Return failure.
if ((result == DIERR_INVALIDPARAM)
|| (result == DIERR_NOTINITIALIZED)) {
LOG_ERROR(
"Error while calling IDirectInputDevice8_Acquire: 0x%lx",
result);
return E_FAIL;
}
// If another application has control of this device, return
// successfully.
if (result == DIERR_OTHERAPPHASPRIO) {
return S_OK;
}
}
// Get the input's device state
if (FAILED(
result = IDirectInputDevice8_GetDeviceState(
IDID_Joystick, sizeof(DIJOYSTATE2), joystate))) {
return result; // The device should have been acquired during the Poll()
}
return S_OK;
}
void S_UpdateInput()
{
int32_t linput = 0;
@ -373,6 +552,75 @@ void S_UpdateInput()
}
}
if (IDID_Joystick) {
DIJOYSTATE2 state;
DInputJoystickPoll(&state);
// check Y
if (state.lY > 512) {
linput |= IN_BACK;
} else if (state.lY < -512) {
linput |= IN_FORWARD;
}
// check X
if (state.lX > 512) {
linput |= IN_RIGHT;
} else if (state.lX < -512) {
linput |= IN_LEFT;
}
// check Z
if (state.lZ > 512) {
linput |= IN_STEPL;
} else if (state.lZ < -512) {
linput |= IN_STEPR;
}
// check 2nd stick X
if (state.lRx > 512) {
linput |= IN_CAMERA_RIGHT;
} else if (state.lRx < -512) {
linput |= IN_CAMERA_LEFT;
}
// check 2nd stick Y
if (state.lRy > 512) {
linput |= IN_CAMERA_DOWN;
} else if (state.lRy < -512) {
linput |= IN_CAMERA_UP;
}
// check buttons
if (state.rgbButtons[0]) { // A
linput |= IN_JUMP | IN_SELECT;
}
if (state.rgbButtons[1]) { // B
linput |= IN_ROLL | IN_DESELECT;
}
if (state.rgbButtons[2]) { // X
linput |= IN_ACTION | IN_SELECT;
}
if (state.rgbButtons[3]) { // Y
linput |= IN_LOOK | IN_DESELECT;
}
if (state.rgbButtons[4]) { // LB
linput |= IN_SLOW;
}
if (state.rgbButtons[5]) { // RB
linput |= IN_DRAW;
}
if (state.rgbButtons[6]) { // back
linput |= IN_OPTION;
}
if (state.rgbButtons[7]) { // start
linput |= IN_PAUSE;
}
if (state.rgbButtons[9]) { // 2nd axis click
linput |= IN_CAMERA_RESET;
}
// check dpad
if (state.rgdwPOV[0] == 0) { // up
linput |= IN_DRAW;
}
}
Input = linput;
return;