aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul LeoNerd Evans <leonerd@leonerd.org.uk>2008-02-10 20:22:33 +0000
committerPaul LeoNerd Evans <leonerd@leonerd.org.uk>2008-02-10 20:22:33 +0000
commit31414eac3bbc40ac10a46a2f5c49ea87b216311a (patch)
tree1182d18aa1c7e2d8d85d2333033ea4e9b29ec26f
parentc71e1928a203855b10bc2524900fd00a48a8435e (diff)
downloadtermo-31414eac3bbc40ac10a46a2f5c49ea87b216311a.tar.gz
termo-31414eac3bbc40ac10a46a2f5c49ea87b216311a.tar.xz
termo-31414eac3bbc40ac10a46a2f5c49ea87b216311a.zip
Implement waittime polling to try to distinguish Esc, 1 from A-1, etc.. on slow terminals
-rw-r--r--termkey.c100
-rw-r--r--termkey.h4
2 files changed, 93 insertions, 11 deletions
diff --git a/termkey.c b/termkey.c
index 6f8b254..819b49f 100644
--- a/termkey.c
+++ b/termkey.c
@@ -1,6 +1,7 @@
#include "termkey.h"
#include <errno.h>
+#include <poll.h>
#include <unistd.h>
#include <string.h>
@@ -20,6 +21,8 @@ struct termkey {
size_t buffcount; // NUMBER of entires valid in buffer
size_t buffsize; // Total malloc'ed size
+ int waittime; // msec
+
char is_closed;
int nkeynames;
@@ -37,7 +40,7 @@ struct termkey {
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));
if(!tk)
@@ -75,6 +78,8 @@ termkey_t *termkey_new_full(int fd, int flags, size_t buffsize)
tk->buffcount = 0;
tk->buffsize = buffsize;
+ tk->waittime = waittime;
+
tk->is_closed = 0;
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)
{
- 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)
@@ -294,8 +309,15 @@ static termkey_result getkey_csi(termkey_t *tk, size_t introlen, termkey_key *ke
csi_end++;
}
- if(csi_end >= tk->buffcount)
- return TERMKEY_RES_NONE;
+ if(csi_end >= tk->buffcount) {
+ 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);
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)
{
- if(introlen + 1 < tk->buffcount)
- return TERMKEY_RES_NONE;
+ if(tk->buffcount < introlen + 1) {
+ 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);
@@ -419,18 +448,30 @@ termkey_result termkey_getkey(termkey_t *tk, termkey_key *key)
if(b0 == 0x1b) {
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);
eatbytes(tk, 1);
return TERMKEY_RES_KEY;
}
unsigned char b1 = CHARAT(1);
+
if(b1 == '[')
return getkey_csi(tk, 2, key);
if(b1 == 'O')
return getkey_ss3(tk, 2, key);
+ if(b1 == 0x1b) {
+ do_codepoint(tk, b0, key);
+ eatbytes(tk, 1);
+ return TERMKEY_RES_KEY;
+ }
+
tk->buffstart++;
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)
- return TERMKEY_RES_NONE;
+ return tk->waittime ? TERMKEY_RES_AGAIN : TERMKEY_RES_NONE;
for(int b = 1; b < nbytes; b++) {
unsigned char cb = CHARAT(b);
@@ -548,14 +589,51 @@ termkey_result termkey_getkey(termkey_t *tk, termkey_key *key)
return TERMKEY_SYM_NONE;
}
+termkey_result termkey_getkey_force(termkey_t *tk, termkey_key *key)
+{
+ int old_waittime = tk->waittime;
+ tk->waittime = 0;
+
+ termkey_result ret = termkey_getkey(tk, key);
+
+ tk->waittime = old_waittime;
+
+ return ret;
+}
+
termkey_result termkey_waitkey(termkey_t *tk, termkey_key *key)
{
- termkey_result ret;
- while((ret = termkey_getkey(tk, key)) == TERMKEY_RES_NONE) {
- termkey_advisereadable(tk);
+ 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;
+ }
}
- return ret;
+ /* UNREACHABLE */
}
void termkey_pushinput(termkey_t *tk, unsigned char *input, size_t inputlen)
diff --git a/termkey.h b/termkey.h
index 0cfacba..077afdc 100644
--- a/termkey.h
+++ b/termkey.h
@@ -110,7 +110,11 @@ enum {
termkey_t *termkey_new(int fd, int flags);
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_force(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);