Implement waittime polling to try to distinguish Esc, 1 from A-1, etc.. on slow terminals

This commit is contained in:
Paul LeoNerd Evans 2008-02-10 20:22:33 +00:00
parent c71e1928a2
commit 31414eac3b
2 changed files with 94 additions and 12 deletions

102
termkey.c
View File

@ -1,6 +1,7 @@
#include "termkey.h" #include "termkey.h"
#include <errno.h> #include <errno.h>
#include <poll.h>
#include <unistd.h> #include <unistd.h>
#include <string.h> #include <string.h>
@ -20,6 +21,8 @@ struct termkey {
size_t buffcount; // NUMBER of entires valid in buffer size_t buffcount; // NUMBER of entires valid in buffer
size_t buffsize; // Total malloc'ed size size_t buffsize; // Total malloc'ed size
int waittime; // msec
char is_closed; char is_closed;
int nkeynames; int nkeynames;
@ -37,7 +40,7 @@ struct termkey {
struct keyinfo *csifuncs; struct keyinfo *csifuncs;
}; };
termkey_t *termkey_new_full(int fd, int flags, size_t buffsize) termkey_t *termkey_new_full(int fd, int flags, size_t buffsize, int waittime)
{ {
termkey_t *tk = malloc(sizeof(*tk)); termkey_t *tk = malloc(sizeof(*tk));
if(!tk) if(!tk)
@ -75,6 +78,8 @@ termkey_t *termkey_new_full(int fd, int flags, size_t buffsize)
tk->buffcount = 0; tk->buffcount = 0;
tk->buffsize = buffsize; tk->buffsize = buffsize;
tk->waittime = waittime;
tk->is_closed = 0; tk->is_closed = 0;
int i; int i;
@ -168,7 +173,17 @@ termkey_t *termkey_new_full(int fd, int flags, size_t buffsize)
termkey_t *termkey_new(int fd, int flags) termkey_t *termkey_new(int fd, int flags)
{ {
return termkey_new_full(fd, flags, 256); return termkey_new_full(fd, flags, 256, 50);
}
void termkey_setwaittime(termkey_t *tk, int msec)
{
tk->waittime = msec;
}
int termkey_getwaittime(termkey_t *tk)
{
return tk->waittime;
} }
static inline void eatbytes(termkey_t *tk, size_t count) static inline void eatbytes(termkey_t *tk, size_t count)
@ -294,8 +309,15 @@ static termkey_result getkey_csi(termkey_t *tk, size_t introlen, termkey_key *ke
csi_end++; csi_end++;
} }
if(csi_end >= tk->buffcount) if(csi_end >= tk->buffcount) {
return TERMKEY_RES_NONE; if(tk->waittime)
return TERMKEY_RES_AGAIN;
do_codepoint(tk, '[', key);
key->modifiers |= TERMKEY_KEYMOD_ALT;
eatbytes(tk, introlen);
return TERMKEY_RES_KEY;
}
unsigned char cmd = CHARAT(csi_end); unsigned char cmd = CHARAT(csi_end);
int arg[16]; int arg[16];
@ -372,8 +394,15 @@ static termkey_result getkey_csi(termkey_t *tk, size_t introlen, termkey_key *ke
static termkey_result getkey_ss3(termkey_t *tk, size_t introlen, termkey_key *key) static termkey_result getkey_ss3(termkey_t *tk, size_t introlen, termkey_key *key)
{ {
if(introlen + 1 < tk->buffcount) if(tk->buffcount < introlen + 1) {
return TERMKEY_RES_NONE; if(tk->waittime)
return TERMKEY_RES_AGAIN;
do_codepoint(tk, 'O', key);
key->modifiers |= TERMKEY_KEYMOD_ALT;
eatbytes(tk, tk->buffcount);
return TERMKEY_RES_KEY;
}
unsigned char cmd = CHARAT(introlen); unsigned char cmd = CHARAT(introlen);
@ -419,18 +448,30 @@ termkey_result termkey_getkey(termkey_t *tk, termkey_key *key)
if(b0 == 0x1b) { if(b0 == 0x1b) {
if(tk->buffcount == 1) { if(tk->buffcount == 1) {
// This might be an <Esc> press, or it may want to be part of a longer
// sequence
if(tk->waittime)
return TERMKEY_RES_AGAIN;
do_codepoint(tk, b0, key); do_codepoint(tk, b0, key);
eatbytes(tk, 1); eatbytes(tk, 1);
return TERMKEY_RES_KEY; return TERMKEY_RES_KEY;
} }
unsigned char b1 = CHARAT(1); unsigned char b1 = CHARAT(1);
if(b1 == '[') if(b1 == '[')
return getkey_csi(tk, 2, key); return getkey_csi(tk, 2, key);
if(b1 == 'O') if(b1 == 'O')
return getkey_ss3(tk, 2, key); return getkey_ss3(tk, 2, key);
if(b1 == 0x1b) {
do_codepoint(tk, b0, key);
eatbytes(tk, 1);
return TERMKEY_RES_KEY;
}
tk->buffstart++; tk->buffstart++;
termkey_result metakey_result = termkey_getkey(tk, key); termkey_result metakey_result = termkey_getkey(tk, key);
@ -503,7 +544,7 @@ termkey_result termkey_getkey(termkey_t *tk, termkey_key *key)
} }
if(tk->buffcount < nbytes) if(tk->buffcount < nbytes)
return TERMKEY_RES_NONE; return tk->waittime ? TERMKEY_RES_AGAIN : TERMKEY_RES_NONE;
for(int b = 1; b < nbytes; b++) { for(int b = 1; b < nbytes; b++) {
unsigned char cb = CHARAT(b); unsigned char cb = CHARAT(b);
@ -548,16 +589,53 @@ termkey_result termkey_getkey(termkey_t *tk, termkey_key *key)
return TERMKEY_SYM_NONE; return TERMKEY_SYM_NONE;
} }
termkey_result termkey_waitkey(termkey_t *tk, termkey_key *key) termkey_result termkey_getkey_force(termkey_t *tk, termkey_key *key)
{ {
termkey_result ret; int old_waittime = tk->waittime;
while((ret = termkey_getkey(tk, key)) == TERMKEY_RES_NONE) { tk->waittime = 0;
termkey_advisereadable(tk);
} termkey_result ret = termkey_getkey(tk, key);
tk->waittime = old_waittime;
return ret; return ret;
} }
termkey_result termkey_waitkey(termkey_t *tk, termkey_key *key)
{
while(1) {
termkey_result ret = termkey_getkey(tk, key);
switch(ret) {
case TERMKEY_RES_KEY:
case TERMKEY_RES_EOF:
return ret;
case TERMKEY_RES_NONE:
termkey_advisereadable(tk);
break;
case TERMKEY_RES_AGAIN:
{
struct pollfd fd;
fd.fd = tk->fd;
fd.events = POLLIN;
int pollres = poll(&fd, 1, tk->waittime);
if(pollres == 0)
return termkey_getkey_force(tk, key);
termkey_advisereadable(tk);
}
break;
}
}
/* UNREACHABLE */
}
void termkey_pushinput(termkey_t *tk, unsigned char *input, size_t inputlen) void termkey_pushinput(termkey_t *tk, unsigned char *input, size_t inputlen)
{ {
if(tk->buffstart + tk->buffcount + inputlen > tk->buffsize) { if(tk->buffstart + tk->buffcount + inputlen > tk->buffsize) {

View File

@ -110,7 +110,11 @@ enum {
termkey_t *termkey_new(int fd, int flags); termkey_t *termkey_new(int fd, int flags);
void termkey_free(termkey_t *tk); void termkey_free(termkey_t *tk);
void termkey_setwaittime(termkey_t *tk, int msec);
int termkey_getwaittime(termkey_t *tk);
termkey_result termkey_getkey(termkey_t *tk, termkey_key *key); termkey_result termkey_getkey(termkey_t *tk, termkey_key *key);
termkey_result termkey_getkey_force(termkey_t *tk, termkey_key *key);
termkey_result termkey_waitkey(termkey_t *tk, termkey_key *key); termkey_result termkey_waitkey(termkey_t *tk, termkey_key *key);
void termkey_pushinput(termkey_t *tk, unsigned char *input, size_t inputlen); void termkey_pushinput(termkey_t *tk, unsigned char *input, size_t inputlen);