aboutsummaryrefslogtreecommitdiff
path: root/termkey.c
diff options
context:
space:
mode:
authorPaul LeoNerd Evans <leonerd@leonerd.org.uk>2008-11-09 19:58:11 +0000
committerPaul LeoNerd Evans <leonerd@leonerd.org.uk>2008-11-09 19:58:11 +0000
commit73cee7f0b009c093aa1a49df907c2b8c001b4946 (patch)
tree6be62c9adc21c3be753c6068e57ee216062f85df /termkey.c
parentaef2e912773ca3669c45725f95226d0081c23046 (diff)
downloadtermo-73cee7f0b009c093aa1a49df907c2b8c001b4946.tar.gz
termo-73cee7f0b009c093aa1a49df907c2b8c001b4946.tar.xz
termo-73cee7f0b009c093aa1a49df907c2b8c001b4946.zip
Allow stacking drivers in a linked list; try all of them at getkey() time
Diffstat (limited to 'termkey.c')
-rw-r--r--termkey.c115
1 files changed, 80 insertions, 35 deletions
diff --git a/termkey.c b/termkey.c
index c28b5a7..75c436f 100644
--- a/termkey.c
+++ b/termkey.c
@@ -157,25 +157,38 @@ termkey_t *termkey_new_full(int fd, int flags, size_t buffsize, int waittime)
const char *term = getenv("TERM");
+ struct termkey_drivernode *tail = NULL;
+
for(i = 0; drivers[i]; i++) {
- void *driver_info = (*drivers[i]->new_driver)(tk, term);
- if(!driver_info)
+ void *info = (*drivers[i]->new_driver)(tk, term);
+ if(!info)
continue;
- tk->driver = *(drivers[i]);
- tk->driver_info = driver_info;
- break;
+#ifdef DEBUG
+ fprintf(stderr, "Loading the %s driver\n", drivers[i]->name);
+#endif
+
+ struct termkey_drivernode *thisdrv = malloc(sizeof(*thisdrv));
+ if(!thisdrv)
+ goto abort_free_drivers;
+
+ thisdrv->driver = drivers[i];
+ thisdrv->info = info;
+ thisdrv->next = NULL;
+
+ if(!tail)
+ tk->drivers = thisdrv;
+ else
+ tail->next = thisdrv;
+
+ tail = thisdrv;
}
- if(!tk->driver_info) {
+ if(!tk->drivers) {
fprintf(stderr, "Unable to find a terminal driver\n");
goto abort_free_keynames;
}
-#ifdef DEBUG
- fprintf(stderr, "Using the %s driver\n", tk->driver.name);
-#endif
-
if(!(flags & TERMKEY_FLAG_NOTERMIOS)) {
struct termios termios;
if(tcgetattr(fd, &termios) == 0) {
@@ -189,11 +202,21 @@ termkey_t *termkey_new_full(int fd, int flags, size_t buffsize, int waittime)
}
}
- if(tk->driver.start_driver)
- (*tk->driver.start_driver)(tk, tk->driver_info);
+ struct termkey_drivernode *p;
+ for(p = tk->drivers; p; p = p->next)
+ if(p->driver->start_driver)
+ (*p->driver->start_driver)(tk, p->info);
return tk;
+abort_free_drivers:
+ for(p = tk->drivers; p; ) {
+ (*p->driver->free_driver)(p->info);
+ struct termkey_drivernode *next = p->next;
+ free(p);
+ p = next;
+ }
+
abort_free_keynames:
free(tk->keynames);
@@ -216,16 +239,23 @@ void termkey_free(termkey_t *tk)
free(tk->buffer); tk->buffer = NULL;
free(tk->keynames); tk->keynames = NULL;
- (*tk->driver.free_driver)(tk->driver_info);
- tk->driver_info = NULL; /* Be nice to GC'ers, etc */
+ struct termkey_drivernode *p;
+ for(p = tk->drivers; p; ) {
+ (*p->driver->free_driver)(p->info);
+ struct termkey_drivernode *next = p->next;
+ free(p);
+ p = next;
+ }
free(tk);
}
void termkey_destroy(termkey_t *tk)
{
- if(tk->driver.stop_driver)
- (*tk->driver.stop_driver)(tk, tk->driver_info);
+ struct termkey_drivernode *p;
+ for(p = tk->drivers; p; p = p->next)
+ if(p->driver->stop_driver)
+ (*p->driver->stop_driver)(tk, p->info);
if(tk->restore_termios_valid)
tcsetattr(tk->fd, TCSANOW, &tk->restore_termios);
@@ -535,28 +565,39 @@ static const char *res2str(termkey_result res)
termkey_result termkey_getkey(termkey_t *tk, termkey_key *key)
{
+ int again = 0;
+
#ifdef DEBUG
fprintf(stderr, "getkey(): buffer ");
print_buffer(tk);
fprintf(stderr, "\n");
#endif
- termkey_result ret = (*tk->driver.getkey)(tk, tk->driver_info, key, 0);
+ termkey_result ret;
+ struct termkey_drivernode *p;
+ for(p = tk->drivers; p; p = p->next) {
+ ret = (p->driver->getkey)(tk, p->info, key, 0);
#ifdef DEBUG
- fprintf(stderr, "Driver %s yields %s\n", tk->driver.name, res2str(ret));
+ fprintf(stderr, "Driver %s yields %s\n", p->driver->name, res2str(ret));
#endif
- switch(ret) {
- case TERMKEY_RES_KEY:
- case TERMKEY_RES_EOF:
- case TERMKEY_RES_AGAIN:
- return ret;
-
- case TERMKEY_RES_NONE:
- break;
+ switch(ret) {
+ case TERMKEY_RES_KEY:
+ case TERMKEY_RES_EOF:
+ return ret;
+
+ case TERMKEY_RES_AGAIN:
+ again = 1;
+ /* fallthrough */
+ case TERMKEY_RES_NONE:
+ break;
+ }
}
+ if(again)
+ return TERMKEY_RES_AGAIN;
+
ret = getkey_simple(tk, key, 0);
#ifdef DEBUG
@@ -574,20 +615,24 @@ termkey_result termkey_getkey_force(termkey_t *tk, termkey_key *key)
fprintf(stderr, "\n");
#endif
- termkey_result ret = (*tk->driver.getkey)(tk, tk->driver_info, key, 1);
+ termkey_result ret;
+ struct termkey_drivernode *p;
+ for(p = tk->drivers; p; p = p->next) {
+ ret = (p->driver->getkey)(tk, p->info, key, 1);
#ifdef DEBUG
- fprintf(stderr, "Driver %s yields %s\n", tk->driver.name, res2str(ret));
+ fprintf(stderr, "Driver %s yields %s\n", p->driver->name, res2str(ret));
#endif
- switch(ret) {
- case TERMKEY_RES_KEY:
- case TERMKEY_RES_EOF:
- return ret;
+ switch(ret) {
+ case TERMKEY_RES_KEY:
+ case TERMKEY_RES_EOF:
+ return ret;
- case TERMKEY_RES_AGAIN:
- case TERMKEY_RES_NONE:
- break;
+ case TERMKEY_RES_AGAIN:
+ case TERMKEY_RES_NONE:
+ break;
+ }
}
ret = getkey_simple(tk, key, 1);