diff --git a/Module.mk b/Module.mk index d0f58e4..215fcb6 100644 --- a/Module.mk +++ b/Module.mk @@ -89,6 +89,7 @@ include src/main/ddrhook/Module.mk include src/main/ddrio/Module.mk include src/main/ddrio-smx/Module.mk include src/main/ddrio-mm/Module.mk +include src/main/dinputhook/Module.mk include src/main/eamio/Module.mk include src/main/eamio-icca/Module.mk include src/main/eamiotest/Module.mk diff --git a/src/main/dinputhook/Module.mk b/src/main/dinputhook/Module.mk new file mode 100644 index 0000000..3893c30 --- /dev/null +++ b/src/main/dinputhook/Module.mk @@ -0,0 +1,10 @@ +libs += dinputhook + +libs_dinputhook := \ + hook \ + hooklib \ + util \ + +src_dinputhook := \ + dinput.c \ + device_dinput8.c \ diff --git a/src/main/dinputhook/device_dinput8.c b/src/main/dinputhook/device_dinput8.c new file mode 100644 index 0000000..d054667 --- /dev/null +++ b/src/main/dinputhook/device_dinput8.c @@ -0,0 +1,280 @@ +#include "dinputhook/device_dinput8.h" + +static ULONG REF_COUNT = 0; + +static HRESULT STDMETHODCALLTYPE IDirectInputDevice8W_QueryInterface( + IDirectInputDevice8W FAR *This, REFIID riid, void **ppvObj) +{ + if (ppvObj == NULL) { + return E_POINTER; + } + + if (IsEqualGUID(riid, &IID_IUnknown) || + IsEqualGUID(riid, &IID_IDirectInputDeviceA) || + IsEqualGUID(riid, &IID_IDirectInputDeviceW) || + IsEqualGUID(riid, &IID_IDirectInputDevice2A) || + IsEqualGUID(riid, &IID_IDirectInputDevice2W) || + IsEqualGUID(riid, &IID_IDirectInputDevice7A) || + IsEqualGUID(riid, &IID_IDirectInputDevice7W) || + IsEqualGUID(riid, &IID_IDirectInputDevice8A) || + IsEqualGUID(riid, &IID_IDirectInputDevice8W)) { + This->lpVtbl->AddRef(This); + *ppvObj = This; + + return S_OK; + } + + return E_NOINTERFACE; +} +static ULONG STDMETHODCALLTYPE +IDirectInputDevice8W_AddRef(IDirectInputDevice8W FAR *This) +{ + return ++REF_COUNT; +} +static ULONG STDMETHODCALLTYPE +IDirectInputDevice8W_Release(IDirectInputDevice8W FAR *This) +{ + return --REF_COUNT; +} + +static HRESULT STDMETHODCALLTYPE IDirectInputDevice8W_GetCapabilities( + IDirectInputDevice8W FAR *This, LPDIDEVCAPS lpDIDevCaps) +{ + return DIERR_INVALIDPARAM; +} +static HRESULT STDMETHODCALLTYPE IDirectInputDevice8W_EnumObjects( + IDirectInputDevice8W FAR *This, + LPDIENUMDEVICEOBJECTSCALLBACKW lpCallback, + LPVOID pvRef, + DWORD dwFlags) +{ + return DIERR_INVALIDPARAM; +} +static HRESULT STDMETHODCALLTYPE IDirectInputDevice8W_GetProperty( + IDirectInputDevice8W FAR *This, REFGUID rguidProp, LPDIPROPHEADER pdiph) +{ + return DIERR_INVALIDPARAM; +} +static HRESULT STDMETHODCALLTYPE IDirectInputDevice8W_SetProperty( + IDirectInputDevice8W FAR *This, REFGUID rguidProp, LPCDIPROPHEADER pdiph) +{ + return DI_OK; +} +static HRESULT STDMETHODCALLTYPE +IDirectInputDevice8W_Acquire(IDirectInputDevice8W FAR *This) +{ + return DIERR_INVALIDPARAM; +} +static HRESULT STDMETHODCALLTYPE +IDirectInputDevice8W_Unacquire(IDirectInputDevice8W FAR *This) +{ + return DIERR_INVALIDPARAM; +} +static HRESULT STDMETHODCALLTYPE IDirectInputDevice8W_GetDeviceState( + IDirectInputDevice8W FAR *This, DWORD cbData, LPVOID lpvData) +{ + return DIERR_INVALIDPARAM; +} +static HRESULT STDMETHODCALLTYPE IDirectInputDevice8W_GetDeviceData( + IDirectInputDevice8W FAR *This, + DWORD cbObjectData, + LPDIDEVICEOBJECTDATA rgdod, + LPDWORD pdwInOut, + DWORD dwFlags) +{ + return DIERR_INVALIDPARAM; +} +static HRESULT STDMETHODCALLTYPE IDirectInputDevice8W_SetDataFormat( + IDirectInputDevice8W FAR *This, LPCDIDATAFORMAT lpdf) +{ + return DI_OK; +} +static HRESULT STDMETHODCALLTYPE IDirectInputDevice8W_SetEventNotification( + IDirectInputDevice8W FAR *This, HANDLE hEvent) +{ + return DIERR_INVALIDPARAM; +} +static HRESULT STDMETHODCALLTYPE IDirectInputDevice8W_SetCooperativeLevel( + IDirectInputDevice8W FAR *This, HWND hWnd, DWORD dwFlags) +{ + return DI_OK; +} +static HRESULT STDMETHODCALLTYPE IDirectInputDevice8W_GetObjectInfo( + IDirectInputDevice8W FAR *This, + LPDIDEVICEOBJECTINSTANCEW pdidoi, + DWORD dwObj, + DWORD dwHow) +{ + return DIERR_INVALIDPARAM; +} +static HRESULT STDMETHODCALLTYPE IDirectInputDevice8W_GetDeviceInfo( + IDirectInputDevice8W FAR *This, LPDIDEVICEINSTANCEW pdidi) +{ + return DIERR_INVALIDPARAM; +} +static HRESULT STDMETHODCALLTYPE IDirectInputDevice8W_RunControlPanel( + IDirectInputDevice8W FAR *This, HWND hwndOwner, DWORD dwFlags) +{ + return DIERR_INVALIDPARAM; +} +static HRESULT STDMETHODCALLTYPE IDirectInputDevice8W_Initialize( + IDirectInputDevice8W FAR *This, + HINSTANCE hinst, + DWORD dwVersion, + REFGUID rguid) +{ + return DIERR_INVALIDPARAM; +} + +static HRESULT STDMETHODCALLTYPE IDirectInputDevice8W_CreateEffect( + IDirectInputDevice8W FAR *This, + REFGUID rguid, + LPCDIEFFECT lpeff, + LPDIRECTINPUTEFFECT *ppdeff, + LPUNKNOWN punkOuter) +{ + return DIERR_INVALIDPARAM; +} +static HRESULT STDMETHODCALLTYPE IDirectInputDevice8W_EnumEffects( + IDirectInputDevice8W FAR *This, + LPDIENUMEFFECTSCALLBACKW lpCallback, + LPVOID pvRef, + DWORD dwEffType) +{ + return DIERR_INVALIDPARAM; +} +static HRESULT STDMETHODCALLTYPE IDirectInputDevice8W_GetEffectInfo( + IDirectInputDevice8W FAR *This, LPDIEFFECTINFOW pdei, REFGUID rguid) +{ + return DIERR_INVALIDPARAM; +} +static HRESULT STDMETHODCALLTYPE IDirectInputDevice8W_GetForceFeedbackState( + IDirectInputDevice8W FAR *This, LPDWORD pdwOut) +{ + return DIERR_INVALIDPARAM; +} +static HRESULT STDMETHODCALLTYPE IDirectInputDevice8W_SendForceFeedbackCommand( + IDirectInputDevice8W FAR *This, DWORD dwFlags) +{ + return DIERR_INVALIDPARAM; +} +static HRESULT STDMETHODCALLTYPE IDirectInputDevice8W_EnumCreatedEffectObjects( + IDirectInputDevice8W FAR *This, + LPDIENUMCREATEDEFFECTOBJECTSCALLBACK lpCallback, + LPVOID pvRef, + DWORD fl) +{ + return DIERR_INVALIDPARAM; +} +static HRESULT STDMETHODCALLTYPE +IDirectInputDevice8W_Escape(IDirectInputDevice8W FAR *This, LPDIEFFESCAPE pesc) +{ + return DIERR_INVALIDPARAM; +} +static HRESULT STDMETHODCALLTYPE +IDirectInputDevice8W_Poll(IDirectInputDevice8W FAR *This) +{ + return DIERR_INVALIDPARAM; +} +static HRESULT STDMETHODCALLTYPE IDirectInputDevice8W_SendDeviceData( + IDirectInputDevice8W FAR *This, + DWORD cbObjectData, + LPCDIDEVICEOBJECTDATA rgdod, + LPDWORD pdwInOut, + DWORD fl) +{ + return DIERR_INVALIDPARAM; +} + +static HRESULT STDMETHODCALLTYPE IDirectInputDevice8W_EnumEffectsInFile( + IDirectInputDevice8W FAR *This, + LPCWSTR lpszFileName, + LPDIENUMEFFECTSINFILECALLBACK pec, + LPVOID pvRef, + DWORD dwFlags) +{ + return DIERR_INVALIDPARAM; +} +static HRESULT STDMETHODCALLTYPE IDirectInputDevice8W_WriteEffectToFile( + IDirectInputDevice8W FAR *This, + LPCWSTR lpszFileName, + DWORD dwEntries, + LPDIFILEEFFECT rgDiFileEft, + DWORD dwFlags) +{ + return DIERR_INVALIDPARAM; +} + +static HRESULT STDMETHODCALLTYPE IDirectInputDevice8W_BuildActionMap( + IDirectInputDevice8W FAR *This, + LPDIACTIONFORMATW lpdiaf, + LPCWSTR lpszUserName, + DWORD dwFlags) +{ + return DIERR_INVALIDPARAM; +} +static HRESULT STDMETHODCALLTYPE IDirectInputDevice8W_SetActionMap( + IDirectInputDevice8W FAR *This, + LPDIACTIONFORMATW lpdiaf, + LPCWSTR lpszUserName, + DWORD dwFlags) +{ + return DIERR_INVALIDPARAM; +} +static HRESULT STDMETHODCALLTYPE IDirectInputDevice8W_GetImageInfo( + IDirectInputDevice8W FAR *This, + LPDIDEVICEIMAGEINFOHEADERW lpdiDevImageInfoHeader) +{ + return DIERR_INVALIDPARAM; +} + +static IDirectInputDevice8WVtbl stub_device_vtbl = { + + // IUnknown + .QueryInterface = IDirectInputDevice8W_QueryInterface, + .AddRef = IDirectInputDevice8W_AddRef, + .Release = IDirectInputDevice8W_Release, + + // IDirectInputDeviceW + .GetCapabilities = IDirectInputDevice8W_GetCapabilities, + .EnumObjects = IDirectInputDevice8W_EnumObjects, + .GetProperty = IDirectInputDevice8W_GetProperty, + .SetProperty = IDirectInputDevice8W_SetProperty, + .Acquire = IDirectInputDevice8W_Acquire, + .Unacquire = IDirectInputDevice8W_Unacquire, + .GetDeviceState = IDirectInputDevice8W_GetDeviceState, + .GetDeviceData = IDirectInputDevice8W_GetDeviceData, + .SetDataFormat = IDirectInputDevice8W_SetDataFormat, + .SetEventNotification = IDirectInputDevice8W_SetEventNotification, + .SetCooperativeLevel = IDirectInputDevice8W_SetCooperativeLevel, + .GetObjectInfo = IDirectInputDevice8W_GetObjectInfo, + .GetDeviceInfo = IDirectInputDevice8W_GetDeviceInfo, + .RunControlPanel = IDirectInputDevice8W_RunControlPanel, + .Initialize = IDirectInputDevice8W_Initialize, + + // IDirectInputDevice2W + .CreateEffect = IDirectInputDevice8W_CreateEffect, + .EnumEffects = IDirectInputDevice8W_EnumEffects, + .GetEffectInfo = IDirectInputDevice8W_GetEffectInfo, + .GetForceFeedbackState = IDirectInputDevice8W_GetForceFeedbackState, + .SendForceFeedbackCommand = IDirectInputDevice8W_SendForceFeedbackCommand, + .EnumCreatedEffectObjects = IDirectInputDevice8W_EnumCreatedEffectObjects, + .Escape = IDirectInputDevice8W_Escape, + .Poll = IDirectInputDevice8W_Poll, + .SendDeviceData = IDirectInputDevice8W_SendDeviceData, + + // IDirectInputDevice7W + .EnumEffectsInFile = IDirectInputDevice8W_EnumEffectsInFile, + .WriteEffectToFile = IDirectInputDevice8W_WriteEffectToFile, + + // IDirectInputDevice8W + .BuildActionMap = IDirectInputDevice8W_BuildActionMap, + .SetActionMap = IDirectInputDevice8W_SetActionMap, + .GetImageInfo = IDirectInputDevice8W_GetImageInfo, +}; + +static IDirectInputDevice8W stub_device_object = { + .lpVtbl = &stub_device_vtbl, +}; + +IDirectInputDevice8W *di8_stub_device = &stub_device_object; diff --git a/src/main/dinputhook/device_dinput8.h b/src/main/dinputhook/device_dinput8.h new file mode 100644 index 0000000..385914d --- /dev/null +++ b/src/main/dinputhook/device_dinput8.h @@ -0,0 +1,10 @@ +#ifndef DINPUTHOOK_DEVICES_DINPUT8_H +#define DINPUTHOOK_DEVICES_DINPUT8_H + +#include + +#include + +extern IDirectInputDevice8W *di8_stub_device; + +#endif diff --git a/src/main/dinputhook/dinput.c b/src/main/dinputhook/dinput.c new file mode 100644 index 0000000..abe8bce --- /dev/null +++ b/src/main/dinputhook/dinput.c @@ -0,0 +1,111 @@ +#include + +#define DIRECTINPUT_VERSION 0x0800 +#include + +#include "dinputhook/device_dinput8.h" +#include "dinputhook/dinput.h" + +#include + +#include "hook/com-proxy.h" +#include "hook/pe.h" +#include "hook/table.h" + +#include "util/defs.h" +#include "util/log.h" + +static HRESULT STDCALL my_DirectInput8Create( + HINSTANCE hinst, + DWORD dwVersion, + REFIID riidltf, + LPVOID *ppvOut, + LPVOID punkOuter); + +static HRESULT(STDCALL *real_DirectInput8Create)( + HINSTANCE hinst, + DWORD dwVersion, + REFIID riidltf, + LPVOID *ppvOut, + LPVOID punkOuter); + +static const struct hook_symbol dinput_syms[] = { + { + .name = "DirectInput8Create", + .patch = my_DirectInput8Create, + .link = (void **) &real_DirectInput8Create, + }, +}; + +static HRESULT STDCALL my_CreateDevice( + IDirectInput8W *self, + REFGUID rguid, + LPDIRECTINPUTDEVICE8W *lplpDirectInputDevice, + LPUNKNOWN pUnkOuter) +{ + log_misc("IDirectInput8::CreateDevice hook hit"); + if (lplpDirectInputDevice == NULL) { + return DIERR_INVALIDPARAM; + } + + if (IsEqualGUID(rguid, &GUID_SysKeyboard) || + IsEqualGUID(rguid, &GUID_SysMouse)) { + log_misc("Returning stub device"); + + *lplpDirectInputDevice = di8_stub_device; + di8_stub_device->lpVtbl->AddRef(di8_stub_device); + + return DI_OK; + } + + return DIERR_NOINTERFACE; +} + +static HRESULT STDCALL my_EnumDevices( + IDirectInput8W *self, + DWORD dwDevType, + LPDIENUMDEVICESCALLBACKW lpCallback, + LPVOID pvRef, + DWORD dwFlags) +{ + log_misc("IDirectInput8::EnumDevices hook hit"); + + return DI_OK; +} + +static HRESULT STDCALL my_DirectInput8Create( + HINSTANCE hinst, + DWORD dwVersion, + REFIID riidltf, + LPVOID *ppvOut, + LPVOID punkOuter) +{ + IDirectInput8W *api; + IDirectInput8WVtbl *api_vtbl; + struct com_proxy *api_proxy; + HRESULT res; + + log_info("DirectInput8Create hook hit"); + + res = real_DirectInput8Create( + hinst, dwVersion, riidltf, (LPVOID *) &api, punkOuter); + if (res != DI_OK) { + return res; + } + api_proxy = com_proxy_wrap(api, sizeof(*api->lpVtbl)); + api_vtbl = api_proxy->vptr; + + api_vtbl->EnumDevices = my_EnumDevices; + api_vtbl->CreateDevice = my_CreateDevice; + + *(IDirectInput8W **) ppvOut = (IDirectInput8W *) api_proxy; + + return res; +} + +void dinput_init(void) +{ + hook_table_apply(NULL, "dinput8.dll", dinput_syms, lengthof(dinput_syms)); + + log_info("Inserted dinput hooks"); +} diff --git a/src/main/dinputhook/dinput.h b/src/main/dinputhook/dinput.h new file mode 100644 index 0000000..3715530 --- /dev/null +++ b/src/main/dinputhook/dinput.h @@ -0,0 +1,10 @@ +#ifndef DINPUTHOOK_DINPUT_H +#define DINPUTHOOK_DINPUT_H + +#include + +// This is to stub out the dinput device +// Such that rawinput can still poll keyboards +void dinput_init(void); + +#endif