Crossfire Client, Branch
R11627
|
00001 const char *rcsid_x11_xutil_c = 00002 "$Id: xutil.c 9201 2008-06-01 17:32:45Z anmaster $"; 00003 /* 00004 Crossfire client, a client program for the crossfire program. 00005 00006 Copyright (C) 2001-2003 Mark Wedel & Crossfire Development Team 00007 00008 This program is free software; you can redistribute it and/or modify 00009 it under the terms of the GNU General Public License as published by 00010 the Free Software Foundation; either version 2 of the License, or 00011 (at your option) any later version. 00012 00013 This program is distributed in the hope that it will be useful, 00014 but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00016 GNU General Public License for more details. 00017 00018 You should have received a copy of the GNU General Public License 00019 along with this program; if not, write to the Free Software 00020 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 00021 00022 The author can be reached via e-mail to crossfire-devel@real-time.com 00023 */ 00024 00025 /* This contains various 'support' functions. These functions will probably 00026 * go mostly unaltered between different toolkits, as long as X11 is still 00027 * used. 00028 */ 00029 00030 #include <client.h> 00031 #include <item.h> 00032 #include <config.h> 00033 #include <p_cmd.h> 00034 00035 #ifdef HAVE_LIBXPM 00036 #include <X11/xpm.h> 00037 #endif 00038 00039 #include <X11/Xlib.h> 00040 #include <X11/Xutil.h> 00041 #include <X11/keysym.h> 00042 00043 #include "def-keys.h" 00044 #include "x11proto.h" 00045 #include "x11.h" 00046 00047 00048 static const char * const colorname[] = { 00049 "Black", /* 0 */ 00050 "White", /* 1 */ 00051 "Navy", /* 2 */ 00052 "Red", /* 3 */ 00053 "Chocolate", /* 4 was Orange, but impossible to read on DarkSeaGreen */ 00054 "DodgerBlue", /* 5 */ 00055 "DarkOrange2", /* 6 */ 00056 "SeaGreen", /* 7 */ 00057 "DarkSeaGreen", /* 8 */ 00058 "Grey80", /* 9 */ /* Used for window background color */ 00059 "Sienna", /* 10 */ 00060 "Gold", /* 11 */ 00061 "Khaki" /* 12 */ 00062 }; 00063 00064 struct { 00065 char *name; 00066 uint32 checksum; 00067 Pixmap pixmap, mask; 00068 } private_cache[MAXPIXMAPNUM]; 00069 00070 int use_private_cache=0, last_face_num=0; 00071 00072 00073 /****************************************************************************** 00074 * 00075 * Code related to face caching. 00076 * 00077 *****************************************************************************/ 00078 00079 typedef struct Keys { 00080 uint8 flags; 00081 sint8 direction; 00082 KeySym keysym; 00083 char *command; 00084 struct Keys *next; 00085 } Key_Entry; 00086 00087 /*********************************************************************** 00088 * 00089 * Key board input translations are handled here. We don't deal with 00090 * the events, but rather KeyCodes and KeySyms. 00091 * 00092 * It would be nice to deal with only KeySyms, but many keyboards 00093 * have keys that do not correspond to a KeySym, so we do need to 00094 * support KeyCodes. 00095 * 00096 ***********************************************************************/ 00097 00098 00099 static KeyCode firekey[2], runkey[2], commandkey, *bind_keycode, prevkey, nextkey, 00100 completekey; 00101 static KeySym firekeysym[2], runkeysym[2], commandkeysym,*bind_keysym, 00102 prevkeysym, nextkeysym, completekeysym; 00103 static int bind_flags=0; 00104 static char bind_buf[MAX_BUF]; 00105 00106 #define KEYF_NORMAL 0x01 /* Used in normal mode */ 00107 #define KEYF_FIRE 0x02 /* Used in fire mode */ 00108 #define KEYF_RUN 0x04 /* Used in run mode */ 00109 #define KEYF_MODIFIERS 0x07 /* Mask for actual keyboard modifiers, */ 00110 /* not action modifiers */ 00111 #define KEYF_EDIT 0x08 /* Line editor */ 00112 #define KEYF_STANDARD 0x10 /* For standard (built in) key definitions */ 00113 00114 extern const char * const directions[9]; 00115 00116 /* Key codes can only be from 8-255 (at least according to 00117 * the X11 manual. This is easier than using a hash 00118 * table, quicker, and doesn't use much more space. 00119 */ 00120 00121 #define MAX_KEYCODE 255 00122 static Key_Entry *keys[256]; 00123 00124 /* Can be set when user is moving to new machine type */ 00125 uint8 updatekeycodes=FALSE; 00126 00127 #ifndef GDK_XUTIL 00128 /* Initializes the data for image caching */ 00129 void init_cache_data(void) 00130 { 00131 int i; 00132 Pixmap ptmp; 00133 #include "pixmaps/question.111" 00134 00135 00136 /* Currently, we can cache in all face modes currently supported, 00137 * so I removed the code that did checks on that. 00138 */ 00139 00140 pixmaps[0] = malloc(sizeof(struct PixmapInfo)); 00141 pixmaps[0]->mask=None; 00142 ptmp=XCreateBitmapFromData(display,DefaultRootWindow(display), 00143 question_bits,question_width,question_height); 00144 00145 /* In xpm mode, XCopyArea is used from this data, so we need to copy 00146 * the image into an pixmap of appropriate depth. 00147 */ 00148 pixmaps[0]->pixmap=XCreatePixmap(display, win_root, image_size, image_size, 00149 DefaultDepth(display,DefaultScreen(display))); 00150 pixmaps[0]->width = 1; 00151 pixmaps[0]->height = 1; 00152 XCopyPlane(display, ptmp, pixmaps[0]->pixmap, gc_game, 00153 0,0,image_size,image_size,0,0,1); 00154 XFreePixmap(display, ptmp); 00155 00156 /* Initialize all the images to be of the same value. */ 00157 for (i=1; i<MAXPIXMAPNUM; i++) { 00158 pixmaps[i]=pixmaps[0]; 00159 } 00160 00161 init_common_cache_data(); 00162 00163 } 00164 #endif 00165 00166 /* Rotate right from bsd sum. */ 00167 #define ROTATE_RIGHT(c) if ((c) & 01) (c) = ((c) >>1) + 0x80000000; else (c) >>= 1; 00168 00169 /*#define CHECKSUM_DEBUG*/ 00170 00171 00172 void allocate_colors(Display *disp, Window w, long screen_num, 00173 Colormap *colormap, XColor discolor[16]) { 00174 int i, tried = 0, depth=0; 00175 Status status; 00176 Visual *vis; 00177 XColor exactcolor; 00178 00179 vis = DefaultVisual(disp,screen_num); 00180 if (vis->class >= StaticColor) { 00181 *colormap = DefaultColormap(disp,screen_num); 00182 depth = DefaultDepth(disp,screen_num); 00183 } 00184 else { 00185 *colormap = DefaultColormap(disp,screen_num); 00186 printf("You have a black and white terminal.\n"); 00187 printf("These are no longer supported by cfclient.\n"); 00188 return; 00189 } 00190 try_private: 00191 if (depth > 3) { 00192 unsigned long pixels[13]; 00193 for (i=0; i<13; i++){ 00194 status = XLookupColor(disp,*colormap, colorname[i],&exactcolor, 00195 &discolor[i]); 00196 if (!status){ 00197 printf("Can't find colour %s.\n", colorname[i]); 00198 break; 00199 } 00200 status = XAllocColor(disp,*colormap,&discolor[i]); 00201 if (!status) { 00202 if (!tried) { 00203 printf( "Not enough colours. Trying a private colourmap.\n"); 00204 XFreeColors(disp, *colormap, pixels, i-1, 0); 00205 *colormap = XCreateColormap(disp, w, vis, AllocNone); 00206 XSetWindowColormap(disp, w, *colormap); 00207 tried = 1; 00208 goto try_private; 00209 } else break; 00210 } 00211 pixels[i] = discolor[i].pixel; 00212 } 00213 } 00214 } 00215 00216 /* Updates the keys array with the keybinding that is passed. All the 00217 * arguments are pretty self explanatory. flags is the various state 00218 * that the keyboard is in. 00219 * This function is common to both gdk and x11 client 00220 */ 00221 static void insert_key(KeySym keysym, KeyCode keycode, int flags, char *command) 00222 { 00223 00224 Key_Entry *newkey; 00225 int i, direction=-1; 00226 00227 #if 0 00228 /* This is at least a meaningless check on my system that results in 00229 * a compile warning (always false result), so may was well comment it 00230 * out - MSW 2005-02-09 00231 */ 00232 if (keycode>MAX_KEYCODE) { 00233 LOG(LOG_WARNING,"x11::insert_key", "keycode that is passed is greater than 255."); 00234 keycode=0; /* hopefully the rest of the data is OK */ 00235 } 00236 #endif 00237 if (keys[keycode]==NULL) { 00238 keys[keycode]=malloc(sizeof(Key_Entry)); 00239 keys[keycode]->command=NULL; 00240 keys[keycode]->next=NULL; 00241 } 00242 newkey=keys[keycode]; 00243 00244 /* Try to find out if the command is a direction command. If so, we 00245 * then want to keep track of this fact, so in fire or run mode, 00246 * things work correctly. 00247 */ 00248 for (i=0; i<9; i++) 00249 if (!strcmp(command, directions[i])) { 00250 direction=i; 00251 break; 00252 } 00253 00254 if (keys[keycode]->command!=NULL) { 00255 /* if keys[keycode]->command is not null, then newkey is 00256 * the same as keys[keycode]->command. 00257 */ 00258 while (newkey->next!=NULL) 00259 newkey = newkey->next; 00260 newkey->next = malloc(sizeof(Key_Entry)); 00261 newkey = newkey->next; 00262 /* This is the only initializing we need to do - the other fields 00263 * will get filled in by the passed parameters 00264 */ 00265 newkey->next = NULL; 00266 } 00267 newkey->keysym = keysym; 00268 newkey->flags = flags; 00269 newkey->command = strdup_local(command); 00270 newkey->direction = direction; 00271 } 00272 00273 00274 #ifdef GDK_XUTIL 00275 #define display GDK_DISPLAY() 00276 #endif 00277 00278 /* This function is common to both gdk and x11 client */ 00279 00280 void parse_keybind_line(char *buf, int line, int standard) 00281 { 00282 char *cp, *cpnext; 00283 KeySym keysym; 00284 KeyCode keycode; 00285 int flags; 00286 00287 if (buf[0]=='#' || buf[0]=='\n') return; 00288 if ((cpnext = strchr(buf,' '))==NULL) { 00289 LOG(LOG_WARNING,"x11::parse_keybind_line","Line %d (%s) corrupted.", line,buf); 00290 return; 00291 } 00292 /* Special keybinding line */ 00293 if (buf[0] == '!') { 00294 char *cp1; 00295 while (*cpnext == ' ') ++cpnext; 00296 cp = strchr(cpnext, ' '); 00297 if (!cp) { 00298 LOG(LOG_WARNING,"x11::parse_keybind_line","Line %d (%s) corrupted in keybinding file.", line,buf); 00299 return; 00300 } 00301 *cp++ = 0; /* Null terminate it */ 00302 cp1 = strchr(cp, ' '); 00303 if (!cp1) { 00304 LOG(LOG_WARNING,"x11::parse_keybind_line","Line %d (%s) corrupted in keybinding file.", line,buf); 00305 return; 00306 } 00307 *cp1 ++ = 0;/* Null terminate it */ 00308 keycode = atoi(cp1); 00309 keysym = XStringToKeysym(cp); 00310 /* As of now, all these keys must have keysyms */ 00311 if (keysym == NoSymbol) { 00312 LOG(LOG_WARNING,"x11::parse_keybind_line","Could not convert %s into keysym", cp); 00313 return; 00314 } 00315 if (!strcmp(cpnext,"commandkey")) { 00316 commandkeysym = keysym; 00317 commandkey = keycode; 00318 return; 00319 } 00320 if (!strcmp(cpnext,"firekey0")) { 00321 firekeysym[0] = keysym; 00322 firekey[0] = keycode; 00323 return; 00324 } 00325 if (!strcmp(cpnext,"firekey1")) { 00326 firekeysym[1] = keysym; 00327 firekey[1] = keycode; 00328 return; 00329 } 00330 if (!strcmp(cpnext,"runkey0")) { 00331 runkeysym[0] = keysym; 00332 runkey[0] = keycode; 00333 return; 00334 } 00335 if (!strcmp(cpnext,"runkey1")) { 00336 runkeysym[1] = keysym; 00337 runkey[1] = keycode; 00338 return; 00339 } 00340 if (!strcmp(cpnext,"completekey")) { 00341 completekeysym = keysym; 00342 completekey = keycode; 00343 return; 00344 } 00345 if (!strcmp(cpnext,"nextkey")) { 00346 nextkeysym = keysym; 00347 nextkey = keycode; 00348 return; 00349 } 00350 if (!strcmp(cpnext,"prevkey")) { 00351 prevkeysym = keysym; 00352 prevkey = keycode; 00353 return; 00354 } 00355 } 00356 if (standard) standard=KEYF_STANDARD; 00357 else standard=0; 00358 00359 *cpnext++ = '\0'; 00360 keysym = XStringToKeysym(buf); 00361 cp = cpnext; 00362 if ((cpnext = strchr(cp,' '))==NULL) { 00363 LOG(LOG_WARNING,"x11::parse_keybind_line","Line %d (%s) corrupted in keybinding file.", line, cp); 00364 return; 00365 } 00366 *cpnext++ = '\0'; 00367 00368 /* If we can, convert the keysym into a keycode. */ 00369 keycode = atoi(cp); 00370 cp = cpnext; 00371 if ((cpnext = strchr(cp,' '))==NULL) { 00372 LOG(LOG_WARNING,"x11::parse_keybind_line","Line %d (%s) corrupted in keybinding file.", line, cp); 00373 return; 00374 } 00375 *cpnext++ = '\0'; 00376 flags = 0; 00377 while (*cp!='\0') { 00378 switch (*cp) { 00379 case 'A': 00380 flags |= KEYF_NORMAL | KEYF_FIRE | KEYF_RUN; 00381 break; 00382 case 'N': 00383 flags |= KEYF_NORMAL; 00384 break; 00385 case 'F': 00386 flags |= KEYF_FIRE; 00387 break; 00388 case 'R': 00389 flags |= KEYF_RUN; 00390 break; 00391 case 'E': 00392 flags |= KEYF_EDIT; 00393 break; 00394 case 'S': 00395 flags |= KEYF_STANDARD; 00396 break; 00397 default: 00398 LOG(LOG_WARNING,"x11::parse_keybind_line","Unknown flag (%c) line %d in key binding file", 00399 *cp, line); 00400 } 00401 cp++; 00402 } 00403 00404 /* This gets tricky - if we are reading the keycodes from the built 00405 * in defaults and keycodes are specified there, we want to honor them. 00406 */ 00407 if ((keysym!=NoSymbol) && 00408 (( (keycode == 1) && standard) || (flags&KEYF_STANDARD) || updatekeycodes)) { 00409 00410 keycode = XKeysymToKeycode(display, keysym); 00411 00412 /* It is possible that we get a keysym that we can not convert 00413 * into a keycode (such a case might be binding the key on 00414 * one system, and later trying to run on another system that 00415 * doesn't have that key. 00416 * While the client will not be able to use it this invocation, 00417 * it may be able to use it in the future. As such, don't throw 00418 * it away, but at least print a warning message. 00419 */ 00420 if (keycode==0) { 00421 LOG(LOG_WARNING,"x11::parse_keybind_line","could not convert keysym %s into keycode, ignoring", 00422 buf); 00423 } 00424 } 00425 /* Rest of the line is the actual command. Lets kill the newline */ 00426 cpnext[strlen(cpnext)-1]='\0'; 00427 if (strlen(cpnext)>(sizeof(bind_buf)-1)){ 00428 cpnext[sizeof(bind_buf)-1]='\0'; 00429 LOG(LOG_WARNING,"gtk::parse_keybind_line","Had to truncate a too long command"); 00430 } 00431 insert_key(keysym, keycode, flags | standard, cpnext); 00432 } 00433 00434 /* This code is common to both x11 and gdk client */ 00435 static void init_default_keybindings(void) 00436 { 00437 char buf[MAX_BUF]; 00438 int i; 00439 00440 for(i=0;i< sizeof(def_keys)/sizeof(char *);i++) { 00441 strcpy(buf,def_keys[i]); 00442 parse_keybind_line(buf,i,1); 00443 } 00444 } 00445 00446 00447 /* This reads in the keybindings, and initializes any special values. 00448 * called by init_windows. 00449 */ 00450 /* This function is common to both x11 and gdk client */ 00451 00452 void init_keys(void) 00453 { 00454 int i, line=0; 00455 FILE *fp; 00456 char buf[BIG_BUF]; 00457 00458 commandkeysym = XK_apostrophe; 00459 commandkey =XKeysymToKeycode(display,XK_apostrophe); 00460 if (!commandkey) { 00461 commandkeysym =XK_acute; 00462 commandkey =XKeysymToKeycode(display, XK_acute); 00463 } 00464 firekeysym[0] =XK_Shift_L; 00465 firekey[0] =XKeysymToKeycode(display, XK_Shift_L); 00466 firekeysym[1] =XK_Shift_R; 00467 firekey[1] =XKeysymToKeycode(display, XK_Shift_R); 00468 runkeysym[0] =XK_Control_L; 00469 runkey[0] =XKeysymToKeycode(display, XK_Control_L); 00470 runkeysym[1] =XK_Control_R; 00471 runkey[1] =XKeysymToKeycode(display, XK_Control_R); 00472 00473 completekeysym = XK_Tab; 00474 completekey = XKeysymToKeycode(display, XK_Tab); 00475 /* Don't set these to anything by default. At least on sun 00476 * keyboards, the keysym for up on both the keypad and arrow 00477 * keys is the same, so player needs to rebind this so we get proper 00478 * keycode. Very unfriendly to log in and not be able to move north/south. 00479 */ 00480 nextkeysym = NoSymbol; 00481 nextkey = 0; 00482 prevkeysym = NoSymbol; 00483 prevkey = 0; 00484 00485 for (i=0; i<=MAX_KEYCODE; i++) { 00486 keys[i] = NULL; 00487 } 00488 00489 /* We now try to load the keybindings. First place to look is the 00490 * users home directory, "~/.crossfire/keys". Using a directory 00491 * seems like a good idea, in the future, additional stuff may be 00492 * stored. 00493 * 00494 * The format is described in the def_keys file. Note that this file 00495 * is the same as what it was in the server distribution. To convert 00496 * bindings in character files to this format, all that needs to be done 00497 * is remove the 'key ' at the start of each line. 00498 * 00499 * We need at least one of these keybinding files to exist - this is 00500 * where the various commands are defined. In theory, we actually 00501 * don't need to have any of these defined -- the player could just 00502 * bind everything. Probably not a good idea, however. 00503 */ 00504 00505 sprintf(buf,"%s/.crossfire/keys", getenv("HOME")); 00506 if ((fp=fopen(buf,"r"))==NULL) { 00507 LOG(LOG_INFO,"x11::init_keys","Could not open ~/.crossfire/keys, trying to load global bindings"); 00508 if (client_libdir==NULL) { 00509 init_default_keybindings(); 00510 return; 00511 } 00512 sprintf(buf,"%s/def_keys", client_libdir); 00513 if ((fp=fopen(buf,"r"))==NULL) { 00514 init_default_keybindings(); 00515 return; 00516 } 00517 } 00518 while (fgets(buf, BIG_BUF, fp)) { 00519 line++; 00520 parse_keybind_line(buf,line,0); 00521 } 00522 fclose(fp); 00523 } 00524 00525 /* The only things we actually care about is the run and fire keys. 00526 * Other key releases are not important. 00527 * If it is the release of a run or fire key, we tell the client 00528 * to stop firing or running. In some cases, it is possible that we 00529 * actually are not running or firing, and in such cases, the server 00530 * will just ignore the command. 00531 */ 00532 00533 /* This code is used by gdk and x11 client, but has 00534 * a fair number of #ifdefs to get the right 00535 * behavioiur 00536 */ 00537 void parse_key_release(KeyCode kc, KeySym ks) { 00538 00539 /* Only send stop firing/running commands if we are in actual 00540 * play mode. Something smart does need to be done when the character 00541 * enters a non play mode with fire or run mode already set, however. 00542 */ 00543 00544 if (kc==firekey[0] || ks==firekeysym[0] || 00545 kc==firekey[1] || ks==firekeysym[1]) { 00546 cpl.fire_on=0; 00547 #ifdef GDK_XUTIL 00548 clear_fire(); 00549 gtk_label_set (GTK_LABEL(fire_label)," "); 00550 #else 00551 stop_fire(); 00552 draw_message_window(0); 00553 #endif 00554 } 00555 else if (kc==runkey[0] || ks==runkeysym[0] || 00556 kc==runkey[1] || ks==runkeysym[1]) { 00557 cpl.run_on=0; 00558 if (use_config[CONFIG_ECHO]) draw_info("stop run",NDI_BLACK); 00559 #ifdef GDK_XUTIL 00560 clear_run(); 00561 gtk_label_set (GTK_LABEL(run_label)," "); 00562 #else 00563 stop_run(); 00564 draw_message_window(0); 00565 #endif 00566 } 00567 /* Firing is handled on server side. However, to keep more like the 00568 * old version, if you release the direction key, you want the firing 00569 * to stop. This should do that. 00570 */ 00571 else if (cpl.fire_on) 00572 stop_fire(); 00573 } 00574 00575 /* This parses a keypress. It should only be called when in Playing 00576 * mode. 00577 */ 00578 void parse_key(char key, KeyCode keycode, KeySym keysym, int repeated) 00579 { 00580 Key_Entry *keyentry, *first_match=NULL; 00581 int present_flags=0; 00582 char buf[MAX_BUF]; 00583 00584 if (keycode == commandkey && keysym==commandkeysym) { 00585 draw_prompt(">"); 00586 cpl.input_state = Command_Mode; 00587 cpl.no_echo=FALSE; 00588 return; 00589 } 00590 if (keycode == firekey[0] || keysym==firekeysym[0] || 00591 keycode == firekey[1] || keysym==firekeysym[1]) { 00592 cpl.fire_on=1; 00593 #ifdef GDK_XUTIL 00594 gtk_label_set (GTK_LABEL(fire_label),"Fire"); 00595 #else 00596 draw_message_window(0); 00597 #endif 00598 return; 00599 } 00600 if (keycode == runkey[0] || keysym==runkeysym[0] || 00601 keycode==runkey[1] || keysym==runkeysym[1]) { 00602 cpl.run_on=1; 00603 #ifdef GDK_XUTIL 00604 gtk_label_set (GTK_LABEL(run_label),"Run"); 00605 #else 00606 draw_message_window(0); 00607 #endif 00608 return; 00609 } 00610 00611 if (cpl.run_on) present_flags |= KEYF_RUN; 00612 if (cpl.fire_on) present_flags |= KEYF_FIRE; 00613 if (present_flags ==0) present_flags = KEYF_NORMAL; 00614 00615 keyentry = keys[keycode]; 00616 while (keyentry!=NULL) { 00617 if ((keyentry->keysym!=NoSymbol && keyentry->keysym!=keysym) || 00618 (!(keyentry->flags & present_flags))) { 00619 keyentry=keyentry->next; 00620 continue; 00621 } 00622 first_match = keyentry; 00623 /* Try to find a prefect match */ 00624 if ((keyentry->flags & KEYF_MODIFIERS)!= present_flags) { 00625 keyentry=keyentry->next; 00626 continue; 00627 } 00628 else break; 00629 } 00630 if (first_match!=NULL) { 00631 char buf[MAX_BUF]; 00632 00633 if (first_match->flags & KEYF_EDIT) { 00634 strcpy(cpl.input_text, first_match->command); 00635 cpl.input_state = Command_Mode; 00636 #ifdef GDK_XUTIL 00637 snprintf(buf, sizeof(buf), "%s", cpl.input_text); 00638 gtk_entry_set_text(GTK_ENTRY(entrytext),buf); 00639 gtk_widget_grab_focus (GTK_WIDGET(entrytext)); 00640 #else 00641 snprintf(buf, sizeof(buf), ">%s", cpl.input_text); 00642 draw_prompt(buf); 00643 #endif 00644 return; 00645 } 00646 00647 if (first_match->direction>=0) { 00648 if (cpl.fire_on) { 00649 snprintf(buf, sizeof(buf), "fire %s", first_match->command); 00650 fire_dir(first_match->direction); 00651 } 00652 else if (cpl.run_on) { 00653 run_dir(first_match->direction); 00654 snprintf(buf, sizeof(buf), "run %s", first_match->command); 00655 } 00656 else if (!repeated) { 00657 strcpy(buf,first_match->command); 00658 extended_command(first_match->command); 00659 } 00660 else 00661 snprintf(buf, sizeof(buf), "move %s (ignored)", first_match->command); 00662 if (use_config[CONFIG_ECHO]) draw_info(buf,NDI_BLACK); 00663 } 00664 else { 00665 if (use_config[CONFIG_ECHO]) draw_info(first_match->command,NDI_BLACK); 00666 extended_command(first_match->command); 00667 } 00668 return; 00669 } 00670 if (key>='0' && key<='9') { 00671 cpl.count = cpl.count*10 + (key-'0'); 00672 if (cpl.count>100000) cpl.count%=100000; 00673 #ifdef GDK_XUTIL 00674 gtk_spin_button_set_value (GTK_SPIN_BUTTON(counttext), (float) cpl.count ); 00675 #endif 00676 return; 00677 } 00678 snprintf(buf, sizeof(buf), "Key unused (%s%s%s)", 00679 (cpl.fire_on? "Fire&": ""), 00680 (cpl.run_on ? "Run&" : ""), 00681 keysym==NoSymbol? "unknown": XKeysymToString(keysym)); 00682 draw_info(buf,NDI_BLACK); 00683 cpl.count=0; 00684 } 00685 00686 00687 /* This returns a character string desribing the key. */ 00688 /* If save_mode is true, it means that the format used for saving 00689 * the information is used, instead of the usual format for displaying 00690 * the information in a friendly manner. 00691 */ 00692 static char * get_key_info(Key_Entry *key, KeyCode kc, int save_mode) 00693 { 00694 /* bind buf is the maximum space allowed for a 00695 * binded command. We will add additional datas to 00696 * it so we increase by MAX_BUF*/ 00697 static char buf[MAX_BUF+sizeof(bind_buf)]; 00698 char buff[MAX_BUF]; 00699 int bi=0; 00700 00701 if ((key->flags & KEYF_MODIFIERS) == KEYF_MODIFIERS) 00702 buff[bi++] ='A'; 00703 else { 00704 if (key->flags & KEYF_NORMAL) 00705 buff[bi++] ='N'; 00706 if (key->flags & KEYF_FIRE) 00707 buff[bi++] ='F'; 00708 if (key->flags & KEYF_RUN) 00709 buff[bi++] ='R'; 00710 } 00711 if (key->flags & KEYF_EDIT) 00712 buff[bi++] ='E'; 00713 if (key->flags & KEYF_STANDARD) 00714 buff[bi++] ='S'; 00715 00716 buff[bi]='\0'; 00717 if (save_mode) { 00718 if(key->keysym == NoSymbol) { 00719 snprintf(buf, sizeof(buf), "(null) %i %s %s", 00720 kc,buff, key->command); 00721 } 00722 else { 00723 snprintf(buf, sizeof(buf), "%s %i %s %s", 00724 XKeysymToString(key->keysym), kc, 00725 buff, key->command); 00726 } 00727 } 00728 else { 00729 if(key->keysym == NoSymbol) { 00730 snprintf(buf, sizeof(buf), "key (null) (%i) %s %s", 00731 kc,buff, key->command); 00732 } 00733 else { 00734 snprintf(buf, sizeof(buf), "key %s (%i) %s %s", 00735 XKeysymToString(key->keysym), kc, 00736 buff, key->command); 00737 } 00738 } 00739 return buf; 00740 } 00741 00742 /* Shows all the keybindings. allbindings me we also show the standard 00743 * (default) keybindings. 00744 */ 00745 00746 static void show_keys(int allbindings) 00747 { 00748 int i, count=1; 00749 Key_Entry *key; 00750 char buf[MAX_BUF]; 00751 00752 snprintf(buf, sizeof(buf), "Commandkey %s (%d)", 00753 commandkeysym==NoSymbol?"unknown":XKeysymToString(commandkeysym), 00754 commandkey); 00755 draw_info(buf,NDI_BLACK); 00756 snprintf(buf, sizeof(buf), "Firekeys 1: %s (%d), 2: %s (%d)", 00757 firekeysym[0]==NoSymbol?"unknown":XKeysymToString(firekeysym[0]), firekey[0], 00758 firekeysym[1]==NoSymbol?"unknown":XKeysymToString(firekeysym[1]), firekey[1]); 00759 draw_info(buf,NDI_BLACK); 00760 snprintf(buf, sizeof(buf), "Runkeys 1: %s (%d), 2: %s (%d)", 00761 runkeysym[0]==NoSymbol?"unknown":XKeysymToString(runkeysym[0]), runkey[0], 00762 runkeysym[1]==NoSymbol?"unknown":XKeysymToString(runkeysym[1]), runkey[1]); 00763 draw_info(buf,NDI_BLACK); 00764 00765 snprintf(buf, sizeof(buf), "Command Completion Key %s (%d)", 00766 completekeysym==NoSymbol?"unknown":XKeysymToString(completekeysym), 00767 completekey); 00768 draw_info(buf,NDI_BLACK); 00769 00770 snprintf(buf, sizeof(buf), "Next Command in History Key %s (%d)", 00771 nextkeysym==NoSymbol?"unknown":XKeysymToString(nextkeysym), 00772 nextkey); 00773 draw_info(buf,NDI_BLACK); 00774 00775 snprintf(buf, sizeof(buf), "Previous Command in History Key %s (%d)", 00776 prevkeysym==NoSymbol?"unknown":XKeysymToString(prevkeysym), 00777 prevkey); 00778 draw_info(buf,NDI_BLACK); 00779 00780 00781 /* Perhaps we should start at 8, so that we only show 'active' 00782 * keybindings? 00783 */ 00784 for (i=0; i<=MAX_KEYCODE; i++) { 00785 for (key=keys[i]; key!=NULL; key =key->next) { 00786 if (key->flags & KEYF_STANDARD && !allbindings) continue; 00787 00788 snprintf(buf, sizeof(buf), "%3d %s", count, get_key_info(key, i, 0)); 00789 draw_info(buf,NDI_BLACK); 00790 count++; 00791 } 00792 } 00793 } 00794 00795 00796 00797 00798 void bind_key(const char *params) 00799 { 00800 char buf[MAX_BUF]; 00801 00802 if (!params) { 00803 draw_info("Usage: bind [-nfre] {<commandline>/commandkey/firekey{1/2}/runkey{1/2}/",NDI_BLACK); 00804 draw_info(" completekey/nextkey/prevkey}",NDI_BLACK); 00805 return; 00806 } 00807 00808 /* Skip over any spaces we may have */ 00809 while (*params==' ') params++; 00810 00811 if (!strcmp(params, "commandkey")) { 00812 bind_keycode = &commandkey; 00813 bind_keysym = &commandkeysym; 00814 draw_info("Push key to bind new commandkey.",NDI_BLACK); 00815 cpl.input_state = Configure_Keys; 00816 return; 00817 } 00818 if (!strcmp(params, "firekey1")) { 00819 bind_keycode = &firekey[0]; 00820 bind_keysym = & firekeysym[0]; 00821 draw_info("Push key to bind new firekey 1.",NDI_BLACK); 00822 cpl.input_state = Configure_Keys; 00823 return; 00824 } 00825 if (!strcmp(params, "firekey2")) { 00826 bind_keycode = &firekey[1]; 00827 bind_keysym = & firekeysym[1]; 00828 draw_info("Push key to bind new firekey 2.",NDI_BLACK); 00829 cpl.input_state = Configure_Keys; 00830 return; 00831 } 00832 if (!strcmp(params, "runkey1")) { 00833 bind_keycode = &runkey[0]; 00834 bind_keysym = &runkeysym[0]; 00835 draw_info("Push key to bind new runkey 1.",NDI_BLACK); 00836 cpl.input_state = Configure_Keys; 00837 return; 00838 } 00839 if (!strcmp(params, "runkey2")) { 00840 bind_keycode = &runkey[1]; 00841 bind_keysym = &runkeysym[1]; 00842 draw_info("Push key to bind new runkey 2.",NDI_BLACK); 00843 cpl.input_state = Configure_Keys; 00844 return; 00845 } 00846 00847 if (!strcmp(params, "completekey")) { 00848 bind_keycode = &completekey; 00849 bind_keysym = &completekeysym; 00850 draw_info("Push key to bind new command completeion key",NDI_BLACK); 00851 cpl.input_state = Configure_Keys; 00852 return; 00853 } 00854 00855 if (!strcmp(params, "prevkey")) { 00856 bind_keycode = &prevkey; 00857 bind_keysym = &prevkeysym; 00858 draw_info("Push key to bind new previous command in history key.",NDI_BLACK); 00859 cpl.input_state = Configure_Keys; 00860 return; 00861 } 00862 00863 if (!strcmp(params, "nextkey")) { 00864 bind_keycode = &nextkey; 00865 bind_keysym = &nextkeysym; 00866 draw_info("Push key to bind new next command in history key.",NDI_BLACK); 00867 cpl.input_state = Configure_Keys; 00868 return; 00869 } 00870 00871 00872 if (params[0] != '-') 00873 bind_flags =KEYF_MODIFIERS; 00874 else { 00875 bind_flags =0; 00876 bind_keysym=NULL; 00877 bind_keycode=NULL; 00878 for (params++; *params != ' '; params++) 00879 switch (*params) { 00880 case 'n': 00881 bind_flags |= KEYF_NORMAL; 00882 break; 00883 case 'f': 00884 bind_flags |= KEYF_FIRE; 00885 break; 00886 case 'r': 00887 bind_flags |= KEYF_RUN; 00888 break; 00889 case 'e': 00890 bind_flags |= KEYF_EDIT; 00891 break; 00892 case '\0': 00893 draw_info("Try unbind to remove bindings..",NDI_BLACK); 00894 return; 00895 default: 00896 snprintf(buf, sizeof(buf), "Unknown flag to bind: '%c'", *params); 00897 draw_info(buf,NDI_BLACK); 00898 return; 00899 } 00900 params++; 00901 } 00902 00903 if (!(bind_flags & KEYF_MODIFIERS)) 00904 bind_flags |= KEYF_MODIFIERS; 00905 00906 if (!params[0]) { 00907 draw_info("Try unbind to remove bindings..",NDI_BLACK); 00908 return; 00909 } 00910 00911 strncpy(bind_buf, params, sizeof(bind_buf)-1); 00912 bind_buf[sizeof(bind_buf)-1]=0; 00913 if (strlen(params) >= sizeof(bind_buf)) { 00914 draw_info("Keybinding too long! Truncated:",NDI_RED); 00915 draw_info(bind_buf,NDI_RED); 00916 } 00917 00918 snprintf(buf, sizeof(buf), "Push key to bind '%s'.", bind_buf); 00919 draw_info(buf,NDI_BLACK); 00920 bind_keycode=NULL; 00921 cpl.input_state = Configure_Keys; 00922 return; 00923 } 00924 00925 00926 /* This is a recursive function that saves all the entries for a particular 00927 * entry. We save the first element first, and then go through 00928 * and save the rest of the elements. In this way, the ordering of the key 00929 * entries in the 00930 * file remains the same. 00931 */ 00932 00933 static void save_individual_key(FILE *fp, Key_Entry *key, KeyCode kc) 00934 { 00935 if (key==NULL) return; 00936 fprintf(fp, "%s\n", get_key_info(key, kc, 1)); 00937 save_individual_key(fp, key->next, kc); 00938 } 00939 00940 static void save_keys(void) 00941 { 00942 char buf[MAX_BUF], buf2[MAX_BUF]; 00943 int i; 00944 FILE *fp; 00945 00946 sprintf(buf,"%s/.crossfire/keys", getenv("HOME")); 00947 if (make_path_to_file(buf)==-1) { 00948 LOG(LOG_WARNING,"x11::save_keys","Could not create %s", buf); 00949 return; 00950 } 00951 if ((fp=fopen(buf,"w"))==NULL) { 00952 snprintf(buf2, sizeof(buf2), "Could not open %s, key bindings not saved\n", buf); 00953 draw_info(buf2,NDI_BLACK); 00954 return; 00955 } 00956 if (commandkeysym != XK_apostrophe && commandkeysym != NoSymbol) { 00957 fprintf(fp, "! commandkey %s %d\n", 00958 XKeysymToString(commandkeysym), commandkey); 00959 } 00960 if (firekeysym[0] != XK_Shift_L && firekeysym[0] != NoSymbol) { 00961 fprintf(fp, "! firekey0 %s %d\n", 00962 XKeysymToString(firekeysym[0]), firekey[0]); 00963 } 00964 if (firekeysym[1] != XK_Shift_R && firekeysym[1] != NoSymbol) { 00965 fprintf(fp, "! firekey1 %s %d\n", 00966 XKeysymToString(firekeysym[1]), firekey[1]); 00967 } 00968 if (runkeysym[0] != XK_Control_L && runkeysym[0] != NoSymbol) { 00969 fprintf(fp, "! runkey0 %s %d\n", 00970 XKeysymToString(runkeysym[0]), runkey[0]); 00971 } 00972 if (runkeysym[1] != XK_Control_R && runkeysym[1] != NoSymbol) { 00973 fprintf(fp, "! runkey1 %s %d\n", 00974 XKeysymToString(runkeysym[1]), runkey[1]); 00975 } 00976 if (completekeysym != XK_Tab && completekeysym != NoSymbol) { 00977 fprintf(fp, "! completekey %s %d\n", 00978 XKeysymToString(completekeysym), completekey); 00979 } 00980 /* No defaults for these, so if it is set to anything, assume its valid */ 00981 if (nextkeysym != NoSymbol) { 00982 fprintf(fp, "! nextkey %s %d\n", 00983 XKeysymToString(nextkeysym), nextkey); 00984 } 00985 if (prevkeysym != NoSymbol) { 00986 fprintf(fp, "! prevkey %s %d\n", 00987 XKeysymToString(prevkeysym), prevkey); 00988 } 00989 00990 for (i=0; i<=MAX_KEYCODE; i++) { 00991 save_individual_key(fp, keys[i], i); 00992 } 00993 fclose(fp); 00994 /* Should probably check return value on all writes to be sure, but... */ 00995 draw_info("key bindings successfully saved.",NDI_BLACK); 00996 } 00997 00998 void configure_keys(KeyCode k, KeySym keysym) 00999 { 01000 char buf[MAX_BUF]; 01001 01002 if (bind_keycode==NULL) { 01003 if(k == firekey[0] || k == firekey[1]) { 01004 cpl.fire_on =1; 01005 draw_message_window(0); 01006 return; 01007 } 01008 if(k == runkey[0] || k == runkey[1]) { 01009 cpl.run_on =1; 01010 draw_message_window(0); 01011 return; 01012 } 01013 } 01014 cpl.input_state = Playing; 01015 /* Try to be clever - take into account shift/control keys being 01016 * held down when binding keys - in this way, player does not have to use 01017 * -f and -r flags to bind for many simple binds. 01018 */ 01019 01020 if ((cpl.fire_on || cpl.run_on) && (bind_flags & KEYF_MODIFIERS)==KEYF_MODIFIERS) { 01021 bind_flags &= ~KEYF_MODIFIERS; 01022 if (cpl.fire_on) bind_flags |= KEYF_FIRE; 01023 if (cpl.run_on) bind_flags |= KEYF_RUN; 01024 } 01025 01026 if (bind_keycode!=NULL) { 01027 *bind_keycode = k; 01028 *bind_keysym=keysym; 01029 } 01030 else { 01031 insert_key(keysym, k, bind_flags, bind_buf); 01032 } 01033 01034 snprintf(buf, sizeof(buf), "Binded to key '%s' (%i)", 01035 keysym==NoSymbol?"unknown":XKeysymToString(keysym), (int)k); 01036 draw_info(buf,NDI_BLACK); 01037 cpl.fire_on=0; 01038 cpl.run_on=0; 01039 draw_message_window(0); 01040 01041 /* Do this each time a new key is bound. This way, we are never actually 01042 * storing any information that needs to be saved when the connection 01043 * dies or the player quits. 01044 */ 01045 save_keys(); 01046 return; 01047 } 01048 01049 static void unbind_usage(void) 01050 { 01051 draw_info("Usage: unbind <entry_number> or",NDI_BLACK); 01052 draw_info("Usage: unbind [-a] [-g] to show existing bindings", NDI_BLACK); 01053 draw_info(" -a shows all (global) bindings", NDI_BLACK); 01054 draw_info(" -g unbinds a global binding", NDI_BLACK); 01055 } 01056 01057 void unbind_key(const char *params) 01058 { 01059 int count=0, keyentry, onkey,global=0; 01060 Key_Entry *key, *tmp; 01061 char buf[MAX_BUF]; 01062 01063 if (params==NULL || params[0]=='\0') { 01064 show_keys(0); 01065 return; 01066 } 01067 01068 /* Skip over any spaces we may have */ 01069 while (*params==' ') params++; 01070 01071 if (!strcmp(params,"-a")) { 01072 show_keys(1); 01073 return; 01074 } 01075 if (!strncmp(params,"-g",2)) { 01076 global=1; 01077 if (!(params=strchr(params,' '))) { 01078 unbind_usage(); 01079 return; 01080 } 01081 } 01082 if ((keyentry=atoi(params))==0) { 01083 unbind_usage(); 01084 return; 01085 } 01086 01087 for (onkey=0; onkey<=MAX_KEYCODE; onkey++) { 01088 for (key=keys[onkey]; key; key =key->next) { 01089 if (global || !(key->flags&KEYF_STANDARD)) count++; 01090 /* We found the key we want to unbind */ 01091 if (keyentry==count) { 01092 01093 /* If it is the first entry, it is easy */ 01094 if (key == keys[onkey]) { 01095 keys[onkey] = key->next; 01096 goto unbinded; 01097 } 01098 /* Otherwise, we need to figure out where in the link list 01099 * the entry is. 01100 */ 01101 for (tmp=keys[onkey]; tmp->next!=NULL; tmp=tmp->next) { 01102 if (tmp->next == key) { 01103 tmp->next =key->next; 01104 goto unbinded; 01105 } 01106 } 01107 LOG(LOG_ERROR,"x11::unbind_key","found number entry, but could not find actual key"); 01108 } 01109 } 01110 } 01111 /* Makes things look better to draw the blank line */ 01112 draw_info("",NDI_BLACK); 01113 draw_info("No such entry. Try 'unbind' with no options to find entry.",NDI_BLACK); 01114 return; 01115 01116 /* 01117 * Found. Now remove it. 01118 */ 01119 01120 unbinded: 01121 01122 snprintf(buf, sizeof(buf), "Removed binding: %3d %s", count, get_key_info(key, onkey, 0)); 01123 01124 01125 draw_info(buf,NDI_BLACK); 01126 free(key->command); 01127 free(key); 01128 save_keys(); 01129 } 01130 01131 01132 /* try to find a face in our private cache. We return the face 01133 * number if we find one, -1 for no face match 01134 */ 01135 int find_face_in_private_cache(char *face, int checksum) 01136 { 01137 int i; 01138 01139 for (i=1; i<=last_face_num; i++) 01140 if (!strcmp(face, private_cache[i].name)) { 01141 return i; 01142 } 01143 return -1; 01144 } 01145 01146 01147 void image_update_download_status(int start, int end, int total) 01148 { 01149 char buf[MAX_BUF]; 01150 01151 snprintf(buf, sizeof(buf), "Downloaded %d of %d images", start, total); 01152 01153 draw_info(buf,NDI_BLUE); 01154 } 01155 01156 /* Start of map handling code. 01157 * For the most part, this actually is not window system specific, 01158 * but certainly how the client wants to store this may vary. 01159 * 01160 * At least in the gtk and x11 clients, 95+% of this code 01161 * is the same - the only think I think is different is 01162 * that the gtk will call sdl_scroll. This should 01163 * probably be moved into the common area. 01164 */ 01165 01166 #define MAXFACES 5 01167 #define MAXPIXMAPNUM 10000 01168 01169 01170 /* 01171 * Added for fog of war. Current size of the map structure in memory. 01172 * We assume a rectangular map so this is the length of one side. 01173 * command.c needs to know about this so not static 01174 * FIX ME: Don't assume rectangle 01175 */ 01176 01177 PlayerPosition pl_pos; 01178 01179 01185 void reset_map(void) 01186 { 01187 } 01188 01189 /* x11 client doesn't do smoothing, so don't need to do anything with this */ 01190 void addsmooth(uint16 face, uint16 smooth_face) 01191 { 01192 } 01193 01194 /* X11 client doesn't care about this */ 01195 void client_tick(uint32 tick) 01196 { 01197 } 01198 01202 void client_pickup(uint32 pickup) 01203 { 01204 }