Allow stacking drivers in a linked list; try all of them at getkey() time
This commit is contained in:
parent
aef2e91277
commit
73cee7f0b0
|
@ -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
|
||||||
|
|
87
termkey.c
87
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");
|
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,27 +565,38 @@ 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_AGAIN:
|
||||||
|
again = 1;
|
||||||
|
/* fallthrough */
|
||||||
case TERMKEY_RES_NONE:
|
case TERMKEY_RES_NONE:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(again)
|
||||||
|
return TERMKEY_RES_AGAIN;
|
||||||
|
|
||||||
ret = getkey_simple(tk, key, 0);
|
ret = getkey_simple(tk, key, 0);
|
||||||
|
|
||||||
|
@ -574,10 +615,13 @@ 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) {
|
||||||
|
@ -589,6 +633,7 @@ termkey_result termkey_getkey_force(termkey_t *tk, termkey_key *key)
|
||||||
case TERMKEY_RES_NONE:
|
case TERMKEY_RES_NONE:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ret = getkey_simple(tk, key, 1);
|
ret = getkey_simple(tk, key, 1);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue