[input] Make a start on the new binding system

Input Mapping Tables are still at the core as they are a good concept,
however they include both axis and button mappings, and the size is not
hard-coded, but dependent on the known devices. Not much actually works
yet (nq segfaults when a key is pressed).
This commit is contained in:
Bill Currie 2021-11-03 19:02:39 +09:00
parent 14a5ec7b41
commit 825d8b7a49
14 changed files with 629 additions and 81 deletions

View file

@ -114,6 +114,8 @@ include_qf_glsl = \
include_qf_input = \ include_qf_input = \
include/QF/binding.h \ include/QF/binding.h \
include/QF/event.h include/QF/event.h
include/QF/imt.h
include_qf_math = \ include_qf_math = \
include/QF/math/dual.h \ include/QF/math/dual.h \
include/QF/math/half.h \ include/QF/math/half.h \

View file

@ -45,6 +45,7 @@ typedef struct in_buttoninfo_s {
} in_buttoninfo_t; } in_buttoninfo_t;
#include "QF/input/binding.h" #include "QF/input/binding.h"
#include "QF/input/imt.h"
#ifndef __QFCC__ #ifndef __QFCC__
@ -104,15 +105,17 @@ typedef struct in_device_s {
\a button_info holds the current raw state of the button \a button_info holds the current raw state of the button
\a axis_imt_id is 0 if the device has no axis bindings, otherwise it is \a axis_imt_id is 0 if the device has no axis bindings, otherwise it is
the based index into the imt array for the imt group. the index into the imt array for the imt group.
\a button_imt_i is 0 if the device has no button bindings, otherwise it \a button_imt_id is 0 if the device has no button bindings, otherwise it
is the index into the imt array for the imt group. is the index into the imt array for the imt group.
*/ */
typedef struct in_devbindings_s { typedef struct in_devbindings_s {
const char *name; ///< name used when binding inputs const char *name; ///< name used when binding inputs
const char *id; ///< physical device name or id (preferred) const char *id; ///< physical device name or id (preferred)
in_device_t *device; ///< device associated with these bindings int devid; ///< id of device associated with these bindings
int num_axes;
int num_buttons;
in_axisinfo_t *axis_info; ///< axis range info and raw state in_axisinfo_t *axis_info; ///< axis range info and raw state
in_buttoninfo_t *button_info; ///< button raw state in_buttoninfo_t *button_info; ///< button raw state
int axis_imt_id; ///< index into array of imt axis bindings int axis_imt_id; ///< index into array of imt axis bindings

View file

@ -217,6 +217,8 @@ int IN_RegisterAxis (in_axis_t *axis, const char *name,
const char *description); const char *description);
in_button_t *IN_FindButton (const char *name); in_button_t *IN_FindButton (const char *name);
void IN_Binding_Init (void);
#endif #endif
#endif//__QF_input_binding_h #endif//__QF_input_binding_h

87
include/QF/input/imt.h Normal file
View file

@ -0,0 +1,87 @@
/*
imt.h
Input Mapping Table management
Copyright (C) 2001 Zephaniah E. Hull <warp@babylon.d2dc.net>
Copyright (C) 2021 Bill Currie <bill@taniwha.org>
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
*/
#ifndef __QF_input_imt_h
#define __QF_input_imt_h
#ifndef __QFCC__
#include "QF/darray.h"
#include "QF/input/binding.h"
typedef enum {
imt_button,
imt_axis,
} imt_type;
/** 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). The device name is
used instead of a pointer to the device descriptor so configs can be
preserved even if the device is not present.
Bindings are allocated to a device in contiguous blocks.
*/
typedef struct imt_block_s {
const char *device; ///< name of the owning device
int base; ///< index of first binding
int count; ///< number of bindings
} imt_block_t;
/** Input Mapping Table
*/
typedef struct imt_s {
struct imt_s *next; ///< list of tables attached to key_dest
struct imt_s *chain; ///< fallback table if input not bound
const char *name; ///< for user interaction
int written;
struct DARRAY_TYPE (in_axisbinding_t *) axis_bindings;
struct DARRAY_TYPE (in_buttonbinding_t *) button_bindings;
} imt_t;
typedef struct in_context_s {
imt_t *imts;
imt_t **imt_tail;
imt_t *active_imt;
imt_t *default_imt;
} in_context_t;
int IMT_GetAxisBlock (const char *device, int num_axes);
int IMT_GetButtonBlock (const char *device, int num_buttons);
int IMT_CreateContext (void);
imt_t *IMT_FindIMT (const char *name);
int IMT_CreateIMT (int context, const char *imt_name,
const char *chain_imt_name);
void IMT_ProcessAxis (int axis, int value);
void IMT_ProcessButton (int button, int state);
#endif
#endif//__QF_input_imt_h

View file

@ -534,26 +534,12 @@ typedef enum {
#ifndef __QFCC__ #ifndef __QFCC__
extern knum_t key_toggleconsole; extern knum_t key_toggleconsole;
typedef struct keybind_s {
char *str;
} keybind_t;
/** Input Mapping Table
*/
typedef struct imt_s {
struct imt_s *next; ///< list of tables attached to key_dest
struct imt_s *chain; ///< fallback table if key not bound
const char *name; ///< for user interaction
keybind_t bindings[QFK_LAST];
int written; ///< avoid duplicate config file writes
} imt_t;
/** Chain of input mapping tables ascociated with a keydest sub-system (game, /** Chain of input mapping tables ascociated with a keydest sub-system (game,
menu, etc). menu, etc).
*/ */
typedef struct keytarget_s { typedef struct keytarget_s {
imt_t *imts; ///< list of tables attached to this target struct imt_s *imts; ///< list of tables attached to this target
imt_t *active; ///< currently active table in this target struct imt_s *active; ///< currently active table in this target
} keytarget_t; } keytarget_t;
extern int keydown[QFK_LAST]; extern int keydown[QFK_LAST];
@ -612,7 +598,7 @@ void Key_Init_Cvars (void);
\param imt_name The name of the imt to find. Case insensitive. \param imt_name The name of the imt to find. Case insensitive.
\return The named imt, or null if not found. \return The named imt, or null if not found.
*/ */
imt_t *Key_FindIMT (const char *imt_name) __attribute__((pure)); struct imt_s *Key_FindIMT (const char *imt_name) __attribute__((pure));
/** Create a new imt and attach it to the specified keydest target. /** Create a new imt and attach it to the specified keydest target.
@ -667,7 +653,7 @@ void Key_ClearStates (void);
\param key The key for which to get the binding. \param key The key for which to get the binding.
\return The command string bound to the key, or null if unbound. \return The command string bound to the key, or null if unbound.
*/ */
const char *Key_GetBinding (imt_t *imt, knum_t key) __attribute__((pure)); const char *Key_GetBinding (struct imt_s *imt, knum_t key) __attribute__((pure));
/** Bind a command string to a key in the specified input mapping table. /** Bind a command string to a key in the specified input mapping table.
@ -678,7 +664,7 @@ const char *Key_GetBinding (imt_t *imt, knum_t key) __attribute__((pure));
\param keynum The key to which the command string will be bound. \param keynum The key to which the command string will be bound.
\param binding The command string that will be bound. \param binding The command string that will be bound.
*/ */
void Key_SetBinding (imt_t *imt, knum_t keynum, const char *binding); void Key_SetBinding (struct imt_s *imt, knum_t keynum, const char *binding);
/** Set the current keydest target. /** Set the current keydest target.

View file

@ -37,7 +37,7 @@
#include "QF/cbuf.h" #include "QF/cbuf.h"
#include "QF/cmd.h" #include "QF/cmd.h"
#include "QF/keys.h" #include "QF/input.h"
#include "QF/sys.h" #include "QF/sys.h"
#include "QF/gib.h" #include "QF/gib.h"

View file

@ -21,9 +21,11 @@ libs_input_libQFinput_la_SOURCES= \
libs/input/keys.c \ libs/input/keys.c \
libs/input/old_keys.c \ libs/input/old_keys.c \
libs/input/in_axis.c \ libs/input/in_axis.c \
libs/input/in_binding.c \
libs/input/in_button.c \ libs/input/in_button.c \
libs/input/in_common.c \ libs/input/in_common.c \
libs/input/in_event.c libs/input/in_event.c \
libs/input/in_imt.c
EXTRA_LTLIBRARIES += \ EXTRA_LTLIBRARIES += \
libs/input/libinput_evdev.la libs/input/libinput_evdev.la

154
libs/input/in_binding.c Normal file
View file

@ -0,0 +1,154 @@
/*
in_binding.c
Input binding management
Copyright (C) 2021 Bill Currie <bill@taniwha.org>
Author: Bill Currie <bill@taniwha.org>
Date: 2021/11/2
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"
#include "QF/hash.h"
#include "QF/input.h"
#include "QF/sys.h"
#include "QF/input/imt.h"
#include "QF/input/binding.h"
#include "QF/input/event.h"
#include "QF/input/imt.h"
typedef struct DARRAY_TYPE (in_devbindings_t) in_devbindingset_t;
static in_devbindingset_t devbindings = DARRAY_STATIC_INIT (8);
static void
in_binding_add_device (const IE_event_t *ie_event)
{
size_t devid = ie_event->device.devid;
if (devid >= devbindings.size) {
DARRAY_RESIZE (&devbindings, devid + 1);
memset (&devbindings.a[devid], 0, sizeof (in_devbindings_t));
}
in_devbindings_t *db = &devbindings.a[devid];
if (db->id) {
if (db->id != IN_GetDeviceId (devid)) {
Sys_Error ("in_binding_add_device: devid conflict: %zd", devid);
}
Sys_Printf ("in_binding_add_device: readd %s\n", db->id);
return;
}
db->id = IN_GetDeviceId (devid);
db->devid = devid;
IN_AxisInfo (devid, 0, &db->num_axes);
IN_ButtonInfo (devid, 0, &db->num_buttons);
db->axis_info = malloc (db->num_axes * sizeof (in_axisinfo_t)
+ db->num_buttons * sizeof (in_buttoninfo_t));
db->button_info = (in_buttoninfo_t *) &db->axis_info[db->num_axes];
IN_AxisInfo (devid, db->axis_info, &db->num_axes);
IN_ButtonInfo (devid, db->button_info, &db->num_buttons);
Sys_Printf ("in_binding_add_device: %s %d %d\n", db->id, db->num_axes,
db->num_buttons);
}
static void
in_binding_remove_device (const IE_event_t *ie_event)
{
size_t devid = ie_event->device.devid;
in_devbindings_t *db = &devbindings.a[devid];
if (devid >= devbindings.size) {
Sys_Error ("in_binding_remove_device: invalid devid: %zd", devid);
}
if (!db->id) {
return;
}
free (db->axis_info); // axis and button info in same block
memset (db, 0, sizeof (*db));
}
static void
in_binding_axis (const IE_event_t *ie_event)
{
size_t devid = ie_event->axis.devid;
int axis = ie_event->axis.axis;
int value = ie_event->axis.value;
in_devbindings_t *db = &devbindings.a[devid];
if (devid < devbindings.size && axis < db->num_axes) {
db->axis_info[axis].value = value;
if (db->axis_imt_id) {
IMT_ProcessAxis (db->axis_imt_id + axis, value);
}
}
}
static void
in_binding_button (const IE_event_t *ie_event)
{
size_t devid = ie_event->button.devid;
int button = ie_event->button.button;
int state = ie_event->button.state;
in_devbindings_t *db = &devbindings.a[devid];
if (devid < devbindings.size && button < db->num_buttons) {
db->button_info[button].state = state;
if (db->button_imt_id) {
IMT_ProcessButton (db->button_imt_id + button, state);
}
}
}
static int
in_binding_event_handler (const IE_event_t *ie_event, void *unused)
{
static void (*handlers[]) (const IE_event_t *ie_event) = {
[ie_add_device] = in_binding_add_device,
[ie_remove_device] = in_binding_remove_device,
[ie_axis] = in_binding_axis,
[ie_button] = in_binding_button,
};
if (ie_event->type < 0 || ie_event->type > ie_button
|| !handlers[ie_event->type]) {
return 0;
}
handlers[ie_event->type] (ie_event);
return 1;
}
void
IN_Binding_Init (void)
{
IE_Add_Handler (in_binding_event_handler, 0);
}

View file

@ -102,7 +102,7 @@ IN_DriverData (int handle, void *data)
} }
static int static int
in_add_device (int driver, in_device_t *device, const char *name, in_add_device (int driver, void *device, const char *name,
const char *id) const char *id)
{ {
size_t devid; size_t devid;
@ -353,7 +353,8 @@ IN_Init (cbuf_t *cbuf)
in_regdriver_t *rd = &in_drivers.a[i]; in_regdriver_t *rd = &in_drivers.a[i];
rd->driver.init (rd->data); rd->driver.init (rd->data);
} }
Key_Init (cbuf); IN_Binding_Init ();
//Key_Init (cbuf);
//JOY_Init (); //JOY_Init ();
in_mouse_x = in_mouse_y = 0.0; in_mouse_x = in_mouse_y = 0.0;
@ -362,7 +363,7 @@ IN_Init (cbuf_t *cbuf)
void void
IN_Init_Cvars (void) IN_Init_Cvars (void)
{ {
Key_Init_Cvars (); //Key_Init_Cvars ();
//JOY_Init_Cvars (); //JOY_Init_Cvars ();
in_grab = Cvar_Get ("in_grab", "0", CVAR_ARCHIVE, IN_UpdateGrab, in_grab = Cvar_Get ("in_grab", "0", CVAR_ARCHIVE, IN_UpdateGrab,
"With this set to 1, quake will grab the mouse, " "With this set to 1, quake will grab the mouse, "
@ -392,7 +393,7 @@ IN_ClearStates (void)
rd->driver.clear_states (rd->data); rd->driver.clear_states (rd->data);
} }
} }
Key_ClearStates (); //Key_ClearStates ();
} }
#ifdef HAVE_EVDEV #ifdef HAVE_EVDEV

View file

@ -58,11 +58,6 @@ static int evdev_driver_handle = -1;
static PR_RESMAP (devmap_t) devmap; static PR_RESMAP (devmap_t) devmap;
static devmap_t *devmap_list; static devmap_t *devmap_list;
static void
in_evdev_keydest_callback (keydest_t key_dest, void *data)
{
}
static void static void
in_evdev_add_select (qf_fd_set *fdset, int *maxfd, void *data) in_evdev_add_select (qf_fd_set *fdset, int *maxfd, void *data)
{ {
@ -179,8 +174,6 @@ device_remove (device_t *dev)
static void static void
in_evdev_init (void *data) in_evdev_init (void *data)
{ {
Key_KeydestCallback (in_evdev_keydest_callback, 0);
inputlib_init (device_add, device_remove); inputlib_init (device_add, device_remove);
} }

238
libs/input/in_imt.c Normal file
View file

@ -0,0 +1,238 @@
/*
in_imt.c
Input Mapping Table management
Copyright (C) 1996-1997 Id Software, Inc.
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"
#include "QF/hash.h"
#include "QF/sys.h"
#include "QF/input/imt.h"
#include "QF/input/binding.h"
#include "QF/input/imt.h"
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);
static imt_block_t * __attribute__((pure))
imt_find_block (imt_blockset_t *blockset, const char *device)
{
for (size_t i = 0; i < blockset->size; i++) {
if (strcmp (blockset->a[i].device, device) == 0) {
return &blockset->a[i];
}
}
return 0;
}
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;
}
int
IMT_GetAxisBlock (const char *device, int num_axes)
{
imt_block_t *block;
if (!(block = imt_find_block (&axis_blocks, device))) {
block = imt_get_block (&axis_blocks);
block->device = device;
block->base = imt_get_axis_block (num_axes);
block->count = num_axes;
}
return block - axis_blocks.a;
}
int
IMT_GetButtonBlock (const char *device, int num_buttons)
{
imt_block_t *block;
if (!(block = imt_find_block (&button_blocks, device))) {
block = imt_get_block (&button_blocks);
block->device = device;
block->base = imt_get_button_block (num_buttons);
block->count = num_buttons;
}
return block - button_blocks.a;
}
int
IMT_CreateContext (void)
{
in_context_t *ctx = DARRAY_OPEN_AT (&in_contexts, in_contexts.size, 1);
memset (ctx, 0, sizeof (*ctx));
ctx->imt_tail = &ctx->imts;
return ctx - in_contexts.a;
}
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;
}
imt_t * __attribute__ ((pure))
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;
}
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));
*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) {
memset (imt->axis_bindings.a, 0,
num_buttons * sizeof (in_buttonbinding_t *));
}
return 1;
}
void
IMT_ProcessAxis (int axis, int value)
{
}
void
IMT_ProcessButton (int button, int state)
{
}

View file

@ -41,15 +41,44 @@
#include "QF/cbuf.h" #include "QF/cbuf.h"
#include "QF/cmd.h" #include "QF/cmd.h"
#include "QF/cmem.h"
#include "QF/cvar.h" #include "QF/cvar.h"
#include "QF/darray.h" #include "QF/darray.h"
#include "QF/dstring.h" #include "QF/dstring.h"
#include "QF/keys.h" #include "QF/keys.h"
#include "QF/input.h"
#include "QF/sys.h" #include "QF/sys.h"
#include "QF/va.h"
#include "compat.h" #include "compat.h"
#include "old_keys.h" #include "old_keys.h"
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)
{
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)
{
cmemfree (binding_mem, binding);
}
/* key up events are sent even if in console mode */ /* key up events are sent even if in console mode */
static keydest_t key_dest = key_console; static keydest_t key_dest = key_console;
@ -90,12 +119,6 @@ static const char *keydest_names[] = {
"key_last" "key_last"
}; };
typedef struct {
const char *name;
imt_t imtnum;
} imtname_t;
typedef struct { typedef struct {
const char *name; const char *name;
knum_t keynum; knum_t keynum;
@ -615,12 +638,25 @@ Key_SetBinding (imt_t *imt, knum_t keynum, const char *binding)
if (keynum == (knum_t) -1) if (keynum == (knum_t) -1)
return; return;
if (imt->bindings[keynum].str) { if (imt->button_bindings.a[keynum]) {
free (imt->bindings[keynum].str); if (imt->button_bindings.a[keynum]->type == inb_command) {
imt->bindings[keynum].str = NULL; free (imt->button_bindings.a[keynum]->command);
}
free_button_binding (imt->button_bindings.a[keynum]);
imt->button_bindings.a[keynum] = 0;
} }
if (binding) { if (binding) {
imt->bindings[keynum].str = strdup(binding); in_buttonbinding_t *b = alloc_button_binding ();
imt->button_bindings.a[keynum] = b;
in_button_t *button;
if (binding[0] == '+' && (button = IN_FindButton (binding + 1))) {
b->type = inb_button;
b->bind_id = keynum; //FIXME alloc?
b->button = button;
} else {
b->type = inb_command;
b->command = strdup(binding);
}
} }
} }
@ -659,14 +695,23 @@ process_binding (knum_t key, const char *kb)
static qboolean static qboolean
Key_Game (knum_t key, short unicode) Key_Game (knum_t key, short unicode)
{ {
const char *kb;
imt_t *imt = key_targets[key_dest].active; imt_t *imt = key_targets[key_dest].active;
while (imt) { while (imt) {
kb = imt->bindings[key].str; in_buttonbinding_t *b = imt->button_bindings.a[key];
if (kb) { if (b) {
if (keydown[key] <= 1) switch (b->type) {
process_binding (key, kb); case inb_button:
if (keydown[key] <= 1) {
IN_ButtonAction (b->button, key, keydown[key]);
}
break;
case inb_command:
if (keydown[key] <= 1) {
process_binding (key, b->command);
}
break;
}
return true; return true;
} }
imt = imt->chain; imt = imt->chain;
@ -830,9 +875,20 @@ Key_IMT_Drop_All_f (void)
while (key_targets[kd].imts) { while (key_targets[kd].imts) {
imt = key_targets[kd].imts; imt = key_targets[kd].imts;
key_targets[kd].imts = imt->next; key_targets[kd].imts = imt->next;
for (int i = 0; i < QFK_LAST; i++) { for (size_t i = 0; i < imt->axis_bindings.size; i++) {
if (imt->bindings[i].str) { free_axis_binding (imt->axis_bindings.a[i]);
free (imt->bindings[i].str); }
for (size_t i = 0; i < imt->button_bindings.size; i++) {
in_buttonbinding_t *b = imt->button_bindings.a[i];
if (b) {
switch (b->type) {
case inb_button:
break;
case inb_command:
free (b->command);
break;
}
free_button_binding (b);
} }
} }
free ((char *) imt->name); free ((char *) imt->name);
@ -843,7 +899,7 @@ Key_IMT_Drop_All_f (void)
} }
static void static void
Key_In_Bind (const char *imt_name, const char *key_name, const char *cmd) Key_In_BindButton (const char *imt_name, const char *key_name, const char *cmd)
{ {
imt_t *imt; imt_t *imt;
int key; int key;
@ -861,11 +917,21 @@ Key_In_Bind (const char *imt_name, const char *key_name, const char *cmd)
} }
if (!cmd) { if (!cmd) {
if (imt->bindings[key].str) in_buttonbinding_t *b = imt->button_bindings.a[key];
Sys_Printf ("%s %s \"%s\"\n", imt_name, key_name, if (b) {
imt->bindings[key].str); switch (b->type) {
else case inb_button:
Sys_Printf ("%s %s \"+%s\"\n", imt_name, key_name,
b->button->name);
break;
case inb_command:
Sys_Printf ("%s %s \"%s\"\n", imt_name, key_name,
b->command);
break;
}
} else {
Sys_Printf ("%s %s is not bound\n", imt_name, key_name); Sys_Printf ("%s %s is not bound\n", imt_name, key_name);
}
return; return;
} }
Key_SetBinding (imt, key, cmd); Key_SetBinding (imt, key, cmd);
@ -880,25 +946,25 @@ Key_In_Bind_f (void)
c = Cmd_Argc (); c = Cmd_Argc ();
if (c < 3) { if (c < 4 || strcmp (Cmd_Argv (2), "button") != 0) {
Sys_Printf ("in_bind <imt> <key> [command] : attach a command to a " Sys_Printf ("in_bind <imt> button <key> [command]\n"
"key\n"); " attach a command to a key\n");
return; return;
} }
imt = Cmd_Argv (1); imt = Cmd_Argv (1);
key = Cmd_Argv (2); key = Cmd_Argv (3);
if (c >= 4) { if (c >= 5) {
cmd_buf = dstring_newstr (); cmd_buf = dstring_newstr ();
for (i = 3; i < c; i++) { for (i = 4; i < c; i++) {
dasprintf (cmd_buf, "%s%s", i > 3 ? " " : "", Cmd_Argv (i)); dasprintf (cmd_buf, "%s%s", i > 3 ? " " : "", Cmd_Argv (i));
} }
cmd = cmd_buf->str; cmd = cmd_buf->str;
} }
Key_In_Bind (imt, key, cmd); Key_In_BindButton (imt, key, cmd);
if (cmd_buf) { if (cmd_buf) {
dstring_delete (cmd_buf); dstring_delete (cmd_buf);
} }
@ -941,7 +1007,7 @@ Key_Bind_f (void)
cmd = cmd_buf->str; cmd = cmd_buf->str;
} }
Key_In_Bind ("imt_mod", key, cmd); Key_In_BindButton ("imt_mod", key, cmd);
if (cmd_buf) { if (cmd_buf) {
dstring_delete (cmd_buf); dstring_delete (cmd_buf);
} }
@ -1054,9 +1120,6 @@ key_printf (QFile *f, const char *fmt, ...)
static void static void
key_write_imt (QFile *f, keydest_t kd, imt_t *imt) key_write_imt (QFile *f, keydest_t kd, imt_t *imt)
{ {
int i;
const char *bind;
if (!imt || imt->written) { if (!imt || imt->written) {
return; return;
} }
@ -1068,11 +1131,19 @@ key_write_imt (QFile *f, keydest_t kd, imt_t *imt)
} else { } else {
key_printf (f, "imt_create %s %s\n", keydest_names[kd], imt->name); key_printf (f, "imt_create %s %s\n", keydest_names[kd], imt->name);
} }
for (i = 0; i < QFK_LAST; i++) { for (size_t i = 0; i < imt->button_bindings.size; i++) {
bind = imt->bindings[i].str; in_buttonbinding_t *b = imt->button_bindings.a[i];
if (bind) { if (b) {
key_printf (f, "in_bind %s %s \"%s\"\n", imt->name, switch (b->type) {
Key_KeynumToString (i), bind); case inb_button:
key_printf (f, "in_bind %s button %s \"+%s\"\n", imt->name,
Key_KeynumToString (i), b->button->name);
break;
case inb_command:
key_printf (f, "in_bind %s button %s \"%s\"\n", imt->name,
Key_KeynumToString (i), b->command);
break;
}
} }
} }
} }
@ -1161,7 +1232,7 @@ Key_Event (knum_t key, short unicode, qboolean down)
//FIXME maybe still a tad over-coupled. Use callbacks for menu and console //FIXME maybe still a tad over-coupled. Use callbacks for menu and console
//toggles? Should keys know anything about menu and console? //toggles? Should keys know anything about menu and console?
if (key_dest != key_console && key == key_toggleconsole if (key_dest != key_console && key == key_toggleconsole
&& keydown[key] == 1) { && keydown[key] == 1) {
Cbuf_AddText (cbuf, "toggleconsole"); Cbuf_AddText (cbuf, "toggleconsole");
return; return;
} }
@ -1258,8 +1329,8 @@ Key_CreateDefaultIMTs (void)
default_imts[i].chain_imt_name); default_imts[i].chain_imt_name);
} }
for (i = 0; default_bindings[i].imt; i++) { for (i = 0; default_bindings[i].imt; i++) {
Key_In_Bind (default_bindings[i].imt, default_bindings[i].key, Key_In_BindButton (default_bindings[i].imt, default_bindings[i].key,
default_bindings[i].command); default_bindings[i].command);
} }
} }
@ -1320,7 +1391,15 @@ const char *
Key_GetBinding (imt_t *imt, knum_t key) Key_GetBinding (imt_t *imt, knum_t key)
{ {
if (imt) { if (imt) {
return imt->bindings[key].str; in_buttonbinding_t *b = imt->button_bindings.a[key];
if (b) {
switch (b->type) {
case inb_button:
return va (0, "+%s", b->button->name);
case inb_command:
return b->command;
}
}
} }
return 0; return 0;
} }

View file

@ -36,7 +36,7 @@
#endif #endif
#include "QF/csqc.h" #include "QF/csqc.h"
#include "QF/keys.h" #include "QF/input.h"
#include "QF/progs.h" #include "QF/progs.h"
#include "QF/zone.h" #include "QF/zone.h"
@ -89,7 +89,7 @@ bi_Key_LookupBinding (progs_t *pr)
imt = Key_FindIMT (imt_name); imt = Key_FindIMT (imt_name);
if (imt) { if (imt) {
for (i = 0; i < QFK_LAST; i++) { for (i = 0; i < QFK_LAST; i++) {
keybind = imt->bindings[i].str; //XXX keybind = imt->button_bindings.a[i].str;
if (keybind == NULL) { if (keybind == NULL) {
continue; continue;
} }
@ -123,7 +123,7 @@ bi_Key_CountBinding (progs_t *pr)
imt = Key_FindIMT (imt_name); imt = Key_FindIMT (imt_name);
if (imt) { if (imt) {
for (i = 0; i < QFK_LAST; i++) { for (i = 0; i < QFK_LAST; i++) {
keybind = imt->bindings[i].str; //XXX keybind = imt->button_bindings.a[i].str;
if (keybind == NULL) { if (keybind == NULL) {
continue; continue;
} }

View file

@ -563,6 +563,7 @@ static void
qwaq_input_init (qwaq_input_resources_t *res) qwaq_input_init (qwaq_input_resources_t *res)
{ {
res->input_event_handler = IE_Add_Handler (qwaq_input_event_handler, res); res->input_event_handler = IE_Add_Handler (qwaq_input_event_handler, res);
IE_Set_Focus (res->input_event_handler);
IN_DriverData (term_driver_handle, res); IN_DriverData (term_driver_handle, res);
if (res->key_sequences) { if (res->key_sequences) {