bananatools/ferrumhook/xinput.c

154 lines
4.5 KiB
C

#include <windows.h>
#include <xinput.h>
#include <stdint.h>
#ifdef __GNUC__
#include <ntdef.h>
#else
#include <winnt.h>
#endif
#include "hook/table.h"
#include "ferrumhook/xinput.h"
#include "ferrumhook/ferrum-dll.h"
#include "util/dprintf.h"
#include "util/str.h"
static DWORD WINAPI my_XInputGetCapabilities(DWORD dwUserIndex, DWORD dwFlags, XINPUT_CAPABILITIES *pCapabilities);
static DWORD WINAPI my_XInputGetState(DWORD dwUserIndex, XINPUT_STATE *pState);
static DWORD WINAPI my_XInputSetState(DWORD dwUserIndex, XINPUT_VIBRATION *pVibration);
static DWORD my_driverUtilGetControllerUsbIdPairs(uint64_t qwUnknown, unsigned int *numControllers);
static DWORD (WINAPI *next_XInputGetCapabilities)(DWORD dwUserIndex, DWORD dwFlags, XINPUT_CAPABILITIES *pCapabilities);
static DWORD (WINAPI *next_XInputGetState)(DWORD dwUserIndex, DWORD dwFlags, XINPUT_CAPABILITIES *pCapabilities);
static DWORD (WINAPI *next_XInputSetState)(DWORD dwUserIndex, DWORD dwFlags, XINPUT_CAPABILITIES *pCapabilities);
static DWORD (*next_driverUtilGetControllerUsbIdPairs)(uint64_t qwUnknown, unsigned int *numControllers);
uint8_t lastBtnState = 0;
DWORD packetNum = 0;
static const struct hook_symbol xinput_hook_syms[] = {
{
.ordinal = 4,
.patch = my_XInputGetCapabilities,
.link = (void **) &next_XInputGetCapabilities,
}, {
.ordinal = 2,
.patch = my_XInputGetState,
.link = (void **) &next_XInputGetState,
}, {
.ordinal = 3,
.patch = my_XInputSetState,
.link = (void **) &next_XInputSetState,
},
};
static const struct hook_symbol driverutil_hook_syms[] = {
{
.name = "driverUtilGetControllerUsbIdPairs",
.ordinal = 1,
.patch = my_driverUtilGetControllerUsbIdPairs,
.link = (void **) &next_driverUtilGetControllerUsbIdPairs,
}
};
HRESULT ferrum_xinput_init(struct ferrum_xinput_config *cfg)
{
if (!cfg->enable) {
dprintf("Xinput: Emulation disabled\n");
return S_OK;
}
dprintf("Xinput: init\n");
hook_table_apply(
NULL,
"XINPUT1_3.dll",
xinput_hook_syms,
_countof(xinput_hook_syms));
hook_table_apply(
NULL,
"driverUtil.dll",
driverutil_hook_syms,
_countof(driverutil_hook_syms));
return S_OK;
}
static DWORD WINAPI my_XInputGetCapabilities(DWORD dwUserIndex, DWORD dwFlags, XINPUT_CAPABILITIES *pCapabilities)
{
//dprintf("Xinput: %s dwUserIndex %li dwFlags %li \n", __func__, dwUserIndex, dwFlags);
if (!dwUserIndex) {
HRESULT hr = ferrum_dll.gamepad_init();
if (FAILED(hr)) {
return ERROR_DEVICE_NOT_CONNECTED;
}
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;
}
}
static DWORD WINAPI my_XInputGetState(DWORD dwUserIndex, XINPUT_STATE *pState)
{
//dprintf("Xinput: %s dwUserIndex %li\n", __func__, dwUserIndex);
assert(ferrum_dll.gamepad_poll != NULL);
if (!dwUserIndex) {
uint16_t gamebtn = 0;
ferrum_dll.gamepad_poll(&gamebtn);
pState->Gamepad.wButtons = gamebtn;
if (gamebtn == lastBtnState) {
pState->dwPacketNumber = packetNum;
} else {
pState->dwPacketNumber = packetNum++;
}
return ERROR_SUCCESS;
}
else {
return ERROR_DEVICE_NOT_CONNECTED;
}
}
static DWORD WINAPI my_XInputSetState(DWORD dwUserIndex, XINPUT_VIBRATION *pVibration)
{
//dprintf("Xinput: %s dwUserIndex %li left %i right %i\n", __func__, dwUserIndex, pVibration->wLeftMotorSpeed, pVibration->wRightMotorSpeed);
if (!dwUserIndex)
return ERROR_SUCCESS;
else
return ERROR_DEVICE_NOT_CONNECTED;
}
static DWORD my_driverUtilGetControllerUsbIdPairs(uint64_t qwUnknown, unsigned int *numControllers)
{
dprintf("Xinput: %s hit!\n", __func__);
return 1;
}