From bef6e9b4aa64b655e64adc752cd6cb7d870068dc Mon Sep 17 00:00:00 2001 From: Tau Date: Sun, 29 Sep 2019 16:37:02 -0400 Subject: [PATCH] idzio/di-dev.c: Factor out DirectInput device handling --- idzio/di-dev.c | 163 ++++++++++++++++++++++++++++++++++++++++++++++ idzio/di-dev.h | 19 ++++++ idzio/meson.build | 2 + 3 files changed, 184 insertions(+) create mode 100644 idzio/di-dev.c create mode 100644 idzio/di-dev.h diff --git a/idzio/di-dev.c b/idzio/di-dev.c new file mode 100644 index 0000000..6f66bf0 --- /dev/null +++ b/idzio/di-dev.c @@ -0,0 +1,163 @@ +#include +#include + +#include + +#include "idzio/di-dev.h" + +#include "util/dprintf.h" + +HRESULT idz_di_dev_start(IDirectInputDevice8W *dev, HWND wnd) +{ + HRESULT hr; + + assert(dev != NULL); + assert(wnd != NULL); + + hr = IDirectInputDevice8_SetCooperativeLevel( + dev, + wnd, + DISCL_BACKGROUND | DISCL_EXCLUSIVE); + + if (FAILED(hr)) { + dprintf("DirectInput: SetCooperativeLevel failed: %08x\n", (int) hr); + + return hr; + } + + hr = IDirectInputDevice8_SetDataFormat(dev, &c_dfDIJoystick); + + if (FAILED(hr)) { + dprintf("DirectInput: SetDataFormat failed: %08x\n", (int) hr); + + return hr; + } + + hr = IDirectInputDevice8_Acquire(dev); + + if (FAILED(hr)) { + dprintf("DirectInput: Acquire failed: %08x\n", (int) hr); + + return hr; + } + + return hr; +} + +void idz_di_dev_start_fx(IDirectInputDevice8W *dev, IDirectInputEffect **out) +{ + /* Set up force-feedback on devices that support it. This is just a stub + for the time being, since we don't yet know how the serial port force + feedback protocol works. + + I'm currently developing with an Xbox One Thrustmaster TMX wheel, if + we don't perform at least some perfunctory FFB initialization of this + nature (or indeed if no DirectInput application is running) then the + wheel exhibits considerable resistance, similar to that of a stationary + car. Changing cf.lMagnitude to a nonzero value does cause the wheel to + continuously turn in the given direction with the given force as one + would expect (max magnitude per DirectInput docs is +/- 10000). + + Failure here is non-fatal, we log any errors and move on. + + https://docs.microsoft.com/en-us/previous-versions/windows/desktop/ee416353(v=vs.85) + */ + + IDirectInputEffect *obj; + DWORD axis; + LONG direction; + DIEFFECT fx; + DICONSTANTFORCE cf; + HRESULT hr; + + assert(dev != NULL); + assert(out != NULL); + + *out = NULL; + + dprintf("DirectInput: Starting force feedback (may take a sec)\n"); + + axis = DIJOFS_X; + direction = 0; + + memset(&cf, 0, sizeof(cf)); + cf.lMagnitude = 0; + + memset(&fx, 0, sizeof(fx)); + fx.dwSize = sizeof(fx); + fx.dwFlags = DIEFF_CARTESIAN | DIEFF_OBJECTOFFSETS; + fx.dwDuration = INFINITE; + fx.dwGain = DI_FFNOMINALMAX; + fx.dwTriggerButton = DIEB_NOTRIGGER; + fx.dwTriggerRepeatInterval = INFINITE; + fx.cAxes = 1; + fx.rgdwAxes = &axis; + fx.rglDirection = &direction; + fx.cbTypeSpecificParams = sizeof(cf); + fx.lpvTypeSpecificParams = &cf; + + hr = IDirectInputDevice8_CreateEffect( + dev, + &GUID_ConstantForce, + &fx, + &obj, + NULL); + + if (FAILED(hr)) { + dprintf("DirectInput: DirectInput force feedback unavailable: %08x\n", + (int) hr); + + return; + } + + hr = IDirectInputEffect_Start(obj, INFINITE, 0); + + if (FAILED(hr)) { + IDirectInputEffect_Release(obj); + dprintf("DirectInput: DirectInput force feedback start failed: %08x\n", + (int) hr); + + return; + } + + *out = obj; + + dprintf("DirectInput: Force feedback initialized and set to zero\n"); +} + +HRESULT idz_di_dev_poll( + IDirectInputDevice8W *dev, + HWND wnd, + union idz_di_state *out) +{ + HRESULT hr; + MSG msg; + + assert(dev != NULL); + assert(wnd != NULL); + assert(out != NULL); + + memset(out, 0, sizeof(*out)); + + /* Pump our dummy window's message queue just in case DirectInput or an + IHV DirectInput driver somehow relies on it */ + + while (PeekMessageW(&msg, wnd, 0, 0, PM_REMOVE)) { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + + hr = IDirectInputDevice8_GetDeviceState( + dev, + sizeof(out->st), + &out->st); + + if (FAILED(hr)) { + dprintf("DirectInput: GetDeviceState error: %08x\n", (int) hr); + } + + /* JVS lacks a protocol for reporting hardware errors from poll command + responses, so this ends up returning zeroed input state instead. */ + + return hr; +} diff --git a/idzio/di-dev.h b/idzio/di-dev.h new file mode 100644 index 0000000..9c8b2d2 --- /dev/null +++ b/idzio/di-dev.h @@ -0,0 +1,19 @@ +#pragma once + +#include +#include + +#include + +union idz_di_state { + DIJOYSTATE st; + uint8_t bytes[sizeof(DIJOYSTATE)]; +}; + +HRESULT idz_di_dev_start(IDirectInputDevice8W *dev, HWND wnd); +void idz_di_dev_start_fx(IDirectInputDevice8W *dev, IDirectInputEffect **out); +HRESULT idz_di_dev_poll( + IDirectInputDevice8W *dev, + HWND wnd, + union idz_di_state *out); + diff --git a/idzio/meson.build b/idzio/meson.build index 15fdc4b..ce1668c 100644 --- a/idzio/meson.build +++ b/idzio/meson.build @@ -19,6 +19,8 @@ idzio_dll = shared_library( 'config.h', 'di.c', 'di.h', + 'di-dev.c', + 'di-dev.h', 'dllmain.c', 'idzio.h', 'shifter.c',