/*--------------------------------------------------------------*/
/* keybindings.c:  List of key bindings				*/
/* Copyright (c) 2002  Tim Edwards, Johns Hopkins University	*/
/*--------------------------------------------------------------*/

/*----------------------------------------------------------------------*/
/*      written by Tim Edwards, 2/27/01                                 */
/*----------------------------------------------------------------------*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>	 /* for tolower(), toupper() */
#include <math.h>

#include <X11/Intrinsic.h>
#include <X11/StringDefs.h>
#define  XK_MISCELLANY
#define  XK_LATIN1
#define  XK_XKB_KEYS
#include <X11/keysymdef.h>

/*----------------------------------------------------------------------*/
/* Local includes							*/
/*----------------------------------------------------------------------*/

#ifdef TCL_WRAPPER 
#include <tk.h>
#endif

#include "xcircuit.h"

/*----------------------------------------------------------------------*/
/* Function prototypes							*/
/*----------------------------------------------------------------------*/

#include "prototypes.h"

/*----------------------------------------------------------------------*/
/* Global variables							*/
/*----------------------------------------------------------------------*/

keybinding *keylist = NULL;

extern Display *dpy;
extern char  _STR[150], _STR2[250];

/*--------------------------------------------------------------*/
/* Key modifiers (convenience definitions)			*/
/*--------------------------------------------------------------*/

#define ALT (Mod1Mask << 16)
#define CTRL (ControlMask << 16)
#define CAPSLOCK (LockMask << 16)
#define SHIFT (ShiftMask << 16)
#define BUTTON1 (Button1Mask << 16)
#define BUTTON2 (Button2Mask << 16)
#define BUTTON3 (Button3Mask << 16)

/*--------------------------------------------------------------*/
/* This list declares all the functions which can be bound to   */
/* keys.  It must match the order of the enumeration listed in	*/
/* xcircuit.h!							*/
/*--------------------------------------------------------------*/

static char *function_names[NUM_FUNCTIONS + 1] = {
   "Page", "Justify", "Superscript", "Subscript", "Normalscript",
   "Nextfont", "Boldfont", "Italicfont", "Normalfont", "Underline",
   "Overline", "ISO Encoding", "Halfspace", "Quarterspace",
   "Special", "Tab Stop", "Tab Forward", "Tab Backward",
   "Text Return", "Text Delete", "Text Right", "Text Left",
   "Text Up", "Text Down", "Text Split", 
   "Text Home", "Text End", "Linebreak", "Parameter",
   "Parameterize Point", "Break at Point", "Delete Point", "Insert Point",
   "Append Point", "Next Point", "Attach", "Next Library", "Library Directory",
   "Library Move", "Library Copy", "Library Edit", "Library Delete",
   "Library Duplicate", "Library Hide", "Library Virtual Copy",
   "Page Directory", "Library Pop", "Virtual Copy",
   "Help", "Redraw", "View", "Zoom In", "Zoom Out", "Pan",
   "Double Snap", "Halve Snap", "Pan Left", "Pan Right", "Pan Up",
   "Pan Down", "Write", "Rotate", "Flip X", "Flip Y", "Snap", "Snap To",
   "Pop", "Push", "Delete", "Select", "Box", "Arc", "Text",
   "Exchange", "Copy", "Move", "Join", "Unjoin", "Spline", "Edit",
   "Undo", "Redo", "Select Save", "Unselect", "Dashed", "Dotted",
   "Solid", "Prompt", "Dot", "Wire", "Start", "Finish", "Cancel",
   "Nothing", "Exit",
   "Netlist", "Swap", "Pin Label", "Pin Global", "Info Label",
   "Connectivity", "Sim", "SPICE", "PCB", "SPICE Flat",
   NULL			/* sentinel */
};

/*--------------------------------------------------------------*/
/* Return TRUE if the indicated key (keysym + bit-shifted state)*/
/* is bound to some function.					*/
/*--------------------------------------------------------------*/

Boolean ismacro(int keywstate)
{
   keybinding *ksearch;

   for (ksearch = keylist; ksearch != NULL; ksearch = ksearch->nextbinding)
      if (keywstate == ksearch->keywstate)
	 return True;

   return False;
}

/*--------------------------------------------------------------*/
/* Return the first key binding for the indicated function	*/
/*--------------------------------------------------------------*/

int firstbinding(int function)
{
   keybinding *ksearch;

   for (ksearch = keylist; ksearch != NULL; ksearch = ksearch->nextbinding)
      if (function == ksearch->function)
	 return ksearch->keywstate;

   return -1;
}

/*--------------------------------------------------------------*/
/* Return TRUE if the indicated key (keysym + bit-shifted state)*/
/* is bound to the indicated function (called by name)		*/
/*--------------------------------------------------------------*/

Boolean isbound(int keywstate, int function)
{
   keybinding *ksearch;

   for (ksearch = keylist; ksearch != NULL; ksearch = ksearch->nextbinding)
      if ((keywstate == ksearch->keywstate) && (function == ksearch->function))
	 return True;

   return False;
}

/*--------------------------------------------------------------*/
/* Return TRUE if the key binding (keysym + bit-shifted state)  */
/* is bound to a function name which matches the indicated	*/
/* function name to "length" characters.  If the function name	*/
/* includes a numerical suffix (e.g., "Page 1"), the suffix is	*/
/* converted to an integer and passed back in "retnum".		*/
/*--------------------------------------------------------------*/

Boolean isnbound(int keywstate, int function, short *retnum)
{
   keybinding *ksearch;

   for (ksearch = keylist; ksearch != NULL; ksearch = ksearch->nextbinding) {
      if ((keywstate == ksearch->keywstate) && (function == ksearch->function)) {
	 if (retnum != NULL)
	    *retnum = (ksearch->value);
	 return True;
      }
   }
   return False;
}

/*--------------------------------------------------------------*/
/* Return the string associated with a function, or NULL if the	*/
/* function value is out-of-bounds.				*/
/*--------------------------------------------------------------*/

char *func_to_string(int function)
{
   if ((function < 0) || (function >= NUM_FUNCTIONS)) return NULL;
   return function_names[function];
}

/*--------------------------------------------------------------*/
/* Identify a function with the string version of its name	*/
/*--------------------------------------------------------------*/

int string_to_func(const char *funcstring, short *value)
{
   int i;

   for (i = 0; i < NUM_FUNCTIONS; i++)
   {
      if (function_names[i] == NULL) {
	 Fprintf(stderr, "Error: resolve bindings and function strings!\n");
	 return -1;	  /* should not happen? */
      }
      if (!strcmp(funcstring, function_names[i]))
	 return i;
   }

   /* Check if this string might have a value attached */

   if (value != NULL)
      for (i = 0; i < NUM_FUNCTIONS; i++)
         if (!strncmp(funcstring, function_names[i], strlen(function_names[i]))) {
	    sscanf(funcstring + strlen(function_names[i]), "%hd", value);
	    return i;
	 }

   return -1;
}

/*--------------------------------------------------------------*/
/* Make a key sym from a string representing the key state 	*/
/*--------------------------------------------------------------*/

int string_to_key(const char *keystring)
{
   int ct, keywstate = 0;
   const char *kptr = keystring;

   while(1) {
      if (*kptr == '\0') return -1;
      if (!strncmp(kptr, "XK_", 3))
	 kptr += 3;
      else if (!strncmp(kptr, "Shift_", 6)) {
	 keywstate |= SHIFT;
	 kptr += 6;
      }
      else if (!strncmp(kptr, "Capslock_", 9)) {
	 keywstate |= CAPSLOCK;
	 kptr += 9;
      }
      else if (!strncmp(kptr, "Control_", 8)) {
	 keywstate |= CTRL;
	 kptr += 8;
      }
      else if (!strncmp(kptr, "Alt_", 4)) {
	 keywstate |= ALT;
	 kptr += 4;
      }
      else if (!strncmp(kptr, "Meta_", 5)) {
	 keywstate |= ALT;
	 kptr += 5;
      }
      else if (*kptr == '^') {
	 kptr++;
	 ct = (int)tolower(*kptr);
	 keywstate |= CTRL | ct;
	 break;
      }
      else if (*(kptr + 1) == '\0') {
	 if ((*kptr) < 32)
	    keywstate |= CTRL | (int)('A' + (*kptr) - 1);
	 else
	    keywstate |= (int)(*kptr);
	 break;
      }
      else {
         if (!strncmp(kptr, "Button", 6)) {
	    switch (*(kptr + 6)) {
	       case '1': keywstate = (Button1Mask << 16); break;
	       case '2': keywstate = (Button2Mask << 16); break;
	       case '3': keywstate = (Button3Mask << 16); break;
	    }
         }
	 else {
	    /* When any modifier keys are used, presence of SHIFT */
	    /* requires that the corresponding key be uppercase,  */
	    /* and lack of SHIFT requires lowercase.  Enforce it  */
	    /* here so that it is not necessary for the user to	  */
	    /* do so.						  */
	    if (*(kptr + 1) == '\0') {
	       if (keywstate & SHIFT)
	          ct = (int)toupper(*kptr);
	       else
	          ct = (int)tolower(*kptr);
	       keywstate |= ct;
	    }
	    else
	       keywstate |= XStringToKeysym(kptr);
	 }
	 break;
      }
   }
   return keywstate;
}

/*--------------------------------------------------------------*/
/* Convert a function into a string representing all of its	*/
/* key bindings, or convert a key into a string representing	*/
/* all of its function bindings.  One of the arguments is	*/
/* valid, and the other should be -1.				*/
/*--------------------------------------------------------------*/

char *binding_to_string(int keywstate, int function)
{
   keybinding *ksearch;
   char *retstr, *tmpstr;
   Bool first = True;

   retstr = (char *)malloc(1);
   retstr[0] = '\0';
   for (ksearch = keylist; ksearch != NULL; ksearch = ksearch->nextbinding) {
      if (function == ksearch->function || keywstate == ksearch->keywstate) {
	 if (function < 0)
	    tmpstr = function_names[ksearch->function];
	 else
	    tmpstr = key_to_string(ksearch->keywstate);
	 retstr = (char *)realloc(retstr, strlen(retstr) + strlen(tmpstr) + 
		((first) ? 1 : 3));
	 if (!first) strcat(retstr, ", ");
	 strcat(retstr, tmpstr);
	 if (function >= 0) free(tmpstr);
	 first = False;
      }
   }
   if (retstr[0] == '\0') {
      retstr = (char *)realloc(retstr, 10);
      strcat(retstr, "<unbound>");
   }
   return(retstr);
}

/*--------------------------------------------------------------*/
/* Convert a key sym into a string				*/
/*--------------------------------------------------------------*/

char *key_to_string(int keywstate)
{
   static char hex[17] = "0123456789ABCDEF";
   char *kptr, *str = NULL;
   KeySym ks = keywstate & 0xffff;
   int kmod = keywstate >> 16;

   if (ks != NoSymbol) str = XKeysymToString(ks);

   kptr = (char *)malloc(32);
   kptr[0] = '\0';
   if (kmod & Mod1Mask) strcat(kptr, "Alt_");
   if (kmod & ControlMask) strcat(kptr, "Control_");
   if (kmod & LockMask) strcat(kptr, "Capslock_");
   if (kmod & ShiftMask) strcat(kptr, "Shift_");

   if (str != NULL) {
      kptr = (char *)realloc(kptr, strlen(str) + 32);
      strcat(kptr, str);
   }
   else {
      kptr = (char *)realloc(kptr, 40);
      if (kmod & Button1Mask) strcat(kptr, "Button1");
      else if (kmod & Button2Mask) strcat(kptr, "Button2");
      else if (kmod & Button3Mask) strcat(kptr, "Button3");
      else {
	 kptr[0] = '0';
	 kptr[1] = 'x';
	 kptr[2] = hex[(kmod & 0xf)];
	 kptr[3] = hex[(keywstate & 0xf000) >> 12];
	 kptr[4] = hex[(keywstate & 0x0f00) >>  8];
	 kptr[5] = hex[(keywstate & 0x00f0) >>  4];
	 kptr[6] = hex[(keywstate & 0x000f)      ];
	 kptr[7] = '\0';
      }
   }
   return kptr;
}

/*--------------------------------------------------------------*/
/* Print the bindings for the (polygon) edit functions		*/
/*--------------------------------------------------------------*/

void printeditbindings()
{
   char *tstr;

   _STR2[0] = '\0';

   tstr = key_to_string(firstbinding(XCF_Edit_Break));
   strcat(_STR2, tstr);
   strcat(_STR2, "=");
   strcat(_STR2, func_to_string(XCF_Edit_Break));
   strcat(_STR2, ", ");
   free(tstr);

   tstr = key_to_string(firstbinding(XCF_Edit_Delete));
   strcat(_STR2, tstr);
   strcat(_STR2, "=");
   strcat(_STR2, func_to_string(XCF_Edit_Delete));
   strcat(_STR2, ", ");
   free(tstr);

   tstr = key_to_string(firstbinding(XCF_Edit_Insert));
   strcat(_STR2, tstr);
   strcat(_STR2, "=");
   strcat(_STR2, func_to_string(XCF_Edit_Insert));
   strcat(_STR2, ", ");
   free(tstr);

   tstr = key_to_string(firstbinding(XCF_Edit_Param));
   strcat(_STR2, tstr);
   strcat(_STR2, "=");
   strcat(_STR2, func_to_string(XCF_Edit_Param));
   strcat(_STR2, ", ");
   free(tstr);

   tstr = key_to_string(firstbinding(XCF_Edit_Next));
   strcat(_STR2, tstr);
   strcat(_STR2, "=");
   strcat(_STR2, func_to_string(XCF_Edit_Next));
   free(tstr);

   Wprintf(_STR2);
}

/*--------------------------------------------------------------*/
/* Remove a key binding from the list				*/
/*--------------------------------------------------------------*/

int remove_binding(int keywstate, int function)
{
   keybinding *ksearch, *klast = NULL;

   for (ksearch = keylist; ksearch != NULL; ksearch = ksearch->nextbinding) {
      if ((function == ksearch->function)
		&& (keywstate == ksearch->keywstate)) {
	 if (klast == NULL)
	    keylist = ksearch->nextbinding;
	 else
	    klast->nextbinding = ksearch->nextbinding;
	 free(ksearch);
	 return 0;
      }
      klast = ksearch;
   }
   return -1;
}

/*--------------------------------------------------------------*/
/* Wrapper for remove_binding					*/
/*--------------------------------------------------------------*/

void remove_keybinding(const char *keystring, const char *fstring)
{
   int function = string_to_func(fstring, NULL);
   int keywstate = string_to_key(keystring);

   if ((function < 0) || (remove_binding(keywstate, function) < 0)) {
      sprintf(_STR2, "Key binding \'%s\' to \'%s\' does not exist in list.",
		keystring, fstring);
      Wprintf(_STR2);
   }
}

/*--------------------------------------------------------------*/
/* Add a key binding to the list				*/
/*--------------------------------------------------------------*/

int add_vbinding(int keywstate, int function, short value)
{
   keybinding *newbinding;

   /* If key is already bound to the function, ignore it */

   if (isbound(keywstate, function)) return 1;

   /* Add the new key binding */

   newbinding = (keybinding *)malloc(sizeof(keybinding));
   newbinding->keywstate = keywstate;
   newbinding->function = function;
   newbinding->value = value;
   newbinding->nextbinding = keylist;
   keylist = newbinding;
   return 0;
}

/*--------------------------------------------------------------*/
/* Wrapper function for key binding without any values		*/
/*--------------------------------------------------------------*/

int add_binding(int keywstate, int function)
{
   return add_vbinding(keywstate, function, -1);
}

/*--------------------------------------------------------------*/
/* Wrapper function for key binding with function as string	*/
/*--------------------------------------------------------------*/

int add_keybinding(const char *keystring, const char *fstring)
{
   short value = -1;
   int function = string_to_func(fstring, &value);
   int keywstate = string_to_key(keystring);

   if (function < 0)
      return -1;
   else
      return add_vbinding(keywstate, function, value);
}

/*--------------------------------------------------------------*/
/* Create list of default key bindings.				*/
/* These are conditional upon any bindings set in the startup	*/
/* file .xcircuitrc.						*/
/*--------------------------------------------------------------*/

void default_keybindings()
{
   add_vbinding(XK_1, XCF_Page, 1);
   add_vbinding(XK_2, XCF_Page, 2);
   add_vbinding(XK_3, XCF_Page, 3);
   add_vbinding(XK_4, XCF_Page, 4);
   add_vbinding(XK_5, XCF_Page, 5);
   add_vbinding(XK_6, XCF_Page, 6);
   add_vbinding(XK_7, XCF_Page, 7);
   add_vbinding(XK_8, XCF_Page, 8);
   add_vbinding(XK_9, XCF_Page, 9);
   add_vbinding(XK_0, XCF_Page, 10);

   add_vbinding(SHIFT | XK_KP_1, XCF_Justify, 0);
   add_vbinding(SHIFT | XK_KP_2, XCF_Justify, 1);
   add_vbinding(SHIFT | XK_KP_3, XCF_Justify, 2);
   add_vbinding(SHIFT | XK_KP_4, XCF_Justify, 3);
   add_vbinding(SHIFT | XK_KP_5, XCF_Justify, 4);
   add_vbinding(SHIFT | XK_KP_6, XCF_Justify, 5);
   add_vbinding(SHIFT | XK_KP_7, XCF_Justify, 6);
   add_vbinding(SHIFT | XK_KP_8, XCF_Justify, 7);
   add_vbinding(SHIFT | XK_KP_9, XCF_Justify, 8);

   add_vbinding(XK_KP_End, XCF_Justify, 0);
   add_vbinding(XK_KP_Down, XCF_Justify, 1);
   add_vbinding(XK_KP_Next, XCF_Justify, 2);
   add_vbinding(XK_KP_Left, XCF_Justify, 3);
   add_vbinding(XK_KP_Begin, XCF_Justify, 4);
   add_vbinding(XK_KP_Right, XCF_Justify, 5);
   add_vbinding(XK_KP_Home, XCF_Justify, 6);
   add_vbinding(XK_KP_Up, XCF_Justify, 7);
   add_vbinding(XK_KP_Prior, XCF_Justify, 8);

   add_binding(XK_Delete, XCF_Text_Delete);
   add_binding(XK_Return, XCF_Text_Return);
   add_binding(XK_BackSpace, XCF_Text_Delete);
   add_binding(XK_Left, XCF_Text_Left);
   add_binding(XK_Right, XCF_Text_Right);
   add_binding(XK_Up, XCF_Text_Up);
   add_binding(XK_Down, XCF_Text_Down);
   add_binding(ALT | XK_x, XCF_Text_Split);
   add_binding(XK_Home, XCF_Text_Home);
   add_binding(XK_End, XCF_Text_End);
   add_binding(XK_Tab, XCF_TabForward);
   add_binding(SHIFT | XK_Tab, XCF_TabBackward);
#ifdef XK_ISO_Left_Tab
   add_binding(SHIFT | XK_ISO_Left_Tab, XCF_TabBackward);
#endif
   add_binding(ALT | XK_Tab, XCF_TabStop);
   add_binding(XK_KP_Add, XCF_Superscript);
   add_binding(XK_KP_Subtract, XCF_Subscript);
   add_binding(XK_KP_Enter, XCF_Normalscript);
   add_binding(ALT | XK_f, XCF_Nextfont);
   add_binding(ALT | XK_b, XCF_Boldfont);
   add_binding(ALT | XK_i, XCF_Italicfont);
   add_binding(ALT | XK_n, XCF_Normalfont);
   add_binding(ALT | XK_u, XCF_Underline);
   add_binding(ALT | XK_o, XCF_Overline);
   add_binding(ALT | XK_e, XCF_ISO_Encoding);
   add_binding(ALT | XK_Return, XCF_Linebreak);
   add_binding(ALT | XK_h, XCF_Halfspace);
   add_binding(ALT | XK_q, XCF_Quarterspace);
   add_binding(XK_backslash, XCF_Special);
   add_binding(ALT | XK_c, XCF_Special);
   add_binding(ALT | XK_p, XCF_Parameter);
   add_binding(XK_p, XCF_Edit_Param);
   add_binding(XK_x, XCF_Edit_Break);
   add_binding(XK_d, XCF_Edit_Delete);
   add_binding(XK_Delete, XCF_Edit_Delete);
   add_binding(XK_i, XCF_Edit_Insert);
   add_binding(XK_Insert, XCF_Edit_Insert);
   add_binding(XK_e, XCF_Edit_Next);
   add_binding(XK_A, XCF_Attach);
   add_binding(XK_V, XCF_Virtual);
   add_binding(XK_l, XCF_Next_Library);
   add_binding(XK_L, XCF_Library_Directory);
   add_binding(XK_c, XCF_Library_Copy);
   add_binding(XK_E, XCF_Library_Edit);
   add_binding(XK_D, XCF_Library_Delete);
   add_binding(XK_C, XCF_Library_Duplicate);
   add_binding(XK_H, XCF_Library_Hide);
   add_binding(XK_V, XCF_Library_Virtual);
   add_binding(XK_M, XCF_Library_Move);
   add_binding(XK_P, XCF_Page_Directory);
   add_binding(XK_less, XCF_Library_Pop);
   add_binding(XK_h, XCF_Help);
   add_binding(XK_question, XCF_Help);
   add_binding(XK_space, XCF_Redraw);
   add_binding(XK_Redo, XCF_Redraw);
   add_binding(XK_Undo, XCF_Redraw);
   add_binding(XK_Home, XCF_View);
   add_binding(XK_v, XCF_View);
   add_binding(XK_Z, XCF_Zoom_In);
   add_binding(XK_z, XCF_Zoom_Out);
   add_binding(XK_p, XCF_Pan);
   add_binding(XK_plus, XCF_Double_Snap);
   add_binding(XK_minus, XCF_Halve_Snap);
   add_binding(XK_Left, XCF_Pan_Left);
   add_binding(XK_Right, XCF_Pan_Right);
   add_binding(XK_Up, XCF_Pan_Up);
   add_binding(XK_Down, XCF_Pan_Down);
   add_binding(XK_W, XCF_Write);
   add_vbinding(XK_O, XCF_Rotate, -5);
   add_vbinding(XK_o, XCF_Rotate, 5);
   add_vbinding(XK_R, XCF_Rotate, -15);
   add_vbinding(XK_r, XCF_Rotate, 15);
   add_binding(XK_f, XCF_Flip_X);
   add_binding(XK_F, XCF_Flip_Y);
   add_binding(XK_S, XCF_Snap);
   add_binding(XK_less, XCF_Pop);
   add_binding(XK_greater, XCF_Push);
   add_binding(XK_Delete, XCF_Delete);
   add_binding(XK_d, XCF_Delete);
   add_binding(XK_F19, XCF_Select);
   add_binding(BUTTON2, XCF_Select);
   add_binding(XK_b, XCF_Box);
   add_binding(XK_a, XCF_Arc);
   add_binding(XK_t, XCF_Text);
   add_binding(XK_X, XCF_Exchange);
   add_binding(XK_c, XCF_Copy);
   add_binding(XK_j, XCF_Join);
   add_binding(XK_J, XCF_Unjoin);
   add_binding(XK_s, XCF_Spline);
   add_binding(XK_e, XCF_Edit);
   add_binding(XK_u, XCF_Undo);
   add_binding(XK_U, XCF_Redo);
   add_binding(XK_M, XCF_Select_Save);
   add_binding(XK_m, XCF_Select_Save);
   add_binding(XK_x, XCF_Unselect);
   add_binding(XK_bar, XCF_Dashed);
   add_binding(XK_colon, XCF_Dotted);
   add_binding(XK_underscore, XCF_Solid);
   add_binding(XK_percent, XCF_Prompt);
   add_binding(XK_period, XCF_Dot);
   add_binding(BUTTON1, XCF_Wire);
   add_binding(XK_w, XCF_Wire);
   add_binding(BUTTON3, XCF_Nothing);
   add_binding(CTRL | ALT | XK_q, XCF_Exit);
   add_binding(BUTTON1, XCF_Start);
   add_binding(SHIFT | BUTTON1, XCF_Finish);
   add_binding(BUTTON2, XCF_Finish);
   add_binding(BUTTON3, XCF_Cancel);
   add_binding(ALT | XK_s, XCF_SnapTo);
   add_binding(ALT | XK_q, XCF_Netlist);
   add_binding(XK_slash, XCF_Swap);
   add_binding(XK_T, XCF_Pin_Label);
   add_binding(XK_G, XCF_Pin_Global);
   add_binding(XK_I, XCF_Info_Label);
   add_binding(ALT | XK_w, XCF_Connectivity);

/* These are for test purposes only.  Menu selection is	*/
/* preferred.						*/

/* add_binding(ALT | XK_d, XCF_Sim);		*/
/* add_binding(ALT | XK_a, XCF_SPICE);		*/
/* add_binding(ALT | XK_f, XCF_SPICEflat);	*/
/* add_binding(ALT | XK_p, XCF_PCB);		*/

}

#undef ALT
#undef CTRL
#undef CAPSLOCK
#undef SHIFT
#undef BUTTON1
#undef BUTTON2
#undef BUTTON3

/*--------------------------------------------------------------*/
