Crossfire Client, Branches  R11627
keys.c
Go to the documentation of this file.
1 const char * const rcsid_gtk_keys_c =
2  "$Id: keys.c 10997 2008-12-17 03:36:53Z kbulgrien $";
3 /*
4  Crossfire client, a client program for the crossfire program.
5 
6  Copyright (C) 2001 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 
32 #include <config.h>
33 #include <stdlib.h>
34 #include <sys/stat.h>
35 #ifndef WIN32
36 #include <unistd.h>
37 #endif
38 
39 /*#include <X11/keysym.h>*/
40 
41 /* Pick up the gtk headers we need */
42 #include <gtk/gtk.h>
43 #ifndef WIN32
44 #include <gdk/gdkx.h>
45 #else
46 #include <gdk/gdkwin32.h>
47 #define NoSymbol 0L /* Special KeySym */
48 typedef int KeyCode; /* Undefined type */
49 #include <io.h> /* access( ) */
50 #endif
51 #include <gdk/gdkkeysyms.h>
52 
53 #include "client-types.h"
54 #include "gx11.h"
55 #include "client.h"
56 #include "p_cmd.h"
57 
58 #include "def-keys.h"
59 
60 #include "gtkproto.h"
61 /******************************************************************************
62  *
63  * Code related to face caching.
64  *
65  *****************************************************************************/
66 
67 typedef struct Keys {
68  uint8 flags;
71  char *command;
72  struct Keys *next;
73 } Key_Entry;
74 
75 /***********************************************************************
76  *
77  * Key board input translations are handled here. We don't deal with
78  * the events, but rather KeyCodes and KeySyms.
79  *
80  * It would be nice to deal with only KeySyms, but many keyboards
81  * have keys that do not correspond to a KeySym, so we do need to
82  * support KeyCodes.
83  *
84  ***********************************************************************/
85 
86 
89 static int bind_flags=0;
90 static char bind_buf[MAX_BUF];
91 
92 #define KEYF_NORMAL 0x01 /* Used in normal mode */
93 #define KEYF_FIRE 0x02 /* Used in fire mode */
94 #define KEYF_RUN 0x04 /* Used in run mode */
95 #define KEYF_MODIFIERS 0x07 /* Mask for actual keyboard modifiers, */
96  /* not action modifiers */
97 #define KEYF_EDIT 0x08 /* Line editor */
98 #define KEYF_STANDARD 0x10 /* For standard (built in) key definitions */
99 
100 extern const char * const directions[9];
101 
102 /* Platform independence defines that we can't use keycodes.
103  * instead, make it a hash, and set KEYHASH to a prime number for
104  * this purpose.
105  */
106 #define KEYHASH 257
108 
109 
110 
111 /* Updates the keys array with the keybinding that is passed. All the
112  * arguments are pretty self explanatory. flags is the various state
113  * that the keyboard is in.
114  * This function is common to both gdk and x11 client
115  */
116 static void insert_key(uint32 keysym, int flags, const char *command)
117 {
118 
119  Key_Entry *newkey;
120  int i, direction=-1, slot;
121 
122  slot = keysym % KEYHASH;
123 
124  if (keys[slot]==NULL) {
125  keys[slot]=malloc(sizeof(Key_Entry));
126  keys[slot]->command=NULL;
127  keys[slot]->next=NULL;
128  newkey=keys[slot];
129  } else {
130  newkey=keys[slot];
131  while (newkey->next!=NULL)
132  newkey = newkey->next;
133  newkey->next = calloc(1, sizeof(Key_Entry));
134  newkey = newkey->next;
135  }
136 
137  /* Try to find out if the command is a direction command. If so, we
138  * then want to keep track of this fact, so in fire or run mode,
139  * things work correctly.
140  */
141  for (i=0; i<9; i++)
142  if (!strcmp(command, directions[i])) {
143  direction=i;
144  break;
145  }
146 
147  newkey->keysym = keysym;
148  newkey->flags = flags;
149  newkey->command = strdup_local(command);
150  newkey->direction = direction;
151 }
152 
153 
154 /* This function is common to both gdk and x11 client */
155 
156 static void parse_keybind_line(char *buf, int line, int standard)
157 {
158  char *cp, *cpnext;
159  uint32 keysym;
160  int flags;
161 
162  cp = NULL; /* There may be a rare error case when cp is used uninitialized. So let's be safe */
163 
164  if (buf[0]=='#' || buf[0]=='\n') return;
165  if ((cpnext = strchr(buf,' '))==NULL) {
166  LOG(LOG_WARNING,"gtk::parse_keybind_line","Line %d (%s) corrupted in keybinding file.", line,buf);
167  return;
168  }
169  /* Special keybinding line */
170  if (buf[0] == '!') {
171  char *cp1;
172  while (*cpnext == ' ') ++cpnext;
173  cp = strchr(cpnext, ' ');
174  if (!cp) {
175  LOG(LOG_WARNING,"gtk::parse_keybind_line","Line %d (%s) corrupted in keybinding file.", line,buf);
176  return;
177  }
178  *cp++ = 0; /* Null terminate it */
179  cp1 = strchr(cp, ' ');
180  if (!cp1) {
181  LOG(LOG_WARNING,"gtk::parse_keybind_line","Line %d (%s) corrupted in keybinding file.", line,buf);
182  return;
183  }
184  *cp1 ++ = 0;/* Null terminate it */
185  keysym = gdk_keyval_from_name(cp);
186  /* As of now, all these keys must have keysyms */
187  if (keysym == 0) {
188  LOG(LOG_WARNING,"gtk::parse_keybind_line","Could not convert %s into keysym", cp);
189  return;
190  }
191  if (!strcmp(cpnext,"commandkey")) {
193  return;
194  }
195  if (!strcmp(cpnext,"firekey0")) {
196  firekeysym[0] = keysym;
197  return;
198  }
199  if (!strcmp(cpnext,"firekey1")) {
200  firekeysym[1] = keysym;
201  return;
202  }
203  if (!strcmp(cpnext,"runkey0")) {
204  runkeysym[0] = keysym;
205  return;
206  }
207  if (!strcmp(cpnext,"runkey1")) {
208  runkeysym[1] = keysym;
209  return;
210  }
211  if (!strcmp(cpnext,"completekey")) {
213  return;
214  }
215  if (!strcmp(cpnext,"nextkey")) {
216  nextkeysym = keysym;
217  return;
218  }
219  if (!strcmp(cpnext,"prevkey")) {
220  prevkeysym = keysym;
221  return;
222  }
223  } else {
224  if (standard) standard=KEYF_STANDARD;
225  else standard=0;
226 
227  *cpnext++ = '\0';
228  keysym = gdk_keyval_from_name(buf);
229  if (!keysym) {
230  LOG(LOG_WARNING,"gtk::parse_keybind_line","Unable to convert line %d (%s) into keysym", line, cp);
231  return;
232  }
233  cp = cpnext;
234  if ((cpnext = strchr(cp,' '))==NULL) {
235  LOG(LOG_WARNING,"gtk::parse_keybind_line","Line %d (%s) corrupted in keybinding file.", line, cp);
236  return;
237  }
238  *cpnext++ = '\0';
239 
240  cp = cpnext;
241  if ((cpnext = strchr(cp,' '))==NULL) {
242  LOG(LOG_WARNING,"gtk::parse_keybind_line","Line %d (%s) corrupted in keybinding file.", line, cp);
243  return;
244  }
245  *cpnext++ = '\0';
246  flags = 0;
247  while (*cp!='\0') {
248  switch (*cp) {
249  case 'A':
250  flags |= KEYF_NORMAL | KEYF_FIRE | KEYF_RUN;
251  break;
252  case 'N':
253  flags |= KEYF_NORMAL;
254  break;
255  case 'F':
256  flags |= KEYF_FIRE;
257  break;
258  case 'R':
259  flags |= KEYF_RUN;
260  break;
261  case 'E':
262  flags |= KEYF_EDIT;
263  break;
264  case 'S':
265  flags |= KEYF_STANDARD;
266  break;
267  default:
268  LOG(LOG_WARNING,"gtk::parse_keybind_line","Unknown flag (%c) line %d in key binding file",
269  *cp, line);
270  }
271  cp++;
272  }
273 
274  /* Rest of the line is the actual command. Lets kill the newline */
275  cpnext[strlen(cpnext)-1]='\0';
276  if (strlen(cpnext)>(sizeof(bind_buf)-1)){
277  cpnext[sizeof(bind_buf)-1]='\0';
278  LOG(LOG_WARNING,"gtk::parse_keybind_line","Had to truncate a too long command");
279  }
280  insert_key(keysym, flags | standard, cpnext);
281  } /* else if not special binding line */
282 }
283 
284 /* This code is common to both x11 and gdk client */
285 static void init_default_keybindings(void)
286 {
287  char buf[MAX_BUF];
288  int i;
289 
290  for(i=0;i< sizeof(def_keys)/sizeof(char *);i++) {
291  strcpy(buf,def_keys[i]);
292  parse_keybind_line(buf,i,1);
293  }
294 }
295 
296 
297 /* This reads in the keybindings, and initializes any special values.
298  * called by init_windows.
299  */
300 /* This function is common to both x11 and gdk client */
301 
302 void init_keys(void)
303 {
304  int i, line=0;
305  FILE *fp;
306  char buf[BIG_BUF];
307  static int was_init = 0;
308 
309  commandkeysym = GDK_apostrophe;
310  firekeysym[0] =GDK_Shift_L;
311  firekeysym[1] =GDK_Shift_R;
312  runkeysym[0] =GDK_Control_L;
313  runkeysym[1] =GDK_Control_R;
314 
315  completekeysym = GDK_Tab;
316  cancelkeysym = GDK_Escape;
317 
318  /* Don't set these to anything by default. At least on sun
319  * keyboards, the keysym for up on both the keypad and arrow
320  * keys is the same, so player needs to rebind this so we get proper
321  * keycode. Very unfriendly to log in and not be able to move north/south.
322  */
323  nextkeysym = NoSymbol;
324  prevkeysym = NoSymbol;
325 
326  for (i=0; i<KEYHASH; i++) {
327  if ( was_init && keys[i] )
328  {
329  Key_Entry* next;
330  Key_Entry* cur = keys[i];
331  while ( cur )
332  {
333  next = cur->next;
334  free(cur->command);
335  free(cur);
336  cur = next;
337  }
338  }
339  keys[i] = NULL;
340  }
341  was_init = 1;
342 
343  /* We now try to load the keybindings. First place to look is the
344  * users home directory, "~/.crossfire/keys". Using a directory
345  * seems like a good idea, in the future, additional stuff may be
346  * stored.
347  *
348  * The format is described in the def_keys file. Note that this file
349  * is the same as what it was in the server distribution. To convert
350  * bindings in character files to this format, all that needs to be done
351  * is remove the 'key ' at the start of each line.
352  *
353  * We need at least one of these keybinding files to exist - this is
354  * where the various commands are defined. In theory, we actually
355  * don't need to have any of these defined -- the player could just
356  * bind everything. Probably not a good idea, however.
357  */
358 
359 #ifdef MULTKEYS
360  /* For Windows, use player name if defined for key file */
361  if ( strlen( cpl.name ) )
362  {
363  sprintf( buf, "%s/.crossfire/%s.keys", getenv( "HOME" ), cpl.name );
364  if ( access( buf, 0 ) == -1 )
365  {
366  /* Client key file not found, reverting to default file */
367  sprintf(buf,"%s/.crossfire/keys", getenv("HOME"));
368  }
369  }
370  else
371  sprintf(buf,"%s/.crossfire/keys", getenv("HOME"));
372 #else
373  sprintf(buf,"%s/.crossfire/keys", getenv("HOME"));
374 #endif
375  if ((fp=fopen(buf,"r"))==NULL) {
376  LOG(LOG_INFO,"gtk::init_keys","Could not open ~/.crossfire/keys, trying to load global bindings");
377  if (client_libdir==NULL) {
379  return;
380  }
381  sprintf(buf,"%s/def_keys", client_libdir);
382  if ((fp=fopen(buf,"r"))==NULL) {
384  return;
385  }
386  }
387  while (fgets(buf, BIG_BUF, fp)) {
388  line++;
389  buf[BIG_BUF-1]='\0';
390  parse_keybind_line(buf,line,0);
391  }
392  fclose(fp);
393 }
394 
395 /* The only things we actually care about is the run and fire keys.
396  * Other key releases are not important.
397  * If it is the release of a run or fire key, we tell the client
398  * to stop firing or running. In some cases, it is possible that we
399  * actually are not running or firing, and in such cases, the server
400  * will just ignore the command.
401  */
402 
403 /* This code is used by gdk and x11 client, but has
404  * a fair number of #ifdefs to get the right
405  * behavioiur
406  */
407 static void parse_key_release(uint32 ks) {
408 
409  /* Only send stop firing/running commands if we are in actual
410  * play mode. Something smart does need to be done when the character
411  * enters a non play mode with fire or run mode already set, however.
412  */
413 
414  if (ks==firekeysym[0] || ks==firekeysym[1]) {
415  cpl.fire_on=0;
416  clear_fire();
417  gtk_label_set (GTK_LABEL(fire_label)," ");
418  }
419  else if (ks==runkeysym[0] || ks==runkeysym[1]) {
420  cpl.run_on=0;
421  if (use_config[CONFIG_ECHO]) draw_info("stop run",NDI_BLACK);
422  clear_run();
423  gtk_label_set (GTK_LABEL(run_label)," ");
424  }
425 
426  /* Firing is handled on server side. However, to keep more like the
427  * old version, if you release the direction key, you want the firing
428  * to stop. This should do that.
429  */
430  else if (cpl.fire_on)
431  clear_fire();
432 }
433 
434 /* This parses a keypress. It should only be called when in Playing
435  * mode.
436  */
437 static void parse_key(char key, uint32 keysym)
438 {
439  Key_Entry *keyentry, *first_match=NULL;
440  int present_flags=0;
441  char buf[MAX_BUF];
442 
443  if (keysym==commandkeysym) {
445  gtk_widget_grab_focus (GTK_WIDGET(gtkwin_info));
446  gtk_widget_grab_focus (GTK_WIDGET(entrytext));
447  } else {
448  gtk_widget_grab_focus (GTK_WIDGET(entrytext));
449  }
450 
451  gtk_entry_set_visibility(GTK_ENTRY(entrytext), 1);
453  cpl.no_echo=FALSE;
454  return;
455  }
456  if (keysym==firekeysym[0] ||keysym==firekeysym[1]) {
457  cpl.fire_on=1;
458  gtk_label_set (GTK_LABEL(fire_label),"Fire");
459  return;
460  }
461  if (keysym==runkeysym[0] || keysym==runkeysym[1]) {
462  cpl.run_on=1;
463  gtk_label_set (GTK_LABEL(run_label),"Run");
464  return;
465  }
466 
467  if (cpl.run_on) present_flags |= KEYF_RUN;
468  if (cpl.fire_on) present_flags |= KEYF_FIRE;
469  if (present_flags ==0) present_flags = KEYF_NORMAL;
470 
471  keyentry = keys[keysym % KEYHASH];
472  while (keyentry!=NULL) {
473  if ((keyentry->keysym!=0 && keyentry->keysym!=keysym) ||
474  (!(keyentry->flags & present_flags))) {
475  keyentry=keyentry->next;
476  continue;
477  }
478  first_match = keyentry;
479 
480  /* Try to find a prefect match */
481  if ((keyentry->flags & KEYF_MODIFIERS)!= present_flags) {
482  keyentry=keyentry->next;
483  continue;
484  }
485  else break;
486  }
487  if (first_match!=NULL) {
488  if (first_match->flags & KEYF_EDIT) {
489  strcpy(cpl.input_text, first_match->command);
491  gtk_entry_set_text(GTK_ENTRY(entrytext),cpl.input_text);
492  gtk_widget_grab_focus (GTK_WIDGET(entrytext));
493 #ifdef CFGTK2
494  gtk_editable_select_region(GTK_EDITABLE(entrytext),strlen(cpl.input_text),-1);
495 #endif
496  return;
497  }
498 
499  if (first_match->direction>=0) {
500  if (cpl.fire_on) {
501  sprintf(buf,"fire %s", first_match->command);
502  /* Some spells (dimension door) need a valid count value */
503  cpl.count = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON(counttext));
504  fire_dir(first_match->direction);
505  }
506  else if (cpl.run_on) {
507  run_dir(first_match->direction);
508  sprintf(buf,"run %s", first_match->command);
509  }
510  else {
511  extended_command(first_match->command);
512  }
513  if (use_config[CONFIG_ECHO]) draw_info(first_match->command,NDI_BLACK);
514  }
515  else {
516  if (use_config[CONFIG_ECHO]) draw_info(first_match->command,NDI_BLACK);
517  extended_command(first_match->command);
518  }
519  return;
520  }
521  if (key>='0' && key<='9') {
522  cpl.count = cpl.count*10 + (key-'0');
523  if (cpl.count>100000) cpl.count%=100000;
524  gtk_spin_button_set_value (GTK_SPIN_BUTTON(counttext), (float) cpl.count );
525  return;
526  }
527  sprintf(buf, "Key unused (%s%s%s)",
528  (cpl.fire_on? "Fire&": ""),
529  (cpl.run_on ? "Run&" : ""),
530  keysym==NoSymbol? "unknown": gdk_keyval_name(keysym));
531 #ifdef WIN32
532  if ( ( 65513 != keysym ) && ( 65511 != keysym ) )
533 #endif
534  draw_info(buf,NDI_BLACK);
535  cpl.count=0;
536 }
537 
538 
539 /* This returns a character string desribing the key. */
540 /* If save_mode is true, it means that the format used for saving
541  * the information is used, instead of the usual format for displaying
542  * the information in a friendly manner.
543  */
544 static char * get_key_info(Key_Entry *key, int save_mode)
545 {
546  /* bind buf is the maximum space allowed for a
547  * binded command. We will add additional datas to
548  * it so we increase by MAX_BUF*/
549  static char buf[MAX_BUF+sizeof(bind_buf)];
550 
551  char buff[MAX_BUF];
552  int bi=0;
553 
554  if ((key->flags & KEYF_MODIFIERS) == KEYF_MODIFIERS)
555  buff[bi++] ='A';
556  else {
557  if (key->flags & KEYF_NORMAL)
558  buff[bi++] ='N';
559  if (key->flags & KEYF_FIRE)
560  buff[bi++] ='F';
561  if (key->flags & KEYF_RUN)
562  buff[bi++] ='R';
563  }
564  if (key->flags & KEYF_EDIT)
565  buff[bi++] ='E';
566  if (key->flags & KEYF_STANDARD)
567  buff[bi++] ='S';
568 
569  buff[bi]='\0';
570  if (save_mode) {
571  if(key->keysym == NoSymbol) {
572  sprintf(buf, "(null) %i %s %s",
573  0,buff, key->command);
574  }
575  else {
576  sprintf(buf, "%s %i %s %s",
577  gdk_keyval_name(key->keysym), 0,
578  buff, key->command);
579  }
580  }
581  else {
582  if(key->keysym == NoSymbol) {
583  sprintf(buf, "key (null) %s %s",
584  buff, key->command);
585  }
586  else {
587  sprintf(buf, "key %s %s %s",
588  gdk_keyval_name(key->keysym),
589  buff, key->command);
590  }
591  }
592  return buf;
593 }
594 
595 /* Shows all the keybindings. allbindings me we also show the standard
596  * (default) keybindings.
597  */
598 
599 static void show_keys(int allbindings)
600 {
601  int i, count=1;
602  Key_Entry *key;
603  char buf[MAX_BUF + sizeof( bind_buf )];
604 
605  sprintf(buf, "Commandkey %s",
606  commandkeysym==NoSymbol?"unknown":gdk_keyval_name(commandkeysym));
607  draw_info(buf,NDI_BLACK);
608 
609  sprintf(buf, "Firekeys 1: %s, 2: %s",
610  firekeysym[0]==NoSymbol?"unknown":gdk_keyval_name(firekeysym[0]),
611  firekeysym[1]==NoSymbol?"unknown":gdk_keyval_name(firekeysym[1]));
612  draw_info(buf,NDI_BLACK);
613 
614  sprintf(buf, "Runkeys 1: %s, 2: %s",
615  runkeysym[0]==NoSymbol?"unknown":gdk_keyval_name(runkeysym[0]),
616  runkeysym[1]==NoSymbol?"unknown":gdk_keyval_name(runkeysym[1]));
617  draw_info(buf,NDI_BLACK);
618 
619  sprintf(buf, "Command Completion Key %s",
620  completekeysym==NoSymbol?"unknown":gdk_keyval_name(completekeysym));
621  draw_info(buf,NDI_BLACK);
622 
623  sprintf(buf, "Next Command in History Key %s",
624  nextkeysym==NoSymbol?"unknown":gdk_keyval_name(nextkeysym));
625  draw_info(buf,NDI_BLACK);
626 
627  sprintf(buf, "Previous Command in History Key %s",
628  prevkeysym==NoSymbol?"unknown":gdk_keyval_name(prevkeysym));
629  draw_info(buf,NDI_BLACK);
630 
631 
632  /* Perhaps we should start at 8, so that we only show 'active'
633  * keybindings?
634  */
635  for (i=0; i<KEYHASH; i++) {
636  for (key=keys[i]; key!=NULL; key =key->next) {
637  if (key->flags & KEYF_STANDARD && !allbindings) continue;
638 
639  sprintf(buf,"%3d %s",count, get_key_info(key,0));
640  draw_info(buf,NDI_BLACK);
641  count++;
642  }
643  }
644 }
645 
646 
647 
648 void bind_key(const char *params)
649 {
650  /* Must have enough room for MAX_BUF and 'Push key to bind to ''.' */
651  char buf[MAX_BUF + 20];
652 
653  if (!params) {
654  draw_info("Usage: bind [-nfre] {<commandline>/commandkey/firekey{1/2}/runkey{1/2}/",NDI_BLACK);
655  draw_info(" completekey/nextkey/prevkey}",NDI_BLACK);
656  return;
657  }
658 
659  /* Skip over any spaces we may have */
660  while (*params==' ') params++;
661 
662  if (!strcmp(params, "commandkey")) {
664  draw_info("Push key to bind new commandkey.",NDI_BLACK);
666  return;
667  }
668 
669  if (!strcmp(params, "firekey1")) {
670  bind_keysym = & firekeysym[0];
671  draw_info("Push key to bind new firekey 1.",NDI_BLACK);
673  return;
674  }
675  if (!strcmp(params, "firekey2")) {
676  bind_keysym = & firekeysym[1];
677  draw_info("Push key to bind new firekey 2.",NDI_BLACK);
679  return;
680  }
681  if (!strcmp(params, "runkey1")) {
682  bind_keysym = &runkeysym[0];
683  draw_info("Push key to bind new runkey 1.",NDI_BLACK);
685  return;
686  }
687 
688  if (!strcmp(params, "runkey2")) {
689  bind_keysym = &runkeysym[1];
690  draw_info("Push key to bind new runkey 2.",NDI_BLACK);
692  return;
693  }
694 
695  if (!strcmp(params, "completekey")) {
697  draw_info("Push key to bind new command completeion key",NDI_BLACK);
699  return;
700  }
701 
702  if (!strcmp(params, "prevkey")) {
704  draw_info("Push key to bind new previous command in history key.",NDI_BLACK);
706  return;
707  }
708 
709  if (!strcmp(params, "nextkey")) {
711  draw_info("Push key to bind new next command in history key.",NDI_BLACK);
713  return;
714  }
715 
716 
717  if (params[0] != '-')
719  else {
720  bind_flags =0;
721  bind_keysym=NULL;
722  for (params++; *params != ' '; params++)
723  switch (*params) {
724  case 'n':
726  break;
727  case 'f':
729  break;
730  case 'r':
731  bind_flags |= KEYF_RUN;
732  break;
733  case 'e':
735  break;
736  case '\0':
737  draw_info("Try unbind to remove bindings..",NDI_BLACK);
738  return;
739  default:
740  sprintf(buf, "Unknown flag to bind: '%c'", *params);
741  draw_info(buf,NDI_BLACK);
742  return;
743  }
744  params++;
745  }
746 
747  if (!(bind_flags & KEYF_MODIFIERS))
749 
750  if (!params[0]) {
751  draw_info("Try unbind to remove bindings..",NDI_BLACK);
752  return;
753  }
754 
755  /* params is read only, so we need to the truncation on
756  * the buffer we will store it in, not params
757  */
758  strncpy(bind_buf, params, sizeof(bind_buf)-1);
759  bind_buf[sizeof(bind_buf)-1] = 0;
760 
761  if (strlen(params) >= sizeof(bind_buf)) {
762  draw_info("Keybinding too long! Truncated:",NDI_RED);
764  }
765 
766  sprintf(buf, "Push key to bind '%s'.", bind_buf);
767  draw_info(buf,NDI_BLACK);
768 
770  return;
771 }
772 
773 
774 /* This is a recursive function that saves all the entries for a particular
775  * entry. We save the first element first, and then go through
776  * and save the rest of the elements. In this way, the ordering of the key
777  * entries in the
778  * file remains the same.
779  */
780 
781 static void save_individual_key(FILE *fp, Key_Entry *key, KeyCode kc)
782 {
783  if (key==NULL) return;
784  fprintf(fp, "%s\n", get_key_info(key, 1));
785  save_individual_key(fp, key->next, kc);
786 }
787 
788 static void save_keys(void)
789 {
790  char buf[MAX_BUF], buf2[MAX_BUF];
791  int i;
792  FILE *fp;
793 
794 #ifdef MULTKEYS
795  /* Use player's name if available */
796  if ( strlen( cpl.name ) )
797  sprintf( buf,"%s/.crossfire/%s.keys", getenv("HOME"), cpl.name );
798  else
799  sprintf( buf,"%s/.crossfire/keys", getenv("HOME") );
800 #else
801  sprintf(buf,"%s/.crossfire/keys", getenv("HOME"));
802 #endif
803 
804  if (make_path_to_file(buf)==-1) {
805  LOG(LOG_WARNING,"gtk::save_keys","Could not create %s", buf);
806  return;
807  }
808  if ((fp=fopen(buf,"w"))==NULL) {
809  sprintf(buf2,"Could not open %s, key bindings not saved\n", buf);
810  draw_info(buf2,NDI_BLACK);
811  return;
812  }
813  if (commandkeysym != GDK_apostrophe && commandkeysym != NoSymbol) {
814  fprintf(fp, "! commandkey %s %d\n",
815  gdk_keyval_name(commandkeysym), 0);
816  }
817  if (firekeysym[0] != GDK_Shift_L && firekeysym[0] != NoSymbol) {
818  fprintf(fp, "! firekey0 %s %d\n",
819  gdk_keyval_name(firekeysym[0]), 0);
820  }
821  if (firekeysym[1] != GDK_Shift_R && firekeysym[1] != NoSymbol) {
822  fprintf(fp, "! firekey1 %s %d\n",
823  gdk_keyval_name(firekeysym[1]), 0);
824  }
825  if (runkeysym[0] != GDK_Control_L && runkeysym[0] != NoSymbol) {
826  fprintf(fp, "! runkey0 %s %d\n",
827  gdk_keyval_name(runkeysym[0]), 0);
828  }
829  if (runkeysym[1] != GDK_Control_R && runkeysym[1] != NoSymbol) {
830  fprintf(fp, "! runkey1 %s %d\n",
831  gdk_keyval_name(runkeysym[1]), 0);
832  }
833  if (completekeysym != GDK_Tab && completekeysym != NoSymbol) {
834  fprintf(fp, "! completekey %s %d\n",
835  gdk_keyval_name(completekeysym), 0);
836  }
837  /* No defaults for these, so if it is set to anything, assume its valid */
838  if (nextkeysym != NoSymbol) {
839  fprintf(fp, "! nextkey %s %d\n",
840  gdk_keyval_name(nextkeysym), 0);
841  }
842  if (prevkeysym != NoSymbol) {
843  fprintf(fp, "! prevkey %s %d\n",
844  gdk_keyval_name(prevkeysym), 0);
845  }
846 
847  for (i=0; i<KEYHASH; i++) {
848  save_individual_key(fp, keys[i], 0);
849  }
850  fclose(fp);
851  /* Should probably check return value on all writes to be sure, but... */
852  draw_info("key bindings successfully saved.",NDI_BLACK);
853 }
854 
856 {
857  char buf[MAX_BUF];
858 
859  /* I think that basically if we are not rebinding the special
860  * control keys (in which case bind_kesym would be set to something)
861  * we just want to handle these keypresses as normal events.
862  */
863  if (bind_keysym==NULL) {
864  if(keysym == firekeysym[0] || keysym == firekeysym[1]) {
865  cpl.fire_on =1;
867  return;
868  }
869  if(keysym == runkeysym[0] || keysym == runkeysym[1]) {
870  cpl.run_on =1;
872  return;
873  }
874  }
876  /* Try to be clever - take into account shift/control keys being
877  * held down when binding keys - in this way, player does not have to use
878  * -f and -r flags to bind for many simple binds.
879  */
880 
881  if ((cpl.fire_on || cpl.run_on) && (bind_flags & KEYF_MODIFIERS)==KEYF_MODIFIERS) {
882  bind_flags &= ~KEYF_MODIFIERS;
884  if (cpl.run_on) bind_flags |= KEYF_RUN;
885  }
886 
887  if (bind_keysym!=NULL) {
889  bind_keysym=NULL;
890  }
891  else {
892  insert_key(keysym, bind_flags, bind_buf);
893  }
894 
895  sprintf(buf, "Binded to key '%s' (%i)",
896  keysym==NoSymbol?"unknown":gdk_keyval_name(keysym), keysym);
897  draw_info(buf,NDI_BLACK);
898  cpl.fire_on=0;
899  cpl.run_on=0;
901 
902  /* Do this each time a new key is bound. This way, we are never actually
903  * storing any information that needs to be saved when the connection
904  * dies or the player quits.
905  */
906  save_keys();
907  return;
908 }
909 
910 static void unbind_usage(void)
911 {
912  draw_info("Usage: unbind <entry_number> or",NDI_BLACK);
913  draw_info("Usage: unbind [-a] [-g] to show existing bindings", NDI_BLACK);
914  draw_info(" -a shows all (global) bindings", NDI_BLACK);
915  draw_info(" -g unbinds a global binding", NDI_BLACK);
916 }
917 
918 void unbind_key(const char *params)
919 {
920  int count=0, keyentry, onkey,global=0;
921  Key_Entry *key, *tmp;
922  /* the key macro itself can be bind_buf long, and we need some extra
923  * space for the sprintf unbind message.
924  */
925  char buf[sizeof(bind_buf)+60];
926 
927  if (params==NULL || params[0]=='\0') {
928  show_keys(0);
929  return;
930  }
931 
932  /* Skip over any spaces we may have */
933  while (*params==' ') params++;
934 
935  if (!strcmp(params,"-a")) {
936  show_keys(1);
937  return;
938  }
939  if (!strncmp(params,"-g",2)) {
940  global=1;
941  if (!(params=strchr(params,' '))) {
942  unbind_usage();
943  return;
944  }
945  }
946  if ((keyentry=atoi(params))==0) {
947  unbind_usage();
948  return;
949  }
950 
951  for (onkey=0; onkey<KEYHASH; onkey++) {
952  for (key=keys[onkey]; key; key =key->next) {
953  if (global || !(key->flags&KEYF_STANDARD)) count++;
954  /* We found the key we want to unbind */
955  if (keyentry==count) {
956 
957  /* If it is the first entry, it is easy */
958  if (key == keys[onkey]) {
959  keys[onkey] = key->next;
960  goto unbinded;
961  }
962  /* Otherwise, we need to figure out where in the link list
963  * the entry is.
964  */
965  for (tmp=keys[onkey]; tmp->next!=NULL; tmp=tmp->next) {
966  if (tmp->next == key) {
967  tmp->next =key->next;
968  goto unbinded;
969  }
970  }
971  LOG(LOG_ERROR,"gtk::unbind_key","found number entry, but could not find actual key");
972  }
973  }
974  }
975  /* Makes things look better to draw the blank line */
976  draw_info("",NDI_BLACK);
977  draw_info("No such entry. Try 'unbind' with no options to find entry.",NDI_BLACK);
978  return;
979 
980  /*
981  * Found. Now remove it.
982  */
983 
984 unbinded:
985 
986  sprintf(buf,"Removed binding: %3d %s", count, get_key_info(key,0));
987 
988  draw_info(buf,NDI_BLACK);
989  free(key->command);
990  free(key);
991  save_keys();
992 }
993 
994 void keyrelfunc(GtkWidget *widget, GdkEventKey *event, GtkWidget *window)
995 {
996 
997  updatelock=0;
998  if (event->keyval>0) {
999  if (GTK_WIDGET_HAS_FOCUS (entrytext) /*|| GTK_WIDGET_HAS_FOCUS(counttext)*/ ) {
1000  } else {
1001  parse_key_release(event->keyval);
1002  gtk_signal_emit_stop_by_name (GTK_OBJECT(window), "key_release_event") ;
1003  }
1004  }
1005 }
1006 
1007 extern void disconnect(GtkWidget*);
1008 void keyfunc(GtkWidget *widget, GdkEventKey *event, GtkWidget *window) {
1009  char *text;
1010  updatelock=0;
1011 
1012  if (!use_config[CONFIG_POPUPS]) {
1013  if ( ((cpl.input_state == Reply_One) || (cpl.input_state == Reply_Many))
1014  && (event->keyval==cancelkeysym) ) {
1015  /*Player hit cancel button during input. Disconnect it (code from menubar)*/
1016  disconnect(widget);
1017  return;
1018  }
1019  if (cpl.input_state == Reply_One) {
1020  text=gdk_keyval_name(event->keyval);
1021  send_reply(text);
1023  gtk_signal_emit_stop_by_name(GTK_OBJECT(window), "key_press_event");
1024  return;
1025  }
1026  else if (cpl.input_state == Reply_Many) {
1027  if (GTK_WIDGET_HAS_FOCUS(entrytext)) {
1028  gtk_widget_event(GTK_WIDGET(entrytext), (GdkEvent*)event);
1029  gtk_signal_emit_stop_by_name(
1030  GTK_OBJECT(window), "key_press_event");
1031  } else
1032  gtk_widget_grab_focus(GTK_WIDGET(entrytext));
1033  return;
1034  }
1035  }
1036 
1037  /* Better check for really weirdo keys, X doesnt like keyval 0*/
1038  if (event->keyval<=0) return;
1039 
1040  if (GTK_WIDGET_HAS_FOCUS (entrytext) /*|| GTK_WIDGET_HAS_FOCUS(counttext)*/) {
1041  if (event->keyval == completekeysym) {
1043  return;
1044  }
1045  if (event->keyval == prevkeysym || event->keyval == nextkeysym)
1046  gtk_command_history(event->keyval==nextkeysym?0:1);
1047 #ifdef CFGTK2
1048  else
1049  gtk_widget_event(GTK_WIDGET(entrytext), (GdkEvent*)event);
1050  gtk_signal_emit_stop_by_name(GTK_OBJECT(window), "key_press_event");
1051 #endif
1052  } else {
1053  switch(cpl.input_state) {
1054  case Playing:
1055  /* Specials - do command history - many times, the player
1056  * will want to go the previous command when nothing is entered
1057  * in the command window.
1058  */
1059  if (event->keyval == prevkeysym || event->keyval == nextkeysym) {
1060  gtk_command_history(event->keyval==nextkeysym?0:1);
1061  return;
1062  }
1063 
1064  if (cpl.run_on) {
1065  if (!(event->state & GDK_CONTROL_MASK)) {
1066  /*printf ("Run is on while ctrl is not\n");*/
1067  gtk_label_set (GTK_LABEL(run_label)," ");
1068  cpl.run_on=0;
1069  stop_run();
1070  }
1071  }
1072  if (cpl.fire_on) {
1073  if (!(event->state & GDK_SHIFT_MASK)) {
1074  /* printf ("Fire is on while shift is not\n");*/
1075  gtk_label_set (GTK_LABEL(fire_label)," ");
1076  cpl.fire_on=0;
1077  stop_fire();
1078  }
1079  }
1080 
1081  if( (event->state & GDK_CONTROL_MASK) && (event->state & GDK_SHIFT_MASK) &&
1082  (event->keyval == GDK_i || event->keyval == GDK_I) ) {
1083  reset_map();
1084  }
1085 
1086 
1087  parse_key(event->string[0], event->keyval);
1088  gtk_signal_emit_stop_by_name (GTK_OBJECT(window), "key_press_event") ;
1089  break;
1090 
1091  case Configure_Keys:
1092  configure_keys(event->keyval);
1093  gtk_signal_emit_stop_by_name (GTK_OBJECT(window), "key_press_event") ;
1094  break;
1095 
1096  case Command_Mode:
1097  if (event->keyval == completekeysym) gtk_complete_command();
1098  if (event->keyval == prevkeysym || event->keyval == nextkeysym)
1099  gtk_command_history(event->keyval==nextkeysym?0:1);
1100  else {
1101  gtk_widget_grab_focus (GTK_WIDGET(entrytext));
1102  /* When running in split windows mode, entrytext can't get focus because
1103  * it is in a different window. So we have to pass the event to it
1104  * explicitly
1105  */
1106  if (GTK_WIDGET_HAS_FOCUS(entrytext)==0)
1107  gtk_widget_event(GTK_WIDGET(entrytext), (GdkEvent*)event);
1108  }
1109  /*
1110  * Don't pass signal along to default handlers - otherwise, we get
1111  * get crashes in the clist area (gtk fault I believe)
1112  */
1113  gtk_signal_emit_stop_by_name (GTK_OBJECT(window), "key_press_event") ;
1114  break;
1115 
1116  case Metaserver_Select:
1117  gtk_widget_grab_focus (GTK_WIDGET(entrytext));
1118  break;
1119 
1120  default:
1121  LOG(LOG_ERROR,"gtk::keyfunc","Unknown input state: %d", cpl.input_state);
1122  }
1123 
1124  }
1125 }
1126 
1127 
1128 
1129 void draw_keybindings (GtkWidget *keylist) {
1130  int i, count=1;
1131  Key_Entry *key;
1132  int allbindings=0;
1133  char buff[MAX_BUF];
1134  int bi=0;
1135  char buffer[5][MAX_BUF];
1136  char *buffers[5];
1137  gint tmprow;
1138 
1139  gtk_clist_clear (GTK_CLIST(keylist));
1140  for (i=0; i<KEYHASH; i++) {
1141  for (key=keys[i]; key!=NULL; key =key->next) {
1142  if (key->flags & KEYF_STANDARD && !allbindings) continue;
1143 
1144  bi=0;
1145 
1146  if ((key->flags & KEYF_MODIFIERS) == KEYF_MODIFIERS)
1147  buff[bi++] ='A';
1148  else {
1149  if (key->flags & KEYF_NORMAL)
1150  buff[bi++] ='N';
1151  if (key->flags & KEYF_FIRE)
1152  buff[bi++] ='F';
1153  if (key->flags & KEYF_RUN)
1154  buff[bi++] ='R';
1155  }
1156  if (key->flags & KEYF_EDIT)
1157  buff[bi++] ='E';
1158  if (key->flags & KEYF_STANDARD)
1159  buff[bi++] ='S';
1160 
1161  buff[bi]='\0';
1162 
1163  if(key->keysym != NoSymbol) {
1164  sprintf(buffer[0], "%i",count);
1165  sprintf(buffer[1], "%s", gdk_keyval_name(key->keysym));
1166  sprintf(buffer[2], "%i",i);
1167  sprintf(buffer[3], "%s",buff);
1168  sprintf(buffer[4], "%s", key->command);
1169  buffers[0] = buffer[0];
1170  buffers[1] = buffer[1];
1171  buffers[2] = buffer[2];
1172  buffers[3] = buffer[3];
1173  buffers[4] = buffer[4];
1174  tmprow = gtk_clist_append (GTK_CLIST (keylist), buffers);
1175  }
1176  count++;
1177  }
1178  }
1179 }
1180 
1181 void bind_callback (GtkWidget *gtklist, GdkEventButton *event) {
1182  KeySym keysym;
1183  const gchar *entry_text;
1184  const gchar *cpnext;
1185  const gchar *mod="";
1186  char buf[MAX_BUF];
1187 
1189 
1190  if ((bind_flags & KEYF_MODIFIERS)==KEYF_MODIFIERS) {
1191  bind_flags &= ~KEYF_MODIFIERS;
1192  mod=gtk_entry_get_text (GTK_ENTRY(cmodentrytext));
1193  if (!strcmp(mod, "F")) {
1194  bind_flags |= KEYF_FIRE;
1195  }
1196  else if (!strcmp(mod, "R")) {
1197  bind_flags |= KEYF_RUN;
1198  }
1199  else if (!strcmp(mod, "A")) {
1201  }
1202  }
1203  cpnext = gtk_entry_get_text (GTK_ENTRY(ckentrytext));
1204  entry_text = gtk_entry_get_text (GTK_ENTRY(ckeyentrytext));
1205 
1206  keysym = gdk_keyval_from_name(entry_text);
1207  insert_key(keysym, bind_flags, cpnext);
1208  save_keys();
1210  sprintf(buf, "Binded to key '%s' (%i)", gdk_keyval_name(keysym), 0);
1211  draw_info(buf,NDI_BLACK);
1212 }
1213 
1214 void ckeyunbind (GtkWidget *gtklist, GdkEventButton *event) {
1215  gchar *buf;
1216  GList *node;
1217  node = GTK_CLIST(cclist)->selection;
1218 
1219  if (node) {
1220  /* this line generates an warning about mismatched pointer sizes. Not sure
1221  * if there is any good fix for it.
1222  * In addition, this appears to be using unsupported logic -
1223  * proper programming logic should not be accessing the clist->selection
1224  * data directly. Better approach would probably be to catch the selection
1225  * in the clist, then store away what as selected.
1226  */
1227  gtk_clist_get_text (GTK_CLIST(cclist), (gint)node->data, 0, &buf);
1228  unbind_key(buf);
1230  }
1231 }
1232 
1233 void ckeyentry_callback (GtkWidget *widget, GdkEventKey *event, GtkWidget *window) {
1234  gtk_entry_set_text (GTK_ENTRY(ckeyentrytext), gdk_keyval_name(event->keyval));
1235 
1236  switch (event->state) {
1237  case GDK_CONTROL_MASK:
1238  gtk_entry_set_text (GTK_ENTRY(cmodentrytext), "R");
1239  break;
1240  case GDK_SHIFT_MASK:
1241  gtk_entry_set_text (GTK_ENTRY(cmodentrytext), "F");
1242  break;
1243  default:
1244  gtk_entry_set_text (GTK_ENTRY(cmodentrytext), "A");
1245  }
1246  /* gdk_keyval_name(event->keyval);*/
1247  gtk_signal_emit_stop_by_name (GTK_OBJECT(window), "key_press_event");
1248 }
1249 
1250 
1251 void ckeyclear (void) {
1252  gtk_label_set (GTK_LABEL(cnumentrytext), "0");
1253  gtk_entry_set_text (GTK_ENTRY(ckeyentrytext), "Press key to bind here");
1254  /* gtk_entry_set_text (GTK_ENTRY(cknumentrytext), ""); */
1255  gtk_entry_set_text (GTK_ENTRY(cmodentrytext), "");
1256  gtk_entry_set_text (GTK_ENTRY(ckentrytext), "");
1257 }
static void insert_key(uint32 keysym, int flags, const char *command)
Definition: keys.c:116
char * client_libdir
Definition: client.c:61
void ckeyclear(void)
Definition: keys.c:1251
struct Keys * next
Definition: image.c:104
static uint32 firekeysym[2]
Definition: keys.c:87
void init_keys(void)
Definition: keys.c:302
uint32 count
Definition: client.h:295
void bind_callback(GtkWidget *gtklist, GdkEventButton *event)
Definition: keys.c:1181
void unbind_key(const char *params)
Definition: keys.c:918
GtkWidget * gtkwin_info
Definition: gx11.c:278
#define CONFIG_POPUPS
Definition: client.h:160
static XEvent event
Definition: x11.c:193
void stop_fire(void)
Definition: player.c:116
void clear_fire(void)
Definition: player.c:134
#define CONFIG_ECHO
Definition: client.h:153
void gtk_command_history(int direction)
Definition: keys.c:1577
void run_dir(int dir)
Definition: player.c:172
snd_pcm_hw_params_t * params
Definition: alsa9.c:111
void clear_run(void)
Definition: player.c:142
static void parse_key_release(uint32 ks)
Definition: keys.c:407
int make_path_to_file(char *filename)
Definition: misc.c:94
static GtkWidget * fire_label
Definition: keys.c:65
const char *const rcsid_gtk_keys_c
Definition: keys.c:1
GtkWidget * ckeyentrytext
Definition: gx11.c:235
#define KEYF_FIRE
Definition: keys.c:93
static void configure_keys(uint32 keysym)
Definition: keys.c:855
void ckeyunbind(GtkWidget *gtklist, GdkEventButton *event)
Definition: keys.c:1214
static uint32 nextkeysym
Definition: keys.c:87
uint32 no_echo
Definition: client.h:294
#define KEYHASH
Definition: keys.c:106
#define KEYF_RUN
Definition: keys.c:94
const char *const directions[9]
Definition: player.c:48
int updatelock
Definition: gx11.c:310
void draw_keybindings(GtkWidget *keylist)
Definition: keys.c:1129
void LOG(LogLevel level, const char *origin, const char *format,...)
Definition: misc.c:178
#define NDI_RED
Definition: newclient.h:204
#define KEYF_STANDARD
Definition: keys.c:98
void gtk_complete_command(void)
Definition: keys.c:1617
gchar * text
Definition: about.h:2
static char * get_key_info(Key_Entry *key, int save_mode)
Definition: keys.c:544
GtkWidget * cclist
Definition: gx11.c:260
sint8 direction
Definition: image.c:101
void draw_message_window(int redraw)
Definition: gx11.c:2458
static uint32 * bind_keysym
Definition: keys.c:87
sint16 use_config[CONFIG_NUMS]
Definition: init.c:50
static void save_keys(void)
Definition: keys.c:788
#define KEYF_MODIFIERS
Definition: keys.c:95
void reset_map(void)
Definition: map.c:76
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: keys.c:781
char name[40]
Definition: client.h:306
GtkWidget * cnumentrytext
Definition: gx11.c:235
void extended_command(const char *ocommand)
Definition: p_cmd.c:890
GtkWidget * entrytext
Definition: gx11.c:270
GtkWidget * ckentrytext
Definition: gx11.c:235
static void unbind_usage(void)
Definition: keys.c:910
static uint32 cancelkeysym
Definition: keys.c:87
void send_reply(const char *text)
Definition: commands.c:769
uint32 run_on
Definition: client.h:291
struct Keys Key_Entry
#define KEYF_NORMAL
Definition: keys.c:92
char * command
Definition: image.c:103
uint32 fire_on
Definition: client.h:290
#define MAX_BUF
Definition: client-types.h:128
static void show_keys(int allbindings)
Definition: keys.c:599
static GtkWidget * run_label
Definition: keys.c:65
static int bind_flags
Definition: keys.c:89
unsigned int uint32
Definition: client-types.h:77
void stop_run(void)
Definition: player.c:166
#define BIG_BUF
Definition: client-types.h:129
char * buffers
Definition: cfsndserv.c:133
static uint32 commandkeysym
Definition: keys.c:87
static Key_Entry * keys[KEYHASH]
Definition: keys.c:107
char * strdup_local(const char *str)
Definition: misc.c:125
signed char sint8
Definition: client-types.h:82
void keyrelfunc(GtkWidget *widget, GdkEventKey *event, GtkWidget *window)
Definition: keys.c:994
uint32 keysym
Definition: keys.c:70
static uint32 completekeysym
Definition: keys.c:87
static void parse_keybind_line(char *buf, int line, int standard)
Definition: keys.c:156
void bind_key(const char *params)
Definition: keys.c:648
static void parse_key(char key, uint32 keysym)
Definition: keys.c:437
Input_State input_state
Definition: client.h:277
void ckeyentry_callback(GtkWidget *widget, GdkEventKey *event, GtkWidget *window)
Definition: keys.c:1233
static char bind_buf[MAX_BUF]
Definition: keys.c:90
void disconnect(GtkWidget *)
Definition: gx11.c:2773
void draw_info(const char *str, int color)
Definition: gx11.c:1773
static uint32 prevkeysym
Definition: keys.c:87
#define KEYF_EDIT
Definition: keys.c:97
uint8 flags
Definition: image.c:100
char input_text[MAX_BUF]
Definition: client.h:279
static void init_default_keybindings(void)
Definition: keys.c:285
unsigned char uint8
Definition: client-types.h:81
static uint32 runkeysym[2]
Definition: keys.c:87
#define NDI_BLACK
Definition: newclient.h:201
GtkWidget * cmodentrytext
Definition: gx11.c:235
#define FALSE
Definition: client-types.h:68
void keyfunc(GtkWidget *widget, GdkEventKey *event, GtkWidget *window)
Definition: keys.c:1008
#define CONFIG_SPLITWIN
Definition: client.h:166
KeySym keysym
Definition: image.c:102
void fire_dir(int dir)
Definition: player.c:151
Definition: image.c:99
GtkWidget * counttext
Definition: inventory.c:1072