#include /* $Log: inkey.c,v $ /* Revision 1.1.1.1 2000/12/16 20:45:31 stuart /* Released TUIPeer sources /* Recognize function key strings. Copyright 1989,1990 Business Management Systems, Inc. Author: Stuart D. Gathman TODO - We could eliminate the nxt field by allocating each branch as an array. The brn field could be a short if we make the whole table a big array. This could be done efficiently (without a lot of realloc's) if the input strings were available as a sorted group. Since input strings are null-terminated, it follows that null characters cannot be matched. Our algorithm doesn't need null terminators, but that is the way the strings come from terminfo... We can distinguish strings when one is a prefix of another. We do this by matching the last character of the short string only if Kready() returns false. This allows ESC, for instance, to be recognized even when some functions keys start with ESC. This also allows us to recognize the null string. This can be useful for returning a special keycode whenever the user stops typing. We make the null string a special case and never match it more than once in a row. */ #include #include "pscreen.h" #include struct keynode { union { int fxn; /* function id if top of tree */ struct keynode *brn; /* pointer to next level otherwise */ } match; /* used for recognizer success */ struct keynode *nxt; /* next node on branch, used for failure */ unsigned char ch; /* character or val index at this node */ char type; /* match type */ }; enum { TOP = 0x20, /* top of tree if set */ RDY = 0x10 /* match only if !Kready() */ }; enum { MAXNODE = 100 }; struct memnode { struct memnode *next; struct keynode mem[MAXNODE]; } *mem; static struct keynode *addnode(void) { static int cnt = 0; struct memnode *p; if (!mem || cnt >= MAXNODE) { p = (struct memnode *)malloc(sizeof *mem); if (!p) return 0; p->next = mem; mem = p; cnt = 0; } else p = mem; return &p->mem[cnt++]; } static struct keynode *root; /* our private function string tree */ static int nullfxn = 0; int Kdefine(const char *str,int id) { /* add string to function tree */ struct keynode **prevptr, *p, *curptr; if (*str == 0) { /* caller want's to know about no input */ nullfxn = id; return 0; } prevptr = &root; /* start at root of tree */ while ((curptr = *prevptr) != 0) { /* follow existing tree */ if (curptr->ch == (unsigned char)*str) { if (*++str==0) { /* next character */ if (curptr->type&TOP) { curptr->match.fxn = id; /* replace entry */ return 0; } p = addnode(); if (p == 0) return -1; *prevptr = p; p->nxt = curptr; p->ch = str[-1]; p->type = TOP+RDY; /* short duplicate */ p->match.fxn = id; return 0; } if (curptr->type&TOP) { curptr->type = TOP+RDY; /* long duplicate */ prevptr = &curptr->nxt; curptr = *prevptr; --str; break; } prevptr = &curptr->match.brn; /* continue next level */ } else if (curptr->ch > (unsigned char)*str) break; else prevptr = &curptr->nxt; /* continue down branch */ } do { p = addnode(); if (p == 0) return -1; *prevptr = p; p->nxt = curptr; p->ch = *str; p->type = 0; prevptr = &p->match.brn; curptr = 0; } while (*str && *++str); /* install remainder of sequence */ p->type |= TOP; p->match.fxn = id; /* install tree top */ return 0; /* normal return */ } int Kget(void) { /* recognize character sequences defined by Kdefine */ int c; /* current input character */ static struct keynode *ptr = 0; /* current node of tree */ static short lev = 0; /* number of levels traveled */ for (;;) { if (ptr == 0) { ptr = root; /* start at root of tree */ lev = 0; if (nullfxn && !Kready()) return nullfxn; /* keycode for null string */ } c=Kgetc(); if (c < 0) return c; /* pass through signal */ do { if (ptr->ch == c && (ptr->type&RDY) && !Kready()) { napms(100); } if (ptr->ch == c && (!(ptr->type&RDY) || !Kready())) { /* character matches */ if (ptr->type&TOP) { lev = 0; c = ptr->match.fxn; ptr = 0; return c; /* return function value if tree top */ } ptr=ptr->match.brn; /* branch to next level */ ++lev; c = Kgetc(); /* get next character in sequence */ if (c < 0) return c; /* pass through signal */ } else if (ptr->ch > c) { ptr = 0; break; } else ptr=ptr->nxt; /* no match: continue along branch */ } while (ptr); if (lev == 0) return c; /* return normal character */ PSbeep(1); /* signal error */ } } short fskey;