2021-11-03 10:02:39 +00:00
|
|
|
/*
|
|
|
|
in_imt.c
|
|
|
|
|
|
|
|
Input Mapping Table management
|
|
|
|
|
2022-05-22 04:52:34 +00:00
|
|
|
Copyright (C) 2001 Zephaniah E. Hull <warp@babylon.d2dc.net>
|
2021-11-03 10:02:39 +00:00
|
|
|
Copyright (C) 2021 Bill Currie <bill@taniwha.org>
|
|
|
|
|
|
|
|
Author: Bill Currie <bill@taniwha.org>
|
|
|
|
Date: 2021/10/30
|
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or
|
|
|
|
modify it under the terms of the GNU General Public License
|
|
|
|
as published by the Free Software Foundation; either version 2
|
|
|
|
of the License, or (at your option) any later version.
|
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
|
|
|
|
|
|
See the GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with this program; if not, write to:
|
|
|
|
|
|
|
|
Free Software Foundation, Inc.
|
|
|
|
59 Temple Place - Suite 330
|
|
|
|
Boston, MA 02111-1307, USA
|
|
|
|
|
|
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
# include "config.h"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef HAVE_STRING_H
|
|
|
|
# include <string.h>
|
|
|
|
#endif
|
|
|
|
#ifdef HAVE_STRINGS_H
|
|
|
|
# include <strings.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include "QF/cmd.h"
|
2021-11-08 07:54:52 +00:00
|
|
|
#include "QF/cmem.h"
|
[input] Create an automatic imt switcher
An imt switcher automatically changes the context's active imt based on
a user specified list of binary inputs. The inputs may be either buttons
(indicated as +button) or cvars (bare name). For buttons, the
pressed/not pressed state is used, and cvars are interpreted as ints
being 0 or not 0. The order of the inputs determines the bit number of
the input, with the first input being bit 0, second bit 1, third bit 2
etc. A default imt is given so large switchers do not need to be fully
configured (the default imt is written to all states).
A context can have any number of switchers attached. The switchers can
wind up fighting over the active imt, but this seems to be something for
the "user" (eg, configuration system) to sort out rather than the
switcher code enforcing anything.
As a result of the inputs being treated as bits, a switcher with N
inputs will have 2**N states, thus there's a maximum of 16 inputs for
now as 65536 states is a lot of configuration.
Using a switcher, setting up a standard strafe/mouse look configuration
is fairly easy.
imt_create key_game imt_mod
imt_create key_game imt_mod_strafe imt_mod
imt_create key_game imt_mod_freelook
imt_create key_game imt_mod_lookstrafe imt_mod_freelook
imt_switcher_create mouse key_game imt_mod_strafe +strafe lookstrafe +mlook freelook
imt_switcher 0 imt_mod 2 imt_mod 4 imt_mod_freelook 8 imt_mod_freelook 12 imt_mod_freelook
imt_switcher 6 imt_mod_lookstrafe 10 imt_mod_lookstrafe 14 imt_mod_lookstrafe
in_bind imt_mod mouse axis 0 move.yaw
in_bind imt_mod mouse axis 1 move.forward
in_bind imt_mod_strafe mouse axis 0 move.side
in_bind imt_mod_lookstrafe mouse axis 0 move.side
in_bind imt_mod_freelook mouse axis 1 move.pitch
This takes advantage of imt chaining and the default imt for the
switcher (there are 8 states that use imt_mod_strafe).
The switcher name must be unique across all contexts, and every imt used
in a switcher must be in the switcher's context.
2021-11-25 09:01:07 +00:00
|
|
|
#include "QF/cvar.h"
|
2021-11-03 10:02:39 +00:00
|
|
|
#include "QF/hash.h"
|
2021-11-11 06:51:47 +00:00
|
|
|
#include "QF/input.h"
|
|
|
|
#include "QF/mathlib.h"
|
2021-11-14 01:17:05 +00:00
|
|
|
#include "QF/plist.h"
|
2021-11-03 10:02:39 +00:00
|
|
|
#include "QF/sys.h"
|
2021-11-08 02:20:04 +00:00
|
|
|
#include "QF/va.h"
|
2021-11-03 10:02:39 +00:00
|
|
|
|
|
|
|
#include "QF/input/imt.h"
|
|
|
|
|
|
|
|
#include "QF/input/binding.h"
|
|
|
|
#include "QF/input/imt.h"
|
|
|
|
|
[input] Create an automatic imt switcher
An imt switcher automatically changes the context's active imt based on
a user specified list of binary inputs. The inputs may be either buttons
(indicated as +button) or cvars (bare name). For buttons, the
pressed/not pressed state is used, and cvars are interpreted as ints
being 0 or not 0. The order of the inputs determines the bit number of
the input, with the first input being bit 0, second bit 1, third bit 2
etc. A default imt is given so large switchers do not need to be fully
configured (the default imt is written to all states).
A context can have any number of switchers attached. The switchers can
wind up fighting over the active imt, but this seems to be something for
the "user" (eg, configuration system) to sort out rather than the
switcher code enforcing anything.
As a result of the inputs being treated as bits, a switcher with N
inputs will have 2**N states, thus there's a maximum of 16 inputs for
now as 65536 states is a lot of configuration.
Using a switcher, setting up a standard strafe/mouse look configuration
is fairly easy.
imt_create key_game imt_mod
imt_create key_game imt_mod_strafe imt_mod
imt_create key_game imt_mod_freelook
imt_create key_game imt_mod_lookstrafe imt_mod_freelook
imt_switcher_create mouse key_game imt_mod_strafe +strafe lookstrafe +mlook freelook
imt_switcher 0 imt_mod 2 imt_mod 4 imt_mod_freelook 8 imt_mod_freelook 12 imt_mod_freelook
imt_switcher 6 imt_mod_lookstrafe 10 imt_mod_lookstrafe 14 imt_mod_lookstrafe
in_bind imt_mod mouse axis 0 move.yaw
in_bind imt_mod mouse axis 1 move.forward
in_bind imt_mod_strafe mouse axis 0 move.side
in_bind imt_mod_lookstrafe mouse axis 0 move.side
in_bind imt_mod_freelook mouse axis 1 move.pitch
This takes advantage of imt chaining and the default imt for the
switcher (there are 8 states that use imt_mod_strafe).
The switcher name must be unique across all contexts, and every imt used
in a switcher must be in the switcher's context.
2021-11-25 09:01:07 +00:00
|
|
|
#include "qfalloca.h"
|
|
|
|
|
2021-11-09 13:23:57 +00:00
|
|
|
/** Describe a region of imt bindings (axis or button)
|
|
|
|
|
|
|
|
Each device may have a block of axis bindings and a block of button
|
|
|
|
bindings (some devices will have only the one block).
|
|
|
|
|
|
|
|
Bindings are allocated to a device in contiguous blocks.
|
|
|
|
*/
|
|
|
|
typedef struct imt_block_s {
|
|
|
|
int base; ///< index of first binding
|
|
|
|
int count; ///< number of bindings
|
|
|
|
} imt_block_t;
|
|
|
|
|
2021-11-03 10:02:39 +00:00
|
|
|
typedef struct DARRAY_TYPE (in_context_t) in_contextset_t;
|
|
|
|
typedef struct DARRAY_TYPE (imt_block_t) imt_blockset_t;
|
|
|
|
/** Binding blocks are allocated across all imts
|
|
|
|
*/
|
|
|
|
static imt_blockset_t axis_blocks = DARRAY_STATIC_INIT (8);
|
|
|
|
static imt_blockset_t button_blocks = DARRAY_STATIC_INIT (8);
|
|
|
|
|
|
|
|
static in_contextset_t in_contexts = DARRAY_STATIC_INIT (8);
|
2021-11-08 02:20:04 +00:00
|
|
|
static size_t imt_current_context;
|
2021-11-03 10:02:39 +00:00
|
|
|
|
2021-11-08 07:54:52 +00:00
|
|
|
static memsuper_t *binding_mem;
|
2021-11-11 06:51:47 +00:00
|
|
|
static hashtab_t *recipe_tab;
|
|
|
|
|
|
|
|
static in_recipe_t *
|
|
|
|
alloc_recipe (void)
|
|
|
|
{
|
|
|
|
return cmemalloc (binding_mem, sizeof (in_recipe_t));
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
free_recipe (in_recipe_t *recipe)
|
|
|
|
{
|
|
|
|
if (!recipe) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
cmemfree (binding_mem, recipe);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
recipe_free (void *recipe, void *data)
|
|
|
|
{
|
|
|
|
free_recipe (recipe);
|
|
|
|
}
|
|
|
|
|
|
|
|
static uintptr_t
|
|
|
|
recipe_get_hash (const void *recipe, void *data)
|
|
|
|
{
|
|
|
|
return Hash_Buffer (recipe, sizeof (in_recipe_t));
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
recipe_compare (const void *a, const void *b, void *data)
|
|
|
|
{
|
|
|
|
return !memcmp (a, b, sizeof (in_recipe_t));
|
|
|
|
}
|
2021-11-08 07:54:52 +00:00
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2021-11-03 10:02:39 +00:00
|
|
|
static imt_block_t *
|
|
|
|
imt_get_block (imt_blockset_t *blockset)
|
|
|
|
{
|
|
|
|
return DARRAY_OPEN_AT (blockset, blockset->size, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
imt_get_next_base (imt_blockset_t *blockset)
|
|
|
|
{
|
|
|
|
if (!blockset->size) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
imt_block_t *b = &blockset->a[blockset->size - 1];
|
|
|
|
return b->base + b->count;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
imt_get_axis_block (int count)
|
|
|
|
{
|
|
|
|
int base = imt_get_next_base (&axis_blocks);
|
|
|
|
|
|
|
|
for (size_t i = 0; i < in_contexts.size; i++) {
|
|
|
|
for (imt_t *imt = in_contexts.a[i].imts; imt; imt = imt->next) {
|
|
|
|
in_axisbinding_t **binding;
|
|
|
|
binding = DARRAY_OPEN_AT (&imt->axis_bindings, base, count);
|
|
|
|
memset (binding, 0, count * sizeof (binding));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return base;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
imt_get_button_block (int count)
|
|
|
|
{
|
|
|
|
int base = imt_get_next_base (&button_blocks);
|
|
|
|
|
|
|
|
for (size_t i = 0; i < in_contexts.size; i++) {
|
|
|
|
for (imt_t *imt = in_contexts.a[i].imts; imt; imt = imt->next) {
|
|
|
|
in_buttonbinding_t **binding;
|
|
|
|
binding = DARRAY_OPEN_AT (&imt->button_bindings, base, count);
|
|
|
|
memset (binding, 0, count * sizeof (binding));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return base;
|
|
|
|
}
|
|
|
|
|
2021-11-16 11:12:53 +00:00
|
|
|
static void
|
|
|
|
imt_reset_blocks (void)
|
|
|
|
{
|
|
|
|
DARRAY_RESIZE (&axis_blocks, 0);
|
|
|
|
DARRAY_RESIZE (&button_blocks, 0);
|
|
|
|
for (size_t i = 0; i < in_contexts.size; i++) {
|
|
|
|
for (imt_t *imt = in_contexts.a[i].imts; imt; imt = imt->next) {
|
|
|
|
DARRAY_RESIZE (&imt->axis_bindings, 0);
|
|
|
|
DARRAY_RESIZE (&imt->button_bindings, 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-03 10:02:39 +00:00
|
|
|
int
|
2021-11-09 13:23:57 +00:00
|
|
|
IMT_GetAxisBlock (int num_axes)
|
2021-11-03 10:02:39 +00:00
|
|
|
{
|
2021-11-11 06:51:47 +00:00
|
|
|
int base = imt_get_axis_block (num_axes);
|
2021-11-16 11:12:53 +00:00
|
|
|
imt_block_t *block = imt_get_block (&axis_blocks);
|
2021-11-11 06:51:47 +00:00
|
|
|
block->base = base;
|
2021-11-09 13:23:57 +00:00
|
|
|
block->count = num_axes;
|
2021-11-16 11:12:53 +00:00
|
|
|
return base;
|
2021-11-03 10:02:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2021-11-09 13:23:57 +00:00
|
|
|
IMT_GetButtonBlock (int num_buttons)
|
2021-11-03 10:02:39 +00:00
|
|
|
{
|
2021-11-11 06:51:47 +00:00
|
|
|
int base = imt_get_button_block (num_buttons);
|
2021-11-16 11:12:53 +00:00
|
|
|
imt_block_t *block = imt_get_block (&button_blocks);
|
2021-11-11 06:51:47 +00:00
|
|
|
block->base = base;
|
2021-11-09 13:23:57 +00:00
|
|
|
block->count = num_buttons;
|
2021-11-16 11:12:53 +00:00
|
|
|
return base;
|
2021-11-03 10:02:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2021-11-08 06:38:26 +00:00
|
|
|
IMT_CreateContext (const char *name)
|
2021-11-03 10:02:39 +00:00
|
|
|
{
|
|
|
|
in_context_t *ctx = DARRAY_OPEN_AT (&in_contexts, in_contexts.size, 1);
|
|
|
|
memset (ctx, 0, sizeof (*ctx));
|
|
|
|
ctx->imt_tail = &ctx->imts;
|
[input] Create an automatic imt switcher
An imt switcher automatically changes the context's active imt based on
a user specified list of binary inputs. The inputs may be either buttons
(indicated as +button) or cvars (bare name). For buttons, the
pressed/not pressed state is used, and cvars are interpreted as ints
being 0 or not 0. The order of the inputs determines the bit number of
the input, with the first input being bit 0, second bit 1, third bit 2
etc. A default imt is given so large switchers do not need to be fully
configured (the default imt is written to all states).
A context can have any number of switchers attached. The switchers can
wind up fighting over the active imt, but this seems to be something for
the "user" (eg, configuration system) to sort out rather than the
switcher code enforcing anything.
As a result of the inputs being treated as bits, a switcher with N
inputs will have 2**N states, thus there's a maximum of 16 inputs for
now as 65536 states is a lot of configuration.
Using a switcher, setting up a standard strafe/mouse look configuration
is fairly easy.
imt_create key_game imt_mod
imt_create key_game imt_mod_strafe imt_mod
imt_create key_game imt_mod_freelook
imt_create key_game imt_mod_lookstrafe imt_mod_freelook
imt_switcher_create mouse key_game imt_mod_strafe +strafe lookstrafe +mlook freelook
imt_switcher 0 imt_mod 2 imt_mod 4 imt_mod_freelook 8 imt_mod_freelook 12 imt_mod_freelook
imt_switcher 6 imt_mod_lookstrafe 10 imt_mod_lookstrafe 14 imt_mod_lookstrafe
in_bind imt_mod mouse axis 0 move.yaw
in_bind imt_mod mouse axis 1 move.forward
in_bind imt_mod_strafe mouse axis 0 move.side
in_bind imt_mod_lookstrafe mouse axis 0 move.side
in_bind imt_mod_freelook mouse axis 1 move.pitch
This takes advantage of imt chaining and the default imt for the
switcher (there are 8 states that use imt_mod_strafe).
The switcher name must be unique across all contexts, and every imt used
in a switcher must be in the switcher's context.
2021-11-25 09:01:07 +00:00
|
|
|
ctx->switcher_tail = &ctx->switchers;
|
2021-11-08 06:38:26 +00:00
|
|
|
ctx->name = name;
|
2021-11-03 10:02:39 +00:00
|
|
|
return ctx - in_contexts.a;
|
|
|
|
}
|
|
|
|
|
2021-11-11 06:43:07 +00:00
|
|
|
static in_context_t * __attribute__ ((pure))
|
2021-11-08 07:54:52 +00:00
|
|
|
imt_find_context (const char *name)
|
|
|
|
{
|
2021-11-14 01:17:05 +00:00
|
|
|
if (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];
|
|
|
|
}
|
2021-11-08 07:54:52 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
[input] Create an automatic imt switcher
An imt switcher automatically changes the context's active imt based on
a user specified list of binary inputs. The inputs may be either buttons
(indicated as +button) or cvars (bare name). For buttons, the
pressed/not pressed state is used, and cvars are interpreted as ints
being 0 or not 0. The order of the inputs determines the bit number of
the input, with the first input being bit 0, second bit 1, third bit 2
etc. A default imt is given so large switchers do not need to be fully
configured (the default imt is written to all states).
A context can have any number of switchers attached. The switchers can
wind up fighting over the active imt, but this seems to be something for
the "user" (eg, configuration system) to sort out rather than the
switcher code enforcing anything.
As a result of the inputs being treated as bits, a switcher with N
inputs will have 2**N states, thus there's a maximum of 16 inputs for
now as 65536 states is a lot of configuration.
Using a switcher, setting up a standard strafe/mouse look configuration
is fairly easy.
imt_create key_game imt_mod
imt_create key_game imt_mod_strafe imt_mod
imt_create key_game imt_mod_freelook
imt_create key_game imt_mod_lookstrafe imt_mod_freelook
imt_switcher_create mouse key_game imt_mod_strafe +strafe lookstrafe +mlook freelook
imt_switcher 0 imt_mod 2 imt_mod 4 imt_mod_freelook 8 imt_mod_freelook 12 imt_mod_freelook
imt_switcher 6 imt_mod_lookstrafe 10 imt_mod_lookstrafe 14 imt_mod_lookstrafe
in_bind imt_mod mouse axis 0 move.yaw
in_bind imt_mod mouse axis 1 move.forward
in_bind imt_mod_strafe mouse axis 0 move.side
in_bind imt_mod_lookstrafe mouse axis 0 move.side
in_bind imt_mod_freelook mouse axis 1 move.pitch
This takes advantage of imt chaining and the default imt for the
switcher (there are 8 states that use imt_mod_strafe).
The switcher name must be unique across all contexts, and every imt used
in a switcher must be in the switcher's context.
2021-11-25 09:01:07 +00:00
|
|
|
static void
|
|
|
|
imt_switcher_update (imt_switcher_t *switcher)
|
|
|
|
{
|
|
|
|
int state = 0;
|
|
|
|
|
|
|
|
for (int i = 0; i < switcher->num_inputs; i++) {
|
|
|
|
imt_input_t *input = &switcher->inputs[i];
|
|
|
|
int val = 0;
|
|
|
|
switch (input->type) {
|
|
|
|
case imti_button:
|
|
|
|
val = !!(input->button->state & inb_down);
|
|
|
|
break;
|
|
|
|
case imti_cvar:
|
[cvar] Make cvars properly typed
This is an extremely extensive patch as it hits every cvar, and every
usage of the cvars. Cvars no longer store the value they control,
instead, they use a cexpr value object to reference the value and
specify the value's type (currently, a null type is used for strings).
Non-string cvars are passed through cexpr, allowing expressions in the
cvars' settings. Also, cvars have returned to an enhanced version of the
original (id quake) registration scheme.
As a minor benefit, relevant code having direct access to the
cvar-controlled variables is probably a slight optimization as it
removed a pointer dereference, and the variables can be located for data
locality.
The static cvar descriptors are made private as an additional safety
layer, though there's nothing stopping external modification via
Cvar_FindVar (which is needed for adding listeners).
While not used yet (partly due to working out the design), cvars can
have a validation function.
Registering a cvar allows a primary listener (and its data) to be
specified: it will always be called first when the cvar is modified. The
combination of proper listeners and direct access to the controlled
variable greatly simplifies the more complex cvar interactions as much
less null checking is required, and there's no need for one cvar's
callback to call another's.
nq-x11 is known to work at least well enough for the demos. More testing
will come.
2022-04-23 03:22:45 +00:00
|
|
|
//FIXME check cvar type
|
|
|
|
val = !!*(int *) input->cvar->value.value;
|
[input] Create an automatic imt switcher
An imt switcher automatically changes the context's active imt based on
a user specified list of binary inputs. The inputs may be either buttons
(indicated as +button) or cvars (bare name). For buttons, the
pressed/not pressed state is used, and cvars are interpreted as ints
being 0 or not 0. The order of the inputs determines the bit number of
the input, with the first input being bit 0, second bit 1, third bit 2
etc. A default imt is given so large switchers do not need to be fully
configured (the default imt is written to all states).
A context can have any number of switchers attached. The switchers can
wind up fighting over the active imt, but this seems to be something for
the "user" (eg, configuration system) to sort out rather than the
switcher code enforcing anything.
As a result of the inputs being treated as bits, a switcher with N
inputs will have 2**N states, thus there's a maximum of 16 inputs for
now as 65536 states is a lot of configuration.
Using a switcher, setting up a standard strafe/mouse look configuration
is fairly easy.
imt_create key_game imt_mod
imt_create key_game imt_mod_strafe imt_mod
imt_create key_game imt_mod_freelook
imt_create key_game imt_mod_lookstrafe imt_mod_freelook
imt_switcher_create mouse key_game imt_mod_strafe +strafe lookstrafe +mlook freelook
imt_switcher 0 imt_mod 2 imt_mod 4 imt_mod_freelook 8 imt_mod_freelook 12 imt_mod_freelook
imt_switcher 6 imt_mod_lookstrafe 10 imt_mod_lookstrafe 14 imt_mod_lookstrafe
in_bind imt_mod mouse axis 0 move.yaw
in_bind imt_mod mouse axis 1 move.forward
in_bind imt_mod_strafe mouse axis 0 move.side
in_bind imt_mod_lookstrafe mouse axis 0 move.side
in_bind imt_mod_freelook mouse axis 1 move.pitch
This takes advantage of imt chaining and the default imt for the
switcher (there are 8 states that use imt_mod_strafe).
The switcher name must be unique across all contexts, and every imt used
in a switcher must be in the switcher's context.
2021-11-25 09:01:07 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
state |= val << i;
|
|
|
|
}
|
|
|
|
switcher->context->active_imt = switcher->imts[state];
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
imt_switcher_button_update (void *_switcher, const in_button_t *button)
|
|
|
|
{
|
|
|
|
imt_switcher_update (_switcher);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
imt_switcher_cvar_update (void *_switcher, const cvar_t *cvar)
|
|
|
|
{
|
|
|
|
imt_switcher_update (_switcher);
|
|
|
|
}
|
|
|
|
|
2021-11-08 02:20:04 +00:00
|
|
|
int
|
|
|
|
IMT_GetContext (void)
|
|
|
|
{
|
|
|
|
return imt_current_context;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
IMT_SetContext (int ctx)
|
|
|
|
{
|
|
|
|
if ((size_t) ctx >= in_contexts.size) {
|
|
|
|
Sys_Error ("IMT_SetContext: invalid context %d", ctx);
|
|
|
|
}
|
|
|
|
imt_current_context = ctx;
|
[input] Create an automatic imt switcher
An imt switcher automatically changes the context's active imt based on
a user specified list of binary inputs. The inputs may be either buttons
(indicated as +button) or cvars (bare name). For buttons, the
pressed/not pressed state is used, and cvars are interpreted as ints
being 0 or not 0. The order of the inputs determines the bit number of
the input, with the first input being bit 0, second bit 1, third bit 2
etc. A default imt is given so large switchers do not need to be fully
configured (the default imt is written to all states).
A context can have any number of switchers attached. The switchers can
wind up fighting over the active imt, but this seems to be something for
the "user" (eg, configuration system) to sort out rather than the
switcher code enforcing anything.
As a result of the inputs being treated as bits, a switcher with N
inputs will have 2**N states, thus there's a maximum of 16 inputs for
now as 65536 states is a lot of configuration.
Using a switcher, setting up a standard strafe/mouse look configuration
is fairly easy.
imt_create key_game imt_mod
imt_create key_game imt_mod_strafe imt_mod
imt_create key_game imt_mod_freelook
imt_create key_game imt_mod_lookstrafe imt_mod_freelook
imt_switcher_create mouse key_game imt_mod_strafe +strafe lookstrafe +mlook freelook
imt_switcher 0 imt_mod 2 imt_mod 4 imt_mod_freelook 8 imt_mod_freelook 12 imt_mod_freelook
imt_switcher 6 imt_mod_lookstrafe 10 imt_mod_lookstrafe 14 imt_mod_lookstrafe
in_bind imt_mod mouse axis 0 move.yaw
in_bind imt_mod mouse axis 1 move.forward
in_bind imt_mod_strafe mouse axis 0 move.side
in_bind imt_mod_lookstrafe mouse axis 0 move.side
in_bind imt_mod_freelook mouse axis 1 move.pitch
This takes advantage of imt chaining and the default imt for the
switcher (there are 8 states that use imt_mod_strafe).
The switcher name must be unique across all contexts, and every imt used
in a switcher must be in the switcher's context.
2021-11-25 09:01:07 +00:00
|
|
|
for (imt_switcher_t *switcher = in_contexts.a[ctx].switchers; switcher;
|
|
|
|
switcher = switcher->next) {
|
|
|
|
imt_switcher_update (switcher);
|
|
|
|
}
|
2021-12-15 03:04:30 +00:00
|
|
|
imt_t *imt = in_contexts.a[imt_current_context].active_imt;
|
|
|
|
Sys_MaskPrintf (SYS_input, "Switched to %s context, imt %s\n",
|
|
|
|
in_contexts.a[imt_current_context].name,
|
|
|
|
imt ? imt->name : 0);
|
2021-11-08 02:20:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
IMT_SetContextCbuf (int ctx, cbuf_t *cbuf)
|
|
|
|
{
|
|
|
|
if ((size_t) ctx >= in_contexts.size) {
|
|
|
|
Sys_Error ("IMT_SetContextCbuf: invalid context %d", ctx);
|
|
|
|
}
|
2021-12-15 03:04:30 +00:00
|
|
|
in_contexts.a[ctx].cbuf = cbuf;
|
2021-11-08 02:20:04 +00:00
|
|
|
}
|
|
|
|
|
2021-11-03 10:02:39 +00:00
|
|
|
static imt_t * __attribute__ ((pure))
|
|
|
|
imt_find_imt (in_context_t *ctx, const char *name)
|
|
|
|
{
|
|
|
|
for (imt_t *imt = ctx->imts; imt; imt = imt->next) {
|
|
|
|
if (strcasecmp (imt->name, name) == 0) {
|
|
|
|
return imt;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2021-11-14 01:10:39 +00:00
|
|
|
imt_t *
|
2021-11-03 10:02:39 +00:00
|
|
|
IMT_FindIMT (const char *name)
|
|
|
|
{
|
|
|
|
for (size_t i = 0; i < in_contexts.size; i++) {
|
|
|
|
in_context_t *ctx = &in_contexts.a[i];
|
|
|
|
imt_t *imt = imt_find_imt (ctx, name);
|
|
|
|
if (imt) {
|
|
|
|
return imt;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
[input] Create an automatic imt switcher
An imt switcher automatically changes the context's active imt based on
a user specified list of binary inputs. The inputs may be either buttons
(indicated as +button) or cvars (bare name). For buttons, the
pressed/not pressed state is used, and cvars are interpreted as ints
being 0 or not 0. The order of the inputs determines the bit number of
the input, with the first input being bit 0, second bit 1, third bit 2
etc. A default imt is given so large switchers do not need to be fully
configured (the default imt is written to all states).
A context can have any number of switchers attached. The switchers can
wind up fighting over the active imt, but this seems to be something for
the "user" (eg, configuration system) to sort out rather than the
switcher code enforcing anything.
As a result of the inputs being treated as bits, a switcher with N
inputs will have 2**N states, thus there's a maximum of 16 inputs for
now as 65536 states is a lot of configuration.
Using a switcher, setting up a standard strafe/mouse look configuration
is fairly easy.
imt_create key_game imt_mod
imt_create key_game imt_mod_strafe imt_mod
imt_create key_game imt_mod_freelook
imt_create key_game imt_mod_lookstrafe imt_mod_freelook
imt_switcher_create mouse key_game imt_mod_strafe +strafe lookstrafe +mlook freelook
imt_switcher 0 imt_mod 2 imt_mod 4 imt_mod_freelook 8 imt_mod_freelook 12 imt_mod_freelook
imt_switcher 6 imt_mod_lookstrafe 10 imt_mod_lookstrafe 14 imt_mod_lookstrafe
in_bind imt_mod mouse axis 0 move.yaw
in_bind imt_mod mouse axis 1 move.forward
in_bind imt_mod_strafe mouse axis 0 move.side
in_bind imt_mod_lookstrafe mouse axis 0 move.side
in_bind imt_mod_freelook mouse axis 1 move.pitch
This takes advantage of imt chaining and the default imt for the
switcher (there are 8 states that use imt_mod_strafe).
The switcher name must be unique across all contexts, and every imt used
in a switcher must be in the switcher's context.
2021-11-25 09:01:07 +00:00
|
|
|
static imt_switcher_t * __attribute__((pure))
|
|
|
|
imt_find_switcher (in_context_t *ctx, const char *name)
|
|
|
|
{
|
|
|
|
for (imt_switcher_t *switcher = ctx->switchers; switcher;
|
|
|
|
switcher = switcher->next) {
|
|
|
|
if (strcasecmp (switcher->name, name) == 0) {
|
|
|
|
return switcher;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
imt_switcher_t *
|
|
|
|
IMT_FindSwitcher (const char *name)
|
|
|
|
{
|
|
|
|
for (size_t i = 0; i < in_contexts.size; i++) {
|
|
|
|
in_context_t *ctx = &in_contexts.a[i];
|
|
|
|
imt_switcher_t *switcher = imt_find_switcher (ctx, name);
|
|
|
|
if (switcher) {
|
|
|
|
return switcher;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2021-11-03 10:02:39 +00:00
|
|
|
int
|
|
|
|
IMT_CreateIMT (int context, const char *imt_name, const char *chain_imt_name)
|
|
|
|
{
|
|
|
|
in_context_t *ctx = &in_contexts.a[context];
|
|
|
|
imt_t *imt;
|
|
|
|
imt_t *chain_imt = 0;
|
|
|
|
|
|
|
|
if ((size_t) context >= in_contexts.size) {
|
|
|
|
Sys_Printf ("invalid imt context %d\n", context);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (IMT_FindIMT (imt_name)) {
|
|
|
|
Sys_Printf ("imt %s already exists\n", imt_name);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
if (chain_imt_name) {
|
|
|
|
chain_imt = IMT_FindIMT (chain_imt_name);
|
|
|
|
if (!chain_imt) {
|
|
|
|
Sys_Printf ("chain imt %s does not exist\n", chain_imt_name);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
chain_imt = imt_find_imt (ctx, chain_imt_name);
|
|
|
|
if (!chain_imt) {
|
|
|
|
Sys_Printf ("chain imt %s not in target context\n",
|
|
|
|
chain_imt_name);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
imt = malloc (sizeof (imt_t));
|
2021-11-14 01:17:05 +00:00
|
|
|
if (!ctx->imts) {
|
|
|
|
ctx->default_imt = imt;
|
|
|
|
ctx->active_imt = imt;
|
|
|
|
}
|
2021-11-03 10:02:39 +00:00
|
|
|
*ctx->imt_tail = imt;
|
|
|
|
ctx->imt_tail = &imt->next;
|
|
|
|
|
|
|
|
imt->next = 0;
|
|
|
|
imt->chain = chain_imt;
|
|
|
|
imt->name = strdup (imt_name);
|
|
|
|
imt->written = 0;
|
|
|
|
DARRAY_INIT (&imt->axis_bindings, 8);
|
|
|
|
DARRAY_INIT (&imt->button_bindings, 8);
|
|
|
|
int num_axes = imt_get_next_base (&axis_blocks);
|
|
|
|
int num_buttons = imt_get_next_base (&button_blocks);
|
|
|
|
DARRAY_RESIZE (&imt->axis_bindings, num_axes);
|
|
|
|
DARRAY_RESIZE (&imt->button_bindings, num_buttons);
|
|
|
|
if (num_axes) {
|
|
|
|
memset (imt->axis_bindings.a, 0,
|
|
|
|
num_axes * sizeof (in_axisbinding_t *));
|
|
|
|
}
|
|
|
|
if (num_buttons) {
|
2021-11-14 01:17:05 +00:00
|
|
|
memset (imt->button_bindings.a, 0,
|
2021-11-03 10:02:39 +00:00
|
|
|
num_buttons * sizeof (in_buttonbinding_t *));
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
[input] Create an automatic imt switcher
An imt switcher automatically changes the context's active imt based on
a user specified list of binary inputs. The inputs may be either buttons
(indicated as +button) or cvars (bare name). For buttons, the
pressed/not pressed state is used, and cvars are interpreted as ints
being 0 or not 0. The order of the inputs determines the bit number of
the input, with the first input being bit 0, second bit 1, third bit 2
etc. A default imt is given so large switchers do not need to be fully
configured (the default imt is written to all states).
A context can have any number of switchers attached. The switchers can
wind up fighting over the active imt, but this seems to be something for
the "user" (eg, configuration system) to sort out rather than the
switcher code enforcing anything.
As a result of the inputs being treated as bits, a switcher with N
inputs will have 2**N states, thus there's a maximum of 16 inputs for
now as 65536 states is a lot of configuration.
Using a switcher, setting up a standard strafe/mouse look configuration
is fairly easy.
imt_create key_game imt_mod
imt_create key_game imt_mod_strafe imt_mod
imt_create key_game imt_mod_freelook
imt_create key_game imt_mod_lookstrafe imt_mod_freelook
imt_switcher_create mouse key_game imt_mod_strafe +strafe lookstrafe +mlook freelook
imt_switcher 0 imt_mod 2 imt_mod 4 imt_mod_freelook 8 imt_mod_freelook 12 imt_mod_freelook
imt_switcher 6 imt_mod_lookstrafe 10 imt_mod_lookstrafe 14 imt_mod_lookstrafe
in_bind imt_mod mouse axis 0 move.yaw
in_bind imt_mod mouse axis 1 move.forward
in_bind imt_mod_strafe mouse axis 0 move.side
in_bind imt_mod_lookstrafe mouse axis 0 move.side
in_bind imt_mod_freelook mouse axis 1 move.pitch
This takes advantage of imt chaining and the default imt for the
switcher (there are 8 states that use imt_mod_strafe).
The switcher name must be unique across all contexts, and every imt used
in a switcher must be in the switcher's context.
2021-11-25 09:01:07 +00:00
|
|
|
int
|
|
|
|
IMT_CreateSwitcher (const char *switcher_name, int context, imt_t *default_imt,
|
|
|
|
int num_inputs, const char **input_names)
|
|
|
|
{
|
|
|
|
if (IMT_FindSwitcher (switcher_name)) {
|
|
|
|
Sys_Printf ("imt switcher %s already exists\n", switcher_name);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((size_t) context >= in_contexts.size) {
|
|
|
|
Sys_Printf ("invalid imt context %d\n", context);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
in_context_t *ctx = &in_contexts.a[context];
|
|
|
|
|
|
|
|
if (!imt_find_imt (ctx, default_imt->name)) {
|
|
|
|
Sys_Printf ("default imt %s not in context %s\n",
|
|
|
|
default_imt->name, ctx->name);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int input_error = 0;
|
|
|
|
if (num_inputs > 16) {
|
|
|
|
Sys_Printf ("too many inputs %d\n", num_inputs);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
for (int i = 0; i < num_inputs; i++) {
|
|
|
|
const char *input_name = input_names[i];
|
|
|
|
if (!input_name) {
|
|
|
|
input_error = 1;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (input_name[0] == '+') {
|
|
|
|
if (!IN_FindButton (input_name + 1)) {
|
|
|
|
Sys_Printf ("invalid button %s\n", input_name);
|
|
|
|
input_error = 1;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (!Cvar_FindVar (input_name)) {
|
|
|
|
Sys_Printf ("invalid cvar %s\n", input_name);
|
|
|
|
input_error = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (input_error) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
int num_states = 1 << num_inputs;
|
|
|
|
size_t size = sizeof (imt_switcher_t)
|
|
|
|
+ num_inputs * sizeof (imt_input_t)
|
|
|
|
+ num_states * sizeof (imt_t *);
|
|
|
|
imt_switcher_t *switcher = malloc (size);
|
|
|
|
*ctx->switcher_tail = switcher;
|
|
|
|
ctx->switcher_tail = &switcher->next;
|
|
|
|
|
|
|
|
switcher->next = 0;
|
|
|
|
switcher->name = strdup (switcher_name);
|
|
|
|
switcher->num_inputs = num_inputs;
|
|
|
|
switcher->inputs = (imt_input_t *) (switcher + 1);
|
|
|
|
switcher->imts = (imt_t **) (switcher->inputs + num_inputs);
|
|
|
|
switcher->context = ctx;
|
|
|
|
for (int i = 0; i < num_inputs; i++) {
|
|
|
|
imt_input_t *input = &switcher->inputs[i];
|
|
|
|
const char *input_name = input_names[i];
|
|
|
|
if (input_name[0] == '+') {
|
|
|
|
input->type = imti_button;
|
|
|
|
input->button = IN_FindButton (input_name + 1);
|
|
|
|
IN_ButtonAddListener (input->button, imt_switcher_button_update,
|
|
|
|
switcher);
|
|
|
|
} else {
|
|
|
|
input->type = imti_cvar;
|
[cvar] Make cvars properly typed
This is an extremely extensive patch as it hits every cvar, and every
usage of the cvars. Cvars no longer store the value they control,
instead, they use a cexpr value object to reference the value and
specify the value's type (currently, a null type is used for strings).
Non-string cvars are passed through cexpr, allowing expressions in the
cvars' settings. Also, cvars have returned to an enhanced version of the
original (id quake) registration scheme.
As a minor benefit, relevant code having direct access to the
cvar-controlled variables is probably a slight optimization as it
removed a pointer dereference, and the variables can be located for data
locality.
The static cvar descriptors are made private as an additional safety
layer, though there's nothing stopping external modification via
Cvar_FindVar (which is needed for adding listeners).
While not used yet (partly due to working out the design), cvars can
have a validation function.
Registering a cvar allows a primary listener (and its data) to be
specified: it will always be called first when the cvar is modified. The
combination of proper listeners and direct access to the controlled
variable greatly simplifies the more complex cvar interactions as much
less null checking is required, and there's no need for one cvar's
callback to call another's.
nq-x11 is known to work at least well enough for the demos. More testing
will come.
2022-04-23 03:22:45 +00:00
|
|
|
//FIXME check cvar type
|
[input] Create an automatic imt switcher
An imt switcher automatically changes the context's active imt based on
a user specified list of binary inputs. The inputs may be either buttons
(indicated as +button) or cvars (bare name). For buttons, the
pressed/not pressed state is used, and cvars are interpreted as ints
being 0 or not 0. The order of the inputs determines the bit number of
the input, with the first input being bit 0, second bit 1, third bit 2
etc. A default imt is given so large switchers do not need to be fully
configured (the default imt is written to all states).
A context can have any number of switchers attached. The switchers can
wind up fighting over the active imt, but this seems to be something for
the "user" (eg, configuration system) to sort out rather than the
switcher code enforcing anything.
As a result of the inputs being treated as bits, a switcher with N
inputs will have 2**N states, thus there's a maximum of 16 inputs for
now as 65536 states is a lot of configuration.
Using a switcher, setting up a standard strafe/mouse look configuration
is fairly easy.
imt_create key_game imt_mod
imt_create key_game imt_mod_strafe imt_mod
imt_create key_game imt_mod_freelook
imt_create key_game imt_mod_lookstrafe imt_mod_freelook
imt_switcher_create mouse key_game imt_mod_strafe +strafe lookstrafe +mlook freelook
imt_switcher 0 imt_mod 2 imt_mod 4 imt_mod_freelook 8 imt_mod_freelook 12 imt_mod_freelook
imt_switcher 6 imt_mod_lookstrafe 10 imt_mod_lookstrafe 14 imt_mod_lookstrafe
in_bind imt_mod mouse axis 0 move.yaw
in_bind imt_mod mouse axis 1 move.forward
in_bind imt_mod_strafe mouse axis 0 move.side
in_bind imt_mod_lookstrafe mouse axis 0 move.side
in_bind imt_mod_freelook mouse axis 1 move.pitch
This takes advantage of imt chaining and the default imt for the
switcher (there are 8 states that use imt_mod_strafe).
The switcher name must be unique across all contexts, and every imt used
in a switcher must be in the switcher's context.
2021-11-25 09:01:07 +00:00
|
|
|
input->cvar = Cvar_FindVar (input_name);
|
|
|
|
Cvar_AddListener (input->cvar, imt_switcher_cvar_update, switcher);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for (int i = 0; i < num_states; i++) {
|
|
|
|
switcher->imts[i] = default_imt;
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2021-11-08 07:54:52 +00:00
|
|
|
void
|
2021-11-11 06:51:47 +00:00
|
|
|
IMT_BindAxis (imt_t *imt, int axis_num, in_axis_t *axis,
|
|
|
|
const in_recipe_t *recipe)
|
2021-11-08 07:54:52 +00:00
|
|
|
{
|
2021-11-11 06:51:47 +00:00
|
|
|
if ((size_t) axis_num >= imt->axis_bindings.size)
|
2021-11-08 07:54:52 +00:00
|
|
|
return;
|
|
|
|
|
2021-11-11 06:51:47 +00:00
|
|
|
in_axisbinding_t **bind = &imt->axis_bindings.a[axis_num];
|
2021-11-08 07:54:52 +00:00
|
|
|
free_axis_binding ((*bind));
|
|
|
|
(*bind) = 0;
|
2021-11-11 06:51:47 +00:00
|
|
|
if (axis && recipe) {
|
2021-11-08 07:54:52 +00:00
|
|
|
in_axisbinding_t *a = alloc_axis_binding ();
|
|
|
|
(*bind) = a;
|
2021-11-11 06:51:47 +00:00
|
|
|
if (!(a->recipe = Hash_FindElement (recipe_tab, recipe))) {
|
|
|
|
*(a->recipe = alloc_recipe ()) = *recipe;
|
|
|
|
Hash_AddElement (recipe_tab, a->recipe);
|
|
|
|
}
|
2021-11-11 15:24:04 +00:00
|
|
|
a->axis = axis;
|
2021-11-08 07:54:52 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-06-13 09:06:11 +00:00
|
|
|
bool
|
2021-11-03 10:02:39 +00:00
|
|
|
IMT_ProcessAxis (int axis, int value)
|
|
|
|
{
|
2021-11-08 02:20:04 +00:00
|
|
|
imt_t *imt = in_contexts.a[imt_current_context].active_imt;
|
|
|
|
|
|
|
|
while (imt) {
|
|
|
|
in_axisbinding_t *a = imt->axis_bindings.a[axis];
|
|
|
|
if (a) {
|
2021-11-11 06:51:47 +00:00
|
|
|
in_recipe_t *recipe = a->recipe;
|
|
|
|
int relative = recipe->min == recipe->max;
|
|
|
|
int deadzone = recipe->deadzone;
|
|
|
|
int minval = recipe->min + recipe->minzone;
|
|
|
|
int maxval = recipe->max - recipe->maxzone;
|
|
|
|
float output;
|
|
|
|
if (relative) {
|
2021-11-11 15:24:04 +00:00
|
|
|
int input = value;
|
2021-11-11 06:51:47 +00:00
|
|
|
if (deadzone > 0) {
|
|
|
|
if (input > deadzone) {
|
|
|
|
input -= deadzone;
|
|
|
|
} else if (input < -deadzone) {
|
|
|
|
input += deadzone;
|
|
|
|
} else {
|
|
|
|
input = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
output = input * recipe->scale;
|
|
|
|
if (recipe->curve != 1) {
|
|
|
|
output = powf (output, recipe->curve);
|
|
|
|
}
|
2021-11-23 13:04:17 +00:00
|
|
|
a->axis->rel_input += output;
|
2021-11-11 06:51:47 +00:00
|
|
|
} else {
|
2021-11-11 15:24:04 +00:00
|
|
|
int input = bound (minval, value, maxval);
|
2021-11-11 06:51:47 +00:00
|
|
|
int range = maxval - minval;
|
|
|
|
int zero = minval;
|
|
|
|
if (recipe->deadzone >= 0) {
|
|
|
|
// balanced axis: -1..1
|
|
|
|
int center = (recipe->min + recipe->max + 1) / 2;
|
2021-12-22 14:43:03 +00:00
|
|
|
minval += deadzone;
|
|
|
|
maxval -= deadzone;
|
2021-11-11 06:51:47 +00:00
|
|
|
input -= center;
|
|
|
|
if (input < -deadzone) {
|
|
|
|
input += deadzone;
|
|
|
|
} else if (input > deadzone) {
|
|
|
|
input -= deadzone;
|
|
|
|
} else {
|
|
|
|
input = 0;
|
|
|
|
}
|
|
|
|
if (center - minval > maxval - center) {
|
|
|
|
range = center - minval;
|
|
|
|
} else {
|
|
|
|
range = maxval - center;
|
|
|
|
}
|
|
|
|
zero = 0;
|
|
|
|
}
|
|
|
|
output = (float)(input - zero) / (range);
|
|
|
|
if (recipe->curve != 1) {
|
|
|
|
output = powf (output, recipe->curve);
|
|
|
|
}
|
|
|
|
output *= recipe->scale;
|
2021-11-23 13:04:17 +00:00
|
|
|
a->axis->abs_input = output;
|
2021-11-11 06:51:47 +00:00
|
|
|
}
|
2021-11-08 02:20:04 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
imt = imt->chain;
|
|
|
|
}
|
|
|
|
return false;
|
2021-11-03 10:02:39 +00:00
|
|
|
}
|
|
|
|
|
2021-11-08 02:20:04 +00:00
|
|
|
static void
|
|
|
|
process_binding (int button, int state, const char *cmd)
|
|
|
|
{
|
|
|
|
cbuf_t *cbuf = in_contexts.a[imt_current_context].cbuf;
|
|
|
|
|
|
|
|
if (!cbuf) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (cmd[0] == '+') {
|
|
|
|
if (state) {
|
|
|
|
Cbuf_AddText (cbuf, va (0, "%s %d\n", cmd, button));
|
|
|
|
} else {
|
|
|
|
Cbuf_AddText (cbuf, va (0, "-%s %d\n", cmd + 1, button));
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (state) {
|
|
|
|
Cbuf_AddText (cbuf, va (0, "%s\n", cmd));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-06-13 09:06:11 +00:00
|
|
|
bool
|
2021-11-03 10:02:39 +00:00
|
|
|
IMT_ProcessButton (int button, int state)
|
|
|
|
{
|
2021-11-08 02:20:04 +00:00
|
|
|
imt_t *imt = in_contexts.a[imt_current_context].active_imt;
|
|
|
|
|
|
|
|
while (imt) {
|
|
|
|
in_buttonbinding_t *b = imt->button_bindings.a[button];
|
|
|
|
if (b) {
|
2021-12-18 05:14:12 +00:00
|
|
|
// ensure IN_ButtonAction never sees button id 0
|
|
|
|
button += 1;
|
2021-11-08 02:20:04 +00:00
|
|
|
switch (b->type) {
|
|
|
|
case inb_button:
|
|
|
|
IN_ButtonAction (b->button, button, state);
|
|
|
|
break;
|
|
|
|
case inb_command:
|
|
|
|
//FIXME avoid repeat
|
|
|
|
process_binding (button, state, b->command);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
imt = imt->chain;
|
|
|
|
}
|
|
|
|
return false;
|
2021-11-03 10:02:39 +00:00
|
|
|
}
|
2021-11-08 07:54:52 +00:00
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
[input] Create an automatic imt switcher
An imt switcher automatically changes the context's active imt based on
a user specified list of binary inputs. The inputs may be either buttons
(indicated as +button) or cvars (bare name). For buttons, the
pressed/not pressed state is used, and cvars are interpreted as ints
being 0 or not 0. The order of the inputs determines the bit number of
the input, with the first input being bit 0, second bit 1, third bit 2
etc. A default imt is given so large switchers do not need to be fully
configured (the default imt is written to all states).
A context can have any number of switchers attached. The switchers can
wind up fighting over the active imt, but this seems to be something for
the "user" (eg, configuration system) to sort out rather than the
switcher code enforcing anything.
As a result of the inputs being treated as bits, a switcher with N
inputs will have 2**N states, thus there's a maximum of 16 inputs for
now as 65536 states is a lot of configuration.
Using a switcher, setting up a standard strafe/mouse look configuration
is fairly easy.
imt_create key_game imt_mod
imt_create key_game imt_mod_strafe imt_mod
imt_create key_game imt_mod_freelook
imt_create key_game imt_mod_lookstrafe imt_mod_freelook
imt_switcher_create mouse key_game imt_mod_strafe +strafe lookstrafe +mlook freelook
imt_switcher 0 imt_mod 2 imt_mod 4 imt_mod_freelook 8 imt_mod_freelook 12 imt_mod_freelook
imt_switcher 6 imt_mod_lookstrafe 10 imt_mod_lookstrafe 14 imt_mod_lookstrafe
in_bind imt_mod mouse axis 0 move.yaw
in_bind imt_mod mouse axis 1 move.forward
in_bind imt_mod_strafe mouse axis 0 move.side
in_bind imt_mod_lookstrafe mouse axis 0 move.side
in_bind imt_mod_freelook mouse axis 1 move.pitch
This takes advantage of imt chaining and the default imt for the
switcher (there are 8 states that use imt_mod_strafe).
The switcher name must be unique across all contexts, and every imt used
in a switcher must be in the switcher's context.
2021-11-25 09:01:07 +00:00
|
|
|
static void
|
|
|
|
imt_switcher_create_f (void)
|
|
|
|
{
|
|
|
|
int argc = Cmd_Argc ();
|
|
|
|
|
|
|
|
if (argc < 5) {
|
|
|
|
Sys_Printf ("see help imt_switcher_create\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
const char *switcher_name = Cmd_Argv (1);
|
|
|
|
const char *context_name = Cmd_Argv (2);
|
|
|
|
const char *default_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_t *default_imt = imt_find_imt (ctx, default_imt_name);
|
|
|
|
if (!default_imt) {
|
|
|
|
Sys_Printf ("default imt %s not in context %s\n",
|
|
|
|
default_imt_name, context_name);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
int num_inputs = argc - 4;
|
|
|
|
const char **input_names = alloca (num_inputs * sizeof (const char*));
|
|
|
|
for (int i = 0; i < num_inputs; i++) {
|
|
|
|
input_names[i] = Cmd_Argv (i + 4);
|
|
|
|
}
|
|
|
|
|
|
|
|
IMT_CreateSwitcher (switcher_name, ctx - in_contexts.a, default_imt,
|
|
|
|
num_inputs, input_names);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
imt_switcher_f (void)
|
|
|
|
{
|
|
|
|
int argc = Cmd_Argc ();
|
|
|
|
|
|
|
|
// state/imt pairs result in an even number of arguments
|
|
|
|
if (argc < 4 || (argc & 1)) {
|
|
|
|
Sys_Printf ("see help imt_switcher\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
const char *switcher_name = Cmd_Argv (1);
|
|
|
|
imt_switcher_t *switcher = IMT_FindSwitcher (switcher_name);
|
|
|
|
if (!switcher) {
|
|
|
|
Sys_Printf ("switcher %s does not exist\n", switcher_name);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
int num_states = 1 << switcher->num_inputs;
|
|
|
|
for (int i = 2; i < argc; i += 2) {
|
|
|
|
const char *state_str = Cmd_Argv (i + 0);
|
|
|
|
const char *imt_name = Cmd_Argv (i + 1);
|
|
|
|
char *end;
|
|
|
|
int state = strtol (state_str, &end, 0);
|
|
|
|
imt_t *imt = imt_find_imt (switcher->context, imt_name);
|
|
|
|
if (*end || state < 0 || state >= num_states) {
|
|
|
|
Sys_Printf ("invalid state: %s\n", state_str);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (!imt) {
|
|
|
|
Sys_Printf ("imt %s not in context %s\n",
|
|
|
|
imt_name, switcher->context->name);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
switcher->imts[state] = imt;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-08 07:54:52 +00:00
|
|
|
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]);
|
|
|
|
}
|
2022-05-12 10:01:45 +00:00
|
|
|
DARRAY_CLEAR (&imt->axis_bindings);
|
|
|
|
DARRAY_CLEAR (&imt->button_bindings);
|
2021-11-08 07:54:52 +00:00
|
|
|
free ((char *) imt->name);
|
|
|
|
free (imt);
|
|
|
|
}
|
[input] Create an automatic imt switcher
An imt switcher automatically changes the context's active imt based on
a user specified list of binary inputs. The inputs may be either buttons
(indicated as +button) or cvars (bare name). For buttons, the
pressed/not pressed state is used, and cvars are interpreted as ints
being 0 or not 0. The order of the inputs determines the bit number of
the input, with the first input being bit 0, second bit 1, third bit 2
etc. A default imt is given so large switchers do not need to be fully
configured (the default imt is written to all states).
A context can have any number of switchers attached. The switchers can
wind up fighting over the active imt, but this seems to be something for
the "user" (eg, configuration system) to sort out rather than the
switcher code enforcing anything.
As a result of the inputs being treated as bits, a switcher with N
inputs will have 2**N states, thus there's a maximum of 16 inputs for
now as 65536 states is a lot of configuration.
Using a switcher, setting up a standard strafe/mouse look configuration
is fairly easy.
imt_create key_game imt_mod
imt_create key_game imt_mod_strafe imt_mod
imt_create key_game imt_mod_freelook
imt_create key_game imt_mod_lookstrafe imt_mod_freelook
imt_switcher_create mouse key_game imt_mod_strafe +strafe lookstrafe +mlook freelook
imt_switcher 0 imt_mod 2 imt_mod 4 imt_mod_freelook 8 imt_mod_freelook 12 imt_mod_freelook
imt_switcher 6 imt_mod_lookstrafe 10 imt_mod_lookstrafe 14 imt_mod_lookstrafe
in_bind imt_mod mouse axis 0 move.yaw
in_bind imt_mod mouse axis 1 move.forward
in_bind imt_mod_strafe mouse axis 0 move.side
in_bind imt_mod_lookstrafe mouse axis 0 move.side
in_bind imt_mod_freelook mouse axis 1 move.pitch
This takes advantage of imt chaining and the default imt for the
switcher (there are 8 states that use imt_mod_strafe).
The switcher name must be unique across all contexts, and every imt used
in a switcher must be in the switcher's context.
2021-11-25 09:01:07 +00:00
|
|
|
while (ctx->switchers) {
|
|
|
|
imt_switcher_t *switcher = ctx->switchers;
|
|
|
|
ctx->switchers = switcher->next;
|
|
|
|
for (int i = 0; i < switcher->num_inputs; i++) {
|
|
|
|
imt_input_t *input = &switcher->inputs[i];
|
|
|
|
switch (input->type) {
|
|
|
|
case imti_button:
|
|
|
|
IN_ButtonRemoveListener (input->button,
|
|
|
|
imt_switcher_button_update,
|
|
|
|
switcher);
|
|
|
|
break;
|
|
|
|
case imti_cvar:
|
|
|
|
Cvar_RemoveListener (input->cvar,
|
|
|
|
imt_switcher_cvar_update,
|
|
|
|
switcher);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
free ((char *) switcher->name);
|
|
|
|
free (switcher);
|
|
|
|
}
|
2021-11-08 07:54:52 +00:00
|
|
|
ctx->active_imt = 0;
|
2021-11-14 01:17:05 +00:00
|
|
|
ctx->default_imt = 0;
|
|
|
|
ctx->imt_tail = &ctx->imts;
|
[input] Create an automatic imt switcher
An imt switcher automatically changes the context's active imt based on
a user specified list of binary inputs. The inputs may be either buttons
(indicated as +button) or cvars (bare name). For buttons, the
pressed/not pressed state is used, and cvars are interpreted as ints
being 0 or not 0. The order of the inputs determines the bit number of
the input, with the first input being bit 0, second bit 1, third bit 2
etc. A default imt is given so large switchers do not need to be fully
configured (the default imt is written to all states).
A context can have any number of switchers attached. The switchers can
wind up fighting over the active imt, but this seems to be something for
the "user" (eg, configuration system) to sort out rather than the
switcher code enforcing anything.
As a result of the inputs being treated as bits, a switcher with N
inputs will have 2**N states, thus there's a maximum of 16 inputs for
now as 65536 states is a lot of configuration.
Using a switcher, setting up a standard strafe/mouse look configuration
is fairly easy.
imt_create key_game imt_mod
imt_create key_game imt_mod_strafe imt_mod
imt_create key_game imt_mod_freelook
imt_create key_game imt_mod_lookstrafe imt_mod_freelook
imt_switcher_create mouse key_game imt_mod_strafe +strafe lookstrafe +mlook freelook
imt_switcher 0 imt_mod 2 imt_mod 4 imt_mod_freelook 8 imt_mod_freelook 12 imt_mod_freelook
imt_switcher 6 imt_mod_lookstrafe 10 imt_mod_lookstrafe 14 imt_mod_lookstrafe
in_bind imt_mod mouse axis 0 move.yaw
in_bind imt_mod mouse axis 1 move.forward
in_bind imt_mod_strafe mouse axis 0 move.side
in_bind imt_mod_lookstrafe mouse axis 0 move.side
in_bind imt_mod_freelook mouse axis 1 move.pitch
This takes advantage of imt chaining and the default imt for the
switcher (there are 8 states that use imt_mod_strafe).
The switcher name must be unique across all contexts, and every imt used
in a switcher must be in the switcher's context.
2021-11-25 09:01:07 +00:00
|
|
|
ctx->switcher_tail = &ctx->switchers;
|
2021-11-08 07:54:52 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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,
|
2022-05-22 04:51:55 +00:00
|
|
|
"List the available input mapping tables."
|
2021-11-08 07:54:52 +00:00
|
|
|
},
|
|
|
|
{ "imt_create", imt_create_f,
|
|
|
|
"create a new imt table:\n"
|
[input] Create an automatic imt switcher
An imt switcher automatically changes the context's active imt based on
a user specified list of binary inputs. The inputs may be either buttons
(indicated as +button) or cvars (bare name). For buttons, the
pressed/not pressed state is used, and cvars are interpreted as ints
being 0 or not 0. The order of the inputs determines the bit number of
the input, with the first input being bit 0, second bit 1, third bit 2
etc. A default imt is given so large switchers do not need to be fully
configured (the default imt is written to all states).
A context can have any number of switchers attached. The switchers can
wind up fighting over the active imt, but this seems to be something for
the "user" (eg, configuration system) to sort out rather than the
switcher code enforcing anything.
As a result of the inputs being treated as bits, a switcher with N
inputs will have 2**N states, thus there's a maximum of 16 inputs for
now as 65536 states is a lot of configuration.
Using a switcher, setting up a standard strafe/mouse look configuration
is fairly easy.
imt_create key_game imt_mod
imt_create key_game imt_mod_strafe imt_mod
imt_create key_game imt_mod_freelook
imt_create key_game imt_mod_lookstrafe imt_mod_freelook
imt_switcher_create mouse key_game imt_mod_strafe +strafe lookstrafe +mlook freelook
imt_switcher 0 imt_mod 2 imt_mod 4 imt_mod_freelook 8 imt_mod_freelook 12 imt_mod_freelook
imt_switcher 6 imt_mod_lookstrafe 10 imt_mod_lookstrafe 14 imt_mod_lookstrafe
in_bind imt_mod mouse axis 0 move.yaw
in_bind imt_mod mouse axis 1 move.forward
in_bind imt_mod_strafe mouse axis 0 move.side
in_bind imt_mod_lookstrafe mouse axis 0 move.side
in_bind imt_mod_freelook mouse axis 1 move.pitch
This takes advantage of imt chaining and the default imt for the
switcher (there are 8 states that use imt_mod_strafe).
The switcher name must be unique across all contexts, and every imt used
in a switcher must be in the switcher's context.
2021-11-25 09:01:07 +00:00
|
|
|
" imt_create <context> <imt_name> [chain_name]\n"
|
2021-11-08 07:54:52 +00:00
|
|
|
"\n"
|
2022-05-22 04:51:55 +00:00
|
|
|
"The new table will be attached to the specified context.\n"
|
|
|
|
"\n"
|
2021-11-08 07:54:52 +00:00
|
|
|
"imt_name must not already exist.\n"
|
[input] Create an automatic imt switcher
An imt switcher automatically changes the context's active imt based on
a user specified list of binary inputs. The inputs may be either buttons
(indicated as +button) or cvars (bare name). For buttons, the
pressed/not pressed state is used, and cvars are interpreted as ints
being 0 or not 0. The order of the inputs determines the bit number of
the input, with the first input being bit 0, second bit 1, third bit 2
etc. A default imt is given so large switchers do not need to be fully
configured (the default imt is written to all states).
A context can have any number of switchers attached. The switchers can
wind up fighting over the active imt, but this seems to be something for
the "user" (eg, configuration system) to sort out rather than the
switcher code enforcing anything.
As a result of the inputs being treated as bits, a switcher with N
inputs will have 2**N states, thus there's a maximum of 16 inputs for
now as 65536 states is a lot of configuration.
Using a switcher, setting up a standard strafe/mouse look configuration
is fairly easy.
imt_create key_game imt_mod
imt_create key_game imt_mod_strafe imt_mod
imt_create key_game imt_mod_freelook
imt_create key_game imt_mod_lookstrafe imt_mod_freelook
imt_switcher_create mouse key_game imt_mod_strafe +strafe lookstrafe +mlook freelook
imt_switcher 0 imt_mod 2 imt_mod 4 imt_mod_freelook 8 imt_mod_freelook 12 imt_mod_freelook
imt_switcher 6 imt_mod_lookstrafe 10 imt_mod_lookstrafe 14 imt_mod_lookstrafe
in_bind imt_mod mouse axis 0 move.yaw
in_bind imt_mod mouse axis 1 move.forward
in_bind imt_mod_strafe mouse axis 0 move.side
in_bind imt_mod_lookstrafe mouse axis 0 move.side
in_bind imt_mod_freelook mouse axis 1 move.pitch
This takes advantage of imt chaining and the default imt for the
switcher (there are 8 states that use imt_mod_strafe).
The switcher name must be unique across all contexts, and every imt used
in a switcher must be in the switcher's context.
2021-11-25 09:01:07 +00:00
|
|
|
"If given, chain_name must already exist and be in the context.\n"
|
|
|
|
},
|
|
|
|
{ "imt_switcher_create", imt_switcher_create_f,
|
|
|
|
"create a new imt switcher:\n"
|
|
|
|
" imt_switcher_create <name> <context> <default_imt> <input0>"
|
|
|
|
" [..<inputN>]\n"
|
|
|
|
"name is the name of the switcher and must be unique across all\n"
|
2022-05-22 04:51:55 +00:00
|
|
|
"contexts.\n"
|
|
|
|
"\n"
|
[input] Create an automatic imt switcher
An imt switcher automatically changes the context's active imt based on
a user specified list of binary inputs. The inputs may be either buttons
(indicated as +button) or cvars (bare name). For buttons, the
pressed/not pressed state is used, and cvars are interpreted as ints
being 0 or not 0. The order of the inputs determines the bit number of
the input, with the first input being bit 0, second bit 1, third bit 2
etc. A default imt is given so large switchers do not need to be fully
configured (the default imt is written to all states).
A context can have any number of switchers attached. The switchers can
wind up fighting over the active imt, but this seems to be something for
the "user" (eg, configuration system) to sort out rather than the
switcher code enforcing anything.
As a result of the inputs being treated as bits, a switcher with N
inputs will have 2**N states, thus there's a maximum of 16 inputs for
now as 65536 states is a lot of configuration.
Using a switcher, setting up a standard strafe/mouse look configuration
is fairly easy.
imt_create key_game imt_mod
imt_create key_game imt_mod_strafe imt_mod
imt_create key_game imt_mod_freelook
imt_create key_game imt_mod_lookstrafe imt_mod_freelook
imt_switcher_create mouse key_game imt_mod_strafe +strafe lookstrafe +mlook freelook
imt_switcher 0 imt_mod 2 imt_mod 4 imt_mod_freelook 8 imt_mod_freelook 12 imt_mod_freelook
imt_switcher 6 imt_mod_lookstrafe 10 imt_mod_lookstrafe 14 imt_mod_lookstrafe
in_bind imt_mod mouse axis 0 move.yaw
in_bind imt_mod mouse axis 1 move.forward
in_bind imt_mod_strafe mouse axis 0 move.side
in_bind imt_mod_lookstrafe mouse axis 0 move.side
in_bind imt_mod_freelook mouse axis 1 move.pitch
This takes advantage of imt chaining and the default imt for the
switcher (there are 8 states that use imt_mod_strafe).
The switcher name must be unique across all contexts, and every imt used
in a switcher must be in the switcher's context.
2021-11-25 09:01:07 +00:00
|
|
|
"The new switcher will be attached to the specified context\n"
|
2022-05-22 04:51:55 +00:00
|
|
|
"\n"
|
[input] Create an automatic imt switcher
An imt switcher automatically changes the context's active imt based on
a user specified list of binary inputs. The inputs may be either buttons
(indicated as +button) or cvars (bare name). For buttons, the
pressed/not pressed state is used, and cvars are interpreted as ints
being 0 or not 0. The order of the inputs determines the bit number of
the input, with the first input being bit 0, second bit 1, third bit 2
etc. A default imt is given so large switchers do not need to be fully
configured (the default imt is written to all states).
A context can have any number of switchers attached. The switchers can
wind up fighting over the active imt, but this seems to be something for
the "user" (eg, configuration system) to sort out rather than the
switcher code enforcing anything.
As a result of the inputs being treated as bits, a switcher with N
inputs will have 2**N states, thus there's a maximum of 16 inputs for
now as 65536 states is a lot of configuration.
Using a switcher, setting up a standard strafe/mouse look configuration
is fairly easy.
imt_create key_game imt_mod
imt_create key_game imt_mod_strafe imt_mod
imt_create key_game imt_mod_freelook
imt_create key_game imt_mod_lookstrafe imt_mod_freelook
imt_switcher_create mouse key_game imt_mod_strafe +strafe lookstrafe +mlook freelook
imt_switcher 0 imt_mod 2 imt_mod 4 imt_mod_freelook 8 imt_mod_freelook 12 imt_mod_freelook
imt_switcher 6 imt_mod_lookstrafe 10 imt_mod_lookstrafe 14 imt_mod_lookstrafe
in_bind imt_mod mouse axis 0 move.yaw
in_bind imt_mod mouse axis 1 move.forward
in_bind imt_mod_strafe mouse axis 0 move.side
in_bind imt_mod_lookstrafe mouse axis 0 move.side
in_bind imt_mod_freelook mouse axis 1 move.pitch
This takes advantage of imt chaining and the default imt for the
switcher (there are 8 states that use imt_mod_strafe).
The switcher name must be unique across all contexts, and every imt used
in a switcher must be in the switcher's context.
2021-11-25 09:01:07 +00:00
|
|
|
"default_imt specifies the default imt to be used for all possible\n"
|
2022-05-19 02:26:19 +00:00
|
|
|
"states and must exist and be in the context.\n"
|
2022-05-22 04:51:55 +00:00
|
|
|
"\n"
|
[input] Create an automatic imt switcher
An imt switcher automatically changes the context's active imt based on
a user specified list of binary inputs. The inputs may be either buttons
(indicated as +button) or cvars (bare name). For buttons, the
pressed/not pressed state is used, and cvars are interpreted as ints
being 0 or not 0. The order of the inputs determines the bit number of
the input, with the first input being bit 0, second bit 1, third bit 2
etc. A default imt is given so large switchers do not need to be fully
configured (the default imt is written to all states).
A context can have any number of switchers attached. The switchers can
wind up fighting over the active imt, but this seems to be something for
the "user" (eg, configuration system) to sort out rather than the
switcher code enforcing anything.
As a result of the inputs being treated as bits, a switcher with N
inputs will have 2**N states, thus there's a maximum of 16 inputs for
now as 65536 states is a lot of configuration.
Using a switcher, setting up a standard strafe/mouse look configuration
is fairly easy.
imt_create key_game imt_mod
imt_create key_game imt_mod_strafe imt_mod
imt_create key_game imt_mod_freelook
imt_create key_game imt_mod_lookstrafe imt_mod_freelook
imt_switcher_create mouse key_game imt_mod_strafe +strafe lookstrafe +mlook freelook
imt_switcher 0 imt_mod 2 imt_mod 4 imt_mod_freelook 8 imt_mod_freelook 12 imt_mod_freelook
imt_switcher 6 imt_mod_lookstrafe 10 imt_mod_lookstrafe 14 imt_mod_lookstrafe
in_bind imt_mod mouse axis 0 move.yaw
in_bind imt_mod mouse axis 1 move.forward
in_bind imt_mod_strafe mouse axis 0 move.side
in_bind imt_mod_lookstrafe mouse axis 0 move.side
in_bind imt_mod_freelook mouse axis 1 move.pitch
This takes advantage of imt chaining and the default imt for the
switcher (there are 8 states that use imt_mod_strafe).
The switcher name must be unique across all contexts, and every imt used
in a switcher must be in the switcher's context.
2021-11-25 09:01:07 +00:00
|
|
|
"input0..inputN specify the inputs (cvar or button) used to set the\n"
|
|
|
|
"switcher's state. As each input forms a bit in the state index,\n"
|
|
|
|
"there will be 2**(N+1) states (so 4 inputs will result in 16\n"
|
|
|
|
"states, and 16 inputs will result in 65536 states). Up to 16 inputs\n"
|
2022-05-22 04:51:55 +00:00
|
|
|
"are allowed.\n"
|
[input] Create an automatic imt switcher
An imt switcher automatically changes the context's active imt based on
a user specified list of binary inputs. The inputs may be either buttons
(indicated as +button) or cvars (bare name). For buttons, the
pressed/not pressed state is used, and cvars are interpreted as ints
being 0 or not 0. The order of the inputs determines the bit number of
the input, with the first input being bit 0, second bit 1, third bit 2
etc. A default imt is given so large switchers do not need to be fully
configured (the default imt is written to all states).
A context can have any number of switchers attached. The switchers can
wind up fighting over the active imt, but this seems to be something for
the "user" (eg, configuration system) to sort out rather than the
switcher code enforcing anything.
As a result of the inputs being treated as bits, a switcher with N
inputs will have 2**N states, thus there's a maximum of 16 inputs for
now as 65536 states is a lot of configuration.
Using a switcher, setting up a standard strafe/mouse look configuration
is fairly easy.
imt_create key_game imt_mod
imt_create key_game imt_mod_strafe imt_mod
imt_create key_game imt_mod_freelook
imt_create key_game imt_mod_lookstrafe imt_mod_freelook
imt_switcher_create mouse key_game imt_mod_strafe +strafe lookstrafe +mlook freelook
imt_switcher 0 imt_mod 2 imt_mod 4 imt_mod_freelook 8 imt_mod_freelook 12 imt_mod_freelook
imt_switcher 6 imt_mod_lookstrafe 10 imt_mod_lookstrafe 14 imt_mod_lookstrafe
in_bind imt_mod mouse axis 0 move.yaw
in_bind imt_mod mouse axis 1 move.forward
in_bind imt_mod_strafe mouse axis 0 move.side
in_bind imt_mod_lookstrafe mouse axis 0 move.side
in_bind imt_mod_freelook mouse axis 1 move.pitch
This takes advantage of imt chaining and the default imt for the
switcher (there are 8 states that use imt_mod_strafe).
The switcher name must be unique across all contexts, and every imt used
in a switcher must be in the switcher's context.
2021-11-25 09:01:07 +00:00
|
|
|
"\n"
|
|
|
|
"Buttons are spefied as +buttonname (eg, +mlook, +strafe).\n"
|
|
|
|
"Cvars are just the cvar name (eg, freelook, lookstrafe).\n"
|
|
|
|
"\n"
|
|
|
|
"Use imt_switcher to set the imt for each state.\n"
|
|
|
|
"\n"
|
|
|
|
"There can be multiple switchers in a context, but they can wind up\n"
|
|
|
|
"fighting over the active imt for the context if they share inputs.\n"
|
|
|
|
},
|
|
|
|
{ "imt_switcher", imt_switcher_f,
|
|
|
|
"Set the imts for states in an imt switcher:\n"
|
|
|
|
" imt_switcher <name> <state_index> <imt>"
|
|
|
|
" [..<state_indexM> <imtM>]\n"
|
|
|
|
"name is the name of the switcher to be modifed and must exist\n"
|
|
|
|
"state_index is the state index formed by the binary number\n"
|
|
|
|
"interpretation of the inputs with input0 being bit 0 and inputN\n"
|
|
|
|
"being bit N.\n"
|
2022-05-22 04:51:55 +00:00
|
|
|
"\n"
|
[input] Create an automatic imt switcher
An imt switcher automatically changes the context's active imt based on
a user specified list of binary inputs. The inputs may be either buttons
(indicated as +button) or cvars (bare name). For buttons, the
pressed/not pressed state is used, and cvars are interpreted as ints
being 0 or not 0. The order of the inputs determines the bit number of
the input, with the first input being bit 0, second bit 1, third bit 2
etc. A default imt is given so large switchers do not need to be fully
configured (the default imt is written to all states).
A context can have any number of switchers attached. The switchers can
wind up fighting over the active imt, but this seems to be something for
the "user" (eg, configuration system) to sort out rather than the
switcher code enforcing anything.
As a result of the inputs being treated as bits, a switcher with N
inputs will have 2**N states, thus there's a maximum of 16 inputs for
now as 65536 states is a lot of configuration.
Using a switcher, setting up a standard strafe/mouse look configuration
is fairly easy.
imt_create key_game imt_mod
imt_create key_game imt_mod_strafe imt_mod
imt_create key_game imt_mod_freelook
imt_create key_game imt_mod_lookstrafe imt_mod_freelook
imt_switcher_create mouse key_game imt_mod_strafe +strafe lookstrafe +mlook freelook
imt_switcher 0 imt_mod 2 imt_mod 4 imt_mod_freelook 8 imt_mod_freelook 12 imt_mod_freelook
imt_switcher 6 imt_mod_lookstrafe 10 imt_mod_lookstrafe 14 imt_mod_lookstrafe
in_bind imt_mod mouse axis 0 move.yaw
in_bind imt_mod mouse axis 1 move.forward
in_bind imt_mod_strafe mouse axis 0 move.side
in_bind imt_mod_lookstrafe mouse axis 0 move.side
in_bind imt_mod_freelook mouse axis 1 move.pitch
This takes advantage of imt chaining and the default imt for the
switcher (there are 8 states that use imt_mod_strafe).
The switcher name must be unique across all contexts, and every imt used
in a switcher must be in the switcher's context.
2021-11-25 09:01:07 +00:00
|
|
|
"imt is the name of the imt to be assigned to the state and must\n"
|
|
|
|
"exist and be in the same context as the switcher.\n"
|
|
|
|
"\n"
|
|
|
|
"Any number of state_index imt pairs can be specified.\n"
|
2021-11-08 07:54:52 +00:00
|
|
|
},
|
|
|
|
{ "imt_drop_all", imt_drop_all_f,
|
2022-05-22 04:51:55 +00:00
|
|
|
"Delete all imt tables.\n"
|
2021-11-08 07:54:52 +00:00
|
|
|
},
|
2021-11-11 15:24:04 +00:00
|
|
|
{},
|
2021-11-08 07:54:52 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
void
|
|
|
|
IMT_Init (void)
|
|
|
|
{
|
|
|
|
binding_mem = new_memsuper ();
|
2021-11-11 06:51:47 +00:00
|
|
|
recipe_tab = Hash_NewTable (61, 0, recipe_free, 0, 0);
|
|
|
|
Hash_SetHashCompare (recipe_tab, recipe_get_hash, recipe_compare);
|
2021-11-08 07:54:52 +00:00
|
|
|
for (imtcmd_t *cmd = imt_commands; cmd->name; cmd++) {
|
|
|
|
Cmd_AddCommand (cmd->name, cmd->func, cmd->desc);
|
|
|
|
}
|
|
|
|
}
|
2021-11-14 01:17:05 +00:00
|
|
|
|
2022-05-12 10:01:45 +00:00
|
|
|
void
|
|
|
|
IMT_Shutdown (void)
|
|
|
|
{
|
|
|
|
imt_drop_all_f ();
|
|
|
|
Hash_DelTable (recipe_tab);
|
|
|
|
|
|
|
|
delete_memsuper (binding_mem);
|
|
|
|
binding_mem = 0;
|
|
|
|
DARRAY_CLEAR (&axis_blocks);
|
|
|
|
DARRAY_CLEAR (&button_blocks);
|
|
|
|
DARRAY_CLEAR (&in_contexts);
|
|
|
|
}
|
|
|
|
|
2021-11-14 01:17:05 +00:00
|
|
|
void
|
|
|
|
IMT_SaveConfig (plitem_t *config)
|
|
|
|
{
|
|
|
|
plitem_t *ctx_list = PL_NewArray ();
|
|
|
|
PL_D_AddObject (config, "contexts", ctx_list);
|
|
|
|
for (size_t i = 0; i < in_contexts.size; i++) {
|
|
|
|
in_context_t *context = &in_contexts.a[i];
|
2022-05-12 08:54:23 +00:00
|
|
|
plitem_t *ctx = PL_NewDictionary (0);
|
2021-11-14 01:17:05 +00:00
|
|
|
PL_A_AddObject (ctx_list, ctx);
|
|
|
|
PL_D_AddObject (ctx, "name", PL_NewString (context->name));
|
|
|
|
if (context->imts) {
|
|
|
|
plitem_t *imt_list = PL_NewArray ();
|
|
|
|
PL_D_AddObject (ctx, "imts", imt_list);
|
|
|
|
for (imt_t *imt = context->imts; imt; imt = imt->next) {
|
2022-05-12 08:54:23 +00:00
|
|
|
plitem_t *imt_cfg = PL_NewDictionary (0);
|
2021-11-14 01:17:05 +00:00
|
|
|
PL_D_AddObject (imt_cfg, "name", PL_NewString (imt->name));
|
|
|
|
if (imt->chain) {
|
|
|
|
PL_D_AddObject (imt_cfg, "chain",
|
|
|
|
PL_NewString (imt->chain->name));
|
|
|
|
}
|
|
|
|
PL_A_AddObject (imt_list, imt_cfg);
|
|
|
|
// the bindings are not written here because they are managed
|
|
|
|
// by IN_Binding_SaveConfig: IMT does not really know the
|
|
|
|
// device-input structure (it cound via the blocks, but it
|
|
|
|
// doesn't know the device names (by design))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (context->default_imt) {
|
|
|
|
PL_D_AddObject (ctx, "default_imt",
|
|
|
|
PL_NewString (context->default_imt->name));
|
|
|
|
}
|
[input] Create an automatic imt switcher
An imt switcher automatically changes the context's active imt based on
a user specified list of binary inputs. The inputs may be either buttons
(indicated as +button) or cvars (bare name). For buttons, the
pressed/not pressed state is used, and cvars are interpreted as ints
being 0 or not 0. The order of the inputs determines the bit number of
the input, with the first input being bit 0, second bit 1, third bit 2
etc. A default imt is given so large switchers do not need to be fully
configured (the default imt is written to all states).
A context can have any number of switchers attached. The switchers can
wind up fighting over the active imt, but this seems to be something for
the "user" (eg, configuration system) to sort out rather than the
switcher code enforcing anything.
As a result of the inputs being treated as bits, a switcher with N
inputs will have 2**N states, thus there's a maximum of 16 inputs for
now as 65536 states is a lot of configuration.
Using a switcher, setting up a standard strafe/mouse look configuration
is fairly easy.
imt_create key_game imt_mod
imt_create key_game imt_mod_strafe imt_mod
imt_create key_game imt_mod_freelook
imt_create key_game imt_mod_lookstrafe imt_mod_freelook
imt_switcher_create mouse key_game imt_mod_strafe +strafe lookstrafe +mlook freelook
imt_switcher 0 imt_mod 2 imt_mod 4 imt_mod_freelook 8 imt_mod_freelook 12 imt_mod_freelook
imt_switcher 6 imt_mod_lookstrafe 10 imt_mod_lookstrafe 14 imt_mod_lookstrafe
in_bind imt_mod mouse axis 0 move.yaw
in_bind imt_mod mouse axis 1 move.forward
in_bind imt_mod_strafe mouse axis 0 move.side
in_bind imt_mod_lookstrafe mouse axis 0 move.side
in_bind imt_mod_freelook mouse axis 1 move.pitch
This takes advantage of imt chaining and the default imt for the
switcher (there are 8 states that use imt_mod_strafe).
The switcher name must be unique across all contexts, and every imt used
in a switcher must be in the switcher's context.
2021-11-25 09:01:07 +00:00
|
|
|
if (context->switchers) {
|
|
|
|
plitem_t *switcher_list = PL_NewArray ();
|
|
|
|
PL_D_AddObject (ctx, "switchers", switcher_list);
|
|
|
|
for (imt_switcher_t *switcher = context->switchers; switcher;
|
|
|
|
switcher = switcher->next) {
|
|
|
|
plitem_t *switcher_cfg = PL_NewDictionary (0);
|
|
|
|
PL_A_AddObject (switcher_list, switcher_cfg);
|
|
|
|
|
|
|
|
PL_D_AddObject (switcher_cfg, "name",
|
|
|
|
PL_NewString (switcher->name));
|
|
|
|
|
|
|
|
plitem_t *input_list = PL_NewArray ();
|
|
|
|
PL_D_AddObject (switcher_cfg, "inputs", input_list);
|
|
|
|
for (int i = 0; i < switcher->num_inputs; i++) {
|
|
|
|
imt_input_t *input = &switcher->inputs[i];
|
|
|
|
const char *name = 0;
|
|
|
|
switch (input->type) {
|
|
|
|
case imti_button:
|
|
|
|
name = va (0, "+%s", input->button->name);
|
|
|
|
break;
|
|
|
|
case imti_cvar:
|
|
|
|
name = input->cvar->name;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
PL_A_AddObject (input_list, PL_NewString (name));
|
|
|
|
}
|
|
|
|
|
|
|
|
plitem_t *state_list = PL_NewArray ();
|
|
|
|
PL_D_AddObject (switcher_cfg, "imts", state_list);
|
|
|
|
int num_states = 1 << switcher->num_inputs;
|
|
|
|
for (int i = 0; i < num_states; i++) {
|
|
|
|
imt_t *imt = switcher->imts[i];
|
|
|
|
PL_A_AddObject (state_list, PL_NewString (imt->name));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-11-14 01:17:05 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
IMT_SaveAxisConfig (plitem_t *axes, int axis_ind, int dev_axis)
|
|
|
|
{
|
|
|
|
for (size_t i = 0; i < in_contexts.size; i++) {
|
|
|
|
in_context_t *context = &in_contexts.a[i];
|
|
|
|
for (imt_t *imt = context->imts; imt; imt = imt->next) {
|
|
|
|
in_axisbinding_t *a = imt->axis_bindings.a[axis_ind];
|
|
|
|
if (a) {
|
|
|
|
in_recipe_t *recipe = a->recipe;
|
2022-05-12 08:54:23 +00:00
|
|
|
plitem_t *axis = PL_NewDictionary (0);
|
2021-11-14 01:17:05 +00:00
|
|
|
PL_A_AddObject (axes, axis);
|
|
|
|
|
|
|
|
PL_D_AddObject (axis, "imt", PL_NewString (imt->name));
|
|
|
|
PL_D_AddObject (axis, "num",
|
|
|
|
PL_NewString (va (0, "%d", dev_axis)));
|
|
|
|
PL_D_AddObject (axis, "axis", PL_NewString (a->axis->name));
|
|
|
|
PL_D_AddObject (axis, "min",
|
|
|
|
PL_NewString (va (0, "%d", recipe->min)));
|
|
|
|
PL_D_AddObject (axis, "max",
|
|
|
|
PL_NewString (va (0, "%d", recipe->max)));
|
|
|
|
PL_D_AddObject (axis, "minzone",
|
|
|
|
PL_NewString (va (0, "%d", recipe->minzone)));
|
|
|
|
PL_D_AddObject (axis, "maxzone",
|
|
|
|
PL_NewString (va (0, "%d", recipe->maxzone)));
|
|
|
|
PL_D_AddObject (axis, "deadzone",
|
|
|
|
PL_NewString (va (0, "%d", recipe->deadzone)));
|
|
|
|
PL_D_AddObject (axis, "curve",
|
|
|
|
PL_NewString (va (0, "%.9g", recipe->curve)));
|
|
|
|
PL_D_AddObject (axis, "scale",
|
|
|
|
PL_NewString (va (0, "%.9g", recipe->scale)));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
IMT_SaveButtonConfig (plitem_t *buttons, int button_ind, int dev_button)
|
|
|
|
{
|
|
|
|
for (size_t i = 0; i < in_contexts.size; i++) {
|
|
|
|
in_context_t *context = &in_contexts.a[i];
|
|
|
|
for (imt_t *imt = context->imts; imt; imt = imt->next) {
|
|
|
|
in_buttonbinding_t *b = imt->button_bindings.a[button_ind];
|
|
|
|
if (b) {
|
2022-05-12 08:54:23 +00:00
|
|
|
plitem_t *button = PL_NewDictionary (0);
|
2021-11-14 01:17:05 +00:00
|
|
|
PL_A_AddObject (buttons, button);
|
|
|
|
|
|
|
|
PL_D_AddObject (button, "imt", PL_NewString (imt->name));
|
|
|
|
PL_D_AddObject (button, "num",
|
|
|
|
PL_NewString (va (0, "%d", dev_button)));
|
|
|
|
switch (b->type) {
|
|
|
|
case inb_button:
|
|
|
|
PL_D_AddObject (button, "binding",
|
|
|
|
PL_NewString (va (0, "+%s",
|
|
|
|
b->button->name)));
|
|
|
|
break;
|
|
|
|
case inb_command:
|
|
|
|
PL_D_AddObject (button, "binding",
|
|
|
|
PL_NewString (b->command));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
IMT_LoadConfig (plitem_t *config)
|
|
|
|
{
|
|
|
|
imt_drop_all_f ();
|
2022-05-12 10:01:45 +00:00
|
|
|
imt_reset_blocks ();
|
2021-11-14 01:17:05 +00:00
|
|
|
|
|
|
|
plitem_t *ctx_list = PL_ObjectForKey (config, "contexts");
|
|
|
|
if (PL_Type (ctx_list) != QFArray) {
|
|
|
|
Sys_Printf ("IMT_LoadConfig: contexts not an array\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
for (int i = 0, count = PL_A_NumObjects (ctx_list); i < count; i++) {
|
|
|
|
plitem_t *ctx = PL_ObjectAtIndex (ctx_list, i);
|
|
|
|
const char *name = PL_String (PL_ObjectForKey (ctx, "name"));
|
|
|
|
in_context_t *context = imt_find_context (name);
|
|
|
|
if (!context) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
plitem_t *imts = PL_ObjectForKey (ctx, "imts");
|
|
|
|
if (!imts || PL_Type (imts) != QFArray) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
for (int j = 0, num_imts = PL_A_NumObjects (imts); j < num_imts; j++) {
|
|
|
|
plitem_t *imt = PL_ObjectAtIndex (imts, j);
|
|
|
|
const char *imt_name = PL_String (PL_ObjectForKey (imt, "name"));
|
|
|
|
const char *imt_chain = PL_String (PL_ObjectForKey (imt, "chain"));
|
|
|
|
if (imt_name) {
|
|
|
|
IMT_CreateIMT (context - in_contexts.a, imt_name, imt_chain);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
const char *default_imt = PL_String (PL_ObjectForKey (ctx,
|
|
|
|
"default_imt"));
|
|
|
|
if (default_imt) {
|
|
|
|
context->default_imt = IMT_FindIMT (default_imt);
|
|
|
|
}
|
|
|
|
if (!context->default_imt) {
|
|
|
|
context->default_imt = context->imts;
|
|
|
|
}
|
|
|
|
context->active_imt = context->default_imt;
|
[input] Create an automatic imt switcher
An imt switcher automatically changes the context's active imt based on
a user specified list of binary inputs. The inputs may be either buttons
(indicated as +button) or cvars (bare name). For buttons, the
pressed/not pressed state is used, and cvars are interpreted as ints
being 0 or not 0. The order of the inputs determines the bit number of
the input, with the first input being bit 0, second bit 1, third bit 2
etc. A default imt is given so large switchers do not need to be fully
configured (the default imt is written to all states).
A context can have any number of switchers attached. The switchers can
wind up fighting over the active imt, but this seems to be something for
the "user" (eg, configuration system) to sort out rather than the
switcher code enforcing anything.
As a result of the inputs being treated as bits, a switcher with N
inputs will have 2**N states, thus there's a maximum of 16 inputs for
now as 65536 states is a lot of configuration.
Using a switcher, setting up a standard strafe/mouse look configuration
is fairly easy.
imt_create key_game imt_mod
imt_create key_game imt_mod_strafe imt_mod
imt_create key_game imt_mod_freelook
imt_create key_game imt_mod_lookstrafe imt_mod_freelook
imt_switcher_create mouse key_game imt_mod_strafe +strafe lookstrafe +mlook freelook
imt_switcher 0 imt_mod 2 imt_mod 4 imt_mod_freelook 8 imt_mod_freelook 12 imt_mod_freelook
imt_switcher 6 imt_mod_lookstrafe 10 imt_mod_lookstrafe 14 imt_mod_lookstrafe
in_bind imt_mod mouse axis 0 move.yaw
in_bind imt_mod mouse axis 1 move.forward
in_bind imt_mod_strafe mouse axis 0 move.side
in_bind imt_mod_lookstrafe mouse axis 0 move.side
in_bind imt_mod_freelook mouse axis 1 move.pitch
This takes advantage of imt chaining and the default imt for the
switcher (there are 8 states that use imt_mod_strafe).
The switcher name must be unique across all contexts, and every imt used
in a switcher must be in the switcher's context.
2021-11-25 09:01:07 +00:00
|
|
|
|
|
|
|
plitem_t *switcher_list = PL_ObjectForKey (ctx, "switchers");
|
|
|
|
if (!switcher_list || PL_Type (switcher_list) != QFArray) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
for (int j = 0, num_switchers = PL_A_NumObjects (switcher_list);
|
|
|
|
j < num_switchers; j++) {
|
|
|
|
plitem_t *switcher = PL_ObjectAtIndex (switcher_list, j);
|
|
|
|
const char *name = PL_String (PL_ObjectForKey (switcher, "name"));
|
|
|
|
plitem_t *input_list = PL_ObjectForKey (switcher, "inputs");
|
|
|
|
if (!name || !input_list || PL_Type (input_list) != QFArray) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
int num_inputs = PL_A_NumObjects (input_list);
|
|
|
|
const char **input_names = alloca (num_inputs * sizeof (char *));
|
|
|
|
for (int k = 0; k < num_inputs; k++) {
|
|
|
|
input_names[k] = PL_String (PL_ObjectAtIndex (input_list, k));
|
|
|
|
}
|
|
|
|
if (!IMT_CreateSwitcher (name, context - in_contexts.a,
|
|
|
|
context->default_imt,
|
|
|
|
num_inputs, input_names)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
imt_switcher_t *s = imt_find_switcher (context, name);
|
|
|
|
|
|
|
|
plitem_t *imt_list = PL_ObjectForKey (switcher, "imts");
|
|
|
|
if (!imt_list || PL_Type (imt_list) != QFArray) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
for (int k = 0, count = PL_A_NumObjects (imt_list); k < count;
|
|
|
|
k++) {
|
|
|
|
const char *imt_name = PL_String(PL_ObjectAtIndex(imt_list, k));
|
|
|
|
if (!imt_name) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
imt_t *imt = imt_find_imt (context, imt_name);
|
|
|
|
if (imt) {
|
|
|
|
s->imts[k] = imt;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-11-14 01:17:05 +00:00
|
|
|
}
|
|
|
|
}
|