Merge pull request #12 from Boomslangnz/master
Fixed game crash with no controller connected
This commit is contained in:
commit
1148385c7d
@ -1,244 +1,273 @@
|
||||
#include <StdInc.h>
|
||||
#include "Utility/InitFunction.h"
|
||||
#include "Functions/Global.h"
|
||||
#include "Utility\Hooking.Patterns.h"
|
||||
|
||||
#pragma comment(lib, "Ws2_32.lib")
|
||||
|
||||
#ifndef _M_AMD64
|
||||
extern int* wheelSection;
|
||||
extern int* ffbOffset;
|
||||
extern int* ffbOffset2;
|
||||
extern int* ffbOffset3;
|
||||
extern int* ffbOffset4;
|
||||
uintptr_t imageBase;
|
||||
bool shiftup = false;
|
||||
bool shiftdown = false;
|
||||
|
||||
void ShiftUp(BYTE shift)
|
||||
{
|
||||
*(BYTE *)(imageBase + 0x15B468C) = shift + 1;
|
||||
}
|
||||
|
||||
void ShiftDown(BYTE shift)
|
||||
{
|
||||
*(BYTE *)(imageBase + 0x15B468C) = shift - 1;
|
||||
}
|
||||
|
||||
static void InjectKeys()
|
||||
{
|
||||
DWORD buttons2 = *wheelSection;
|
||||
DWORD buttons = *ffbOffset;
|
||||
BYTE wheel = *ffbOffset2;
|
||||
BYTE gas = *ffbOffset3;
|
||||
BYTE brake = *ffbOffset4;
|
||||
BYTE gamestate = *(BYTE *)(imageBase + 0x15B5744);
|
||||
BYTE gear = *(BYTE *)(imageBase + 0x15B468C);
|
||||
|
||||
*(BYTE *)(imageBase + 0x15B4679) = gas;
|
||||
*(BYTE *)(imageBase + 0x15B467A) = brake;
|
||||
DWORD track = *(DWORD *)(imageBase + 0x1228C78);
|
||||
if (track != 0)
|
||||
{
|
||||
BYTE track1 = *(BYTE *)(track + 0x4);
|
||||
#ifdef _DEBUG
|
||||
info(true, "%02X %02X", track1, gamestate);
|
||||
#endif
|
||||
if ((track1 == 2 || track1 == 4) && (gamestate == 0x16))
|
||||
{
|
||||
BYTE reverse = wheel * 0xFF;
|
||||
if (reverse == 0x00)
|
||||
*(BYTE *)(imageBase + 0x15B4678) = 0xFF;
|
||||
else
|
||||
*(BYTE *)(imageBase + 0x15B4678) = reverse;
|
||||
#ifdef _DEBUG
|
||||
info(true, "Reverse wheel");
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
*(BYTE *)(imageBase + 0x15B4678) = wheel;
|
||||
#ifdef _DEBUG
|
||||
info(true, "Normal wheel1");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
*(BYTE *)(imageBase + 0x15B4678) = wheel;
|
||||
#ifdef _DEBUG
|
||||
info(true, "Normal wheel2");
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
if(wheel <= 0x40)
|
||||
{
|
||||
//Menu Left
|
||||
DWORD p = *(DWORD *)(imageBase + 0x1AAFFF0);
|
||||
DWORD p1 = *(DWORD *)(p + 0x00);
|
||||
if (p != 0)
|
||||
{
|
||||
*(BYTE *)(p1 + 0x25) = 0xFF;
|
||||
}
|
||||
|
||||
}
|
||||
else if(wheel >= 0xC0)
|
||||
{
|
||||
//Menu Right
|
||||
DWORD p = *(DWORD *)(imageBase + 0x1AAFFF0);
|
||||
DWORD p1 = *(DWORD *)(p + 0x00);
|
||||
if (p1 != 0)
|
||||
{
|
||||
*(BYTE *)(p1 + 0x27) = 0xFF;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
DWORD p = *(DWORD *)(imageBase + 0x1AAFFF0);
|
||||
DWORD p1 = *(DWORD *)(p + 0x00);
|
||||
if (p1 != 0)
|
||||
{
|
||||
*(BYTE *)(p1 + 0x25) = 0x00;
|
||||
*(BYTE *)(p1 + 0x27) = 0x00;
|
||||
}
|
||||
}
|
||||
|
||||
if (buttons == 0x01)
|
||||
{
|
||||
//Inject Start
|
||||
DWORD p = *(DWORD *)(imageBase + 0x1AB0010);
|
||||
DWORD p1 = *(DWORD *)(p + 0x00);
|
||||
if (p1 != 0)
|
||||
{
|
||||
*(DWORD *)(p1 + 0x08) = 0x01;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
DWORD p = *(DWORD *)(imageBase + 0x1AB0010);
|
||||
DWORD p1 = *(DWORD *)(p + 0x00);
|
||||
if (p1 != 0)
|
||||
{
|
||||
*(DWORD *)(p1 + 0x08) = 0x00;
|
||||
}
|
||||
}
|
||||
|
||||
if ((buttons == 0x02) && (gear < 0x03))
|
||||
{
|
||||
if (!shiftup)
|
||||
{
|
||||
shiftup = true;
|
||||
ShiftUp(*(BYTE *)(imageBase + 0x15B468C));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
shiftup = false;
|
||||
}
|
||||
|
||||
if ((buttons == 0x04) && (gear > 0x00)) //crashes right now
|
||||
{
|
||||
if (!shiftdown)
|
||||
{
|
||||
shiftdown = true;
|
||||
ShiftDown(*(BYTE *)(imageBase + 0x15B468C));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
shiftdown = false;
|
||||
}
|
||||
|
||||
if (buttons2 == 0x01)
|
||||
{
|
||||
//Gear Change 1
|
||||
*(BYTE *)(imageBase + 0x15B468C) = 0x00;
|
||||
}
|
||||
|
||||
if (buttons2 == 0x02)
|
||||
{
|
||||
//Gear Change 2
|
||||
*(BYTE *)(imageBase + 0x15B468C) = 0x01;
|
||||
}
|
||||
|
||||
if (buttons2 == 0x04)
|
||||
{
|
||||
//Gear Change 3
|
||||
*(BYTE *)(imageBase + 0x15B468C) = 0x02;
|
||||
}
|
||||
|
||||
if (buttons2 == 0x08)
|
||||
{
|
||||
//Gear Change 4
|
||||
*(BYTE *)(imageBase + 0x15B468C) = 0x03;
|
||||
}
|
||||
|
||||
if (buttons2 == 0x10)
|
||||
{
|
||||
//View Change 1
|
||||
{
|
||||
*(DWORD *)(imageBase + 0x15B5DB0) = 0x00;
|
||||
}
|
||||
}
|
||||
|
||||
if (buttons2 == 0x20)
|
||||
{
|
||||
//View Change 2
|
||||
{
|
||||
*(DWORD *)(imageBase + 0x15B5DB0) = 0x01;
|
||||
}
|
||||
}
|
||||
|
||||
if (buttons2 == 0x40)
|
||||
{
|
||||
//View Change 3
|
||||
{
|
||||
*(DWORD *)(imageBase + 0x15B5DB0) = 0x02;
|
||||
}
|
||||
}
|
||||
|
||||
if (buttons2 == 0x80)
|
||||
{
|
||||
//View Change 4
|
||||
{
|
||||
*(DWORD *)(imageBase + 0x15B5DB0) = 0x03;
|
||||
}
|
||||
}
|
||||
|
||||
if (buttons2 == 0xF0)
|
||||
{
|
||||
//View Change 5
|
||||
{
|
||||
*(DWORD *)(imageBase + 0x15B5DB0) = 0x04;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int(__stdcall *g_origControlsFunction)();
|
||||
|
||||
int __stdcall ControlsFunction()
|
||||
{
|
||||
int result = g_origControlsFunction();
|
||||
InjectKeys();
|
||||
return result;
|
||||
}
|
||||
|
||||
static InitFunction Daytona3Func([]()
|
||||
{
|
||||
|
||||
imageBase = (uintptr_t)GetModuleHandleA(0);
|
||||
injector::WriteMemoryRaw(imageBase + 0xDD697, "\x90\x90\x90\x90\x90\x90\x38\x05\xC8\xF9\x5A\x01\x90\x90\x90\x90\x90\x90", 18, true);
|
||||
injector::MakeNOP(imageBase + 0x1DDDFA, 5);
|
||||
injector::MakeNOP(imageBase + 0x1DDE1E, 6);
|
||||
injector::MakeNOP(imageBase + 0x1DDE45, 6);
|
||||
injector::MakeNOP(imageBase + 0x1DE10D, 6);
|
||||
injector::MakeNOP(imageBase + 0x29B481, 3);
|
||||
injector::MakeNOP(imageBase + 0x29B513, 4);
|
||||
MH_Initialize();
|
||||
MH_CreateHook((void*)(imageBase + 0x1E9280), ControlsFunction, (void**)&g_origControlsFunction);
|
||||
MH_EnableHook(MH_ALL_HOOKS);
|
||||
|
||||
}, GameID::Daytona3);
|
||||
#include <StdInc.h>
|
||||
#include "Utility/InitFunction.h"
|
||||
#include "Functions/Global.h"
|
||||
#include "Utility\Hooking.Patterns.h"
|
||||
|
||||
#pragma comment(lib, "Ws2_32.lib")
|
||||
|
||||
#ifndef _M_AMD64
|
||||
extern int* wheelSection;
|
||||
extern int* ffbOffset;
|
||||
extern int* ffbOffset2;
|
||||
extern int* ffbOffset3;
|
||||
extern int* ffbOffset4;
|
||||
bool daytonaPressStart = false;
|
||||
uintptr_t imageBase;
|
||||
bool shiftup = false;
|
||||
bool shiftdown = false;
|
||||
|
||||
void ShiftUp(BYTE shift)
|
||||
{
|
||||
*(BYTE *)(imageBase + 0x15B468C) = shift + 1;
|
||||
}
|
||||
|
||||
void ShiftDown(BYTE shift)
|
||||
{
|
||||
*(BYTE *)(imageBase + 0x15B468C) = shift - 1;
|
||||
}
|
||||
|
||||
static void InjectKeys()
|
||||
{
|
||||
|
||||
DWORD buttons2 = *wheelSection;
|
||||
DWORD buttons = *ffbOffset;
|
||||
BYTE wheel = *ffbOffset2;
|
||||
BYTE gas = *ffbOffset3;
|
||||
BYTE brake = *ffbOffset4;
|
||||
|
||||
BYTE gamestate = *(BYTE *)(imageBase + 0x15B5744);
|
||||
BYTE gear = *(BYTE *)(imageBase + 0x15B468C);
|
||||
|
||||
*(BYTE *)(imageBase + 0x15B4679) = gas;
|
||||
*(BYTE *)(imageBase + 0x15B467A) = brake;
|
||||
|
||||
DWORD track = *(DWORD *)(imageBase + 0x011B0148);
|
||||
if (track != 0)
|
||||
{
|
||||
BYTE track1 = *(BYTE *)(track + 0x4);
|
||||
#ifdef _DEBUG
|
||||
info(true, "%02X %02X", track1, gamestate);
|
||||
#endif
|
||||
if ((track1 == 2 || track1 == 4) && (gamestate == 0x16))
|
||||
{
|
||||
BYTE reverse = wheel * 0xFF;
|
||||
if (reverse == 0x00)
|
||||
*(BYTE *)(imageBase + 0x15B4678) = 0xFF;
|
||||
else
|
||||
*(BYTE *)(imageBase + 0x15B4678) = reverse;
|
||||
#ifdef _DEBUG
|
||||
info(true, "Reverse wheel");
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
*(BYTE *)(imageBase + 0x15B4678) = wheel;
|
||||
#ifdef _DEBUG
|
||||
info(true, "Normal wheel1");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
*(BYTE *)(imageBase + 0x15B4678) = wheel;
|
||||
#ifdef _DEBUG
|
||||
info(true, "Normal wheel2");
|
||||
#endif
|
||||
}
|
||||
|
||||
if (gas >= 0x40)
|
||||
{
|
||||
daytonaPressStart = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
daytonaPressStart = false;
|
||||
}
|
||||
|
||||
if (wheel <= 0x40)
|
||||
{
|
||||
//Menu Left
|
||||
DWORD p = *(DWORD *)(imageBase + 0x1AAFFF0);
|
||||
if (p != 0)
|
||||
{
|
||||
DWORD p1 = *(DWORD *)(p + 0x00);
|
||||
if (p1 != 0)
|
||||
{
|
||||
*(BYTE *)(p1 + 0x25) = 0xFF;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (wheel >= 0xC0)
|
||||
{
|
||||
//Menu Right
|
||||
DWORD p = *(DWORD *)(imageBase + 0x1AAFFF0);
|
||||
if (p != 0)
|
||||
{
|
||||
DWORD p1 = *(DWORD *)(p + 0x00);
|
||||
if (p1 != 0)
|
||||
{
|
||||
*(BYTE *)(p1 + 0x27) = 0xFF;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
DWORD p = *(DWORD *)(imageBase + 0x1AAFFF0);
|
||||
if (p != 0)
|
||||
{
|
||||
DWORD p1 = *(DWORD *)(p + 0x00);
|
||||
if (p1 != 0)
|
||||
{
|
||||
*(BYTE *)(p1 + 0x25) = 0x00;
|
||||
*(BYTE *)(p1 + 0x27) = 0x00;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (buttons == 0x01)
|
||||
{
|
||||
//Inject Start
|
||||
DWORD p = *(DWORD *)(imageBase + 0x1AB0010);
|
||||
if (p != 0)
|
||||
{
|
||||
DWORD p1 = *(DWORD *)(p + 0x00);
|
||||
if (p1 != 0)
|
||||
{
|
||||
*(DWORD *)(p1 + 0x08) = 0x01;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
DWORD p = *(DWORD *)(imageBase + 0x1AB0010);
|
||||
if (p != 0)
|
||||
{
|
||||
DWORD p1 = *(DWORD *)(p + 0x00);
|
||||
if (p1 != 0)
|
||||
{
|
||||
*(DWORD *)(p1 + 0x08) = 0x00;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((buttons == 0x02) && (gear < 0x03))
|
||||
{
|
||||
if (!shiftup)
|
||||
{
|
||||
shiftup = true;
|
||||
ShiftUp(*(BYTE *)(imageBase + 0x15B468C));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
shiftup = false;
|
||||
}
|
||||
|
||||
if ((buttons == 0x04) && (gear > 0x00))
|
||||
{
|
||||
if (!shiftdown)
|
||||
{
|
||||
shiftdown = true;
|
||||
ShiftDown(*(BYTE *)(imageBase + 0x15B468C));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
shiftdown = false;
|
||||
}
|
||||
|
||||
if (buttons2 == 0x01)
|
||||
{
|
||||
//Gear Change 1
|
||||
*(BYTE *)(imageBase + 0x15B468C) = 0x00;
|
||||
}
|
||||
|
||||
if (buttons2 == 0x02)
|
||||
{
|
||||
//Gear Change 2
|
||||
*(BYTE *)(imageBase + 0x15B468C) = 0x01;
|
||||
}
|
||||
|
||||
if (buttons2 == 0x04)
|
||||
{
|
||||
//Gear Change 3
|
||||
*(BYTE *)(imageBase + 0x15B468C) = 0x02;
|
||||
}
|
||||
|
||||
if (buttons2 == 0x08)
|
||||
{
|
||||
//Gear Change 4
|
||||
*(BYTE *)(imageBase + 0x15B468C) = 0x03;
|
||||
}
|
||||
|
||||
if (buttons2 == 0x10)
|
||||
{
|
||||
//View Change 1
|
||||
{
|
||||
*(DWORD *)(imageBase + 0x15B5DB0) = 0x00;
|
||||
}
|
||||
}
|
||||
|
||||
if (buttons2 == 0x20)
|
||||
{
|
||||
//View Change 2
|
||||
{
|
||||
*(DWORD *)(imageBase + 0x15B5DB0) = 0x01;
|
||||
}
|
||||
}
|
||||
|
||||
if (buttons2 == 0x40)
|
||||
{
|
||||
//View Change 3
|
||||
{
|
||||
*(DWORD *)(imageBase + 0x15B5DB0) = 0x02;
|
||||
}
|
||||
}
|
||||
|
||||
if (buttons2 == 0x80)
|
||||
{
|
||||
//View Change 4
|
||||
{
|
||||
*(DWORD *)(imageBase + 0x15B5DB0) = 0x03;
|
||||
}
|
||||
}
|
||||
|
||||
if (buttons2 == 0xF0)
|
||||
{
|
||||
//View Change 5
|
||||
{
|
||||
*(DWORD *)(imageBase + 0x15B5DB0) = 0x04;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int(__stdcall *g_origControlsFunction)();
|
||||
|
||||
int __stdcall ControlsFunction()
|
||||
{
|
||||
int result = g_origControlsFunction();
|
||||
InjectKeys();
|
||||
return result;
|
||||
}
|
||||
|
||||
static InitFunction Daytona3Func([]()
|
||||
{
|
||||
imageBase = (uintptr_t)GetModuleHandleA(0);
|
||||
injector::WriteMemoryRaw(imageBase + 0xDD697, "\x90\x90\x90\x90\x90\x90\x38\x05\xC8\xF9\x5A\x01\x90\x90\x90\x90\x90\x90", 18, true);
|
||||
injector::WriteMemoryRaw(imageBase + 0x12958F, "\x33\xC0\x8A\x45\x08\x90\x90\x90\x90\x72\x08\x66\xA3\x46\xFC\x5A\x01\xEB\x06\x66\xA3\x44\xFC\x5A\x01\x31\xFF\x31\xF6\x47\xBE\x0F\x00\x00\x00\xEB\x4C\x90\x90\x90\x90", 41, true);
|
||||
injector::MakeNOP(imageBase + 0x1DDDFA, 5);
|
||||
injector::MakeNOP(imageBase + 0x1DDE1E, 6);
|
||||
injector::MakeNOP(imageBase + 0x1DDE45, 6);
|
||||
injector::MakeNOP(imageBase + 0x1DE10D, 6);
|
||||
injector::MakeNOP(imageBase + 0x29B481, 3);
|
||||
injector::MakeNOP(imageBase + 0x29B513, 4);
|
||||
if (ToBool(config["General"]["MSAA4X Disable"]))
|
||||
{
|
||||
injector::WriteMemoryRaw(imageBase + 0x17CD3D, "\x00", 1, true);
|
||||
}
|
||||
MH_Initialize();
|
||||
MH_CreateHook((void*)(imageBase + 0x1E9280), ControlsFunction, (void**)&g_origControlsFunction);
|
||||
MH_EnableHook(MH_ALL_HOOKS);
|
||||
|
||||
}, GameID::Daytona3);
|
||||
#endif
|
@ -1,359 +1,357 @@
|
||||
#pragma optimize("", off)
|
||||
#include "StdInc.h"
|
||||
#include "Utility/GameDetect.h"
|
||||
#include "Utility/InitFunction.h"
|
||||
#include "PokkenXInputEmu.h"
|
||||
|
||||
struct XboxOneControllerHandler
|
||||
{
|
||||
struct usb_dev_handle *handle;
|
||||
bool isConnected;
|
||||
XBOXONE_STATE controllerState;
|
||||
|
||||
uint8_t lastState[64];
|
||||
unsigned int tickCount;
|
||||
|
||||
XINPUT_GAMEPAD lastGamepadState;
|
||||
};
|
||||
|
||||
XboxOneControllerHandler *controllerHandler[4] = { NULL, NULL, NULL, NULL };
|
||||
HANDLE XboxOneControllerThread[4] = { 0 };
|
||||
HANDLE XboxOneControllerMutex[4] = { 0 };
|
||||
|
||||
static unsigned short idVendor = 0x045E;
|
||||
static unsigned short idProduct = 0x02D1;
|
||||
|
||||
static bool daytonaPressStart = false;
|
||||
|
||||
int configuration = 1;
|
||||
int interface = 0;
|
||||
int endpointIn = 0x81;
|
||||
int endpointOut = 0x01;
|
||||
int timeout = 2000; // milliseconds
|
||||
bool controllerInit = false;
|
||||
bool runThread = true;
|
||||
|
||||
// Structure we receive from the controller
|
||||
struct XboxOneControllerState
|
||||
{
|
||||
char eventCount;
|
||||
char unknown;
|
||||
char buttons1;
|
||||
char buttons2;
|
||||
short leftTrigger; // Triggers are 0 - 1023
|
||||
short rightTrigger;
|
||||
short thumbLX; // Axes are -32767 - 32767
|
||||
short thumbLY;
|
||||
short thumbRX;
|
||||
short thumbRY;
|
||||
};
|
||||
|
||||
bool connectController(bool enable)
|
||||
{
|
||||
controllerInit = enable;
|
||||
return true;
|
||||
}
|
||||
|
||||
int iround(double num) {
|
||||
return (num > 0.0) ? (int)floor(num + 0.5) : (int)ceil(num - 0.5);
|
||||
}
|
||||
|
||||
extern int* ffbOffset;
|
||||
|
||||
DWORD WINAPI XInputGetState
|
||||
(
|
||||
__in DWORD dwUserIndex, // Index of the gamer associated with the device
|
||||
__out XINPUT_STATE* pState // Receives the current state
|
||||
)
|
||||
{
|
||||
if (!controllerInit)
|
||||
{
|
||||
connectController(true);
|
||||
}
|
||||
if (controllerInit && dwUserIndex == 0)
|
||||
{
|
||||
XINPUT_GAMEPAD gamepadState = { 0 };
|
||||
|
||||
if (GameDetect::currentGame == GameID::Daytona3)
|
||||
gamepadState.wButtons |= *ffbOffset;
|
||||
else
|
||||
gamepadState.wButtons |= 0;
|
||||
|
||||
if (GameDetect::currentGame == GameID::Daytona3)
|
||||
{
|
||||
gamepadState.bRightTrigger = daytonaPressStart ? 0xFF : 0x00;
|
||||
}
|
||||
|
||||
if (pState->dwPacketNumber == UINT_MAX)
|
||||
pState->dwPacketNumber = 0;
|
||||
else
|
||||
pState->dwPacketNumber++;
|
||||
|
||||
pState->Gamepad = gamepadState;
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
else
|
||||
{
|
||||
return ERROR_DEVICE_NOT_CONNECTED;
|
||||
}
|
||||
}
|
||||
|
||||
DWORD WINAPI XInputSetState
|
||||
(
|
||||
__in DWORD dwUserIndex, // Index of the gamer associated with the device
|
||||
__in XINPUT_VIBRATION* pVibration // The vibration information to send to the controller
|
||||
)
|
||||
{
|
||||
if (!controllerInit)
|
||||
{
|
||||
connectController(true);
|
||||
}
|
||||
|
||||
if (controllerInit && dwUserIndex == 0)
|
||||
{
|
||||
// We're receiving as XInput [0 ~ 65535], need to be [0 ~ 255] !!
|
||||
int leftVal = iround(((float)pVibration->wLeftMotorSpeed / 65535) * 255);
|
||||
int rightVal = iround(((float)pVibration->wRightMotorSpeed / 65535) * 255);
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
else
|
||||
{
|
||||
return ERROR_DEVICE_NOT_CONNECTED;
|
||||
}
|
||||
}
|
||||
|
||||
DWORD WINAPI XInputGetCapabilities
|
||||
(
|
||||
__in DWORD dwUserIndex, // Index of the gamer associated with the device
|
||||
__in DWORD dwFlags, // Input flags that identify the device type
|
||||
__out XINPUT_CAPABILITIES* pCapabilities // Receives the capabilities
|
||||
)
|
||||
{
|
||||
if (!controllerInit)
|
||||
{
|
||||
connectController(true);
|
||||
}
|
||||
|
||||
if (dwFlags > XINPUT_FLAG_GAMEPAD)
|
||||
{
|
||||
return ERROR_BAD_ARGUMENTS;
|
||||
}
|
||||
|
||||
if (controllerInit && dwUserIndex == 0)
|
||||
{
|
||||
pCapabilities->Flags = XINPUT_CAPS_VOICE_SUPPORTED;
|
||||
pCapabilities->Type = XINPUT_DEVTYPE_GAMEPAD;
|
||||
pCapabilities->SubType = XINPUT_DEVSUBTYPE_GAMEPAD;
|
||||
|
||||
pCapabilities->Gamepad.wButtons = 0xF3FF;
|
||||
|
||||
pCapabilities->Gamepad.bLeftTrigger = 0xFF;
|
||||
pCapabilities->Gamepad.bRightTrigger = 0xFF;
|
||||
|
||||
pCapabilities->Gamepad.sThumbLX = (SHORT)0xFFC0;
|
||||
pCapabilities->Gamepad.sThumbLY = (SHORT)0xFFC0;
|
||||
pCapabilities->Gamepad.sThumbRX = (SHORT)0xFFC0;
|
||||
pCapabilities->Gamepad.sThumbRY = (SHORT)0xFFC0;
|
||||
|
||||
pCapabilities->Vibration.wLeftMotorSpeed = 0xFF;
|
||||
pCapabilities->Vibration.wRightMotorSpeed = 0xFF;
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
else
|
||||
{
|
||||
return ERROR_DEVICE_NOT_CONNECTED;
|
||||
}
|
||||
}
|
||||
|
||||
void WINAPI XInputEnable
|
||||
(
|
||||
__in bool enable // [in] Indicates whether xinput is enabled or disabled.
|
||||
)
|
||||
{
|
||||
if (!controllerInit)
|
||||
{
|
||||
connectController(true);
|
||||
}
|
||||
|
||||
if (controllerInit && !enable)
|
||||
{
|
||||
XINPUT_VIBRATION Vibration = { 0, 0 };
|
||||
int xboxControllerCounter = 0;
|
||||
|
||||
while (xboxControllerCounter < 4)
|
||||
{
|
||||
if (controllerHandler[xboxControllerCounter])
|
||||
{
|
||||
XInputSetState(xboxControllerCounter, &Vibration);
|
||||
}
|
||||
xboxControllerCounter++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DWORD WINAPI XInputGetDSoundAudioDeviceGuids
|
||||
(
|
||||
__in DWORD dwUserIndex, // Index of the gamer associated with the device
|
||||
__out GUID* pDSoundRenderGuid, // DSound device ID for render
|
||||
__out GUID* pDSoundCaptureGuid // DSound device ID for capture
|
||||
)
|
||||
{
|
||||
if (!controllerInit)
|
||||
{
|
||||
connectController(true);
|
||||
}
|
||||
|
||||
if (controllerInit && dwUserIndex == 0)
|
||||
{
|
||||
pDSoundRenderGuid = NULL;
|
||||
pDSoundCaptureGuid = NULL;
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
else
|
||||
{
|
||||
return ERROR_DEVICE_NOT_CONNECTED;
|
||||
}
|
||||
}
|
||||
|
||||
DWORD XInputGetBatteryInformation
|
||||
(
|
||||
__in DWORD dwUserIndex, // Index of the gamer associated with the device
|
||||
__in BYTE devType, // Which device on this user index
|
||||
__out XINPUT_BATTERY_INFORMATION* pBatteryInformation // Contains the level and types of batteries
|
||||
)
|
||||
{
|
||||
if (!controllerInit)
|
||||
{
|
||||
connectController(true);
|
||||
}
|
||||
|
||||
if (controllerInit && dwUserIndex == 0)
|
||||
{
|
||||
pBatteryInformation->BatteryType = BATTERY_TYPE_WIRED;
|
||||
pBatteryInformation->BatteryLevel = BATTERY_LEVEL_FULL;
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
else
|
||||
{
|
||||
return ERROR_DEVICE_NOT_CONNECTED;
|
||||
}
|
||||
}
|
||||
|
||||
DWORD WINAPI XInputGetKeystroke
|
||||
(
|
||||
__in DWORD dwUserIndex, // Index of the gamer associated with the device
|
||||
__reserved DWORD dwReserved, // Reserved for future use
|
||||
__out PXINPUT_KEYSTROKE pKeystroke // Pointer to an XINPUT_KEYSTROKE structure that receives an input event.
|
||||
)
|
||||
{
|
||||
if (!controllerInit)
|
||||
{
|
||||
connectController(true);
|
||||
}
|
||||
|
||||
if (controllerInit && dwUserIndex == 0)
|
||||
{
|
||||
return ERROR_EMPTY; // or ERROR_SUCCESS
|
||||
}
|
||||
else
|
||||
{
|
||||
return ERROR_DEVICE_NOT_CONNECTED;
|
||||
}
|
||||
}
|
||||
|
||||
DWORD WINAPI XInputGetStateEx
|
||||
(
|
||||
__in DWORD dwUserIndex, // Index of the gamer associated with the device
|
||||
__out XINPUT_STATE* pState // Receives the current state
|
||||
)
|
||||
{
|
||||
if (!controllerInit)
|
||||
{
|
||||
connectController(true);
|
||||
}
|
||||
if (controllerInit && dwUserIndex == 0)
|
||||
{
|
||||
XINPUT_GAMEPAD gamepadState = { 0 };
|
||||
|
||||
if (GameDetect::currentGame == GameID::Daytona3)
|
||||
gamepadState.wButtons = *ffbOffset;
|
||||
else
|
||||
gamepadState.wButtons = 0;
|
||||
|
||||
if (GameDetect::currentGame == GameID::Daytona3)
|
||||
{
|
||||
gamepadState.bRightTrigger = daytonaPressStart ? 0xFF : 0x00;
|
||||
}
|
||||
|
||||
if (pState->dwPacketNumber == UINT_MAX)
|
||||
pState->dwPacketNumber = 0;
|
||||
else
|
||||
pState->dwPacketNumber++;
|
||||
pState->Gamepad = gamepadState;
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
else
|
||||
{
|
||||
return ERROR_DEVICE_NOT_CONNECTED;
|
||||
}
|
||||
}
|
||||
|
||||
DWORD WINAPI XInputSetStateEx
|
||||
(
|
||||
__in DWORD dwUserIndex, // Index of the gamer associated with the device
|
||||
__in XINPUT_VIBRATION_EX* pVibration // The vibration information to send to the controller
|
||||
)
|
||||
{
|
||||
if (!controllerInit)
|
||||
{
|
||||
connectController(true);
|
||||
}
|
||||
|
||||
if (controllerInit && dwUserIndex == 0)
|
||||
{
|
||||
int leftTriggerVal = iround(((float)pVibration->wLeftTriggerMotorSpeed / 65535) * 255);
|
||||
int rightTriggerVal = iround(((float)pVibration->wRightTriggerMotorSpeed / 65535) * 255);
|
||||
int leftVal = iround(((float)pVibration->wLeftMotorSpeed / 65535) * 255);
|
||||
int rightVal = iround(((float)pVibration->wRightMotorSpeed / 65535) * 255);
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
else
|
||||
{
|
||||
return ERROR_DEVICE_NOT_CONNECTED;
|
||||
}
|
||||
}
|
||||
|
||||
LPCWSTR libName = L"xinput1_3.dll";
|
||||
LPCWSTR daytonalibName = L"xinput9_1_0.dll";
|
||||
LPCWSTR ptrToUse;
|
||||
|
||||
static InitFunction XInputHook([]()
|
||||
{
|
||||
if (GameDetect::currentGame == GameID::PokkenTournament || GameDetect::currentGame == GameID::SchoolOfRagnarok || GameDetect::currentGame == GameID::Daytona3)
|
||||
{
|
||||
controllerInit = true;
|
||||
|
||||
MH_Initialize();
|
||||
|
||||
if (GameDetect::currentGame == GameID::Daytona3)
|
||||
ptrToUse = daytonalibName;
|
||||
else
|
||||
ptrToUse = libName;
|
||||
|
||||
MH_CreateHookApi(ptrToUse, "XInputGetState", &XInputGetState, NULL);
|
||||
MH_CreateHookApi(ptrToUse, "XInputSetState", &XInputSetState, NULL);
|
||||
MH_CreateHookApi(ptrToUse, "XInputGetCapabilities", &XInputGetCapabilities, NULL);
|
||||
MH_CreateHookApi(ptrToUse, "XInputEnable", &XInputEnable, NULL);
|
||||
MH_CreateHookApi(ptrToUse, "XInputGetDSoundAudioDeviceGuids", &XInputGetDSoundAudioDeviceGuids, NULL);
|
||||
MH_CreateHookApi(ptrToUse, "XInputGetBatteryInformation", &XInputGetBatteryInformation, NULL);
|
||||
MH_CreateHookApi(ptrToUse, "XInputGetKeystroke", &XInputGetKeystroke, NULL);
|
||||
MH_CreateHookApi(ptrToUse, "XInputGetStateEx", &XInputGetStateEx, NULL);
|
||||
MH_CreateHookApi(ptrToUse, "XInputSetStateEx", &XInputSetStateEx, NULL);
|
||||
|
||||
MH_EnableHook(MH_ALL_HOOKS);
|
||||
}
|
||||
});
|
||||
#pragma optimize("", on)
|
||||
#pragma optimize("", off)
|
||||
#include "StdInc.h"
|
||||
#include "Utility/GameDetect.h"
|
||||
#include "Utility/InitFunction.h"
|
||||
#include "PokkenXInputEmu.h"
|
||||
|
||||
struct XboxOneControllerHandler
|
||||
{
|
||||
struct usb_dev_handle *handle;
|
||||
bool isConnected;
|
||||
XBOXONE_STATE controllerState;
|
||||
|
||||
uint8_t lastState[64];
|
||||
unsigned int tickCount;
|
||||
|
||||
XINPUT_GAMEPAD lastGamepadState;
|
||||
};
|
||||
|
||||
XboxOneControllerHandler *controllerHandler[4] = { NULL, NULL, NULL, NULL };
|
||||
HANDLE XboxOneControllerThread[4] = { 0 };
|
||||
HANDLE XboxOneControllerMutex[4] = { 0 };
|
||||
|
||||
static unsigned short idVendor = 0x045E;
|
||||
static unsigned short idProduct = 0x02D1;
|
||||
|
||||
int configuration = 1;
|
||||
int interface = 0;
|
||||
int endpointIn = 0x81;
|
||||
int endpointOut = 0x01;
|
||||
int timeout = 2000; // milliseconds
|
||||
bool controllerInit = false;
|
||||
bool runThread = true;
|
||||
|
||||
// Structure we receive from the controller
|
||||
struct XboxOneControllerState
|
||||
{
|
||||
char eventCount;
|
||||
char unknown;
|
||||
char buttons1;
|
||||
char buttons2;
|
||||
short leftTrigger; // Triggers are 0 - 1023
|
||||
short rightTrigger;
|
||||
short thumbLX; // Axes are -32767 - 32767
|
||||
short thumbLY;
|
||||
short thumbRX;
|
||||
short thumbRY;
|
||||
};
|
||||
|
||||
bool connectController(bool enable)
|
||||
{
|
||||
controllerInit = enable;
|
||||
return true;
|
||||
}
|
||||
|
||||
int iround(double num) {
|
||||
return (num > 0.0) ? (int)floor(num + 0.5) : (int)ceil(num - 0.5);
|
||||
}
|
||||
|
||||
extern int* ffbOffset;
|
||||
|
||||
DWORD WINAPI XInputGetState
|
||||
(
|
||||
__in DWORD dwUserIndex, // Index of the gamer associated with the device
|
||||
__out XINPUT_STATE* pState // Receives the current state
|
||||
)
|
||||
{
|
||||
if (!controllerInit)
|
||||
{
|
||||
connectController(true);
|
||||
}
|
||||
if (controllerInit && dwUserIndex == 0)
|
||||
{
|
||||
XINPUT_GAMEPAD gamepadState = { 0 };
|
||||
|
||||
if (GameDetect::currentGame == GameID::Daytona3)
|
||||
gamepadState.wButtons |= *ffbOffset;
|
||||
else
|
||||
gamepadState.wButtons |= 0;
|
||||
|
||||
if (GameDetect::currentGame == GameID::Daytona3)
|
||||
{
|
||||
gamepadState.bRightTrigger = daytonaPressStart ? 0xFF : 0x00;
|
||||
}
|
||||
|
||||
if (pState->dwPacketNumber == UINT_MAX)
|
||||
pState->dwPacketNumber = 0;
|
||||
else
|
||||
pState->dwPacketNumber++;
|
||||
|
||||
pState->Gamepad = gamepadState;
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
else
|
||||
{
|
||||
return ERROR_DEVICE_NOT_CONNECTED;
|
||||
}
|
||||
}
|
||||
|
||||
DWORD WINAPI XInputSetState
|
||||
(
|
||||
__in DWORD dwUserIndex, // Index of the gamer associated with the device
|
||||
__in XINPUT_VIBRATION* pVibration // The vibration information to send to the controller
|
||||
)
|
||||
{
|
||||
if (!controllerInit)
|
||||
{
|
||||
connectController(true);
|
||||
}
|
||||
|
||||
if (controllerInit && dwUserIndex == 0)
|
||||
{
|
||||
// We're receiving as XInput [0 ~ 65535], need to be [0 ~ 255] !!
|
||||
int leftVal = iround(((float)pVibration->wLeftMotorSpeed / 65535) * 255);
|
||||
int rightVal = iround(((float)pVibration->wRightMotorSpeed / 65535) * 255);
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
else
|
||||
{
|
||||
return ERROR_DEVICE_NOT_CONNECTED;
|
||||
}
|
||||
}
|
||||
|
||||
DWORD WINAPI XInputGetCapabilities
|
||||
(
|
||||
__in DWORD dwUserIndex, // Index of the gamer associated with the device
|
||||
__in DWORD dwFlags, // Input flags that identify the device type
|
||||
__out XINPUT_CAPABILITIES* pCapabilities // Receives the capabilities
|
||||
)
|
||||
{
|
||||
if (!controllerInit)
|
||||
{
|
||||
connectController(true);
|
||||
}
|
||||
|
||||
if (dwFlags > XINPUT_FLAG_GAMEPAD)
|
||||
{
|
||||
return ERROR_BAD_ARGUMENTS;
|
||||
}
|
||||
|
||||
if (controllerInit && dwUserIndex == 0)
|
||||
{
|
||||
pCapabilities->Flags = XINPUT_CAPS_VOICE_SUPPORTED;
|
||||
pCapabilities->Type = XINPUT_DEVTYPE_GAMEPAD;
|
||||
pCapabilities->SubType = XINPUT_DEVSUBTYPE_GAMEPAD;
|
||||
|
||||
pCapabilities->Gamepad.wButtons = 0xF3FF;
|
||||
|
||||
pCapabilities->Gamepad.bLeftTrigger = 0xFF;
|
||||
pCapabilities->Gamepad.bRightTrigger = 0xFF;
|
||||
|
||||
pCapabilities->Gamepad.sThumbLX = (SHORT)0xFFC0;
|
||||
pCapabilities->Gamepad.sThumbLY = (SHORT)0xFFC0;
|
||||
pCapabilities->Gamepad.sThumbRX = (SHORT)0xFFC0;
|
||||
pCapabilities->Gamepad.sThumbRY = (SHORT)0xFFC0;
|
||||
|
||||
pCapabilities->Vibration.wLeftMotorSpeed = 0xFF;
|
||||
pCapabilities->Vibration.wRightMotorSpeed = 0xFF;
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
else
|
||||
{
|
||||
return ERROR_DEVICE_NOT_CONNECTED;
|
||||
}
|
||||
}
|
||||
|
||||
void WINAPI XInputEnable
|
||||
(
|
||||
__in bool enable // [in] Indicates whether xinput is enabled or disabled.
|
||||
)
|
||||
{
|
||||
if (!controllerInit)
|
||||
{
|
||||
connectController(true);
|
||||
}
|
||||
|
||||
if (controllerInit && !enable)
|
||||
{
|
||||
XINPUT_VIBRATION Vibration = { 0, 0 };
|
||||
int xboxControllerCounter = 0;
|
||||
|
||||
while (xboxControllerCounter < 4)
|
||||
{
|
||||
if (controllerHandler[xboxControllerCounter])
|
||||
{
|
||||
XInputSetState(xboxControllerCounter, &Vibration);
|
||||
}
|
||||
xboxControllerCounter++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DWORD WINAPI XInputGetDSoundAudioDeviceGuids
|
||||
(
|
||||
__in DWORD dwUserIndex, // Index of the gamer associated with the device
|
||||
__out GUID* pDSoundRenderGuid, // DSound device ID for render
|
||||
__out GUID* pDSoundCaptureGuid // DSound device ID for capture
|
||||
)
|
||||
{
|
||||
if (!controllerInit)
|
||||
{
|
||||
connectController(true);
|
||||
}
|
||||
|
||||
if (controllerInit && dwUserIndex == 0)
|
||||
{
|
||||
pDSoundRenderGuid = NULL;
|
||||
pDSoundCaptureGuid = NULL;
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
else
|
||||
{
|
||||
return ERROR_DEVICE_NOT_CONNECTED;
|
||||
}
|
||||
}
|
||||
|
||||
DWORD XInputGetBatteryInformation
|
||||
(
|
||||
__in DWORD dwUserIndex, // Index of the gamer associated with the device
|
||||
__in BYTE devType, // Which device on this user index
|
||||
__out XINPUT_BATTERY_INFORMATION* pBatteryInformation // Contains the level and types of batteries
|
||||
)
|
||||
{
|
||||
if (!controllerInit)
|
||||
{
|
||||
connectController(true);
|
||||
}
|
||||
|
||||
if (controllerInit && dwUserIndex == 0)
|
||||
{
|
||||
pBatteryInformation->BatteryType = BATTERY_TYPE_WIRED;
|
||||
pBatteryInformation->BatteryLevel = BATTERY_LEVEL_FULL;
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
else
|
||||
{
|
||||
return ERROR_DEVICE_NOT_CONNECTED;
|
||||
}
|
||||
}
|
||||
|
||||
DWORD WINAPI XInputGetKeystroke
|
||||
(
|
||||
__in DWORD dwUserIndex, // Index of the gamer associated with the device
|
||||
__reserved DWORD dwReserved, // Reserved for future use
|
||||
__out PXINPUT_KEYSTROKE pKeystroke // Pointer to an XINPUT_KEYSTROKE structure that receives an input event.
|
||||
)
|
||||
{
|
||||
if (!controllerInit)
|
||||
{
|
||||
connectController(true);
|
||||
}
|
||||
|
||||
if (controllerInit && dwUserIndex == 0)
|
||||
{
|
||||
return ERROR_EMPTY; // or ERROR_SUCCESS
|
||||
}
|
||||
else
|
||||
{
|
||||
return ERROR_DEVICE_NOT_CONNECTED;
|
||||
}
|
||||
}
|
||||
|
||||
DWORD WINAPI XInputGetStateEx
|
||||
(
|
||||
__in DWORD dwUserIndex, // Index of the gamer associated with the device
|
||||
__out XINPUT_STATE* pState // Receives the current state
|
||||
)
|
||||
{
|
||||
if (!controllerInit)
|
||||
{
|
||||
connectController(true);
|
||||
}
|
||||
if (controllerInit && dwUserIndex == 0)
|
||||
{
|
||||
XINPUT_GAMEPAD gamepadState = { 0 };
|
||||
|
||||
if (GameDetect::currentGame == GameID::Daytona3)
|
||||
gamepadState.wButtons = *ffbOffset;
|
||||
else
|
||||
gamepadState.wButtons = 0;
|
||||
|
||||
if (GameDetect::currentGame == GameID::Daytona3)
|
||||
{
|
||||
gamepadState.bRightTrigger = daytonaPressStart ? 0xFF : 0x00;
|
||||
}
|
||||
|
||||
if (pState->dwPacketNumber == UINT_MAX)
|
||||
pState->dwPacketNumber = 0;
|
||||
else
|
||||
pState->dwPacketNumber++;
|
||||
pState->Gamepad = gamepadState;
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
else
|
||||
{
|
||||
return ERROR_DEVICE_NOT_CONNECTED;
|
||||
}
|
||||
}
|
||||
|
||||
DWORD WINAPI XInputSetStateEx
|
||||
(
|
||||
__in DWORD dwUserIndex, // Index of the gamer associated with the device
|
||||
__in XINPUT_VIBRATION_EX* pVibration // The vibration information to send to the controller
|
||||
)
|
||||
{
|
||||
if (!controllerInit)
|
||||
{
|
||||
connectController(true);
|
||||
}
|
||||
|
||||
if (controllerInit && dwUserIndex == 0)
|
||||
{
|
||||
int leftTriggerVal = iround(((float)pVibration->wLeftTriggerMotorSpeed / 65535) * 255);
|
||||
int rightTriggerVal = iround(((float)pVibration->wRightTriggerMotorSpeed / 65535) * 255);
|
||||
int leftVal = iround(((float)pVibration->wLeftMotorSpeed / 65535) * 255);
|
||||
int rightVal = iround(((float)pVibration->wRightMotorSpeed / 65535) * 255);
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
else
|
||||
{
|
||||
return ERROR_DEVICE_NOT_CONNECTED;
|
||||
}
|
||||
}
|
||||
|
||||
LPCWSTR libName = L"xinput1_3.dll";
|
||||
LPCWSTR daytonalibName = L"xinput9_1_0.dll";
|
||||
LPCWSTR ptrToUse;
|
||||
|
||||
static InitFunction XInputHook([]()
|
||||
{
|
||||
if (GameDetect::currentGame == GameID::PokkenTournament || GameDetect::currentGame == GameID::SchoolOfRagnarok || GameDetect::currentGame == GameID::Daytona3)
|
||||
{
|
||||
controllerInit = true;
|
||||
|
||||
MH_Initialize();
|
||||
|
||||
if (GameDetect::currentGame == GameID::Daytona3)
|
||||
ptrToUse = daytonalibName;
|
||||
else
|
||||
ptrToUse = libName;
|
||||
|
||||
MH_CreateHookApi(ptrToUse, "XInputGetState", &XInputGetState, NULL);
|
||||
MH_CreateHookApi(ptrToUse, "XInputSetState", &XInputSetState, NULL);
|
||||
MH_CreateHookApi(ptrToUse, "XInputGetCapabilities", &XInputGetCapabilities, NULL);
|
||||
MH_CreateHookApi(ptrToUse, "XInputEnable", &XInputEnable, NULL);
|
||||
MH_CreateHookApi(ptrToUse, "XInputGetDSoundAudioDeviceGuids", &XInputGetDSoundAudioDeviceGuids, NULL);
|
||||
MH_CreateHookApi(ptrToUse, "XInputGetBatteryInformation", &XInputGetBatteryInformation, NULL);
|
||||
MH_CreateHookApi(ptrToUse, "XInputGetKeystroke", &XInputGetKeystroke, NULL);
|
||||
MH_CreateHookApi(ptrToUse, "XInputGetStateEx", &XInputGetStateEx, NULL);
|
||||
MH_CreateHookApi(ptrToUse, "XInputSetStateEx", &XInputSetStateEx, NULL);
|
||||
|
||||
MH_EnableHook(MH_ALL_HOOKS);
|
||||
}
|
||||
});
|
||||
#pragma optimize("", on)´
|
||||
|
@ -149,4 +149,6 @@ typedef struct _XINPUT_KEYSTROKE
|
||||
WORD Flags;
|
||||
BYTE UserIndex;
|
||||
BYTE HidCode;
|
||||
} XINPUT_KEYSTROKE, *PXINPUT_KEYSTROKE;
|
||||
} XINPUT_KEYSTROKE, *PXINPUT_KEYSTROKE;
|
||||
|
||||
extern bool daytonaPressStart;
|
Loading…
x
Reference in New Issue
Block a user