2008-12-03 21:19:15 +01:00
|
|
|
// we want strdup()
|
2011-08-25 23:49:17 +02:00
|
|
|
#define _XOPEN_SOURCE 600
|
2008-12-03 21:19:15 +01:00
|
|
|
|
2008-10-08 03:04:47 +02:00
|
|
|
#include "termkey.h"
|
|
|
|
#include "termkey-internal.h"
|
|
|
|
|
2011-09-24 01:04:01 +02:00
|
|
|
#ifdef HAVE_UNIBILIUM
|
|
|
|
# include <unibilium.h>
|
|
|
|
#else
|
|
|
|
# include <curses.h>
|
|
|
|
# include <term.h>
|
2008-10-08 03:04:47 +02:00
|
|
|
|
2009-11-24 02:31:35 +01:00
|
|
|
/* curses.h has just poluted our namespace. We want this back */
|
2011-09-24 01:04:01 +02:00
|
|
|
# undef buttons
|
|
|
|
#endif
|
2009-11-24 02:31:35 +01:00
|
|
|
|
2008-10-08 03:04:47 +02:00
|
|
|
#include <ctype.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
2008-11-02 18:59:30 +01:00
|
|
|
#include <unistd.h>
|
2012-01-20 21:01:11 +01:00
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/stat.h>
|
2008-10-08 03:04:47 +02:00
|
|
|
|
2008-11-12 17:32:17 +01:00
|
|
|
/* To be efficient at lookups, we store the byte sequence => keyinfo mapping
|
2008-11-13 00:58:20 +01:00
|
|
|
* in a trie. This avoids a slow linear search through a flat list of
|
|
|
|
* sequences. Because it is likely most nodes will be very sparse, we optimise
|
|
|
|
* vector to store an extent map after the database is loaded.
|
2008-11-12 17:32:17 +01:00
|
|
|
*/
|
|
|
|
|
|
|
|
typedef enum {
|
|
|
|
TYPE_KEY,
|
2009-11-24 02:31:35 +01:00
|
|
|
TYPE_ARR,
|
|
|
|
TYPE_MOUSE,
|
2008-11-12 17:32:17 +01:00
|
|
|
} trie_nodetype;
|
|
|
|
|
|
|
|
struct trie_node {
|
|
|
|
trie_nodetype type;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct trie_node_key {
|
|
|
|
trie_nodetype type;
|
2008-10-08 03:04:47 +02:00
|
|
|
struct keyinfo key;
|
|
|
|
};
|
|
|
|
|
2008-11-12 17:32:17 +01:00
|
|
|
struct trie_node_arr {
|
|
|
|
trie_nodetype type;
|
2008-11-13 00:58:20 +01:00
|
|
|
unsigned char min, max; /* INCLUSIVE endpoints of the extent range */
|
2008-12-02 02:05:47 +01:00
|
|
|
struct trie_node *arr[]; /* dynamic size at allocation time */
|
2008-11-12 17:32:17 +01:00
|
|
|
};
|
|
|
|
|
2008-10-08 03:04:47 +02:00
|
|
|
typedef struct {
|
2009-07-15 21:40:44 +02:00
|
|
|
TermKey *tk;
|
2008-10-08 03:04:47 +02:00
|
|
|
|
2008-11-12 17:32:17 +01:00
|
|
|
struct trie_node *root;
|
2008-12-03 21:19:15 +01:00
|
|
|
|
|
|
|
char *start_string;
|
|
|
|
char *stop_string;
|
2009-07-15 21:40:44 +02:00
|
|
|
} TermKeyTI;
|
2008-10-08 03:04:47 +02:00
|
|
|
|
2009-07-15 21:40:44 +02:00
|
|
|
static int funcname2keysym(const char *funcname, TermKeyType *typep, TermKeySym *symp, int *modmask, int *modsetp);
|
2009-11-24 02:31:35 +01:00
|
|
|
static int insert_seq(TermKeyTI *ti, const char *seq, struct trie_node *node);
|
2008-10-08 03:04:47 +02:00
|
|
|
|
2009-07-15 21:40:44 +02:00
|
|
|
static struct trie_node *new_node_key(TermKeyType type, TermKeySym sym, int modmask, int modset)
|
2008-11-12 17:32:17 +01:00
|
|
|
{
|
2008-11-24 23:15:43 +01:00
|
|
|
struct trie_node_key *n = malloc(sizeof(*n));
|
2008-11-12 17:32:17 +01:00
|
|
|
if(!n)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
n->type = TYPE_KEY;
|
|
|
|
|
|
|
|
n->key.type = type;
|
|
|
|
n->key.sym = sym;
|
|
|
|
n->key.modifier_mask = modmask;
|
|
|
|
n->key.modifier_set = modset;
|
|
|
|
|
|
|
|
return (struct trie_node*)n;
|
|
|
|
}
|
|
|
|
|
2008-11-13 00:58:20 +01:00
|
|
|
static struct trie_node *new_node_arr(unsigned char min, unsigned char max)
|
2008-11-12 17:32:17 +01:00
|
|
|
{
|
2008-11-24 23:15:43 +01:00
|
|
|
struct trie_node_arr *n = malloc(sizeof(*n) + ((int)max-min+1) * sizeof(n->arr[0]));
|
2008-11-12 17:32:17 +01:00
|
|
|
if(!n)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
n->type = TYPE_ARR;
|
2008-11-13 00:58:20 +01:00
|
|
|
n->min = min; n->max = max;
|
2008-11-12 17:32:17 +01:00
|
|
|
|
2008-11-13 00:58:20 +01:00
|
|
|
int i;
|
|
|
|
for(i = min; i <= max; i++)
|
|
|
|
n->arr[i-min] = NULL;
|
2008-11-12 17:32:17 +01:00
|
|
|
|
|
|
|
return (struct trie_node*)n;
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct trie_node *lookup_next(struct trie_node *n, unsigned char b)
|
|
|
|
{
|
|
|
|
switch(n->type) {
|
|
|
|
case TYPE_KEY:
|
2009-11-24 02:31:35 +01:00
|
|
|
case TYPE_MOUSE:
|
2008-11-12 17:32:17 +01:00
|
|
|
fprintf(stderr, "ABORT: lookup_next within a TYPE_KEY node\n");
|
|
|
|
abort();
|
|
|
|
case TYPE_ARR:
|
|
|
|
{
|
|
|
|
struct trie_node_arr *nar = (struct trie_node_arr*)n;
|
2008-11-13 00:58:20 +01:00
|
|
|
if(b < nar->min || b > nar->max)
|
|
|
|
return NULL;
|
|
|
|
return nar->arr[b - nar->min];
|
2008-11-12 17:32:17 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL; // Never reached but keeps compiler happy
|
|
|
|
}
|
|
|
|
|
|
|
|
static void free_trie(struct trie_node *n)
|
|
|
|
{
|
|
|
|
switch(n->type) {
|
|
|
|
case TYPE_KEY:
|
2009-11-24 02:31:35 +01:00
|
|
|
case TYPE_MOUSE:
|
2008-11-12 17:32:17 +01:00
|
|
|
break;
|
|
|
|
case TYPE_ARR:
|
|
|
|
{
|
|
|
|
struct trie_node_arr *nar = (struct trie_node_arr*)n;
|
2008-11-13 00:58:20 +01:00
|
|
|
int i;
|
|
|
|
for(i = nar->min; i <= nar->max; i++)
|
|
|
|
if(nar->arr[i - nar->min])
|
|
|
|
free_trie(nar->arr[i - nar->min]);
|
2008-11-12 17:32:17 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
free(n);
|
|
|
|
}
|
|
|
|
|
2008-11-13 00:58:20 +01:00
|
|
|
static struct trie_node *compress_trie(struct trie_node *n)
|
|
|
|
{
|
|
|
|
if(!n)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
switch(n->type) {
|
|
|
|
case TYPE_KEY:
|
2009-11-24 02:31:35 +01:00
|
|
|
case TYPE_MOUSE:
|
2008-11-13 00:58:20 +01:00
|
|
|
return n;
|
|
|
|
case TYPE_ARR:
|
|
|
|
{
|
|
|
|
struct trie_node_arr *nar = (struct trie_node_arr*)n;
|
|
|
|
unsigned char min, max;
|
|
|
|
// Find the real bounds
|
|
|
|
for(min = 0; !nar->arr[min]; min++)
|
|
|
|
;
|
|
|
|
for(max = 0xff; !nar->arr[max]; max--)
|
|
|
|
;
|
|
|
|
|
|
|
|
struct trie_node_arr *new = (struct trie_node_arr*)new_node_arr(min, max);
|
|
|
|
int i;
|
|
|
|
for(i = min; i <= max; i++)
|
|
|
|
new->arr[i - min] = compress_trie(nar->arr[i]);
|
|
|
|
|
|
|
|
free(nar);
|
|
|
|
return (struct trie_node*)new;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return n;
|
|
|
|
}
|
|
|
|
|
2011-09-24 00:40:54 +02:00
|
|
|
static int load_terminfo(TermKeyTI *ti, const char *term)
|
2008-10-08 03:04:47 +02:00
|
|
|
{
|
2011-09-24 01:04:01 +02:00
|
|
|
int i;
|
|
|
|
|
|
|
|
#ifdef HAVE_UNIBILIUM
|
|
|
|
unibi_term *unibi = unibi_from_term(term);
|
|
|
|
if(!unibi)
|
|
|
|
return 0;
|
|
|
|
#else
|
2008-10-09 21:23:45 +02:00
|
|
|
int err;
|
|
|
|
|
2008-11-28 20:48:41 +01:00
|
|
|
/* Have to cast away the const. But it's OK - we know terminfo won't really
|
|
|
|
* modify term */
|
|
|
|
if(setupterm((char*)term, 1, &err) != OK)
|
2011-09-24 00:40:54 +02:00
|
|
|
return 0;
|
2011-09-24 01:04:01 +02:00
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef HAVE_UNIBILIUM
|
|
|
|
for(i = unibi_string_begin_+1; i < unibi_string_end_; i++)
|
|
|
|
#else
|
|
|
|
for(i = 0; strfnames[i]; i++)
|
|
|
|
#endif
|
|
|
|
{
|
2008-10-08 03:04:47 +02:00
|
|
|
// Only care about the key_* constants
|
2011-09-24 01:04:01 +02:00
|
|
|
#ifdef HAVE_UNIBILIUM
|
|
|
|
const char *name = unibi_name_str(i);
|
|
|
|
#else
|
2008-10-08 03:04:47 +02:00
|
|
|
const char *name = strfnames[i];
|
2011-09-24 01:04:01 +02:00
|
|
|
#endif
|
2008-10-08 03:04:47 +02:00
|
|
|
if(strncmp(name, "key_", 4) != 0)
|
|
|
|
continue;
|
|
|
|
|
2011-09-24 01:04:01 +02:00
|
|
|
#ifdef HAVE_UNIBILIUM
|
|
|
|
const char *value = unibi_get_str(unibi, i);
|
|
|
|
#else
|
2008-10-08 03:04:47 +02:00
|
|
|
const char *value = tigetstr(strnames[i]);
|
2011-09-24 01:04:01 +02:00
|
|
|
#endif
|
2008-10-08 03:04:47 +02:00
|
|
|
if(!value || value == (char*)-1)
|
|
|
|
continue;
|
|
|
|
|
2009-11-24 02:31:35 +01:00
|
|
|
struct trie_node *node = NULL;
|
2008-10-08 03:04:47 +02:00
|
|
|
|
2011-09-24 00:40:54 +02:00
|
|
|
if(strcmp(name + 4, "mouse") == 0) {
|
2009-11-24 02:31:35 +01:00
|
|
|
node = malloc(sizeof(*node));
|
|
|
|
if(!node)
|
2011-09-24 00:40:54 +02:00
|
|
|
return 0;
|
2009-11-24 02:31:35 +01:00
|
|
|
|
|
|
|
node->type = TYPE_MOUSE;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
TermKeyType type;
|
|
|
|
TermKeySym sym;
|
|
|
|
int mask = 0;
|
|
|
|
int set = 0;
|
|
|
|
|
2011-09-24 00:40:54 +02:00
|
|
|
if(!funcname2keysym(name + 4, &type, &sym, &mask, &set))
|
2009-11-24 02:31:35 +01:00
|
|
|
continue;
|
2008-10-08 03:04:47 +02:00
|
|
|
|
2009-11-24 02:31:35 +01:00
|
|
|
if(sym == TERMKEY_SYM_NONE)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
node = new_node_key(type, sym, mask, set);
|
|
|
|
}
|
|
|
|
|
|
|
|
if(node)
|
|
|
|
if(!insert_seq(ti, value, node)) {
|
|
|
|
free(node);
|
2011-09-24 00:40:54 +02:00
|
|
|
return 0;
|
2009-11-24 02:31:35 +01:00
|
|
|
}
|
2008-10-08 03:04:47 +02:00
|
|
|
}
|
|
|
|
|
2008-12-03 21:19:15 +01:00
|
|
|
/* Take copies of these terminfo strings, in case we build multiple termkey
|
|
|
|
* instances for multiple different termtypes, and it's different by the
|
|
|
|
* time we want to use it
|
|
|
|
*/
|
2011-09-24 01:04:01 +02:00
|
|
|
#ifdef HAVE_UNIBILIUM
|
|
|
|
const char *keypad_xmit = unibi_get_str(unibi, unibi_pkey_xmit);
|
|
|
|
#endif
|
|
|
|
|
2008-12-03 21:19:15 +01:00
|
|
|
if(keypad_xmit)
|
|
|
|
ti->start_string = strdup(keypad_xmit);
|
|
|
|
else
|
|
|
|
ti->start_string = NULL;
|
|
|
|
|
2011-09-24 01:04:01 +02:00
|
|
|
#ifdef HAVE_UNIBILIUM
|
|
|
|
const char *keypad_local = unibi_get_str(unibi, unibi_pkey_local);
|
|
|
|
#endif
|
|
|
|
|
2008-12-03 21:19:15 +01:00
|
|
|
if(keypad_local)
|
|
|
|
ti->stop_string = strdup(keypad_local);
|
|
|
|
else
|
|
|
|
ti->stop_string = NULL;
|
|
|
|
|
2011-09-24 01:04:01 +02:00
|
|
|
#ifdef HAVE_UNIBILIUM
|
|
|
|
unibi_destroy(unibi);
|
|
|
|
#endif
|
|
|
|
|
2011-09-24 00:40:54 +02:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void *new_driver(TermKey *tk, const char *term)
|
|
|
|
{
|
|
|
|
TermKeyTI *ti = malloc(sizeof *ti);
|
|
|
|
if(!ti)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
ti->tk = tk;
|
|
|
|
|
|
|
|
ti->root = new_node_arr(0, 0xff);
|
|
|
|
if(!ti->root)
|
|
|
|
goto abort_free_ti;
|
|
|
|
|
|
|
|
if(!load_terminfo(ti, term))
|
|
|
|
goto abort_free_trie;
|
|
|
|
|
|
|
|
ti->root = compress_trie(ti->root);
|
|
|
|
|
2008-10-08 03:04:47 +02:00
|
|
|
return ti;
|
2008-10-10 00:19:10 +02:00
|
|
|
|
2008-11-12 17:32:17 +01:00
|
|
|
abort_free_trie:
|
|
|
|
free_trie(ti->root);
|
2008-11-12 17:10:58 +01:00
|
|
|
|
2008-10-10 00:19:10 +02:00
|
|
|
abort_free_ti:
|
|
|
|
free(ti);
|
|
|
|
|
|
|
|
return NULL;
|
2008-10-08 03:04:47 +02:00
|
|
|
}
|
|
|
|
|
2012-01-20 18:00:09 +01:00
|
|
|
static int start_driver(TermKey *tk, void *info)
|
2008-11-02 18:59:30 +01:00
|
|
|
{
|
2009-07-15 21:40:44 +02:00
|
|
|
TermKeyTI *ti = info;
|
2012-01-20 21:01:11 +01:00
|
|
|
struct stat statbuf;
|
2012-01-20 18:00:09 +01:00
|
|
|
char *start_string = ti->start_string;
|
|
|
|
size_t len;
|
|
|
|
|
|
|
|
if(tk->fd == -1 || !start_string)
|
|
|
|
return 1;
|
2008-12-03 21:19:15 +01:00
|
|
|
|
2008-11-02 18:59:30 +01:00
|
|
|
/* The terminfo database will contain keys in application cursor key mode.
|
|
|
|
* We may need to enable that mode
|
|
|
|
*/
|
2012-01-20 18:00:09 +01:00
|
|
|
|
2012-01-20 21:01:11 +01:00
|
|
|
/* There's no point trying to write() to a pipe */
|
|
|
|
if(fstat(tk->fd, &statbuf) == -1)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if(S_ISFIFO(statbuf.st_mode))
|
|
|
|
return 1;
|
|
|
|
|
2012-01-20 18:00:09 +01:00
|
|
|
// Can't call putp or tputs because they suck and don't give us fd control
|
|
|
|
len = strlen(start_string);
|
|
|
|
while(len) {
|
|
|
|
size_t written = write(tk->fd, start_string, len);
|
|
|
|
if(written == -1)
|
|
|
|
return 0;
|
|
|
|
start_string += written;
|
|
|
|
len -= written;
|
2008-11-02 18:59:30 +01:00
|
|
|
}
|
2012-01-20 18:00:09 +01:00
|
|
|
return 1;
|
2008-11-02 18:59:30 +01:00
|
|
|
}
|
|
|
|
|
2012-01-20 18:00:09 +01:00
|
|
|
static int stop_driver(TermKey *tk, void *info)
|
2008-11-02 18:59:30 +01:00
|
|
|
{
|
2009-07-15 21:40:44 +02:00
|
|
|
TermKeyTI *ti = info;
|
2012-01-20 21:01:11 +01:00
|
|
|
struct stat statbuf;
|
2012-01-20 18:00:09 +01:00
|
|
|
char *stop_string = ti->stop_string;
|
|
|
|
size_t len;
|
2008-12-03 21:19:15 +01:00
|
|
|
|
2012-01-20 18:00:09 +01:00
|
|
|
if(tk->fd == -1 || !stop_string)
|
|
|
|
return 1;
|
|
|
|
|
2012-01-20 21:01:11 +01:00
|
|
|
/* There's no point trying to write() to a pipe */
|
|
|
|
if(fstat(tk->fd, &statbuf) == -1)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if(S_ISFIFO(statbuf.st_mode))
|
|
|
|
return 1;
|
|
|
|
|
2012-01-20 18:00:09 +01:00
|
|
|
/* The terminfo database will contain keys in application cursor key mode.
|
|
|
|
* We may need to enable that mode
|
|
|
|
*/
|
|
|
|
|
|
|
|
// Can't call putp or tputs because they suck and don't give us fd control
|
|
|
|
len = strlen(stop_string);
|
|
|
|
while(len) {
|
|
|
|
size_t written = write(tk->fd, stop_string, len);
|
|
|
|
if(written == -1)
|
|
|
|
return 0;
|
|
|
|
stop_string += written;
|
|
|
|
len -= written;
|
2008-11-02 18:59:30 +01:00
|
|
|
}
|
2012-01-20 18:00:09 +01:00
|
|
|
return 1;
|
2008-11-02 18:59:30 +01:00
|
|
|
}
|
|
|
|
|
2008-11-08 18:47:57 +01:00
|
|
|
static void free_driver(void *info)
|
2008-10-08 03:04:47 +02:00
|
|
|
{
|
2009-07-15 21:40:44 +02:00
|
|
|
TermKeyTI *ti = info;
|
2008-11-09 23:38:10 +01:00
|
|
|
|
2008-11-12 17:32:17 +01:00
|
|
|
free_trie(ti->root);
|
2008-11-09 23:38:10 +01:00
|
|
|
|
2008-12-03 21:19:15 +01:00
|
|
|
if(ti->start_string)
|
|
|
|
free(ti->start_string);
|
|
|
|
|
|
|
|
if(ti->stop_string)
|
|
|
|
free(ti->stop_string);
|
|
|
|
|
2008-11-09 23:38:10 +01:00
|
|
|
free(ti);
|
2008-10-08 03:04:47 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
#define CHARAT(i) (tk->buffer[tk->buffstart + (i)])
|
|
|
|
|
2009-07-15 21:40:44 +02:00
|
|
|
static TermKeyResult peekkey(TermKey *tk, void *info, TermKeyKey *key, int force, size_t *nbytep)
|
2008-10-08 03:04:47 +02:00
|
|
|
{
|
2009-07-15 21:40:44 +02:00
|
|
|
TermKeyTI *ti = info;
|
2008-10-08 03:04:47 +02:00
|
|
|
|
|
|
|
if(tk->buffcount == 0)
|
|
|
|
return tk->is_closed ? TERMKEY_RES_EOF : TERMKEY_RES_NONE;
|
|
|
|
|
2008-11-12 17:32:17 +01:00
|
|
|
struct trie_node *p = ti->root;
|
2008-10-08 03:04:47 +02:00
|
|
|
|
2008-11-24 23:06:14 +01:00
|
|
|
unsigned int pos = 0;
|
2008-11-12 17:32:17 +01:00
|
|
|
while(pos < tk->buffcount) {
|
|
|
|
p = lookup_next(p, CHARAT(pos));
|
|
|
|
if(!p)
|
|
|
|
break;
|
2008-10-08 03:04:47 +02:00
|
|
|
|
2008-11-12 17:32:17 +01:00
|
|
|
pos++;
|
2008-10-08 03:04:47 +02:00
|
|
|
|
2008-11-12 17:32:17 +01:00
|
|
|
if(p->type == TYPE_KEY) {
|
|
|
|
struct trie_node_key *nk = (struct trie_node_key*)p;
|
|
|
|
key->type = nk->key.type;
|
|
|
|
key->code.sym = nk->key.sym;
|
|
|
|
key->modifiers = nk->key.modifier_set;
|
2008-12-10 01:23:47 +01:00
|
|
|
*nbytep = pos;
|
2008-11-12 17:32:17 +01:00
|
|
|
return TERMKEY_RES_KEY;
|
2008-10-08 03:04:47 +02:00
|
|
|
}
|
2009-11-24 02:31:35 +01:00
|
|
|
else if(p->type == TYPE_MOUSE) {
|
2009-11-26 01:27:58 +01:00
|
|
|
tk->buffstart += pos;
|
|
|
|
tk->buffcount -= pos;
|
|
|
|
|
|
|
|
TermKeyResult mouse_result = (*tk->method.peekkey_mouse)(tk, key, nbytep);
|
|
|
|
|
|
|
|
tk->buffstart -= pos;
|
|
|
|
tk->buffcount += pos;
|
|
|
|
|
|
|
|
if(mouse_result == TERMKEY_RES_KEY)
|
|
|
|
*nbytep += pos;
|
|
|
|
|
|
|
|
return mouse_result;
|
2009-11-24 02:31:35 +01:00
|
|
|
}
|
2008-10-08 03:04:47 +02:00
|
|
|
}
|
|
|
|
|
2008-11-12 17:32:17 +01:00
|
|
|
// If p is not NULL then we hadn't walked off the end yet, so we have a
|
|
|
|
// partial match
|
|
|
|
if(p && !force)
|
|
|
|
return TERMKEY_RES_AGAIN;
|
|
|
|
|
2008-11-09 20:45:43 +01:00
|
|
|
return TERMKEY_RES_NONE;
|
2008-10-08 03:04:47 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static struct {
|
|
|
|
const char *funcname;
|
2009-07-15 21:40:44 +02:00
|
|
|
TermKeyType type;
|
|
|
|
TermKeySym sym;
|
2008-10-08 03:04:47 +02:00
|
|
|
int mods;
|
|
|
|
} funcs[] =
|
|
|
|
{
|
2008-10-10 01:44:13 +02:00
|
|
|
/* THIS LIST MUST REMAIN SORTED! */
|
2008-10-08 03:04:47 +02:00
|
|
|
{ "backspace", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_BACKSPACE, 0 },
|
|
|
|
{ "begin", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_BEGIN, 0 },
|
2008-10-10 02:11:24 +02:00
|
|
|
{ "beg", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_BEGIN, 0 },
|
2008-10-08 03:04:47 +02:00
|
|
|
{ "btab", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_TAB, TERMKEY_KEYMOD_SHIFT },
|
2008-10-10 02:11:24 +02:00
|
|
|
{ "cancel", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_CANCEL, 0 },
|
|
|
|
{ "clear", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_CLEAR, 0 },
|
|
|
|
{ "close", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_CLOSE, 0 },
|
|
|
|
{ "command", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_COMMAND, 0 },
|
|
|
|
{ "copy", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_COPY, 0 },
|
2008-10-08 03:04:47 +02:00
|
|
|
{ "dc", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_DELETE, 0 },
|
|
|
|
{ "down", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_DOWN, 0 },
|
|
|
|
{ "end", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_END, 0 },
|
2008-10-10 02:11:24 +02:00
|
|
|
{ "enter", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_ENTER, 0 },
|
|
|
|
{ "exit", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_EXIT, 0 },
|
2008-10-08 03:04:47 +02:00
|
|
|
{ "find", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_FIND, 0 },
|
2008-10-10 02:11:24 +02:00
|
|
|
{ "help", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_HELP, 0 },
|
2008-10-08 03:04:47 +02:00
|
|
|
{ "home", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_HOME, 0 },
|
|
|
|
{ "ic", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_INSERT, 0 },
|
|
|
|
{ "left", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_LEFT, 0 },
|
2008-10-10 02:11:24 +02:00
|
|
|
{ "mark", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_MARK, 0 },
|
|
|
|
{ "message", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_MESSAGE, 0 },
|
2008-11-02 23:16:03 +01:00
|
|
|
{ "mouse", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_NONE, 0 },
|
2008-10-10 02:11:24 +02:00
|
|
|
{ "move", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_MOVE, 0 },
|
2008-10-08 03:04:47 +02:00
|
|
|
{ "next", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_PAGEDOWN, 0 }, // Not quite, but it's the best we can do
|
|
|
|
{ "npage", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_PAGEDOWN, 0 },
|
2008-10-10 02:11:24 +02:00
|
|
|
{ "open", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_OPEN, 0 },
|
|
|
|
{ "options", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_OPTIONS, 0 },
|
2008-10-08 03:04:47 +02:00
|
|
|
{ "ppage", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_PAGEUP, 0 },
|
|
|
|
{ "previous", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_PAGEUP, 0 }, // Not quite, but it's the best we can do
|
2008-10-10 02:11:24 +02:00
|
|
|
{ "print", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_PRINT, 0 },
|
|
|
|
{ "redo", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_REDO, 0 },
|
|
|
|
{ "reference", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_REFERENCE, 0 },
|
|
|
|
{ "refresh", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_REFRESH, 0 },
|
|
|
|
{ "replace", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_REPLACE, 0 },
|
|
|
|
{ "restart", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_RESTART, 0 },
|
|
|
|
{ "resume", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_RESUME, 0 },
|
2008-10-08 03:04:47 +02:00
|
|
|
{ "right", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_RIGHT, 0 },
|
2008-10-10 02:11:24 +02:00
|
|
|
{ "save", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_SAVE, 0 },
|
2008-10-08 03:04:47 +02:00
|
|
|
{ "select", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_SELECT, 0 },
|
2008-10-10 02:11:24 +02:00
|
|
|
{ "suspend", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_SUSPEND, 0 },
|
|
|
|
{ "undo", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_UNDO, 0 },
|
2008-10-08 03:04:47 +02:00
|
|
|
{ "up", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_UP, 0 },
|
|
|
|
{ NULL },
|
|
|
|
};
|
|
|
|
|
2009-07-15 21:40:44 +02:00
|
|
|
static int funcname2keysym(const char *funcname, TermKeyType *typep, TermKeySym *symp, int *modmaskp, int *modsetp)
|
2008-10-08 03:04:47 +02:00
|
|
|
{
|
2008-10-10 01:44:13 +02:00
|
|
|
// Binary search
|
|
|
|
|
|
|
|
int start = 0;
|
|
|
|
int end = sizeof(funcs)/sizeof(funcs[0]); // is "one past" the end of the range
|
|
|
|
|
|
|
|
while(1) {
|
|
|
|
int i = (start+end) / 2;
|
|
|
|
int cmp = strcmp(funcname, funcs[i].funcname);
|
|
|
|
|
|
|
|
if(cmp == 0) {
|
2008-10-08 03:04:47 +02:00
|
|
|
*typep = funcs[i].type;
|
|
|
|
*symp = funcs[i].sym;
|
|
|
|
*modmaskp = funcs[i].mods;
|
|
|
|
*modsetp = funcs[i].mods;
|
|
|
|
return 1;
|
|
|
|
}
|
2008-10-10 01:44:13 +02:00
|
|
|
else if(end == start + 1)
|
|
|
|
// That was our last choice and it wasn't it - not found
|
|
|
|
break;
|
|
|
|
else if(cmp > 0)
|
|
|
|
start = i;
|
|
|
|
else
|
|
|
|
end = i;
|
2008-10-08 03:04:47 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if(funcname[0] == 'f' && isdigit(funcname[1])) {
|
|
|
|
*typep = TERMKEY_TYPE_FUNCTION;
|
|
|
|
*symp = atoi(funcname + 1);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Last-ditch attempt; maybe it's a shift key?
|
|
|
|
if(funcname[0] == 's' && funcname2keysym(funcname + 1, typep, symp, modmaskp, modsetp)) {
|
|
|
|
*modmaskp |= TERMKEY_KEYMOD_SHIFT;
|
|
|
|
*modsetp |= TERMKEY_KEYMOD_SHIFT;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2008-11-18 16:55:29 +01:00
|
|
|
#ifdef DEBUG
|
|
|
|
fprintf(stderr, "TODO: Need to convert funcname %s to a type/sym\n", funcname);
|
|
|
|
#endif
|
|
|
|
|
2008-10-08 03:04:47 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2009-11-24 02:31:35 +01:00
|
|
|
static int insert_seq(TermKeyTI *ti, const char *seq, struct trie_node *node)
|
2008-10-08 03:04:47 +02:00
|
|
|
{
|
2008-11-12 17:32:17 +01:00
|
|
|
int pos = 0;
|
|
|
|
struct trie_node *p = ti->root;
|
|
|
|
|
|
|
|
// Unsigned because we'll be using it as an array subscript
|
|
|
|
unsigned char b;
|
|
|
|
|
|
|
|
while((b = seq[pos])) {
|
|
|
|
struct trie_node *next = lookup_next(p, b);
|
|
|
|
if(!next)
|
|
|
|
break;
|
|
|
|
p = next;
|
|
|
|
pos++;
|
2008-10-08 03:04:47 +02:00
|
|
|
}
|
|
|
|
|
2008-11-12 17:32:17 +01:00
|
|
|
while((b = seq[pos])) {
|
|
|
|
struct trie_node *next;
|
|
|
|
if(seq[pos+1])
|
|
|
|
// Intermediate node
|
2008-11-13 00:58:20 +01:00
|
|
|
next = new_node_arr(0, 0xff);
|
2008-11-12 17:32:17 +01:00
|
|
|
else
|
|
|
|
// Final key node
|
2009-11-24 02:31:35 +01:00
|
|
|
next = node;
|
2008-11-12 17:32:17 +01:00
|
|
|
|
|
|
|
if(!next)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
switch(p->type) {
|
|
|
|
case TYPE_ARR:
|
|
|
|
{
|
|
|
|
struct trie_node_arr *nar = (struct trie_node_arr*)p;
|
2008-11-13 00:58:20 +01:00
|
|
|
if(b < nar->min || b > nar->max) {
|
|
|
|
fprintf(stderr, "ASSERT FAIL: Trie insert at 0x%02x is outside of extent bounds (0x%02x..0x%02x)\n",
|
|
|
|
b, nar->min, nar->max);
|
|
|
|
abort();
|
|
|
|
}
|
|
|
|
nar->arr[b - nar->min] = next;
|
2008-11-12 17:32:17 +01:00
|
|
|
p = next;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case TYPE_KEY:
|
2009-11-24 02:31:35 +01:00
|
|
|
case TYPE_MOUSE:
|
2008-11-12 17:32:17 +01:00
|
|
|
fprintf(stderr, "ASSERT FAIL: Tried to insert child node in TYPE_KEY\n");
|
|
|
|
abort();
|
|
|
|
}
|
|
|
|
|
|
|
|
pos++;
|
|
|
|
}
|
2008-11-12 17:10:58 +01:00
|
|
|
|
|
|
|
return 1;
|
2008-10-08 03:04:47 +02:00
|
|
|
}
|
|
|
|
|
2009-07-15 21:40:44 +02:00
|
|
|
struct TermKeyDriver termkey_driver_ti = {
|
2008-11-08 18:56:44 +01:00
|
|
|
.name = "terminfo",
|
|
|
|
|
2008-10-08 03:04:47 +02:00
|
|
|
.new_driver = new_driver,
|
|
|
|
.free_driver = free_driver,
|
|
|
|
|
2008-11-02 18:59:30 +01:00
|
|
|
.start_driver = start_driver,
|
|
|
|
.stop_driver = stop_driver,
|
|
|
|
|
2008-12-10 01:23:47 +01:00
|
|
|
.peekkey = peekkey,
|
2008-10-08 03:04:47 +02:00
|
|
|
};
|