|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: T t
Length: 9847 (0x2677) Types: TextFile Names: »ttykbd.c«
└─⟦a0efdde77⟧ Bits:30001252 EUUGD11 Tape, 1987 Spring Conference Helsinki └─⟦this⟧ »EUUGD11/euug-87hel/sec1/micrognu/tty/termcap/ttykbd.c«
/* * Name: MicroEmacs * Version: 30 * Termcap keyboard driver * Created: 21-Aug-1986 * Mic Kaczmarczik ...!ihnp4!seismo!ut-sally!ut-ngp!mic * Last edit: 03-Sep-86 * * [ Several of the nasty comments about the XKEYS code are * by me. [Bob Larson (usc-oberon!blarson)] It is my opinion * that function keys cannot be made to work with standard * emacs keybindings except on a very limited set of terminals. * I just work with to many that do not fit the assumptions Mic's * XKEYS code makes to consider it useful to me, and think that * others considering using this code should look and see what * it realy does first. * ] * * If XKEYS is defined this routine looks for the following * termcap sequences, which are obtained by "tty.c": * * ks -- start using the function keypad * ke -- finish using the function keypad * kh -- home key * ku -- up arrow * kd -- down arrow * kl -- left arrow * kr -- right arrow * k0-k9 -- standard termcap function keys * l0-l9 -- labels for termcap function keys * (nonstandard) * K0-K9 -- extra keys that we look for -- the get mapped * internally to F10-F19 * L0-L9 -- labels for same. * * Bugs/features/problems: * * XKEYS and DPROMPT do not work together well. * * If the META introducer is used as the initial character of * a function key sequence, what should the key parser do when the * user wants to type a META-ed key, or just the META introducer * alone? This is of practical importance on DEC terminals, where * the META introducer is the Escape key. Even worse things happen * on terminals that have something (or more than one thing) other * than the META introducer as the inital character of a function * sequence. * * The approach I took was that if the META introducer is the first * character in a function sequence, and the second character c * isn't part of a function key sequence, the parser returns * (KMETA | c). If it sees two META introducers in a row, it * returns one instance of METACH. This approach is subject to * discussion and debate, but it works. [In at lease some cases.] * * If the META introducer is NOT the first character in a function * sequence (including arrow keys) this code has a very nasty * side effect of eating that key. For example, on an Adds viewpoint * 60, six normal control characters are eaten if you have defined * XKEYS and put the keys in the termcap. More than a little * creativity is needed because ^U is one of the arrow keys, and * prefixes aren't bindable. * * [ From a quick look at the code, it seems that a single character * funciton key won't work, but it is still put in the table. * ] */ #include "def.h" /* * Default key name table. Can be overridden by * definitions of l0-l9 in the termcap entry. You * can't redefine the names for the arrow keys * and the home key. */ #ifdef XKEYS /* key sequences (from tty.c) */ extern char *K[], *L[], *KS, *KE, *KH, *KU, *KD, *KL, *KR; extern int putpad(); /* also from tty.c */ char *keystrings[] = { NULL, "Home", "Down-Arrow", "Up-Arrow", "Left-Arrow", "Right-Arrow", "F0", "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "F10", "F11", "F12", "F13", "F14", "F15", "F16", "F17", "F18", "F19", NULL, NULL, NULL, NULL, NULL, NULL }; #else char *keystrings[] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; #endif #ifdef XKEYS /* * Type declarations for data structure we * use to parse for function key sequences */ #define NODE 0 /* internal node */ #define VALUE 1 /* internal key code value */ #define SENTINEL 2 /* sentinel value */ typedef struct trienode { int type; /* one of NODE, LEAF */ struct trienode *sibling, *child; KEY value; } TRIENODE, *TRIE; TRIE keywords, sentinel, talloc(), tinsert(); #endif /* * Get keyboard character, and interpret * any special keys on the keyboard. If XKEYS is * #defined, use a dictionary organized as a * trie to keep the parsing overhead down. * * To keep the function call overhead down, do the * first level of parse() inside getkbd(). * * Also, since ESC (the usual value of METACH) is * the first character in many function key sequences, * we return (KMETA | ch) if METACH-<ch> is not * the start of an escape sequence. Blecch. Furthermore, * if we see METACH-METACH, we return the value METACH. * Phhhht. */ getkbd() { #ifndef XKEYS return (ttgetc()); #else register TRIE t; register int c; KEY code; c = ttgetc(); for (t = keywords; t->type == NODE; t = t->sibling) if (t->value == c) { /* possible function key sequence */ if (c != METACH) return (parse(t->child)); else { /* maybe sequence, maybe META char */ c = ttgetc(); for (t = t->child; t->type == NODE; t = t->sibling) if (t->value == c) return (parse(t->child)); /* METACH-METACH -> METACH */ if (c == METACH) return (METACH); /* Else make c into a META character */ if (ISLOWER(c) != FALSE) c = TOUPPER(c); if (c>=0x00 && c<=0x1F) c = KCTRL | (c+'@'); return (KMETA | c); } } return (c); #endif } #ifdef XKEYS static parse(first) TRIE first; { register TRIE t; register int c; if (first->type == VALUE) /* found a match! */ return (first->value); c = ttgetc(); for (t = first; t->type == NODE; t = t->sibling)/* look thru list */ if (t->value == c) return (parse(t->child)); /* try next level */ return (c); /* nothing matched */ } #endif /* * If XKEYS is defined, get key definitions from the termcap * entry and put them in the parse table. */ ttykeymapinit() { #ifdef XKEYS register int i; register int s; register char *cp; register SYMBOL *sp; if (KS && *KS) /* turn on keypad */ putpad(KS); tinit(); /* set up initial trie */ for (i = 0; i < NFKEYS; i++) { if (K[i] && *K[i]) adddict(K[i], (KEY) (KF0 + i)); if (L[i] && *L[i]) /* record new name */ keystrings[(KF0-KFIRST)+i] = L[i]; } /* * Add the home and arrow keys */ if (KH && *KH) adddict(KH, (KEY) KHOME); if (KU && *KU) adddict(KU, (KEY) KUP); if (KD && *KD) adddict(KD, (KEY) KDOWN); if (KL && *KL) adddict(KL, (KEY) KLEFT); if (KR && *KR) adddict(KR, (KEY) KRIGHT); /* * Bind things to the movement keys */ keydup(KHOME, "beginning-of-buffer"); /* for now */ keydup(KUP, "previous-line"); keydup(KDOWN, "next-line"); keydup(KLEFT, "backward-char"); keydup(KRIGHT, "forward-char"); /* * These bindings sort of go with the termcap I use for my vt220 * clone, which is why they're #ifdef'd. I don't really use * them, but it gives you an example of what to do... */ #ifdef MPK keydup((KEY)KF0, "describe-key-briefly"); /* Help */ keydup((KEY)KF1, "execute-extended-command"); /* Do */ keydup((KEY)KF2, "search-forward"); /* Find */ keydup((KEY)KF3, "yank"); /* Insert here */ keydup((KEY)KF4, "kill-region"); /* Remove */ keydup((KEY)KF5, "set-mark-command"); /* Select */ keydup((KEY)KF6, "scroll-down"); /* Prev Screen */ keydup((KEY)KF7, "scroll-up"); /* Next Screen */ /* Don't expect these to make much sense, I'm just filling in */ /* the keymap B-] */ keydup((KEY)KF10, "suspend-emacs"); /* PF1 */ keydup((KEY)KF11, "query-replace"); /* PF2 */ keydup((KEY)KF12, "call-last-kbd-macro"); /* PF3 */ keydup((KEY)KF13, "save-buffers-kill-emacs"); /* PF4 */ #endif MPK #endif XKEYS } #ifdef XKEYS /* * Clean up the keyboard -- called by tttidy() */ ttykeymaptidy() { tdelete(keywords); /* get rid of parse tree */ free(sentinel); /* remove sentinel value */ if (KE && *KE) putpad(KE); /* turn off keypad */ } /* * * * * * * * * Dictionary management * * * * * * * * * */ /* * Add a key string to the dictionary. */ static adddict(kstr, kcode) char *kstr; KEY kcode; { keywords = tinsert(kstr, kcode, keywords); } /* * Initialize the parse tree by creating the sentinel value */ static tinit() { keywords = sentinel = talloc(); sentinel->type = SENTINEL; sentinel->value = (KEY) -1; sentinel->sibling = sentinel->child = sentinel; /* set up a loop */ } /* * Deallocate all the space used by the trie -- * Tell all the siblings to deallocate space, then * all the children. */ static tdelete(t) register TRIE t; { if (t->type != SENTINEL) { tdelete(t->sibling); tdelete(t->child); free(t); } } /* * Insert a dictionary key string and a value into the dictionary, * returning as the value the first sibling in the current sublevel, * which may have been changed by an insertion into the list of siblings. */ static TRIE tinsert(kstring, kcode, first) register char *kstring; register KEY kcode; TRIE first; { register TRIE match; register TRIE p; if (!*kstring) { /* base case -- return a value node */ p = talloc(); p->type = VALUE; p->value = kcode; p->sibling = p->child = sentinel; return (p); } /* recursive case -- insert rest of string in trie */ /* search for sibling that matches the current character */ match = NULL; for (p = first; p->type == NODE; p = p->sibling) if (p->value == *kstring) { match = p; break; } if (match == NULL) { /* if not, add it to beginning of the list */ match = talloc(); match->type = NODE; match->value = *kstring; match->sibling = first; match->child = sentinel; first = match; } /* add rest of string to this child's subtrie */ match->child = tinsert(kstring+1, kcode, match->child); return (first); } /* * Allocate a trie node */ static TRIE talloc() { char *malloc(); TRIE t; if ((t = (TRIE) malloc(sizeof(TRIENODE))) == NULL) panic("talloc: can't allocate trie node!"); return (t); } #endif