Implement waittime polling to try to distinguish Esc, 1 from A-1, etc.. on slow terminals
This commit is contained in:
		
							parent
							
								
									c71e1928a2
								
							
						
					
					
						commit
						31414eac3b
					
				
							
								
								
									
										102
									
								
								termkey.c
									
									
									
									
									
								
							
							
						
						
									
										102
									
								
								termkey.c
									
									
									
									
									
								
							| @ -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) { | ||||||
|  | |||||||
| @ -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); | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user