Allow stacking drivers in a linked list; try all of them at getkey() time

This commit is contained in:
Paul LeoNerd Evans 2008-11-09 19:58:11 +00:00
parent aef2e91277
commit 73cee7f0b0
2 changed files with 87 additions and 36 deletions

View File

@ -23,6 +23,13 @@ struct keyinfo {
int modifier_set; int modifier_set;
}; };
struct termkey_drivernode;
struct termkey_drivernode {
struct termkey_driver *driver;
void *info;
struct termkey_drivernode *next;
};
struct termkey { struct termkey {
int fd; int fd;
int flags; int flags;
@ -44,8 +51,7 @@ struct termkey {
// There are 32 C0 codes // There are 32 C0 codes
struct keyinfo c0[32]; struct keyinfo c0[32];
struct termkey_driver driver; struct termkey_drivernode *drivers;
void *driver_info;
// Now some "protected" methods for the driver to call but which we don't // Now some "protected" methods for the driver to call but which we don't
// want exported as real symbols in the library // want exported as real symbols in the library

113
termkey.c
View File

@ -157,25 +157,38 @@ termkey_t *termkey_new_full(int fd, int flags, size_t buffsize, int waittime)
const char *term = getenv("TERM"); const char *term = getenv("TERM");
struct termkey_drivernode *tail = NULL;
for(i = 0; drivers[i]; i++) { for(i = 0; drivers[i]; i++) {
void *driver_info = (*drivers[i]->new_driver)(tk, term); void *info = (*drivers[i]->new_driver)(tk, term);
if(!driver_info) if(!info)
continue; continue;
tk->driver = *(drivers[i]); #ifdef DEBUG
tk->driver_info = driver_info; fprintf(stderr, "Loading the %s driver\n", drivers[i]->name);
break; #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"); fprintf(stderr, "Unable to find a terminal driver\n");
goto abort_free_keynames; goto abort_free_keynames;
} }
#ifdef DEBUG
fprintf(stderr, "Using the %s driver\n", tk->driver.name);
#endif
if(!(flags & TERMKEY_FLAG_NOTERMIOS)) { if(!(flags & TERMKEY_FLAG_NOTERMIOS)) {
struct termios termios; struct termios termios;
if(tcgetattr(fd, &termios) == 0) { 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) struct termkey_drivernode *p;
(*tk->driver.start_driver)(tk, tk->driver_info); for(p = tk->drivers; p; p = p->next)
if(p->driver->start_driver)
(*p->driver->start_driver)(tk, p->info);
return tk; 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: abort_free_keynames:
free(tk->keynames); free(tk->keynames);
@ -216,16 +239,23 @@ void termkey_free(termkey_t *tk)
free(tk->buffer); tk->buffer = NULL; free(tk->buffer); tk->buffer = NULL;
free(tk->keynames); tk->keynames = NULL; free(tk->keynames); tk->keynames = NULL;
(*tk->driver.free_driver)(tk->driver_info); struct termkey_drivernode *p;
tk->driver_info = NULL; /* Be nice to GC'ers, etc */ for(p = tk->drivers; p; ) {
(*p->driver->free_driver)(p->info);
struct termkey_drivernode *next = p->next;
free(p);
p = next;
}
free(tk); free(tk);
} }
void termkey_destroy(termkey_t *tk) void termkey_destroy(termkey_t *tk)
{ {
if(tk->driver.stop_driver) struct termkey_drivernode *p;
(*tk->driver.stop_driver)(tk, tk->driver_info); 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) if(tk->restore_termios_valid)
tcsetattr(tk->fd, TCSANOW, &tk->restore_termios); 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) termkey_result termkey_getkey(termkey_t *tk, termkey_key *key)
{ {
int again = 0;
#ifdef DEBUG #ifdef DEBUG
fprintf(stderr, "getkey(): buffer "); fprintf(stderr, "getkey(): buffer ");
print_buffer(tk); print_buffer(tk);
fprintf(stderr, "\n"); fprintf(stderr, "\n");
#endif #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 #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 #endif
switch(ret) { switch(ret) {
case TERMKEY_RES_KEY: case TERMKEY_RES_KEY:
case TERMKEY_RES_EOF: case TERMKEY_RES_EOF:
case TERMKEY_RES_AGAIN: return ret;
return ret;
case TERMKEY_RES_NONE: case TERMKEY_RES_AGAIN:
break; again = 1;
/* fallthrough */
case TERMKEY_RES_NONE:
break;
}
} }
if(again)
return TERMKEY_RES_AGAIN;
ret = getkey_simple(tk, key, 0); ret = getkey_simple(tk, key, 0);
#ifdef DEBUG #ifdef DEBUG
@ -574,20 +615,24 @@ termkey_result termkey_getkey_force(termkey_t *tk, termkey_key *key)
fprintf(stderr, "\n"); fprintf(stderr, "\n");
#endif #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 #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 #endif
switch(ret) { switch(ret) {
case TERMKEY_RES_KEY: case TERMKEY_RES_KEY:
case TERMKEY_RES_EOF: case TERMKEY_RES_EOF:
return ret; return ret;
case TERMKEY_RES_AGAIN: case TERMKEY_RES_AGAIN:
case TERMKEY_RES_NONE: case TERMKEY_RES_NONE:
break; break;
}
} }
ret = getkey_simple(tk, key, 1); ret = getkey_simple(tk, key, 1);