1 /*--------------------------------------------------------------*/
2 /* keybindings.c:  List of key bindings				*/
3 /* Copyright (c) 2002  Tim Edwards, Johns Hopkins University	*/
4 /*--------------------------------------------------------------*/
5 
6 /*----------------------------------------------------------------------*/
7 /*      written by Tim Edwards, 2/27/01                                 */
8 /*----------------------------------------------------------------------*/
9 
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <ctype.h>	 /* for tolower(), toupper() */
14 #include <math.h>
15 
16 #ifndef XC_WIN32
17 #include <X11/Intrinsic.h>
18 #include <X11/StringDefs.h>
19 #endif
20 
21 #if !defined(XC_WIN32) || defined(TCL_WRAPPER)
22 #define  XK_MISCELLANY
23 #define  XK_LATIN1
24 #define  XK_XKB_KEYS
25 #include <X11/keysymdef.h>
26 #endif
27 
28 /*----------------------------------------------------------------------*/
29 /* Local includes							*/
30 /*----------------------------------------------------------------------*/
31 
32 #ifdef TCL_WRAPPER
33 #include <tk.h>
34 #endif
35 
36 #include "xcircuit.h"
37 
38 /*----------------------------------------------------------------------*/
39 /* Function prototypes							*/
40 /*----------------------------------------------------------------------*/
41 
42 #include "prototypes.h"
43 
44 /*----------------------------------------------------------------------*/
45 /* Global variables							*/
46 /*----------------------------------------------------------------------*/
47 
48 keybinding *keylist = NULL;
49 
50 extern Display *dpy;
51 extern char  _STR[150], _STR2[250];
52 extern int pressmode;
53 extern XCWindowData *areawin;
54 
55 /*----------------------------------------------------------------------*/
56 /* Key modifiers (convenience definitions)				*/
57 /* Use Mod5Mask for a "hold" ("press") definition.			*/
58 /* Why Mod5Mask?  Mod2Mask is used by fvwm2 for some obscure purpose,	*/
59 /* so I went to the other end (Mod5Mask is just below Button1Mask).	*/
60 /* Thanks to John Heil for reporting the problem and confirming the	*/
61 /* Mod5Mask solution.							*/
62 /*----------------------------------------------------------------------*/
63 
64 #define ALT (Mod1Mask << 16)
65 #define CTRL (ControlMask << 16)
66 #define CAPSLOCK (LockMask << 16)
67 #define SHIFT (ShiftMask << 16)
68 #define BUTTON1 (Button1Mask << 16)
69 #define BUTTON2 (Button2Mask << 16)
70 #define BUTTON3 (Button3Mask << 16)
71 #define BUTTON4 (Button4Mask << 16)
72 #define BUTTON5 (Button5Mask << 16)
73 #define HOLD (Mod4Mask << 16)
74 
75 #define ALL_WINDOWS (xcWidget)NULL
76 
77 /*--------------------------------------------------------------*/
78 /* This list declares all the functions which can be bound to   */
79 /* keys.  It must match the order of the enumeration listed in	*/
80 /* xcircuit.h!							*/
81 /*--------------------------------------------------------------*/
82 
83 static char *function_names[NUM_FUNCTIONS + 1] = {
84    "Page", "Anchor", "Superscript", "Subscript", "Normalscript",
85    "Nextfont", "Boldfont", "Italicfont", "Normalfont", "Underline",
86    "Overline", "ISO Encoding", "Halfspace", "Quarterspace",
87    "Special", "Tab Stop", "Tab Forward", "Tab Backward",
88    "Text Return", "Text Delete", "Text Right", "Text Left",
89    "Text Up", "Text Down", "Text Split",
90    "Text Home", "Text End", "Linebreak", "Parameter",
91    "Parameterize Point", "Change Style", "Delete Point", "Insert Point",
92    "Append Point", "Next Point", "Attach", "Next Library", "Library Directory",
93    "Library Move", "Library Copy", "Library Edit", "Library Delete",
94    "Library Duplicate", "Library Hide", "Library Virtual Copy",
95    "Page Directory", "Library Pop", "Virtual Copy",
96    "Help", "Redraw", "View", "Zoom In", "Zoom Out", "Pan",
97    "Double Snap", "Halve Snap", "Write", "Rotate", "Flip X",
98    "Flip Y", "Snap", "Snap To",
99    "Pop", "Push", "Delete", "Select", "Box", "Arc", "Text",
100    "Exchange", "Copy", "Move", "Join", "Unjoin", "Spline", "Edit",
101    "Undo", "Redo", "Select Save", "Unselect", "Dashed", "Dotted",
102    "Solid", "Prompt", "Dot", "Wire", "Cancel", "Nothing", "Exit",
103    "Netlist", "Swap", "Pin Label", "Pin Global", "Info Label", "Graphic",
104    "Select Box", "Connectivity", "Continue Element", "Finish Element",
105    "Continue Copy", "Finish Copy", "Finish", "Cancel Last", "Sim",
106    "SPICE", "PCB", "SPICE Flat", "Rescale", "Reorder", "Color",
107    "Margin Stop", "Text Delete Param",
108    NULL			/* sentinel */
109 };
110 
111 /*--------------------------------------------------------------*/
112 /* Return TRUE if the indicated key (keysym + bit-shifted state)*/
113 /* is bound to some function.					*/
114 /*--------------------------------------------------------------*/
115 
ismacro(xcWidget window,int keywstate)116 Boolean ismacro(xcWidget window, int keywstate)
117 {
118    keybinding *ksearch;
119 
120    for (ksearch = keylist; ksearch != NULL; ksearch = ksearch->nextbinding)
121       if (ksearch->window == ALL_WINDOWS || ksearch->window == window)
122          if (keywstate == ksearch->keywstate)
123 	    return True;
124 
125    return False;
126 }
127 
128 /*--------------------------------------------------------------*/
129 /* Return the first key binding for the indicated function	*/
130 /*--------------------------------------------------------------*/
131 
firstbinding(xcWidget window,int function)132 int firstbinding(xcWidget window, int function)
133 {
134    keybinding *ksearch;
135    int keywstate = -1;
136 
137    for (ksearch = keylist; ksearch != NULL; ksearch = ksearch->nextbinding) {
138       if (ksearch->function == function) {
139          if (ksearch->window == window)
140 	    return ksearch->keywstate;
141          else if (ksearch->window == ALL_WINDOWS)
142 	    keywstate = ksearch->keywstate;
143       }
144    }
145    return keywstate;
146 }
147 
148 /*--------------------------------------------------------------*/
149 /* Find the first function bound to the indicated key that is	*/
150 /* compatible with the current state (eventmode).  Window-	*/
151 /* specific bindings shadow ALL_WINDOWS bindings.  Return the	*/
152 /* function number if found, or -1 if no compatible functions	*/
153 /* are bound to the key state.					*/
154 /*--------------------------------------------------------------*/
155 
boundfunction(xcWidget window,int keywstate,short * retnum)156 int boundfunction(xcWidget window, int keywstate, short *retnum)
157 {
158    keybinding *ksearch;
159    int tempfunc = -1;
160 
161    for (ksearch = keylist; ksearch != NULL; ksearch = ksearch->nextbinding) {
162       if (keywstate == ksearch->keywstate) {
163 	 if (compatible_function(ksearch->function)) {
164 	    if (ksearch->window == window) {
165 	       if (retnum != NULL) *retnum = (ksearch->value);
166 	       return ksearch->function;
167 	    }
168 	    else if (ksearch->window == ALL_WINDOWS) {
169 	       if (retnum != NULL) *retnum = (ksearch->value);
170 	       tempfunc = ksearch->function;
171 	    }
172 	 }
173       }
174    }
175    return tempfunc;
176 }
177 
178 /*--------------------------------------------------------------*/
179 /* Check if an entry exists for a given key-function pair	*/
180 /*--------------------------------------------------------------*/
181 
isbound(xcWidget window,int keywstate,int function,short value)182 int isbound(xcWidget window, int keywstate, int function, short value)
183 {
184    keybinding *ksearch;
185 
186    for (ksearch = keylist; ksearch != NULL; ksearch = ksearch->nextbinding)
187       if (keywstate == ksearch->keywstate && function == ksearch->function)
188 	 if (window == ALL_WINDOWS || window == ksearch->window ||
189 		ksearch->window == ALL_WINDOWS)
190 	    if (value == -1 || value == ksearch->value || ksearch->value == -1)
191 	       return TRUE;
192 
193    return FALSE;
194 }
195 
196 /*--------------------------------------------------------------*/
197 /* Return the string associated with a function, or NULL if the	*/
198 /* function value is out-of-bounds.				*/
199 /*--------------------------------------------------------------*/
200 
func_to_string(int function)201 char *func_to_string(int function)
202 {
203    if ((function < 0) || (function >= NUM_FUNCTIONS)) return NULL;
204    return function_names[function];
205 }
206 
207 /*--------------------------------------------------------------*/
208 /* Identify a function with the string version of its name	*/
209 /*--------------------------------------------------------------*/
210 
string_to_func(const char * funcstring,short * value)211 int string_to_func(const char *funcstring, short *value)
212 {
213    int i;
214 
215    for (i = 0; i < NUM_FUNCTIONS; i++)
216    {
217       if (function_names[i] == NULL) {
218 	 Fprintf(stderr, "Error: resolve bindings and function strings!\n");
219 	 return -1;	  /* should not happen? */
220       }
221       if (!strcmp(funcstring, function_names[i]))
222 	 return i;
223    }
224 
225    /* Check if this string might have a value attached */
226 
227    if (value != NULL)
228       for (i = 0; i < NUM_FUNCTIONS; i++)
229          if (!strncmp(funcstring, function_names[i], strlen(function_names[i]))) {
230 	    sscanf(funcstring + strlen(function_names[i]), "%hd", value);
231 	    return i;
232 	 }
233 
234    return -1;
235 }
236 
237 /*--------------------------------------------------------------*/
238 /* Make a key sym from a string representing the key state 	*/
239 /*--------------------------------------------------------------*/
240 
string_to_key(const char * keystring)241 int string_to_key(const char *keystring)
242 {
243    int ct, keywstate = 0;
244    const char *kptr = keystring;
245 
246    while(1) {
247       if (*kptr == '\0') return -1;
248       if (!strncmp(kptr, "XK_", 3))
249 	 kptr += 3;
250       else if (!strncmp(kptr, "Shift_", 6)) {
251 	 keywstate |= SHIFT;
252 	 kptr += 6;
253       }
254       else if (!strncmp(kptr, "Capslock_", 9)) {
255 	 keywstate |= CAPSLOCK;
256 	 kptr += 9;
257       }
258       else if (!strncmp(kptr, "Control_", 8)) {
259 	 keywstate |= CTRL;
260 	 kptr += 8;
261       }
262       else if (!strncmp(kptr, "Alt_", 4)) {
263 	 keywstate |= ALT;
264 	 kptr += 4;
265       }
266       else if (!strncmp(kptr, "Meta_", 5)) {
267 	 keywstate |= ALT;
268 	 kptr += 5;
269       }
270       else if (!strncmp(kptr, "Hold_", 5)) {
271 	 keywstate |= HOLD;
272 	 kptr += 5;
273       }
274       else if (*kptr == '^') {
275 	 kptr++;
276 	 ct = (int)tolower(*kptr);
277 	 keywstate |= CTRL | ct;
278 	 break;
279       }
280       else if (*(kptr + 1) == '\0') {
281 	 if ((*kptr) < 32)
282 	    keywstate |= CTRL | (int)('A' + (*kptr) - 1);
283 	 else
284 	    keywstate |= (int)(*kptr);
285 	 break;
286       }
287       else {
288          if (!strncmp(kptr, "Button", 6)) {
289 	    switch (*(kptr + 6)) {
290 	       case '1': keywstate = (Button1Mask << 16); break;
291 	       case '2': keywstate = (Button2Mask << 16); break;
292 	       case '3': keywstate = (Button3Mask << 16); break;
293 	       case '4': keywstate = (Button4Mask << 16); break;
294 	       case '5': keywstate = (Button5Mask << 16); break;
295 	    }
296          }
297 	 else {
298 	    /* When any modifier keys are used, presence of SHIFT */
299 	    /* requires that the corresponding key be uppercase,  */
300 	    /* and lack of SHIFT requires lowercase.  Enforce it  */
301 	    /* here so that it is not necessary for the user to	  */
302 	    /* do so.						  */
303 	    if (*(kptr + 1) == '\0') {
304 	       if (keywstate & SHIFT)
305 	          ct = (int)toupper(*kptr);
306 	       else
307 	          ct = (int)tolower(*kptr);
308 	       keywstate |= ct;
309 	    }
310 	    else
311 	       keywstate |= XStringToKeysym(kptr);
312 	 }
313 	 break;
314       }
315    }
316    return keywstate;
317 }
318 
319 /*--------------------------------------------------------------*/
320 /* Convert a function into a string representing all of its	*/
321 /* key bindings.						*/
322 /*--------------------------------------------------------------*/
323 
function_binding_to_string(xcWidget window,int function)324 char *function_binding_to_string(xcWidget window, int function)
325 {
326    keybinding *ksearch;
327    char *retstr, *tmpstr;
328    Bool first = True;
329 
330    retstr = (char *)malloc(1);
331    retstr[0] = '\0';
332    for (ksearch = keylist; ksearch != NULL; ksearch = ksearch->nextbinding) {
333       if (function == ksearch->function) {
334          if (ksearch->window == ALL_WINDOWS || ksearch->window == window) {
335 	    tmpstr = key_to_string(ksearch->keywstate);
336 	    if (tmpstr != NULL) {
337 	       retstr = (char *)realloc(retstr, strlen(retstr) + strlen(tmpstr) +
338 		   ((first) ? 1 : 3));
339 	       if (!first) strcat(retstr, ", ");
340 	       strcat(retstr, tmpstr);
341 	       free(tmpstr);
342 	    }
343 	    first = False;
344 	 }
345       }
346    }
347    if (retstr[0] == '\0') {
348       retstr = (char *)realloc(retstr, 10);
349       strcat(retstr, "<unbound>");
350    }
351    return(retstr);
352 }
353 
354 /*--------------------------------------------------------------*/
355 /* Convert a key into a string representing all of its function	*/
356 /* bindings.							*/
357 /*--------------------------------------------------------------*/
358 
key_binding_to_string(xcWidget window,int keywstate)359 char *key_binding_to_string(xcWidget window, int keywstate)
360 {
361    keybinding *ksearch;
362    char *retstr, *tmpstr;
363    Bool first = True;
364 
365    retstr = (char *)malloc(1);
366    retstr[0] = '\0';
367    for (ksearch = keylist; ksearch != NULL; ksearch = ksearch->nextbinding) {
368       if (keywstate == ksearch->keywstate) {
369          if (ksearch->window == ALL_WINDOWS || ksearch->window == window) {
370 	    tmpstr = function_names[ksearch->function];
371 	    if (tmpstr != NULL) {
372 	       retstr = (char *)realloc(retstr, strlen(retstr) + strlen(tmpstr) +
373 		   ((first) ? 1 : 3));
374 	       if (!first) strcat(retstr, ", ");
375 	       strcat(retstr, tmpstr);
376 	    }
377 	    first = False;
378 	 }
379       }
380    }
381    if (retstr[0] == '\0') {
382       retstr = (char *)realloc(retstr, 10);
383       strcat(retstr, "<unbound>");
384    }
385    return(retstr);
386 }
387 
388 /*--------------------------------------------------------------*/
389 /* Return an allocated string name of the function that		*/
390 /* is bound to the indicated key state for the indicated	*/
391 /* window and compattible with the current event mode.		*/
392 /*--------------------------------------------------------------*/
393 
compat_key_to_string(xcWidget window,int keywstate)394 char *compat_key_to_string(xcWidget window, int keywstate)
395 {
396    char *retstr, *tmpstr;
397    int function;
398 
399    function = boundfunction(window, keywstate, NULL);
400    tmpstr = func_to_string(function);
401 
402    /* Pass back "Nothing" for unbound key states, since a	*/
403    /* wrapper script may want to use the result as an action.	*/
404 
405    if (tmpstr == NULL) {
406       retstr = (char *)malloc(8);
407       strcpy(retstr, "Nothing");
408    }
409    else
410       retstr = strdup(tmpstr);
411 
412    return(retstr);
413 }
414 
415 /*--------------------------------------------------------------*/
416 /* Convert a key sym into a string				*/
417 /*--------------------------------------------------------------*/
418 
key_to_string(int keywstate)419 char *key_to_string(int keywstate)
420 {
421    static char hex[17] = "0123456789ABCDEF";
422    char *kptr, *str = NULL;
423    KeySym ks;
424    int kmod;
425 
426    ks = keywstate & 0xffff;
427    kmod = keywstate >> 16;
428 #if defined(XC_WIN32) && defined(TCL_WRAPPER)
429    if (ks != NoSymbol) str = XKeysymToString_TkW32(ks);
430 #else
431    if (ks != NoSymbol) str = XKeysymToString(ks);
432 #endif
433 
434    kptr = (char *)malloc(32);
435    kptr[0] = '\0';
436    if (kmod & Mod1Mask) strcat(kptr, "Alt_");
437    if (kmod & Mod4Mask) strcat(kptr, "Hold_");
438    if (kmod & ControlMask) strcat(kptr, "Control_");
439    if (kmod & LockMask) strcat(kptr, "Capslock_");
440    if (kmod & ShiftMask) strcat(kptr, "Shift_");
441 
442    if (str != NULL) {
443       /* 33 is length of all modifiers concatenated + 1 */
444       kptr = (char *)realloc(kptr, strlen(str) + 33);
445       strcat(kptr, str);
446    }
447    else {
448       kptr = (char *)realloc(kptr, 40);
449       if (kmod & Button1Mask) strcat(kptr, "Button1");
450       else if (kmod & Button2Mask) strcat(kptr, "Button2");
451       else if (kmod & Button3Mask) strcat(kptr, "Button3");
452       else if (kmod & Button4Mask) strcat(kptr, "Button4");
453       else if (kmod & Button5Mask) strcat(kptr, "Button5");
454       else {
455 	 kptr[0] = '0';
456 	 kptr[1] = 'x';
457 	 kptr[2] = hex[(kmod & 0xf)];
458 	 kptr[3] = hex[(keywstate & 0xf000) >> 12];
459 	 kptr[4] = hex[(keywstate & 0x0f00) >>  8];
460 	 kptr[5] = hex[(keywstate & 0x00f0) >>  4];
461 	 kptr[6] = hex[(keywstate & 0x000f)      ];
462 	 kptr[7] = '\0';
463       }
464    }
465    return kptr;
466 }
467 
468 /*--------------------------------------------------------------*/
469 /* Print the bindings for the (polygon) edit functions		*/
470 /*--------------------------------------------------------------*/
471 
printeditbindings()472 void printeditbindings()
473 {
474    char *tstr;
475 
476    _STR2[0] = '\0';
477 
478    tstr = key_to_string(firstbinding(areawin->area, XCF_Edit_Delete));
479    strcat(_STR2, tstr);
480    strcat(_STR2, "=");
481    strcat(_STR2, func_to_string(XCF_Edit_Delete));
482    strcat(_STR2, ", ");
483    free(tstr);
484 
485    tstr = key_to_string(firstbinding(areawin->area, XCF_Edit_Insert));
486    strcat(_STR2, tstr);
487    strcat(_STR2, "=");
488    strcat(_STR2, func_to_string(XCF_Edit_Insert));
489    strcat(_STR2, ", ");
490    free(tstr);
491 
492    tstr = key_to_string(firstbinding(areawin->area, XCF_Edit_Param));
493    strcat(_STR2, tstr);
494    strcat(_STR2, "=");
495    strcat(_STR2, func_to_string(XCF_Edit_Param));
496    strcat(_STR2, ", ");
497    free(tstr);
498 
499    tstr = key_to_string(firstbinding(areawin->area, XCF_Edit_Next));
500    strcat(_STR2, tstr);
501    strcat(_STR2, "=");
502    strcat(_STR2, func_to_string(XCF_Edit_Next));
503    free(tstr);
504 
505    /* Use W3printf().  In the Tcl version, this prints to the	*/
506    /* message window but does not duplicate the output to 	*/
507    /* stdout, where it would be just an annoyance.		*/
508 
509    W3printf("%s", _STR2);
510 }
511 
512 /*--------------------------------------------------------------*/
513 /* Remove a key binding from the list				*/
514 /*								*/
515 /* Note:  This routine needs to correctly handle ALL_WINDOWS	*/
516 /* bindings that shadow specific window bindings.		*/
517 /*--------------------------------------------------------------*/
518 
remove_binding(xcWidget window,int keywstate,int function)519 int remove_binding(xcWidget window, int keywstate, int function)
520 {
521    keybinding *ksearch, *klast = NULL;
522 
523    for (ksearch = keylist; ksearch != NULL; ksearch = ksearch->nextbinding) {
524       if (window == ALL_WINDOWS || window == ksearch->window) {
525          if ((function == ksearch->function)
526 		&& (keywstate == ksearch->keywstate)) {
527 	    if (klast == NULL)
528 	       keylist = ksearch->nextbinding;
529 	    else
530 	       klast->nextbinding = ksearch->nextbinding;
531 	    free(ksearch);
532 	    return 0;
533          }
534       }
535       klast = ksearch;
536    }
537    return -1;
538 }
539 
540 /*--------------------------------------------------------------*/
541 /* Wrapper for remove_binding					*/
542 /*--------------------------------------------------------------*/
543 
remove_keybinding(xcWidget window,const char * keystring,const char * fstring)544 void remove_keybinding(xcWidget window, const char *keystring, const char *fstring)
545 {
546    int function = string_to_func(fstring, NULL);
547    int keywstate = string_to_key(keystring);
548 
549    if ((function < 0) || (remove_binding(window, keywstate, function) < 0)) {
550       Wprintf("Key binding \'%s\' to \'%s\' does not exist in list.",
551 		keystring, fstring);
552    }
553 }
554 
555 /*--------------------------------------------------------------*/
556 /* Add a key binding to the list				*/
557 /*--------------------------------------------------------------*/
558 
add_vbinding(xcWidget window,int keywstate,int function,short value)559 int add_vbinding(xcWidget window, int keywstate, int function, short value)
560 {
561    keybinding *newbinding;
562 
563    /* If key is already bound to the function, ignore it */
564 
565    if (isbound(window, keywstate, function, value)) return 1;
566 
567    /* Add the new key binding */
568 
569    newbinding = (keybinding *)malloc(sizeof(keybinding));
570    newbinding->window = window;
571    newbinding->keywstate = keywstate;
572    newbinding->function = function;
573    newbinding->value = value;
574    newbinding->nextbinding = keylist;
575    keylist = newbinding;
576    return 0;
577 }
578 
579 /*--------------------------------------------------------------*/
580 /* Wrapper function for key binding without any values		*/
581 /*--------------------------------------------------------------*/
582 
add_binding(xcWidget window,int keywstate,int function)583 int add_binding(xcWidget window, int keywstate, int function)
584 {
585    return add_vbinding(window, keywstate, function, (short)-1);
586 }
587 
588 /*--------------------------------------------------------------*/
589 /* Wrapper function for key binding with function as string	*/
590 /*--------------------------------------------------------------*/
591 
add_keybinding(xcWidget window,const char * keystring,const char * fstring)592 int add_keybinding(xcWidget window, const char *keystring, const char *fstring)
593 {
594    short value = -1;
595    int function = string_to_func(fstring, &value);
596    int keywstate = string_to_key(keystring);
597 
598    if (function < 0)
599       return -1;
600    else
601       return add_vbinding(window, keywstate, function, value);
602 }
603 
604 /*--------------------------------------------------------------*/
605 /* Create list of default key bindings.				*/
606 /* These are conditional upon any bindings set in the startup	*/
607 /* file .xcircuitrc.						*/
608 /*--------------------------------------------------------------*/
609 
default_keybindings()610 void default_keybindings()
611 {
612    add_vbinding(ALL_WINDOWS, XK_1, XCF_Page, 1);
613    add_vbinding(ALL_WINDOWS, XK_2, XCF_Page, 2);
614    add_vbinding(ALL_WINDOWS, XK_3, XCF_Page, 3);
615    add_vbinding(ALL_WINDOWS, XK_4, XCF_Page, 4);
616    add_vbinding(ALL_WINDOWS, XK_5, XCF_Page, 5);
617    add_vbinding(ALL_WINDOWS, XK_6, XCF_Page, 6);
618    add_vbinding(ALL_WINDOWS, XK_7, XCF_Page, 7);
619    add_vbinding(ALL_WINDOWS, XK_8, XCF_Page, 8);
620    add_vbinding(ALL_WINDOWS, XK_9, XCF_Page, 9);
621    add_vbinding(ALL_WINDOWS, XK_0, XCF_Page, 10);
622 
623    add_vbinding(ALL_WINDOWS, SHIFT | XK_KP_1, XCF_Anchor, 0);
624    add_vbinding(ALL_WINDOWS, SHIFT | XK_KP_2, XCF_Anchor, 1);
625    add_vbinding(ALL_WINDOWS, SHIFT | XK_KP_3, XCF_Anchor, 2);
626    add_vbinding(ALL_WINDOWS, SHIFT | XK_KP_4, XCF_Anchor, 3);
627    add_vbinding(ALL_WINDOWS, SHIFT | XK_KP_5, XCF_Anchor, 4);
628    add_vbinding(ALL_WINDOWS, SHIFT | XK_KP_6, XCF_Anchor, 5);
629    add_vbinding(ALL_WINDOWS, SHIFT | XK_KP_7, XCF_Anchor, 6);
630    add_vbinding(ALL_WINDOWS, SHIFT | XK_KP_8, XCF_Anchor, 7);
631    add_vbinding(ALL_WINDOWS, SHIFT | XK_KP_9, XCF_Anchor, 8);
632 
633    add_vbinding(ALL_WINDOWS, XK_KP_End, XCF_Anchor, 0);
634    add_vbinding(ALL_WINDOWS, XK_KP_Down, XCF_Anchor, 1);
635    add_vbinding(ALL_WINDOWS, XK_KP_Next, XCF_Anchor, 2);
636    add_vbinding(ALL_WINDOWS, XK_KP_Left, XCF_Anchor, 3);
637    add_vbinding(ALL_WINDOWS, XK_KP_Begin, XCF_Anchor, 4);
638    add_vbinding(ALL_WINDOWS, XK_KP_Right, XCF_Anchor, 5);
639    add_vbinding(ALL_WINDOWS, XK_KP_Home, XCF_Anchor, 6);
640    add_vbinding(ALL_WINDOWS, XK_KP_Up, XCF_Anchor, 7);
641    add_vbinding(ALL_WINDOWS, XK_KP_Prior, XCF_Anchor, 8);
642 
643    add_binding(ALL_WINDOWS, XK_Delete, XCF_Text_Delete);
644    add_binding(ALL_WINDOWS, ALT | XK_Delete, XCF_Text_Delete_Param);
645    add_binding(ALL_WINDOWS, XK_Return, XCF_Text_Return);
646    add_binding(ALL_WINDOWS, BUTTON1, XCF_Text_Return);
647    add_binding(ALL_WINDOWS, XK_BackSpace, XCF_Text_Delete);
648    add_binding(ALL_WINDOWS, XK_Left, XCF_Text_Left);
649    add_binding(ALL_WINDOWS, XK_Right, XCF_Text_Right);
650    add_binding(ALL_WINDOWS, XK_Up, XCF_Text_Up);
651    add_binding(ALL_WINDOWS, XK_Down, XCF_Text_Down);
652    add_binding(ALL_WINDOWS, ALT | XK_x, XCF_Text_Split);
653    add_binding(ALL_WINDOWS, XK_Home, XCF_Text_Home);
654    add_binding(ALL_WINDOWS, XK_End, XCF_Text_End);
655    add_binding(ALL_WINDOWS, XK_Tab, XCF_TabForward);
656    add_binding(ALL_WINDOWS, SHIFT | XK_Tab, XCF_TabBackward);
657 #ifdef XK_ISO_Left_Tab
658    add_binding(ALL_WINDOWS, SHIFT | XK_ISO_Left_Tab, XCF_TabBackward);
659 #endif
660    add_binding(ALL_WINDOWS, ALT | XK_Tab, XCF_TabStop);
661    add_binding(ALL_WINDOWS, XK_KP_Add, XCF_Superscript);
662    add_binding(ALL_WINDOWS, XK_KP_Subtract, XCF_Subscript);
663    add_binding(ALL_WINDOWS, XK_KP_Enter, XCF_Normalscript);
664    add_vbinding(ALL_WINDOWS, ALT | XK_f, XCF_Font, 1000);
665    add_binding(ALL_WINDOWS, ALT | XK_b, XCF_Boldfont);
666    add_binding(ALL_WINDOWS, ALT | XK_i, XCF_Italicfont);
667    add_binding(ALL_WINDOWS, ALT | XK_n, XCF_Normalfont);
668    add_binding(ALL_WINDOWS, ALT | XK_u, XCF_Underline);
669    add_binding(ALL_WINDOWS, ALT | XK_o, XCF_Overline);
670    add_binding(ALL_WINDOWS, ALT | XK_e, XCF_ISO_Encoding);
671    add_binding(ALL_WINDOWS, ALT | XK_Return, XCF_Linebreak);
672    add_binding(ALL_WINDOWS, ALT | XK_h, XCF_Halfspace);
673    add_binding(ALL_WINDOWS, ALT | XK_q, XCF_Quarterspace);
674 #ifndef TCL_WRAPPER
675    add_binding(ALL_WINDOWS, ALT | XK_p, XCF_Parameter);
676 #endif
677    add_binding(ALL_WINDOWS, XK_backslash, XCF_Special);
678    add_binding(ALL_WINDOWS, ALT | XK_c, XCF_Special);
679    add_binding(ALL_WINDOWS, XK_p, XCF_Edit_Param);
680    add_binding(ALL_WINDOWS, XK_d, XCF_Edit_Delete);
681    add_binding(ALL_WINDOWS, XK_Delete, XCF_Edit_Delete);
682    add_binding(ALL_WINDOWS, XK_i, XCF_Edit_Insert);
683    add_binding(ALL_WINDOWS, XK_Insert, XCF_Edit_Insert);
684    add_binding(ALL_WINDOWS, XK_e, XCF_Edit_Next);
685    add_binding(ALL_WINDOWS, BUTTON1, XCF_Edit_Next);
686    add_binding(ALL_WINDOWS, XK_A, XCF_Attach);
687    add_binding(ALL_WINDOWS, XK_V, XCF_Virtual);
688    add_binding(ALL_WINDOWS, XK_l, XCF_Next_Library);
689    add_binding(ALL_WINDOWS, XK_L, XCF_Library_Directory);
690    add_binding(ALL_WINDOWS, XK_c, XCF_Library_Copy);
691    add_binding(ALL_WINDOWS, XK_E, XCF_Library_Edit);
692    add_binding(ALL_WINDOWS, XK_e, XCF_Library_Edit);
693    add_binding(ALL_WINDOWS, XK_D, XCF_Library_Delete);
694    add_binding(ALL_WINDOWS, XK_C, XCF_Library_Duplicate);
695    add_binding(ALL_WINDOWS, XK_H, XCF_Library_Hide);
696    add_binding(ALL_WINDOWS, XK_V, XCF_Library_Virtual);
697    add_binding(ALL_WINDOWS, XK_M, XCF_Library_Move);
698    add_binding(ALL_WINDOWS, XK_m, XCF_Library_Move);
699    add_binding(ALL_WINDOWS, XK_P, XCF_Page_Directory);
700    add_binding(ALL_WINDOWS, XK_less, XCF_Library_Pop);
701    add_binding(ALL_WINDOWS, HOLD | BUTTON1, XCF_Library_Pop);
702    add_binding(ALL_WINDOWS, XK_h, XCF_Help);
703    add_binding(ALL_WINDOWS, XK_question, XCF_Help);
704    add_binding(ALL_WINDOWS, XK_space, XCF_Redraw);
705    add_binding(ALL_WINDOWS, XK_Redo, XCF_Redraw);
706    add_binding(ALL_WINDOWS, XK_Undo, XCF_Redraw);
707    add_binding(ALL_WINDOWS, XK_Home, XCF_View);
708    add_binding(ALL_WINDOWS, XK_v, XCF_View);
709    add_binding(ALL_WINDOWS, XK_Z, XCF_Zoom_In);
710    add_binding(ALL_WINDOWS, XK_z, XCF_Zoom_Out);
711    add_vbinding(ALL_WINDOWS, XK_p, XCF_Pan, 0);
712    add_binding(ALL_WINDOWS, XK_plus, XCF_Double_Snap);
713    add_binding(ALL_WINDOWS, XK_minus, XCF_Halve_Snap);
714    add_vbinding(ALL_WINDOWS, XK_Left, XCF_Pan, 1);
715    add_vbinding(ALL_WINDOWS, XK_Right, XCF_Pan, 2);
716    add_vbinding(ALL_WINDOWS, XK_Up, XCF_Pan, 3);
717    add_vbinding(ALL_WINDOWS, XK_Down, XCF_Pan, 4);
718    add_binding(ALL_WINDOWS, XK_W, XCF_Write);
719    add_vbinding(ALL_WINDOWS, XK_O, XCF_Rotate, -5);
720    add_vbinding(ALL_WINDOWS, XK_o, XCF_Rotate, 5);
721    add_vbinding(ALL_WINDOWS, XK_R, XCF_Rotate, -15);
722    add_vbinding(ALL_WINDOWS, XK_r, XCF_Rotate, 15);
723    add_binding(ALL_WINDOWS, XK_f, XCF_Flip_X);
724    add_binding(ALL_WINDOWS, XK_F, XCF_Flip_Y);
725    add_binding(ALL_WINDOWS, XK_S, XCF_Snap);
726    add_binding(ALL_WINDOWS, XK_less, XCF_Pop);
727    add_binding(ALL_WINDOWS, XK_greater, XCF_Push);
728    add_binding(ALL_WINDOWS, XK_Delete, XCF_Delete);
729    add_binding(ALL_WINDOWS, XK_d, XCF_Delete);
730    add_binding(ALL_WINDOWS, XK_F19, XCF_Select);
731    add_binding(ALL_WINDOWS, XK_b, XCF_Box);
732    add_binding(ALL_WINDOWS, XK_a, XCF_Arc);
733    add_binding(ALL_WINDOWS, XK_t, XCF_Text);
734    add_binding(ALL_WINDOWS, XK_X, XCF_Exchange);
735    add_binding(ALL_WINDOWS, XK_c, XCF_Copy);
736    add_binding(ALL_WINDOWS, XK_j, XCF_Join);
737    add_binding(ALL_WINDOWS, XK_J, XCF_Unjoin);
738    add_binding(ALL_WINDOWS, XK_s, XCF_Spline);
739    add_binding(ALL_WINDOWS, XK_e, XCF_Edit);
740    add_binding(ALL_WINDOWS, XK_u, XCF_Undo);
741    add_binding(ALL_WINDOWS, XK_U, XCF_Redo);
742    add_binding(ALL_WINDOWS, XK_M, XCF_Select_Save);
743    add_binding(ALL_WINDOWS, XK_m, XCF_Select_Save);
744    add_binding(ALL_WINDOWS, XK_x, XCF_Unselect);
745    add_binding(ALL_WINDOWS, XK_bar, XCF_Dashed);
746    add_binding(ALL_WINDOWS, XK_colon, XCF_Dotted);
747    add_binding(ALL_WINDOWS, XK_underscore, XCF_Solid);
748    add_binding(ALL_WINDOWS, XK_percent, XCF_Prompt);
749    add_binding(ALL_WINDOWS, XK_period, XCF_Dot);
750 #ifndef TCL_WRAPPER
751    /* TCL_WRAPPER version req's binding to specific windows */
752    add_binding(ALL_WINDOWS, BUTTON1, XCF_Wire);
753 #endif
754    add_binding(ALL_WINDOWS, XK_w, XCF_Wire);
755    add_binding(ALL_WINDOWS, CTRL | ALT | XK_q, XCF_Exit);
756    add_binding(ALL_WINDOWS, HOLD | BUTTON1, XCF_Move);
757    add_binding(ALL_WINDOWS, BUTTON1, XCF_Continue_Element);
758    add_binding(ALL_WINDOWS, BUTTON1, XCF_Continue_Copy);
759    add_binding(ALL_WINDOWS, BUTTON1, XCF_Finish);
760    add_binding(ALL_WINDOWS, XK_Escape, XCF_Cancel);
761    add_binding(ALL_WINDOWS, ALT | XK_r, XCF_Rescale);
762    add_binding(ALL_WINDOWS, ALT | XK_s, XCF_SnapTo);
763    add_binding(ALL_WINDOWS, ALT | XK_q, XCF_Netlist);
764    add_binding(ALL_WINDOWS, XK_slash, XCF_Swap);
765    add_binding(ALL_WINDOWS, XK_T, XCF_Pin_Label);
766    add_binding(ALL_WINDOWS, XK_G, XCF_Pin_Global);
767    add_binding(ALL_WINDOWS, XK_I, XCF_Info_Label);
768    add_binding(ALL_WINDOWS, ALT | XK_w, XCF_Connectivity);
769 
770 /* These are for test purposes only.  Menu selection is	*/
771 /* preferred.						*/
772 
773 /* add_binding(ALL_WINDOWS, ALT | XK_d, XCF_Sim);		*/
774 /* add_binding(ALL_WINDOWS, ALT | XK_a, XCF_SPICE);		*/
775 /* add_binding(ALL_WINDOWS, ALT | XK_f, XCF_SPICEflat);	*/
776 /* add_binding(ALL_WINDOWS, ALT | XK_p, XCF_PCB);		*/
777 
778    /* Avoid spurious Num_Lock messages */
779    add_binding(ALL_WINDOWS, XK_Num_Lock, XCF_Nothing);
780 
781    /* 2-button vs. 3-button mouse bindings (set with -2	*/
782    /* commandline option; 3-button bindings default)	*/
783 
784    if (pressmode == 1) {
785       add_binding(ALL_WINDOWS, BUTTON3, XCF_Text_Return);
786       add_binding(ALL_WINDOWS, BUTTON3, XCF_Select);
787       add_binding(ALL_WINDOWS, HOLD | BUTTON3, XCF_SelectBox);
788       add_binding(ALL_WINDOWS, BUTTON3, XCF_Finish_Element);
789       add_binding(ALL_WINDOWS, BUTTON3, XCF_Finish_Copy);
790 
791       add_binding(ALL_WINDOWS, XK_BackSpace, XCF_Cancel_Last);
792       add_binding(ALL_WINDOWS, XK_BackSpace, XCF_Cancel);
793    }
794    else {
795       add_binding(ALL_WINDOWS, BUTTON2, XCF_Text_Return);
796       add_binding(ALL_WINDOWS, SHIFT | BUTTON1, XCF_Text_Return);
797       add_binding(ALL_WINDOWS, BUTTON2, XCF_Select);
798       add_binding(ALL_WINDOWS, SHIFT | BUTTON1, XCF_Select);
799       add_binding(ALL_WINDOWS, HOLD | BUTTON2, XCF_SelectBox);
800       add_binding(ALL_WINDOWS, SHIFT | HOLD | BUTTON1, XCF_Select);
801       add_binding(ALL_WINDOWS, BUTTON2, XCF_Finish_Element);
802       add_binding(ALL_WINDOWS, SHIFT | BUTTON1, XCF_Finish_Element);
803       add_binding(ALL_WINDOWS, BUTTON2, XCF_Finish_Copy);
804       add_binding(ALL_WINDOWS, SHIFT | BUTTON1, XCF_Finish_Copy);
805       add_binding(ALL_WINDOWS, BUTTON3, XCF_Cancel_Last);
806       add_binding(ALL_WINDOWS, BUTTON3, XCF_Cancel);
807    }
808 }
809 
810 #ifndef TCL_WRAPPER
811 /*----------------------------------------------*/
812 /* Mode-setting rebindings (non-Tcl version)	*/
813 /*----------------------------------------------*/
814 
815 static int button1mode = XCF_Wire;
816 
817 /*--------------------------------------------------------------*/
818 /* Re-bind BUTTON1 to the indicated function and optional value */
819 /*--------------------------------------------------------------*/
820 
mode_rebinding(int newmode,int newvalue)821 void mode_rebinding(int newmode, int newvalue)
822 {
823    xcWidget window = areawin->area;
824 
825    remove_binding(window, BUTTON1, button1mode);
826    add_vbinding(window, BUTTON1, newmode, (short)newvalue);
827    button1mode = newmode;
828    toolcursor(newmode);
829 }
830 
831 /*--------------------------------------------------------------*/
832 /* Execute the function associated with the indicated BUTTON1	*/
833 /* mode, but return the keybinding to its previous state.	*/
834 /*--------------------------------------------------------------*/
835 
mode_tempbinding(int newmode,int newvalue)836 void mode_tempbinding(int newmode, int newvalue)
837 {
838    short saveval;
839    XPoint cpos;
840    xcWidget window = areawin->area;
841 
842    if (boundfunction(window, BUTTON1, &saveval) == button1mode) {
843       remove_binding(window, BUTTON1, button1mode);
844       add_vbinding(window, BUTTON1, newmode, (short)newvalue);
845       cpos = UGetCursor();
846       eventdispatch(BUTTON1, (int)cpos.x, (int)cpos.y);
847       remove_binding(window, BUTTON1, newmode);
848       add_vbinding(window, BUTTON1, button1mode, saveval);
849    }
850    else
851       fprintf(stderr, "Error: No such button1 binding %s\n",
852 		func_to_string(button1mode));
853 }
854 
855 #endif /* TCL_WRAPPER */
856 
857 #undef ALT
858 #undef CTRL
859 #undef CAPSLOCK
860 #undef SHIFT
861 #undef BUTTON1
862 #undef BUTTON2
863 #undef BUTTON3
864 
865 /*--------------------------------------------------------------*/
866