Crossfire Client, Branches  R11627
xutil.c
Go to the documentation of this file.
1 const char *rcsid_x11_xutil_c =
2  "$Id: xutil.c 9201 2008-06-01 17:32:45Z anmaster $";
3 /*
4  Crossfire client, a client program for the crossfire program.
5 
6  Copyright (C) 2001-2003 Mark Wedel & Crossfire Development Team
7 
8  This program is free software; you can redistribute it and/or modify
9  it under the terms of the GNU General Public License as published by
10  the Free Software Foundation; either version 2 of the License, or
11  (at your option) any later version.
12 
13  This program is distributed in the hope that it will be useful,
14  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  GNU General Public License for more details.
17 
18  You should have received a copy of the GNU General Public License
19  along with this program; if not, write to the Free Software
20  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 
22  The author can be reached via e-mail to crossfire-devel@real-time.com
23 */
24 
25 /* This contains various 'support' functions. These functions will probably
26  * go mostly unaltered between different toolkits, as long as X11 is still
27  * used.
28  */
29 
30 #include <client.h>
31 #include <item.h>
32 #include <config.h>
33 #include <p_cmd.h>
34 
35 #ifdef HAVE_LIBXPM
36 #include <X11/xpm.h>
37 #endif
38 
39 #include <X11/Xlib.h>
40 #include <X11/Xutil.h>
41 #include <X11/keysym.h>
42 
43 #include "def-keys.h"
44 #include "x11proto.h"
45 #include "x11.h"
46 
47 
48 static const char * const colorname[] = {
49 "Black", /* 0 */
50 "White", /* 1 */
51 "Navy", /* 2 */
52 "Red", /* 3 */
53 "Chocolate", /* 4 was Orange, but impossible to read on DarkSeaGreen */
54 "DodgerBlue", /* 5 */
55 "DarkOrange2", /* 6 */
56 "SeaGreen", /* 7 */
57 "DarkSeaGreen", /* 8 */
58 "Grey80", /* 9 */ /* Used for window background color */
59 "Sienna", /* 10 */
60 "Gold", /* 11 */
61 "Khaki" /* 12 */
62 };
63 
64 struct {
65  char *name;
67  Pixmap pixmap, mask;
69 
71 
72 
73 /******************************************************************************
74  *
75  * Code related to face caching.
76  *
77  *****************************************************************************/
78 
79 typedef struct Keys {
80  uint8 flags;
82  KeySym keysym;
83  char *command;
84  struct Keys *next;
85 } Key_Entry;
86 
87 /***********************************************************************
88  *
89  * Key board input translations are handled here. We don't deal with
90  * the events, but rather KeyCodes and KeySyms.
91  *
92  * It would be nice to deal with only KeySyms, but many keyboards
93  * have keys that do not correspond to a KeySym, so we do need to
94  * support KeyCodes.
95  *
96  ***********************************************************************/
97 
98 
99 static KeyCode firekey[2], runkey[2], commandkey, *bind_keycode, prevkey, nextkey,
100  completekey;
103 static int bind_flags=0;
104 static char bind_buf[MAX_BUF];
105 
106 #define KEYF_NORMAL 0x01 /* Used in normal mode */
107 #define KEYF_FIRE 0x02 /* Used in fire mode */
108 #define KEYF_RUN 0x04 /* Used in run mode */
109 #define KEYF_MODIFIERS 0x07 /* Mask for actual keyboard modifiers, */
110  /* not action modifiers */
111 #define KEYF_EDIT 0x08 /* Line editor */
112 #define KEYF_STANDARD 0x10 /* For standard (built in) key definitions */
113 
114 extern const char * const directions[9];
115 
116 /* Key codes can only be from 8-255 (at least according to
117  * the X11 manual. This is easier than using a hash
118  * table, quicker, and doesn't use much more space.
119  */
120 
121 #define MAX_KEYCODE 255
122 static Key_Entry *keys[256];
123 
124 /* Can be set when user is moving to new machine type */
126 
127 #ifndef GDK_XUTIL
128 /* Initializes the data for image caching */
129 void init_cache_data(void)
130 {
131  int i;
132  Pixmap ptmp;
133 #include "pixmaps/question.111"
134 
135 
136  /* Currently, we can cache in all face modes currently supported,
137  * so I removed the code that did checks on that.
138  */
139 
140  pixmaps[0] = malloc(sizeof(struct PixmapInfo));
141  pixmaps[0]->mask=None;
142  ptmp=XCreateBitmapFromData(display,DefaultRootWindow(display),
143  question_bits,question_width,question_height);
144 
145  /* In xpm mode, XCopyArea is used from this data, so we need to copy
146  * the image into an pixmap of appropriate depth.
147  */
148  pixmaps[0]->pixmap=XCreatePixmap(display, win_root, image_size, image_size,
149  DefaultDepth(display,DefaultScreen(display)));
150  pixmaps[0]->width = 1;
151  pixmaps[0]->height = 1;
152  XCopyPlane(display, ptmp, pixmaps[0]->pixmap, gc_game,
153  0,0,image_size,image_size,0,0,1);
154  XFreePixmap(display, ptmp);
155 
156  /* Initialize all the images to be of the same value. */
157  for (i=1; i<MAXPIXMAPNUM; i++) {
158  pixmaps[i]=pixmaps[0];
159  }
160 
162 
163 }
164 #endif
165 
166 /* Rotate right from bsd sum. */
167 #define ROTATE_RIGHT(c) if ((c) & 01) (c) = ((c) >>1) + 0x80000000; else (c) >>= 1;
168 
169 /*#define CHECKSUM_DEBUG*/
170 
171 
172 void allocate_colors(Display *disp, Window w, long screen_num,
173  Colormap *colormap, XColor discolor[16]) {
174  int i, tried = 0, depth=0;
175  Status status;
176  Visual *vis;
177  XColor exactcolor;
178 
179  vis = DefaultVisual(disp,screen_num);
180  if (vis->class >= StaticColor) {
181  *colormap = DefaultColormap(disp,screen_num);
182  depth = DefaultDepth(disp,screen_num);
183  }
184  else {
185  *colormap = DefaultColormap(disp,screen_num);
186  printf("You have a black and white terminal.\n");
187  printf("These are no longer supported by cfclient.\n");
188  return;
189  }
190 try_private:
191  if (depth > 3) {
192  unsigned long pixels[13];
193  for (i=0; i<13; i++){
194  status = XLookupColor(disp,*colormap, colorname[i],&exactcolor,
195  &discolor[i]);
196  if (!status){
197  printf("Can't find colour %s.\n", colorname[i]);
198  break;
199  }
200  status = XAllocColor(disp,*colormap,&discolor[i]);
201  if (!status) {
202  if (!tried) {
203  printf( "Not enough colours. Trying a private colourmap.\n");
204  XFreeColors(disp, *colormap, pixels, i-1, 0);
205  *colormap = XCreateColormap(disp, w, vis, AllocNone);
206  XSetWindowColormap(disp, w, *colormap);
207  tried = 1;
208  goto try_private;
209  } else break;
210  }
211  pixels[i] = discolor[i].pixel;
212  }
213  }
214 }
215 
216 /* Updates the keys array with the keybinding that is passed. All the
217  * arguments are pretty self explanatory. flags is the various state
218  * that the keyboard is in.
219  * This function is common to both gdk and x11 client
220  */
221 static void insert_key(KeySym keysym, KeyCode keycode, int flags, char *command)
222 {
223 
224  Key_Entry *newkey;
225  int i, direction=-1;
226 
227 #if 0
228  /* This is at least a meaningless check on my system that results in
229  * a compile warning (always false result), so may was well comment it
230  * out - MSW 2005-02-09
231  */
232  if (keycode>MAX_KEYCODE) {
233  LOG(LOG_WARNING,"x11::insert_key", "keycode that is passed is greater than 255.");
234  keycode=0; /* hopefully the rest of the data is OK */
235  }
236 #endif
237  if (keys[keycode]==NULL) {
238  keys[keycode]=malloc(sizeof(Key_Entry));
239  keys[keycode]->command=NULL;
240  keys[keycode]->next=NULL;
241  }
242  newkey=keys[keycode];
243 
244  /* Try to find out if the command is a direction command. If so, we
245  * then want to keep track of this fact, so in fire or run mode,
246  * things work correctly.
247  */
248  for (i=0; i<9; i++)
249  if (!strcmp(command, directions[i])) {
250  direction=i;
251  break;
252  }
253 
254  if (keys[keycode]->command!=NULL) {
255  /* if keys[keycode]->command is not null, then newkey is
256  * the same as keys[keycode]->command.
257  */
258  while (newkey->next!=NULL)
259  newkey = newkey->next;
260  newkey->next = malloc(sizeof(Key_Entry));
261  newkey = newkey->next;
262  /* This is the only initializing we need to do - the other fields
263  * will get filled in by the passed parameters
264  */
265  newkey->next = NULL;
266  }
267  newkey->keysym = keysym;
268  newkey->flags = flags;
269  newkey->command = strdup_local(command);
270  newkey->direction = direction;
271 }
272 
273 
274 #ifdef GDK_XUTIL
275 #define display GDK_DISPLAY()
276 #endif
277 
278 /* This function is common to both gdk and x11 client */
279 
280 void parse_keybind_line(char *buf, int line, int standard)
281 {
282  char *cp, *cpnext;
283  KeySym keysym;
284  KeyCode keycode;
285  int flags;
286 
287  if (buf[0]=='#' || buf[0]=='\n') return;
288  if ((cpnext = strchr(buf,' '))==NULL) {
289  LOG(LOG_WARNING,"x11::parse_keybind_line","Line %d (%s) corrupted.", line,buf);
290  return;
291  }
292  /* Special keybinding line */
293  if (buf[0] == '!') {
294  char *cp1;
295  while (*cpnext == ' ') ++cpnext;
296  cp = strchr(cpnext, ' ');
297  if (!cp) {
298  LOG(LOG_WARNING,"x11::parse_keybind_line","Line %d (%s) corrupted in keybinding file.", line,buf);
299  return;
300  }
301  *cp++ = 0; /* Null terminate it */
302  cp1 = strchr(cp, ' ');
303  if (!cp1) {
304  LOG(LOG_WARNING,"x11::parse_keybind_line","Line %d (%s) corrupted in keybinding file.", line,buf);
305  return;
306  }
307  *cp1 ++ = 0;/* Null terminate it */
308  keycode = atoi(cp1);
309  keysym = XStringToKeysym(cp);
310  /* As of now, all these keys must have keysyms */
311  if (keysym == NoSymbol) {
312  LOG(LOG_WARNING,"x11::parse_keybind_line","Could not convert %s into keysym", cp);
313  return;
314  }
315  if (!strcmp(cpnext,"commandkey")) {
317  commandkey = keycode;
318  return;
319  }
320  if (!strcmp(cpnext,"firekey0")) {
321  firekeysym[0] = keysym;
322  firekey[0] = keycode;
323  return;
324  }
325  if (!strcmp(cpnext,"firekey1")) {
326  firekeysym[1] = keysym;
327  firekey[1] = keycode;
328  return;
329  }
330  if (!strcmp(cpnext,"runkey0")) {
331  runkeysym[0] = keysym;
332  runkey[0] = keycode;
333  return;
334  }
335  if (!strcmp(cpnext,"runkey1")) {
336  runkeysym[1] = keysym;
337  runkey[1] = keycode;
338  return;
339  }
340  if (!strcmp(cpnext,"completekey")) {
342  completekey = keycode;
343  return;
344  }
345  if (!strcmp(cpnext,"nextkey")) {
346  nextkeysym = keysym;
347  nextkey = keycode;
348  return;
349  }
350  if (!strcmp(cpnext,"prevkey")) {
351  prevkeysym = keysym;
352  prevkey = keycode;
353  return;
354  }
355  }
356  if (standard) standard=KEYF_STANDARD;
357  else standard=0;
358 
359  *cpnext++ = '\0';
360  keysym = XStringToKeysym(buf);
361  cp = cpnext;
362  if ((cpnext = strchr(cp,' '))==NULL) {
363  LOG(LOG_WARNING,"x11::parse_keybind_line","Line %d (%s) corrupted in keybinding file.", line, cp);
364  return;
365  }
366  *cpnext++ = '\0';
367 
368  /* If we can, convert the keysym into a keycode. */
369  keycode = atoi(cp);
370  cp = cpnext;
371  if ((cpnext = strchr(cp,' '))==NULL) {
372  LOG(LOG_WARNING,"x11::parse_keybind_line","Line %d (%s) corrupted in keybinding file.", line, cp);
373  return;
374  }
375  *cpnext++ = '\0';
376  flags = 0;
377  while (*cp!='\0') {
378  switch (*cp) {
379  case 'A':
380  flags |= KEYF_NORMAL | KEYF_FIRE | KEYF_RUN;
381  break;
382  case 'N':
383  flags |= KEYF_NORMAL;
384  break;
385  case 'F':
386  flags |= KEYF_FIRE;
387  break;
388  case 'R':
389  flags |= KEYF_RUN;
390  break;
391  case 'E':
392  flags |= KEYF_EDIT;
393  break;
394  case 'S':
395  flags |= KEYF_STANDARD;
396  break;
397  default:
398  LOG(LOG_WARNING,"x11::parse_keybind_line","Unknown flag (%c) line %d in key binding file",
399  *cp, line);
400  }
401  cp++;
402  }
403 
404  /* This gets tricky - if we are reading the keycodes from the built
405  * in defaults and keycodes are specified there, we want to honor them.
406  */
407  if ((keysym!=NoSymbol) &&
408  (( (keycode == 1) && standard) || (flags&KEYF_STANDARD) || updatekeycodes)) {
409 
410  keycode = XKeysymToKeycode(display, keysym);
411 
412  /* It is possible that we get a keysym that we can not convert
413  * into a keycode (such a case might be binding the key on
414  * one system, and later trying to run on another system that
415  * doesn't have that key.
416  * While the client will not be able to use it this invocation,
417  * it may be able to use it in the future. As such, don't throw
418  * it away, but at least print a warning message.
419  */
420  if (keycode==0) {
421  LOG(LOG_WARNING,"x11::parse_keybind_line","could not convert keysym %s into keycode, ignoring",
422  buf);
423  }
424  }
425  /* Rest of the line is the actual command. Lets kill the newline */
426  cpnext[strlen(cpnext)-1]='\0';
427  if (strlen(cpnext)>(sizeof(bind_buf)-1)){
428  cpnext[sizeof(bind_buf)-1]='\0';
429  LOG(LOG_WARNING,"gtk::parse_keybind_line","Had to truncate a too long command");
430  }
431  insert_key(keysym, keycode, flags | standard, cpnext);
432 }
433 
434 /* This code is common to both x11 and gdk client */
435 static void init_default_keybindings(void)
436 {
437  char buf[MAX_BUF];
438  int i;
439 
440  for(i=0;i< sizeof(def_keys)/sizeof(char *);i++) {
441  strcpy(buf,def_keys[i]);
442  parse_keybind_line(buf,i,1);
443  }
444 }
445 
446 
447 /* This reads in the keybindings, and initializes any special values.
448  * called by init_windows.
449  */
450 /* This function is common to both x11 and gdk client */
451 
452 void init_keys(void)
453 {
454  int i, line=0;
455  FILE *fp;
456  char buf[BIG_BUF];
457 
458  commandkeysym = XK_apostrophe;
459  commandkey =XKeysymToKeycode(display,XK_apostrophe);
460  if (!commandkey) {
461  commandkeysym =XK_acute;
462  commandkey =XKeysymToKeycode(display, XK_acute);
463  }
464  firekeysym[0] =XK_Shift_L;
465  firekey[0] =XKeysymToKeycode(display, XK_Shift_L);
466  firekeysym[1] =XK_Shift_R;
467  firekey[1] =XKeysymToKeycode(display, XK_Shift_R);
468  runkeysym[0] =XK_Control_L;
469  runkey[0] =XKeysymToKeycode(display, XK_Control_L);
470  runkeysym[1] =XK_Control_R;
471  runkey[1] =XKeysymToKeycode(display, XK_Control_R);
472 
473  completekeysym = XK_Tab;
474  completekey = XKeysymToKeycode(display, XK_Tab);
475  /* Don't set these to anything by default. At least on sun
476  * keyboards, the keysym for up on both the keypad and arrow
477  * keys is the same, so player needs to rebind this so we get proper
478  * keycode. Very unfriendly to log in and not be able to move north/south.
479  */
480  nextkeysym = NoSymbol;
481  nextkey = 0;
482  prevkeysym = NoSymbol;
483  prevkey = 0;
484 
485  for (i=0; i<=MAX_KEYCODE; i++) {
486  keys[i] = NULL;
487  }
488 
489  /* We now try to load the keybindings. First place to look is the
490  * users home directory, "~/.crossfire/keys". Using a directory
491  * seems like a good idea, in the future, additional stuff may be
492  * stored.
493  *
494  * The format is described in the def_keys file. Note that this file
495  * is the same as what it was in the server distribution. To convert
496  * bindings in character files to this format, all that needs to be done
497  * is remove the 'key ' at the start of each line.
498  *
499  * We need at least one of these keybinding files to exist - this is
500  * where the various commands are defined. In theory, we actually
501  * don't need to have any of these defined -- the player could just
502  * bind everything. Probably not a good idea, however.
503  */
504 
505  sprintf(buf,"%s/.crossfire/keys", getenv("HOME"));
506  if ((fp=fopen(buf,"r"))==NULL) {
507  LOG(LOG_INFO,"x11::init_keys","Could not open ~/.crossfire/keys, trying to load global bindings");
508  if (client_libdir==NULL) {
510  return;
511  }
512  sprintf(buf,"%s/def_keys", client_libdir);
513  if ((fp=fopen(buf,"r"))==NULL) {
515  return;
516  }
517  }
518  while (fgets(buf, BIG_BUF, fp)) {
519  line++;
520  parse_keybind_line(buf,line,0);
521  }
522  fclose(fp);
523 }
524 
525 /* The only things we actually care about is the run and fire keys.
526  * Other key releases are not important.
527  * If it is the release of a run or fire key, we tell the client
528  * to stop firing or running. In some cases, it is possible that we
529  * actually are not running or firing, and in such cases, the server
530  * will just ignore the command.
531  */
532 
533 /* This code is used by gdk and x11 client, but has
534  * a fair number of #ifdefs to get the right
535  * behavioiur
536  */
537 void parse_key_release(KeyCode kc, KeySym ks) {
538 
539  /* Only send stop firing/running commands if we are in actual
540  * play mode. Something smart does need to be done when the character
541  * enters a non play mode with fire or run mode already set, however.
542  */
543 
544  if (kc==firekey[0] || ks==firekeysym[0] ||
545  kc==firekey[1] || ks==firekeysym[1]) {
546  cpl.fire_on=0;
547 #ifdef GDK_XUTIL
548  clear_fire();
549  gtk_label_set (GTK_LABEL(fire_label)," ");
550 #else
551  stop_fire();
553 #endif
554  }
555  else if (kc==runkey[0] || ks==runkeysym[0] ||
556  kc==runkey[1] || ks==runkeysym[1]) {
557  cpl.run_on=0;
558  if (use_config[CONFIG_ECHO]) draw_info("stop run",NDI_BLACK);
559 #ifdef GDK_XUTIL
560  clear_run();
561  gtk_label_set (GTK_LABEL(run_label)," ");
562 #else
563  stop_run();
565 #endif
566  }
567  /* Firing is handled on server side. However, to keep more like the
568  * old version, if you release the direction key, you want the firing
569  * to stop. This should do that.
570  */
571  else if (cpl.fire_on)
572  stop_fire();
573 }
574 
575 /* This parses a keypress. It should only be called when in Playing
576  * mode.
577  */
578 void parse_key(char key, KeyCode keycode, KeySym keysym, int repeated)
579 {
580  Key_Entry *keyentry, *first_match=NULL;
581  int present_flags=0;
582  char buf[MAX_BUF];
583 
584  if (keycode == commandkey && keysym==commandkeysym) {
585  draw_prompt(">");
587  cpl.no_echo=FALSE;
588  return;
589  }
590  if (keycode == firekey[0] || keysym==firekeysym[0] ||
591  keycode == firekey[1] || keysym==firekeysym[1]) {
592  cpl.fire_on=1;
593 #ifdef GDK_XUTIL
594  gtk_label_set (GTK_LABEL(fire_label),"Fire");
595 #else
597 #endif
598  return;
599  }
600  if (keycode == runkey[0] || keysym==runkeysym[0] ||
601  keycode==runkey[1] || keysym==runkeysym[1]) {
602  cpl.run_on=1;
603 #ifdef GDK_XUTIL
604  gtk_label_set (GTK_LABEL(run_label),"Run");
605 #else
607 #endif
608  return;
609  }
610 
611  if (cpl.run_on) present_flags |= KEYF_RUN;
612  if (cpl.fire_on) present_flags |= KEYF_FIRE;
613  if (present_flags ==0) present_flags = KEYF_NORMAL;
614 
615  keyentry = keys[keycode];
616  while (keyentry!=NULL) {
617  if ((keyentry->keysym!=NoSymbol && keyentry->keysym!=keysym) ||
618  (!(keyentry->flags & present_flags))) {
619  keyentry=keyentry->next;
620  continue;
621  }
622  first_match = keyentry;
623  /* Try to find a prefect match */
624  if ((keyentry->flags & KEYF_MODIFIERS)!= present_flags) {
625  keyentry=keyentry->next;
626  continue;
627  }
628  else break;
629  }
630  if (first_match!=NULL) {
631  char buf[MAX_BUF];
632 
633  if (first_match->flags & KEYF_EDIT) {
634  strcpy(cpl.input_text, first_match->command);
636 #ifdef GDK_XUTIL
637  snprintf(buf, sizeof(buf), "%s", cpl.input_text);
638  gtk_entry_set_text(GTK_ENTRY(entrytext),buf);
639  gtk_widget_grab_focus (GTK_WIDGET(entrytext));
640 #else
641  snprintf(buf, sizeof(buf), ">%s", cpl.input_text);
642  draw_prompt(buf);
643 #endif
644  return;
645  }
646 
647  if (first_match->direction>=0) {
648  if (cpl.fire_on) {
649  snprintf(buf, sizeof(buf), "fire %s", first_match->command);
650  fire_dir(first_match->direction);
651  }
652  else if (cpl.run_on) {
653  run_dir(first_match->direction);
654  snprintf(buf, sizeof(buf), "run %s", first_match->command);
655  }
656  else if (!repeated) {
657  strcpy(buf,first_match->command);
658  extended_command(first_match->command);
659  }
660  else
661  snprintf(buf, sizeof(buf), "move %s (ignored)", first_match->command);
663  }
664  else {
665  if (use_config[CONFIG_ECHO]) draw_info(first_match->command,NDI_BLACK);
666  extended_command(first_match->command);
667  }
668  return;
669  }
670  if (key>='0' && key<='9') {
671  cpl.count = cpl.count*10 + (key-'0');
672  if (cpl.count>100000) cpl.count%=100000;
673 #ifdef GDK_XUTIL
674  gtk_spin_button_set_value (GTK_SPIN_BUTTON(counttext), (float) cpl.count );
675 #endif
676  return;
677  }
678  snprintf(buf, sizeof(buf), "Key unused (%s%s%s)",
679  (cpl.fire_on? "Fire&": ""),
680  (cpl.run_on ? "Run&" : ""),
681  keysym==NoSymbol? "unknown": XKeysymToString(keysym));
682  draw_info(buf,NDI_BLACK);
683  cpl.count=0;
684 }
685 
686 
687 /* This returns a character string desribing the key. */
688 /* If save_mode is true, it means that the format used for saving
689  * the information is used, instead of the usual format for displaying
690  * the information in a friendly manner.
691  */
692 static char * get_key_info(Key_Entry *key, KeyCode kc, int save_mode)
693 {
694  /* bind buf is the maximum space allowed for a
695  * binded command. We will add additional datas to
696  * it so we increase by MAX_BUF*/
697  static char buf[MAX_BUF+sizeof(bind_buf)];
698  char buff[MAX_BUF];
699  int bi=0;
700 
701  if ((key->flags & KEYF_MODIFIERS) == KEYF_MODIFIERS)
702  buff[bi++] ='A';
703  else {
704  if (key->flags & KEYF_NORMAL)
705  buff[bi++] ='N';
706  if (key->flags & KEYF_FIRE)
707  buff[bi++] ='F';
708  if (key->flags & KEYF_RUN)
709  buff[bi++] ='R';
710  }
711  if (key->flags & KEYF_EDIT)
712  buff[bi++] ='E';
713  if (key->flags & KEYF_STANDARD)
714  buff[bi++] ='S';
715 
716  buff[bi]='\0';
717  if (save_mode) {
718  if(key->keysym == NoSymbol) {
719  snprintf(buf, sizeof(buf), "(null) %i %s %s",
720  kc,buff, key->command);
721  }
722  else {
723  snprintf(buf, sizeof(buf), "%s %i %s %s",
724  XKeysymToString(key->keysym), kc,
725  buff, key->command);
726  }
727  }
728  else {
729  if(key->keysym == NoSymbol) {
730  snprintf(buf, sizeof(buf), "key (null) (%i) %s %s",
731  kc,buff, key->command);
732  }
733  else {
734  snprintf(buf, sizeof(buf), "key %s (%i) %s %s",
735  XKeysymToString(key->keysym), kc,
736  buff, key->command);
737  }
738  }
739  return buf;
740 }
741 
742 /* Shows all the keybindings. allbindings me we also show the standard
743  * (default) keybindings.
744  */
745 
746 static void show_keys(int allbindings)
747 {
748  int i, count=1;
749  Key_Entry *key;
750  char buf[MAX_BUF];
751 
752  snprintf(buf, sizeof(buf), "Commandkey %s (%d)",
753  commandkeysym==NoSymbol?"unknown":XKeysymToString(commandkeysym),
754  commandkey);
755  draw_info(buf,NDI_BLACK);
756  snprintf(buf, sizeof(buf), "Firekeys 1: %s (%d), 2: %s (%d)",
757  firekeysym[0]==NoSymbol?"unknown":XKeysymToString(firekeysym[0]), firekey[0],
758  firekeysym[1]==NoSymbol?"unknown":XKeysymToString(firekeysym[1]), firekey[1]);
759  draw_info(buf,NDI_BLACK);
760  snprintf(buf, sizeof(buf), "Runkeys 1: %s (%d), 2: %s (%d)",
761  runkeysym[0]==NoSymbol?"unknown":XKeysymToString(runkeysym[0]), runkey[0],
762  runkeysym[1]==NoSymbol?"unknown":XKeysymToString(runkeysym[1]), runkey[1]);
763  draw_info(buf,NDI_BLACK);
764 
765  snprintf(buf, sizeof(buf), "Command Completion Key %s (%d)",
766  completekeysym==NoSymbol?"unknown":XKeysymToString(completekeysym),
767  completekey);
768  draw_info(buf,NDI_BLACK);
769 
770  snprintf(buf, sizeof(buf), "Next Command in History Key %s (%d)",
771  nextkeysym==NoSymbol?"unknown":XKeysymToString(nextkeysym),
772  nextkey);
773  draw_info(buf,NDI_BLACK);
774 
775  snprintf(buf, sizeof(buf), "Previous Command in History Key %s (%d)",
776  prevkeysym==NoSymbol?"unknown":XKeysymToString(prevkeysym),
777  prevkey);
778  draw_info(buf,NDI_BLACK);
779 
780 
781  /* Perhaps we should start at 8, so that we only show 'active'
782  * keybindings?
783  */
784  for (i=0; i<=MAX_KEYCODE; i++) {
785  for (key=keys[i]; key!=NULL; key =key->next) {
786  if (key->flags & KEYF_STANDARD && !allbindings) continue;
787 
788  snprintf(buf, sizeof(buf), "%3d %s", count, get_key_info(key, i, 0));
789  draw_info(buf,NDI_BLACK);
790  count++;
791  }
792  }
793 }
794 
795 
796 
797 
798 void bind_key(const char *params)
799 {
800  char buf[MAX_BUF];
801 
802  if (!params) {
803  draw_info("Usage: bind [-nfre] {<commandline>/commandkey/firekey{1/2}/runkey{1/2}/",NDI_BLACK);
804  draw_info(" completekey/nextkey/prevkey}",NDI_BLACK);
805  return;
806  }
807 
808  /* Skip over any spaces we may have */
809  while (*params==' ') params++;
810 
811  if (!strcmp(params, "commandkey")) {
814  draw_info("Push key to bind new commandkey.",NDI_BLACK);
816  return;
817  }
818  if (!strcmp(params, "firekey1")) {
819  bind_keycode = &firekey[0];
820  bind_keysym = & firekeysym[0];
821  draw_info("Push key to bind new firekey 1.",NDI_BLACK);
823  return;
824  }
825  if (!strcmp(params, "firekey2")) {
826  bind_keycode = &firekey[1];
827  bind_keysym = & firekeysym[1];
828  draw_info("Push key to bind new firekey 2.",NDI_BLACK);
830  return;
831  }
832  if (!strcmp(params, "runkey1")) {
833  bind_keycode = &runkey[0];
834  bind_keysym = &runkeysym[0];
835  draw_info("Push key to bind new runkey 1.",NDI_BLACK);
837  return;
838  }
839  if (!strcmp(params, "runkey2")) {
840  bind_keycode = &runkey[1];
841  bind_keysym = &runkeysym[1];
842  draw_info("Push key to bind new runkey 2.",NDI_BLACK);
844  return;
845  }
846 
847  if (!strcmp(params, "completekey")) {
850  draw_info("Push key to bind new command completeion key",NDI_BLACK);
852  return;
853  }
854 
855  if (!strcmp(params, "prevkey")) {
858  draw_info("Push key to bind new previous command in history key.",NDI_BLACK);
860  return;
861  }
862 
863  if (!strcmp(params, "nextkey")) {
866  draw_info("Push key to bind new next command in history key.",NDI_BLACK);
868  return;
869  }
870 
871 
872  if (params[0] != '-')
874  else {
875  bind_flags =0;
876  bind_keysym=NULL;
877  bind_keycode=NULL;
878  for (params++; *params != ' '; params++)
879  switch (*params) {
880  case 'n':
882  break;
883  case 'f':
885  break;
886  case 'r':
887  bind_flags |= KEYF_RUN;
888  break;
889  case 'e':
891  break;
892  case '\0':
893  draw_info("Try unbind to remove bindings..",NDI_BLACK);
894  return;
895  default:
896  snprintf(buf, sizeof(buf), "Unknown flag to bind: '%c'", *params);
897  draw_info(buf,NDI_BLACK);
898  return;
899  }
900  params++;
901  }
902 
903  if (!(bind_flags & KEYF_MODIFIERS))
905 
906  if (!params[0]) {
907  draw_info("Try unbind to remove bindings..",NDI_BLACK);
908  return;
909  }
910 
911  strncpy(bind_buf, params, sizeof(bind_buf)-1);
912  bind_buf[sizeof(bind_buf)-1]=0;
913  if (strlen(params) >= sizeof(bind_buf)) {
914  draw_info("Keybinding too long! Truncated:",NDI_RED);
916  }
917 
918  snprintf(buf, sizeof(buf), "Push key to bind '%s'.", bind_buf);
919  draw_info(buf,NDI_BLACK);
920  bind_keycode=NULL;
922  return;
923 }
924 
925 
926 /* This is a recursive function that saves all the entries for a particular
927  * entry. We save the first element first, and then go through
928  * and save the rest of the elements. In this way, the ordering of the key
929  * entries in the
930  * file remains the same.
931  */
932 
933 static void save_individual_key(FILE *fp, Key_Entry *key, KeyCode kc)
934 {
935  if (key==NULL) return;
936  fprintf(fp, "%s\n", get_key_info(key, kc, 1));
937  save_individual_key(fp, key->next, kc);
938 }
939 
940 static void save_keys(void)
941 {
942  char buf[MAX_BUF], buf2[MAX_BUF];
943  int i;
944  FILE *fp;
945 
946  sprintf(buf,"%s/.crossfire/keys", getenv("HOME"));
947  if (make_path_to_file(buf)==-1) {
948  LOG(LOG_WARNING,"x11::save_keys","Could not create %s", buf);
949  return;
950  }
951  if ((fp=fopen(buf,"w"))==NULL) {
952  snprintf(buf2, sizeof(buf2), "Could not open %s, key bindings not saved\n", buf);
953  draw_info(buf2,NDI_BLACK);
954  return;
955  }
956  if (commandkeysym != XK_apostrophe && commandkeysym != NoSymbol) {
957  fprintf(fp, "! commandkey %s %d\n",
958  XKeysymToString(commandkeysym), commandkey);
959  }
960  if (firekeysym[0] != XK_Shift_L && firekeysym[0] != NoSymbol) {
961  fprintf(fp, "! firekey0 %s %d\n",
962  XKeysymToString(firekeysym[0]), firekey[0]);
963  }
964  if (firekeysym[1] != XK_Shift_R && firekeysym[1] != NoSymbol) {
965  fprintf(fp, "! firekey1 %s %d\n",
966  XKeysymToString(firekeysym[1]), firekey[1]);
967  }
968  if (runkeysym[0] != XK_Control_L && runkeysym[0] != NoSymbol) {
969  fprintf(fp, "! runkey0 %s %d\n",
970  XKeysymToString(runkeysym[0]), runkey[0]);
971  }
972  if (runkeysym[1] != XK_Control_R && runkeysym[1] != NoSymbol) {
973  fprintf(fp, "! runkey1 %s %d\n",
974  XKeysymToString(runkeysym[1]), runkey[1]);
975  }
976  if (completekeysym != XK_Tab && completekeysym != NoSymbol) {
977  fprintf(fp, "! completekey %s %d\n",
978  XKeysymToString(completekeysym), completekey);
979  }
980  /* No defaults for these, so if it is set to anything, assume its valid */
981  if (nextkeysym != NoSymbol) {
982  fprintf(fp, "! nextkey %s %d\n",
983  XKeysymToString(nextkeysym), nextkey);
984  }
985  if (prevkeysym != NoSymbol) {
986  fprintf(fp, "! prevkey %s %d\n",
987  XKeysymToString(prevkeysym), prevkey);
988  }
989 
990  for (i=0; i<=MAX_KEYCODE; i++) {
991  save_individual_key(fp, keys[i], i);
992  }
993  fclose(fp);
994  /* Should probably check return value on all writes to be sure, but... */
995  draw_info("key bindings successfully saved.",NDI_BLACK);
996 }
997 
998 void configure_keys(KeyCode k, KeySym keysym)
999 {
1000  char buf[MAX_BUF];
1001 
1002  if (bind_keycode==NULL) {
1003  if(k == firekey[0] || k == firekey[1]) {
1004  cpl.fire_on =1;
1006  return;
1007  }
1008  if(k == runkey[0] || k == runkey[1]) {
1009  cpl.run_on =1;
1011  return;
1012  }
1013  }
1015  /* Try to be clever - take into account shift/control keys being
1016  * held down when binding keys - in this way, player does not have to use
1017  * -f and -r flags to bind for many simple binds.
1018  */
1019 
1020  if ((cpl.fire_on || cpl.run_on) && (bind_flags & KEYF_MODIFIERS)==KEYF_MODIFIERS) {
1021  bind_flags &= ~KEYF_MODIFIERS;
1022  if (cpl.fire_on) bind_flags |= KEYF_FIRE;
1023  if (cpl.run_on) bind_flags |= KEYF_RUN;
1024  }
1025 
1026  if (bind_keycode!=NULL) {
1027  *bind_keycode = k;
1029  }
1030  else {
1031  insert_key(keysym, k, bind_flags, bind_buf);
1032  }
1033 
1034  snprintf(buf, sizeof(buf), "Binded to key '%s' (%i)",
1035  keysym==NoSymbol?"unknown":XKeysymToString(keysym), (int)k);
1036  draw_info(buf,NDI_BLACK);
1037  cpl.fire_on=0;
1038  cpl.run_on=0;
1040 
1041  /* Do this each time a new key is bound. This way, we are never actually
1042  * storing any information that needs to be saved when the connection
1043  * dies or the player quits.
1044  */
1045  save_keys();
1046  return;
1047 }
1048 
1049 static void unbind_usage(void)
1050 {
1051  draw_info("Usage: unbind <entry_number> or",NDI_BLACK);
1052  draw_info("Usage: unbind [-a] [-g] to show existing bindings", NDI_BLACK);
1053  draw_info(" -a shows all (global) bindings", NDI_BLACK);
1054  draw_info(" -g unbinds a global binding", NDI_BLACK);
1055 }
1056 
1057 void unbind_key(const char *params)
1058 {
1059  int count=0, keyentry, onkey,global=0;
1060  Key_Entry *key, *tmp;
1061  char buf[MAX_BUF];
1062 
1063  if (params==NULL || params[0]=='\0') {
1064  show_keys(0);
1065  return;
1066  }
1067 
1068  /* Skip over any spaces we may have */
1069  while (*params==' ') params++;
1070 
1071  if (!strcmp(params,"-a")) {
1072  show_keys(1);
1073  return;
1074  }
1075  if (!strncmp(params,"-g",2)) {
1076  global=1;
1077  if (!(params=strchr(params,' '))) {
1078  unbind_usage();
1079  return;
1080  }
1081  }
1082  if ((keyentry=atoi(params))==0) {
1083  unbind_usage();
1084  return;
1085  }
1086 
1087  for (onkey=0; onkey<=MAX_KEYCODE; onkey++) {
1088  for (key=keys[onkey]; key; key =key->next) {
1089  if (global || !(key->flags&KEYF_STANDARD)) count++;
1090  /* We found the key we want to unbind */
1091  if (keyentry==count) {
1092 
1093  /* If it is the first entry, it is easy */
1094  if (key == keys[onkey]) {
1095  keys[onkey] = key->next;
1096  goto unbinded;
1097  }
1098  /* Otherwise, we need to figure out where in the link list
1099  * the entry is.
1100  */
1101  for (tmp=keys[onkey]; tmp->next!=NULL; tmp=tmp->next) {
1102  if (tmp->next == key) {
1103  tmp->next =key->next;
1104  goto unbinded;
1105  }
1106  }
1107  LOG(LOG_ERROR,"x11::unbind_key","found number entry, but could not find actual key");
1108  }
1109  }
1110  }
1111  /* Makes things look better to draw the blank line */
1112  draw_info("",NDI_BLACK);
1113  draw_info("No such entry. Try 'unbind' with no options to find entry.",NDI_BLACK);
1114  return;
1115 
1116  /*
1117  * Found. Now remove it.
1118  */
1119 
1120 unbinded:
1121 
1122  snprintf(buf, sizeof(buf), "Removed binding: %3d %s", count, get_key_info(key, onkey, 0));
1123 
1124 
1125  draw_info(buf,NDI_BLACK);
1126  free(key->command);
1127  free(key);
1128  save_keys();
1129 }
1130 
1131 
1132 /* try to find a face in our private cache. We return the face
1133  * number if we find one, -1 for no face match
1134  */
1136 {
1137  int i;
1138 
1139  for (i=1; i<=last_face_num; i++)
1140  if (!strcmp(face, private_cache[i].name)) {
1141  return i;
1142  }
1143  return -1;
1144 }
1145 
1146 
1147 void image_update_download_status(int start, int end, int total)
1148 {
1149  char buf[MAX_BUF];
1150 
1151  snprintf(buf, sizeof(buf), "Downloaded %d of %d images", start, total);
1152 
1153  draw_info(buf,NDI_BLUE);
1154 }
1155 
1156 /* Start of map handling code.
1157  * For the most part, this actually is not window system specific,
1158  * but certainly how the client wants to store this may vary.
1159  *
1160  * At least in the gtk and x11 clients, 95+% of this code
1161  * is the same - the only think I think is different is
1162  * that the gtk will call sdl_scroll. This should
1163  * probably be moved into the common area.
1164  */
1165 
1166 #define MAXFACES 5
1167 #define MAXPIXMAPNUM 10000
1168 
1169 
1170 /*
1171  * Added for fog of war. Current size of the map structure in memory.
1172  * We assume a rectangular map so this is the length of one side.
1173  * command.c needs to know about this so not static
1174  * FIX ME: Don't assume rectangle
1175  */
1176 
1178 
1179 
1185 void reset_map(void)
1186 {
1187 }
1188 
1189 /* x11 client doesn't do smoothing, so don't need to do anything with this */
1190 void addsmooth(uint16 face, uint16 smooth_face)
1191 {
1192 }
1193 
1194 /* X11 client doesn't care about this */
1196 {
1197 }
1198 
1202 void client_pickup(uint32 pickup)
1203 {
1204 }
Pixmap pixmap
Definition: x11.h:37
#define KEYF_MODIFIERS
Definition: xutil.c:109
void parse_key_release(KeyCode kc, KeySym ks)
Definition: xutil.c:537
char * client_libdir
Definition: client.c:61
static KeySym completekeysym
Definition: xutil.c:101
uint32 checksum
Definition: xutil.c:66
struct Keys * next
Definition: image.c:104
static const char *const colorname[]
Definition: xutil.c:48
struct @10 private_cache[MAXPIXMAPNUM]
uint32 count
Definition: client.h:295
void parse_key(char key, KeyCode keycode, KeySym keysym, int repeated)
Definition: xutil.c:578
static char * get_key_info(Key_Entry *key, KeyCode kc, int save_mode)
Definition: xutil.c:692
#define KEYF_EDIT
Definition: xutil.c:111
void init_cache_data(void)
Definition: xutil.c:129
static char bind_buf[MAX_BUF]
Definition: xutil.c:104
void stop_fire(void)
Definition: player.c:116
static void save_keys(void)
Definition: xutil.c:940
void clear_fire(void)
Definition: player.c:134
#define CONFIG_ECHO
Definition: client.h:153
void client_pickup(uint32 pickup)
Definition: xutil.c:1202
void run_dir(int dir)
Definition: player.c:172
static KeyCode completekey
Definition: xutil.c:99
#define MAXPIXMAPNUM
Definition: xutil.c:1167
snd_pcm_hw_params_t * params
Definition: alsa9.c:111
static XColor discolor[16]
Definition: x11.c:191
int total
Definition: gx11.c:322
void clear_run(void)
Definition: player.c:142
static void init_default_keybindings(void)
Definition: xutil.c:435
Window win_root
Definition: x11.c:189
int make_path_to_file(char *filename)
Definition: misc.c:94
const char *const directions[9]
Definition: player.c:48
static KeyCode prevkey
Definition: xutil.c:99
void reset_map(void)
Definition: xutil.c:1185
uint32 no_echo
Definition: client.h:294
static KeySym runkeysym[2]
Definition: xutil.c:101
PixmapInfo * pixmaps[MAXPIXMAPNUM]
Definition: gx11.c:118
uint8 height
Definition: x11.h:38
void configure_keys(KeyCode k, KeySym keysym)
Definition: xutil.c:998
void LOG(LogLevel level, const char *origin, const char *format,...)
Definition: misc.c:178
#define NDI_RED
Definition: newclient.h:204
#define KEYF_RUN
Definition: xutil.c:108
#define KEYF_NORMAL
Definition: xutil.c:106
uint32 tick
Definition: client.c:70
void parse_keybind_line(char *buf, int line, int standard)
Definition: xutil.c:280
static void unbind_usage(void)
Definition: xutil.c:1049
static Key_Entry * keys[256]
Definition: xutil.c:122
uint8 updatekeycodes
Definition: xutil.c:125
sint8 direction
Definition: image.c:101
void draw_message_window(int redraw)
Definition: gx11.c:2458
sint16 use_config[CONFIG_NUMS]
Definition: init.c:50
static int bind_flags
Definition: xutil.c:103
static void show_keys(int allbindings)
Definition: xutil.c:746
void client_tick(uint32 tick)
Definition: xutil.c:1195
Pixmap mask
Definition: x11.h:37
Client_Player cpl
Definition: client.c:77
const char *const def_keys[]
Definition: def-keys.h:1
static void save_individual_key(FILE *fp, Key_Entry *key, KeyCode kc)
Definition: xutil.c:933
int last_face_num
Definition: xutil.c:70
static KeySym firekeysym[2]
Definition: xutil.c:101
Display * display
Definition: x11.c:184
PlayerPosition pl_pos
Definition: xutil.c:1177
unsigned short uint16
Definition: client-types.h:79
void extended_command(const char *ocommand)
Definition: p_cmd.c:890
GtkWidget * entrytext
Definition: gx11.c:270
uint32 run_on
Definition: client.h:291
static KeySym * bind_keysym
Definition: xutil.c:101
void bind_key(const char *params)
Definition: xutil.c:798
static KeySym nextkeysym
Definition: xutil.c:101
static KeySym prevkeysym
Definition: xutil.c:101
char * command
Definition: image.c:103
uint32 fire_on
Definition: client.h:290
#define MAX_BUF
Definition: client-types.h:128
const char * rcsid_x11_xutil_c
Definition: xutil.c:1
unsigned int uint32
Definition: client-types.h:77
void stop_run(void)
Definition: player.c:166
#define BIG_BUF
Definition: client-types.h:129
#define MAX_KEYCODE
Definition: xutil.c:121
char * strdup_local(const char *str)
Definition: misc.c:125
static KeyCode runkey[2]
Definition: xutil.c:99
void image_update_download_status(int start, int end, int total)
Definition: xutil.c:1147
signed char sint8
Definition: client-types.h:82
static void insert_key(KeySym keysym, KeyCode keycode, int flags, char *command)
Definition: xutil.c:221
static KeyCode commandkey
Definition: xutil.c:99
struct Keys Key_Entry
Pixmap pixmap
Definition: xutil.c:67
void allocate_colors(Display *disp, Window w, long screen_num, Colormap *colormap, XColor discolor[16])
Definition: xutil.c:172
Input_State input_state
Definition: client.h:277
void init_common_cache_data(void)
Definition: image.c:332
void draw_info(const char *str, int color)
Definition: gx11.c:1773
uint8 width
Definition: x11.h:38
#define KEYF_STANDARD
Definition: xutil.c:112
int find_face_in_private_cache(char *face, int checksum)
Definition: xutil.c:1135
#define KEYF_FIRE
Definition: xutil.c:107
uint8 flags
Definition: image.c:100
char input_text[MAX_BUF]
Definition: client.h:279
static KeyCode * bind_keycode
Definition: xutil.c:99
int use_private_cache
Definition: xutil.c:70
GC gc_game
Definition: x11.c:255
void init_keys(void)
Definition: xutil.c:452
unsigned char uint8
Definition: client-types.h:81
Colormap colormap
Definition: x11.c:190
GtkWidget * run_label
Definition: gx11.c:228
void unbind_key(const char *params)
Definition: xutil.c:1057
static KeyCode nextkey
Definition: xutil.c:99
#define NDI_BLACK
Definition: newclient.h:201
#define FALSE
Definition: client-types.h:68
void draw_prompt(const char *str)
Definition: gx11.c:1310
static KeySym commandkeysym
Definition: xutil.c:101
int image_size
Definition: gx11.c:116
KeySym keysym
Definition: image.c:102
GtkWidget * fire_label
Definition: gx11.c:228
static KeyCode firekey[2]
Definition: xutil.c:99
void fire_dir(int dir)
Definition: player.c:151
Definition: image.c:99
void addsmooth(uint16 face, uint16 smooth_face)
Definition: xutil.c:1190
#define NDI_BLUE
Definition: newclient.h:206
GtkWidget * counttext
Definition: inventory.c:1072
char * name
Definition: xutil.c:65