mirror of
https://github.com/XProger/OpenLara.git
synced 2025-08-17 18:36:43 +02:00
#15 add XInput support for Windows
This commit is contained in:
@@ -1046,7 +1046,7 @@ namespace Core {
|
|||||||
ctrl.keys[ cDuck ] = KeySet( ikZ, jkLT );
|
ctrl.keys[ cDuck ] = KeySet( ikZ, jkLT );
|
||||||
ctrl.keys[ cDash ] = KeySet( ikX, jkRT );
|
ctrl.keys[ cDash ] = KeySet( ikX, jkRT );
|
||||||
ctrl.keys[ cRoll ] = KeySet( ikA, jkB );
|
ctrl.keys[ cRoll ] = KeySet( ikA, jkB );
|
||||||
ctrl.keys[ cInventory ] = KeySet( ikTab, jkSelect );
|
ctrl.keys[ cInventory ] = KeySet( ikEscape, jkSelect );
|
||||||
ctrl.keys[ cStart ] = KeySet( ikEnter, jkStart );
|
ctrl.keys[ cStart ] = KeySet( ikEnter, jkStart );
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1076,7 +1076,8 @@ namespace Core {
|
|||||||
|
|
||||||
// use D key for jump in browsers
|
// use D key for jump in browsers
|
||||||
#ifdef __EMSCRIPTEN__
|
#ifdef __EMSCRIPTEN__
|
||||||
settings.controls[0].keys[cJump].key = ikD;
|
settings.controls[0].keys[ cJump ].key = ikD;
|
||||||
|
settings.controls[0].keys[ cInventory ].key = ikTab;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef __RPI__
|
#ifdef __RPI__
|
||||||
|
@@ -596,6 +596,7 @@ struct Lara : Character {
|
|||||||
|
|
||||||
void reset(int room, const vec3 &pos, float angle, Stand forceStand = STAND_GROUND) {
|
void reset(int room, const vec3 &pos, float angle, Stand forceStand = STAND_GROUND) {
|
||||||
visibleMask = 0xFFFFFFFF;
|
visibleMask = 0xFFFFFFFF;
|
||||||
|
health = LARA_MAX_HEALTH;
|
||||||
|
|
||||||
if (room == TR::NO_ROOM) {
|
if (room == TR::NO_ROOM) {
|
||||||
stand = STAND_AIR;
|
stand = STAND_AIR;
|
||||||
|
@@ -141,21 +141,85 @@ InputKey mouseToInputKey(int msg) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// joystick
|
// joystick
|
||||||
|
typedef struct _XINPUT_GAMEPAD
|
||||||
|
{
|
||||||
|
WORD wButtons;
|
||||||
|
BYTE bLeftTrigger;
|
||||||
|
BYTE bRightTrigger;
|
||||||
|
SHORT sThumbLX;
|
||||||
|
SHORT sThumbLY;
|
||||||
|
SHORT sThumbRX;
|
||||||
|
SHORT sThumbRY;
|
||||||
|
} XINPUT_GAMEPAD, *PXINPUT_GAMEPAD;
|
||||||
|
|
||||||
|
typedef struct _XINPUT_STATE
|
||||||
|
{
|
||||||
|
DWORD dwPacketNumber;
|
||||||
|
XINPUT_GAMEPAD Gamepad;
|
||||||
|
} XINPUT_STATE, *PXINPUT_STATE;
|
||||||
|
|
||||||
|
typedef struct _XINPUT_VIBRATION
|
||||||
|
{
|
||||||
|
WORD wLeftMotorSpeed;
|
||||||
|
WORD wRightMotorSpeed;
|
||||||
|
} XINPUT_VIBRATION, *PXINPUT_VIBRATION;
|
||||||
|
|
||||||
|
#define XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE 7849
|
||||||
|
#define XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE 8689
|
||||||
|
#define XINPUT_GAMEPAD_TRIGGER_THRESHOLD 30
|
||||||
|
|
||||||
|
DWORD (WINAPI *XInputGetState)(DWORD dwUserIndex, XINPUT_STATE* pState);
|
||||||
|
DWORD (WINAPI *XInputSetState)(DWORD dwUserIndex, XINPUT_VIBRATION* pVibration);
|
||||||
|
|
||||||
#define JOY_DEAD_ZONE_STICK 0.3f
|
#define JOY_DEAD_ZONE_STICK 0.3f
|
||||||
#define JOY_DEAD_ZONE_TRIGGER 0.01f
|
#define JOY_DEAD_ZONE_TRIGGER 0.01f
|
||||||
|
#define JOY_MAX_COUNT 2
|
||||||
|
#define JOY_NONE 255
|
||||||
|
|
||||||
bool joyReady[2];
|
uint8 joyIndex[JOY_MAX_COUNT];
|
||||||
|
|
||||||
void joyInit(int index) {
|
void osJoyVibrate(int index, float L, float R) {
|
||||||
|
if (XInputSetState && joyIndex[index] != JOY_NONE) {
|
||||||
|
XINPUT_VIBRATION vibration;
|
||||||
|
vibration.wLeftMotorSpeed = int(L * 65535.0f);
|
||||||
|
vibration.wRightMotorSpeed = int(R * 65535.0f);
|
||||||
|
XInputSetState(joyIndex[index], &vibration);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void joyInit() {
|
||||||
|
memset(joyIndex, JOY_NONE, sizeof(joyIndex));
|
||||||
|
int index = 0;
|
||||||
|
|
||||||
|
HMODULE h = LoadLibrary("xinput9_1_0.dll");
|
||||||
|
|
||||||
|
XInputGetState = (decltype(XInputGetState))GetProcAddress(h, "XInputGetState");
|
||||||
|
XInputSetState = (decltype(XInputSetState))GetProcAddress(h, "XInputSetState");
|
||||||
|
|
||||||
|
for (int j = 0; j < 4; j++) {
|
||||||
|
if (XInputGetState) { // XInput
|
||||||
|
XINPUT_STATE state;
|
||||||
|
if (XInputGetState(j, &state) == ERROR_SUCCESS)
|
||||||
|
joyIndex[index] = j;
|
||||||
|
} else { // mmSystem (legacy)
|
||||||
JOYINFOEX info;
|
JOYINFOEX info;
|
||||||
info.dwSize = sizeof(info);
|
info.dwSize = sizeof(info);
|
||||||
info.dwFlags = JOY_RETURNALL;
|
info.dwFlags = JOY_RETURNALL;
|
||||||
joyReady[index] = joyGetPosEx(index, &info) == JOYERR_NOERROR;
|
if (joyGetPosEx(j, &info) == JOYERR_NOERROR)
|
||||||
|
joyIndex[index] = j;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (joyIndex[index] != JOY_NONE) {
|
||||||
|
index++;
|
||||||
|
if (index >= JOY_MAX_COUNT)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void joyFree(int index) {
|
void joyFree() {
|
||||||
joyReady[index] = false;
|
memset(joyIndex, JOY_NONE, sizeof(joyIndex));
|
||||||
memset(&Input::joy[index], 0, sizeof(Input::joy[index]));
|
Input::reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
float joyAxis(int x, int xMin, int xMax) {
|
float joyAxis(int x, int xMin, int xMax) {
|
||||||
@@ -170,16 +234,58 @@ vec2 joyDir(float ax, float ay) {
|
|||||||
return dir.normal() * dist;
|
return dir.normal() * dist;
|
||||||
}
|
}
|
||||||
|
|
||||||
void joyUpdate(int index) {
|
float joyGetPOV(int mask) {
|
||||||
if (!joyReady[index]) return;
|
switch (mask) {
|
||||||
|
case 0b0001 : return 1;
|
||||||
|
case 0b1001 : return 2;
|
||||||
|
case 0b1000 : return 3;
|
||||||
|
case 0b1010 : return 4;
|
||||||
|
case 0b0010 : return 5;
|
||||||
|
case 0b0110 : return 6;
|
||||||
|
case 0b0100 : return 7;
|
||||||
|
case 0b0101 : return 8;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int joyDeadZone(int value, int zone) {
|
||||||
|
return (value < -zone || value > zone) ? value : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void joyUpdate() {
|
||||||
|
for (int j = 0; j < JOY_MAX_COUNT; j++) {
|
||||||
|
if (joyIndex[j] == JOY_NONE) break;
|
||||||
|
int index = joyIndex[j];
|
||||||
|
|
||||||
|
if (XInputGetState) { // XInput
|
||||||
|
XINPUT_STATE state;
|
||||||
|
if (XInputGetState(index, &state) == ERROR_SUCCESS) {
|
||||||
|
// osJoyVibrate(j, state.Gamepad.bLeftTrigger / 255.0f, state.Gamepad.bRightTrigger / 255.0f); // vibration test
|
||||||
|
|
||||||
|
Input::setJoyPos(j, jkL, joyDir(joyAxis(joyDeadZone( state.Gamepad.sThumbLX, XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE), -32768, 32767),
|
||||||
|
joyAxis(joyDeadZone(-state.Gamepad.sThumbLY, XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE), -32768, 32767)));
|
||||||
|
Input::setJoyPos(j, jkR, joyDir(joyAxis(joyDeadZone( state.Gamepad.sThumbRX, XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE), -32768, 32767),
|
||||||
|
joyAxis(joyDeadZone(-state.Gamepad.sThumbRY, XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE), -32768, 32767)));
|
||||||
|
Input::setJoyPos(j, jkLT, vec2(joyDeadZone(state.Gamepad.bLeftTrigger, XINPUT_GAMEPAD_TRIGGER_THRESHOLD) / 255.0f, 0.0f));
|
||||||
|
Input::setJoyPos(j, jkRT, vec2(joyDeadZone(state.Gamepad.bRightTrigger, XINPUT_GAMEPAD_TRIGGER_THRESHOLD) / 255.0f, 0.0f));
|
||||||
|
Input::setJoyPos(j, jkPOV, vec2(joyGetPOV(state.Gamepad.wButtons & 15), 0));
|
||||||
|
|
||||||
|
static const JoyKey keys[] = { jkUp, jkDown, jkLeft, jkRight, jkStart, jkSelect, jkL, jkR, jkLB, jkRB, jkNone, jkNone, jkA, jkB, jkX, jkY };
|
||||||
|
for (int i = 4; i < 16; i++)
|
||||||
|
Input::setJoyDown(j, keys[i], (state.Gamepad.wButtons & (1 << i)) != 0);
|
||||||
|
} else {
|
||||||
|
joyFree();
|
||||||
|
joyInit();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else { // mmSystem (legacy)
|
||||||
JOYINFOEX info;
|
JOYINFOEX info;
|
||||||
info.dwSize = sizeof(info);
|
info.dwSize = sizeof(info);
|
||||||
info.dwFlags = JOY_RETURNALL;
|
info.dwFlags = JOY_RETURNALL;
|
||||||
|
|
||||||
if (joyGetPosEx(index, &info) == JOYERR_NOERROR) {
|
if (joyGetPosEx(index, &info) == JOYERR_NOERROR) {
|
||||||
JOYCAPS caps;
|
JOYCAPS caps;
|
||||||
joyGetDevCaps(0, &caps, sizeof(caps));
|
joyGetDevCaps(index, &caps, sizeof(caps));
|
||||||
|
|
||||||
if (caps.wNumAxes > 0) {
|
if (caps.wNumAxes > 0) {
|
||||||
Input::setJoyPos(index, jkL, joyDir(joyAxis(info.dwXpos, caps.wXmin, caps.wXmax),
|
Input::setJoyPos(index, jkL, joyDir(joyAxis(info.dwXpos, caps.wXmin, caps.wXmax),
|
||||||
@@ -208,18 +314,19 @@ void joyUpdate(int index) {
|
|||||||
|
|
||||||
for (int i = 0; i < 10; i++)
|
for (int i = 0; i < 10; i++)
|
||||||
Input::setJoyDown(index, JoyKey(jkA + i), (info.dwButtons & (1 << i)) > 0);
|
Input::setJoyDown(index, JoyKey(jkA + i), (info.dwButtons & (1 << i)) > 0);
|
||||||
} else
|
} else {
|
||||||
joyFree(index);
|
joyFree();
|
||||||
|
joyInit();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// touch
|
// touch
|
||||||
typedef BOOL (__stdcall *PREGISTERTOUCHWINDOW)(HWND, ULONG);
|
BOOL (WINAPI *RegisterTouchWindowX)(HWND, ULONG);
|
||||||
typedef BOOL (__stdcall *PGETTOUCHINPUTINFO)(HTOUCHINPUT, UINT, PTOUCHINPUT, int);
|
BOOL (WINAPI *GetTouchInputInfoX)(HTOUCHINPUT, UINT, PTOUCHINPUT, int);
|
||||||
typedef BOOL (__stdcall *PCLOSETOUCHINPUTHANDLE)(HTOUCHINPUT);
|
BOOL (WINAPI *CloseTouchInputHandleX)(HTOUCHINPUT);
|
||||||
|
|
||||||
PREGISTERTOUCHWINDOW RegisterTouchWindowX;
|
|
||||||
PGETTOUCHINPUTINFO GetTouchInputInfoX;
|
|
||||||
PCLOSETOUCHINPUTHANDLE CloseTouchInputHandleX;
|
|
||||||
|
|
||||||
#define MAX_TOUCH_COUNT 6
|
#define MAX_TOUCH_COUNT 6
|
||||||
|
|
||||||
@@ -227,9 +334,9 @@ void touchInit(HWND hWnd) {
|
|||||||
int value = GetSystemMetrics(SM_DIGITIZER);
|
int value = GetSystemMetrics(SM_DIGITIZER);
|
||||||
if (value) {
|
if (value) {
|
||||||
HMODULE hUser32 = LoadLibrary("user32.dll");
|
HMODULE hUser32 = LoadLibrary("user32.dll");
|
||||||
RegisterTouchWindowX = (PREGISTERTOUCHWINDOW)GetProcAddress(hUser32, "RegisterTouchWindow");
|
RegisterTouchWindowX = (decltype(RegisterTouchWindowX)) GetProcAddress(hUser32, "RegisterTouchWindow");
|
||||||
GetTouchInputInfoX = (PGETTOUCHINPUTINFO)GetProcAddress(hUser32, "GetTouchInputInfo");
|
GetTouchInputInfoX = (decltype(GetTouchInputInfoX)) GetProcAddress(hUser32, "GetTouchInputInfo");
|
||||||
CloseTouchInputHandleX = (PCLOSETOUCHINPUTHANDLE)GetProcAddress(hUser32, "CloseTouchInputHandle");
|
CloseTouchInputHandleX = (decltype(CloseTouchInputHandleX)) GetProcAddress(hUser32, "CloseTouchInputHandle");
|
||||||
if (RegisterTouchWindowX && GetTouchInputInfoX && CloseTouchInputHandleX)
|
if (RegisterTouchWindowX && GetTouchInputInfoX && CloseTouchInputHandleX)
|
||||||
RegisterTouchWindowX(hWnd, 0);
|
RegisterTouchWindowX(hWnd, 0);
|
||||||
}
|
}
|
||||||
@@ -366,10 +473,8 @@ static LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lPara
|
|||||||
break;
|
break;
|
||||||
// joystick
|
// joystick
|
||||||
case WM_DEVICECHANGE :
|
case WM_DEVICECHANGE :
|
||||||
joyFree(0);
|
joyFree();
|
||||||
joyFree(1);
|
joyInit();
|
||||||
joyInit(0);
|
|
||||||
joyInit(1);
|
|
||||||
return 1;
|
return 1;
|
||||||
// touch
|
// touch
|
||||||
case WM_TOUCH :
|
case WM_TOUCH :
|
||||||
@@ -557,8 +662,7 @@ int main(int argc, char** argv) {
|
|||||||
osStartTime = osGetTime();
|
osStartTime = osGetTime();
|
||||||
|
|
||||||
touchInit(hWnd);
|
touchInit(hWnd);
|
||||||
joyInit(0);
|
joyInit();
|
||||||
joyInit(1);
|
|
||||||
sndInit(hWnd);
|
sndInit(hWnd);
|
||||||
|
|
||||||
Game::init(argc > 1 ? argv[1] : NULL);
|
Game::init(argc > 1 ? argv[1] : NULL);
|
||||||
@@ -580,8 +684,7 @@ int main(int argc, char** argv) {
|
|||||||
if (msg.message == WM_QUIT)
|
if (msg.message == WM_QUIT)
|
||||||
Core::quit();
|
Core::quit();
|
||||||
} else {
|
} else {
|
||||||
joyUpdate(0);
|
joyUpdate();
|
||||||
joyUpdate(1);
|
|
||||||
#ifdef VR_SUPPORT
|
#ifdef VR_SUPPORT
|
||||||
vrUpdateInput();
|
vrUpdateInput();
|
||||||
#endif
|
#endif
|
||||||
|
Reference in New Issue
Block a user