diff options
author | Willian Henrique <wsimanbrazil@yahoo.com.br> | 2022-07-16 18:08:23 +0100 |
---|---|---|
committer | Michael Smith <mikesmiffy128@gmail.com> | 2022-07-23 19:07:03 +0100 |
commit | b53b780e1b14e174204457765b4a0a72b6d2924f (patch) | |
tree | dad9999812afc77fbb09dfefa7aec5739b794017 /src/ac.c | |
parent | 8c8680ad112f3ad1360aa5547392119ed4de6581 (diff) |
Add stuff to track keypresses
Committer's note: this is somewhat adapted from Bill's original code,
written a while back, but he gets full credit for actually doing the
hard part.
Diffstat (limited to 'src/ac.c')
-rw-r--r-- | src/ac.c | 106 |
1 files changed, 106 insertions, 0 deletions
@@ -1,5 +1,6 @@ /* * Copyright © 2022 Michael Smith <mikesmiffy128@gmail.com> + * Copyright © 2022 Willian Henrique <wsimanbrazil@yahoo.com.br> * * 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,6 +18,7 @@ #include <stdbool.h> #include <stdlib.h> +#include "bind.h" #include "con_.h" #include "hook.h" #include "engineapi.h" @@ -25,6 +27,9 @@ #include "mem.h" #include "os.h" #include "ppmagic.h" +#include "vcall.h" +#include "x86.h" +#include "x86util.h" static bool lockdown = false; @@ -134,17 +139,118 @@ static void endlockdown(void) { lockdown = false; } +enum /* from InputEventType_t - terser names used here */ { + BTNDOWN = 0, // data contains button code + BTNUP, // " + BTNDOUBLECLICK, // " + ANALOGUEVALCHG, // data contains analogue code, data2 contains value + SYSQUIT = 100, + SYSCTRLHOTPLUG, // data contains controller ID + SYSCTRLCOLDPLUG, // " + // ranges for other things + FIRSTVGUIEV = 1000, + FIRSTAPPEV = 2000 +}; + +struct inputevent { + int type; // above enum + int tick; + int data, data2, data3; +}; + +DECL_VFUNC_DYN(void, GetDesktopResolution, int *, int *) +DECL_VFUNC_DYN(void, DispatchAllStoredGameMessages) + +typedef void (*VCALLCONV DispatchInputEvent_func)(void *, struct inputevent *); +static DispatchInputEvent_func orig_DispatchInputEvent; +static void VCALLCONV hook_DispatchInputEvent(void *this, + struct inputevent *ev) { + // TODO(rta): do something here! (here's a quick reference/example) + //switch (ev->type) { + // CASES(BTNDOWN, BTNUP, BTNDOUBLECLICK): + // const char *desc[] = {"DOWN", "UP", "DOUBLE"}; + // const char *binding = bind_get(ev->data); + // if (!binding) binding = "[unbound]"; + // con_msg("key %d %s => %s\n", ev->data, desc[ev->type - BTNDOWN], + // binding); + //} + orig_DispatchInputEvent(this, ev); +} + +static bool find_DispatchInputEvent(void) { +#ifdef _WIN32 + // Crazy pointer-chasing path to get to DispachInputEvent (to log keypresses + // and their associated binds): + // IGameUIFuncs interface + // -> CGameUIFuncs::GetDesktopResolution vfunc + // -> IGame/CGame (first mov into ECX) + // -> CGame::DispatchAllStoredGameMessages vfunc + // -> DispatchInputEvent (first call instruction) + void *gameuifuncs = factory_engine("VENGINE_GAMEUIFUNCS_VERSION005", 0); + if (!gameuifuncs) { + errmsg_errorx("couldn't get engine game UI interface"); + return false; + } + void *cgame; + GetDesktopResolution_func GetDesktopResolution = + VFUNC(gameuifuncs, GetDesktopResolution); + for (uchar *p = (uchar *)GetDesktopResolution; + p - (uchar *)GetDesktopResolution < 16;) { + if (p[0] == X86_MOVRMW && p[1] == X86_MODRM(0, 1, 5)) { + void **indirect = mem_loadptr(p + 2); + cgame = *indirect; + goto ok; + } + NEXT_INSN(p, "CGame instance pointer"); + } + errmsg_errorx("couldn't find pointer to CGame instance"); + return false; +ok: DispatchAllStoredGameMessages_func DispatchAllStoredGameMessages = + VFUNC(cgame, DispatchAllStoredGameMessages); + for (uchar *p = (uchar *)DispatchAllStoredGameMessages; + p - (uchar *)DispatchAllStoredGameMessages < 128;) { + if (p[0] == X86_CALL) { + orig_DispatchInputEvent = (DispatchInputEvent_func)(p + 5 + + mem_loadoffset(p + 1)); + // Note: we could go further and dig HandleEngineKey from Key_Event, + // but it seems like Key_Event isn't directly called from + // DispatchInputEvent in L4D2 (or has a much different structure, + // requiring another function call to lead to HandleEngineKey). + return true; + } + NEXT_INSN(p, "DispatchInputEvent function"); + } + errmsg_errorx("couldn't find DispatchInputEvent function"); +#else +#warning TODO(linux): more find-y stuff +#endif + return false; +} + bool ac_init(void) { + if (!has_vtidx_GetDesktopResolution || + !has_vtidx_DispatchAllStoredGameMessages) { + errmsg_errorx("missing gamedata entries for this engine"); + return false; + } #if defined(_WIN32) if (!win32_init()) return false; #elif defined(__linux__) // TODO(linux): call init things #endif + if (!find_DispatchInputEvent()) return false; + orig_DispatchInputEvent = (DispatchInputEvent_func)hook_inline( + (void *)orig_DispatchInputEvent, (void *)&hook_DispatchInputEvent); + if (!orig_DispatchInputEvent) { + errmsg_errorsys("couldn't hook DispatchInputEvent function"); + return false; + } return true; } void ac_end(void) { endlockdown(); + unhook_inline((void *)orig_DispatchInputEvent); } // vi: sw=4 ts=4 noet tw=80 cc=80 |