[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:
Bill Currie 2020-03-22 13:47:44 +09:00
parent 28f50d2719
commit fc44582726
5 changed files with 187 additions and 8 deletions

View file

@ -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)

View file

@ -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;
};

View file

@ -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);

View file

@ -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

View file

@ -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);