My hex editor `axe' has existed in prototype for about ten years,
[sgt/tweak] / keytab.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <ctype.h>
4
5 #include "tweak.h"
6
7 typedef union keytab keytab;
8
9 union keytab {
10 enum {ACTION, EXTENDED} type;
11 struct {
12 int type;
13 keyact action;
14 } a;
15 struct {
16 int type;
17 keytab *extended[256];
18 } e;
19 };
20
21 keytab *base[256] = { NULL256 };
22
23 /*
24 * Bind a key sequence to an action.
25 */
26 void bind_key (char *sequence, int len, keyact action) {
27 keytab *(*table)[256];
28 int k, i;
29
30 table = &base;
31 while (--len) {
32 k = (unsigned char) *sequence++;
33 if ( !(*table)[k] ) {
34 /*
35 * We must create an EXTENDED entry.
36 */
37 (*table)[k] = malloc(sizeof(base[0]->e));
38 (*table)[k]->type = EXTENDED;
39 for (i=0; i<256; i++)
40 (*table)[k]->e.extended[i] = NULL;
41 } else if ( (*table)[k]->type == ACTION ) {
42 /*
43 * A subsequence is already bound: fail.
44 */
45 return;
46 }
47 table = &(*table)[k]->e.extended;
48 }
49 k = (unsigned char) *sequence;
50 if ( !(*table)[k] ) {
51 /*
52 * We can bind the key.
53 */
54 (*table)[k] = malloc(sizeof(base[0]->a));
55 (*table)[k]->type = ACTION;
56 (*table)[k]->a.action = action;
57 }
58 }
59
60 /*
61 * Format an ASCII code into a printable description of the key stroke.
62 */
63 static void strkey (char *s, int k) {
64 k &= 255; /* force unsigned */
65 if (k==27)
66 strcpy(s, " ESC");
67 else if (k<32 || k==127)
68 sprintf(s, " ^%c", k ^ 64);
69 else if (k<127)
70 sprintf(s, " %c", k);
71 else
72 sprintf(s, " <0x%2X>", k);
73 }
74
75 /*
76 * Get and process a key stroke.
77 */
78 void proc_key (void) {
79 keytab *kt;
80
81 #if defined(unix) && !defined(GO32)
82 if (update_required)
83 update();
84 safe_update = TRUE;
85 #endif
86 last_char = display_getkey();
87 #if defined(unix) && !defined(GO32)
88 safe_update = FALSE;
89 #endif
90 strcpy(message, "Unknown key sequence");
91 strkey(message+strlen(message), last_char);
92 kt = base[(unsigned char) last_char];
93 if (!kt) {
94 display_beep();
95 while (display_input_to_flush())
96 strkey(message+strlen(message), display_getkey());
97 return;
98 }
99
100 while (kt->type == EXTENDED) {
101 #if defined(unix) && !defined(GO32)
102 if (update_required)
103 update();
104 safe_update = TRUE;
105 #endif
106 last_char = display_getkey();
107 #if defined(unix) && !defined(GO32)
108 safe_update = FALSE;
109 #endif
110 strkey(message+strlen(message), last_char);
111 kt = kt->e.extended[(unsigned char) last_char];
112 if (!kt) {
113 display_beep();
114 while (display_input_to_flush())
115 strkey(message+strlen(message), display_getkey());
116 return;
117 }
118 }
119 message[0] = '\0'; /* clear the "unknown" message */
120 (*kt->a.action)();
121 }