From bbe37bfb4044371e53ebf5671f79d14b9b6912a0 Mon Sep 17 00:00:00 2001 From: puniru Date: Tue, 8 Sep 2026 13:47:23 +0000 Subject: [PATCH] idac, idz, swdc: recover dinput device during gameplay (#134) This PR adds a feature that lets the segatools reacquire dinput device if it disconnects during gameplay. Before this if dinput device disconnects for any reason then it would require user to restart the game since segatools doesn't attempt to reacquire the same dinput device it launched with. Reviewed-on: https://gitea.tendokyu.moe/TeamTofuShop/segatools/pulls/134 Co-authored-by: puniru --- games/idacio/di-dev.c | 30 ++++++++++++++++++++++++++++++ games/idacio/dllmain.c | 2 +- games/idzio/di-dev.c | 29 +++++++++++++++++++++++++++++ games/idzio/dllmain.c | 2 +- games/swdcio/di-dev.c | 30 ++++++++++++++++++++++++++++++ games/swdcio/dllmain.c | 2 +- 6 files changed, 92 insertions(+), 3 deletions(-) diff --git a/games/idacio/di-dev.c b/games/idacio/di-dev.c index a7758df..18fa6dc 100644 --- a/games/idacio/di-dev.c +++ b/games/idacio/di-dev.c @@ -14,6 +14,13 @@ static IDirectInputDevice8W* idac_di_dev = NULL; static void update_or_create_effect(LPDIRECTINPUTEFFECT* effect_ptr, REFGUID guid, DIEFFECT* fx); +static bool idac_di_dev_state_lost(HRESULT hr) +{ + return hr == DIERR_INPUTLOST + || hr == DIERR_NOTACQUIRED + || hr == DIERR_UNPLUGGED; +} + /* Effect handles */ static IDirectInputEffect* idac_di_fx_constant = NULL; static IDirectInputEffect* idac_di_fx_rumble = NULL; @@ -115,6 +122,29 @@ HRESULT idac_di_dev_poll(IDirectInputDevice8W* dev, HWND wnd, } hr = IDirectInputDevice8_GetDeviceState(dev, sizeof(out->st), &out->st); + + if (FAILED(hr) && idac_di_dev_state_lost(hr)) { + HRESULT acquire_hr; + + dprintf("DirectInput: Device lost (%08x), attempting to reacquire\n", + (int) hr); + + acquire_hr = IDirectInputDevice8_Acquire(dev); + + if (SUCCEEDED(acquire_hr)) { + hr = IDirectInputDevice8_GetDeviceState( + dev, + sizeof(out->st), + &out->st); + + if (SUCCEEDED(hr)) { + dprintf("DirectInput: Device reacquired\n"); + } + } else { + dprintf("DirectInput: Acquire failed: %08x\n", (int) acquire_hr); + } + } + if (FAILED(hr)) { dprintf("DirectInput: GetDeviceState error: %08x\n", (int)hr); } diff --git a/games/idacio/dllmain.c b/games/idacio/dllmain.c index fe8246e..03eceb2 100644 --- a/games/idacio/dllmain.c +++ b/games/idacio/dllmain.c @@ -104,7 +104,7 @@ void idac_io_get_shifter(uint8_t *gear) void idac_io_get_analogs(struct idac_io_analog_state *out) { - struct idac_io_analog_state tmp; + struct idac_io_analog_state tmp = { 0 }; assert(out != NULL); assert(idac_io_backend != NULL); diff --git a/games/idzio/di-dev.c b/games/idzio/di-dev.c index 84fc364..a5ca4ac 100644 --- a/games/idzio/di-dev.c +++ b/games/idzio/di-dev.c @@ -13,6 +13,13 @@ static IDirectInputDevice8W* idz_di_dev = NULL; static void update_or_create_effect(LPDIRECTINPUTEFFECT* effect_ptr, REFGUID guid, DIEFFECT* fx); +static bool idz_di_dev_state_lost(HRESULT hr) +{ + return hr == DIERR_INPUTLOST + || hr == DIERR_NOTACQUIRED + || hr == DIERR_UNPLUGGED; +} + /* Individual DI Effects */ static IDirectInputEffect* idz_di_fx_constant = NULL; static IDirectInputEffect* idz_di_fx_rumble = NULL; @@ -122,6 +129,28 @@ HRESULT idz_di_dev_poll(IDirectInputDevice8W* dev, HWND wnd, hr = IDirectInputDevice8_GetDeviceState(dev, sizeof(out->st), &out->st); + if (FAILED(hr) && idz_di_dev_state_lost(hr)) { + HRESULT acquire_hr; + + dprintf("DirectInput: Device lost (%08x), attempting to reacquire\n", + (int) hr); + + acquire_hr = IDirectInputDevice8_Acquire(dev); + + if (SUCCEEDED(acquire_hr)) { + hr = IDirectInputDevice8_GetDeviceState( + dev, + sizeof(out->st), + &out->st); + + if (SUCCEEDED(hr)) { + dprintf("DirectInput: Device reacquired\n"); + } + } else { + dprintf("DirectInput: Acquire failed: %08x\n", (int) acquire_hr); + } + } + if (FAILED(hr)) { dprintf("DirectInput: GetDeviceState error: %08x\n", (int)hr); } diff --git a/games/idzio/dllmain.c b/games/idzio/dllmain.c index 322d194..e3740fa 100644 --- a/games/idzio/dllmain.c +++ b/games/idzio/dllmain.c @@ -88,7 +88,7 @@ void idz_io_jvs_read_shifter(uint8_t *gear) void idz_io_jvs_read_analogs(struct idz_io_analog_state *out) { - struct idz_io_analog_state tmp; + struct idz_io_analog_state tmp = { 0 }; assert(out != NULL); assert(idz_io_backend != NULL); diff --git a/games/swdcio/di-dev.c b/games/swdcio/di-dev.c index 2343347..0b59f6d 100644 --- a/games/swdcio/di-dev.c +++ b/games/swdcio/di-dev.c @@ -14,6 +14,13 @@ static IDirectInputDevice8W* swdc_di_dev = NULL; static void update_or_create_effect(LPDIRECTINPUTEFFECT* effect_ptr, REFGUID guid, DIEFFECT* fx); +static bool swdc_di_dev_state_lost(HRESULT hr) +{ + return hr == DIERR_INPUTLOST + || hr == DIERR_NOTACQUIRED + || hr == DIERR_UNPLUGGED; +} + /* Individual DI Effects */ static IDirectInputEffect* swdc_di_fx_constant = NULL; static IDirectInputEffect* swdc_di_fx_rumble = NULL; @@ -116,6 +123,29 @@ HRESULT swdc_di_dev_poll(IDirectInputDevice8W* dev, HWND wnd, } hr = IDirectInputDevice8_GetDeviceState(dev, sizeof(out->st), &out->st); + + if (FAILED(hr) && swdc_di_dev_state_lost(hr)) { + HRESULT acquire_hr; + + dprintf("DirectInput: Device lost (%08x), attempting to reacquire\n", + (int) hr); + + acquire_hr = IDirectInputDevice8_Acquire(dev); + + if (SUCCEEDED(acquire_hr)) { + hr = IDirectInputDevice8_GetDeviceState( + dev, + sizeof(out->st), + &out->st); + + if (SUCCEEDED(hr)) { + dprintf("DirectInput: Device reacquired\n"); + } + } else { + dprintf("DirectInput: Acquire failed: %08x\n", (int) acquire_hr); + } + } + if (FAILED(hr)) { dprintf("DirectInput: GetDeviceState error: %08x\n", (int)hr); } diff --git a/games/swdcio/dllmain.c b/games/swdcio/dllmain.c index a35b8e8..5b9ad44 100644 --- a/games/swdcio/dllmain.c +++ b/games/swdcio/dllmain.c @@ -96,7 +96,7 @@ void swdc_io_get_gamebtns(uint16_t *gamebtn_out) void swdc_io_get_analogs(struct swdc_io_analog_state *out) { - struct swdc_io_analog_state tmp; + struct swdc_io_analog_state tmp = { 0 }; assert(out != NULL); assert(swdc_io_backend != NULL);