File: | handle.c |
Location: | line 654, column 2 |
Description: | Potential leak of memory pointed to by 'kslist' |
1 | /* | |||||
2 | ||||||
3 | Copyright 1988, 1998 The Open Group | |||||
4 | ||||||
5 | Permission to use, copy, modify, distribute, and sell this software and its | |||||
6 | documentation for any purpose is hereby granted without fee, provided that | |||||
7 | the above copyright notice appear in all copies and that both that | |||||
8 | copyright notice and this permission notice appear in supporting | |||||
9 | documentation. | |||||
10 | ||||||
11 | The above copyright notice and this permission notice shall be included | |||||
12 | in all copies or substantial portions of the Software. | |||||
13 | ||||||
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS | |||||
15 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | |||||
16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. | |||||
17 | IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR | |||||
18 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | |||||
19 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | |||||
20 | OTHER DEALINGS IN THE SOFTWARE. | |||||
21 | ||||||
22 | Except as contained in this notice, the name of The Open Group shall | |||||
23 | not be used in advertising or otherwise to promote the sale, use or | |||||
24 | other dealings in this Software without prior written authorization | |||||
25 | from The Open Group. | |||||
26 | ||||||
27 | */ | |||||
28 | ||||||
29 | #ifdef HAVE_CONFIG_H1 | |||||
30 | #include "config.h" | |||||
31 | #endif | |||||
32 | ||||||
33 | #include <X11/Xos.h> | |||||
34 | #include <X11/Xlib.h> | |||||
35 | #include <stdio.h> | |||||
36 | #include <ctype.h> | |||||
37 | #include "xmodmap.h" | |||||
38 | #include "wq.h" | |||||
39 | #include <stdlib.h> | |||||
40 | ||||||
41 | #ifdef HAVE_STRNCASECMP1 | |||||
42 | #include <strings.h> | |||||
43 | #endif | |||||
44 | ||||||
45 | static XModifierKeymap *map = NULL((void*)0); | |||||
46 | ||||||
47 | ||||||
48 | /* | |||||
49 | * The routines in this file manipulate a queue of intructions. Instead of | |||||
50 | * executing each line as it is entered, we build up a list of actions to | |||||
51 | * take and execute them all at the end. This allows us to find all errors | |||||
52 | * at once, and to preserve the context in which we are looking up keysyms. | |||||
53 | */ | |||||
54 | ||||||
55 | struct wq work_queue = {NULL((void*)0), NULL((void*)0)}; | |||||
56 | ||||||
57 | ||||||
58 | /* | |||||
59 | * common utility routines | |||||
60 | */ | |||||
61 | ||||||
62 | static KeyCode * | |||||
63 | KeysymToKeycodes(Display *dpy, KeySym keysym, int *pnum_kcs) | |||||
64 | { | |||||
65 | KeyCode *kcs = NULL((void*)0); | |||||
66 | int i, j; | |||||
67 | ||||||
68 | *pnum_kcs = 0; | |||||
69 | for (i = min_keycode; i <= max_keycode; i++) { | |||||
70 | for (j = 0; j < 8; j++) { | |||||
71 | if (XKeycodeToKeysym(dpy, (KeyCode) i, j) == keysym) { | |||||
72 | if (!kcs) | |||||
73 | kcs = malloc(sizeof(KeyCode)); | |||||
74 | else | |||||
75 | kcs = realloc(kcs, sizeof(KeyCode) * (*pnum_kcs + 1)); | |||||
76 | kcs[*pnum_kcs] = i; | |||||
77 | *pnum_kcs += 1; | |||||
78 | break; | |||||
79 | } | |||||
80 | } | |||||
81 | } | |||||
82 | return kcs; | |||||
83 | } | |||||
84 | ||||||
85 | static char * | |||||
86 | copy_to_scratch(const char *s, int len) | |||||
87 | { | |||||
88 | static char *buf = NULL((void*)0); | |||||
89 | static int buflen = 0; | |||||
90 | ||||||
91 | if (len < 0) | |||||
92 | len = 0; | |||||
93 | ||||||
94 | if (len >= buflen) { | |||||
95 | if (buf) free (buf); | |||||
96 | buflen = (len < 40) ? 80 : (len * 2); | |||||
97 | buf = malloc (buflen+1); | |||||
98 | if (!buf) { | |||||
99 | fprintf (stderr__stderrp, "attempt to allocate %d byte scratch buffer\n", buflen + 1); | |||||
100 | return NULL((void*)0); | |||||
101 | } | |||||
102 | } | |||||
103 | ||||||
104 | strncpy (buf, s, len)__builtin___strncpy_chk (buf, s, len, __builtin_object_size ( buf, 2 > 1 ? 1 : 0)); | |||||
105 | buf[len] = '\0'; | |||||
106 | ||||||
107 | return (buf); | |||||
108 | } | |||||
109 | ||||||
110 | static void | |||||
111 | badheader(void) | |||||
112 | { | |||||
113 | fprintf (stderr__stderrp, "%s: %s:%d: bad ", ProgramName, inputFilename, lineno+1); | |||||
114 | parse_errors++; | |||||
115 | } | |||||
116 | ||||||
117 | #define badmsg0(what){ badheader(); fprintf (__stderrp, what); putc ('\n', __stderrp ); } { badheader(); fprintf (stderr__stderrp, what); \ | |||||
118 | putc ('\n', stderr__stderrp); } | |||||
119 | ||||||
120 | #define badmsg(what,arg){ badheader(); fprintf (__stderrp, what, arg); putc ('\n', __stderrp ); } { badheader(); fprintf (stderr__stderrp, what, arg); \ | |||||
121 | putc ('\n', stderr__stderrp); } | |||||
122 | ||||||
123 | #define badmsgn(what,s,len){ badheader(); fprintf (__stderrp, what, copy_to_scratch (s, len )); putc ('\n', __stderrp); } badmsg (what, copy_to_scratch (s, len)){ badheader(); fprintf (__stderrp, what, copy_to_scratch (s, len )); putc ('\n', __stderrp); } | |||||
124 | ||||||
125 | void | |||||
126 | initialize_map (void) | |||||
127 | { | |||||
128 | map = XGetModifierMapping (dpy); | |||||
129 | return; | |||||
130 | } | |||||
131 | ||||||
132 | static void do_keycode ( char *line, int len ); | |||||
133 | static void do_keysym ( char *line, int len ); | |||||
134 | static void finish_keycodes ( const char *line, int len, KeyCode *keycodes, | |||||
135 | int count ); | |||||
136 | static void do_add ( char *line, int len ); | |||||
137 | static void do_remove ( char *line, int len ); | |||||
138 | static void do_clear ( char *line, int len ); | |||||
139 | static void do_pointer ( char *line, int len ); | |||||
140 | static int get_keysym_list ( const char *line, int len, int *np, KeySym **kslistp ); | |||||
141 | ||||||
142 | static void print_opcode(union op *op); | |||||
143 | ||||||
144 | static int skip_word ( const char *s, int len ); | |||||
145 | static int skip_chars ( const char *s, int len ); | |||||
146 | static int skip_space ( const char *s, int len ); | |||||
147 | ||||||
148 | static struct dt { | |||||
149 | const char *command; /* name of input command */ | |||||
150 | int length; /* length of command */ | |||||
151 | void (*proc)(char *, int); /* handler */ | |||||
152 | } dispatch_table[] = { | |||||
153 | { "keycode", 7, do_keycode }, | |||||
154 | { "keysym", 6, do_keysym }, | |||||
155 | { "add", 3, do_add }, | |||||
156 | { "remove", 6, do_remove }, | |||||
157 | { "clear", 5, do_clear }, | |||||
158 | { "pointer", 7, do_pointer }, | |||||
159 | { NULL((void*)0), 0, NULL((void*)0) }}; | |||||
160 | ||||||
161 | /* | |||||
162 | * handle_line - this routine parses the input line (which has had all leading | |||||
163 | * and trailing whitespace removed) and builds up the work queue. | |||||
164 | */ | |||||
165 | ||||||
166 | void | |||||
167 | handle_line(char *line, /* string to parse */ | |||||
168 | int len) /* length of line */ | |||||
169 | { | |||||
170 | int n; | |||||
171 | struct dt *dtp; | |||||
172 | ||||||
173 | n = skip_chars (line, len); | |||||
174 | if (n < 0) { | |||||
175 | badmsg ("input line '%s'", line){ badheader(); fprintf (__stderrp, "input line '%s'", line); putc ('\n', __stderrp); }; | |||||
176 | return; | |||||
177 | } | |||||
178 | ||||||
179 | for (dtp = dispatch_table; dtp->command != NULL((void*)0); dtp++) { | |||||
180 | if (n == dtp->length && | |||||
181 | strncmp (line, dtp->command, dtp->length) == 0) { | |||||
182 | ||||||
183 | n += skip_space (line+n, len-n); | |||||
184 | line += n, len -= n; | |||||
185 | ||||||
186 | (*(dtp->proc)) (line, len); | |||||
187 | return; | |||||
188 | } | |||||
189 | } | |||||
190 | ||||||
191 | fprintf (stderr__stderrp, "%s: unknown command on line %s:%d\n", | |||||
192 | ProgramName, inputFilename, lineno+1); | |||||
193 | parse_errors++; | |||||
194 | } | |||||
195 | ||||||
196 | /* | |||||
197 | * the following routines are useful for parsing | |||||
198 | */ | |||||
199 | ||||||
200 | static int | |||||
201 | skip_word (const char *s, int len) | |||||
202 | { | |||||
203 | register int n; | |||||
204 | ||||||
205 | n = skip_chars (s, len); | |||||
206 | return (n + skip_space (s+n, len-n)); | |||||
207 | } | |||||
208 | ||||||
209 | static int | |||||
210 | skip_chars(const char *s, int len) | |||||
211 | { | |||||
212 | register int i; | |||||
213 | ||||||
214 | if (len <= 0 || !s || *s == '\0') return (0); | |||||
215 | ||||||
216 | for (i = 0; i < len; i++) { | |||||
217 | if (isspace(s[i])) break; | |||||
218 | } | |||||
219 | return (i); | |||||
220 | } | |||||
221 | ||||||
222 | static int | |||||
223 | skip_space(const char *s, int len) | |||||
224 | { | |||||
225 | register int i; | |||||
226 | ||||||
227 | if (len <= 0 || !s || *s == '\0') return (0); | |||||
228 | ||||||
229 | for (i = 0; i < len; i++) { | |||||
230 | if (!s[i] || !isspace(s[i])) break; | |||||
231 | } | |||||
232 | return (i); | |||||
233 | } | |||||
234 | ||||||
235 | ||||||
236 | static int | |||||
237 | skip_until_char(const char *s, int len, char c) | |||||
238 | { | |||||
239 | register int i; | |||||
240 | ||||||
241 | for (i = 0; i < len; i++) { | |||||
242 | if (s[i] == c) break; | |||||
243 | } | |||||
244 | return (i); | |||||
245 | } | |||||
246 | ||||||
247 | ||||||
248 | /* | |||||
249 | * The action routines. | |||||
250 | * | |||||
251 | * This is where the real work gets done. Each routine is responsible for | |||||
252 | * parsing its input (note that the command keyword has been stripped off) | |||||
253 | * and adding to the work queue. They are also in charge of outputting | |||||
254 | * error messages and returning non-zero if there is a problem. | |||||
255 | * | |||||
256 | * The following global variables are available: | |||||
257 | * dpy the display descriptor | |||||
258 | * work_queue linked list of opcodes | |||||
259 | * inputFilename name of the file being processed | |||||
260 | * lineno line number of current line in input file | |||||
261 | */ | |||||
262 | static void | |||||
263 | add_to_work_queue(union op *p) /* this can become a macro someday */ | |||||
264 | { | |||||
265 | if (work_queue.head == NULL((void*)0)) { /* nothing on the list */ | |||||
266 | work_queue.head = work_queue.tail = p; /* head, tail, no prev */ | |||||
267 | } else { | |||||
268 | work_queue.tail->generic.next = p; /* head okay, prev */ | |||||
269 | work_queue.tail = p; /* tail */ | |||||
270 | } | |||||
271 | p->generic.next = NULL((void*)0); | |||||
272 | ||||||
273 | if (verbose) { | |||||
274 | print_opcode (p); | |||||
275 | } | |||||
276 | return; | |||||
277 | } | |||||
278 | ||||||
279 | static Boolint | |||||
280 | parse_number(const char *str, unsigned long *val) | |||||
281 | { | |||||
282 | const char *fmt = "%ld"; | |||||
283 | ||||||
284 | if (*str == '0') { | |||||
285 | str++; | |||||
286 | while (isspace(*str)) | |||||
287 | str++; | |||||
288 | fmt = "%lo"; | |||||
289 | if (*str == '\0') { | |||||
290 | *val = 0; | |||||
291 | return 1; | |||||
292 | } | |||||
293 | if (*str == 'x' || *str == 'X') { | |||||
294 | str++; | |||||
295 | fmt = "%lx"; | |||||
296 | } | |||||
297 | } | |||||
298 | return (sscanf (str, fmt, val) == 1); | |||||
299 | } | |||||
300 | ||||||
301 | static Boolint | |||||
302 | parse_keysym(const char *line, int n, char **name, KeySym *keysym) | |||||
303 | { | |||||
304 | *name = copy_to_scratch (line, n); | |||||
305 | if (!strcmp(*name, "NoSymbol")) { | |||||
306 | *keysym = NoSymbol0L; | |||||
307 | return (True1); | |||||
308 | } | |||||
309 | *keysym = XStringToKeysym (*name); | |||||
310 | if (*keysym == NoSymbol0L && '0' <= **name && **name <= '9') | |||||
311 | return parse_number(*name, keysym); | |||||
312 | return (*keysym != NoSymbol0L); | |||||
313 | } | |||||
314 | ||||||
315 | /* | |||||
316 | * do_keycode - parse off lines of the form | |||||
317 | * | |||||
318 | * "keycode" number "=" [keysym ...] | |||||
319 | * ^ | |||||
320 | * | |||||
321 | * where number is in decimal, hex, or octal. Any number of keysyms may be | |||||
322 | * listed. | |||||
323 | */ | |||||
324 | ||||||
325 | static void | |||||
326 | do_keycode(char *line, int len) | |||||
327 | { | |||||
328 | int dummy; | |||||
329 | const char *fmt = "%d"; | |||||
330 | KeyCode keycode; | |||||
331 | ||||||
332 | if (len < 3 || !line || *line == '\0') { /* 5=a minimum */ | |||||
333 | badmsg0 ("keycode input line"){ badheader(); fprintf (__stderrp, "keycode input line"); putc ('\n', __stderrp); }; | |||||
334 | return; | |||||
335 | } | |||||
336 | ||||||
337 | /* | |||||
338 | * We need not bother to advance line/len past the | |||||
339 | * number (or the string 'any') as finish_keycodes() will | |||||
340 | * first advance past the '='. | |||||
341 | */ | |||||
342 | if (!strncmp("any", line, 3)) { | |||||
343 | keycode = 0; | |||||
344 | } else { | |||||
345 | if (*line == '0') line++, len--, fmt = "%o"; | |||||
346 | if (*line == 'x' || *line == 'X') line++, len--, fmt = "%x"; | |||||
347 | ||||||
348 | dummy = 0; | |||||
349 | if (sscanf (line, fmt, &dummy) != 1 || dummy == 0) { | |||||
350 | badmsg0 ("keycode value"){ badheader(); fprintf (__stderrp, "keycode value"); putc ('\n' , __stderrp); }; | |||||
351 | return; | |||||
352 | } | |||||
353 | keycode = (KeyCode) dummy; | |||||
354 | if ((int)keycode < min_keycode || (int)keycode > max_keycode) { | |||||
355 | badmsg0 ("keycode value (out of range)"){ badheader(); fprintf (__stderrp, "keycode value (out of range)" ); putc ('\n', __stderrp); }; | |||||
356 | return; | |||||
357 | } | |||||
358 | } | |||||
359 | ||||||
360 | finish_keycodes (line, len, &keycode, 1); | |||||
361 | } | |||||
362 | ||||||
363 | ||||||
364 | /* | |||||
365 | * do_keysym - parse off lines of the form | |||||
366 | * | |||||
367 | * "keysym" keysym "=" [keysym ...] | |||||
368 | * ^ | |||||
369 | * | |||||
370 | * The left keysyms has to be checked for validity and evaluated. | |||||
371 | */ | |||||
372 | ||||||
373 | static void | |||||
374 | do_keysym(char *line, int len) | |||||
375 | { | |||||
376 | int n; | |||||
377 | KeyCode *keycodes; | |||||
378 | KeySym keysym; | |||||
379 | char *tmpname; | |||||
380 | ||||||
381 | if (len < 3 || !line || *line == '\0') { /* a=b minimum */ | |||||
382 | badmsg0 ("keysym input line"){ badheader(); fprintf (__stderrp, "keysym input line"); putc ('\n', __stderrp); }; | |||||
383 | return; | |||||
384 | } | |||||
385 | ||||||
386 | n = skip_chars (line, len); | |||||
387 | if (n < 1) { | |||||
388 | badmsg0 ("target keysym name"){ badheader(); fprintf (__stderrp, "target keysym name"); putc ('\n', __stderrp); }; | |||||
389 | return; | |||||
390 | } | |||||
391 | if (!parse_keysym(line, n, &tmpname, &keysym)) { | |||||
392 | badmsg ("keysym target key symbol '%s'", tmpname){ badheader(); fprintf (__stderrp, "keysym target key symbol '%s'" , tmpname); putc ('\n', __stderrp); }; | |||||
393 | return; | |||||
394 | } | |||||
395 | ||||||
396 | keycodes = KeysymToKeycodes (dpy, keysym, &n); | |||||
397 | if (n == 0) { | |||||
398 | badmsg ("keysym target keysym '%s', no corresponding keycodes",{ badheader(); fprintf (__stderrp, "keysym target keysym '%s', no corresponding keycodes" , tmpname); putc ('\n', __stderrp); } | |||||
399 | tmpname){ badheader(); fprintf (__stderrp, "keysym target keysym '%s', no corresponding keycodes" , tmpname); putc ('\n', __stderrp); }; | |||||
400 | return; | |||||
401 | } | |||||
402 | if (verbose) { | |||||
403 | int i; | |||||
404 | printf ("! Keysym %s (0x%lx) corresponds to keycode(s)", | |||||
405 | tmpname, (long) keysym); | |||||
406 | for (i = 0; i < n; i++) | |||||
407 | printf (" 0x%x", keycodes[i]); | |||||
408 | printf("\n"); | |||||
409 | } | |||||
410 | ||||||
411 | finish_keycodes (line, len, keycodes, n); | |||||
412 | } | |||||
413 | ||||||
414 | static void | |||||
415 | finish_keycodes(const char *line, int len, KeyCode *keycodes, int count) | |||||
416 | { | |||||
417 | int n; | |||||
418 | KeySym *kslist; | |||||
419 | union op *uop; | |||||
420 | struct op_keycode *opk; | |||||
421 | ||||||
422 | n = skip_until_char (line, len, '='); | |||||
423 | line += n, len -= n; | |||||
424 | ||||||
425 | if (len < 1 || *line != '=') { /* = minimum */ | |||||
426 | badmsg0 ("keycode command (missing keysym list),"){ badheader(); fprintf (__stderrp, "keycode command (missing keysym list)," ); putc ('\n', __stderrp); }; | |||||
427 | return; | |||||
428 | } | |||||
429 | line++, len--; /* skip past the = */ | |||||
430 | ||||||
431 | n = skip_space (line, len); | |||||
432 | line += n, len -= n; | |||||
433 | ||||||
434 | /* allow empty list */ | |||||
435 | if (get_keysym_list (line, len, &n, &kslist) < 0) | |||||
436 | return; | |||||
437 | ||||||
438 | while (--count >= 0) { | |||||
439 | uop = AllocStruct (union op)(malloc (sizeof (union op))); | |||||
440 | if (!uop) { | |||||
441 | badmsg ("attempt to allocate a %ld byte keycode opcode",{ badheader(); fprintf (__stderrp, "attempt to allocate a %ld byte keycode opcode" , (long) sizeof (struct op_keycode)); putc ('\n', __stderrp); } | |||||
442 | (long) sizeof (struct op_keycode)){ badheader(); fprintf (__stderrp, "attempt to allocate a %ld byte keycode opcode" , (long) sizeof (struct op_keycode)); putc ('\n', __stderrp); }; | |||||
443 | return; | |||||
444 | } | |||||
445 | opk = &uop->keycode; | |||||
446 | ||||||
447 | opk->type = doKeycode; | |||||
448 | opk->target_keycode = keycodes[count]; | |||||
449 | opk->count = n; | |||||
450 | opk->keysyms = kslist; | |||||
451 | ||||||
452 | add_to_work_queue (uop); | |||||
453 | } | |||||
454 | ||||||
455 | #ifdef later | |||||
456 | /* make sure we handle any special keys */ | |||||
457 | check_special_keys (keycode, n, kslist); | |||||
458 | #endif | |||||
459 | } | |||||
460 | ||||||
461 | ||||||
462 | /* | |||||
463 | * parse_modifier - convert a modifier string name to its index | |||||
464 | */ | |||||
465 | ||||||
466 | struct modtab modifier_table[] = { /* keep in order so it can be index */ | |||||
467 | { "shift", 5, 0 }, | |||||
468 | { "lock", 4, 1 }, | |||||
469 | { "control", 7, 2 }, | |||||
470 | { "mod1", 4, 3 }, | |||||
471 | { "mod2", 4, 4 }, | |||||
472 | { "mod3", 4, 5 }, | |||||
473 | { "mod4", 4, 6 }, | |||||
474 | { "mod5", 4, 7 }, | |||||
475 | { "ctrl", 4, 2 }, | |||||
476 | { NULL((void*)0), 0, 0 }}; | |||||
477 | ||||||
478 | static int | |||||
479 | parse_modifier(char *line, int n) | |||||
480 | { | |||||
481 | register int i; | |||||
482 | struct modtab *mt; | |||||
483 | ||||||
484 | /* lowercase for comparison against table */ | |||||
485 | for (i = 0; i < n; i++) { | |||||
486 | if (isupper (line[i])) line[i] = tolower (line[i]); | |||||
487 | } | |||||
488 | ||||||
489 | for (mt = modifier_table; mt->name; mt++) { | |||||
490 | if (n == mt->length && strncmp (line, mt->name, n) == 0) | |||||
491 | return (mt->value); | |||||
492 | } | |||||
493 | return (-1); | |||||
494 | } | |||||
495 | ||||||
496 | ||||||
497 | /* | |||||
498 | * do_add - parse off lines of the form | |||||
499 | * | |||||
500 | * add MODIFIER = keysym ... | |||||
501 | * ^ | |||||
502 | * where the MODIFIER is one of Shift, Lock, Control, Mod[1-5] where case | |||||
503 | * is not important. There should also be an alias Ctrl for control. | |||||
504 | */ | |||||
505 | ||||||
506 | static void | |||||
507 | do_add(char *line, int len) | |||||
508 | { | |||||
509 | int n; | |||||
510 | int modifier; | |||||
511 | KeySym *kslist; | |||||
512 | union op *uop; | |||||
513 | struct op_addmodifier *opam; | |||||
514 | ||||||
515 | if (len < 6 || !line || *line == '\0') { /* Lock=a minimum */ | |||||
516 | badmsg0 ("add modifier input line"){ badheader(); fprintf (__stderrp, "add modifier input line") ; putc ('\n', __stderrp); }; | |||||
517 | return; | |||||
518 | } | |||||
519 | ||||||
520 | n = skip_chars (line, len); | |||||
521 | if (n < 1) { | |||||
522 | badmsg ("add modifier name %s", line){ badheader(); fprintf (__stderrp, "add modifier name %s", line ); putc ('\n', __stderrp); }; | |||||
523 | return; | |||||
524 | } | |||||
525 | ||||||
526 | modifier = parse_modifier (line, n); | |||||
527 | if (modifier < 0) { | |||||
528 | badmsgn ("add modifier name '%s', not allowed", line, n){ badheader(); fprintf (__stderrp, "add modifier name '%s', not allowed" , copy_to_scratch (line, n)); putc ('\n', __stderrp); }; | |||||
529 | return; | |||||
530 | } | |||||
531 | ||||||
532 | line += n, len -= n; | |||||
533 | n = skip_until_char (line, len, '='); | |||||
534 | if (n < 0) { | |||||
535 | badmsg0 ("add modifier = keysym"){ badheader(); fprintf (__stderrp, "add modifier = keysym"); putc ('\n', __stderrp); }; | |||||
536 | return; | |||||
537 | } | |||||
538 | ||||||
539 | n++; /* skip = */ | |||||
540 | n += skip_space (line+n, len-n); | |||||
541 | line += n, len -= n; | |||||
542 | ||||||
543 | if (get_keysym_list (line, len, &n, &kslist) < 0) | |||||
544 | return; | |||||
545 | if (n == 0) { | |||||
546 | badmsg0 ("add modifier keysym list (empty)"){ badheader(); fprintf (__stderrp, "add modifier keysym list (empty)" ); putc ('\n', __stderrp); }; | |||||
547 | return; | |||||
548 | } | |||||
549 | ||||||
550 | uop = AllocStruct (union op)(malloc (sizeof (union op))); | |||||
551 | if (!uop) { | |||||
552 | badmsg ("attempt to allocate %ld byte addmodifier opcode",{ badheader(); fprintf (__stderrp, "attempt to allocate %ld byte addmodifier opcode" , (long) sizeof (struct op_addmodifier)); putc ('\n', __stderrp ); } | |||||
553 | (long) sizeof (struct op_addmodifier)){ badheader(); fprintf (__stderrp, "attempt to allocate %ld byte addmodifier opcode" , (long) sizeof (struct op_addmodifier)); putc ('\n', __stderrp ); }; | |||||
554 | return; | |||||
555 | } | |||||
556 | opam = &uop->addmodifier; | |||||
557 | ||||||
558 | opam->type = doAddModifier; | |||||
559 | opam->modifier = modifier; | |||||
560 | opam->count = n; | |||||
561 | opam->keysyms = kslist; | |||||
562 | ||||||
563 | add_to_work_queue (uop); | |||||
564 | } | |||||
565 | ||||||
566 | #ifdef AUTO_ADD_REMOVE | |||||
567 | /* | |||||
568 | * make_add - stick a single add onto the queue | |||||
569 | */ | |||||
570 | static void | |||||
571 | make_add(int modifier, KeySym keysym) | |||||
572 | { | |||||
573 | union op *uop; | |||||
574 | struct op_addmodifier *opam; | |||||
575 | ||||||
576 | uop = AllocStruct (union op)(malloc (sizeof (union op))); | |||||
577 | if (!uop) { | |||||
578 | badmsg ("attempt to allocate %ld byte addmodifier opcode",{ badheader(); fprintf (__stderrp, "attempt to allocate %ld byte addmodifier opcode" , (long) sizeof (struct op_addmodifier)); putc ('\n', __stderrp ); } | |||||
579 | (long) sizeof (struct op_addmodifier)){ badheader(); fprintf (__stderrp, "attempt to allocate %ld byte addmodifier opcode" , (long) sizeof (struct op_addmodifier)); putc ('\n', __stderrp ); }; | |||||
580 | return; | |||||
581 | } | |||||
582 | opam = &uop->addmodifier; | |||||
583 | ||||||
584 | opam->type = doAddModifier; | |||||
585 | opam->modifier = modifier; | |||||
586 | opam->count = 1; | |||||
587 | opam->keysyms = malloc (sizeof (KeySym)); | |||||
588 | if (!opam->keysyms) { | |||||
589 | badmsg ("attempt to allocate %ld byte KeySym", (long) sizeof (KeySym)){ badheader(); fprintf (__stderrp, "attempt to allocate %ld byte KeySym" , (long) sizeof (KeySym)); putc ('\n', __stderrp); }; | |||||
590 | free (opam); | |||||
591 | return; | |||||
592 | } | |||||
593 | opam->keysyms[0] = keysym; | |||||
594 | ||||||
595 | add_to_work_queue (uop); | |||||
596 | return; | |||||
597 | } | |||||
598 | #endif /* AUTO_ADD_REMOVE */ | |||||
599 | ||||||
600 | ||||||
601 | /* | |||||
602 | * do_remove - parse off lines of the form | |||||
603 | * | |||||
604 | * remove MODIFIER = oldkeysym ... | |||||
605 | * ^ | |||||
606 | * where the MODIFIER is one of Shift, Lock, Control, Mod[1-5] where case | |||||
607 | * is not important. There should also be an alias Ctrl for control. | |||||
608 | */ | |||||
609 | ||||||
610 | static void | |||||
611 | do_remove(char *line, int len) | |||||
612 | { | |||||
613 | int n; | |||||
614 | int nc; | |||||
615 | int i; | |||||
616 | int tot; | |||||
617 | int modifier; | |||||
618 | KeySym *kslist; | |||||
619 | KeyCode *kclist; | |||||
620 | union op *uop; | |||||
621 | struct op_removemodifier *oprm; | |||||
622 | ||||||
623 | if (len < 6 || !line || *line == '\0') { /* Lock=a minimum */ | |||||
| ||||||
624 | badmsg0 ("remove modifier input line"){ badheader(); fprintf (__stderrp, "remove modifier input line" ); putc ('\n', __stderrp); }; | |||||
625 | return; | |||||
626 | } | |||||
627 | ||||||
628 | n = skip_chars (line, len); | |||||
629 | if (n < 1) { | |||||
630 | badmsg ("remove modifier name %s", line){ badheader(); fprintf (__stderrp, "remove modifier name %s", line); putc ('\n', __stderrp); }; | |||||
631 | return; | |||||
632 | } | |||||
633 | ||||||
634 | modifier = parse_modifier (line, n); | |||||
635 | if (modifier < 0) { | |||||
636 | badmsgn ("remove modifier name '%s', not allowed", line, n){ badheader(); fprintf (__stderrp, "remove modifier name '%s', not allowed" , copy_to_scratch (line, n)); putc ('\n', __stderrp); }; | |||||
637 | return; | |||||
638 | } | |||||
639 | ||||||
640 | line += n, len -= n; | |||||
641 | n = skip_until_char (line, len, '='); | |||||
642 | if (n < 0) { | |||||
643 | badmsg0 ("remove modifier = keysym"){ badheader(); fprintf (__stderrp, "remove modifier = keysym" ); putc ('\n', __stderrp); }; | |||||
644 | return; | |||||
645 | } | |||||
646 | ||||||
647 | n++; | |||||
648 | n += skip_space (line+n, len-n); | |||||
649 | line += n, len -= n; | |||||
650 | ||||||
651 | if (get_keysym_list (line, len, &n, &kslist) < 0) | |||||
652 | return; | |||||
653 | if (n == 0) { | |||||
654 | badmsg0 ("remove modifier keysym list (empty)"){ badheader(); fprintf (__stderrp, "remove modifier keysym list (empty)" ); putc ('\n', __stderrp); }; | |||||
| ||||||
655 | return; | |||||
656 | } | |||||
657 | ||||||
658 | /* | |||||
659 | * unlike the add command, we have to now evaluate the keysyms | |||||
660 | */ | |||||
661 | ||||||
662 | kclist = malloc (n * sizeof (KeyCode)); | |||||
663 | if (!kclist) { | |||||
664 | badmsg ("attempt to allocate %ld byte keycode list",{ badheader(); fprintf (__stderrp, "attempt to allocate %ld byte keycode list" , (long) (n * sizeof (KeyCode))); putc ('\n', __stderrp); } | |||||
665 | (long) (n * sizeof (KeyCode))){ badheader(); fprintf (__stderrp, "attempt to allocate %ld byte keycode list" , (long) (n * sizeof (KeyCode))); putc ('\n', __stderrp); }; | |||||
666 | free (kslist); | |||||
667 | return; | |||||
668 | } | |||||
669 | ||||||
670 | tot = n; | |||||
671 | nc = 0; | |||||
672 | for (i = 0; i < n; i++) { | |||||
673 | int num_kcs; | |||||
674 | KeyCode *kcs; | |||||
675 | kcs = KeysymToKeycodes (dpy, kslist[i], &num_kcs); | |||||
676 | if (num_kcs == 0) { | |||||
677 | char *tmpname = XKeysymToString (kslist[i]); | |||||
678 | badmsg ("keysym in remove modifier list '%s', no corresponding keycodes",{ badheader(); fprintf (__stderrp, "keysym in remove modifier list '%s', no corresponding keycodes" , tmpname ? tmpname : "?"); putc ('\n', __stderrp); } | |||||
679 | tmpname ? tmpname : "?"){ badheader(); fprintf (__stderrp, "keysym in remove modifier list '%s', no corresponding keycodes" , tmpname ? tmpname : "?"); putc ('\n', __stderrp); }; | |||||
680 | continue; | |||||
681 | } | |||||
682 | if (verbose) { | |||||
683 | int j; | |||||
684 | char *tmpname = XKeysymToString (kslist[i]); | |||||
685 | printf ("! Keysym %s (0x%lx) corresponds to keycode(s)", | |||||
686 | tmpname ? tmpname : "?", (long) kslist[i]); | |||||
687 | for (j = 0; j < num_kcs; j++) | |||||
688 | printf(" 0x%x", kcs[j]); | |||||
689 | printf("\n"); | |||||
690 | } | |||||
691 | if (nc + num_kcs > tot) { | |||||
692 | tot = nc + num_kcs; | |||||
693 | kclist = realloc(kclist, tot * sizeof(KeyCode)); | |||||
694 | if (!kclist) { | |||||
695 | badmsg ("attempt to allocate %ld byte keycode list",{ badheader(); fprintf (__stderrp, "attempt to allocate %ld byte keycode list" , (long) (tot * sizeof (KeyCode))); putc ('\n', __stderrp); } | |||||
696 | (long) (tot * sizeof (KeyCode))){ badheader(); fprintf (__stderrp, "attempt to allocate %ld byte keycode list" , (long) (tot * sizeof (KeyCode))); putc ('\n', __stderrp); }; | |||||
697 | free (kslist); | |||||
698 | return; | |||||
699 | } | |||||
700 | } | |||||
701 | while (--num_kcs >= 0) | |||||
702 | kclist[nc++] = *kcs++; /* okay, add it to list */ | |||||
703 | } | |||||
704 | ||||||
705 | free (kslist); /* all done with it */ | |||||
706 | ||||||
707 | uop = AllocStruct (union op)(malloc (sizeof (union op))); | |||||
708 | if (!uop) { | |||||
709 | badmsg ("attempt to allocate %ld byte removemodifier opcode",{ badheader(); fprintf (__stderrp, "attempt to allocate %ld byte removemodifier opcode" , (long) sizeof (struct op_removemodifier)); putc ('\n', __stderrp ); } | |||||
710 | (long) sizeof (struct op_removemodifier)){ badheader(); fprintf (__stderrp, "attempt to allocate %ld byte removemodifier opcode" , (long) sizeof (struct op_removemodifier)); putc ('\n', __stderrp ); }; | |||||
711 | return; | |||||
712 | } | |||||
713 | oprm = &uop->removemodifier; | |||||
714 | ||||||
715 | oprm->type = doRemoveModifier; | |||||
716 | oprm->modifier = modifier; | |||||
717 | oprm->count = nc; | |||||
718 | oprm->keycodes = kclist; | |||||
719 | ||||||
720 | add_to_work_queue (uop); | |||||
721 | } | |||||
722 | ||||||
723 | #ifdef AUTO_ADD_REMOVE | |||||
724 | /* | |||||
725 | * make_remove - stick a single remove onto the queue | |||||
726 | */ | |||||
727 | static void | |||||
728 | make_remove(int modifier, KeyCode keycode) | |||||
729 | { | |||||
730 | union op *uop; | |||||
731 | struct op_removemodifier *oprm; | |||||
732 | ||||||
733 | uop = AllocStruct (union op)(malloc (sizeof (union op))); | |||||
734 | if (!uop) { | |||||
735 | badmsg ("attempt to allocate %ld byte removemodifier opcode",{ badheader(); fprintf (__stderrp, "attempt to allocate %ld byte removemodifier opcode" , (long) sizeof (struct op_removemodifier)); putc ('\n', __stderrp ); } | |||||
736 | (long) sizeof (struct op_removemodifier)){ badheader(); fprintf (__stderrp, "attempt to allocate %ld byte removemodifier opcode" , (long) sizeof (struct op_removemodifier)); putc ('\n', __stderrp ); }; | |||||
737 | return; | |||||
738 | } | |||||
739 | oprm = &uop->removemodifier; | |||||
740 | ||||||
741 | oprm->type = doRemoveModifier; | |||||
742 | oprm->modifier = modifier; | |||||
743 | oprm->count = 1; | |||||
744 | oprm->keycodes = malloc (sizeof (KeyCode)); | |||||
745 | if (!oprm->keycodes) { | |||||
746 | badmsg ("attempt to allocate %ld byte KeyCode",{ badheader(); fprintf (__stderrp, "attempt to allocate %ld byte KeyCode" , (long) sizeof (KeyCode)); putc ('\n', __stderrp); } | |||||
747 | (long) sizeof (KeyCode)){ badheader(); fprintf (__stderrp, "attempt to allocate %ld byte KeyCode" , (long) sizeof (KeyCode)); putc ('\n', __stderrp); }; | |||||
748 | free (oprm); | |||||
749 | return; | |||||
750 | } | |||||
751 | oprm->keycodes[0] = keycode; | |||||
752 | ||||||
753 | add_to_work_queue (uop); | |||||
754 | return; | |||||
755 | } | |||||
756 | #endif /* AUTO_ADD_REMOVE */ | |||||
757 | ||||||
758 | ||||||
759 | /* | |||||
760 | * do_clear - parse off lines of the form | |||||
761 | * | |||||
762 | * clear MODIFIER | |||||
763 | * ^ | |||||
764 | */ | |||||
765 | ||||||
766 | static void | |||||
767 | do_clear(char *line, int len) | |||||
768 | { | |||||
769 | int n; | |||||
770 | int modifier; | |||||
771 | union op *uop; | |||||
772 | struct op_clearmodifier *opcm; | |||||
773 | ||||||
774 | if (len < 4 || !line || *line == '\0') { /* Lock minimum */ | |||||
775 | badmsg0 ("clear modifier input line"){ badheader(); fprintf (__stderrp, "clear modifier input line" ); putc ('\n', __stderrp); }; | |||||
776 | return; | |||||
777 | } | |||||
778 | ||||||
779 | n = skip_chars (line, len); | |||||
780 | ||||||
781 | modifier = parse_modifier (line, n); | |||||
782 | if (modifier < 0) { | |||||
783 | badmsgn ("clear modifier name '%s'", line, n){ badheader(); fprintf (__stderrp, "clear modifier name '%s'" , copy_to_scratch (line, n)); putc ('\n', __stderrp); }; | |||||
784 | return; | |||||
785 | } | |||||
786 | n += skip_space (line+n, len-n); | |||||
787 | if (n != len) { | |||||
788 | badmsgn ("extra argument '%s' to clear modifier", line+n, len-n){ badheader(); fprintf (__stderrp, "extra argument '%s' to clear modifier" , copy_to_scratch (line+n, len-n)); putc ('\n', __stderrp); }; | |||||
789 | /* okay to continue */ | |||||
790 | } | |||||
791 | ||||||
792 | uop = AllocStruct (union op)(malloc (sizeof (union op))); | |||||
793 | if (!uop) { | |||||
794 | badmsg ("attempt to allocate %ld byte clearmodifier opcode",{ badheader(); fprintf (__stderrp, "attempt to allocate %ld byte clearmodifier opcode" , (long) sizeof (struct op_clearmodifier)); putc ('\n', __stderrp ); } | |||||
795 | (long) sizeof (struct op_clearmodifier)){ badheader(); fprintf (__stderrp, "attempt to allocate %ld byte clearmodifier opcode" , (long) sizeof (struct op_clearmodifier)); putc ('\n', __stderrp ); }; | |||||
796 | return; | |||||
797 | } | |||||
798 | opcm = &uop->clearmodifier; | |||||
799 | ||||||
800 | opcm->type = doClearModifier; | |||||
801 | opcm->modifier = modifier; | |||||
802 | ||||||
803 | add_to_work_queue (uop); | |||||
804 | } | |||||
805 | ||||||
806 | #ifndef HAVE_STRNCASECMP1 | |||||
807 | static int | |||||
808 | strncasecmp(const char *a, const char *b, int n) | |||||
809 | { | |||||
810 | int i; | |||||
811 | int a1, b1; | |||||
812 | ||||||
813 | for (i = 0; i < n; i++, a++, b++) { | |||||
814 | if (!*a) return -1; | |||||
815 | if (!*b) return 1; | |||||
816 | ||||||
817 | if (*a != *b) { | |||||
818 | a1 = (isascii(*a) && isupper(*a)) ? tolower(*a) : *a; | |||||
819 | b1 = (isascii(*b) && isupper(*b)) ? tolower(*b) : *b; | |||||
820 | if (a1 != b1) return b1 - a1; | |||||
821 | } | |||||
822 | } | |||||
823 | return 0; | |||||
824 | } | |||||
825 | #endif | |||||
826 | ||||||
827 | /* | |||||
828 | * do_pointer = get list of numbers of the form | |||||
829 | * | |||||
830 | * buttons = NUMBER ... | |||||
831 | * ^ | |||||
832 | */ | |||||
833 | ||||||
834 | static void | |||||
835 | do_pointer(char *line, int len) | |||||
836 | { | |||||
837 | int n; | |||||
838 | int i; | |||||
839 | unsigned long val; | |||||
840 | union op *uop; | |||||
841 | struct op_pointer *opp; | |||||
842 | unsigned char buttons[MAXBUTTONCODES256]; | |||||
843 | int nbuttons; | |||||
844 | char *strval; | |||||
845 | Boolint ok; | |||||
846 | ||||||
847 | if (len < 2 || !line || *line == '\0') { /* =1 minimum */ | |||||
848 | badmsg0 ("buttons input line"){ badheader(); fprintf (__stderrp, "buttons input line"); putc ('\n', __stderrp); }; | |||||
849 | return; | |||||
850 | } | |||||
851 | ||||||
852 | nbuttons = XGetPointerMapping (dpy, buttons, MAXBUTTONCODES256); | |||||
853 | ||||||
854 | n = skip_space (line, len); | |||||
855 | line += n, len -= n; | |||||
856 | ||||||
857 | if (line[0] != '=') { | |||||
858 | badmsg0 ("buttons pointer code list, missing equal sign"){ badheader(); fprintf (__stderrp, "buttons pointer code list, missing equal sign" ); putc ('\n', __stderrp); }; | |||||
859 | return; | |||||
860 | } | |||||
861 | ||||||
862 | line++, len--; /* skip = */ | |||||
863 | n = skip_space (line, len); | |||||
864 | line += n, len -= n; | |||||
865 | ||||||
866 | i = 0; | |||||
867 | if (len < 7 || strncasecmp (line, "default", 7) != 0) { | |||||
868 | while (len > 0) { | |||||
869 | n = skip_space (line, len); | |||||
870 | line += n, len -= n; | |||||
871 | if (line[0] == '\0') break; | |||||
872 | n = skip_word (line, len); | |||||
873 | if (n < 1) { | |||||
874 | badmsg ("skip of word in buttons line: %s", line){ badheader(); fprintf (__stderrp, "skip of word in buttons line: %s" , line); putc ('\n', __stderrp); }; | |||||
875 | return; | |||||
876 | } | |||||
877 | strval = copy_to_scratch(line, n); | |||||
878 | if (strval == NULL((void*)0)) | |||||
879 | /* copy_to_scratch already printed error message */ | |||||
880 | return; | |||||
881 | ok = parse_number (strval, &val); | |||||
882 | if (!ok || val >= MAXBUTTONCODES256) { | |||||
883 | badmsg ("value %s given for buttons list", strval){ badheader(); fprintf (__stderrp, "value %s given for buttons list" , strval); putc ('\n', __stderrp); }; | |||||
884 | return; | |||||
885 | } | |||||
886 | buttons[i++] = (unsigned char) val; | |||||
887 | line += n, len -= n; | |||||
888 | } | |||||
889 | } | |||||
890 | ||||||
891 | if (i > 0 && i != nbuttons) { | |||||
892 | fprintf (stderr__stderrp, "Warning: Only changing the first %d of %d buttons.\n", | |||||
893 | i, nbuttons); | |||||
894 | i = nbuttons; | |||||
895 | } | |||||
896 | ||||||
897 | uop = AllocStruct (union op)(malloc (sizeof (union op))); | |||||
898 | if (!uop) { | |||||
899 | badmsg ("attempt to allocate a %ld byte pointer opcode",{ badheader(); fprintf (__stderrp, "attempt to allocate a %ld byte pointer opcode" , (long) sizeof (struct op_pointer)); putc ('\n', __stderrp); } | |||||
900 | (long) sizeof (struct op_pointer)){ badheader(); fprintf (__stderrp, "attempt to allocate a %ld byte pointer opcode" , (long) sizeof (struct op_pointer)); putc ('\n', __stderrp); }; | |||||
901 | return; | |||||
902 | } | |||||
903 | opp = &uop->pointer; | |||||
904 | ||||||
905 | opp->type = doPointer; | |||||
906 | opp->count = i; | |||||
907 | for (i = 0; i < opp->count; i++) { | |||||
908 | opp->button_codes[i] = buttons[i]; | |||||
909 | } | |||||
910 | ||||||
911 | add_to_work_queue (uop); | |||||
912 | } | |||||
913 | ||||||
914 | ||||||
915 | /* | |||||
916 | * get_keysym_list - parses the rest of the line into a keysyms assumes | |||||
917 | * that the = sign has been parsed off but there may be leading whitespace | |||||
918 | * | |||||
919 | * keysym ... | |||||
920 | * ^ | |||||
921 | * | |||||
922 | * this involves getting the word containing the keysym, checking its range, | |||||
923 | * and adding it to the list. | |||||
924 | */ | |||||
925 | ||||||
926 | static int | |||||
927 | get_keysym_list(const char *line, int len, int *np, KeySym **kslistp) | |||||
928 | { | |||||
929 | int havesofar, maxcanhave; | |||||
930 | KeySym *keysymlist; | |||||
931 | ||||||
932 | *np = 0; | |||||
933 | *kslistp = NULL((void*)0); | |||||
934 | ||||||
935 | if (len == 0) return (0); /* empty list */ | |||||
936 | ||||||
937 | havesofar = 0; | |||||
938 | maxcanhave = 4; /* most lists are small */ | |||||
939 | keysymlist = malloc (maxcanhave * sizeof (KeySym)); | |||||
940 | if (!keysymlist) { | |||||
941 | badmsg ("attempt to allocate %ld byte initial keysymlist",{ badheader(); fprintf (__stderrp, "attempt to allocate %ld byte initial keysymlist" , (long) (maxcanhave * sizeof (KeySym))); putc ('\n', __stderrp ); } | |||||
942 | (long) (maxcanhave * sizeof (KeySym))){ badheader(); fprintf (__stderrp, "attempt to allocate %ld byte initial keysymlist" , (long) (maxcanhave * sizeof (KeySym))); putc ('\n', __stderrp ); }; | |||||
943 | return (-1); | |||||
944 | } | |||||
945 | ||||||
946 | while (len > 0) { | |||||
947 | KeySym keysym; | |||||
948 | int n; | |||||
949 | char *tmpname; | |||||
950 | Boolint ok; | |||||
951 | ||||||
952 | n = skip_space (line, len); | |||||
953 | line += n, len -= n; | |||||
954 | ||||||
955 | n = skip_chars (line, len); | |||||
956 | if (n < 0) { | |||||
957 | badmsg0 ("keysym name list"){ badheader(); fprintf (__stderrp, "keysym name list"); putc ( '\n', __stderrp); }; | |||||
958 | free(keysymlist); | |||||
959 | return (-1); | |||||
960 | } | |||||
961 | ||||||
962 | ok = parse_keysym (line, n, &tmpname, &keysym); | |||||
963 | line += n, len -= n; | |||||
964 | if (!ok) { | |||||
965 | badmsg ("keysym name '%s' in keysym list", tmpname){ badheader(); fprintf (__stderrp, "keysym name '%s' in keysym list" , tmpname); putc ('\n', __stderrp); }; | |||||
966 | /* do NOT return here, look for others */ | |||||
967 | continue; | |||||
968 | } | |||||
969 | ||||||
970 | /* | |||||
971 | * Do NOT test to see if the keysym translates to a keycode or you | |||||
972 | * won't be able to assign new ones.... | |||||
973 | */ | |||||
974 | ||||||
975 | /* grow the list bigger if necessary */ | |||||
976 | if (havesofar >= maxcanhave) { | |||||
977 | KeySym *origkeysymlist = keysymlist; | |||||
978 | maxcanhave *= 2; | |||||
979 | keysymlist = realloc (keysymlist, maxcanhave * sizeof (KeySym)); | |||||
980 | if (!keysymlist) { | |||||
981 | badmsg ("attempt to grow keysym list to %ld bytes",{ badheader(); fprintf (__stderrp, "attempt to grow keysym list to %ld bytes" , (long) (maxcanhave * sizeof (KeySym))); putc ('\n', __stderrp ); } | |||||
982 | (long) (maxcanhave * sizeof (KeySym))){ badheader(); fprintf (__stderrp, "attempt to grow keysym list to %ld bytes" , (long) (maxcanhave * sizeof (KeySym))); putc ('\n', __stderrp ); }; | |||||
983 | free(origkeysymlist); | |||||
984 | return (-1); | |||||
985 | } | |||||
986 | } | |||||
987 | ||||||
988 | /* and add it to the list */ | |||||
989 | keysymlist[havesofar++] = keysym; | |||||
990 | } | |||||
991 | ||||||
992 | *kslistp = keysymlist; | |||||
993 | *np = havesofar; | |||||
994 | return (0); | |||||
995 | } | |||||
996 | ||||||
997 | ||||||
998 | #ifdef later | |||||
999 | /* | |||||
1000 | * check_special_keys - run through list of keysyms and generate "add" or | |||||
1001 | * "remove" commands for for any of the key syms that appear in the modifier | |||||
1002 | * list. this involves running down the modifier map which is an array of | |||||
1003 | * 8 by map->max_keypermod keycodes. | |||||
1004 | */ | |||||
1005 | ||||||
1006 | static void | |||||
1007 | check_special_keys(KeyCode keycode, int n, KeySym *kslist) | |||||
1008 | { | |||||
1009 | int i; /* iterator variable */ | |||||
1010 | KeyCode *kcp; /* keycode pointer */ | |||||
1011 | ||||||
1012 | /* | |||||
1013 | * walk the modifiermap array. since its dimensions are not known at | |||||
1014 | * compile time, we have to walk it by hand instead of indexing. this | |||||
1015 | * is why it is initialized outside the loop, but incremented inside the | |||||
1016 | * second loop. | |||||
1017 | */ | |||||
1018 | ||||||
1019 | kcp = map->modifiermap; /* start at beginning and iterate */ | |||||
1020 | for (i = 0; i < 8; i++) { /* there are 8 modifier keys */ | |||||
1021 | int j; | |||||
1022 | ||||||
1023 | for (j = 0; j < map->max_keypermod; j++, kcp++) { | |||||
1024 | KeySym keysym; | |||||
1025 | int k; | |||||
1026 | ||||||
1027 | if (!*kcp) continue; /* only non-zero entries significant */ | |||||
1028 | ||||||
1029 | /* | |||||
1030 | * check to see if the target keycode is already a modifier; if so, | |||||
1031 | * then we have to remove it | |||||
1032 | */ | |||||
1033 | if (keycode == *kcp) { | |||||
1034 | make_remove (i, keycode); | |||||
1035 | } | |||||
1036 | ||||||
1037 | /* | |||||
1038 | * now, check to see if any of the keysyms map to keycodes | |||||
1039 | * that are in the modifier list | |||||
1040 | */ | |||||
1041 | for (k = 0; k < n; k++) { | |||||
1042 | KeyCodes kc; | |||||
1043 | ||||||
1044 | kc = XKeysymToKeycode (dpy, kslist[k]); | |||||
1045 | if (kc == *kcp) { /* yup, found one */ | |||||
1046 | /* | |||||
1047 | * have to generate a remove of the CURRENT keycode | |||||
1048 | * and then an add of the new KEYCODE | |||||
1049 | */ | |||||
1050 | make_remove (i, kc); /* modifier, keycode */ | |||||
1051 | make_add (i, kslist[k]); /* modifier, keysym */ | |||||
1052 | } | |||||
1053 | } | |||||
1054 | } | |||||
1055 | } | |||||
1056 | return; | |||||
1057 | } | |||||
1058 | #endif | |||||
1059 | ||||||
1060 | /* | |||||
1061 | * print_work_queue - disassemble the work queue and print it on stdout | |||||
1062 | */ | |||||
1063 | ||||||
1064 | void | |||||
1065 | print_work_queue(void) | |||||
1066 | { | |||||
1067 | union op *op; | |||||
1068 | ||||||
1069 | printf ("! dump of work queue\n"); | |||||
1070 | for (op = work_queue.head; op; op = op->generic.next) { | |||||
1071 | print_opcode (op); | |||||
1072 | } | |||||
1073 | return; | |||||
1074 | } | |||||
1075 | ||||||
1076 | static void | |||||
1077 | print_opcode(union op *op) | |||||
1078 | { | |||||
1079 | int i; | |||||
1080 | ||||||
1081 | printf (" "); | |||||
1082 | switch (op->generic.type) { | |||||
1083 | case doKeycode: | |||||
1084 | if (op->keycode.target_keycode) | |||||
1085 | printf ("keycode 0x%lx =", (long) op->keycode.target_keycode); | |||||
1086 | else | |||||
1087 | printf ("keycode any ="); | |||||
1088 | for (i = 0; i < op->keycode.count; i++) { | |||||
1089 | char *name = XKeysymToString (op->keycode.keysyms[i]); | |||||
1090 | ||||||
1091 | printf (" %s", name ? name : "BADKEYSYM"); | |||||
1092 | } | |||||
1093 | printf ("\n"); | |||||
1094 | break; | |||||
1095 | case doAddModifier: | |||||
1096 | printf ("add %s =", modifier_table[op->addmodifier.modifier].name); | |||||
1097 | for (i = 0; i < op->addmodifier.count; i++) { | |||||
1098 | char *name = XKeysymToString (op->addmodifier.keysyms[i]); | |||||
1099 | printf (" %s", name ? name : "BADKEYSYM"); | |||||
1100 | } | |||||
1101 | printf ("\n"); | |||||
1102 | break; | |||||
1103 | case doRemoveModifier: | |||||
1104 | printf ("remove %s = ", | |||||
1105 | modifier_table[op->removemodifier.modifier].name); | |||||
1106 | for (i = 0; i < op->removemodifier.count; i++) { | |||||
1107 | printf (" 0x%lx", (long) op->removemodifier.keycodes[i]); | |||||
1108 | } | |||||
1109 | printf ("\n"); | |||||
1110 | break; | |||||
1111 | case doClearModifier: | |||||
1112 | printf ("clear %s\n", modifier_table[op->clearmodifier.modifier].name); | |||||
1113 | break; | |||||
1114 | case doPointer: | |||||
1115 | printf ("pointer = "); | |||||
1116 | if (op->pointer.count == 0) | |||||
1117 | printf(" default"); | |||||
1118 | else for (i=0; i < op->pointer.count; i++) | |||||
1119 | printf(" %d", op->pointer.button_codes[i]); | |||||
1120 | printf ("\n"); | |||||
1121 | break; | |||||
1122 | default: | |||||
1123 | printf ("! unknown opcode %d\n", op->generic.type); | |||||
1124 | break; | |||||
1125 | } /* end switch */ | |||||
1126 | return; | |||||
1127 | } | |||||
1128 | ||||||
1129 | /* | |||||
1130 | * execute_work_queue - do the real meat and potatoes now that we know what | |||||
1131 | * we need to do and that all of the input is correct. | |||||
1132 | */ | |||||
1133 | static int exec_keycode ( struct op_keycode *opk ); | |||||
1134 | static int exec_add ( struct op_addmodifier *opam ); | |||||
1135 | static int exec_remove ( struct op_removemodifier *oprm ); | |||||
1136 | static int exec_clear ( struct op_clearmodifier *opcm ); | |||||
1137 | static int exec_pointer ( struct op_pointer *opp ); | |||||
1138 | ||||||
1139 | ||||||
1140 | int | |||||
1141 | execute_work_queue (void) | |||||
1142 | { | |||||
1143 | union op *op; | |||||
1144 | int errors; | |||||
1145 | Boolint update_map = False0; | |||||
1146 | int dosync; | |||||
1147 | ||||||
1148 | if (verbose) { | |||||
1149 | printf ("!\n"); | |||||
1150 | printf ("! executing work queue\n"); | |||||
1151 | printf ("!\n"); | |||||
1152 | } | |||||
1153 | ||||||
1154 | errors = 0; | |||||
1155 | dosync = 0; | |||||
1156 | ||||||
1157 | for (op = work_queue.head; op; op = op->generic.next) { | |||||
1158 | if (verbose) print_opcode (op); | |||||
1159 | ||||||
1160 | /* check to see if we have to update the keyboard mapping */ | |||||
1161 | if (dosync && | |||||
1162 | (dosync < 0 || | |||||
1163 | op->generic.type != doKeycode || | |||||
1164 | !op->keycode.target_keycode)) { | |||||
1165 | XSync (dpy, 0); | |||||
1166 | while (XEventsQueued (dpy, QueuedAlready0) > 0) { | |||||
1167 | XEvent event; | |||||
1168 | XNextEvent (dpy, &event); | |||||
1169 | if (event.type == MappingNotify34) { | |||||
1170 | /* read all MappingNotify events */ | |||||
1171 | while (XCheckTypedEvent (dpy, MappingNotify34, &event)) ; | |||||
1172 | XRefreshKeyboardMapping (&event.xmapping); | |||||
1173 | } else { | |||||
1174 | fprintf (stderr__stderrp, "%s: unknown event %ld\n", | |||||
1175 | ProgramName, (long) event.type); | |||||
1176 | } | |||||
1177 | } | |||||
1178 | } | |||||
1179 | dosync = 0; | |||||
1180 | switch (op->generic.type) { | |||||
1181 | case doKeycode: | |||||
1182 | if (exec_keycode (&op->keycode) < 0) errors++; | |||||
1183 | if (op->keycode.target_keycode) | |||||
1184 | dosync = 1; | |||||
1185 | else | |||||
1186 | dosync = -1; | |||||
1187 | break; | |||||
1188 | case doAddModifier: | |||||
1189 | if (exec_add (&op->addmodifier) < 0) errors++; | |||||
1190 | else update_map = True1; | |||||
1191 | break; | |||||
1192 | case doRemoveModifier: | |||||
1193 | if (exec_remove (&op->removemodifier) < 0) errors++; | |||||
1194 | else update_map = True1; | |||||
1195 | break; | |||||
1196 | case doClearModifier: | |||||
1197 | if (exec_clear (&op->clearmodifier) < 0) errors++; | |||||
1198 | else update_map = True1; | |||||
1199 | break; | |||||
1200 | case doPointer: | |||||
1201 | if (exec_pointer (&op->pointer) < 0) errors++; | |||||
1202 | break; | |||||
1203 | default: | |||||
1204 | fprintf (stderr__stderrp, "%s: unknown opcode %d\n", | |||||
1205 | ProgramName, op->generic.type); | |||||
1206 | break; | |||||
1207 | } | |||||
1208 | } | |||||
1209 | ||||||
1210 | if (update_map) { | |||||
1211 | if (UpdateModifierMapping (map) < 0) errors++; | |||||
1212 | } | |||||
1213 | ||||||
1214 | return (errors > 0 ? -1 : 0); | |||||
1215 | } | |||||
1216 | ||||||
1217 | static int | |||||
1218 | exec_keycode(struct op_keycode *opk) | |||||
1219 | { | |||||
1220 | if (!opk->target_keycode) { | |||||
1221 | int i, j; | |||||
1222 | KeyCode free; | |||||
1223 | if (!opk->count) | |||||
1224 | return (0); | |||||
1225 | free = 0; | |||||
1226 | for (i = min_keycode; i <= max_keycode; i++) { | |||||
1227 | for (j = 0; j < opk->count; j++) { | |||||
1228 | if (XKeycodeToKeysym(dpy, (KeyCode) i, j) != opk->keysyms[j]) | |||||
1229 | break; | |||||
1230 | } | |||||
1231 | if (j >= opk->count) | |||||
1232 | return (0); | |||||
1233 | if (free) | |||||
1234 | continue; | |||||
1235 | for (j = 0; j < 8; j++) { | |||||
1236 | if (XKeycodeToKeysym(dpy, (KeyCode) i, j) != None0L) | |||||
1237 | break; | |||||
1238 | } | |||||
1239 | if (j >= 8) | |||||
1240 | free = i; | |||||
1241 | } | |||||
1242 | if (!free) { | |||||
1243 | fprintf(stderr__stderrp, "%s: no available keycode for assignment\n", | |||||
1244 | ProgramName); | |||||
1245 | return (-1); | |||||
1246 | } | |||||
1247 | XChangeKeyboardMapping (dpy, free, opk->count, opk->keysyms, 1); | |||||
1248 | } else if (opk->count == 0) { | |||||
1249 | KeySym dummy = NoSymbol0L; | |||||
1250 | XChangeKeyboardMapping (dpy, opk->target_keycode, 1, | |||||
1251 | &dummy, 1); | |||||
1252 | } else { | |||||
1253 | XChangeKeyboardMapping (dpy, opk->target_keycode, opk->count, | |||||
1254 | opk->keysyms, 1); | |||||
1255 | } | |||||
1256 | return (0); | |||||
1257 | } | |||||
1258 | ||||||
1259 | static int | |||||
1260 | exec_add(struct op_addmodifier *opam) | |||||
1261 | { | |||||
1262 | int i; | |||||
1263 | int status; | |||||
1264 | ||||||
1265 | status = 0; | |||||
1266 | for (i = 0; i < opam->count; i++) { | |||||
1267 | int num_kcs; | |||||
1268 | KeyCode *kcs; | |||||
1269 | ||||||
1270 | kcs = KeysymToKeycodes (dpy, opam->keysyms[i], &num_kcs); | |||||
1271 | if (num_kcs == 0) | |||||
1272 | status = -1; | |||||
1273 | while (--num_kcs >= 0) { | |||||
1274 | if (AddModifier (&map, *kcs++, opam->modifier) < 0) | |||||
1275 | status = -1; | |||||
1276 | } | |||||
1277 | } | |||||
1278 | return (status); | |||||
1279 | } | |||||
1280 | ||||||
1281 | static int | |||||
1282 | exec_remove(struct op_removemodifier *oprm) | |||||
1283 | { | |||||
1284 | int i; | |||||
1285 | int status; | |||||
1286 | ||||||
1287 | status = 0; | |||||
1288 | for (i = 0; i < oprm->count; i++) { | |||||
1289 | if (RemoveModifier (&map, oprm->keycodes[i], oprm->modifier) < 0) | |||||
1290 | status = -1; | |||||
1291 | } | |||||
1292 | return (status); | |||||
1293 | } | |||||
1294 | ||||||
1295 | static int | |||||
1296 | exec_clear(struct op_clearmodifier *opcm) | |||||
1297 | { | |||||
1298 | return (ClearModifier (&map, opcm->modifier)); | |||||
1299 | } | |||||
1300 | ||||||
1301 | ||||||
1302 | static int | |||||
1303 | exec_pointer(struct op_pointer *opp) | |||||
1304 | { | |||||
1305 | return (SetPointerMap (opp->button_codes, opp->count)); | |||||
1306 | } | |||||
1307 | ||||||
1308 | void | |||||
1309 | print_modifier_map(void) | |||||
1310 | { | |||||
1311 | PrintModifierMapping (map, stdout__stdoutp); | |||||
1312 | return; | |||||
1313 | } | |||||
1314 | ||||||
1315 | void | |||||
1316 | print_key_table(Boolint exprs) | |||||
1317 | { | |||||
1318 | PrintKeyTable (exprs, stdout__stdoutp); | |||||
1319 | return; | |||||
1320 | } | |||||
1321 | ||||||
1322 | void | |||||
1323 | print_pointer_map(void) | |||||
1324 | { | |||||
1325 | PrintPointerMap (stdout__stdoutp); | |||||
1326 | return; | |||||
1327 | } | |||||
1328 | ||||||
1329 |