[input] Implement imt creation, binding, etc

Much testing is needed, but the bulk of imt management is implemented.
Axis bindings are not properly implemented yet, though.
This commit is contained in:
Bill Currie 2021-11-08 16:54:52 +09:00
parent fd5abb4c61
commit 925ca8081c
5 changed files with 235 additions and 4 deletions

View file

@ -107,10 +107,7 @@ typedef enum {
typedef struct in_buttonbinding_s {
in_button_type type;
union {
struct {
int bind_id; ///< for button multi-press support
in_button_t *button;
};
in_button_t *button;
char *command;
};
} in_buttonbinding_t;

View file

@ -85,8 +85,11 @@ void IMT_SetContextCbuf (int ctx, struct cbuf_s *cbuf);
imt_t *IMT_FindIMT (const char *name);
int IMT_CreateIMT (int context, const char *imt_name,
const char *chain_imt_name);
void IMT_BindAxis (imt_t *imt, int axis, const char *binding);
void IMT_BindButton (imt_t *imt, int button, const char *binding);
qboolean IMT_ProcessAxis (int axis, int value);
qboolean IMT_ProcessButton (int button, int state);
void IMT_Init (void);
#endif

View file

@ -348,6 +348,7 @@ void
IN_Init (cbuf_t *cbuf)
{
Sys_RegisterShutdown (IN_shutdown, 0);
IMT_Init ();
IN_Binding_Init ();
for (size_t i = 0; i < in_drivers.size; i++) {

View file

@ -40,6 +40,7 @@
#endif
#include "QF/cmd.h"
#include "QF/cmem.h"
#include "QF/hash.h"
#include "QF/sys.h"
#include "QF/va.h"
@ -59,6 +60,45 @@ static imt_blockset_t button_blocks = DARRAY_STATIC_INIT (8);
static in_contextset_t in_contexts = DARRAY_STATIC_INIT (8);
static size_t imt_current_context;
static memsuper_t *binding_mem;
static in_axisbinding_t *
alloc_axis_binding (void)
{
return cmemalloc (binding_mem, sizeof (in_axisbinding_t));
}
static void
free_axis_binding (in_axisbinding_t *binding)
{
if (!binding) {
return;
}
cmemfree (binding_mem, binding);
}
static in_buttonbinding_t *
alloc_button_binding (void)
{
return cmemalloc (binding_mem, sizeof (in_buttonbinding_t));
}
static void
free_button_binding (in_buttonbinding_t *binding)
{
if (!binding) {
return;
}
switch (binding->type) {
case inb_button:
break;
case inb_command:
free (binding->command);
break;
}
cmemfree (binding_mem, binding);
}
static imt_block_t * __attribute__((pure))
imt_find_block (imt_blockset_t *blockset, const char *device)
{
@ -152,6 +192,17 @@ IMT_CreateContext (const char *name)
return ctx - in_contexts.a;
}
static in_context_t *
imt_find_context (const char *name)
{
for (size_t i = 0; i < in_contexts.size; i++) {
if (strcmp (name, in_contexts.a[i].name) == 0) {
return &in_contexts.a[i];
}
}
return 0;
}
int
IMT_GetContext (void)
{
@ -254,6 +305,45 @@ IMT_CreateIMT (int context, const char *imt_name, const char *chain_imt_name)
return 1;
}
void
IMT_BindAxis (imt_t *imt, int axis, const char *binding)
{
if ((size_t) axis >= imt->axis_bindings.size)
return;
in_axisbinding_t **bind = &imt->axis_bindings.a[axis];
free_axis_binding ((*bind));
(*bind) = 0;
if (binding) {
in_axisbinding_t *a = alloc_axis_binding ();
(*bind) = a;
*a = (in_axisbinding_t) {};
}
}
void
IMT_BindButton (imt_t *imt, int button, const char *binding)
{
if ((size_t) button >= imt->button_bindings.size)
return;
in_buttonbinding_t **bind = &imt->button_bindings.a[button];
free_button_binding ((*bind));
(*bind) = 0;
if (binding) {
in_buttonbinding_t *b = alloc_button_binding ();
(*bind) = b;
in_button_t *button;
if (binding[0] == '+' && (button = IN_FindButton (binding + 1))) {
b->type = inb_button;
b->button = button;
} else {
b->type = inb_command;
b->command = strdup(binding);
}
}
}
qboolean
IMT_ProcessAxis (int axis, int value)
{
@ -315,3 +405,138 @@ IMT_ProcessButton (int button, int state)
}
return false;
}
static void
imt_f (void)
{
int c;
imt_t *imt;
const char *imt_name = 0;
const char *context_name;
c = Cmd_Argc ();
switch (c) {
case 3:
imt_name = Cmd_Argv (2);
case 2:
context_name = Cmd_Argv (1);
break;
default:
return;
}
in_context_t *ctx = imt_find_context (context_name);
if (!ctx) {
Sys_Printf ("imt error: invalid context: %s\n", context_name);
return;
}
if (!imt_name) {
Sys_Printf ("Current imt is %s\n", ctx->active_imt->name);
Sys_Printf ("imt <imt> : set to a specific input mapping table\n");
return;
}
imt = imt_find_imt (ctx, imt_name);
if (!imt) {
Sys_Printf ("\"%s\" is not an imt in %s\n", imt_name, ctx->name);
return;
}
ctx->active_imt = imt;
}
static void
imt_list_f (void)
{
for (size_t i = 0; i < in_contexts.size; i++) {
in_context_t *ctx = &in_contexts.a[i];
Sys_Printf ("context: %s\n", ctx->name);
for (imt_t *imt = ctx->imts; imt; imt = imt->next) {
if (imt->chain) {
Sys_Printf (" %s -> %s\n", imt->name, imt->chain->name);
} else {
Sys_Printf (" %s\n", imt->name);
}
}
}
}
static void
imt_create_f (void)
{
const char *context_name;
const char *imt_name;
const char *chain_imt_name = 0;
if (Cmd_Argc () < 3 || Cmd_Argc () > 4) {
Sys_Printf ("see help imt_create\n");
return;
}
context_name = Cmd_Argv (1);
imt_name = Cmd_Argv (2);
if (Cmd_Argc () == 4) {
chain_imt_name = Cmd_Argv (3);
}
in_context_t *ctx = imt_find_context (context_name);
if (!ctx) {
Sys_Printf ("imt error: invalid context: %s\n", context_name);
return;
}
IMT_CreateIMT (ctx - in_contexts.a, imt_name, chain_imt_name);
}
static void
imt_drop_all_f (void)
{
for (size_t i = 0; i < in_contexts.size; i++) {
in_context_t *ctx = &in_contexts.a[i];
while (ctx->imts) {
imt_t *imt = ctx->imts;
ctx->imts = imt->next;
for (size_t i = 0; i < imt->axis_bindings.size; i++) {
free_axis_binding (imt->axis_bindings.a[i]);
}
for (size_t i = 0; i < imt->button_bindings.size; i++) {
free_button_binding (imt->button_bindings.a[i]);
}
free ((char *) imt->name);
free (imt);
}
ctx->active_imt = 0;
}
}
typedef struct {
const char *name;
xcommand_t func;
const char *desc;
} imtcmd_t;
static imtcmd_t imt_commands[] = {
{ "imt", imt_f,
"Set the active imt of the specified context"
},
{ "imt_list", imt_list_f,
"List the available input mapping tables"
},
{ "imt_create", 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"
},
{ "imt_drop_all", imt_drop_all_f,
"delete all imt tables\n"
},
};
void
IMT_Init (void)
{
binding_mem = new_memsuper ();
for (imtcmd_t *cmd = imt_commands; cmd->name; cmd++) {
Cmd_AddCommand (cmd->name, cmd->func, cmd->desc);
}
}

View file

@ -59,6 +59,9 @@
#include "qw/include/client.h"
#include "qw/include/host.h"
int cl_game_context;
int cl_demo_context;
cvar_t *cl_nodelta;
cvar_t *cl_maxnetfps;
cvar_t *cl_spamimpulse;
@ -522,6 +525,8 @@ CL_Input_Init (void)
for (int i = 0; cl_in_buttons[i]; i++) {
IN_RegisterButton (cl_in_buttons[i]);
}
cl_game_context = IMT_CreateContext ("key_game");
cl_demo_context = IMT_CreateContext ("key_demo");
Cmd_AddDataCommand ("impulse", IN_Impulse, 0,
"Call a game function or QuakeC function.");
}