From 8c8680ad112f3ad1360aa5547392119ed4de6581 Mon Sep 17 00:00:00 2001 From: Michael Smith Date: Sat, 16 Jul 2022 16:37:25 +0100 Subject: Add keybind lookup code Also centralise NEXT_INSN macro, into its own header at least for now. --- src/alias.c | 11 +--------- src/bind.c | 70 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/bind.h | 28 ++++++++++++++++++++++++ src/demorec.c | 12 +--------- src/sst.c | 4 +++- src/x86util.h | 37 +++++++++++++++++++++++++++++++ 6 files changed, 140 insertions(+), 22 deletions(-) create mode 100644 src/bind.c create mode 100644 src/bind.h create mode 100644 src/x86util.h (limited to 'src') diff --git a/src/alias.c b/src/alias.c index 9d53e69..3605800 100644 --- a/src/alias.c +++ b/src/alias.c @@ -25,6 +25,7 @@ #include "gametype.h" #include "mem.h" #include "x86.h" +#include "x86util.h" struct alias **_alias_head; @@ -68,16 +69,6 @@ DEF_CCMD_HERE(sst_alias_clear, "Remove all command aliases", 0) { alias_nuke(); } -// XXX: same as in demorec, might want some abstraction for this -#define NEXT_INSN(p, tgt) do { \ - int _len = x86_len(p); \ - if (_len == -1) { \ - errmsg_errorx("unknown or invalid instruction looking for %s", tgt); \ - return false; \ - } \ - (p) += _len; \ -} while (0) - static bool find_alias_head(con_cmdcb alias_cb) { #ifdef _WIN32 for (uchar *p = (uchar *)alias_cb; p - (uchar *)alias_cb < 64;) { diff --git a/src/bind.c b/src/bind.c new file mode 100644 index 0000000..62cdec3 --- /dev/null +++ b/src/bind.c @@ -0,0 +1,70 @@ +/* + * Copyright © 2022 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 + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED “AS IS” AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include + +#include "con_.h" +#include "dbg.h" +#include "errmsg.h" +#include "hook.h" +#include "intdefs.h" +#include "mem.h" +#include "x86.h" +#include "x86util.h" + +struct keyinfo { + char *binding; + uchar keyuptgt : 3; + uchar pressed : 1; +}; +static struct keyinfo *keyinfo; // engine keybinds list (s_pKeyInfo[]) + +const char *bind_get(int keycode) { return keyinfo[keycode].binding; } + +static bool find_keyinfo(con_cmdcb klbc_cb) { +#ifdef _WIN32 + for (uchar *p = (uchar *)klbc_cb; p - (uchar *)klbc_cb < 32;) { + // key_listboundkeys command, in its loop through each possible index, + // does a mov from that index into a register, something like: + // mov , dword ptr [ * 8 + s_pKeyInfo] + if (p[0] == X86_MOVRMW && (p[1] & 0xC7) == 4 /* SIB + imm32 */ && + (p[2] & 0xC7) == 0xC5 /* [immediate + reg * 8] */) { + keyinfo = mem_loadptr(p + 3); + return true; + } + NEXT_INSN(p, "load from key binding list"); + } +#else +#warning TODO(linux): check whether linux is equivalent! +#endif + return false; +} + +bool bind_init(void) { + struct con_cmd *cmd_key_listboundkeys = con_findcmd("key_listboundkeys"); + if (!cmd_key_listboundkeys) { + errmsg_errorx("couldn't find key_listboundkeys command"); + return false; + } + con_cmdcb cb = con_getcmdcb(cmd_key_listboundkeys); + if (!find_keyinfo(cb)) { + errmsg_warnx("couldn't find key binding list"); + return false; + } + return true; +} + +// vi: sw=4 ts=4 noet tw=80 cc=80 diff --git a/src/bind.h b/src/bind.h new file mode 100644 index 0000000..4d91a96 --- /dev/null +++ b/src/bind.h @@ -0,0 +1,28 @@ +/* + * Copyright © 2022 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 + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED “AS IS” AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef INC_BIND_H +#define INC_BIND_H + +#include + +const char *bind_get(int keycode); + +bool bind_init(void); + +#endif + +// vi: sw=4 ts=4 noet tw=80 cc=80 diff --git a/src/demorec.c b/src/demorec.c index 17b1d08..b4a674d 100644 --- a/src/demorec.c +++ b/src/demorec.c @@ -32,6 +32,7 @@ #include "ppmagic.h" #include "vcall.h" #include "x86.h" +#include "x86util.h" DEF_CVAR(sst_autorecord, "Continuously record demos even after reconnecting", 1, CON_ARCHIVE | CON_HIDDEN) @@ -152,17 +153,6 @@ static void hook_stop_cb(const struct con_cmdargs *args) { wantstop = false; } -// XXX: probably want some general foreach-instruction macro once we start doing -// this kind of hackery in multiple different places -#define NEXT_INSN(p, tgt) do { \ - int _len = x86_len(p); \ - if (_len == -1) { \ - errmsg_errorx("unknown or invalid instruction looking for %s", tgt); \ - return false; \ - } \ - (p) += _len; \ -} while (0) - // This finds the "demorecorder" global variable (the engine-wide CDemoRecorder // instance). static inline bool find_demorecorder(void) { diff --git a/src/sst.c b/src/sst.c index 1321d03..93908dc 100644 --- a/src/sst.c +++ b/src/sst.c @@ -22,6 +22,7 @@ #endif #include "ac.h" +#include "bind.h" #include "alias.h" #include "autojump.h" #include "con_.h" @@ -190,7 +191,7 @@ static const void *const *const plugin_obj; // figures out the dependencies at build time and generates all the init glue // but we want to actually release the plugin this decade so for now I'm just // plonking some bools here and worrying about it later. :^) -static bool has_ac = false, has_autojump = false, has_demorec = false, +static bool has_ac = false, has_autojump = false, has_demorec = false, has_fov = false, has_nosleep = false, has_portalcolours = false; #ifdef _WIN32 static bool has_rinput = false; @@ -206,6 +207,7 @@ static const char *updatenotes = "\ "; static void do_featureinit(void) { + bool has_bind = bind_init(); has_ac = ac_init(); bool has_alias = alias_init(); has_autojump = autojump_init(); diff --git a/src/x86util.h b/src/x86util.h new file mode 100644 index 0000000..0ae89ae --- /dev/null +++ b/src/x86util.h @@ -0,0 +1,37 @@ +/* + * Copyright © 2022 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 + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED “AS IS” AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef INC_X86UTIL_H +#define INC_X86UTIL_H + +#include + +#include "errmsg.h" +#include "x86.h" + +// XXX: don't know where else to put this, or how else to design this, so this +// is very much a plonk-it-here-for-now scenario. + +#define NEXT_INSN(p, tgt) do { \ + int _len = x86_len(p); \ + if (_len == -1) { \ + errmsg_errorx("unknown or invalid instruction looking for %s", tgt); \ + return false; \ + } \ + (p) += _len; \ +} while (0) + +#endif -- cgit v1.2.3