00001 /*************************************************************************** 00002 *cr 00003 *cr (C) Copyright 1995-2019 The Board of Trustees of the 00004 *cr University of Illinois 00005 *cr All Rights Reserved 00006 *cr 00007 ***************************************************************************/ 00008 00009 /*************************************************************************** 00010 * RCS INFORMATION: 00011 * 00012 * $RCSfile: cmd_user.C,v $ 00013 * $Author: johns $ $Locker: $ $State: Exp $ 00014 * $Revision: 1.28 $ $Date: 2019年01月17日 21:21:03 $ 00015 * 00016 *************************************************************************** 00017 * DESCRIPTION: 00018 * Commands to allow the user to customize the hotkeys and pop-up menus. 00019 ***************************************************************************/ 00020 00021 #include <string.h> 00022 #include <ctype.h> // for toupper/tolower 00023 #include <tcl.h> 00024 #include "config.h" 00025 #include "Mouse.h" 00026 #include "utilities.h" 00027 #include "DisplayDevice.h" 00028 #include "JString.h" 00029 #include "VMDApp.h" 00030 00031 static int check_canonical_form(const char *s) { 00032 // Handle single-word key names 00033 if (!strcmp(s, "Escape")) return TRUE; 00034 if (!strcmp(s, "Up")) return TRUE; 00035 if (!strcmp(s, "Down")) return TRUE; 00036 if (!strcmp(s, "Left")) return TRUE; 00037 if (!strcmp(s, "Right")) return TRUE; 00038 if (!strcmp(s, "Page_Up")) return TRUE; 00039 if (!strcmp(s, "Page_Down")) return TRUE; 00040 if (!strcmp(s, "Home")) return TRUE; 00041 if (!strcmp(s, "End")) return TRUE; 00042 if (!strcmp(s, "Insert")) return TRUE; 00043 if (!strcmp(s, "Delete")) return TRUE; 00044 00045 // Handle key code sequences involving combinations 00046 if (s[0] == 'A') { 00047 // could be a letter, 'Alt-', or 'Aux-' 00048 s++; 00049 if (*s == 0) { 00050 return TRUE; 00051 } 00052 00053 // must be an Alt- or Aux- 00054 if (*s != 'l' && *s != 'u') { 00055 return FALSE; 00056 } 00057 00058 if (*s == 'l') { 00059 s++; 00060 if (*s++ != 't') return FALSE; 00061 if (*s++ != '-') return FALSE; 00062 } else if (*s == 'u') { 00063 s++; 00064 if (*s++ != 'x') return FALSE; 00065 if (*s++ != '-') return FALSE; 00066 } 00067 } 00068 00069 if (s[0] == 'C') { 00070 // could be a letter, or 'Control-' 00071 s++; 00072 if (*s == 0) { 00073 return TRUE; 00074 } 00075 // must be a Control 00076 if (*s++ != 'o') return FALSE; 00077 if (*s++ != 'n') return FALSE; 00078 if (*s++ != 't') return FALSE; 00079 if (*s++ != 'r') return FALSE; 00080 if (*s++ != 'o') return FALSE; 00081 if (*s++ != 'l') return FALSE; 00082 if (*s++ != '-') return FALSE; 00083 } 00084 00085 if (s[0] == 'F') { 00086 // could be a letter, or 'Fn' (F1-F12) 00087 s++; 00088 if (*s == 0) { 00089 return TRUE; 00090 } 00091 // must be an Fn 00092 if ((*s) >= '0' && (*s) <= '9') { 00093 s++; 00094 if (*s == 0) { 00095 return TRUE; 00096 } 00097 if (*s >= '0' && *s <= '2') { 00098 s++; 00099 if (*s == 0) { 00100 return TRUE; 00101 } 00102 } 00103 return FALSE; 00104 } 00105 } 00106 00107 // must be a single character 00108 if (s[0] == 0) return FALSE; // NULL, was invalid 00109 00110 if (s[1] == 0) return TRUE; // was a valid single character 00111 00112 return FALSE; // was otherwise invalid 00113 } 00114 00115 int text_cmd_user(ClientData cd, Tcl_Interp *interp, int argc, 00116 const char *argv[]) { 00117 00118 VMDApp *app = (VMDApp *)cd; 00119 00120 if(argc < 3) { 00121 Tcl_SetResult(interp, 00122 (char *) 00123 "user list keys\n" 00124 "user print keys\n" 00125 "user add key <character> <command>", 00126 TCL_STATIC); 00127 return TCL_ERROR; 00128 } 00129 00130 if(!strupncmp(argv[1], "add", CMDLEN)) { 00131 if (!strupncmp(argv[2], "key", CMDLEN)) { 00132 if(argc < 5) 00133 return TCL_ERROR; 00134 // check this is a valid string 00135 if (check_canonical_form(argv[3])) { 00136 const char *combstr = argv[4]; 00137 const char *desc = NULL; 00138 if (argc > 5) desc = argv[5]; 00139 int indx = app->userKeys.typecode(argv[3]); 00140 if (indx < 0) { 00141 app->userKeys.add_name(argv[3], stringdup(combstr)); 00142 } else { 00143 delete [] app->userKeys.data(indx); 00144 app->userKeys.set_data(indx, stringdup(combstr)); 00145 } 00146 if (desc) { 00147 indx = app->userKeyDesc.typecode(argv[3]); 00148 if (indx < 0) { 00149 app->userKeyDesc.add_name(argv[3], stringdup(desc)); 00150 } else { 00151 delete [] app->userKeyDesc.data(indx); 00152 app->userKeys.set_data(indx, stringdup(desc)); 00153 } 00154 } 00155 } else { 00156 Tcl_AppendResult(interp, "user key ", argv[3], " is not valid", 00157 NULL); 00158 return TCL_ERROR; 00159 } 00160 } else 00161 return TCL_ERROR; 00162 00163 } else if(!strupncmp(argv[1], "list", CMDLEN)) { 00164 // return definitions of current items 00165 if (argc != 3) { 00166 return TCL_ERROR; 00167 } 00168 if (!strcmp(argv[2], "keys")) { 00169 int num = app->userKeys.num(); 00170 for (int i=0; i<num; i++) { 00171 // return tuples of {keystroke command description} 00172 Tcl_AppendResult(interp, i==0?"":" ", "{", NULL); 00173 Tcl_AppendElement(interp, app->userKeys.name(i)); 00174 Tcl_AppendElement(interp, 00175 (const char *) app->userKeys.data(i)); 00176 int desc_typecode = app->userKeyDesc.typecode(app->userKeys.name(i)); 00177 if (desc_typecode >= 0) { 00178 Tcl_AppendElement(interp, 00179 (const char *) app->userKeyDesc.data(i)); 00180 } else { 00181 Tcl_AppendElement(interp, ""); 00182 } 00183 Tcl_AppendResult(interp, "}", NULL); 00184 } 00185 return TCL_OK; 00186 } else { 00187 return TCL_ERROR; 00188 } 00189 // will never get here 00190 00191 } else if(!strupncmp(argv[1], "print", CMDLEN)) { 00192 // print out definitions of current items 00193 Tcl_AppendResult(interp, 00194 "Keyboard shortcuts:\n", 00195 "-------------------\n", NULL); 00196 for (int i=0; i<app->userKeys.num(); i++) { 00197 const char *key = app->userKeys.name(i); 00198 Tcl_AppendResult(interp, "'", key, "' : ", app->userKeys.data(i), "\n", 00199 NULL); 00200 if (app->userKeyDesc.typecode(key) >= 0) { 00201 Tcl_AppendResult(interp, " Description: ", 00202 app->userKeyDesc.data(key), NULL); 00203 } 00204 } 00205 } else 00206 return TCL_ERROR; 00207 00208 // if here, everything worked out ok 00209 return TCL_OK; 00210 } 00211