From b86049034fceb2137bcc1aa28ab954ae2da42caa Mon Sep 17 00:00:00 2001 From: kyoubate-haruka <46010460+kyoubate-haruka@users.noreply.github.com> Date: Wed, 12 Nov 2025 22:33:32 +0000 Subject: [PATCH] Add setting to only allow game input in foreground (#83) This adds a setting to the global configuration to allow only input when the game is focused. This prevents issues, such as triggering game buttons or service buttons while being tabbed out. Turned off by default. The implementation is not the best, but in the context how these games are structured, the most acceptable. It will keep scanning if the foreground window title fully matches (some games partially match, like FGO because due to the revision number in the title), and if found, will grab the HWND of that window and compare that from then on, to not tank performance due to constant string operations. Tested with FGO, chusan and ongeki. Reviewed-on: https://gitea.tendokyu.moe/TeamTofuShop/segatools/pulls/83 Reviewed-by: Dniel97 Co-authored-by: kyoubate-haruka <46010460+kyoubate-haruka@users.noreply.github.com> Co-committed-by: kyoubate-haruka <46010460+kyoubate-haruka@users.noreply.github.com> --- common/amex/config.c | 1 + common/amex/jvs.h | 1 + common/board/config.c | 1 + common/board/io3.c | 11 ++++++- common/board/io4.c | 31 +++++++++++++----- common/board/io4.h | 16 +++++---- common/util/fg-detect.c | 66 ++++++++++++++++++++++++++++++++++++++ common/util/fg-detect.h | 8 +++++ common/util/meson.build | 2 ++ doc/config/common.md | 13 ++++++++ games/apm3hook/io4.c | 2 +- games/chunihook/dllmain.c | 5 +++ games/chusanhook/io4.c | 39 +++++++++++----------- games/cmhook/io4.c | 13 ++++---- games/cxbhook/config.c | 1 + games/cxbhook/dllmain.c | 5 +++ games/cxbhook/revio.c | 38 +++++++++++++--------- games/cxbhook/revio.h | 1 + games/divahook/dllmain.c | 5 +++ games/fgohook/io4.c | 13 ++++---- games/idachook/io4.c | 31 +++++++++--------- games/idzhook/dllmain.c | 5 +++ games/kemonohook/dllmain.c | 5 +++ games/mai2hook/io4.c | 13 ++++---- games/mercuryhook/io4.c | 15 ++++----- games/mu3hook/io4.c | 28 ++++++++-------- games/swdchook/io4.c | 33 ++++++++++--------- games/tokyohook/io4.c | 2 +- 28 files changed, 276 insertions(+), 128 deletions(-) create mode 100644 common/util/fg-detect.c create mode 100644 common/util/fg-detect.h diff --git a/common/amex/config.c b/common/amex/config.c index e138447..3604c08 100644 --- a/common/amex/config.c +++ b/common/amex/config.c @@ -73,6 +73,7 @@ void jvs_config_load(struct jvs_config *cfg, const wchar_t *filename) assert(filename != NULL); cfg->enable = GetPrivateProfileIntW(L"jvs", L"enable", 1, filename); + cfg->foreground = GetPrivateProfileIntW(L"jvs", L"foreground", 0, filename); } void sram_config_load(struct sram_config *cfg, const wchar_t *filename) diff --git a/common/amex/jvs.h b/common/amex/jvs.h index 0bedb0f..ab3ea36 100644 --- a/common/amex/jvs.h +++ b/common/amex/jvs.h @@ -15,6 +15,7 @@ DEFINE_GUID( struct jvs_config { bool enable; + bool foreground; }; typedef HRESULT (*jvs_provider_t)(struct jvs_node **root); diff --git a/common/board/config.c b/common/board/config.c index 96c4146..be98ebe 100644 --- a/common/board/config.c +++ b/common/board/config.c @@ -92,6 +92,7 @@ void io4_config_load(struct io4_config *cfg, const wchar_t *filename) assert(filename != NULL); cfg->enable = GetPrivateProfileIntW(L"io4", L"enable", 1, filename); + cfg->foreground_only = GetPrivateProfileIntW(L"io4", L"foreground", 0, filename); } void vfd_config_load(struct vfd_config *cfg, const wchar_t *filename) diff --git a/common/board/io3.c b/common/board/io3.c index d61cfdc..2a7ca83 100644 --- a/common/board/io3.c +++ b/common/board/io3.c @@ -26,6 +26,7 @@ #include "util/dprintf.h" #include "util/dump.h" +#include "util/fg-detect.h" static void io3_transact( struct jvs_node *node, @@ -146,6 +147,8 @@ static uint8_t io3_features[] = { 0x00, }; +static struct io3_switch_state prev_state = {0}; + void io3_init( struct io3 *io3, struct jvs_node *next, @@ -423,7 +426,13 @@ static HRESULT io3_cmd_read_switches( memset(&state, 0, sizeof(state)); if (io3->ops != NULL) { - io3->ops->read_switches(io3->ops_ctx, &state); + fgdet_poll(); + if (fgdet_in_foreground()) { // returns true if fgdet is not enabled + io3->ops->read_switches(io3->ops_ctx, &state); + memcpy(&prev_state, &state, sizeof(state)); + } else { + state = prev_state; + } } hr = iobuf_write_8(resp_buf, state.system); /* Test, Tilt lines */ diff --git a/common/board/io4.c b/common/board/io4.c index e1def19..8001457 100644 --- a/common/board/io4.c +++ b/common/board/io4.c @@ -20,6 +20,7 @@ #include "util/async.h" #include "util/dprintf.h" +#include "util/fg-detect.h" #pragma pack(push, 1) @@ -99,12 +100,14 @@ static struct async io4_async; static uint8_t io4_system_status; static const struct io4_ops *io4_ops; static void *io4_ops_ctx; +static struct io4_state prev_state; HRESULT io4_hook_init( - const struct io4_config *cfg, - const struct io4_ops *ops, - void *ctx) -{ + const struct io4_config *cfg, + const struct io4_ops *ops, + void *ctx, + const wchar_t* window_name, + const bool window_name_is_partial_match) { HRESULT hr; assert(cfg != NULL); @@ -122,9 +125,14 @@ HRESULT io4_hook_init( return hr; } + if (window_name != NULL && cfg->foreground_only) { + fgdet_init(window_name, window_name_is_partial_match); + } + io4_ops = ops; io4_ops_ctx = ctx; io4_system_status = 0x02; /* idk */ + memset(&prev_state, 0, sizeof(prev_state)); iohook_push_handler(io4_handle_irp); hr = setupapi_add_phantom_dev(&hid_guid, io4_path); @@ -325,11 +333,18 @@ static HRESULT io4_async_poll(void *ctx, struct irp *irp) /* Call into ops to poll the underlying inputs */ - memset(&state, 0, sizeof(state)); - hr = io4_ops->poll(io4_ops_ctx, &state); + fgdet_poll(); + if (fgdet_in_foreground()) { // returns true if fgdet is not enabled + memset(&state, 0, sizeof(state)); + hr = io4_ops->poll(io4_ops_ctx, &state); - if (FAILED(hr)) { - return hr; + if (FAILED(hr)) { + return hr; + } + + memcpy(&prev_state, &state, sizeof(state)); + } else { + state = prev_state; // if we're unfocused, freeze the current input } /* Construct IN report. Values are all little-endian, unlike JVS. */ diff --git a/common/board/io4.h b/common/board/io4.h index 09a921b..1f93cf1 100644 --- a/common/board/io4.h +++ b/common/board/io4.h @@ -10,12 +10,13 @@ enum { /* System buttons in button[0] */ - IO4_BUTTON_TEST = 1 << 9, - IO4_BUTTON_SERVICE = 1 << 6, + IO4_BUTTON_TEST = 1 << 9, + IO4_BUTTON_SERVICE = 1 << 6, }; struct io4_config { bool enable; + bool foreground_only; }; struct io4_state { @@ -26,11 +27,14 @@ struct io4_state { }; struct io4_ops { - HRESULT (*poll)(void *ctx, struct io4_state *state); + HRESULT (*poll)(void* ctx, struct io4_state* state); + HRESULT (*write_gpio)(uint8_t* payload, size_t len); }; HRESULT io4_hook_init( - const struct io4_config *cfg, - const struct io4_ops *ops, - void *ctx); + const struct io4_config* cfg, + const struct io4_ops* ops, + void* ctx, + const wchar_t* window_name, + const bool window_name_is_partial_match); \ No newline at end of file diff --git a/common/util/fg-detect.c b/common/util/fg-detect.c new file mode 100644 index 0000000..e5ed83c --- /dev/null +++ b/common/util/fg-detect.c @@ -0,0 +1,66 @@ +#include +#include + +#include "util/dprintf.h" +#include "util/fg-detect.h" + +#include + +static HWND window_handle; +static const wchar_t* window_title = NULL; +static bool foreground_state = true; +static bool partial_match; +static wchar_t scanned_title[256]; + +static HWND get_window(){ + if (window_handle != NULL){ + return window_handle; + } + + // try detecting the window + HWND hwnd = GetForegroundWindow(); + if (GetWindowTextW(hwnd, scanned_title, sizeof(scanned_title)) == 0) { + return NULL; + } + if (partial_match) { + if (wcsstr(scanned_title, window_title) == NULL) { + return NULL; + } + } else { + if (wcscmp(scanned_title, window_title) != 0) { + return NULL; + } + } + dprintf("FG-Detect: Program window detected\n"); + window_handle = hwnd; + return window_handle; +} + +void fgdet_init(const wchar_t* wnd_title, const bool wnd_partial_match) { + assert(wnd_title != NULL); + + window_handle = NULL; + window_title = wnd_title; + partial_match = wnd_partial_match; + dprintf("FG-Detect: Searching for \"%ls\"\n", window_title); +} + +bool fgdet_in_foreground(){ + return foreground_state; +} + +void fgdet_poll(){ + if (window_title == NULL){ + return; + } else if (GetForegroundWindow() == get_window()){ + if (!foreground_state){ + dprintf("FG-Detect: Got focus\n"); + foreground_state = true; + } + } else { + if (foreground_state){ + dprintf("FG-Detect: Lost focus\n"); + foreground_state = false; + } + } +} diff --git a/common/util/fg-detect.h b/common/util/fg-detect.h new file mode 100644 index 0000000..3961fac --- /dev/null +++ b/common/util/fg-detect.h @@ -0,0 +1,8 @@ +#pragma once +#include + +void fgdet_init(const wchar_t* wnd_title, const bool wnd_partial_match); + +bool fgdet_in_foreground(); + +void fgdet_poll(); \ No newline at end of file diff --git a/common/util/meson.build b/common/util/meson.build index 58782d3..a0150a7 100644 --- a/common/util/meson.build +++ b/common/util/meson.build @@ -17,6 +17,8 @@ util_lib = static_library( 'dprintf.h', 'dump.c', 'dump.h', + 'fg-detect.c', + 'fg-detect.h', 'get_function_ordinal.c', 'get_function_ordinal.h', 'lib.c', diff --git a/doc/config/common.md b/doc/config/common.md index d2eb385..1be9b7c 100644 --- a/doc/config/common.md +++ b/doc/config/common.md @@ -409,6 +409,12 @@ Default `1` Enable JVS port emulation. Disable to use the JVS port on a real AMEX. +### `foreground` + +Default `0` + +Only enables input when the game's main window is focused. This does not work for all games. + ## `[io4]` Configure emulation of the IO4 board. Same settings also apply to `[io3]`. @@ -419,6 +425,13 @@ Default `1` Enable IO4 port emulation. Disable to use the IO4 port on a real ALLS. + +### `foreground` + +Default `0` + +Only enables input when the game's main window is focused. This does not work for all games, notably APMv3, due to the game switching involved. + ### `test` Default `0x31` diff --git a/games/apm3hook/io4.c b/games/apm3hook/io4.c index 4d04f97..596aa80 100644 --- a/games/apm3hook/io4.c +++ b/games/apm3hook/io4.c @@ -23,7 +23,7 @@ HRESULT apm3_io4_hook_init(const struct io4_config *cfg) assert(apm3_dll.init != NULL); - hr = io4_hook_init(cfg, &apm3_io4_ops, NULL); + hr = io4_hook_init(cfg, &apm3_io4_ops, NULL, NULL, false); // can't use fgdet here because the main window closes if (FAILED(hr)) { return hr; diff --git a/games/chunihook/dllmain.c b/games/chunihook/dllmain.c index a3fa8ab..16e663f 100644 --- a/games/chunihook/dllmain.c +++ b/games/chunihook/dllmain.c @@ -37,6 +37,7 @@ #include "util/dprintf.h" #include "util/env.h" +#include "util/fg-detect.h" static HMODULE chuni_hook_mod; static process_entry_t chuni_startup; @@ -129,6 +130,10 @@ static DWORD CALLBACK chuni_pre_startup(void) goto fail; } + if (chuni_hook_cfg.amex.jvs.enable && chuni_hook_cfg.amex.jvs.foreground) { + fgdet_init(L"teaGfx DirectX Release", false); + } + /* Initialize debug helpers */ spike_hook_init(get_config_path()); diff --git a/games/chusanhook/io4.c b/games/chusanhook/io4.c index c7f8265..48234a3 100644 --- a/games/chusanhook/io4.c +++ b/games/chusanhook/io4.c @@ -16,32 +16,32 @@ struct chunithm_jvs_ir_mask { // Incorrect IR beam mappings retained for backward compatibility static const struct chunithm_jvs_ir_mask chunithm_jvs_ir_masks_v1[] = { - { 0, 1 << 13 }, - { 1 << 13, 0 }, - { 0, 1 << 12 }, - { 1 << 12, 0 }, - { 0, 1 << 11 }, - { 1 << 11, 0 }, + {0, 1 << 13}, + {1 << 13, 0}, + {0, 1 << 12}, + {1 << 12, 0}, + {0, 1 << 11}, + {1 << 11, 0}, }; static const struct chunithm_jvs_ir_mask chunithm_jvs_ir_masks[] = { - { 1 << 13, 0 }, - { 0, 1 << 13 }, - { 1 << 12, 0 }, - { 0, 1 << 12 }, - { 1 << 11, 0 }, - { 0, 1 << 11 }, + {1 << 13, 0}, + {0, 1 << 13}, + {1 << 12, 0}, + {0, 1 << 12}, + {1 << 11, 0}, + {0, 1 << 11}, }; static HRESULT chusan_io4_poll(void* ctx, struct io4_state* state); + static uint16_t coins; static const struct io4_ops chusan_io4_ops = { .poll = chusan_io4_poll, }; -HRESULT chusan_io4_hook_init(const struct io4_config* cfg) -{ +HRESULT chusan_io4_hook_init(const struct io4_config* cfg) { HRESULT hr; assert(chuni_dll.jvs_init != NULL); @@ -50,19 +50,18 @@ HRESULT chusan_io4_hook_init(const struct io4_config* cfg) hr = chuni_dll.jvs_init(); if (FAILED(hr)) { - dprintf("USB I/O: Backend error, I/O disconnected: %x\n", (int)hr); + dprintf("USB I/O: Backend error, I/O disconnected: %x\n", (int) hr); return hr; } - io4_hook_init(cfg, &chusan_io4_ops, NULL); + io4_hook_init(cfg, &chusan_io4_ops, NULL, L"teaGfx DirectX Release", false); return S_OK; } -static HRESULT chusan_io4_poll(void* ctx, struct io4_state* state) -{ - const struct chunithm_jvs_ir_mask *masks; +static HRESULT chusan_io4_poll(void* ctx, struct io4_state* state) { + const struct chunithm_jvs_ir_mask* masks; uint8_t opbtn; uint8_t beams; size_t i; @@ -103,4 +102,4 @@ static HRESULT chusan_io4_poll(void* ctx, struct io4_state* state) } return S_OK; -} +} \ No newline at end of file diff --git a/games/cmhook/io4.c b/games/cmhook/io4.c index 073f681..c497b37 100644 --- a/games/cmhook/io4.c +++ b/games/cmhook/io4.c @@ -10,20 +10,20 @@ #include "util/dprintf.h" -static HRESULT cm_io4_poll(void *ctx, struct io4_state *state); +static HRESULT cm_io4_poll(void* ctx, struct io4_state* state); + static uint16_t coins; static const struct io4_ops cm_io4_ops = { .poll = cm_io4_poll, }; -HRESULT cm_io4_hook_init(const struct io4_config *cfg) -{ +HRESULT cm_io4_hook_init(const struct io4_config* cfg) { HRESULT hr; assert(cm_dll.init != NULL); - hr = io4_hook_init(cfg, &cm_io4_ops, NULL); + hr = io4_hook_init(cfg, &cm_io4_ops, NULL, L"MU3CardViewer", false); if (FAILED(hr)) { return hr; @@ -32,8 +32,7 @@ HRESULT cm_io4_hook_init(const struct io4_config *cfg) return cm_dll.init(); } -static HRESULT cm_io4_poll(void *ctx, struct io4_state *state) -{ +static HRESULT cm_io4_poll(void* ctx, struct io4_state* state) { uint8_t opbtn; HRESULT hr; @@ -66,4 +65,4 @@ static HRESULT cm_io4_poll(void *ctx, struct io4_state *state) state->chutes[0] = coins << 8; return S_OK; -} +} \ No newline at end of file diff --git a/games/cxbhook/config.c b/games/cxbhook/config.c index 98d326d..8a2d6fb 100644 --- a/games/cxbhook/config.c +++ b/games/cxbhook/config.c @@ -42,6 +42,7 @@ void revio_config_load(struct revio_config *cfg, const wchar_t *filename) assert(filename != NULL); cfg->enable = GetPrivateProfileIntW(L"revio", L"enable", 1, filename); + cfg->foreground = GetPrivateProfileIntW(L"revio", L"foreground", 0, filename); } void led_config_load(struct led_config *cfg, const wchar_t *filename) diff --git a/games/cxbhook/dllmain.c b/games/cxbhook/dllmain.c index d644b5e..fd6f4e0 100644 --- a/games/cxbhook/dllmain.c +++ b/games/cxbhook/dllmain.c @@ -24,6 +24,7 @@ #include "util/dprintf.h" #include "util/env.h" +#include "util/fg-detect.h" static HMODULE cxb_hook_mod; static process_entry_t cxb_startup; @@ -103,6 +104,10 @@ static DWORD CALLBACK cxb_pre_startup(void) goto fail; } + if (cxb_hook_cfg.revio.enable && cxb_hook_cfg.revio.foreground) { + fgdet_init(L"MT Framework", false); + } + hr = led_hook_init(&cxb_hook_cfg.led); if (FAILED(hr)) { diff --git a/games/cxbhook/revio.c b/games/cxbhook/revio.c index 84ab016..b06a007 100644 --- a/games/cxbhook/revio.c +++ b/games/cxbhook/revio.c @@ -14,6 +14,7 @@ #include "hook/table.h" #include "util/dprintf.h" +#include "util/fg-detect.h" static int my_cCommIo_Open(char *port); static int my_cCommIo_Close(); @@ -31,6 +32,7 @@ static int my_cCommIo_SetAmpMute(int amp_id, int a2); int amp_volume[] = {20, 20, 20}; int last_triggers = 0; int last_is_mouse_down = false; +int prev_out = 0; static struct hook_symbol revio_syms[] = { { @@ -139,26 +141,32 @@ static int my_cCommIo_GetTrigger() uint16_t btns = 0; int out = 0; - cxb_dll.revio_poll(&btns); + fgdet_poll(); + if (fgdet_in_foreground()) { + cxb_dll.revio_poll(&btns); - if (btns & 0x01) { - out |= 1 << 4; // test - } + if (btns & 0x01) { + out |= 1 << 4; // test + } - if (btns & 0x02) { - out |= 1 << 5; // service? - } + if (btns & 0x02) { + out |= 1 << 5; // service? + } - if (btns & 0x04) { - out |= 1 << 1; // up - } + if (btns & 0x04) { + out |= 1 << 1; // up + } - if (btns & 0x08) { - out |= 1 << 3; // down - } + if (btns & 0x08) { + out |= 1 << 3; // down + } - if (btns & 0x0F) { - out |= 1 << 2; // cancel + if (btns & 0x0F) { + out |= 1 << 2; // cancel + } + prev_out = out; + } else { + out = prev_out; } out &= ~last_triggers; diff --git a/games/cxbhook/revio.h b/games/cxbhook/revio.h index 8150c97..c787607 100644 --- a/games/cxbhook/revio.h +++ b/games/cxbhook/revio.h @@ -6,6 +6,7 @@ struct revio_config { bool enable; + bool foreground; uint8_t test; uint8_t service; uint8_t coin; diff --git a/games/divahook/dllmain.c b/games/divahook/dllmain.c index eb6e16f..52789b1 100644 --- a/games/divahook/dllmain.c +++ b/games/divahook/dllmain.c @@ -34,6 +34,7 @@ #include "util/dprintf.h" #include "util/env.h" +#include "util/fg-detect.h" static HMODULE diva_hook_mod; static process_entry_t diva_startup; @@ -104,6 +105,10 @@ static DWORD CALLBACK diva_pre_startup(void) goto fail; } + if (diva_hook_cfg.amex.jvs.enable && diva_hook_cfg.amex.jvs.foreground) { + fgdet_init(L"Hatsune Miku Project DIVA Arcade Future Tone", false); + } + /* Initialize debug helpers */ spike_hook_init(get_config_path()); diff --git a/games/fgohook/io4.c b/games/fgohook/io4.c index 67dfba4..5194fa3 100644 --- a/games/fgohook/io4.c +++ b/games/fgohook/io4.c @@ -10,20 +10,20 @@ #include "util/dprintf.h" -static HRESULT fgo_io4_poll(void *ctx, struct io4_state *state); +static HRESULT fgo_io4_poll(void* ctx, struct io4_state* state); + static uint16_t coins; static const struct io4_ops fgo_io4_ops = { .poll = fgo_io4_poll, }; -HRESULT fgo_io4_hook_init(const struct io4_config *cfg) -{ +HRESULT fgo_io4_hook_init(const struct io4_config* cfg) { HRESULT hr; assert(fgo_dll.init != NULL); - hr = io4_hook_init(cfg, &fgo_io4_ops, NULL); + hr = io4_hook_init(cfg, &fgo_io4_ops, NULL, L"Fate/Grand Order Arcade r", true); if (FAILED(hr)) { return hr; @@ -32,8 +32,7 @@ HRESULT fgo_io4_hook_init(const struct io4_config *cfg) return fgo_dll.init(); } -static HRESULT fgo_io4_poll(void *ctx, struct io4_state *state) -{ +static HRESULT fgo_io4_poll(void* ctx, struct io4_state* state) { uint8_t opbtn; uint8_t gamebtn; int16_t stick_x; @@ -101,4 +100,4 @@ static HRESULT fgo_io4_poll(void *ctx, struct io4_state *state) state->adcs[4] = 0x8000 + stick_y; return S_OK; -} +} \ No newline at end of file diff --git a/games/idachook/io4.c b/games/idachook/io4.c index 3861ef8..fa4f82b 100644 --- a/games/idachook/io4.c +++ b/games/idachook/io4.c @@ -10,12 +10,14 @@ #include "util/dprintf.h" -static HRESULT idac_io4_poll(void *ctx, struct io4_state *state); +static HRESULT idac_io4_poll(void* ctx, struct io4_state* state); + static HRESULT idac_io4_write_gpio(uint8_t* payload, size_t len); + static uint16_t coins; static const struct io4_ops idac_io4_ops = { - .poll = idac_io4_poll, + .poll = idac_io4_poll, .write_gpio = idac_io4_write_gpio }; @@ -36,13 +38,12 @@ static const uint16_t idac_gear_signals[] = { 0x0014, }; -HRESULT idac_io4_hook_init(const struct io4_config *cfg) -{ +HRESULT idac_io4_hook_init(const struct io4_config* cfg) { HRESULT hr; assert(idac_dll.init != NULL); - hr = io4_hook_init(cfg, &idac_io4_ops, NULL); + hr = io4_hook_init(cfg, &idac_io4_ops, NULL, L"GameProject", false); if (FAILED(hr)) { return hr; @@ -51,8 +52,7 @@ HRESULT idac_io4_hook_init(const struct io4_config *cfg) return idac_dll.init(); } -static HRESULT idac_io4_poll(void *ctx, struct io4_state *state) -{ +static HRESULT idac_io4_poll(void* ctx, struct io4_state* state) { uint8_t opbtn; uint8_t gamebtn; uint8_t gear; @@ -131,21 +131,20 @@ static HRESULT idac_io4_poll(void *ctx, struct io4_state *state) return S_OK; } -static HRESULT idac_io4_write_gpio(uint8_t* payload, size_t len) -{ +static HRESULT idac_io4_write_gpio(uint8_t* payload, size_t len) { assert(idac_dll.led_set_leds != NULL); - + // Just fast fail if there aren't enough bytes in the payload - if (len < 3) + if (len < 3) return S_OK; - + // This command is used for lights in IDAC, but it only contains button lights, // and only in the first 3 bytes of the payload; everything else is padding to // make the payload 62 bytes. The rest of the cabinet lights and the side button // lights are handled separately, by the 15070 lights controller. - uint32_t lights_data = (uint32_t) ((uint8_t)(payload[0]) << 24 | - (uint8_t)(payload[1]) << 16 | - (uint8_t)(payload[2]) << 8); + uint32_t lights_data = (uint32_t)((uint8_t)(payload[0]) << 24 | + (uint8_t)(payload[1]) << 16 | + (uint8_t)(payload[2]) << 8); // Since Sega uses an odd ordering for the first part of the bitfield, // let's normalize the data and just send over bytes for the receiver @@ -162,4 +161,4 @@ static HRESULT idac_io4_write_gpio(uint8_t* payload, size_t len) idac_dll.led_set_leds(0, rgb_out); return S_OK; -} +} \ No newline at end of file diff --git a/games/idzhook/dllmain.c b/games/idzhook/dllmain.c index 534f4d0..b73a6a4 100644 --- a/games/idzhook/dllmain.c +++ b/games/idzhook/dllmain.c @@ -41,6 +41,7 @@ #include "util/dprintf.h" #include "util/lib.h" #include "util/env.h" +#include "util/fg-detect.h" static HMODULE idz_hook_mod; static process_entry_t idz_startup; @@ -136,6 +137,10 @@ static DWORD CALLBACK idz_pre_startup(void) goto fail; } + if (idz_hook_cfg.amex.jvs.enable && idz_hook_cfg.amex.jvs.foreground) { + fgdet_init(L"Direct3D Window", false); + } + /* Initialize debug helpers */ spike_hook_init(get_config_path()); diff --git a/games/kemonohook/dllmain.c b/games/kemonohook/dllmain.c index 3373489..f429299 100644 --- a/games/kemonohook/dllmain.c +++ b/games/kemonohook/dllmain.c @@ -18,6 +18,7 @@ #include "unityhook/hook.h" #include "util/dprintf.h" #include "util/env.h" +#include "util/fg-detect.h" static HMODULE kemono_hook_mod; static process_entry_t kemono_startup; @@ -103,6 +104,10 @@ static DWORD CALLBACK kemono_pre_startup(void) { goto fail; } + if (kemono_hook_cfg.amex.jvs.enable && kemono_hook_cfg.amex.jvs.foreground) { + fgdet_init(L"Parade", false); + } + kemono_extra_hooks_init(); /* Initialize Unity native plugin DLL hooks diff --git a/games/mai2hook/io4.c b/games/mai2hook/io4.c index 4eb7f6b..cb0b38d 100644 --- a/games/mai2hook/io4.c +++ b/games/mai2hook/io4.c @@ -10,20 +10,20 @@ #include "util/dprintf.h" -static HRESULT mai2_io4_poll(void *ctx, struct io4_state *state); +static HRESULT mai2_io4_poll(void* ctx, struct io4_state* state); + static uint16_t coins; static const struct io4_ops mai2_io4_ops = { .poll = mai2_io4_poll, }; -HRESULT mai2_io4_hook_init(const struct io4_config *cfg) -{ +HRESULT mai2_io4_hook_init(const struct io4_config* cfg) { HRESULT hr; assert(mai2_dll.init != NULL); - hr = io4_hook_init(cfg, &mai2_io4_ops, NULL); + hr = io4_hook_init(cfg, &mai2_io4_ops, NULL, L"Sinmai", false); if (FAILED(hr)) { return hr; @@ -32,8 +32,7 @@ HRESULT mai2_io4_hook_init(const struct io4_config *cfg) return mai2_dll.init(); } -static HRESULT mai2_io4_poll(void *ctx, struct io4_state *state) -{ +static HRESULT mai2_io4_poll(void* ctx, struct io4_state* state) { uint8_t opbtn; uint16_t player1; uint16_t player2; @@ -150,4 +149,4 @@ static HRESULT mai2_io4_poll(void *ctx, struct io4_state *state) } return S_OK; -} +} \ No newline at end of file diff --git a/games/mercuryhook/io4.c b/games/mercuryhook/io4.c index df22656..c34eb6f 100644 --- a/games/mercuryhook/io4.c +++ b/games/mercuryhook/io4.c @@ -14,19 +14,18 @@ bool mercury_io_coin = false; uint16_t mercury_io_coins = 0; -static HRESULT mercury_io4_poll(void *ctx, struct io4_state *state); +static HRESULT mercury_io4_poll(void* ctx, struct io4_state* state); static const struct io4_ops mercury_io4_ops = { .poll = mercury_io4_poll, }; -HRESULT mercury_io4_hook_init(const struct io4_config *cfg) -{ +HRESULT mercury_io4_hook_init(const struct io4_config* cfg) { HRESULT hr; assert(mercury_dll.init != NULL); - hr = io4_hook_init(cfg, &mercury_io4_ops, NULL); + hr = io4_hook_init(cfg, &mercury_io4_ops, NULL, L"Mercury", false); if (FAILED(hr)) { return hr; @@ -35,8 +34,7 @@ HRESULT mercury_io4_hook_init(const struct io4_config *cfg) return mercury_dll.init(); } -static HRESULT mercury_io4_poll(void *ctx, struct io4_state *state) -{ +static HRESULT mercury_io4_poll(void* ctx, struct io4_state* state) { uint8_t opbtn; uint8_t gamebtn; HRESULT hr; @@ -72,8 +70,7 @@ static HRESULT mercury_io4_poll(void *ctx, struct io4_state *state) mercury_io_coin = true; mercury_io_coins++; } - } - else { + } else { mercury_io_coin = false; } @@ -88,4 +85,4 @@ static HRESULT mercury_io4_poll(void *ctx, struct io4_state *state) } return S_OK; -} +} \ No newline at end of file diff --git a/games/mu3hook/io4.c b/games/mu3hook/io4.c index dfa7ad8..430d17a 100644 --- a/games/mu3hook/io4.c +++ b/games/mu3hook/io4.c @@ -10,7 +10,8 @@ #include "util/dprintf.h" -static HRESULT mu3_io4_poll(void *ctx, struct io4_state *state); +static HRESULT mu3_io4_poll(void* ctx, struct io4_state* state); + static HRESULT mu3_io4_write_gpio(uint8_t* payload, size_t len); static uint16_t coins; @@ -20,13 +21,12 @@ static const struct io4_ops mu3_io4_ops = { .write_gpio = mu3_io4_write_gpio, }; -HRESULT mu3_io4_hook_init(const struct io4_config *cfg) -{ +HRESULT mu3_io4_hook_init(const struct io4_config* cfg) { HRESULT hr; assert(mu3_dll.init != NULL); - hr = io4_hook_init(cfg, &mu3_io4_ops, NULL); + hr = io4_hook_init(cfg, &mu3_io4_ops, NULL, L"Otoge", false); if (FAILED(hr)) { return hr; @@ -35,8 +35,7 @@ HRESULT mu3_io4_hook_init(const struct io4_config *cfg) return mu3_dll.init(); } -static HRESULT mu3_io4_poll(void *ctx, struct io4_state *state) -{ +static HRESULT mu3_io4_poll(void* ctx, struct io4_state* state) { uint8_t opbtn; uint8_t left; uint8_t right; @@ -111,11 +110,11 @@ static HRESULT mu3_io4_poll(void *ctx, struct io4_state *state) } if (!(left & MU3_IO_GAMEBTN_SIDE)) { - state->buttons[1] |= 1 << 15; /* L-Side, active-low */ + state->buttons[1] |= 1 << 15; /* L-Side, active-low */ } if (!(right & MU3_IO_GAMEBTN_SIDE)) { - state->buttons[0] |= 1 << 14; /* R-Side, active-low */ + state->buttons[0] |= 1 << 14; /* R-Side, active-low */ } /* Lever increases right-to-left, not left-to-right. @@ -128,19 +127,18 @@ static HRESULT mu3_io4_poll(void *ctx, struct io4_state *state) return S_OK; } -static HRESULT mu3_io4_write_gpio(uint8_t* payload, size_t len) -{ +static HRESULT mu3_io4_write_gpio(uint8_t* payload, size_t len) { // Just fast fail if there aren't enough bytes in the payload - if (len < 3) + if (len < 3) return S_OK; // This command is used for lights in Ongeki, but it only contains button lights, // and only in the first 3 bytes of the payload; everything else is padding to // make the payload 62 bytes. The rest of the cabinet lights and the side button // lights are handled separately, by the 15093 lights controller. - uint32_t lights_data = (uint32_t) ((uint8_t)(payload[0]) << 24 | - (uint8_t)(payload[1]) << 16 | - (uint8_t)(payload[2]) << 8); + uint32_t lights_data = (uint32_t)((uint8_t)(payload[0]) << 24 | + (uint8_t)(payload[1]) << 16 | + (uint8_t)(payload[2]) << 8); // Since Sega uses an odd ordering for the first part of the bitfield, // let's normalize the data and just send over bytes for the receiver @@ -169,4 +167,4 @@ static HRESULT mu3_io4_write_gpio(uint8_t* payload, size_t len) mu3_dll.led_set_leds(1, rgb_out); return S_OK; -} +} \ No newline at end of file diff --git a/games/swdchook/io4.c b/games/swdchook/io4.c index 679a646..1d3ffcf 100644 --- a/games/swdchook/io4.c +++ b/games/swdchook/io4.c @@ -11,24 +11,28 @@ #include "swdchook/swdc-dll.h" static HANDLE mmf; + static HRESULT init_mmf(void); + static void swdc_set_gamebtns(uint16_t value); -static HRESULT swdc_io4_poll(void *ctx, struct io4_state *state); +static HRESULT swdc_io4_poll(void* ctx, struct io4_state* state); + static HRESULT swdc_io4_write_gpio(uint8_t* payload, size_t len); + static uint16_t coins; static const struct io4_ops swdc_io4_ops = { - .poll = swdc_io4_poll, + .poll = swdc_io4_poll, .write_gpio = swdc_io4_write_gpio }; -HRESULT swdc_io4_hook_init(const struct io4_config *cfg) { +HRESULT swdc_io4_hook_init(const struct io4_config* cfg) { HRESULT hr; assert(swdc_dll.init != NULL); - hr = io4_hook_init(cfg, &swdc_io4_ops, NULL); + hr = io4_hook_init(cfg, &swdc_io4_ops, NULL, L"Todoroki", false); if (FAILED(hr)) { return hr; @@ -61,7 +65,7 @@ void swdc_set_gamebtns(uint16_t value) { // Update the memory-mapped file LPVOID mmf_view = MapViewOfFile(mmf, FILE_MAP_ALL_ACCESS, 0, 0, 2); if (mmf_view != NULL) { - uint16_t* ptr = (uint16_t*)mmf_view; + uint16_t* ptr = (uint16_t *) mmf_view; *ptr = value; UnmapViewOfFile(mmf_view); @@ -70,7 +74,7 @@ void swdc_set_gamebtns(uint16_t value) { // ReleaseMutex(mutex); } -static HRESULT swdc_io4_poll(void *ctx, struct io4_state *state) { +static HRESULT swdc_io4_poll(void* ctx, struct io4_state* state) { uint8_t opbtn; uint16_t gamebtn; struct swdc_io_analog_state analog_state; @@ -128,7 +132,7 @@ static HRESULT swdc_io4_poll(void *ctx, struct io4_state *state) { state->buttons[0] |= 1 << 2; } -/* + /* Update steering wheel buttons Those are connected to the SEGA 838-15415 INDICATOR BD MAIN @@ -175,21 +179,20 @@ static HRESULT swdc_io4_poll(void *ctx, struct io4_state *state) { return S_OK; } -static HRESULT swdc_io4_write_gpio(uint8_t* payload, size_t len) -{ +static HRESULT swdc_io4_write_gpio(uint8_t* payload, size_t len) { assert(swdc_dll.led_set_leds != NULL); // Just fast fail if there aren't enough bytes in the payload - if (len < 3) + if (len < 3) return S_OK; - + // This command is used for lights in SWDC, but it only contains button lights, // and only in the first 3 bytes of the payload; everything else is padding to // make the payload 62 bytes. The rest of the cabinet lights and the side button // lights are handled separately, by the 15070 lights controller. - uint32_t lights_data = (uint32_t) ((uint8_t)(payload[0]) << 24 | - (uint8_t)(payload[1]) << 16 | - (uint8_t)(payload[2]) << 8); + uint32_t lights_data = (uint32_t)((uint8_t)(payload[0]) << 24 | + (uint8_t)(payload[1]) << 16 | + (uint8_t)(payload[2]) << 8); // Since Sega uses an odd ordering for the first part of the bitfield, // let's normalize the data and just send over bytes for the receiver @@ -206,4 +209,4 @@ static HRESULT swdc_io4_write_gpio(uint8_t* payload, size_t len) swdc_dll.led_set_leds(0, rgb_out); return S_OK; -} +} \ No newline at end of file diff --git a/games/tokyohook/io4.c b/games/tokyohook/io4.c index b2924c7..e1995eb 100644 --- a/games/tokyohook/io4.c +++ b/games/tokyohook/io4.c @@ -26,7 +26,7 @@ HRESULT tokyo_io4_hook_init(const struct io4_config *cfg) assert(tokyo_dll.init != NULL); - hr = io4_hook_init(cfg, &tokyo_io4_ops, NULL); + hr = io4_hook_init(cfg, &tokyo_io4_ops, NULL, L"STAR", false); if (FAILED(hr)) { return hr;