Implement dynamic IMTs.

Now the user can create and destroy IMTs at will, though currently
destroying IMTs is currently all or nothing (imt_drop_all).

An IMT is created via imt_create which takes the keydest name (key_game
etc), the name of the IMT (must be unique for all IMTs) and optionally the
name of the IMT to which the key binding search will fall back if there is
no binding in the current IMT, but must be already defined and on the same
keydest. This means that IMTs now have user determined fallback paths. The
requirements for the fallback IMT prevent loops and other weird behaviour.

Actual key binding via in_bind is unaffected. This is why the IMT name must
be unique across all IMTs.

The "imt" command works with the key_game keydest, but imt_keydest is
provided for specifying the active IMT for a specific keydest.

At startup, default IMTs are setup to emulate the previous static IMTs so
old configs will continue to work (mostly). New config files will be
written with commands to drop all of the current IMTs and build new ones,
with the bindings and active IMT set as well.
This commit is contained in:
Bill Currie 2013-01-16 19:35:23 +09:00
parent ec6ba8a03c
commit ace8d9ebc5
6 changed files with 424 additions and 230 deletions

View file

@ -413,37 +413,15 @@ typedef enum {
QFK_LAST QFK_LAST
} knum_t; } knum_t;
typedef enum {
IMT_MENU,
IMT_CONSOLE,
IMT_MOD,
IMT_DEMO,
IMT_0,
IMT_1,
IMT_2,
IMT_3,
IMT_4,
IMT_5,
IMT_6,
IMT_7,
IMT_8,
IMT_9,
IMT_10,
IMT_11,
IMT_12,
IMT_13,
IMT_14,
IMT_15,
IMT_16,
IMT_LAST,
} imt_t; // Input Mapping Table
typedef enum { typedef enum {
key_unfocused, // engine has lost input focus key_unfocused, // engine has lost input focus
key_game, key_game,
key_demo,
key_console, key_console,
key_message, key_message,
key_menu, key_menu,
key_last // enum size
} keydest_t; } keydest_t;
#ifndef __QFCC__ #ifndef __QFCC__
@ -452,15 +430,34 @@ typedef struct {
int state; // low bit is down state int state; // low bit is down state
} kbutton_t; } kbutton_t;
extern imt_t key_game_target;
extern knum_t key_togglemenu; extern knum_t key_togglemenu;
extern knum_t key_toggleconsole; extern knum_t key_toggleconsole;
extern struct keybind_s { typedef struct keybind_s {
char *str; char *str;
} keybindings[IMT_LAST][QFK_LAST]; } keybind_t;
/** Input Mapping Table
*/
typedef struct imt_s {
struct imt_s *next; ///< list of tables attached to key_dest
struct imt_s *chain; ///< fallback table if key not bound
const char *name; ///< for user interaction
keybind_t bindings[QFK_LAST];
int written; ///< avoid duplicate config file writes
} imt_t;
typedef struct keytarget_s {
imt_t *imts;
imt_t *active;
} keytarget_t;
extern int keydown[QFK_LAST]; extern int keydown[QFK_LAST];
imt_t *Key_FindIMT (const char *imt_name);
void Key_CreateIMT (keydest_t kd, const char *imt_name,
const char *chain_imt_name);
struct cbuf_s; struct cbuf_s;
void Key_Event (knum_t key, short unicode, qboolean down); void Key_Event (knum_t key, short unicode, qboolean down);
void Key_FocusEvent (int gain); void Key_FocusEvent (int gain);
@ -468,8 +465,8 @@ void Key_Init (struct cbuf_s *cb);
void Key_Init_Cvars (void); void Key_Init_Cvars (void);
void Key_WriteBindings (QFile *f); void Key_WriteBindings (QFile *f);
void Key_ClearStates (void); void Key_ClearStates (void);
const char *Key_GetBinding (imt_t imt, knum_t key); const char *Key_GetBinding (const char *imt_name, knum_t key);
void Key_SetBinding (imt_t target, knum_t keynum, const char *binding); void Key_SetBinding (imt_t *imt, knum_t keynum, const char *binding);
void Key_SetKeyDest(keydest_t kd); void Key_SetKeyDest(keydest_t kd);
typedef void keydest_callback_t (keydest_t); typedef void keydest_callback_t (keydest_t);
void Key_KeydestCallback (keydest_callback_t *callback); void Key_KeydestCallback (keydest_callback_t *callback);

View file

@ -59,8 +59,8 @@ static U void (*const key_progs_init)(struct progs_s *) = Key_Progs_Init;
/* key up events are sent even if in console mode */ /* key up events are sent even if in console mode */
VISIBLE keydest_t key_dest = key_unfocused; static keydest_t key_dest = key_unfocused;
VISIBLE imt_t key_game_target = IMT_0; static keytarget_t key_targets[key_last];
VISIBLE knum_t key_togglemenu = QFK_ESCAPE; VISIBLE knum_t key_togglemenu = QFK_ESCAPE;
VISIBLE knum_t key_toggleconsole = QFK_BACKQUOTE; VISIBLE knum_t key_toggleconsole = QFK_BACKQUOTE;
@ -69,46 +69,28 @@ static keydest_callback_t **keydest_callbacks;
static int num_keydest_callbacks; static int num_keydest_callbacks;
static int max_keydest_callbacks; static int max_keydest_callbacks;
VISIBLE struct keybind_s keybindings[IMT_LAST][QFK_LAST];
VISIBLE int keydown[QFK_LAST]; VISIBLE int keydown[QFK_LAST];
static imt_t key_target = IMT_CONSOLE;
static int keyhelp; static int keyhelp;
static cbuf_t *cbuf; static cbuf_t *cbuf;
static const char *keydest_names[] = {
"key_unfocused",
"key_game",
"key_demo",
"key_console",
"key_message",
"key_menu",
"key_last"
};
typedef struct { typedef struct {
const char *name; const char *name;
imt_t imtnum; imt_t imtnum;
} imtname_t; } imtname_t;
imtname_t imtnames[] = {
{"IMT_MENU", IMT_MENU},
{"IMT_CONSOLE", IMT_CONSOLE},
{"IMT_MOD", IMT_MOD},
{"IMT_DEMO", IMT_DEMO},
{"IMT_0", IMT_0},
{"IMT_1", IMT_1},
{"IMT_2", IMT_2},
{"IMT_3", IMT_3},
{"IMT_4", IMT_4},
{"IMT_5", IMT_5},
{"IMT_6", IMT_6},
{"IMT_7", IMT_7},
{"IMT_8", IMT_8},
{"IMT_9", IMT_9},
{"IMT_10", IMT_10},
{"IMT_11", IMT_11},
{"IMT_12", IMT_12},
{"IMT_13", IMT_13},
{"IMT_14", IMT_14},
{"IMT_15", IMT_15},
{"IMT_16", IMT_16},
{"IMT_DEFAULT", IMT_0},
{NULL, 0}
};
typedef struct { typedef struct {
const char *name; const char *name;
knum_t keynum; knum_t keynum;
@ -464,6 +446,81 @@ keyname_t keynames[] = {
{NULL, 0} {NULL, 0}
}; };
static imt_t *
key_target_find_imt (keytarget_t *kt, const char *imt_name)
{
imt_t *imt;
for (imt = kt->imts; imt; imt = imt->next) {
if (!strcasecmp (imt->name, imt_name)) {
return imt;
}
}
return 0;
}
VISIBLE imt_t *
Key_FindIMT (const char *imt_name)
{
keydest_t kd;
imt_t *imt = 0;
for (kd = key_unfocused; !imt && kd < key_last; kd++) {
imt = key_target_find_imt (&key_targets[kd], imt_name);
}
return imt;
}
void
Key_CreateIMT (keydest_t kd, const char *imt_name, const char *chain_imt_name)
{
imt_t *imt;
imt_t *chain_imt = 0;
keytarget_t *kt = &key_targets[kd];
imt = Key_FindIMT (imt_name);
if (imt) {
Sys_Printf ("imt error: imt %s already exists\n", imt_name);
return;
}
if (chain_imt_name) {
chain_imt = Key_FindIMT (chain_imt_name);
if (!chain_imt) {
Sys_Printf ("imt error: chain imt %s does not exist\n",
chain_imt_name);
return;
}
imt = key_target_find_imt (kt, chain_imt_name);
if (!imt) {
Sys_Printf ("imt error: chain imt %s not on target key "
"destination\n", chain_imt_name);
return;
}
}
imt = calloc (1, sizeof (imt_t));
imt->name = strdup (imt_name);
imt->chain = chain_imt;
imt->next = kt->imts;
kt->imts = imt;
if (!kt->active) {
kt->active = imt;
}
}
VISIBLE void
Key_SetBinding (imt_t *imt, knum_t keynum, const char *binding)
{
if (keynum == (knum_t) -1)
return;
if (imt->bindings[keynum].str) {
free (imt->bindings[keynum].str);
imt->bindings[keynum].str = NULL;
}
if (binding) {
imt->bindings[keynum].str = strdup(binding);
}
}
static void static void
Key_CallDestCallbacks (keydest_t kd) Key_CallDestCallbacks (keydest_t kd)
{ {
@ -490,6 +547,7 @@ process_binding (knum_t key, const char *kb)
} }
Cbuf_AddText (cbuf, cmd); Cbuf_AddText (cbuf, cmd);
} }
/* /*
Key_Game Key_Game
@ -499,25 +557,22 @@ static qboolean
Key_Game (knum_t key, short unicode) Key_Game (knum_t key, short unicode)
{ {
const char *kb; const char *kb;
imt_t *imt = key_targets[key_dest].active;
kb = Key_GetBinding (key_target, key); while (imt) {
if (!kb && (key_target > IMT_0)) kb = imt->bindings[key].str;
kb = Key_GetBinding (IMT_0, key); if (kb) {
if (!kb && (key_target >= IMT_MOD)) if (keydown[key] <= 1)
kb = Key_GetBinding (IMT_MOD, key); process_binding (key, kb);
return true;
}
imt = imt->chain;
}
return false;
/* /*
Sys_DPrintf("kb %p, key_target %d, key_dest %d, key %d\n", kb, Sys_DPrintf("kb %p, key_target %d, key_dest %d, key %d\n", kb,
key_target, key_dest, key); key_target, key_dest, key);
*/ */
if (!kb)
return false;
if (keydown[key] > 1)
return true;
process_binding (key, kb);
return true;
} }
/* /*
@ -537,48 +592,6 @@ Key_Console (knum_t key, short unicode)
//============================================================================ //============================================================================
/*
Key_StringToIMTnum
Returns an imt number to be used to index imtbindings[] by looking at
the given string. Single ascii characters return themselves, while
the QFK_* names are matched up.
*/
static int
Key_StringToIMTnum (const char *str)
{
imtname_t *kn;
if (!str || !str[0])
return -1;
for (kn = imtnames; kn->name; kn++) {
if (!strcasecmp (str, kn->name))
return kn->imtnum;
}
return -1;
}
/*
Key_IMTnumToString
Returns a string (a QFK_* name) for the given imtnum.
FIXME: handle quote special (general escape sequence?)
*/
static const char *
Key_IMTnumToString (const imt_t imtnum)
{
imtname_t *kn;
if (imtnum == (imt_t) -1)
return "<IMT NOT FOUND>";
for (kn = imtnames; kn->name; kn++)
if (imtnum == kn->imtnum)
return kn->name;
return "<UNKNOWN IMTNUM>";
}
/* /*
Key_StringToKeynum Key_StringToKeynum
@ -623,23 +636,24 @@ Key_KeynumToString (knum_t keynum)
} }
static void static void
Key_In_Unbind (const char *imt, const char *key) Key_In_Unbind (const char *imt_name, const char *key_name)
{ {
int t, b; imt_t *imt;
int key;
t = Key_StringToIMTnum (imt); imt = Key_FindIMT (imt_name);
if (t == -1) { if (!imt) {
Sys_Printf ("\"%s\" isn't a valid imt\n", imt); Sys_Printf ("\"%s\" isn't a valid imt\n", imt_name);
return; return;
} }
b = Key_StringToKeynum (key); key = Key_StringToKeynum (key_name);
if (b == -1) { if (key == -1) {
Sys_Printf ("\"%s\" isn't a valid key\n", key); Sys_Printf ("\"%s\" isn't a valid key\n", key_name);
return; return;
} }
Key_SetBinding (t, b, NULL); Key_SetBinding (imt, key, NULL);
} }
static void static void
@ -655,18 +669,24 @@ Key_In_Unbind_f (void)
static void static void
Key_Unbindall_f (void) Key_Unbindall_f (void)
{ {
int i, j; keydest_t kd;
imt_t *imt;
int i;
for (j = 0; j < IMT_LAST; j++) for (kd = key_unfocused; kd < key_last; kd++) {
for (i = 0; i < QFK_LAST; i++) for (imt = key_targets[kd].imts; imt; imt = imt->next) {
Key_SetBinding (j, i, NULL); for (i = 0; i < QFK_LAST; i++) {
Key_SetBinding (imt, i, 0);
}
}
}
} }
static void static void
Key_In_Clear (void) Key_In_Clear (void)
{ {
int err = 0; int err = 0;
int imt; imt_t *imt;
int i, j; int i, j;
if (Cmd_Argc () == 1) { if (Cmd_Argc () == 1) {
@ -674,7 +694,7 @@ Key_In_Clear (void)
return; return;
} }
for (i = 1; i < Cmd_Argc (); i++) { for (i = 1; i < Cmd_Argc (); i++) {
if (Key_StringToIMTnum (Cmd_Argv (i)) == -1) { if (!Key_FindIMT (Cmd_Argv (i))) {
Sys_Printf ("\"%s\" isn't a valid imt\n", Cmd_Argv (i)); Sys_Printf ("\"%s\" isn't a valid imt\n", Cmd_Argv (i));
err = 1; err = 1;
} }
@ -682,38 +702,85 @@ Key_In_Clear (void)
if (err) if (err)
return; return;
for (i = 1; i < Cmd_Argc (); i++) { for (i = 1; i < Cmd_Argc (); i++) {
imt = Key_StringToIMTnum (Cmd_Argv (i)); imt = Key_FindIMT (Cmd_Argv (i));
for (j = 0; j < QFK_LAST; j++) for (j = 0; j < QFK_LAST; j++)
Key_SetBinding (imt, j, NULL); Key_SetBinding (imt, j, NULL);
} }
} }
static void static void
Key_In_Bind (const char *imt, const char *key, const char *cmd) Key_IMT_Create_f (void)
{ {
int t, b; const char *keydest;
const char *imt_name;
const char *chain_imt_name = 0;
keydest_t kd;
t = Key_StringToIMTnum (imt); if (Cmd_Argc () < 3 || Cmd_Argc () > 4) {
if (t == -1) { Sys_Printf ("see help imt_create\n");
Sys_Printf ("\"%s\" isn't a valid imt\n", imt); return;
}
keydest = Cmd_Argv (1);
imt_name = Cmd_Argv (2);
if (Cmd_Argc () == 4) {
chain_imt_name = Cmd_Argv (3);
}
for (kd = key_game; kd < key_last; kd++) {
if (!strcasecmp (keydest_names[kd], keydest)) {
break;
}
}
if (kd == key_last) {
Sys_Printf ("imt error: invalid keydest: %s\n", keydest);
return;
}
Key_CreateIMT (kd, imt_name, chain_imt_name);
}
static void
Key_IMT_Drop_All_f (void)
{
keydest_t kd;
imt_t *imt;
for (kd = key_unfocused; kd < key_last; kd++) {
while (key_targets[kd].imts) {
imt = key_targets[kd].imts;
key_targets[kd].imts = imt->next;
free ((char *) imt->name);
free (imt);
}
key_targets[kd].active = 0;
}
}
static void
Key_In_Bind (const char *imt_name, const char *key_name, const char *cmd)
{
imt_t *imt;
int key;
imt = Key_FindIMT (imt_name);
if (!imt) {
Sys_Printf ("\"%s\" isn't a valid imt\n", imt_name);
return; return;
} }
b = Key_StringToKeynum (key); key = Key_StringToKeynum (key_name);
if (b == -1) { if (key == -1) {
Sys_Printf ("\"%s\" isn't a valid key\n", key); Sys_Printf ("\"%s\" isn't a valid key\n", key_name);
return; return;
} }
if (!cmd) { if (!cmd) {
if (Key_GetBinding (t, b)) if (imt->bindings[key].str)
Sys_Printf ("%s %s \"%s\"\n", imt, key, Sys_Printf ("%s %s \"%s\"\n", imt_name, key_name,
Key_GetBinding(t, b)); imt->bindings[key].str);
else else
Sys_Printf ("%s %s is not bound\n", imt, key); Sys_Printf ("%s %s is not bound\n", imt_name, key_name);
return; return;
} }
Key_SetBinding (t, b, cmd); Key_SetBinding (imt, key, cmd);
} }
static void static void
@ -810,7 +877,7 @@ Key_GIB_Bind_Get_f (void)
return; return;
} }
if (!(cmd = Key_GetBinding (IMT_MOD, k))) if (!(cmd = Key_GetBinding ("IMT_MOD", k)))
GIB_Return (""); GIB_Return ("");
else else
GIB_Return (cmd); GIB_Return (cmd);
@ -853,49 +920,137 @@ in_key_toggleconsole_f (cvar_t *var)
static void static void
Key_InputMappingTable_f (void) Key_InputMappingTable_f (void)
{ {
int c, t; int c;
imt_t *imt;
c = Cmd_Argc (); c = Cmd_Argc ();
if (c != 2) { if (c != 2) {
Sys_Printf ("Current imt is %s\n", Key_IMTnumToString(key_target)); Sys_Printf ("Current imt is %s\n", key_targets[key_game].active->name);
Sys_Printf ("imt <imt> : set to a specific input mapping table\n"); Sys_Printf ("imt <imt> : set to a specific input mapping table\n");
return; return;
} }
t = Key_StringToIMTnum (Cmd_Argv (1)); imt = Key_FindIMT (Cmd_Argv (1));
if (t == -1) { if (!imt) {
Sys_Printf ("\"%s\" isn't a valid imt\n", Cmd_Argv (1)); Sys_Printf ("\"%s\" isn't a valid imt\n", Cmd_Argv (1));
return; return;
} }
key_target = t; key_targets[key_game].active = imt;
} }
/* static void
Key_WriteBindings Key_IMT_Keydest_f (void)
{
int c;
imt_t *imt;
const char *imt_name = 0;
const char *keydest;
keydest_t kd;
c = Cmd_Argc ();
switch (c) {
case 3:
imt_name = Cmd_Argv (2);
case 2:
keydest = Cmd_Argv (1);
break;
default:
return;
}
for (kd = key_game; kd < key_last; kd++) {
if (!strcasecmp (keydest_names[kd], keydest)) {
break;
}
}
if (kd == key_last) {
Sys_Printf ("imt error: invalid keydest: %s\n", keydest);
return;
}
if (!imt_name) {
Sys_Printf ("Current imt is %s\n", key_targets[key_game].active->name);
Sys_Printf ("imt <imt> : set to a specific input mapping table\n");
return;
}
imt = key_target_find_imt (&key_targets[kd], imt_name);
if (!imt) {
Sys_Printf ("\"%s\" isn't an imt on %s\n", imt_name, keydest);
return;
}
key_targets[kd].active = imt;
}
static void __attribute__((format(printf,2,3)))
key_printf (QFile *f, const char *fmt, ...)
{
va_list args;
static dstring_t *string;
if (!string) {
string = dstring_new ();
}
va_start (args, fmt);
dvsprintf (string, fmt, args);
va_end (args);
if (f) {
Qprintf (f, "%s", string->str);
} else {
Sys_Printf ("%s", string->str);
}
}
static void
key_write_imt (QFile *f, keydest_t kd, imt_t *imt)
{
int i;
const char *bind;
if (!imt || imt->written) {
return;
}
imt->written = 1;
key_write_imt (f, kd, imt->chain);
if (imt->chain) {
key_printf (f, "imt_create %s %s %s\n", keydest_names[kd],
imt->name, imt->chain->name);
} else {
key_printf (f, "imt_create %s %s\n", keydest_names[kd], imt->name);
}
for (i = 0; i < QFK_LAST; i++) {
bind = imt->bindings[i].str;
if (bind) {
key_printf (f, "in_bind %s %s \"%s\"\n", imt->name,
Key_KeynumToString (i), bind);
}
}
}
Writes lines containing "bind key value"
*/
void void
Key_WriteBindings (QFile *f) Key_WriteBindings (QFile *f)
{ {
int i, j; keydest_t kd;
const char *bind; imt_t *imt;
for (j = 0; j < IMT_LAST; j++) for (kd = key_unfocused; kd < key_last; kd++) {
for (i = 0; i < QFK_LAST; i++) for (imt = key_targets[kd].imts; imt; imt = imt->next) {
if ((bind = Key_GetBinding(j, i))) { imt->written = 0;
if (f) { }
Qprintf (f, "in_bind %s %s \"%s\"\n", }
Key_IMTnumToString (j), key_printf (f, "imt_drop_all\n");
Key_KeynumToString (i), bind); for (kd = key_unfocused; kd < key_last; kd++) {
} else { if (key_targets[kd].imts) {
Sys_Printf ("in_bind %s %s \"%s\"\n", for (imt = key_targets[kd].imts; imt; imt = imt->next) {
Key_IMTnumToString (j), key_write_imt (f, kd, imt);
Key_KeynumToString (i), bind);
}
} }
key_printf (f, "imt_keydest %s %s\n", keydest_names[kd],
key_targets[kd].active->name);
}
}
} }
static void static void
@ -979,11 +1134,54 @@ Key_ClearStates (void)
} }
} }
static struct {
keydest_t kd;
const char *imt_name;
const char *chain_imt_name;
} default_imts[] = {
{key_game, "imt_mod", 0},
{key_game, "imt_0", "imt_mod"},
{key_game, "imt_1", "imt_0"},
{key_game, "imt_2", "imt_0"},
{key_game, "imt_3", "imt_0"},
{key_game, "imt_4", "imt_0"},
{key_game, "imt_5", "imt_0"},
{key_game, "imt_6", "imt_0"},
{key_game, "imt_7", "imt_0"},
{key_game, "imt_8", "imt_0"},
{key_game, "imt_9", "imt_0"},
{key_game, "imt_10", "imt_0"},
{key_game, "imt_11", "imt_0"},
{key_game, "imt_12", "imt_0"},
{key_game, "imt_13", "imt_0"},
{key_game, "imt_14", "imt_0"},
{key_game, "imt_15", "imt_0"},
{key_game, "imt_16", "imt_0"},
{key_demo, "imt_demo", 0},
{key_console, "imt_console", 0},
{key_message, "imt_message", 0},
{key_menu, "imt_menu", 0},
{key_last, 0, 0},
};
static void
Key_CreateDefaultIMTs (void)
{
int i;
for (i = 0; default_imts[i].kd != key_last; i++) {
Key_CreateIMT (default_imts[i].kd, default_imts[i].imt_name,
default_imts[i].chain_imt_name);
}
}
void void
Key_Init (cbuf_t *cb) Key_Init (cbuf_t *cb)
{ {
cbuf = cb; cbuf = cb;
Key_CreateDefaultIMTs ();
OK_Init (); OK_Init ();
// register our functions // register our functions
@ -998,6 +1196,17 @@ Key_Init (cbuf_t *cb)
Cmd_AddCommand ("in_clear", Key_In_Clear, Cmd_AddCommand ("in_clear", Key_In_Clear,
"Remove all binds from the specified imts"); "Remove all binds from the specified imts");
Cmd_AddCommand ("imt", Key_InputMappingTable_f, ""); Cmd_AddCommand ("imt", Key_InputMappingTable_f, "");
Cmd_AddCommand ("imt_keydest", Key_IMT_Keydest_f, "");
Cmd_AddCommand ("imt_create", Key_IMT_Create_f,
"create a new imt table:\n"
" imt_create <keydest> <imt_name> [chain_name]\n"
"\n"
"The new table will be attached to the specified keydest\n"
"imt_name must not already exist.\n"
"If given, chain_name must already exist and be on "
"keydest.\n");
Cmd_AddCommand ("imt_drop_all", Key_IMT_Drop_All_f,
"delete all imt tables\n");
Cmd_AddCommand ("bind", Key_Bind_f, "wrapper for in_bind that uses " Cmd_AddCommand ("bind", Key_Bind_f, "wrapper for in_bind that uses "
"in_bind_imt for the imt parameter"); "in_bind_imt for the imt parameter");
Cmd_AddCommand ("unbind", Key_Unbind_f, Cmd_AddCommand ("unbind", Key_Unbind_f,
@ -1023,46 +1232,24 @@ Key_Init_Cvars (void)
} }
const char * const char *
Key_GetBinding (imt_t imt, knum_t key) Key_GetBinding (const char *imt_name, knum_t key)
{ {
return keybindings[imt][key].str; imt_t *imt;
}
VISIBLE void imt = Key_FindIMT (imt_name);
Key_SetBinding (imt_t target, knum_t keynum, const char *binding) if (imt) {
{ return imt->bindings[key].str;
if (keynum == (knum_t) -1)
return;
// free old bindings
if (keybindings[target][keynum].str) {
free (keybindings[target][keynum].str);
keybindings[target][keynum].str = NULL;
}
// allocate memory for new binding
if (binding) {
keybindings[target][keynum].str = strdup(binding);
} }
return 0;
} }
VISIBLE void VISIBLE void
Key_SetKeyDest(keydest_t kd) Key_SetKeyDest(keydest_t kd)
{ {
key_dest = kd; if ((int) kd < key_unfocused || kd >= key_last) {
switch (key_dest) { Sys_Error ("Bad key_dest");
default:
Sys_Error ("Bad key_dest");
case key_game:
key_target = key_game_target;
break;
case key_console:
case key_message:
key_target = IMT_CONSOLE;
break;
case key_menu:
key_target = IMT_MENU;
break;
} }
key_dest = kd;
Key_CallDestCallbacks (key_dest); Key_CallDestCallbacks (key_dest);
} }

View file

@ -48,15 +48,19 @@
static void static void
bi_Key_SetBinding (progs_t *pr) bi_Key_SetBinding (progs_t *pr)
{ {
int target = P_INT (pr, 0); const char *imt_name = P_GSTRING (pr, 0);
int keynum = P_INT (pr, 1); int keynum = P_INT (pr, 1);
const char *binding = P_GSTRING (pr, 2); const char *binding = P_GSTRING (pr, 2);
imt_t *imt;
if (strlen (binding) == 0 || binding[0] == '\0') { if (binding && !binding[0]) {
binding = NULL; /* unbind a binding */ binding = NULL; /* unbind a binding */
} }
Key_SetBinding (target, keynum, binding); imt = Key_FindIMT (imt_name);
if (imt) {
Key_SetBinding (imt, keynum, binding);
}
} }
/* /*
@ -67,23 +71,27 @@ bi_Key_SetBinding (progs_t *pr)
static void static void
bi_Key_LookupBinding (progs_t *pr) bi_Key_LookupBinding (progs_t *pr)
{ {
int target = P_INT (pr, 0); const char *imt_name = P_GSTRING (pr, 0);
int bindnum = P_INT (pr, 1); int bindnum = P_INT (pr, 1);
const char *binding = P_GSTRING (pr, 2); const char *binding = P_GSTRING (pr, 2);
imt_t *imt;
int i; int i;
knum_t keynum = -1; knum_t keynum = -1;
const char *keybind = NULL; const char *keybind = NULL;
for (i = 0; i < QFK_LAST; i++) { imt = Key_FindIMT (imt_name);
keybind = keybindings[target][i].str; if (imt) {
if (keybind == NULL) { for (i = 0; i < QFK_LAST; i++) {
continue; keybind = imt->bindings[i].str;
} if (keybind == NULL) {
if (strcmp (keybind, binding) == 0) { continue;
bindnum--; }
if (bindnum == 0) { if (strcmp (keybind, binding) == 0) {
keynum = i; bindnum--;
break; if (bindnum == 0) {
keynum = i;
break;
}
} }
} }
} }
@ -99,18 +107,22 @@ bi_Key_LookupBinding (progs_t *pr)
static void static void
bi_Key_CountBinding (progs_t *pr) bi_Key_CountBinding (progs_t *pr)
{ {
int target = P_INT (pr, 0); const char *imt_name = P_GSTRING (pr, 0);
const char *binding = P_GSTRING (pr, 1); const char *binding = P_GSTRING (pr, 1);
int i, res = 0; int i, res = 0;
const char *keybind = NULL; const char *keybind = NULL;
imt_t *imt;
for (i = 0; i < QFK_LAST; i++) { imt = Key_FindIMT (imt_name);
keybind = keybindings[target][i].str; if (imt) {
if (keybind == NULL) { for (i = 0; i < QFK_LAST; i++) {
continue; keybind = imt->bindings[i].str;
} if (keybind == NULL) {
if (strcmp (keybind, binding) == 0) { continue;
res++; }
if (strcmp (keybind, binding) == 0) {
res++;
}
} }
} }

View file

@ -125,7 +125,6 @@ CL_StopPlayback (void)
Qclose (cls.demofile); Qclose (cls.demofile);
cls.demofile = NULL; cls.demofile = NULL;
key_game_target = IMT_0;
CL_SetState (ca_disconnected); CL_SetState (ca_disconnected);
cls.demo_capture = 0; cls.demo_capture = 0;
cls.demoplayback = 0; cls.demoplayback = 0;
@ -472,8 +471,7 @@ CL_StartDemo (void)
cls.demoplayback = true; cls.demoplayback = true;
CL_SetState (ca_connected); CL_SetState (ca_connected);
cls.forcetrack = 0; cls.forcetrack = 0;
key_game_target = IMT_DEMO; Key_SetKeyDest (key_demo);
Key_SetKeyDest (key_game);
while ((c = Qgetc (cls.demofile)) != '\n') while ((c = Qgetc (cls.demofile)) != '\n')
if (c == '-') if (c == '-')

View file

@ -242,6 +242,7 @@ cl_chat_keydest (keydest_t keydest)
{ {
switch (keydest) { switch (keydest) {
case key_game: case key_game:
case key_demo:
CL_ChatInfo (0); CL_ChatInfo (0);
break; break;
case key_message: case key_message:
@ -250,6 +251,7 @@ cl_chat_keydest (keydest_t keydest)
case key_console: case key_console:
case key_menu: case key_menu:
case key_unfocused: case key_unfocused:
case key_last: // should not happen
CL_ChatInfo (2); CL_ChatInfo (2);
break; break;
} }

View file

@ -144,7 +144,6 @@ CL_StopPlayback (void)
Qclose (cls.demofile); Qclose (cls.demofile);
cls.demofile = NULL; cls.demofile = NULL;
key_game_target = IMT_0;
CL_SetState (ca_disconnected); CL_SetState (ca_disconnected);
cls.demo_capture = 0; cls.demo_capture = 0;
cls.demoplayback = 0; cls.demoplayback = 0;
@ -1018,8 +1017,7 @@ CL_StartDemo (void)
Sys_Printf ("Playing demo from %s.\n", name->str); Sys_Printf ("Playing demo from %s.\n", name->str);
cls.demoplayback = true; cls.demoplayback = true;
key_game_target = IMT_DEMO; Key_SetKeyDest (key_demo);
Key_SetKeyDest (key_game);
net_blocksend = 1; net_blocksend = 1;
if (type == 2) { if (type == 2) {
cls.demoplayback2 = true; cls.demoplayback2 = true;