From 182b36609acc44d3338f64ca3975e1604b50f619 Mon Sep 17 00:00:00 2001 From: Michael Smith Date: Fri, 5 May 2023 00:07:39 +0100 Subject: Somewhat expand on WIP ac.c stuff This still isn't totally complete, or used anywhere yet, but it's been sitting here for literally months, so it might as well get committed so there's one less thing to deal with later. --- src/ac.c | 73 ++++++++++++++++++++++++++++++++++++++++++++++++---------------- src/ac.h | 5 +++-- 2 files changed, 58 insertions(+), 20 deletions(-) (limited to 'src') diff --git a/src/ac.c b/src/ac.c index 326894a..01b969f 100644 --- a/src/ac.c +++ b/src/ac.c @@ -1,5 +1,5 @@ /* - * Copyright © 2022 Michael Smith + * Copyright © 2023 Michael Smith * Copyright © 2022 Willian Henrique * * Permission to use, copy, modify, and/or distribute this software for any @@ -16,6 +16,9 @@ */ #include +#ifdef _WIN32 +#include +#endif #include "bind.h" #include "con_.h" @@ -67,29 +70,50 @@ static ssize __stdcall mproc(int code, UINT_PTR wp, ssize lp) { // this is its own thread to meet the strict timing deadline, otherwise the // hook gets silently removed. plus, we don't wanna incur latency anyway. -static ulong __stdcall inhookthrmain(void *unused) { +static ulong __stdcall inhookthrmain(void *param) { + volatile u32 *sig = param; if (!SetWindowsHookExW(WH_KEYBOARD_LL, &kproc, 0, 0) || !SetWindowsHookExW(WH_MOUSE_LL, &mproc, 0, 0)) { + *sig = 2; return -1; } + *sig = 1; MSG m; int ret; while ((ret = GetMessageW(&m, inhookwin, 0, 0)) > 0) DispatchMessage(&m); return ret; } +static WNDPROC orig_wndproc; +static ssize __stdcall hook_wndproc(void *wnd, uint msg, UINT_PTR wp, ssize lp) { + if (msg == WM_COPYDATA && lockdown) return DefWindowProcW(wnd, msg, wp, lp); + return orig_wndproc(wnd, msg, wp, lp); +} + static bool win32_init(void) { gamewin = FindWindowW(L"Valve001", 0); + // note: error messages here are a bit cryptic on purpose, but easy to find + // in the code. in other words, we're hiding in plain sight :-) if (!gamewin) { - errmsg_errorsys("failed to get game window handle"); + errmsg_errorsys("failed to find window"); return false; } + orig_wndproc = (WNDPROC)SetWindowLongPtrW(gamewin, GWLP_WNDPROC, + (ssize)hook_wndproc); + if (!orig_wndproc) { + errmsg_errorsys("failed to attach message handler"); + } return true; } -static void inhook_start(void) { - inhookwin = CreateWindowW(L"sst-eventloop", L"sst-eventloop", - WS_DISABLED, 0, 0, 0, 0, HWND_MESSAGE, 0, 0, 0); - inhookthr = CreateThread(0, 0, &inhookthrmain, 0, 0, &inhooktid); +static void win32_end(void) { + // no error handling here because we'd crash either way. good luck! + SetWindowLongW(gamewin, GWLP_WNDPROC, (ssize)orig_wndproc); +} + +static void inhook_start(volatile u32 *sig) { + inhookwin = CreateWindowW(L"sst-eventloop", L"sst-eventloop", WS_DISABLED, + 0, 0, 0, 0, HWND_MESSAGE, 0, 0, 0); + inhookthr = CreateThread(0, 0, &inhookthrmain, (u32 *)sig, 0, &inhooktid); } static void inhook_check(void) { @@ -120,6 +144,7 @@ static void inhook_stop(void) { // not much else we can do now! con_warn("warning: RTA mode message loop had an error during shutdown"); } + CloseHandle(inhookthr); } #else @@ -128,20 +153,27 @@ static void inhook_stop(void) { #endif -// TODO(rta): call these functions as part of the run lifecycle - -static void startlockdown(void) { - if (lockdown) return; +bool ac_enable(void) { + if (lockdown) return true; #ifdef _WIN32 - inhook_start(); + // and now for some frivolously microoptimised spinlocking nonsense + volatile u32 sig = 0; // paranoid volatile to ensure no loop misopt... + inhook_start(&sig); + register u32 x; // avoid double-reading the volatile + // pausing in the middle here seems to produce shorter asm with gcc -O2 and + // clang -O3 in godbolt (avoids unrolling of head which is unlikely to help) + while (x = sig, _mm_pause(), !x); + if (x == 2) { // else 1 for success + con_warn("** sst: ERROR starting message loop, can't continue! **"); + CloseHandle(inhookthr); + return false; + } #endif - // FIXME: should really have some semaphore to make sure inhook thread got - // going okay... lockdown = true; - // TODO(rta): start demos, etc + return true; } -HANDLE_EVENT(Tick) { +HANDLE_EVENT(Tick, bool simulating) { #ifdef _WIN32 static uint fewticks = 0; // just check this every so often (roughly 0.1-0.3s depending on game) @@ -149,7 +181,7 @@ HANDLE_EVENT(Tick) { #endif } -static void endlockdown(void) { +void ac_disable(void) { if (!lockdown) return; #ifdef _WIN32 inhook_stop(); @@ -262,7 +294,12 @@ INIT { } END { - endlockdown(); +#if defined(_WIN32) + win32_end(); +#elif defined(__linux__) + // TODO(linux): call cleanup things +#endif + ac_disable(); unhook_inline((void *)orig_DispatchInputEvent); } diff --git a/src/ac.h b/src/ac.h index 7b48cd1..2da6446 100644 --- a/src/ac.h +++ b/src/ac.h @@ -1,5 +1,5 @@ /* - * Copyright © 2022 Michael Smith + * Copyright © 2023 Michael Smith * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -17,7 +17,8 @@ #ifndef INC_AC_H #define INC_AC_H -// TODO(rta): keeping this header here as I expect to expose some functions... +bool ac_enable(void); +void ac_disable(void); #endif -- cgit v1.2.3