From 2907c1a1b504837666ce3024db9328c38545373c Mon Sep 17 00:00:00 2001 From: Tau Date: Sat, 28 Sep 2019 23:29:12 -0400 Subject: [PATCH] idzio: Add configuration file --- idzio/config.c | 78 ++++++++++++++++++ idzio/config.h | 34 ++++++++ idzio/di.c | 198 +++++++++++++++++++++++++++++++++++++++++----- idzio/di.h | 6 +- idzio/dllmain.c | 30 ++++++- idzio/meson.build | 2 + 6 files changed, 324 insertions(+), 24 deletions(-) create mode 100644 idzio/config.c create mode 100644 idzio/config.h diff --git a/idzio/config.c b/idzio/config.c new file mode 100644 index 0000000..1636048 --- /dev/null +++ b/idzio/config.c @@ -0,0 +1,78 @@ +#include + +#include +#include +#include + +#include "idzio/config.h" + +void idz_di_config_load(struct idz_di_config *cfg, const wchar_t *filename) +{ + assert(cfg != NULL); + assert(filename != NULL); + + GetPrivateProfileStringW( + L"dinput", + L"deviceName", + L"", + cfg->device_name, + _countof(cfg->device_name), + filename); + + GetPrivateProfileStringW( + L"dinput", + L"brakeAxis", + L"RZ", + cfg->brake_axis, + _countof(cfg->brake_axis), + filename); + + GetPrivateProfileStringW( + L"dinput", + L"accelAxis", + L"Y", + cfg->accel_axis, + _countof(cfg->accel_axis), + filename); + + cfg->start = GetPrivateProfileIntW(L"dinput", L"start", 0, filename); + cfg->view_chg = GetPrivateProfileIntW(L"dinput", L"viewChg", 0, filename); + cfg->shift_dn = GetPrivateProfileIntW(L"dinput", L"shiftDn", 0, filename); + cfg->shift_up = GetPrivateProfileIntW(L"dinput", L"shiftUp", 0, filename); +} + +void idz_io_config_load(struct idz_io_config *cfg, const wchar_t *filename) +{ + assert(cfg != NULL); + assert(filename != NULL); + + cfg->vk_test = GetPrivateProfileIntW(L"io3", L"test", '1', filename); + cfg->vk_service = GetPrivateProfileIntW(L"io3", L"service", '2', filename); + cfg->vk_coin = GetPrivateProfileIntW(L"io3", L"coin", '3', filename); + + GetPrivateProfileStringW( + L"io3", + L"mode", + L"xinput", + cfg->mode, + _countof(cfg->mode), + filename); + + idz_shifter_config_load(&cfg->shifter, filename); + idz_di_config_load(&cfg->di, filename); +} + +void idz_shifter_config_load( + struct idz_shifter_config *cfg, + const wchar_t *filename) +{ + assert(cfg != NULL); + assert(filename != NULL); + + cfg->auto_neutral = GetPrivateProfileIntW( + L"io3", + L"autoNeutral", + 0, + filename); +} + diff --git a/idzio/config.h b/idzio/config.h new file mode 100644 index 0000000..6beed49 --- /dev/null +++ b/idzio/config.h @@ -0,0 +1,34 @@ +#pragma once + +#include +#include +#include + +struct idz_shifter_config { + bool auto_neutral; +}; + +struct idz_di_config { + wchar_t device_name[64]; + wchar_t brake_axis[16]; + wchar_t accel_axis[16]; + uint8_t start; + uint8_t view_chg; + uint8_t shift_dn; + uint8_t shift_up; +}; + +struct idz_io_config { + uint8_t vk_test; + uint8_t vk_service; + uint8_t vk_coin; + wchar_t mode[8]; + struct idz_shifter_config shifter; + struct idz_di_config di; +}; + +void idz_di_config_load(struct idz_di_config *cfg, const wchar_t *filename); +void idz_io_config_load(struct idz_io_config *cfg, const wchar_t *filename); +void idz_shifter_config_load( + struct idz_shifter_config *cfg, + const wchar_t *filename); diff --git a/idzio/di.c b/idzio/di.c index 4fc2f4d..357ff31 100644 --- a/idzio/di.c +++ b/idzio/di.c @@ -6,20 +6,47 @@ #include #include "idzio/backend.h" +#include "idzio/config.h" +#include "idzio/di.h" #include "idzio/idzio.h" #include "idzio/shifter.h" #include "idzio/wnd.h" #include "util/dprintf.h" +#include "util/str.h" +struct idz_di_axis { + wchar_t name[4]; + size_t off; +}; + +union idz_di_state { + DIJOYSTATE st; + uint8_t bytes[sizeof(DIJOYSTATE)]; +}; + +static HRESULT idz_di_config_apply(const struct idz_di_config *cfg); +static const struct idz_di_axis *idz_di_get_axis(const wchar_t *name); static BOOL idz_di_enum_callback(const DIDEVICEINSTANCEW *dev, void *ctx); static void idz_di_try_fx(void); -static HRESULT idz_di_poll(DIJOYSTATE *out); +static HRESULT idz_di_poll(union idz_di_state *state); static void idz_di_jvs_read_buttons(uint8_t *gamebtn_out); static uint8_t idz_di_decode_pov(DWORD pov); static void idz_di_jvs_read_shifter(uint8_t *gear); static void idz_di_jvs_read_analogs(struct idz_io_analog_state *out); +static const struct idz_di_axis idz_di_axes[] = { + /* Just map DIJOYSTATE for now, we can map DIJOYSTATE2 later if needed */ + { .name = L"X", .off = DIJOFS_X }, + { .name = L"Y", .off = DIJOFS_Y }, + { .name = L"Z", .off = DIJOFS_Z }, + { .name = L"RX", .off = DIJOFS_RX }, + { .name = L"RY", .off = DIJOFS_RY }, + { .name = L"RZ", .off = DIJOFS_RZ }, + { .name = L"U", .off = DIJOFS_SLIDER(0) }, + { .name = L"V", .off = DIJOFS_SLIDER(1) }, +}; + static const struct idz_io_backend idz_di_backend = { .jvs_read_buttons = idz_di_jvs_read_buttons, .jvs_read_shifter = idz_di_jvs_read_shifter, @@ -30,8 +57,17 @@ static HWND idz_di_wnd; static IDirectInput8W *idz_di_api; static IDirectInputDevice8W *idz_di_dev; static IDirectInputEffect *idz_di_fx; +static size_t idz_di_off_brake; +static size_t idz_di_off_accel; +static uint8_t idz_di_shift_dn; +static uint8_t idz_di_shift_up; +static uint8_t idz_di_view_chg; +static uint8_t idz_di_start; -HRESULT idz_di_init(HINSTANCE inst, const struct idz_io_backend **backend) +HRESULT idz_di_init( + const struct idz_di_config *cfg, + HINSTANCE inst, + const struct idz_io_backend **backend) { HRESULT hr; HMODULE dinput8; @@ -39,10 +75,17 @@ HRESULT idz_di_init(HINSTANCE inst, const struct idz_io_backend **backend) wchar_t dll_path[MAX_PATH]; UINT path_pos; + assert(cfg != NULL); assert(backend != NULL); *backend = NULL; + hr = idz_di_config_apply(cfg); + + if (FAILED(hr)) { + return hr; + } + hr = idz_io_wnd_create(inst, &idz_di_wnd); if (FAILED(hr)) { @@ -96,15 +139,21 @@ HRESULT idz_di_init(HINSTANCE inst, const struct idz_io_backend **backend) idz_di_api, DI8DEVCLASS_GAMECTRL, idz_di_enum_callback, - NULL, + (void *) cfg, DIEDFL_ATTACHEDONLY); - if (FAILED(hr) || idz_di_dev == NULL) { - dprintf("Wheel: Could not find a controller: %08x\n", (int) hr); + if (FAILED(hr)) { + dprintf("Wheel: EnumDevices failed: %08x\n", (int) hr); return hr; } + if (idz_di_dev == NULL) { + dprintf("Wheel: Controller not found\n"); + + return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); + } + hr = IDirectInputDevice8_SetCooperativeLevel( idz_di_dev, idz_di_wnd, @@ -139,8 +188,101 @@ HRESULT idz_di_init(HINSTANCE inst, const struct idz_io_backend **backend) return S_OK; } +static HRESULT idz_di_config_apply(const struct idz_di_config *cfg) +{ + const struct idz_di_axis *brake_axis; + const struct idz_di_axis *accel_axis; + + brake_axis = idz_di_get_axis(cfg->brake_axis); + accel_axis = idz_di_get_axis(cfg->accel_axis); + + if (brake_axis == NULL) { + dprintf("Wheel: Invalid brake axis: %S\n", cfg->brake_axis); + + return E_INVALIDARG; + } + + if (accel_axis == NULL) { + dprintf("Wheel: Invalid accel axis: %S\n", cfg->accel_axis); + + return E_INVALIDARG; + } + + if (cfg->start > 32) { + dprintf("Wheel: Invalid start button: %i\n", cfg->start); + + return E_INVALIDARG; + } + + if (cfg->view_chg > 32) { + dprintf("Wheel: Invalid view change button: %i\n", cfg->view_chg); + + return E_INVALIDARG; + } + + if (cfg->shift_dn > 32) { + dprintf("Wheel: Invalid shift down button: %i\n", cfg->shift_dn); + + return E_INVALIDARG; + } + + if (cfg->shift_up > 32) { + dprintf("Wheel: Invalid shift up button: %i\n", cfg->shift_up); + + return E_INVALIDARG; + } + + /* Print some debug output to make sure config works... */ + + dprintf("Wheel: --- Begin configuration ---\n"); + dprintf("Wheel: Device name . . . . : Contains \"%S\"\n", + cfg->device_name); + dprintf("Wheel: Brake axis . . . . : %S\n", accel_axis->name); + dprintf("Wheel: Accelerator axis . : %S\n", brake_axis->name); + dprintf("Wheel: Start button . . . : %i\n", cfg->start); + dprintf("Wheel: View Change button : %i\n", cfg->view_chg); + dprintf("Wheel: Shift Down button . : %i\n", cfg->shift_dn); + dprintf("Wheel: Shift Up button . . : %i\n", cfg->shift_up); + dprintf("Wheel: --- End configuration ---\n"); + + idz_di_off_brake = accel_axis->off; + idz_di_off_accel = brake_axis->off; + idz_di_start = cfg->start; + idz_di_view_chg = cfg->view_chg; + idz_di_shift_dn = cfg->shift_dn; + idz_di_shift_up = cfg->shift_up; + + return S_OK; +} + +static const struct idz_di_axis *idz_di_get_axis(const wchar_t *name) +{ + const struct idz_di_axis *axis; + size_t i; + + for (i = 0 ; i < _countof(idz_di_axes) ; i++) { + axis = &idz_di_axes[i]; + + if (wstr_ieq(name, axis->name)) { + return axis; + } + } + + return NULL; +} + static BOOL idz_di_enum_callback(const DIDEVICEINSTANCEW *dev, void *ctx) { + const struct idz_di_config *cfg; + + cfg = ctx; + + if (wcsstr(dev->tszProductName, cfg->device_name) == NULL) { + return DIENUM_CONTINUE; + } + + dprintf("Wheel: Using DirectInput device \"%S\"\n", dev->tszProductName); + IDirectInput8_CreateDevice( idz_di_api, &dev->guidInstance, @@ -222,7 +364,7 @@ static void idz_di_try_fx(void) dprintf("Wheel: Force feedback initialized and set to zero\n"); } -static HRESULT idz_di_poll(DIJOYSTATE *out) +static HRESULT idz_di_poll(union idz_di_state *out) { HRESULT hr; MSG msg; @@ -241,7 +383,10 @@ static HRESULT idz_di_poll(DIJOYSTATE *out) DispatchMessage(&msg); } - hr = IDirectInputDevice8_GetDeviceState(idz_di_dev, sizeof(*out), out); + hr = IDirectInputDevice8_GetDeviceState( + idz_di_dev, + sizeof(out->st), + &out->st); if (FAILED(hr)) { dprintf("Wheel: I/O error: %08x\n", (int) hr); @@ -255,8 +400,8 @@ static HRESULT idz_di_poll(DIJOYSTATE *out) static void idz_di_jvs_read_buttons(uint8_t *gamebtn_out) { + union idz_di_state state; uint8_t gamebtn; - DIJOYSTATE state; HRESULT hr; assert(gamebtn_out != NULL); @@ -267,13 +412,13 @@ static void idz_di_jvs_read_buttons(uint8_t *gamebtn_out) return; } - gamebtn = idz_di_decode_pov(state.rgdwPOV[0]); + gamebtn = idz_di_decode_pov(state.st.rgdwPOV[0]); - if (state.rgbButtons[2]) { + if (idz_di_start && state.st.rgbButtons[idz_di_start - 1]) { gamebtn |= IDZ_IO_GAMEBTN_START; } - if (state.rgbButtons[9]) { + if (idz_di_view_chg && state.st.rgbButtons[idz_di_view_chg - 1]) { gamebtn |= IDZ_IO_GAMEBTN_VIEW_CHANGE; } @@ -297,7 +442,9 @@ static uint8_t idz_di_decode_pov(DWORD pov) static void idz_di_jvs_read_shifter(uint8_t *gear) { - DIJOYSTATE state; + union idz_di_state state; + bool shift_dn; + bool shift_up; HRESULT hr; assert(gear != NULL); @@ -308,18 +455,28 @@ static void idz_di_jvs_read_shifter(uint8_t *gear) return; } - if (state.rgbButtons[2]) { - idz_shifter_reset(); + if (idz_di_shift_dn) { + shift_dn = state.st.rgbButtons[idz_di_shift_dn - 1]; + } else { + shift_dn = false; } - idz_shifter_update(state.rgbButtons[0], state.rgbButtons[1]); + if (idz_di_shift_up) { + shift_up = state.st.rgbButtons[idz_di_shift_up - 1]; + } else { + shift_up = false; + } + + idz_shifter_update(shift_dn, shift_up); *gear = idz_shifter_current_gear(); } static void idz_di_jvs_read_analogs(struct idz_io_analog_state *out) { - DIJOYSTATE state; + union idz_di_state state; + const LONG *brake; + const LONG *accel; HRESULT hr; assert(out != NULL); @@ -330,7 +487,10 @@ static void idz_di_jvs_read_analogs(struct idz_io_analog_state *out) return; } - out->wheel = state.lX - 32768; - out->accel = 65535 - state.lRz; - out->brake = 65535 - state.lY; + brake = (LONG *) &state.bytes[idz_di_off_brake]; + accel = (LONG *) &state.bytes[idz_di_off_accel]; + + out->wheel = state.st.lX - 32768; + out->brake = 65535 - *brake; + out->accel = 65535 - *accel; } diff --git a/idzio/di.h b/idzio/di.h index 0470ef9..d218bbd 100644 --- a/idzio/di.h +++ b/idzio/di.h @@ -1,5 +1,9 @@ #pragma once #include "idzio/backend.h" +#include "idzio/config.h" -HRESULT idz_di_init(HINSTANCE inst, const struct idz_io_backend **backend); +HRESULT idz_di_init( + const struct idz_di_config *cfg, + HINSTANCE inst, + const struct idz_io_backend **backend); diff --git a/idzio/dllmain.c b/idzio/dllmain.c index 4256764..3ced7fe 100644 --- a/idzio/dllmain.c +++ b/idzio/dllmain.c @@ -5,20 +5,39 @@ #include #include "idzio/backend.h" +#include "idzio/config.h" #include "idzio/di.h" #include "idzio/idzio.h" #include "idzio/xi.h" +#include "util/dprintf.h" +#include "util/str.h" + static HMODULE idz_io_hmodule; +static struct idz_io_config idz_io_cfg; static const struct idz_io_backend *idz_io_backend; static bool idz_io_coin; static uint16_t idz_io_coins; HRESULT idz_io_init(void) { + HRESULT hr; + assert(idz_io_backend == NULL); - return idz_di_init(idz_io_hmodule, &idz_io_backend); + idz_io_config_load(&idz_io_cfg, L".\\segatools.ini"); + + if (wstr_ieq(idz_io_cfg.mode, L"dinput")) { + hr = idz_di_init(&idz_io_cfg.di, idz_io_hmodule, &idz_io_backend); + } else if (wstr_ieq(idz_io_cfg.mode, L"xinput")) { + hr = idz_xi_init(&idz_io_backend); + } else { + hr = E_INVALIDARG; + dprintf("IDZ IO: Invalid IO mode \"%S\", use dinput or xinput\n", + idz_io_cfg.mode); + } + + return hr; } void idz_io_jvs_read_buttons(uint8_t *opbtn_out, uint8_t *gamebtn_out) @@ -31,11 +50,13 @@ void idz_io_jvs_read_buttons(uint8_t *opbtn_out, uint8_t *gamebtn_out) opbtn = 0; - if (GetAsyncKeyState('1')) { + if ( idz_io_cfg.vk_test && + (GetAsyncKeyState(idz_io_cfg.vk_test) & 0x8000)) { opbtn |= IDZ_IO_OPBTN_TEST; } - if (GetAsyncKeyState('2')) { + if ( idz_io_cfg.vk_service && + (GetAsyncKeyState(idz_io_cfg.vk_service) & 0x8000)) { opbtn |= IDZ_IO_OPBTN_SERVICE; } @@ -66,7 +87,8 @@ void idz_io_jvs_read_coin_counter(uint16_t *out) /* Coin counter is not backend-specific */ - if (GetAsyncKeyState('3')) { + if ( idz_io_cfg.vk_coin && + (GetAsyncKeyState(idz_io_cfg.vk_coin) & 0x8000)) { if (!idz_io_coin) { idz_io_coin = true; idz_io_coins++; diff --git a/idzio/meson.build b/idzio/meson.build index 91f2724..15fdc4b 100644 --- a/idzio/meson.build +++ b/idzio/meson.build @@ -15,6 +15,8 @@ idzio_dll = shared_library( ], sources : [ 'backend.h', + 'config.c', + 'config.h', 'di.c', 'di.h', 'dllmain.c',