mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2025-03-21 18:01:15 +00:00
[qwaq] Parse function keys
While the key escape sequences are xterm-specific, they are only the default and preliminary provision has been made for overriding them. However, no override mechanism has been implemented beyond using dynamic table lookup.
This commit is contained in:
parent
28f50d2719
commit
fc44582726
5 changed files with 187 additions and 8 deletions
|
@ -12,7 +12,7 @@ QFCC_DEP=$(top_builddir)/tools/qfcc/source/qfcc$(EXEEXT)
|
|||
QFCC=$(top_builddir)/tools/qfcc/source/qfcc
|
||||
|
||||
QCFLAGS=-qq -O -g -Werror
|
||||
QCPPFLAGS=--no-default-paths -I$(top_srcdir)/ruamoko/include
|
||||
QCPPFLAGS=--no-default-paths -I$(top_srcdir)/ruamoko/include -I$(top_srcdir)/include
|
||||
QCLINKFLAGS=--no-default-paths -L$(top_builddir)/ruamoko/lib
|
||||
QCOMPILE=$(QFCC) $(QCFLAGS) $(QCPPFLAGS)
|
||||
QLINK=$(QFCC) $(QCFLAGS) $(QCLINKFLAGS)
|
||||
|
@ -36,7 +36,11 @@ qwaq_app_dat_src= \
|
|||
qwaq-view.r \
|
||||
qwaq-window.r
|
||||
|
||||
qwaq_curses_libs=
|
||||
#FIXME this coupling is horrible
|
||||
qwaq_curses_libs= \
|
||||
$(top_builddir)/libs/video/targets/libvid_common.la \
|
||||
$(top_builddir)/libs/console/libQFconsole.la \
|
||||
$(top_builddir)/libs/gib/libQFgib.la
|
||||
qwaq_curses_SOURCES=main.c qwaq-curses.c qwaq-input.c
|
||||
qwaq_curses_LDADD= $(qwaq_curses_libs) $(QWAQ_LIBS) \
|
||||
$(PANEL_LIBS) $(CURSES_LIBS) $(PTHREAD_LDFLAGS) $(DL_LIBS)
|
||||
|
@ -73,7 +77,7 @@ qwaq_app_dat_SOURCES=$(qwaq_app_dat_src)
|
|||
qwaq_app_obj=$(qwaq_app_dat_SOURCES:.r=.o)
|
||||
qwaq_app_dep=$(addprefix ./$(DEPDIR)/,$(qwaq_app_obj:.o=.Qo))
|
||||
qwaq-app.dat$(EXEEXT): $(qwaq_app_obj) $(QFCC_DEP)
|
||||
$(QLINK) -o $@ $(qwaq_app_obj) -lr
|
||||
$(QLINK) -o $@ $(qwaq_app_obj) -lcsqc -lr
|
||||
include $(qwaq_app_dep) # am--include-marker
|
||||
r_depfiles_remade += $(qwaq_app_dep)
|
||||
|
||||
|
|
|
@ -41,6 +41,11 @@ typedef struct qwaq_mevent_s {
|
|||
int click;
|
||||
} qwaq_mevent_t;
|
||||
|
||||
typedef struct qwaq_kevent_s {
|
||||
int code;
|
||||
int shift;
|
||||
} qwaq_kevent_t;
|
||||
|
||||
typedef struct qwaq_message_s {
|
||||
qwaq_command command;
|
||||
} qwaq_message_t;
|
||||
|
@ -49,7 +54,7 @@ typedef struct qwaq_event_s {
|
|||
int what;
|
||||
double when; // NOTE: 1<<32 based
|
||||
union {
|
||||
int key;
|
||||
qwaq_kevent_t key;
|
||||
qwaq_mevent_t mouse;
|
||||
qwaq_message_t message;
|
||||
};
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
#include "QF/cvar.h"
|
||||
#include "QF/gib.h"
|
||||
#include "QF/idparse.h"
|
||||
#include "QF/keys.h"
|
||||
#include "QF/progs.h"
|
||||
#include "QF/qargs.h"
|
||||
#include "QF/quakefs.h"
|
||||
|
@ -151,6 +152,7 @@ create_progs (void)
|
|||
PR_Init_Cvars ();
|
||||
PR_Init (pr);
|
||||
RUA_Init (pr, 0);
|
||||
Key_Progs_Init (pr);
|
||||
PR_Cmds_Init (pr);
|
||||
BI_Init (pr);
|
||||
|
||||
|
|
|
@ -166,6 +166,7 @@ typedef enum {
|
|||
esc_csi,
|
||||
esc_mouse,
|
||||
esc_sgr,
|
||||
esc_key,
|
||||
} esc_state_t;
|
||||
|
||||
typedef struct qwaq_resources_s {
|
||||
|
@ -188,6 +189,7 @@ typedef struct qwaq_resources_s {
|
|||
esc_state_t escstate;
|
||||
unsigned button_state;
|
||||
qwaq_event_t lastClick;
|
||||
struct hashtab_s *key_sequences;
|
||||
} qwaq_resources_t;
|
||||
// gcc stuff
|
||||
|
||||
|
|
|
@ -40,6 +40,8 @@
|
|||
#include <unistd.h>
|
||||
|
||||
#include "QF/dstring.h"
|
||||
#include "QF/hash.h"
|
||||
#include "QF/keys.h"
|
||||
#include "QF/sys.h"
|
||||
|
||||
#include "qwaq.h"
|
||||
|
@ -54,6 +56,112 @@
|
|||
#define SGR_OFF "\033[?1006l"
|
||||
#define WHEEL_BUTTONS 0x7c // scroll up/down/left/right - always click
|
||||
|
||||
typedef struct qwaq_key_s {
|
||||
const char *sequence;
|
||||
knum_t key;
|
||||
unsigned shift;
|
||||
} qwaq_key_t;
|
||||
|
||||
static qwaq_key_t default_keys[] = {
|
||||
{ "\033OP", QFK_F1 },
|
||||
{ "\033OQ", QFK_F2 },
|
||||
{ "\033OR", QFK_F3 },
|
||||
{ "\033OS", QFK_F4 },
|
||||
{ "\033[15~", QFK_F5 },
|
||||
{ "\033[17~", QFK_F6 },
|
||||
{ "\033[18~", QFK_F7 },
|
||||
{ "\033[19~", QFK_F8 },
|
||||
{ "\033[20~", QFK_F9 },
|
||||
{ "\033[21~", QFK_F10 },
|
||||
{ "\033[23~", QFK_F11 },
|
||||
{ "\033[24~", QFK_F12 },
|
||||
// shift F1-F12
|
||||
{ "\033[1;2P", QFK_F13 },
|
||||
{ "\033[1;2Q", QFK_F14 },
|
||||
{ "\033[1;2R", QFK_F15 },
|
||||
{ "\033[1;2S", QFK_F16 },
|
||||
{ "\033[15;2~", QFK_F17 },
|
||||
{ "\033[17;2~", QFK_F18 },
|
||||
{ "\033[18;2~", QFK_F19 },
|
||||
{ "\033[19;2~", QFK_F20 },
|
||||
{ "\033[20;2~", QFK_F21 },
|
||||
{ "\033[21;2~", QFK_F22 },
|
||||
{ "\033[23;2~", QFK_F23 },
|
||||
{ "\033[24;2~", QFK_F24 },
|
||||
// control F1-F12
|
||||
{ "\033[1;5P", QFK_F25 },
|
||||
{ "\033[1;5Q", QFK_F26 },
|
||||
{ "\033[1;5R", QFK_F27 },
|
||||
{ "\033[1;5S", QFK_F28 },
|
||||
{ "\033[15;5~", QFK_F29 },
|
||||
{ "\033[17;5~", QFK_F30 },
|
||||
{ "\033[18;5~", QFK_F31 },
|
||||
{ "\033[19;5~", QFK_F32 },
|
||||
{ "\033[20;5~", QFK_F33 },
|
||||
{ "\033[21;5~", QFK_F34 },
|
||||
{ "\033[23;5~", QFK_F35 },
|
||||
{ "\033[24;5~", QFK_F36 },
|
||||
// shift control F1-F12
|
||||
{ "\033[1;6P", QFK_F37 },
|
||||
{ "\033[1;6Q", QFK_F38 },
|
||||
{ "\033[1;6R", QFK_F39 },
|
||||
{ "\033[1;6S", QFK_F40 },
|
||||
{ "\033[15;6~", QFK_F41 },
|
||||
{ "\033[17;6~", QFK_F42 },
|
||||
{ "\033[18;6~", QFK_F43 },
|
||||
{ "\033[19;6~", QFK_F44 },
|
||||
{ "\033[20;6~", QFK_F45 },
|
||||
{ "\033[21;6~", QFK_F46 },
|
||||
{ "\033[23;6~", QFK_F47 },
|
||||
{ "\033[24;6~", QFK_F48 },
|
||||
|
||||
{ "\033[2~", QFK_INSERT, 0 },
|
||||
{ "\033[3~", QFK_DELETE, 0 },
|
||||
{ "\033[H", QFK_HOME, 0 },
|
||||
{ "\033[F", QFK_END, 0 },
|
||||
{ "\033[5~", QFK_PAGEUP, 0 },
|
||||
{ "\033[6~", QFK_PAGEDOWN, 0 },
|
||||
{ "\033[A", QFK_UP, 0 },
|
||||
{ "\033[B", QFK_DOWN, 0 },
|
||||
{ "\033[C", QFK_RIGHT, 0 },
|
||||
{ "\033[D", QFK_LEFT, 0 },
|
||||
// shift
|
||||
// there may be a setting to tell xterm to NOT act on shift ins/pgup/pgdn
|
||||
{ "\033[2;2~", QFK_INSERT, 1 }, // xterm gobbles (and pastes)
|
||||
{ "\033[3;2~", QFK_DELETE, 1 },
|
||||
{ "\033[1;2H", QFK_HOME, 1 },
|
||||
{ "\033[1;2F", QFK_END, 1 },
|
||||
{ "\033[5;2~", QFK_PAGEUP, 1 }, // xterm gobbles (scrolls term)
|
||||
{ "\033[6;2~", QFK_PAGEDOWN, 1 }, // xterm gobbles (scrolls term)
|
||||
{ "\033[1;2A", QFK_UP, 1 },
|
||||
{ "\033[1;2B", QFK_DOWN, 1 },
|
||||
{ "\033[1;2C", QFK_RIGHT, 1 },
|
||||
{ "\033[1;2D", QFK_LEFT, 1 },
|
||||
{ "\033[Z", QFK_TAB, 1 },
|
||||
// control
|
||||
{ "\033[2;5~", QFK_INSERT, 4 },
|
||||
{ "\033[3;5~", QFK_DELETE, 4 },
|
||||
{ "\033[1;5H", QFK_HOME, 4 },
|
||||
{ "\033[1;5F", QFK_END, 4 },
|
||||
{ "\033[5;5~", QFK_PAGEUP, 4 },
|
||||
{ "\033[6;5~", QFK_PAGEDOWN, 4 },
|
||||
{ "\033[1;5A", QFK_UP, 4 },
|
||||
{ "\033[1;5B", QFK_DOWN, 4 },
|
||||
{ "\033[1;5C", QFK_RIGHT, 4 },
|
||||
{ "\033[1;5D", QFK_LEFT, 4 },
|
||||
// shift control
|
||||
{ "\033[2;6~", QFK_INSERT, 5 },
|
||||
{ "\033[3;6~", QFK_DELETE, 5 },
|
||||
{ "\033[1;6H", QFK_HOME, 5 },
|
||||
{ "\033[1;6F", QFK_END, 5 },
|
||||
{ "\033[5;6~", QFK_PAGEUP, 5 },
|
||||
{ "\033[6;6~", QFK_PAGEDOWN, 5 },
|
||||
{ "\033[1;6A", QFK_UP, 5 },
|
||||
{ "\033[1;6B", QFK_DOWN, 5 },
|
||||
{ "\033[1;6C", QFK_RIGHT, 5 },
|
||||
{ "\033[1;6D", QFK_LEFT, 5 },
|
||||
};
|
||||
|
||||
static void
|
||||
add_event (qwaq_resources_t *res, qwaq_event_t *event)
|
||||
{
|
||||
|
@ -87,12 +195,13 @@ add_event (qwaq_resources_t *res, qwaq_event_t *event)
|
|||
}
|
||||
|
||||
static void
|
||||
key_event (qwaq_resources_t *res, int key)
|
||||
key_event (qwaq_resources_t *res, int key, unsigned shift)
|
||||
{
|
||||
qwaq_event_t event = {};
|
||||
event.what = qe_keydown;
|
||||
event.when = Sys_DoubleTime ();
|
||||
event.key = key;
|
||||
event.key.code = key;
|
||||
event.key.shift = shift;
|
||||
add_event (res, &event);
|
||||
}
|
||||
|
||||
|
@ -180,6 +289,19 @@ parse_sgr (qwaq_resources_t *res, char cmd)
|
|||
parse_mouse (res, ctrl, x - 1, y - 1, cmd);
|
||||
}
|
||||
|
||||
static void
|
||||
parse_key (qwaq_resources_t *res)
|
||||
{
|
||||
qwaq_key_t *key = Hash_Find (res->key_sequences, res->escbuff.str);
|
||||
|
||||
Sys_Printf ("parse_key %s %p\n", res->escbuff.str + 1, key);
|
||||
if (key) {
|
||||
Sys_Printf (" %d %03x %s\n", key->key, key->shift,
|
||||
Key_KeynumToString (key->key));
|
||||
key_event (res, key->key, key->shift);
|
||||
}
|
||||
}
|
||||
|
||||
static void process_char (qwaq_resources_t *res, char ch)
|
||||
{
|
||||
if (ch == 0x1b) {
|
||||
|
@ -188,11 +310,19 @@ static void process_char (qwaq_resources_t *res, char ch)
|
|||
} else {
|
||||
switch (res->escstate) {
|
||||
case esc_ground:
|
||||
key_event (res, (byte) ch);
|
||||
key_event (res, (byte) ch, 0); // shift state unknown
|
||||
break;
|
||||
case esc_escape:
|
||||
if (ch == '[') {
|
||||
res->escstate = esc_csi;
|
||||
} else if (ch == 'O') {
|
||||
// will wind up accepting P;P... but meh
|
||||
res->escstate = esc_key;
|
||||
dstring_clear (&res->escbuff);
|
||||
// start the buffer with what got us hear: eases key lookup
|
||||
dstring_append (&res->escbuff, "\033O", 2);
|
||||
} else {
|
||||
res->escstate = esc_ground;
|
||||
}
|
||||
break;
|
||||
case esc_csi:
|
||||
|
@ -202,6 +332,14 @@ static void process_char (qwaq_resources_t *res, char ch)
|
|||
} else if (ch == '<') {
|
||||
res->escstate = esc_sgr;
|
||||
dstring_clear (&res->escbuff);
|
||||
} else if (ch >= '0' && ch < 127) {
|
||||
res->escstate = esc_key;
|
||||
dstring_clear (&res->escbuff);
|
||||
// start the buffer with what got us hear: eases key lookup
|
||||
dstring_append (&res->escbuff, "\033[", 2);
|
||||
// the csi code might be short (eg, \e[H for home) so
|
||||
// need to check for end of string right away
|
||||
goto esc_key_jump;
|
||||
} else {
|
||||
res->escstate = esc_ground;
|
||||
}
|
||||
|
@ -214,23 +352,51 @@ static void process_char (qwaq_resources_t *res, char ch)
|
|||
}
|
||||
break;
|
||||
case esc_sgr:
|
||||
if (isdigit (ch) || ch ==';') {
|
||||
if (isdigit (ch) || ch == ';') {
|
||||
dstring_append (&res->escbuff, &ch, 1);
|
||||
} else {
|
||||
if (ch == 'm' || ch == 'M') {
|
||||
// terminate the string
|
||||
dstring_append (&res->escbuff, "", 1);
|
||||
parse_sgr (res, ch);
|
||||
}
|
||||
res->escstate = esc_ground;
|
||||
}
|
||||
break;
|
||||
case esc_key:
|
||||
esc_key_jump:
|
||||
dstring_append (&res->escbuff, &ch, 1);
|
||||
if (!isdigit (ch) && ch != ';') {
|
||||
// terminate the string
|
||||
dstring_append (&res->escbuff, "", 1);
|
||||
// parse_key will sort out whether it was a valid sequence
|
||||
parse_key (res);
|
||||
res->escstate = esc_ground;
|
||||
}
|
||||
break;
|
||||
}
|
||||
//printf("res->escstate %d\n", res->escstate);
|
||||
}
|
||||
}
|
||||
|
||||
static const char *
|
||||
key_sequence_getkey (const void *_seq, void *unused)
|
||||
{
|
||||
__auto_type seq = (const qwaq_key_t *) _seq;
|
||||
return seq->sequence;
|
||||
}
|
||||
|
||||
void qwaq_input_init (qwaq_resources_t *res)
|
||||
{
|
||||
if (res->key_sequences) {
|
||||
Hash_FlushTable (res->key_sequences);
|
||||
} else {
|
||||
res->key_sequences = Hash_NewTable (127, key_sequence_getkey, 0, 0);
|
||||
}
|
||||
for (size_t i = 0; i < sizeof (default_keys) / sizeof (default_keys[0]);
|
||||
i++) {
|
||||
Hash_Add (res->key_sequences, &default_keys[i]);
|
||||
}
|
||||
// ncurses takes care of input mode for us, so need only tell xterm
|
||||
// what we need
|
||||
write(1, MOUSE_MOVES_ON, sizeof (MOUSE_MOVES_ON) - 1);
|
||||
|
|
Loading…
Reference in a new issue