#!/bin/sh
#  
#  			***keytool - Ken Laprade - 31 Oct 88 ***
#
#   A tooltool application to run a command with interactively redefineable
#   function keys.  C-S-M-right-mouse brings up a menu that controls key
#   definition.  Two keysets may be defined called primary and secondary.
#   Any undefined C-S-M-function-key will toggle between the two keysets.
#   Typical useful commands: /bin/ssh, /usr/ucb/telnet, /usr/ucb/rlogin.
#  
#
if test "$1" = "-i" ; then
   shift;
   if test "$1" = "" ; then
      echo "Usage:  keytool [-i init_file] command [args ...]"; exit
   fi
   initfile=$1; shift;
else
   initfile="$HOME/.keytool"
fi
cmd=$1
if /bin/test "$cmd" = "" ; then
   echo "Usage:  keytool [-i init_file] command [args ...]"; exit
fi
if test ! -x $cmd ; then
   echo "keytool: bad command: $cmd."; exit
fi
shift; 

tooltool $@ << END

application "$cmd"
label "keytool"

/* Fonts: */
#define POPUP_FONT "/usr/lib/fonts/fixedwidthfonts/screen.b.14"
#define TEXT_FONT "/usr/lib/fonts/fixedwidthfonts/screen.r.14"
#define SPECIAL_FONT "./keytool.r.14"
#define MENU_FONT "/usr/lib/fonts/fixedwidthfonts/screen.b.14"

#define DEFAULT_INIT_FILE "./keytool.defaults"

/* Macros for repetitive functions: */
#define init_keys() { \
    /* Initialize all keys, both primary and secondary keysets. */ \
    for (i = 0; i<cardinality(keyname); i++) keypress[0][keyname[i]] = empty_key; \
    keypress[1] = keypress[0]; \
  }

#define read_init_file() { \
    /* Read key definitions from initialization file. */  \
    if (exists(init_file)) file = init_file; \
    else file = DEFAULT_INIT_FILE; \
    contents = output_of("/bin/cat ",file); \
    if (substr(contents,1,10) == "SEPARATOR=") { \
      item_separator = substr(contents,11,1); \
      line_separator = substr(contents,12,1); \
    } \
    else { \
      item_separator = "\t"; \
      line_separator = "\n"; \
    } \
    delimiters = line_separator; \
    lines = tokenize(contents); \
    delimiters = (item_separator,"'"); \
    keyset = 0; \
    abort = 0;	/* Flag from init_file_error popup window. */ \
    for (i=0; i<cardinality(lines) && !abort; i++) { \
      if (substr(lines[i],1,7) == "PRIMARY") keyset = 0; \
      else if (substr(lines[i],1,9) == "SECONDARY") keyset = 1; \
      else if (substr(lines[i],1,10) == "SEPARATOR=") ; \
      else { \
        s = index(lines[i],item_separator); \
        if (s > 0) { \
          k = substr(lines[i],1,s-1); \
          for (j=0,ok=0; j<cardinality(keyname) && !ok; j++) \
            if (keyname[j] == k) ok++; \
        } \
        if (!ok) {\
          error = lines[i]; \
          popup init_file_error; \
        } \
        else \
          keypress[keyset][k] = tokenize(substr(lines[i],s+1)); \
      } \
    } \
    delimiters = " \t\r\n"; \
    definition = keypress[active_keyset][keyname[selected_key]][selected_shift]; \
  }

initialize {
  init_file = "$initfile";
  active_keyset = 0;
  selected_key = 0;
  selected_shift = 0;
  remove line_separator;

  /* Initialize valid keynames and positions. */
  keynames = "L2 L3 L4 L9 L10 F1 F2 F3 F4 F5 F6 F7 F8 F9 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 LEFT MIDDLE RIGHT";
  keyname = tokenize(keynames);
  for (i=0; i<cardinality(keyname); i++) keynum[keyname[i]] = i;
  position = tokenize("NORMAL SHIFT CONTROL SHIFT_CONTROL META META_SHIFT META_CONTROL META_SHIFT_CONTROL");
  /* Define an empty key. */
  for (i=0; i<cardinality(position); i++) empty_key[i] = "";

  /* Read key definitions from initialization file. */
  init_keys();
  read_init_file();
}

dialog init_file_error
  size 8 by 40 characters
  gadgets
    top
    font POPUP_FONT
    label at 10 10
      "Key definition error in keytool initialization file."
    end_label
    text error at 10 30
      display 40
      label "Error:"
      font SPECIAL_FONT
    end_text
    button at 90 50
      normal  "  Continue  " remove init_file_error;
    end_button
    button at 260 50
      normal  "   Abort   " { abort++; remove init_file_error; }
      control "   Quit" { abort++; exit; remove init_file_error; }
    end_button
  end_gadgets
end_dialog

dialog write_file_error
  size 8 by 40 characters
  gadgets
    left
    align center
    font POPUP_FONT
    label
      "Cannot write to keytool initialization file!"
    end_label
    button
      normal  "  OK  " remove write_file_error;
    end_button
  end_gadgets
end_dialog

dialog key_definition_window
  size 8 by 40 characters
  label "Key Definitions"
  gadgets
    top
    proportional
    font POPUP_FONT
#define XL1 10
#define XL2 48
#define XF1 91
#define XTEXT1 105
#define XF2 129
#define XF3 167
#define XTEXT2 177
#define XML 196
#define XTEXT3 205
#define XF4 250
#define XMM 315
#define XF5 333
#define XTEXT4 397
#define XF6 416
#define XMR 434
#define XF7 499
#define XTEXT5 522
#define XTEXT6 550
#define XTEXT7 575
#define XF8 582
#define XF9 620
#define XR1 663
#define XR2 701
#define XR3 739
#define Y1 5
#define Y2 30
#define Y3 55
#define Y4 80
#define Y5 105
#define YTEXT2 34
#define YTEXT3 59
#define YTEXT4 85
#define YTEXT5 109

#define key_button(NAME,K,X,Y) button at X Y \
    normal NAME { selected_key = keynum["K"]; selected_shift = 0; \
                  definition = keypress[active_keyset]["K"][0]; } \
    shift NAME { selected_key = keynum["K"]; selected_shift = 1; \
                  definition = keypress[active_keyset]["K"][1]; } \
    control NAME { selected_key = keynum["K"]; selected_shift = 2; \
                  definition = keypress[active_keyset]["K"][2]; } \
    shift control NAME { selected_key = keynum["K"]; selected_shift = 3; \
                  definition = keypress[active_keyset]["K"][3]; } \
    meta NAME { selected_key = keynum["K"]; selected_shift = 4; \
                  definition = keypress[active_keyset]["K"][4]; } \
    meta shift NAME { selected_key = keynum["K"]; selected_shift = 5; \
                  definition = keypress[active_keyset]["K"][5]; } \
    meta control NAME { selected_key = keynum["K"]; selected_shift = 6; \
                  definition = keypress[active_keyset]["K"][6]; } \
    meta shift control NAME { selected_key = keynum["K"]; selected_shift = 7; \
                  definition = keypress[active_keyset]["K"][7]; } \
  end_button

#define select_key(TEXT) TEXT definition = keypress[active_keyset][keyname[selected_key]][selected_shift];

    key_button("L2 ",L2,XL2,Y1)
    key_button("L3 ",L3,XL1,Y2)
    key_button("L4 ",L4,XL2,Y2)
    key_button("L9 ",L9,XL1,Y5)
    key_button("L10",L10,XL2,Y5)
    key_button("L10",L10,XL2,Y5)
    key_button("F1 ",F1,XF1,Y1)
    key_button("F2 ",F2,XF2,Y1)
    key_button("   F3   ",F3,XF3,Y1)
    key_button("   F4   ",F4,XF4,Y1)
    key_button("   F5   ",F5,XF5,Y1)
    key_button("   F6   ",F6,XF6,Y1)
    key_button("   F7   ",F7,XF7,Y1)
    key_button("F8 ",F8,XF8,Y1)
    key_button("F9 ",F9,XF9,Y1)
    key_button("R1 ",R1,XR1,Y1)
    key_button("R2 ",R2,XR2,Y1)
    key_button("R3 ",R3,XR3,Y1)
    key_button("R4 ",R4,XR1,Y2)
    key_button("R5 ",R5,XR2,Y2)
    key_button("R6 ",R6,XR3,Y2)
    key_button("R7 ",R7,XR1,Y3)
    key_button("R8 ",R8,XR2,Y3)
    key_button("R9 ",R9,XR3,Y3)
    key_button("R10",R10,XR1,Y4)
    key_button("R11",R11,XR2,Y4)
    key_button("R12",R12,XR3,Y4)
    key_button("R13",R13,XR1,Y5)
    key_button("R14",R14,XR2,Y5)
    key_button("R15",R15,XR3,Y5)
    key_button(" MOUSE LEFT ",LEFT,XML,Y2)
    key_button("MOUSE MIDDLE",MIDDLE,XMM,Y2)
    key_button("MOUSE RIGHT ",RIGHT,XMR,Y2)
    button at XTEXT7 Y4
      normal " DONE " remove key_definition_window;
    end_button
    choice active_keyset at XTEXT3 YTEXT4
      display horizontal
      label "Keyset: "
      select_key("Primary  ")
      select_key("Secondary")
    end_choice
    choice selected_shift at XTEXT1 YTEXT5
      display current
      select_key(" NORMAL") select_key("  SHIFT") select_key("CONTROL") select_key("SH CTRL")
      select_key("   META") select_key(" M SHFT") select_key(" M CTRL") select_key("  M S C")
    end_choice
    choice selected_key at XTEXT2 YTEXT5
      display current
      select_key("L2") select_key("L3") select_key("L4") select_key("L9") select_key("L10")
      select_key("F1") select_key("F2") select_key("F3") select_key("F4") select_key("F5")
      select_key("F6") select_key("F7") select_key("F8") select_key("F9")
      select_key("R1") select_key("R2") select_key("R3") select_key("R4") select_key("R5")
      select_key("R6") select_key("R7") select_key("R8") select_key("R9") select_key("R10")
      select_key("R11") select_key("R12") select_key("R13") select_key("R14") select_key("R15")
      select_key("LFT") select_key("MID") select_key("RHT")
    end_choice
    text definition at XTEXT3 YTEXT5
      label ":"
      display 40
      font SPECIAL_FONT
      trigger ""
      ignore ""
    end_text
    button at XTEXT7 Y5
      normal "DEFINE" keypress[active_keyset][keyname[selected_key]][selected_shift] = definition;
    end_button
    button at XTEXT6 Y5
      normal "\t":SPECIAL_FONT definition = (definition,"\t");
      shift "\177":SPECIAL_FONT definition = (definition,"\177");
      control "^U":SPECIAL_FONT definition = (definition,"^U");
      shift control "^W":SPECIAL_FONT definition = (definition,"^W");
    end_button
    text init_file at XTEXT1 YTEXT3
      label "File:"
      display 29
      font TEXT_FONT
      completion " ^Z"
    end_text
    button at XTEXT7 Y3
      normal " SAVE " {
        if ((exists(init_file) && !writable(init_file)) || !writable(head(init_file)))
          popup write_file_error;
        else {
          /* Clear out lines array. */
          lines = 0;
          l = 0;
          if (item_separator == "") item_separator = "\t";
          if (line_separator == "") line_separator = "\n";
          lines[l++] = ("SEPARATOR=",item_separator);
          lines[l++] = "PRIMARY";
          delimiters = item_separator;
          for (i = 0; i<cardinality(keyname); i++) {
            for (j=0; j<cardinality(position); j++) {
              if (keypress[0][keyname[i]][j] == "")
                /* Put a '' in any unused slots as a placeholder for tokenize. */
                 temp[j] = "''";
              else temp[j] = keypress[0][keyname[i]][j];
            }
            lines[l++] = (keyname[i],item_separator,temp);
          }
          lines[l++] = "SECONDARY";
          for (i = 0; i<cardinality(keyname); i++) {
            for (j=0; j<cardinality(position); j++) {
              if (keypress[1][keyname[i]][j] == "")
                /* Put a '' in any unused slots as a placeholder for tokenize. */
                 temp[j] = "''";
              else temp[j] = keypress[1][keyname[i]][j];
            }
            lines[l++] = (keyname[i],item_separator,temp);
          } 
          delimiters = line_separator;
          system("/bin/cat > ",init_file," << 'END-OF-FILE'\n",lines,"\n");
          delimiters = " \t\r\n";
        }
      }
      shift " LOAD" {
        /* Read key definitions from initialization file. */
        init_keys();
        read_init_file();
      }
      control " Copy Primary -> Secondary" {
        keypress[1] = keypress[0];
        definition = keypress[active_keyset][keyname[selected_key]][selected_shift];
      }
      shift control " Copy Secondary -> Primary" {
        keypress[0] = keypress[1];
        definition = keypress[active_keyset][keyname[selected_key]][selected_shift];
      }
      meta "Default File" {
        if (exists("$initfile")) init_file = "$initfile";
        else init_file = DEFAULT_INIT_FILE;
      }
    end_button
    choice displayed_separator at XTEXT4 YTEXT3
      display current
      "Item Separator" { remove line_separator; display item_separator; }
      "Line Separator" { remove item_separator; display line_separator; }
    end_choice
    text item_separator at XTEXT5 YTEXT3
      label ":"
      display 1
      retain 1
      font SPECIAL_FONT
      trigger ""
      ignore ""
    end_text
    text line_separator at XTEXT5 YTEXT3
      label ":"
      display 1
      retain 1
      font SPECIAL_FONT
      trigger ""
      ignore ""
    end_text
    button at XTEXT6 Y3
#define set_separator(S) { if (displayed_separator) line_separator = S; \
			  else item_separator = S; }
      normal "\t":SPECIAL_FONT set_separator("\t")
      shift "\177":SPECIAL_FONT set_separator("\177")
      control "^U":SPECIAL_FONT set_separator("^U")
      shift control "^W":SPECIAL_FONT set_separator("^W")
    end_button
  end_gadgets
end_dialog

keys
#define keydef(K)  key K \
    normal send keypress[active_keyset]["K"][0]; \
    shift send keypress[active_keyset]["K"][1]; \
    control send keypress[active_keyset]["K"][2]; \
    shift control send keypress[active_keyset]["K"][3]; \
    meta send keypress[active_keyset]["K"][4]; \
    meta shift send keypress[active_keyset]["K"][5]; \
    meta control send keypress[active_keyset]["K"][6]; \
    meta shift control { \
      if (keypress[active_keyset]["K"][7] == "") { \
        active_keyset = !active_keyset; \
        definition = keypress[active_keyset][keyname[selected_key]][selected_shift]; \
      } \
      else send keypress[active_keyset]["K"][7]; \
    } \
  end_key

  keydef(L2)
  keydef(L3)
  keydef(L4)
  keydef(L9)
  keydef(L10)
  keydef(F1)
  keydef(F2)
  keydef(F3)
  keydef(F4)
  keydef(F5)
  keydef(F6)
  keydef(F7)
  keydef(F8)
  keydef(F9)
  keydef(R1)
  keydef(R2)
  keydef(R3)
  keydef(R4)
  keydef(R5)
  keydef(R6)
  keydef(R7)
  keydef(R8)
  keydef(R9)
  keydef(R10)
  keydef(R11)
  keydef(R12)
  keydef(R13)
  keydef(R14)
  keydef(R15)
end_keys 

mouse
  base 0 characters
#define mousedef(K)  button K \
    /* Normal is left to perform the suntools functions. */ \
    shift send format(keypress[active_keyset]["K"][1],mouse_x,mouse_y); \
    control send format(keypress[active_keyset]["K"][2],mouse_x,mouse_y); \
    shift control send format(keypress[active_keyset]["K"][3],mouse_x,mouse_y); \
    meta send format(keypress[active_keyset]["K"][4],mouse_x,mouse_y); \
    meta shift send format(keypress[active_keyset]["K"][5],mouse_x,mouse_y); \
    meta control send format(keypress[active_keyset]["K"][6],mouse_x,mouse_y); \
    meta shift control send format(keypress[active_keyset]["K"][7],mouse_x,mouse_y); \
  end_button

  mousedef(LEFT)
  mousedef(MIDDLE)
  button RIGHT
    /* Normal is left to perform the suntools functions. */
    shift send format(keypress[active_keyset]["RIGHT"][1],mouse_x,mouse_y);
    control send format(keypress[active_keyset]["RIGHT"][2],mouse_x,mouse_y);
    shift control send format(keypress[active_keyset]["RIGHT"][3],mouse_x,mouse_y);
    meta send format(keypress[active_keyset]["RIGHT"][4],mouse_x,mouse_y);
    meta shift send format(keypress[active_keyset]["RIGHT"][5],mouse_x,mouse_y);
    meta control send format(keypress[active_keyset]["RIGHT"][6],mouse_x,mouse_y);
    meta shift control menu
      "Define Keys":MENU_FONT
        display key_definition_window;
      "Use Primary":MENU_FONT
        { active_keyset = 0; definition = keypress[0][keyname[selected_key]][selected_shift]; }
      "Use Secondary":MENU_FONT
        { active_keyset = 1; definition = keypress[1][keyname[selected_key]][selected_shift]; }
      "Read Init File":MENU_FONT {
        /* Read key definitions from initialization file. */
        init_keys();
        read_init_file();
      }
    end_menu
  end_button
end_mouse
END
