#include #include #include #ifdef __GNUC__ #include #else #include #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; }