1 #include <stdio.h>
2 #include <ctype.h>
3 #include <X11/Xlib.h>
4 #include <X11/Xutil.h>
5 #include <X11/keysym.h>
6
7 #include "ztypes.h"
8 #include "xio.h"
9
10 #define NUMCOMMANDS (768) /* 3*256 */
11
12 cmdentry *keycmds[NUMCOMMANDS];
13 char *keycmdargs[NUMCOMMANDS];
14
15 static cmdentry mastertable[] = {
16 {xted_insert, -1, 0, "insert-self"},
17 {xted_enter, op_Enter, 0, "enter"},
18
19 {xted_movecursor, op_ForeChar, 0, "forward-char"},
20 {xted_movecursor, op_BackChar, 0, "backward-char"},
21 {xted_movecursor, op_ForeWord, 0, "forward-word"},
22 {xted_movecursor, op_BackWord, 0, "backward-word"},
23 {xted_movecursor, op_ForeLine, 0, "forward-line"},
24 {xted_movecursor, op_BackLine, 0, "backward-line"},
25 {xted_movecursor, op_BeginLine, 0, "beginning-of-line"},
26 {xted_movecursor, op_EndLine, 0, "end-of-line"},
27
28 {xted_scroll, op_DownPage, 0, "scroll-down"},
29 {xted_scroll, op_UpPage, 0, "scroll-up"},
30 {xted_scroll, op_DownLine, 0, "scroll-down-line"},
31 {xted_scroll, op_UpLine, 0, "scroll-up-line"},
32 {xted_scroll, op_ToBottom, 0, "scroll-to-bottom"},
33 {xted_scroll, op_ToTop, 0, "scroll-to-top"},
34
35 {xted_delete, op_ForeChar, 0, "delete-next-char"},
36 {xted_delete, op_BackChar, 0, "delete-char"},
37 {xted_delete, op_ForeWord, 0, "delete-next-word"},
38 {xted_delete, op_BackWord, 0, "delete-word"},
39
40 {xted_cutbuf, op_Yank, 0, "yank"},
41 {xted_cutbuf, op_Wipe, 0, "kill-region"},
42 {xted_cutbuf, op_Copy, 0, "copy-region"},
43 {xted_cutbuf, op_YankReplace, 0, "yank-pop"},
44 {xted_cutbuf, op_Kill, 0, "kill-line"},
45 {xted_cutbuf, op_Untype, 0, "kill-input"},
46
47 {xted_history, op_BackLine, 0, "backward-history"},
48 {xted_history, op_ForeLine, 0, "forward-history"},
49
50 {xted_macro, -1, 0, "macro"},
51
52 {xtexted_meta, op_Cancel, 1, "cancel"},
53 {xtexted_meta, op_Escape, 1, "escape"},
54 {xtexted_meta, op_ExplainKey, 0, "explain-key"},
55 {xtexted_meta, op_DefineMacro, 0, "define-macro"},
56 {xtexted_redraw, op_Screen, 0, "redraw-screen"},
57 {xtexted_redraw, op_Status, 0, "redraw-status"},
58 {xtexted_redraw, op_AllWindows, 0, "redraw-all-windows"},
59 {xstat_reset_window_size, op_Zoom, 0, "zoom-status"},
60 {xstat_reset_window_size, op_Shrink, 0, "shrink-status"},
61 {xstat_reset_window_size, op_Clear, 0, "clear-status"},
62
63 {xted_noop, -1, 0, "no-op"},
64
65 {NULL, 0, 0, NULL}
66 };
67
68 typedef struct binding_t {
69 unsigned int key; /* or keysym */
70 int which; /* keytype_main, keytype_meta, keytype_sym */
71 char *name;
72 } binding;
73
74 static binding defaultbindings[] = {
75 {XK_Left, keytype_sym, "backward-char"},
76 {XK_KP_Left, keytype_sym, "backward-char"},
77 {XK_Right, keytype_sym, "forward-char"},
78 {XK_KP_Right, keytype_sym, "forward-char"},
79 {XK_Up, keytype_sym, "backward-history"},
80 {XK_KP_Up, keytype_sym, "backward-history"},
81 {XK_Down, keytype_sym, "forward-history"},
82 {XK_KP_Down, keytype_sym, "forward-history"},
83 {XK_Begin, keytype_sym, "beginning-of-line"},
84 {XK_KP_Begin, keytype_sym, "beginning-of-line"},
85 {XK_End, keytype_sym, "end-of-line"},
86 {XK_KP_End, keytype_sym, "end-of-line"},
87 {XK_Prior, keytype_sym, "scroll-up"},
88 {XK_KP_Prior, keytype_sym, "scroll-up"},
89 {XK_Next, keytype_sym, "scroll-down"},
90 {XK_KP_Next, keytype_sym, "scroll-down"},
91 {XK_Delete, keytype_sym, "delete-char"},
92 {XK_KP_Delete, keytype_sym, "delete-char"},
93 {XK_Help, keytype_sym, "explain-key"},
94
95 {'w', keytype_meta, "copy-region"},
96 {'y', keytype_meta, "yank-pop"},
97 {'b', keytype_meta, "backward-word"},
98 {'f', keytype_meta, "forward-word"},
99 {'v', keytype_meta, "scroll-up"},
100 {'d', keytype_meta, "delete-next-word"},
101 {'`', keytype_meta, "forward-history"},
102 {'=', keytype_meta, "backward-history"},
103 {'z', keytype_meta, "zoom-status"},
104 {'s', keytype_meta, "shrink-status"},
105 {'c', keytype_meta, "clear-status"},
106 {'r', keytype_meta, "define-macro"},
107 {'0', keytype_meta, "macro"},
108 {'1', keytype_meta, "macro"},
109 {'2', keytype_meta, "macro"},
110 {'3', keytype_meta, "macro"},
111 {'4', keytype_meta, "macro"},
112 {'5', keytype_meta, "macro"},
113 {'6', keytype_meta, "macro"},
114 {'7', keytype_meta, "macro"},
115 {'8', keytype_meta, "macro"},
116 {'9', keytype_meta, "macro"},
117
118 {'\177', keytype_meta, "delete-word"},
119 {'\010', keytype_meta, "delete-word"},
120
121 {'\007' /* ctrl-G */, keytype_main, "cancel"},
122 {'\033' /* Escape */, keytype_main, "escape"},
123 {'\007' /* ctrl-G */, keytype_meta, "cancel"},
124 {'\037' /* ctrl-_ */, keytype_main, "explain-key"},
125 #ifdef TESTING
126 {'\021' /* ctrl-Q */, keytype_main, "scroll-up-line"},
127 {'\032' /* ctrl-Z */, keytype_main, "scroll-down-line"},
128 #endif
129 {'\001' /* ctrl-A */, keytype_main, "beginning-of-line"},
130 {'\005' /* ctrl-E */, keytype_main, "end-of-line"},
131 {'\002' /* ctrl-B */, keytype_main, "backward-char"},
132 {'\006' /* ctrl-F */, keytype_main, "forward-char"},
133 {'\014' /* ctrl-L */, keytype_main, "redraw-all-windows"},
134 {'\031' /* ctrl-Y */, keytype_main, "yank"},
135 {'\027' /* ctrl-W */, keytype_main, "kill-region"},
136 {'\013' /* ctrl-K */, keytype_main, "kill-line"},
137 {'\025' /* ctrl-U */, keytype_main, "kill-input"},
138 {'\026' /* ctrl-V */, keytype_main, "scroll-down"},
139 {'\016' /* ctrl-N */, keytype_main, "forward-line"},
140 {'\020' /* ctrl-P */, keytype_main, "backward-line"},
141 {'\177' /* del */, keytype_main, "delete-char"},
142 {'\010' /* del */, keytype_main, "delete-char"},
143 {'\004' /* ctrl-D */, keytype_main, "delete-next-char"},
144 {'\n' /* newline */, keytype_main, "enter"},
145 {'\r' /* return */, keytype_main, "enter"},
146
147 {0, 0, NULL}
148 };
149
150 #ifdef __STDC__
151 static void parse_one_binding(char *key, char *proc, char *marg);
152 #else
153 static void parse_one_binding();
154 #endif
155
156 /* initialize key tables */
157 #ifdef __STDC__
xkey_init()158 void xkey_init()
159 #else
160 void xkey_init()
161 #endif
162 {
163 int ix, keynum;
164 cmdentry *cmd;
165 binding *bx;
166
167 for (ix=0; ix<NUMCOMMANDS; ix++) {
168 keycmds[ix] = NULL;
169 keycmdargs[ix] = NULL;
170 }
171
172 cmd = xkey_find_cmd_by_name("insert-self");
173 for (ix=' '; ix<='~'; ix++) {
174 keycmds[ix | keytype_main] = cmd;
175 }
176
177 for (bx=defaultbindings; bx->name; bx++) {
178 ix = (bx->key & 255);
179 cmd = xkey_find_cmd_by_name(bx->name);
180 if (!cmd) {
181 fprintf(stderr, "%s: unknown function <%s> in default bindings\n", PROGRAMNAME, bx->name);
182 }
183 else {
184 keynum = ix | bx->which;
185 if (keycmds[keynum]) {
186 fprintf(stderr, "%s: key <%s> (%d) defined twice in default bindings\n", PROGRAMNAME,
187 xkey_get_key_name(keynum), ix);
188 }
189 keycmds[keynum] = cmd;
190 }
191 }
192 }
193
194 #ifdef __STDC__
xkey_get_key_name(int key)195 char *xkey_get_key_name(int key)
196 #else
197 char *xkey_get_key_name(key)
198 int key;
199 #endif
200 {
201 static char buf[32];
202 char *prefix, *name;
203 int which;
204
205 which = key & keytype_Mask;
206 key = key & (~keytype_Mask);
207
208 if (which==keytype_sym) {
209 KeySym ksym = (KeySym)((XK_Home & (~255)) | key); /* I bet this is a stupid thing to do */
210 name = XKeysymToString(ksym);
211 if (!name)
212 name = "Unknown key";
213 strcpy(buf, name);
214 return buf;
215 }
216
217 if (which==keytype_meta)
218 prefix = "meta-";
219 else
220 prefix = "";
221
222 if (iscntrl(key)) {
223 sprintf(buf, "%sctrl-%c", prefix, key+'A'-1);
224 }
225 else {
226 sprintf(buf, "%s%c", prefix, key);
227 }
228
229 return buf;
230 }
231
232 /* parse stuff of the form key=proc-name;key=proc-name;...
233 Spaces are optional, c-X and m-X are abbreviations, /123 codes are accepted, and I'm getting a headache. */
234 #ifdef __STDC__
xkey_parse_bindings(char * str)235 void xkey_parse_bindings(char *str)
236 #else
237 void xkey_parse_bindings(str)
238 char *str;
239 #endif
240 {
241 char *cx, *cx2, *key, *proc, *marg;
242 char buf[64], nbuf[256], margbuf[256];
243 int escaped;
244 int keylen, proclen;
245 int hasmarg;
246
247 cx = str;
248 for (; *cx && isspace(*cx); cx++);
249 while (*cx) {
250
251 key = cx;
252
253 escaped = FALSE;
254 for (; *cx && *cx != '=' && !isspace(*cx); cx++) {
255 if (*cx == '\\' && *(cx+1) != '\0') {
256 cx++;
257 if (isdigit(*cx)) {
258 cx++;
259 if (isdigit(*cx)) {
260 cx++;
261 }
262 }
263 }
264 }
265 keylen = cx - key;
266 if (keylen >= sizeof(buf)) {
267 keylen = sizeof(buf)-1;
268 }
269 strncpy(buf, key, keylen);
270 buf[keylen] = '\0';
271 if (*cx == '\0') {
272 fprintf(stderr, "%s: binding for <%s> has no procedure\n", PROGRAMNAME, buf);
273 break;
274 }
275
276 for (; *cx && isspace(*cx); cx++);
277 if (*cx != '=') {
278 fprintf(stderr, "%s: unexpected '%c' instead of '=' after <%s>\n", PROGRAMNAME, *cx, buf);
279 break;
280 }
281 cx++; /* skip equals */
282 for (; *cx && isspace(*cx); cx++);
283 proc = cx;
284 for (; *cx && (*cx=='-' || isalnum(*cx)); cx++);
285 proclen = cx - proc;
286 if (proclen >= sizeof(nbuf)) {
287 proclen = sizeof(nbuf)-1;
288 }
289 strncpy(nbuf, proc, proclen);
290 nbuf[proclen] = '\0';
291
292 for (; *cx && isspace(*cx); cx++);
293 hasmarg = FALSE;
294 if (*cx == ',') {
295 cx++; /* skip comma */
296 for (; *cx && isspace(*cx); cx++);
297 if (*cx != '"') {
298 fprintf(stderr, "%s: unexpected '%c' instead of '\"' after ','\n", PROGRAMNAME, *cx);
299 break;
300 }
301 cx++; /* skip open-quote */
302 marg = cx;
303 for (; *cx && *cx!='\"'; cx++);
304 if (*cx == '\0') {
305 fprintf(stderr, "%s: unexpected end of string after '\"'\n", PROGRAMNAME);
306 break;
307 }
308 proclen = cx - marg;
309 if (proclen >= sizeof(margbuf)) {
310 proclen = sizeof(margbuf)-1;
311 }
312 strncpy(margbuf, marg, proclen);
313 margbuf[proclen] = '\0';
314 hasmarg = TRUE;
315
316 cx++; /* skip close-quote */
317 for (; *cx && isspace(*cx); cx++);
318 }
319
320 parse_one_binding(buf, nbuf, hasmarg ? margbuf : NULL);
321
322 if (*cx == '\0')
323 break;
324 if (*cx != ';') {
325 fprintf(stderr, "%s: unexpected '%c' instead of ';' after <%s>\n", PROGRAMNAME, *cx, nbuf);
326 break;
327 }
328 cx++; /* skip semicolon */
329 for (; *cx && isspace(*cx); cx++);
330 }
331
332 }
333
334 #ifdef __STDC__
parse_one_binding(char * key,char * proc,char * marg)335 static void parse_one_binding(char *key, char *proc, char *marg)
336 #else
337 static void parse_one_binding(key, proc, marg)
338 char *key;
339 char *proc;
340 char *marg;
341 #endif
342 {
343 cmdentry *cmd;
344 int ismeta = FALSE;
345 int isctrl = FALSE;
346 int keynum;
347 KeySym ksym;
348
349 cmd = xkey_find_cmd_by_name(proc);
350 if (!cmd) {
351 fprintf(stderr, "%s: unknown procedure <%s>\n", PROGRAMNAME, proc);
352 return;
353 }
354
355 while ((*key=='c' || *key=='C' || *key=='m' || *key=='M') && *(key+1)=='-') {
356 if (*key=='c' || *key=='C')
357 isctrl = TRUE;
358 else
359 ismeta = TRUE;
360 key += 2;
361 }
362 if (strlen(key)==1) {
363 keynum = (*key);
364 if (isctrl) {
365 if (islower(keynum))
366 keynum = toupper(keynum);
367 if (keynum >= 'A'-1)
368 keynum -= ('A'-1);
369 }
370 if (ismeta)
371 keynum |= keytype_meta;
372 }
373 else {
374 ksym = XStringToKeysym(key);
375 if (ksym==NoSymbol) {
376 fprintf(stderr, "%s: unknown key <%s>\n", PROGRAMNAME, key);
377 return;
378 }
379 if ((ksym & (~255)) == (XK_Home & (~255))) {
380 keynum = keytype_sym | (ksym & (255));
381 }
382 else if ((ksym & (~255)) == (XK_A & (~255))) {
383 keynum = keytype_main | (ksym & (255));
384 if (ismeta)
385 keynum |= keytype_meta;
386 }
387 else {
388 fprintf(stderr, "%s: unknown key <%s>\n", PROGRAMNAME, key);
389 return;
390 }
391 }
392
393 keycmds[keynum] = cmd;
394
395 if (keycmdargs[keynum]) {
396 free(keycmdargs[keynum]);
397 keycmdargs[keynum] = NULL;
398 }
399
400 if (marg) {
401 keycmdargs[keynum] = (char *)malloc(sizeof(char) * (1+strlen(marg)));
402 strcpy(keycmdargs[keynum], marg);
403 }
404 }
405
406 #ifdef __STDC__
xkey_find_cmd_by_name(char * str)407 cmdentry *xkey_find_cmd_by_name(char *str)
408 #else
409 cmdentry *xkey_find_cmd_by_name(str)
410 char *str;
411 #endif
412 {
413 cmdentry *retval;
414
415 for (retval = mastertable; retval->func; retval++) {
416 if (!strcmp(str, retval->name))
417 return retval;
418 }
419 return NULL;
420 }
421