Crossfire Client, Trunk
keys.c
Go to the documentation of this file.
1 /*
2  * Crossfire -- cooperative multi-player graphical RPG and adventure game
3  *
4  * Copyright (c) 1999-2013 Mark Wedel and the Crossfire Development Team
5  * Copyright (c) 1992 Frank Tore Johansen
6  *
7  * Crossfire is free software and comes with ABSOLUTELY NO WARRANTY. You are
8  * welcome to redistribute it under certain conditions. For details, see the
9  * 'LICENSE' and 'COPYING' files.
10  *
11  * The authors can be reached via e-mail to crossfire-devel@real-time.com
12  */
13 
20 #include "client.h"
21 
22 #include <gdk/gdkkeysyms.h>
23 #include <gtk/gtk.h>
24 
25 #ifndef WIN32
26 #include <gdk/gdkx.h>
27 #else
28 #include <gdk/gdkwin32.h>
29 #define NoSymbol 0L
30 typedef int KeyCode;
31 #endif
32 
33 #include "main.h"
34 #include "proto.h"
35 
36 #include "image.h"
37 #include "gtk2proto.h"
38 #include "p_cmd.h"
39 
40 const int COUNT_MAX = 10000000;
41 
42 struct keybind;
43 static int keybind_remove(struct keybind *entry);
44 static void keybind_free(struct keybind **entry);
45 
51 static GtkWidget *fire_label, *run_label, *keybinding_window,
60 
61 static GtkListStore *keybinding_store;
62 static GtkTreeSelection *keybinding_selection;
63 
64 GtkWidget *spinbutton_count;
65 GtkWidget *entry_commands;
75 enum {
78 };
87 #define MAX_HISTORY 50
88 #define MAX_COMMAND_LEN 256
90 
101 struct keybind {
102  guint8 flags;
103  gint8 direction;
104  guint32 keysym;
105  char *command;
106  struct keybind *next;
107 };
108 
109 
110 /***********************************************************************
111  *
112  * Key board input translations are handled here. We don't deal with
113  * the events, but rather KeyCodes and KeySyms.
114  *
115  * It would be nice to deal with only KeySyms, but many keyboards
116  * have keys that do not correspond to a KeySym, so we do need to
117  * support KeyCodes.
118  *
119  ***********************************************************************/
120 
124 
125 static int bind_flags = 0;
126 static char bind_buf[MAX_BUF];
127 
128 /*
129  * Key modifiers
130  *
131  * The Run, Fire, Alt and/or Meta keys can be used to qualify a key
132  * (i.e. a keybinding of the key 's' with the KEYF_RUN and KEYF_FIRE
133  * flags set will only match if both Run and Fire are held while 's' is
134  * pressed).
135  *
136  * If the user wants a key to match no matter the state of the modifier
137  * keys, the KEYF_ANY flag must be set in the binding.
138  */
139 
140 #define KEYF_MOD_SHIFT (1 << 0)
141 #define KEYF_MOD_CTRL (1 << 1)
142 #define KEYF_MOD_ALT (1 << 2)
143 #define KEYF_MOD_META (1 << 3)
144 #define KEYF_MOD_MASK (KEYF_MOD_SHIFT | \
145  KEYF_MOD_CTRL | \
146  KEYF_MOD_ALT | \
147  KEYF_MOD_META)
148 
149 #define KEYF_ANY (1 << 4)
150 #define KEYF_EDIT (1 << 5)
152 /* Keybinding's scope, decides where the binding will be saved */
153 #define KEYF_R_GLOBAL (1 << 6)
154 #define KEYF_R_CHAR (1 << 7)
156 extern const char *const directions[9];
157 
158 #define KEYHASH 257
159 
169 
175 #define EKEYBIND_NOMEM 1
176 
182 static bool debounce = false;
183 
200 static struct keybind *keybind_find(guint32 keysym, unsigned int flags,
201  int scope) {
202  struct keybind *kb;
203  kb = scope ? keys_global[keysym % KEYHASH] : keys_char[keysym % KEYHASH];
204  while (kb != NULL) {
205  if (kb->keysym == 0 || kb->keysym == keysym) {
206  if ((kb->flags & KEYF_ANY) || (flags & KEYF_ANY)) {
207  return kb;
208  }
209  if ((kb->flags & KEYF_MOD_MASK) == (flags & KEYF_MOD_MASK)) {
210  return kb;
211  }
212  }
213  kb = kb->next;
214  }
215 
216  return NULL;
217 }
218 
229 static int keybind_insert(guint32 keysym, unsigned int flags,
230  const char *command) {
231  struct keybind **next_ptr, *kb;
232  int slot;
233  int i;
234  int dir;
235 
237  while (kb != NULL) {
238  /*
239  * Keep the last binding instead of the first (backwards compatible).
240  *
241  * Also, if the new binding has the ANY flag, remove all matching
242  * previous bindings and keep this one.
243  */
244  LOG(LOG_DEBUG, "gtk-v2::keybind_insert",
245  "Overwriting previous binding for key %s with command %s ",
246  gdk_keyval_name(keysym), kb->command);
247  keybind_remove(kb);
248  keybind_free(&kb);
250  }
251 
252  slot = keysym % KEYHASH;
253 
254  next_ptr = (flags & KEYF_R_GLOBAL) ? &keys_global[slot] : &keys_char[slot];
255  while (*next_ptr) {
256  next_ptr = &(*next_ptr)->next;
257  }
258  *next_ptr = calloc(1, sizeof(**next_ptr));
259  if (*next_ptr == NULL) {
260  return -EKEYBIND_NOMEM;
261  }
262 
263  (*next_ptr)->keysym = keysym;
264  (*next_ptr)->flags = flags;
265  (*next_ptr)->command = g_strdup(command);
266 
267  /*
268  * Try to find out if the command is a direction command. If so, keep
269  * track of this fact, so in fire or run mode, things work correctly.
270  */
271  dir = -1;
272  for (i = 0; i < 9; i++) {
273  if (!strcmp(command, directions[i])) {
274  dir = i;
275  break;
276  }
277  }
278  (*next_ptr)->direction = dir;
279 
280  return 0;
281 }
282 
283 static int keybind_remove(struct keybind *entry) {
284  struct keybind **next_ptr;
285  int slot;
286 
287  slot = entry->keysym % KEYHASH;
288 
289  next_ptr = (entry->flags & KEYF_R_GLOBAL) ? &keys_global[slot] :
290  &keys_char[slot];
291  while (*next_ptr) {
292  if (*next_ptr == entry) {
293  *next_ptr = entry->next;
294  return 0;
295  }
296  next_ptr = &(*next_ptr)->next;
297  }
298 
299  /* No such key entry */
300  return -1;
301 }
302 
303 static void keybind_free(struct keybind **entry) {
304  free((*entry)->command);
305  (*entry)->command = NULL;
306  free(*entry);
307  *entry = NULL;
308 }
309 
317 static void parse_keybind_line(char *buf, int line, unsigned int scope_flag) {
318  char *cp, *cpnext;
319  guint32 keysym, low_keysym;
320  int flags;
321 
322  /*
323  * There may be a rare error case when cp is used uninitialized. So let's
324  * be safe
325  */
326  cp = NULL;
327 
328  if (buf[0] == '\0' || buf[0] == '#' || buf[0] == '\n') {
329  return;
330  }
331  cpnext = strchr(buf, ' ');
332  if (cpnext == NULL) {
333  LOG(LOG_WARNING, "gtk-v2::parse_keybind_line",
334  "Line %d (%s) corrupted in keybinding file.", line, buf);
335  return;
336  }
337  /* Special keybinding line */
338  if (buf[0] == '!') {
339  char *cp1;
340  while (*cpnext == ' ') {
341  ++cpnext;
342  }
343  cp = strchr(cpnext, ' ');
344  if (!cp) {
345  LOG(LOG_WARNING, "gtk-v2::parse_keybind_line",
346  "Line %d (%s) corrupted in keybinding file.", line, buf);
347  return;
348  }
349  *cp++ = 0; /* Null terminate it */
350  cp1 = strchr(cp, ' ');
351  if (!cp1) {
352  LOG(LOG_WARNING, "gtk-v2::parse_keybind_line",
353  "Line %d (%s) corrupted in keybinding file.", line, buf);
354  return;
355  }
356  *cp1++ = 0; /* Null terminate it */
357  keysym = gdk_keyval_from_name(cp);
358  /* As of now, all these keys must have keysyms */
359  if (keysym == 0) {
360  LOG(LOG_WARNING, "gtk-v2::parse_keybind_line",
361  "Could not convert %s into keysym", cp);
362  return;
363  }
364  if (!strcmp(cpnext, "commandkey")) {
366  return;
367  }
368  if (!strcmp(cpnext, "altkey0")) {
369  altkeysym[0] = keysym;
370  return;
371  }
372  if (!strcmp(cpnext, "altkey1")) {
373  altkeysym[1] = keysym;
374  return;
375  }
376  if (!strcmp(cpnext, "firekey0")) {
377  firekeysym[0] = keysym;
378  return;
379  }
380  if (!strcmp(cpnext, "firekey1")) {
381  firekeysym[1] = keysym;
382  return;
383  }
384  if (!strcmp(cpnext, "metakey0")) {
385  metakeysym[0] = keysym;
386  return;
387  }
388  if (!strcmp(cpnext, "metakey1")) {
389  metakeysym[1] = keysym;
390  return;
391  }
392  if (!strcmp(cpnext, "runkey0")) {
393  runkeysym[0] = keysym;
394  return;
395  }
396  if (!strcmp(cpnext, "runkey1")) {
397  runkeysym[1] = keysym;
398  return;
399  }
400  if (!strcmp(cpnext, "completekey")) {
402  return;
403  }
404  if (!strcmp(cpnext, "nextkey")) {
405  nextkeysym = keysym;
406  return;
407  }
408  if (!strcmp(cpnext, "prevkey")) {
409  prevkeysym = keysym;
410  return;
411  }
412  } else {
413  *cpnext++ = '\0';
414  keysym = gdk_keyval_from_name(buf);
415  if (!keysym) {
416  LOG(LOG_WARNING, "gtk-v2::parse_keybind_line",
417  "Unable to convert line %d (%s) into keysym", line, buf);
418  return;
419  }
420  cp = cpnext;
421  cpnext = strchr(cp, ' ');
422  if (cpnext == NULL) {
423  LOG(LOG_WARNING, "gtk-v2::parse_keybind_line",
424  "Line %d (%s) corrupted in keybinding file.", line, cp);
425  return;
426  }
427  *cpnext++ = '\0';
428 
429  cp = cpnext;
430  cpnext = strchr(cp, ' ');
431  if (cpnext == NULL) {
432  LOG(LOG_WARNING, "gtk-v2::parse_keybind_line",
433  "Line %d (%s) corrupted in keybinding file.", line, cp);
434  return;
435  }
436  *cpnext++ = '\0';
437 
438  flags = 0;
439  low_keysym = gdk_keyval_to_lower(keysym);
440  if (low_keysym != keysym) {
441  /* This binding is uppercase, switch to lowercase and flag the shift modifier */
443  keysym = low_keysym;
444  }
445  while (*cp != '\0') {
446  switch (*cp) {
447  case 'A':
448  flags |= KEYF_ANY;
449  break;
450  case 'E':
451  flags |= KEYF_EDIT;
452  break;
453  case 'F':
455  break;
456  case 'L': /* A is used, so using L for alt */
457  flags |= KEYF_MOD_ALT;
458  break;
459  case 'M':
460  flags |= KEYF_MOD_META;
461  break;
462  case 'N':
463  /* Nothing to do */
464  break;
465  case 'R':
466  flags |= KEYF_MOD_CTRL;
467  break;
468  case 'S':
469  LOG(LOG_WARNING, "gtk-v2::parse_keybind_line",
470  "Deprecated flag (S) ignored at line %d in key binding file", line);
471  break;
472  default:
473  LOG(LOG_WARNING, "gtk-v2::parse_keybind_line",
474  "Unknown flag (%c) line %d in key binding file",
475  *cp, line);
476  }
477  cp++;
478  }
479 
480  if (strlen(cpnext) > (sizeof(bind_buf) - 1)) {
481  cpnext[sizeof(bind_buf) - 1] = '\0';
482  LOG(LOG_WARNING, "gtk-v2::parse_keybind_line",
483  "Command too long! Truncated.");
484  }
485 
486  flags |= scope_flag; /* add the corresponding scope flag */
487 
488  // If there is a trailing CR, remove it.
489  cpnext[strcspn(cpnext, "\r")] = 0;
490 
491  keybind_insert(keysym, flags, cpnext);
492 
493  } /* else if not special binding line */
494 }
495 
504 static int parse_keys_file(GInputStream *in, unsigned int scope_flag) {
505  GDataInputStream *stream = g_data_input_stream_new(in);
506  int line_no = 0;
507  char *line;
508  while ((line = g_data_input_stream_read_line(stream, NULL, NULL, NULL)) != NULL) {
509  line_no++;
510  parse_keybind_line(line, line_no, scope_flag);
511  }
512 
513  return 0;
514 }
515 
520  LOG(LOG_DEBUG, "init_default_keybindings", "Loading default keybindings");
521  GInputStream *in = g_resources_open_stream("/org/crossfire/client/common/def-keys", 0, NULL);
522  if (in == NULL) {
523  g_error("could not load default keybindings");
524  }
526  g_object_unref(in);
527 }
528 
534 void keybindings_init(const char *character_name) {
535  char buf[BIG_BUF];
536  int i;
537 
538  /* Clear out the bind history. */
539  for (i = 0; i < MAX_HISTORY; i++) {
540  history[i][0] = 0;
541  }
542 
543  commandkeysym = GDK_KEY_apostrophe;
544  firekeysym[0] = GDK_KEY_Shift_L;
545  firekeysym[1] = GDK_KEY_Shift_R;
546  runkeysym[0] = GDK_KEY_Control_L;
547  runkeysym[1] = GDK_KEY_Control_R;
548  metakeysym[0] = GDK_KEY_Meta_L;
549  metakeysym[1] = GDK_KEY_Meta_R;
550  altkeysym[0] = GDK_KEY_Alt_L;
551  altkeysym[1] = GDK_KEY_Alt_R;
552 
553  completekeysym = GDK_KEY_Tab;
554  cancelkeysym = GDK_KEY_Escape;
555 
556  /*
557  * Don't set these to anything by default. At least on Sun keyboards, the
558  * keysym for up on both the keypad and arrow keys is the same, so player
559  * needs to rebind this so we get proper keycode. Very unfriendly to log
560  * in and not be able to move north/south.
561  */
562  nextkeysym = NoSymbol;
563  prevkeysym = NoSymbol;
564 
565  for (i = 0; i < KEYHASH; i++) {
566  while (keys_global[i]) {
568  }
569 
570  while (keys_char[i]) {
572  }
573  }
574 
575  /*
576  * If we were supplied with a character name, store it so that we
577  * can load and save a character-specific keys file.
578  */
579  if (cpl.name) {
580  free(cpl.name);
581  cpl.name = NULL;
582  }
583  if (character_name) {
584  cpl.name = g_strdup(character_name);
585  }
586 
587  /*
588  * We now try to load the keybindings. First load defaults.
589  * Then go through the more specific files in the home directory:
590  * 1) user wide "~/.crossfire/keys".
591  * 2) and, if character name is known, "~/.crossfire/<name>.keys"
592  *
593  * The format is described in the def_keys file. Note that this file is
594  * the same as what it was in the server distribution. To convert bindings
595  * in character files to this format, all that needs to be done is remove
596  * the 'key ' at the start of each line.
597  */
598 
600 
601  /* Try to load global keybindings. */
602  snprintf(buf, sizeof(buf), "%s/keys", config_dir);
603  GFile *f = g_file_new_for_path(buf);
604  GFileInputStream * fs = g_file_read(f, NULL, NULL);
605  if (fs != NULL) {
606  GInputStream *in = G_INPUT_STREAM(fs);
607  if (in != NULL) {
608  LOG(LOG_DEBUG, "keybindings_init", "Loading global keybindings");
610  g_object_unref(in);
611  }
612  g_object_unref(fs);
613  }
614  g_object_unref(f);
615 
616  /* Try to load the character-specific keybindings. */
617  if (cpl.name) {
618  snprintf(buf, sizeof(buf), "%s/%s.%s.keys", config_dir,
620  GFile *f = g_file_new_for_path(buf);
621  GFileInputStream * fs = g_file_read(f, NULL, NULL);
622  if (fs != NULL) {
623  GInputStream *in = G_INPUT_STREAM(fs);
624  if (in != NULL) {
625  LOG(LOG_DEBUG, "keybindings_init", "Loading character keybindings for '%s'", cpl.name);
627  g_object_unref(in);
628  }
629  g_object_unref(fs);
630  } else {
631  LOG(LOG_DEBUG, "keybindings_init", "No character keybindings for '%s' found", cpl.name);
632  }
633  g_object_unref(f);
634  } else {
635  LOG(LOG_DEBUG, "keybindings_init", "No character name");
636  }
637 }
638 
639 static void on_count_changed(GtkSpinButton *spinbutton, gpointer *data) {
640  cpl.count = gtk_spin_button_get_value_as_int(spinbutton);
641 }
642 
650 void keys_init(GtkWidget *window_root) {
651  GtkTreeViewColumn *column;
652  GtkCellRenderer *renderer;
653  GtkWidget *widget;
654  int i;
655 
656  fire_label = GTK_WIDGET(gtk_builder_get_object(window_xml, "fire_label"));
657  run_label = GTK_WIDGET(gtk_builder_get_object(window_xml, "run_label"));
658  entry_commands = GTK_WIDGET(gtk_builder_get_object(window_xml,
659  "entry_commands"));
660  spinbutton_count = GTK_WIDGET(gtk_builder_get_object(window_xml,
661  "spinbutton_count"));
662  g_signal_connect(spinbutton_count, "value-changed", G_CALLBACK(on_count_changed), NULL);
663 
664  g_signal_connect((gpointer) entry_commands, "activate",
665  G_CALLBACK(on_entry_commands_activate), NULL);
666 
667  keybinding_window = GTK_WIDGET(gtk_builder_get_object(dialog_xml,
668  "keybinding_window"));
669 
671  GTK_WIDGET(gtk_builder_get_object(dialog_xml, "kb_scope_togglebutton_global"));
673  GTK_WIDGET(gtk_builder_get_object(dialog_xml,
674  "kb_scope_togglebutton_character"));
676  GTK_WIDGET(gtk_builder_get_object(dialog_xml, "keybinding_checkbutton_any"));
678  GTK_WIDGET(gtk_builder_get_object(dialog_xml,
679  "keybinding_checkbutton_control"));
681  GTK_WIDGET(gtk_builder_get_object(dialog_xml, "keybinding_checkbutton_shift"));
683  GTK_WIDGET(gtk_builder_get_object(dialog_xml, "keybinding_checkbutton_alt"));
685  GTK_WIDGET(gtk_builder_get_object(dialog_xml, "keybinding_checkbutton_meta"));
687  GTK_WIDGET(gtk_builder_get_object(dialog_xml,
688  "keybinding_checkbutton_stayinedit"));
690  GTK_WIDGET(gtk_builder_get_object(dialog_xml, "keybinding_entry_key"));
692  GTK_WIDGET(gtk_builder_get_object(dialog_xml, "keybinding_entry_command"));
694  GTK_WIDGET(gtk_builder_get_object(dialog_xml, "keybinding_treeview"));
696  GTK_WIDGET(gtk_builder_get_object(dialog_xml, "keybinding_button_remove"));
698  GTK_WIDGET(gtk_builder_get_object(dialog_xml, "keybinding_button_update"));
700  GTK_WIDGET(gtk_builder_get_object(dialog_xml, "keybinding_button_bind"));
701 
702  g_signal_connect((gpointer) keybinding_window, "delete_event",
703  G_CALLBACK(gtk_widget_hide_on_delete), NULL);
704  g_signal_connect((gpointer) keybinding_entry_key, "key_press_event",
705  G_CALLBACK(on_keybinding_entry_key_key_press_event), NULL);
706  g_signal_connect((gpointer) keybinding_button_remove, "clicked",
707  G_CALLBACK(on_keybinding_button_remove_clicked), NULL);
708  g_signal_connect((gpointer) keybinding_button_update, "clicked",
709  G_CALLBACK(on_keybinding_button_update_clicked), NULL);
710  g_signal_connect((gpointer) keybinding_button_bind, "clicked",
711  G_CALLBACK(on_keybinding_button_bind_clicked), NULL);
712 
713  g_signal_connect((gpointer) kb_scope_togglebutton_character, "toggled",
715  g_signal_connect((gpointer) kb_scope_togglebutton_global, "toggled",
716  G_CALLBACK(on_kb_scope_togglebutton_global_toggled), NULL);
717 
718  g_signal_connect((gpointer) keybinding_checkbutton_any, "clicked",
719  G_CALLBACK(on_keybinding_checkbutton_any_clicked), NULL);
720 
721  widget = GTK_WIDGET(gtk_builder_get_object(dialog_xml,
722  "keybinding_button_clear"));
723  g_signal_connect((gpointer) widget, "clicked",
724  G_CALLBACK(on_keybinding_button_clear_clicked), NULL);
725 
726  widget = GTK_WIDGET(gtk_builder_get_object(dialog_xml,
727  "keybinding_button_close"));
728  g_signal_connect((gpointer) widget, "clicked",
729  G_CALLBACK(on_keybinding_button_close_clicked), NULL);
730 
731  gtk_widget_set_sensitive(keybinding_button_remove, FALSE);
732  gtk_widget_set_sensitive(keybinding_button_update, FALSE);
733  keybinding_store = gtk_list_store_new(7,
734  G_TYPE_INT,
735  G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING,
736  G_TYPE_POINTER
737  );
738  gtk_tree_view_set_model(GTK_TREE_VIEW(keybinding_treeview),
739  GTK_TREE_MODEL(keybinding_store));
740 
741  renderer = gtk_cell_renderer_text_new();
742  column = gtk_tree_view_column_new_with_attributes("Key", renderer,
743  "text", KLIST_KEY,
744  NULL);
745  gtk_tree_view_column_set_sort_column_id(column, KLIST_KEY);
746  gtk_tree_view_append_column(GTK_TREE_VIEW(keybinding_treeview), column);
747 
748  renderer = gtk_cell_renderer_text_new();
749  column = gtk_tree_view_column_new_with_attributes("Modifiers", renderer,
750  "text", KLIST_MODS,
751  NULL);
752  gtk_tree_view_column_set_sort_column_id(column, KLIST_MODS);
753  gtk_tree_view_append_column(GTK_TREE_VIEW(keybinding_treeview), column);
754 
755  renderer = gtk_cell_renderer_text_new();
756  column = gtk_tree_view_column_new_with_attributes("Scope", renderer,
757  "text", KLIST_SCOPE,
758  NULL);
759  gtk_tree_view_column_set_sort_column_id(column, KLIST_SCOPE);
760  gtk_tree_view_append_column(GTK_TREE_VIEW(keybinding_treeview), column);
761 
762  renderer = gtk_cell_renderer_text_new();
763  column = gtk_tree_view_column_new_with_attributes("Edit Mode", renderer,
764  "text", KLIST_EDIT,
765  NULL);
766  gtk_tree_view_column_set_sort_column_id(column, KLIST_EDIT);
767  gtk_tree_view_append_column(GTK_TREE_VIEW(keybinding_treeview), column);
768 
769  renderer = gtk_cell_renderer_text_new();
770  column = gtk_tree_view_column_new_with_attributes("Command", renderer,
771  "text", KLIST_COMMAND,
772  NULL);
773  gtk_tree_view_column_set_sort_column_id(column, KLIST_COMMAND);
774  gtk_tree_view_append_column(GTK_TREE_VIEW(keybinding_treeview), column);
775 
776 
777  keybinding_selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(
779  gtk_tree_selection_set_mode(keybinding_selection, GTK_SELECTION_BROWSE);
780  gtk_tree_selection_set_select_function(keybinding_selection,
781  keybinding_selection_func, NULL, NULL);
782 
783  gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(keybinding_store),
784  KLIST_KEY,
785  GTK_SORT_ASCENDING);
786 
787  for (i = 0; i < KEYHASH; i++) {
788  keys_global[i] = NULL;
789  keys_char[i] = NULL;
790  }
791 }
792 
805 static void parse_key_release(guint32 keysym) {
806 
807  /*
808  * Only send stop firing/running commands if we are in actual play mode.
809  * Something smart does need to be done when the character enters a non
810  * play mode with fire or run mode already set, however.
811  */
812  if (keysym == firekeysym[0] || keysym == firekeysym[1]) {
813  cpl.fire_on = 0;
814  clear_fire();
815  gtk_label_set_text(GTK_LABEL(fire_label), " ");
816  } else if (keysym == runkeysym[0] || keysym == runkeysym[1]) {
817  cpl.run_on = 0;
818  clear_run();
819  gtk_label_set_text(GTK_LABEL(run_label), " ");
820  } else if (keysym == altkeysym[0] || keysym == altkeysym[1]) {
821  cpl.alt_on = 0;
822  } else if (keysym == metakeysym[0] || keysym == metakeysym[1]) {
823  cpl.meta_on = 0;
824  }
825  /*
826  * Firing is handled on server side. However, to keep more like the old
827  * version, if you release the direction key, you want the firing to stop.
828  * This should do that.
829  */
830  else if (cpl.fire_on) {
831  clear_fire();
832  }
833 }
834 
841 static void parse_key(char key, guint32 keysym) {
842  struct keybind *kb;
843  int present_flags = 0;
844  char buf[MAX_BUF], tmpbuf[MAX_BUF];
845 
846  /* We handle the Shift key separately */
847  keysym = gdk_keyval_to_lower(keysym);
848 
849  if (keysym == commandkeysym) {
850  gtk_widget_grab_focus(GTK_WIDGET(entry_commands));
851  gtk_entry_set_visibility(GTK_ENTRY(entry_commands), 1);
853  cpl.no_echo = FALSE;
854  return;
855  }
856  if (keysym == altkeysym[0] || keysym == altkeysym[1]) {
857  cpl.alt_on = 1;
858  return;
859  }
860  if (keysym == metakeysym[0] || keysym == metakeysym[1]) {
861  cpl.meta_on = 1;
862  return;
863  }
864  if (keysym == firekeysym[0] || keysym == firekeysym[1]) {
865  cpl.fire_on = 1;
866  gtk_label_set_text(GTK_LABEL(fire_label), "Fire");
867  return;
868  }
869  if (keysym == runkeysym[0] || keysym == runkeysym[1]) {
870  cpl.run_on = 1;
871  gtk_label_set_text(GTK_LABEL(run_label), "Run");
872  return;
873  }
874 
875  present_flags = 0;
876  if (cpl.run_on) {
877  present_flags |= KEYF_MOD_CTRL;
878  }
879  if (cpl.fire_on) {
880  present_flags |= KEYF_MOD_SHIFT;
881  }
882  if (cpl.alt_on) {
883  present_flags |= KEYF_MOD_ALT;
884  }
885  if (cpl.meta_on) {
886  present_flags |= KEYF_MOD_META;
887  }
888 
889  const bool numkey = key >= '0' && key <= '9';
890 
891  kb = keybind_find(keysym, present_flags, 0); /* char scope */
892  if (kb == NULL) {
893  kb = keybind_find(keysym, present_flags, 1); /* global scope */
894  }
895  if (kb != NULL &&
896  // ignore number bindings if count is focused
897  !(numkey && gtk_widget_has_focus(GTK_WIDGET(spinbutton_count)))) {
898  if (kb->flags & KEYF_EDIT) {
899  strcpy(cpl.input_text, kb->command);
901  gtk_entry_set_text(GTK_ENTRY(entry_commands), cpl.input_text);
902  gtk_widget_grab_focus(GTK_WIDGET(entry_commands));
903  gtk_editable_select_region(GTK_EDITABLE(entry_commands), 0, 0);
904  gtk_editable_set_position(GTK_EDITABLE(entry_commands), -1);
905  return;
906  }
907 
908  if (kb->direction >= 0) {
909  if (cpl.fire_on) {
910  snprintf(buf, sizeof(buf), "fire %s", kb->command);
911  fire_dir(kb->direction);
912  return;
913  } else if (cpl.run_on) {
914  snprintf(buf, sizeof(buf), "run %s", kb->command);
915  run_dir(kb->direction);
916  return;
917  }
918  }
920  gtk_spin_button_set_value(GTK_SPIN_BUTTON(spinbutton_count), (float) cpl.count);
921  return;
922  }
923 
924  if (numkey) {
925  cpl.count = cpl.count * 10 + (key - '0');
926  if (cpl.count > COUNT_MAX) {
927  cpl.count %= COUNT_MAX;
928  }
929  gtk_spin_button_set_value(GTK_SPIN_BUTTON(spinbutton_count), (float) cpl.count);
930  return;
931  }
932  tmpbuf[0] = 0;
933  if (cpl.fire_on) {
934  strcat(tmpbuf, "fire+");
935  }
936  if (cpl.run_on) {
937  strcat(tmpbuf, "run+");
938  }
939  if (cpl.alt_on) {
940  strcat(tmpbuf, "alt+");
941  }
942  if (cpl.meta_on) {
943  strcat(tmpbuf, "meta+");
944  }
945 
946  snprintf(buf, sizeof(buf),
947  "Key %s%s is not bound to any command. Use 'bind' to associate this keypress with a command",
948  tmpbuf, keysym == NoSymbol ? "unknown" : gdk_keyval_name(keysym));
949 #ifdef WIN32
950  if ((65513 != keysym) && (65511 != keysym))
951 #endif
953  cpl.count = 0;
954 }
955 
956 static void get_key_modchars(struct keybind *kb, int save_mode, char *buf) {
957  int bi = 0;
958 
959  if (kb->flags & KEYF_ANY) {
960  buf[bi++] = 'A';
961  }
962  if (save_mode || !(kb->flags & KEYF_ANY)) {
963  if ((kb->flags & KEYF_MOD_MASK) == 0) {
964  buf[bi++] = 'N';
965  }
966  if (kb->flags & KEYF_MOD_SHIFT) {
967  buf[bi++] = 'F';
968  }
969  if (kb->flags & KEYF_MOD_CTRL) {
970  buf[bi++] = 'R';
971  }
972  if (kb->flags & KEYF_MOD_ALT) {
973  buf[bi++] = 'L';
974  }
975  if (kb->flags & KEYF_MOD_META) {
976  buf[bi++] = 'M';
977  }
978  }
979  if (kb->flags & KEYF_EDIT) {
980  buf[bi++] = 'E';
981  }
982 
983  buf[bi] = '\0';
984 }
985 
994 static char *get_key_info(struct keybind *kb, int save_mode) {
995  /* bind buf is the maximum space allowed for a
996  * bound command. We will add additional data to
997  * it so we increase its size by MAX_BUF*/
998  static char buf[MAX_BUF + sizeof(bind_buf)];
999 
1000  char buff[MAX_BUF];
1001 
1002  get_key_modchars(kb, save_mode, buff);
1003 
1004  if (save_mode) {
1005  if (kb->keysym == NoSymbol) {
1006  snprintf(buf, sizeof(buf), "(null) %i %s %s",
1007  0, buff, kb->command);
1008  } else {
1009  snprintf(buf, sizeof(buf), "%s %i %s %s",
1010  gdk_keyval_name(kb->keysym),
1011  0, buff, kb->command);
1012  }
1013  } else {
1014  if (kb->keysym == NoSymbol) {
1015  snprintf(buf, sizeof(buf), "key (null) %s %s",
1016  buff, kb->command);
1017  } else {
1018  snprintf(buf, sizeof(buf), "key %s %s %s",
1019  gdk_keyval_name(kb->keysym),
1020  buff, kb->command);
1021  }
1022  }
1023  return buf;
1024 }
1025 
1031 static void show_keys(void) {
1032  int i, j, count = 1;
1033  struct keybind *kb;
1034  char buf[MAX_BUF];
1035 
1036  snprintf(buf, sizeof(buf), "Commandkey %s",
1037  commandkeysym == NoSymbol ? "unknown" : gdk_keyval_name(commandkeysym));
1039 
1040  snprintf(buf, sizeof(buf), "Firekeys 1: %s, 2: %s",
1041  firekeysym[0] == NoSymbol ? "unknown" : gdk_keyval_name(firekeysym[0]),
1042  firekeysym[1] == NoSymbol ? "unknown" : gdk_keyval_name(firekeysym[1]));
1044 
1045  snprintf(buf, sizeof(buf), "Altkeys 1: %s, 2: %s",
1046  altkeysym[0] == NoSymbol ? "unknown" : gdk_keyval_name(altkeysym[0]),
1047  altkeysym[1] == NoSymbol ? "unknown" : gdk_keyval_name(altkeysym[1]));
1049 
1050  snprintf(buf, sizeof(buf), "Metakeys 1: %s, 2: %s",
1051  metakeysym[0] == NoSymbol ? "unknown" : gdk_keyval_name(metakeysym[0]),
1052  metakeysym[1] == NoSymbol ? "unknown" : gdk_keyval_name(metakeysym[1]));
1054 
1055  snprintf(buf, sizeof(buf), "Runkeys 1: %s, 2: %s",
1056  runkeysym[0] == NoSymbol ? "unknown" : gdk_keyval_name(runkeysym[0]),
1057  runkeysym[1] == NoSymbol ? "unknown" : gdk_keyval_name(runkeysym[1]));
1059 
1060  snprintf(buf, sizeof(buf), "Command Completion Key %s",
1061  completekeysym == NoSymbol ? "unknown" : gdk_keyval_name(completekeysym));
1063 
1064  snprintf(buf, sizeof(buf), "Next Command in History Key %s",
1065  nextkeysym == NoSymbol ? "unknown" : gdk_keyval_name(nextkeysym));
1067 
1068  snprintf(buf, sizeof(buf), "Previous Command in History Key %s",
1069  prevkeysym == NoSymbol ? "unknown" : gdk_keyval_name(prevkeysym));
1071 
1072  /*
1073  * Perhaps we should start at 8, so that we only show 'active' keybindings?
1074  */
1075  for (i = 0; i < KEYHASH; i++) {
1076  for (j = 0; j < 2; j++) {
1077  for (kb = (j == 0) ? keys_global[i] : keys_char[i]; kb != NULL; kb = kb->next) {
1078  snprintf(buf, sizeof(buf), "%3d %s", count, get_key_info(kb, 0));
1079  draw_ext_info(
1081  count++;
1082  }
1083  }
1084  }
1085 }
1086 
1095 void bind_key(char *params) {
1096  char buf[MAX_BUF + 16];
1097 
1098  if (!params) {
1100  "Usage: 'bind -ei {<commandline>,commandkey,firekey{1,2},runkey{1,2},altkey{1,2},metakey{1,2},completekey,nextkey,prevkey}'\n"
1101  "Where\n"
1102  " -e means enter edit mode\n"
1103  " -g means this binding should be global (used for all your characters)\n"
1104  " -i means ignore modifier keys (keybinding works no matter if Ctrl/Alt etc are held)");
1105  return;
1106  }
1107 
1108  /* Skip over any spaces we may have */
1109  while (*params == ' ') {
1110  params++;
1111  }
1112 
1113  if (!strcmp(params, "commandkey")) {
1116  "Push key to bind new commandkey.");
1118  return;
1119  }
1120 
1121  if (!strcmp(params, "firekey1")) {
1122  bind_keysym = &firekeysym[0];
1124  "Push key to bind new firekey 1.");
1126  return;
1127  }
1128  if (!strcmp(params, "firekey2")) {
1129  bind_keysym = &firekeysym[1];
1131  "Push key to bind new firekey 2.");
1133  return;
1134  }
1135  if (!strcmp(params, "metakey1")) {
1136  bind_keysym = &metakeysym[0];
1138  "Push key to bind new metakey 1.");
1140  return;
1141  }
1142  if (!strcmp(params, "metakey2")) {
1143  bind_keysym = &metakeysym[1];
1145  "Push key to bind new metakey 2.");
1147  return;
1148  }
1149  if (!strcmp(params, "altkey1")) {
1150  bind_keysym = &altkeysym[0];
1152  "Push key to bind new altkey 1.");
1154  return;
1155  }
1156  if (!strcmp(params, "altkey2")) {
1157  bind_keysym = &altkeysym[1];
1159  "Push key to bind new altkey 2.");
1161  return;
1162  }
1163  if (!strcmp(params, "runkey1")) {
1164  bind_keysym = &runkeysym[0];
1166  "Push key to bind new runkey 1.");
1168  return;
1169  }
1170 
1171  if (!strcmp(params, "runkey2")) {
1172  bind_keysym = &runkeysym[1];
1174  "Push key to bind new runkey 2.");
1176  return;
1177  }
1178 
1179  if (!strcmp(params, "completekey")) {
1182  "Push key to bind new command completion key");
1184  return;
1185  }
1186 
1187  if (!strcmp(params, "prevkey")) {
1190  "Push key to bind new previous command in history key.");
1192  return;
1193  }
1194 
1195  if (!strcmp(params, "nextkey")) {
1198  "Push key to bind new next command in history key.");
1200  return;
1201  }
1202  bind_keysym = NULL;
1203 
1204  bind_flags = 0;
1205  if (params[0] == '-') {
1206  for (params++; *params != ' '; params++)
1207  switch (*params) {
1208  case 'e':
1209  bind_flags |= KEYF_EDIT;
1210  break;
1211  case 'i':
1212  bind_flags |= KEYF_ANY;
1213  break;
1214  case 'g':
1216  break;
1217  case '\0':
1218  draw_ext_info(
1220  "Use unbind to remove bindings.");
1221  return;
1222  default:
1223  snprintf(buf, sizeof(buf),
1224  "Unsupported or invalid bind flag: '%c'", *params);
1226  return;
1227  }
1228  params++;
1229  }
1230 
1231  if (!params[0]) {
1233  "Use unbind to remove bindings.");
1234  return;
1235  }
1236 
1237  if (strlen(params) >= sizeof(bind_buf)) {
1238  params[sizeof(bind_buf) - 1] = '\0';
1240  "Keybinding too long! Truncated:");
1242  }
1243  snprintf(buf, sizeof(buf), "Push key to bind '%s'.", params);
1245 
1246  strcpy(bind_buf, params);
1248  return;
1249 }
1250 
1263 static void save_individual_key(FILE *fp, struct keybind *kb, KeyCode kc) {
1264  while (kb) {
1265  fprintf(fp, "%s\n", get_key_info(kb, 1));
1266  kb = kb->next;
1267  }
1268 }
1269 
1277 static void save_keys(void) {
1278  char buf[MAX_BUF], buf2[MAX_BUF];
1279  int i;
1280  FILE *fp;
1281 
1282  /* If we are logged in open file to save character specific bindings */
1283  if (cpl.name) {
1284  snprintf(buf, sizeof(buf), "%s/%s.%s.keys", config_dir,
1286  LOG(LOG_INFO, "gtk-v2::save_keys",
1287  "Saving character specific keybindings to %s", buf);
1288 
1289  if (make_path_to_file(buf) == -1) {
1290  LOG(LOG_WARNING, "gtk-v2::save_keys", "Could not create %s", buf);
1291  }
1292 
1293  fp = fopen(buf, "w");
1294  if (fp == NULL) {
1295  snprintf(buf2, sizeof(buf2),
1296  "Could not open %s, character bindings not saved\n", buf);
1298  } else {
1299  for (i = 0; i < KEYHASH; i++) {
1300  save_individual_key(fp, keys_char[i], 0);
1301  }
1302  fclose(fp);
1303  }
1304  }
1305 
1306  /* Open file to save global user bindings */
1307  snprintf(buf, sizeof(buf), "%s/keys", config_dir);
1308  LOG(LOG_INFO, "gtk-v2::save_keys",
1309  "Saving global user's keybindings to %s", buf);
1310 
1311  if (make_path_to_file(buf) == -1) {
1312  LOG(LOG_WARNING, "gtk-v2::save_keys", "Could not create %s", buf);
1313  } else {
1314  fp = fopen(buf, "w");
1315  if (fp == NULL) {
1316  snprintf(buf2, sizeof(buf2),
1317  "Could not open %s, global key bindings not saved\n", buf);
1319  } else {
1320  /* Save default bindings as part of the global scope */
1321  if (firekeysym[0] != GDK_KEY_Shift_L && firekeysym[0] != NoSymbol)
1322  fprintf(fp, "! firekey0 %s %d\n",
1323  gdk_keyval_name(firekeysym[0]), 0);
1324  if (firekeysym[1] != GDK_KEY_Shift_R && firekeysym[1] != NoSymbol)
1325  fprintf(fp, "! firekey1 %s %d\n",
1326  gdk_keyval_name(firekeysym[1]), 0);
1327  if (metakeysym[0] != GDK_KEY_Shift_L && metakeysym[0] != NoSymbol)
1328  fprintf(fp, "! metakey0 %s %d\n",
1329  gdk_keyval_name(metakeysym[0]), 0);
1330  if (metakeysym[1] != GDK_KEY_Shift_R && metakeysym[1] != NoSymbol)
1331  fprintf(fp, "! metakey1 %s %d\n",
1332  gdk_keyval_name(metakeysym[1]), 0);
1333  if (altkeysym[0] != GDK_KEY_Shift_L && altkeysym[0] != NoSymbol)
1334  fprintf(fp, "! altkey0 %s %d\n",
1335  gdk_keyval_name(altkeysym[0]), 0);
1336  if (altkeysym[1] != GDK_KEY_Shift_R && altkeysym[1] != NoSymbol)
1337  fprintf(fp, "! altkey1 %s %d\n",
1338  gdk_keyval_name(altkeysym[1]), 0);
1339  if (runkeysym[0] != GDK_KEY_Control_L && runkeysym[0] != NoSymbol)
1340  fprintf(fp, "! runkey0 %s %d\n",
1341  gdk_keyval_name(runkeysym[0]), 0);
1342  if (runkeysym[1] != GDK_KEY_Control_R && runkeysym[1] != NoSymbol)
1343  fprintf(fp, "! runkey1 %s %d\n",
1344  gdk_keyval_name(runkeysym[1]), 0);
1345  if (completekeysym != GDK_KEY_Tab && completekeysym != NoSymbol)
1346  fprintf(fp, "! completekey %s %d\n",
1347  gdk_keyval_name(completekeysym), 0);
1348  /* No defaults for these, so if it is set to anything, assume its valid */
1349  if (nextkeysym != NoSymbol)
1350  fprintf(fp, "! nextkey %s %d\n",
1351  gdk_keyval_name(nextkeysym), 0);
1352  if (prevkeysym != NoSymbol)
1353  fprintf(fp, "! prevkey %s %d\n",
1354  gdk_keyval_name(prevkeysym), 0);
1355 
1356  for (i = 0; i < KEYHASH; i++) {
1357  save_individual_key(fp, keys_global[i], 0);
1358  }
1359  fclose(fp);
1360  }
1361  }
1362 
1363  /* Should probably check return value on all writes to be sure, but... */
1365  "Key bindings saved.");
1366 }
1367 
1372 static void configure_keys(guint32 keysym) {
1373  char buf[MAX_BUF];
1374  struct keybind *kb;
1375 
1376  /* We handle the Shift key separately */
1377  keysym = gdk_keyval_to_lower(keysym);
1378 
1379  /*
1380  * I think that basically if we are not rebinding the special control keys
1381  * (in which case bind_keysym would be set to something) we just want to
1382  * handle these keypresses as normal events.
1383  */
1384  if (bind_keysym == NULL) {
1385  if (keysym == altkeysym[0] || keysym == altkeysym[1]) {
1386  cpl.alt_on = 1;
1387  return;
1388  }
1389  if (keysym == metakeysym[0] || keysym == metakeysym[1]) {
1390  cpl.meta_on = 1;
1391  return;
1392  }
1393  if (keysym == firekeysym[0] || keysym == firekeysym[1]) {
1394  cpl.fire_on = 1;
1396  return;
1397  }
1398  if (keysym == runkeysym[0] || keysym == runkeysym[1]) {
1399  cpl.run_on = 1;
1401  return;
1402  }
1403  }
1404 
1405  /*
1406  * Take shift/control keys into account when binding keys.
1407  */
1408  if (!(bind_flags & KEYF_ANY)) {
1409  if (cpl.fire_on) {
1411  }
1412  if (cpl.run_on) {
1414  }
1415  if (cpl.meta_on) {
1417  }
1418  if (cpl.alt_on) {
1420  }
1421  }
1422 
1423  /* Reset state now. We might return early if bind fails. */
1425 
1426  if (bind_keysym != NULL) {
1427  *bind_keysym = keysym;
1428  bind_keysym = NULL;
1429  } else {
1431  if (kb) {
1432  snprintf(buf, sizeof(buf),
1433  "Error: Key already used for command \"%s\". Use unbind first.",
1434  kb->command);
1435  draw_ext_info(
1437  return;
1438  } else {
1440  }
1441  }
1442 
1443  snprintf(buf, sizeof(buf), "Bound to key '%s' (%i)",
1444  keysym == NoSymbol ? "unknown" : gdk_keyval_name(keysym), keysym);
1447 
1448  /*
1449  * Do this each time a new key is bound. This way, we are never actually
1450  * storing any information that needs to be saved when the connection dies
1451  * or the player quits.
1452  */
1453  save_keys();
1454  return;
1455 }
1456 
1460 static void unbind_usage(void) {
1462  "Usage: 'unbind <entry_number>' or");
1464  "Usage: 'unbind' to show existing bindings");
1465 }
1466 
1471 void unbind_key(const char *params) {
1472  int count = 0, keyentry, slot, j;
1473  int res;
1474  struct keybind *kb;
1475  char buf[MAX_BUF];
1476 
1477  if (params == NULL) {
1478  show_keys();
1479  return;
1480  }
1481 
1482  /* Skip over any spaces we may have */
1483  while (*params == ' ') {
1484  params++;
1485  }
1486 
1487  if (params[0] == '\0') {
1488  show_keys();
1489  return;
1490  }
1491 
1492  if ((keyentry = atoi(params)) == 0) {
1493  unbind_usage();
1494  return;
1495  }
1496 
1497  for (slot = 0; slot < KEYHASH; slot++) {
1498  for (j = 0; j < 2; j++) {
1499  for (kb = (j == 0) ? keys_global[slot] : keys_char[slot]; kb != NULL;
1500  kb = kb->next) {
1501  count++;
1502 
1503  if (keyentry == count) {
1504  /* We found the key we want to unbind */
1505  snprintf(buf, sizeof(buf), "Removing binding: %3d %s",
1506  count, get_key_info(kb, 0));
1508  MSG_TYPE_CLIENT_CONFIG, buf);
1509  res = keybind_remove(kb);
1510  if (res < 0)
1511  LOG(LOG_ERROR, "gtk-v2::unbind_key",
1512  "found number entry, but could not find actual key");
1513  keybind_free(&kb);
1514  save_keys();
1515  return;
1516  }
1517  }
1518  }
1519  }
1520 
1521  /* Not found */
1522  /* Makes things look better to draw the blank line */
1525  "Not found. Try 'unbind' with no options to find entry.");
1526  return;
1527 }
1528 
1532 void focusoutfunc(GtkWidget *widget, GdkEventKey *event, GtkWidget *window) {
1533  if (cpl.fire_on == 1) {
1534  cpl.fire_on = 0;
1535  clear_fire();
1536  gtk_label_set_text(GTK_LABEL(fire_label), " ");
1537  }
1538  if (cpl.run_on == 1) {
1539  cpl.run_on = 0;
1540  clear_run();
1541  gtk_label_set_text(GTK_LABEL(run_label), " ");
1542  }
1543  if (cpl.alt_on == 1) {
1544  cpl.alt_on = 0;
1545  }
1546  if (cpl.meta_on == 1) {
1547  cpl.meta_on = 0;
1548  }
1549 }
1550 
1558 void keyrelfunc(GtkWidget *widget, GdkEventKey *event, GtkWidget *window) {
1559  if (event->keyval > 0 && !gtk_widget_has_focus(entry_commands)) {
1560  parse_key_release(event->keyval);
1561  debounce = false;
1562  }
1563  g_signal_stop_emission_by_name(GTK_WIDGET(window), "key_release_event");
1564 }
1565 
1573 void keyfunc(GtkWidget *widget, GdkEventKey *event, GtkWidget *window) {
1574  char *text;
1575 
1576  if (!use_config[CONFIG_POPUPS]) {
1577  if (((cpl.input_state == Reply_One) || (cpl.input_state == Reply_Many))
1578  && (event->keyval == cancelkeysym)) {
1579 
1580  /*
1581  * Player hit cancel button during input. Disconnect it (code from
1582  * menubar)
1583  */
1584 
1586 
1587  g_signal_stop_emission_by_name(
1588  GTK_WIDGET(window), "key_press_event");
1589  return;
1590  }
1591  if (cpl.input_state == Reply_One) {
1592  text = gdk_keyval_name(event->keyval);
1593  send_reply(text);
1595  g_signal_stop_emission_by_name(
1596  GTK_WIDGET(window), "key_press_event");
1597  return;
1598  } else if (cpl.input_state == Reply_Many) {
1599  if (gtk_widget_has_focus(entry_commands)) {
1600  gtk_widget_event(GTK_WIDGET(entry_commands), (GdkEvent *)event);
1601  } else {
1602  gtk_widget_grab_focus(GTK_WIDGET(entry_commands));
1603  }
1604  g_signal_stop_emission_by_name(
1605  GTK_WIDGET(window), "key_press_event");
1606  return;
1607  }
1608  }
1609  /*
1610  * Better check for really weirdo keys, X doesnt like keyval 0 so avoid
1611  * handling these key values.
1612  */
1613  if (event->keyval > 0) {
1614  if (gtk_widget_has_focus(entry_commands)) {
1615  if (event->keyval == completekeysym) {
1617  }
1618  if (event->keyval == prevkeysym || event->keyval == nextkeysym) {
1619  gtk_command_history(event->keyval == nextkeysym ? 0 : 1);
1620  } else {
1621  gtk_widget_event(GTK_WIDGET(entry_commands), (GdkEvent *)event);
1622  }
1623  } else {
1624  switch (cpl.input_state) {
1625  case Playing:
1626  /*
1627  * Specials - do command history - many times, the player
1628  * will want to go the previous command when nothing is
1629  * entered in the command window.
1630  */
1631  if ((event->keyval == prevkeysym)
1632  || (event->keyval == nextkeysym)) {
1633  gtk_command_history(event->keyval == nextkeysym ? 0 : 1);
1634  } else {
1635  if (cpl.run_on) {
1636  if (!(event->state & GDK_CONTROL_MASK)) {
1637  /* printf("Run is on while ctrl is not\n"); */
1638  gtk_label_set_text(GTK_LABEL(run_label), " ");
1639  cpl.run_on = 0;
1640  stop_run();
1641  }
1642  }
1643  if (cpl.fire_on) {
1644  if (!(event->state & GDK_SHIFT_MASK)) {
1645  /* printf("Fire is on while shift is not\n");*/
1646  gtk_label_set_text(GTK_LABEL(fire_label), " ");
1647  cpl.fire_on = 0;
1648  stop_fire();
1649  }
1650  }
1651 
1653  debounce = false;
1654  }
1655 
1656  if (!use_config[CONFIG_DEBOUNCE] || !debounce) {
1657  parse_key(event->string[0], event->keyval);
1658  debounce = true;
1659  }
1660  }
1661  break;
1662 
1663  case Configure_Keys:
1664  configure_keys(event->keyval);
1665  break;
1666 
1667  case Command_Mode:
1668  if (event->keyval == completekeysym) {
1670  }
1671  if ((event->keyval == prevkeysym)
1672  || (event->keyval == nextkeysym)) {
1673  gtk_command_history(event->keyval == nextkeysym ? 0 : 1);
1674  } else {
1675  gtk_widget_grab_focus(GTK_WIDGET(entry_commands));
1676  /*
1677  * When running in split windows mode, entry_commands
1678  * can't get focus because it is in a different
1679  * window. So we have to pass the event to it
1680  * explicitly.
1681  */
1682  if (gtk_widget_has_focus(entry_commands) == 0)
1683  gtk_widget_event(
1684  GTK_WIDGET(entry_commands), (GdkEvent *)event);
1685  }
1686  /*
1687  * Don't pass signal along to default handlers -
1688  * otherwise, we get get crashes in the clist area (gtk
1689  * fault I believe)
1690  */
1691  break;
1692 
1693  case Metaserver_Select:
1694  gtk_widget_grab_focus(GTK_WIDGET(entry_commands));
1695  break;
1696 
1697  default:
1698  LOG(LOG_ERROR, "gtk-v2::keyfunc",
1699  "Unknown input state: %d", cpl.input_state);
1700  }
1701  }
1702  }
1703  g_signal_stop_emission_by_name(
1704  GTK_WIDGET(window), "key_press_event");
1705 }
1706 
1710 void x_set_echo(void) {
1711  gtk_entry_set_visibility(GTK_ENTRY(entry_commands), !cpl.no_echo);
1712 }
1713 
1719 void draw_prompt(const char *str) {
1721  gtk_widget_grab_focus(GTK_WIDGET(entry_commands));
1722 }
1723 
1730  int i = scroll_history_position;
1731  if (direction) {
1732  i--;
1733  if (i < 0) {
1734  i += MAX_HISTORY;
1735  }
1736  if (i == cur_history_position) {
1737  return;
1738  }
1739  } else {
1740  i++;
1741  if (i >= MAX_HISTORY) {
1742  i = 0;
1743  }
1744  if (i == cur_history_position) {
1745  /*
1746  * User has forwarded to what should be current entry - reset it
1747  * now.
1748  */
1749  gtk_entry_set_text(GTK_ENTRY(entry_commands), "");
1750  gtk_editable_set_position(GTK_EDITABLE(entry_commands), 0);
1752  return;
1753  }
1754  }
1755 
1756  if (history[i][0] == 0) {
1757  return;
1758  }
1759 
1761  /* fprintf(stderr, "resetting postion to %d, data = %s\n", i, history[i]);*/
1762  gtk_entry_set_text(GTK_ENTRY(entry_commands), history[i]);
1763  gtk_widget_grab_focus(GTK_WIDGET(entry_commands));
1764  gtk_editable_select_region(GTK_EDITABLE(entry_commands), 0, 0);
1765  gtk_editable_set_position(GTK_EDITABLE(entry_commands), -1);
1766 
1768 }
1769 
1777  const gchar *entry_text, *newcommand;
1778 
1779  entry_text = gtk_entry_get_text(GTK_ENTRY(entry_commands));
1780  newcommand = complete_command(entry_text);
1781  /* value differ, so update window */
1782  if (newcommand != NULL) {
1783  gtk_entry_set_text(GTK_ENTRY(entry_commands), newcommand);
1784  gtk_widget_grab_focus(GTK_WIDGET(entry_commands));
1785  gtk_editable_select_region(GTK_EDITABLE(entry_commands), 0, 0);
1786  gtk_editable_set_position(GTK_EDITABLE(entry_commands), -1);
1787  }
1788 }
1789 
1797 void on_entry_commands_activate(GtkEntry *entry, gpointer user_data) {
1798  const gchar *entry_text;
1799  extern GtkWidget *treeview_look;
1800 
1801  /* Next reply will reset this as necessary */
1802  if (!use_config[CONFIG_POPUPS]) {
1803  gtk_entry_set_visibility(GTK_ENTRY(entry), TRUE);
1804  }
1805 
1806  entry_text = gtk_entry_get_text(GTK_ENTRY(entry));
1807 
1809  strcpy(cpl.input_text, entry_text);
1810  } else if (cpl.input_state == Reply_One || cpl.input_state == Reply_Many) {
1812  strcpy(cpl.input_text, entry_text);
1813  if (cpl.input_state == Reply_One) {
1814  cpl.input_text[1] = 0;
1815  }
1816 
1818 
1819  } else {
1821  /* No reason to do anything for a null string */
1822  if (entry_text[0] != 0) {
1823  strncpy(history[cur_history_position], entry_text, MAX_COMMAND_LEN);
1828  extended_command(entry_text);
1829  gtk_spin_button_set_value(GTK_SPIN_BUTTON(spinbutton_count), (float) cpl.count);
1830  }
1831  }
1832  gtk_entry_set_text(GTK_ENTRY(entry), "");
1833 
1834  /*
1835  * This grab focus is really just so the entry box doesn't have focus -
1836  * this way, keypresses are used to play the game, and not as stuff that
1837  * goes into the entry box. It doesn't make much difference what widget
1838  * this is set to, as long as it is something that can get focus.
1839  */
1840  gtk_widget_grab_focus(GTK_WIDGET(treeview_look));
1841 
1844  /*
1845  * This is the gtk_main that is started up by get_metaserver The client
1846  * will start another one once it is connected to a crossfire server
1847  */
1848  gtk_main_quit();
1849  }
1850 }
1851 
1865  int i, j;
1866  struct keybind *kb;
1867  char *modifier_label, *scope_label;
1868  GtkTreeIter iter;
1869 
1870  gtk_list_store_clear(keybinding_store);
1871  for (i = 0; i < KEYHASH; i++) {
1872  for (j = 0; j < 2; j++) {
1873  for (kb = (j == 0) ? keys_global[i] : keys_char[i]; kb != NULL; kb = kb->next) {
1874  if (j == 0) {
1875  kb->flags |= KEYF_R_GLOBAL;
1876  } else {
1877  kb->flags |= KEYF_R_CHAR;
1878  }
1879 
1880  if (kb->flags & KEYF_ANY) {
1881  modifier_label = "Any";
1882  } else if ((kb->flags & KEYF_MOD_MASK) == 0) {
1883  modifier_label = "None";
1884  } else {
1885  if (kb->flags & KEYF_MOD_ALT) {
1886  modifier_label = "Alt";
1887  if (kb->flags & (KEYF_MOD_SHIFT | KEYF_MOD_CTRL | KEYF_MOD_META)) {
1888  modifier_label = " + ";
1889  }
1890  }
1891  if (kb->flags & KEYF_MOD_SHIFT) {
1892  modifier_label = "Fire";
1893  if (kb->flags & (KEYF_MOD_CTRL | KEYF_MOD_META)) {
1894  modifier_label = " + ";
1895  }
1896  }
1897  if (kb->flags & KEYF_MOD_CTRL) {
1898  modifier_label = "Run";
1899  if (kb->flags & KEYF_MOD_META) {
1900  modifier_label = " + ";
1901  }
1902  }
1903  if (kb->flags & KEYF_MOD_META) {
1904  modifier_label = "Meta";
1905  }
1906  }
1907  if (!(kb->flags & KEYF_R_GLOBAL)) {
1908  scope_label = "char";
1909  } else {
1910  scope_label = "global";
1911  }
1912  gtk_list_store_append(keybinding_store, &iter);
1913  gtk_list_store_set(keybinding_store, &iter,
1914  KLIST_ENTRY, i,
1915  KLIST_KEY, gdk_keyval_name(kb->keysym),
1916  KLIST_MODS, modifier_label,
1917  KLIST_SCOPE, scope_label,
1918  KLIST_EDIT, (kb->flags & KEYF_EDIT) ? "Yes" : "No",
1919  KLIST_COMMAND, kb->command,
1920  KLIST_KEY_ENTRY, kb,
1921  -1);
1922  }
1923  }
1924  }
1926 }
1927 
1934 void on_keybindings_activate(GtkMenuItem *menuitem, gpointer user_data) {
1935  gtk_widget_show(keybinding_window);
1937 }
1938 
1951 gboolean
1953  GdkEventKey *event,
1954  gpointer user_data) {
1955  gtk_entry_set_text(
1956  GTK_ENTRY(keybinding_entry_key), gdk_keyval_name(event->keyval));
1957  /*
1958  * This code is basically taken from the GTKv1 client. However, at some
1959  * level it is broken, since the control/shift/etc masks are hardcoded, yet
1960  * we do let the users redefine them.
1961  *
1962  * The clearing of the modifiers is disabled. In my basic testing, I
1963  * checked the modifiers and then pressed the key - have those modifiers go
1964  * away I think is less intuitive.
1965  */
1966  if (event->state & GDK_CONTROL_MASK)
1967  gtk_toggle_button_set_active(
1968  GTK_TOGGLE_BUTTON(keybinding_checkbutton_control), TRUE);
1969 
1970 #if 0
1971  else
1972  gtk_toggle_button_set_active(
1973  GTK_TOGGLE_BUTTON(keybinding_checkbutton_control), FALSE);
1974 #endif
1975 
1976  if (event->state & GDK_SHIFT_MASK)
1977  gtk_toggle_button_set_active(
1978  GTK_TOGGLE_BUTTON(keybinding_checkbutton_shift), TRUE);
1979 
1980 #if 0
1981  else {
1982  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(keybinding_checkbutton_shift),
1983  FALSE);
1984  }
1985 
1986  /* The GDK_MOD_MASK* will likely correspond to alt and meta, yet there is
1987  * no way to be sure what goes to what, so easiest to just not allow them.
1988  */
1989  gtk_toggle_button_set_active(
1990  GTK_TOGGLE_BUTTON(keybinding_checkbutton_alt), FALSE);
1991  gtk_toggle_button_set_active(
1992  GTK_TOGGLE_BUTTON(keybinding_checkbutton_meta), FALSE);
1993 #endif
1994 
1995  /* Returning TRUE prevents widget from getting this event */
1996  return TRUE;
1997 }
1998 
2005 void toggle_buttons_scope(int scope) {
2006  int state_u, state_c;
2007 
2008  state_u = gtk_toggle_button_get_active(
2009  GTK_TOGGLE_BUTTON(kb_scope_togglebutton_global));
2010  state_c = gtk_toggle_button_get_active(
2011  GTK_TOGGLE_BUTTON(kb_scope_togglebutton_character));
2012  /* If the states of the buttons are not already what we are asked for, or if
2013  * they are equal (which is inconsistent) then update them. Deactivate the
2014  * callbacks for the "toggled" events temporarily to avoid an infinite loop.
2015  */
2016  if (state_u != scope || state_u == state_c) {
2017  g_signal_handlers_block_by_func(
2018  GTK_TOGGLE_BUTTON(kb_scope_togglebutton_character),
2019  G_CALLBACK(on_kb_scope_togglebutton_character_toggled), NULL);
2020  g_signal_handlers_block_by_func(
2021  GTK_TOGGLE_BUTTON(kb_scope_togglebutton_global),
2022  G_CALLBACK(on_kb_scope_togglebutton_global_toggled), NULL);
2023 
2024  gtk_toggle_button_set_active(
2025  GTK_TOGGLE_BUTTON(kb_scope_togglebutton_character), !scope);
2026  gtk_toggle_button_set_active(
2027  GTK_TOGGLE_BUTTON(kb_scope_togglebutton_global), scope);
2028 
2029  g_signal_handlers_unblock_by_func(
2030  GTK_TOGGLE_BUTTON(kb_scope_togglebutton_character),
2031  G_CALLBACK(on_kb_scope_togglebutton_character_toggled), NULL);
2032  g_signal_handlers_unblock_by_func(
2033  GTK_TOGGLE_BUTTON(kb_scope_togglebutton_global),
2034  G_CALLBACK(on_kb_scope_togglebutton_global_toggled), NULL);
2035  }
2036 }
2037 
2045 static int keybind_overwrite_confirm(struct keybind *kb) {
2046  GtkWidget *dialog, *label;
2047  int result;
2048  char buf[MAX_BUF], buf2[MAX_BUF];
2049 
2050  dialog = gtk_dialog_new_with_buttons(
2051  "Key already in use",
2052  GTK_WINDOW(keybinding_window),
2053  GTK_DIALOG_MODAL,
2054  GTK_STOCK_YES, 1,
2055  GTK_STOCK_NO, 2,
2056  NULL);
2057  get_key_modchars(kb, 1, buf2);
2058  snprintf(buf, sizeof(buf), "Overwrite this binding?\n (%s) %s\n%s",
2059  buf2, gdk_keyval_name(kb->keysym), kb->command);
2060  label = gtk_label_new(buf);
2061  gtk_box_pack_start(
2062  GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))),
2063  label, TRUE, TRUE, 0);
2064  gtk_widget_show_all(dialog);
2065 
2066  result = gtk_dialog_run(GTK_DIALOG(dialog));
2067  gtk_widget_destroy(dialog);
2068  return (result == 1);
2069 }
2070 
2080 void toggle_keybind_scope(int scope, struct keybind *kb) {
2081  struct keybind *kb_old, **next_ptr;
2082  int ret, flags;
2083  char buf[MAX_BUF];
2084 
2085  /* First check for matching bindings in the new scope */
2086  kb_old = keybind_find(kb->keysym, kb->flags, scope);
2087  while (kb_old) {
2088  if (!keybind_overwrite_confirm(kb_old)) {
2089  /* Restore all bindings and buttons state.
2090  * Need to call keybindings_init() because we may have already
2091  * removed some bindings from memory */
2092  toggle_buttons_scope(!scope);
2095  return;
2096  }
2097  /* Completely remove the old binding */
2098  keybind_remove(kb_old);
2099  keybind_free(&kb_old);
2100  kb_old = keybind_find(kb->keysym, kb->flags, scope);
2101  }
2102 
2103  /* If the new scope is 'global' we remove the binding from keys_char (don't
2104  * free it), switch scope flags and rehash in keys_global.
2105  *
2106  * Else just make a copy into keys_char only switching the state flags.
2107  */
2108  if (scope) {
2109  if ((kb->flags & KEYF_R_GLOBAL) == 0) {
2110  /* Remove kb from keys_char, don't free it. */
2111  ret = keybind_remove(kb);
2112  if (ret == -1) {
2114  "\nCould not remove keybind. Operation failed.\n");
2115  toggle_buttons_scope(!scope);
2118  return;
2119  }
2120  /* Place the modified kb in keys_global */
2121  kb->flags ^= KEYF_R_CHAR;
2122  kb->flags |= KEYF_R_GLOBAL;
2123  next_ptr = &keys_global[kb->keysym % KEYHASH];
2124  kb->next = NULL;
2125 
2126  if (*next_ptr) {
2127  while ((*next_ptr)->next) {
2128  next_ptr = &(*next_ptr)->next;
2129  }
2130  (*next_ptr)->next = kb;
2131  } else {
2132  keys_global[kb->keysym % KEYHASH] = kb;
2133  }
2134  }
2135  } else {
2136  if ((kb->flags & KEYF_R_GLOBAL) != 0) {
2137  /* Copy the selected binding in the char's scope with the right flags. */
2138  snprintf(buf, sizeof(buf), "%s", kb->command);
2139  flags = kb->flags;
2140  flags |= KEYF_R_CHAR;
2141  flags ^= KEYF_R_GLOBAL;
2142  keybind_insert(kb->keysym, flags, buf);
2143  }
2144  }
2145  save_keys();
2147 }
2148 
2156 void on_kb_scope_togglebutton_character_toggled(GtkToggleButton *toggle_button,
2157  gpointer user_data) {
2158  GtkTreeModel *model;
2159  GtkTreeIter iter;
2160  struct keybind *kb;
2161  gboolean scope;
2162  if (gtk_tree_selection_get_selected(keybinding_selection, &model, &iter)) {
2163  gtk_tree_model_get(model, &iter, KLIST_KEY_ENTRY, &kb, -1);
2164  scope = !gtk_toggle_button_get_active(
2165  GTK_TOGGLE_BUTTON(kb_scope_togglebutton_character));
2166  toggle_buttons_scope(scope);
2167  toggle_keybind_scope(scope, kb);
2168  }
2169 }
2170 
2178 void on_kb_scope_togglebutton_global_toggled(GtkToggleButton *toggle_button,
2179  gpointer user_data) {
2180  GtkTreeModel *model;
2181  GtkTreeIter iter;
2182  struct keybind *kb;
2183  gboolean scope;
2184  if (gtk_tree_selection_get_selected(keybinding_selection, &model, &iter)) {
2185  gtk_tree_model_get(model, &iter, KLIST_KEY_ENTRY, &kb, -1);
2186  scope = gtk_toggle_button_get_active(
2187  GTK_TOGGLE_BUTTON(kb_scope_togglebutton_global));
2188  toggle_buttons_scope(scope);
2189  toggle_keybind_scope(scope, kb);
2190  }
2191 }
2192 
2201  gpointer user_data) {
2202  GtkTreeModel *model;
2203  GtkTreeIter iter;
2204  struct keybind *kb;
2205  int res;
2206 
2207  if (!gtk_tree_selection_get_selected(keybinding_selection, &model, &iter)) {
2208  LOG(LOG_ERROR, "keys.c::on_keybinding_button_remove_clicked",
2209  "Function called with nothing selected\n");
2210  return;
2211  }
2212  gtk_tree_model_get(model, &iter, KLIST_KEY_ENTRY, &kb, -1);
2213  res = keybind_remove(kb);
2214  if (res < 0)
2215  LOG(LOG_ERROR, "keys.c::on_keybinding_button_remove_clicked",
2216  "Unable to find matching key entry\n");
2217  keybind_free(&kb);
2218 
2219  save_keys();
2221 }
2222 
2232 static void keybinding_get_data(guint32 *keysym, guint8 *flags,
2233  const char **command) {
2234  static char bind_buf[MAX_BUF];
2235  const char *ed;
2236  *flags = 0;
2237 
2238  if (gtk_toggle_button_get_active(
2239  GTK_TOGGLE_BUTTON(keybinding_checkbutton_any))) {
2240  *flags |= KEYF_ANY;
2241  }
2242 
2243  if (gtk_toggle_button_get_active(
2244  GTK_TOGGLE_BUTTON(kb_scope_togglebutton_global))) {
2245  *flags |= KEYF_R_GLOBAL;
2246  }
2247 
2248  if (gtk_toggle_button_get_active(
2249  GTK_TOGGLE_BUTTON(keybinding_checkbutton_control))) {
2250  *flags |= KEYF_MOD_CTRL;
2251  }
2252  if (gtk_toggle_button_get_active(
2253  GTK_TOGGLE_BUTTON(keybinding_checkbutton_shift))) {
2254  *flags |= KEYF_MOD_SHIFT;
2255  }
2256  if (gtk_toggle_button_get_active(
2257  GTK_TOGGLE_BUTTON(keybinding_checkbutton_alt))) {
2258  *flags |= KEYF_MOD_ALT;
2259  }
2260  if (gtk_toggle_button_get_active(
2261  GTK_TOGGLE_BUTTON(keybinding_checkbutton_meta))) {
2262  *flags |= KEYF_MOD_META;
2263  }
2264  if (gtk_toggle_button_get_active(
2265  GTK_TOGGLE_BUTTON(keybinding_checkbutton_edit))) {
2266  *flags |= KEYF_EDIT;
2267  }
2268 
2269  ed = gtk_entry_get_text(GTK_ENTRY(keybinding_entry_command));
2270  if (strlen(ed) >= sizeof(bind_buf)) {
2272  "Keybinding too long! Truncated.");
2273  strncpy(bind_buf, ed, MAX_BUF - 1);
2274  bind_buf[MAX_BUF - 1] = 0;
2275  *command = bind_buf;
2276  } else {
2277  *command = ed;
2278  }
2279 
2280  /*
2281  * This isn't ideal - when the key is pressed, we convert it to a string,
2282  * and now we are converting it back. It'd be nice to tuck the keysym
2283  * itself away someplace.
2284  */
2285  *keysym = gdk_keyval_from_name(
2286  gtk_entry_get_text(GTK_ENTRY(keybinding_entry_key)));
2287  if (*keysym == GDK_KEY_VoidSymbol) {
2288  LOG(LOG_ERROR, "keys.c::keybinding_get_data",
2289  "Cannot get valid keysym from selection");
2290  }
2291 }
2292 
2299 void on_keybinding_button_bind_clicked(GtkButton *button, gpointer user_data) {
2300  guint32 keysym;
2301  guint8 flags;
2302  const char *command;
2303  struct keybind *kb;
2304 
2306 
2307  /* keybind_insert will do a g_strdup of command for us */
2309  if (kb && (!keybind_overwrite_confirm(kb))) {
2310  return;
2311  }
2313 
2314  /*
2315  * I think it is more appropriate to clear the fields once the user adds
2316  * it. I suppose the ideal case would be to select the newly inserted
2317  * keybinding.
2318  */
2320  save_keys();
2322 }
2323 
2334  gpointer user_data) {
2335  GtkTreeIter iter;
2336  struct keybind *kb;
2337  GtkTreeModel *model;
2338  guint32 keysym;
2339  guint8 flags;
2340  const char *buf;
2341  int res;
2342 
2343  if (gtk_tree_selection_get_selected(keybinding_selection, &model, &iter)) {
2344  gtk_tree_model_get(model, &iter, KLIST_KEY_ENTRY, &kb, -1);
2345 
2346  if (!kb) {
2347  LOG(LOG_ERROR, "keys.c::on_keybinding_button_update_clicked",
2348  "Unable to get key_entry structure\n");
2349  return;
2350  }
2351 
2352  /* We need to rehash the binding (remove the old and add the
2353  * new) since the keysym might have changed. */
2354 
2355  keybind_remove(kb);
2356 
2357  keybinding_get_data(&keysym, &flags, &buf);
2358 
2359  res = keybind_insert(keysym, flags, buf);
2360  if (res == 0) {
2361  keybind_free(&kb);
2362  } else {
2363  /* Re-enter old binding if the update failed */
2364  keybind_insert(kb->keysym, kb->flags, kb->command);
2365  // FIXME: Popup dialog key in use
2366  }
2367 
2368  save_keys();
2370  } else {
2371  LOG(LOG_ERROR, "keys.c::on_keybinding_button_update_clicked",
2372  "Nothing selected to update\n");
2373  }
2374 }
2375 
2382 void on_keybinding_button_close_clicked(GtkButton *button, gpointer user_data) {
2383  gtk_widget_hide(keybinding_window);
2384 }
2385 
2393  gpointer user_data) {
2394  gboolean enabled;
2395 
2396  enabled = !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cb));
2397 
2398  gtk_widget_set_sensitive(GTK_WIDGET(keybinding_checkbutton_control), enabled);
2399  gtk_widget_set_sensitive(GTK_WIDGET(keybinding_checkbutton_shift), enabled);
2400  gtk_widget_set_sensitive(GTK_WIDGET(keybinding_checkbutton_alt), enabled);
2401  gtk_widget_set_sensitive(GTK_WIDGET(keybinding_checkbutton_meta), enabled);
2402 }
2403 
2417  GtkTreeSelection *selection,
2418  GtkTreeModel *model,
2419  GtkTreePath *path,
2420  gboolean path_currently_selected,
2421  gpointer userdata) {
2422  GtkTreeIter iter;
2423  struct keybind *kb;
2424 
2425  gtk_widget_set_sensitive(keybinding_button_remove, TRUE);
2426  gtk_widget_set_sensitive(keybinding_button_update, TRUE);
2427 
2428  if (gtk_tree_model_get_iter(model, &iter, path)) {
2429 
2430  gtk_tree_model_get(model, &iter, KLIST_KEY_ENTRY, &kb, -1);
2431 
2432  if (!kb) {
2433  LOG(LOG_ERROR, "keys.c::keybinding_selection_func",
2434  "Unable to get key_entry structure\n");
2435  return FALSE;
2436  }
2437  if (kb->flags & KEYF_ANY)
2438  gtk_toggle_button_set_active(
2439  GTK_TOGGLE_BUTTON(keybinding_checkbutton_any), TRUE);
2440  else
2441  gtk_toggle_button_set_active(
2442  GTK_TOGGLE_BUTTON(keybinding_checkbutton_any), FALSE);
2443 
2444  if (kb->flags & KEYF_MOD_CTRL)
2445  gtk_toggle_button_set_active(
2446  GTK_TOGGLE_BUTTON(keybinding_checkbutton_control), TRUE);
2447  else
2448  gtk_toggle_button_set_active(
2449  GTK_TOGGLE_BUTTON(keybinding_checkbutton_control), FALSE);
2450 
2451  if (kb->flags & KEYF_MOD_SHIFT)
2452  gtk_toggle_button_set_active(
2453  GTK_TOGGLE_BUTTON(keybinding_checkbutton_shift), TRUE);
2454  else
2455  gtk_toggle_button_set_active(
2456  GTK_TOGGLE_BUTTON(keybinding_checkbutton_shift), FALSE);
2457 
2458  if (kb->flags & KEYF_MOD_ALT)
2459  gtk_toggle_button_set_active(
2460  GTK_TOGGLE_BUTTON(keybinding_checkbutton_alt), TRUE);
2461  else
2462  gtk_toggle_button_set_active(
2463  GTK_TOGGLE_BUTTON(keybinding_checkbutton_alt), FALSE);
2464 
2465  if (kb->flags & KEYF_MOD_META)
2466  gtk_toggle_button_set_active(
2467  GTK_TOGGLE_BUTTON(keybinding_checkbutton_meta), TRUE);
2468  else
2469  gtk_toggle_button_set_active(
2470  GTK_TOGGLE_BUTTON(keybinding_checkbutton_meta), FALSE);
2471 
2472  if (kb->flags & KEYF_EDIT)
2473  gtk_toggle_button_set_active(
2474  GTK_TOGGLE_BUTTON(keybinding_checkbutton_edit), TRUE);
2475  else
2476  gtk_toggle_button_set_active(
2477  GTK_TOGGLE_BUTTON(keybinding_checkbutton_edit), FALSE);
2478 
2479  gtk_entry_set_text(
2480  GTK_ENTRY(keybinding_entry_key), gdk_keyval_name(kb->keysym));
2481  gtk_entry_set_text(
2482  GTK_ENTRY(keybinding_entry_command), kb->command);
2483 
2485  }
2486  return TRUE;
2487 }
2488 
2495  gtk_toggle_button_set_active(
2496  GTK_TOGGLE_BUTTON(keybinding_checkbutton_any), FALSE);
2497  gtk_toggle_button_set_active(
2498  GTK_TOGGLE_BUTTON(keybinding_checkbutton_control), FALSE);
2499  gtk_toggle_button_set_active(
2500  GTK_TOGGLE_BUTTON(keybinding_checkbutton_shift), FALSE);
2501  gtk_toggle_button_set_active(
2502  GTK_TOGGLE_BUTTON(keybinding_checkbutton_alt), FALSE);
2503  gtk_toggle_button_set_active(
2504  GTK_TOGGLE_BUTTON(keybinding_checkbutton_meta), FALSE);
2505  gtk_toggle_button_set_active(
2506  GTK_TOGGLE_BUTTON(keybinding_checkbutton_edit), FALSE);
2507  gtk_entry_set_text(GTK_ENTRY(keybinding_entry_key), "");
2508  gtk_entry_set_text(GTK_ENTRY(keybinding_entry_command), "");
2509 
2510  toggle_buttons_scope(FALSE);
2511 
2512  gtk_widget_set_sensitive(keybinding_button_remove, FALSE);
2513  gtk_widget_set_sensitive(keybinding_button_update, FALSE);
2514 }
2515 
2524 void on_keybinding_button_clear_clicked(GtkButton *button, gpointer user_data) {
2525  GtkTreeModel *model;
2526  GtkTreeIter iter;
2527 
2528  /*
2529  * As the cleared state is not supposed to have a keybinding selected,
2530  * deselect the currently selected keybinding if there is one.
2531  */
2532  if (gtk_tree_selection_get_selected(keybinding_selection, &model, &iter)) {
2533  gtk_tree_selection_unselect_iter(keybinding_selection, &iter);
2534  }
2535  reset_keybinding_status(); /* Clear inputs and reset buttons. */
2536 }
2537 
run_dir
void run_dir(int dir)
Definition: player.c:146
keybinding_checkbutton_control
static GtkWidget * keybinding_checkbutton_control
Definition: keys.c:54
keybind_overwrite_confirm
static int keybind_overwrite_confirm(struct keybind *kb)
Shows a dialog that prompts for confirmation before overwriting a keybind, showing details of the key...
Definition: keys.c:2045
LOG_INFO
@ LOG_INFO
Minor, non-harmful issues.
Definition: client.h:437
update_keybinding_list
void update_keybinding_list(void)
Update the keybinding dialog to reflect the current state of the keys file.
Definition: keys.c:1864
MSG_TYPE_CLIENT
#define MSG_TYPE_CLIENT
Client originated Messages.
Definition: newclient.h:390
keybinding_window
static GtkWidget * keybinding_window
Definition: keys.c:51
save_individual_key
static void save_individual_key(FILE *fp, struct keybind *kb, KeyCode kc)
A recursive function that saves all the entries for a particular entry.
Definition: keys.c:1263
LOG_WARNING
@ LOG_WARNING
Warning that something might not work.
Definition: client.h:438
Playing
@ Playing
Definition: client.h:145
init_default_keybindings
static void init_default_keybindings()
Load pre-compiled built-in default keybindings.
Definition: keys.c:519
keybinding_store
static GtkListStore * keybinding_store
Bound key list for bind dialog.
Definition: keys.c:61
on_entry_commands_activate
void on_entry_commands_activate(GtkEntry *entry, gpointer user_data)
Used to process keyboard input whenever the player types commands into the command entry box.
Definition: keys.c:1797
keyfunc
void keyfunc(GtkWidget *widget, GdkEventKey *event, GtkWidget *window)
GTK Callback function used to handle client key press events.
Definition: keys.c:1573
on_keybindings_activate
void on_keybindings_activate(GtkMenuItem *menuitem, gpointer user_data)
Menubar item to activate keybindings window.
Definition: keys.c:1934
keybind_free
static void keybind_free(struct keybind **entry)
Definition: keys.c:303
Player_Struct::fire_on
guint32 fire_on
True if fire key is pressed.
Definition: client.h:355
keybinding_get_data
static void keybinding_get_data(guint32 *keysym, guint8 *flags, const char **command)
Gets the state information from checkboxes and other data in the window and puts it in the variables ...
Definition: keys.c:2232
BIG_BUF
#define BIG_BUF
Definition: client.h:41
on_count_changed
static void on_count_changed(GtkSpinButton *spinbutton, gpointer *data)
Definition: keys.c:639
ClientSocket::command_received
guint16 command_received
These are used for the newer 'windowing' method of commands - number of last command sent,...
Definition: client.h:127
keybindings_init
void keybindings_init(const char *character_name)
Reads in the keybindings, and initializes special values.
Definition: keys.c:534
KEYF_MOD_SHIFT
#define KEYF_MOD_SHIFT
Used in fire mode.
Definition: keys.c:140
Player_Struct::input_state
Input_State input_state
What the input state is.
Definition: client.h:342
client_disconnect
void client_disconnect()
Closes the connection to the server.
Definition: client.c:175
keybind::keysym
guint32 keysym
Key this binding record is for.
Definition: keys.c:104
keys_global
static struct keybind * keys_global[KEYHASH]
Will hold the keybindings into two separate hashes depending on the scope they afect (global or chara...
Definition: keys.c:168
extended_command
void extended_command(const char *ocommand)
This is an extended command (ie, 'who, 'whatever, etc).
Definition: p_cmd.c:531
keybinding_entry_key
static GtkWidget * keybinding_entry_key
Definition: keys.c:56
Player_Struct::run_on
guint32 run_on
True if run key is on.
Definition: client.h:356
EKEYBIND_NOMEM
#define EKEYBIND_NOMEM
Definition: keys.c:175
Configure_Keys
@ Configure_Keys
Definition: client.h:146
keybinding_treeview
static GtkWidget * keybinding_treeview
Definition: keys.c:57
parse_key
static void parse_key(char key, guint32 keysym)
Parses a keypress.
Definition: keys.c:841
KEYF_MOD_MASK
#define KEYF_MOD_MASK
Definition: keys.c:144
Player_Struct::meta_on
guint32 meta_on
True if fire key is pressed.
Definition: client.h:357
on_keybinding_button_bind_clicked
void on_keybinding_button_bind_clicked(GtkButton *button, gpointer user_data)
Sets up a new binding when the "Add" button is clicked.
Definition: keys.c:2299
toggle_buttons_scope
void toggle_buttons_scope(int scope)
Toggles buttons state to reflect a scope state.
Definition: keys.c:2005
Reply_One
@ Reply_One
Definition: client.h:146
on_kb_scope_togglebutton_global_toggled
void on_kb_scope_togglebutton_global_toggled(GtkToggleButton *toggle_button, gpointer user_data)
Called when "All characters" is clicked.
Definition: keys.c:2178
toggle_keybind_scope
void toggle_keybind_scope(int scope, struct keybind *kb)
Toggles a keybinding's scope to the desired value.
Definition: keys.c:2080
stop_fire
void stop_fire()
Definition: player.c:104
history
char history[MAX_HISTORY][MAX_COMMAND_LEN]
Definition: keys.c:89
treeview_look
GtkWidget * treeview_look
Definition: inventory.c:27
keybind_find
static struct keybind * keybind_find(guint32 keysym, unsigned int flags, int scope)
Find a keybinding for keysym.
Definition: keys.c:200
NDI_RED
#define NDI_RED
Definition: newclient.h:227
keybind
Definition: keys.c:101
KEYF_EDIT
#define KEYF_EDIT
Enter command mode.
Definition: keys.c:150
bind_keysym
static guint32 * bind_keysym
Definition: keys.c:121
COUNT_MAX
const int COUNT_MAX
Definition: keys.c:40
keybind::flags
guint8 flags
KEYF_* flags set for the record.
Definition: keys.c:102
KEYF_MOD_CTRL
#define KEYF_MOD_CTRL
Used in run mode.
Definition: keys.c:141
Player_Struct::input_text
char input_text[MAX_BUF]
keys typed (for long commands)
Definition: client.h:344
clear_fire
void clear_fire()
Definition: player.c:111
MSG_TYPE_CLIENT_ERROR
#define MSG_TYPE_CLIENT_ERROR
Bad things happening.
Definition: newclient.h:641
KLIST_ENTRY
@ KLIST_ENTRY
Definition: keys.c:76
commandkeysym
static guint32 commandkeysym
Definition: keys.c:121
spinbutton_count
GtkWidget * spinbutton_count
Definition: keys.c:64
MAX_COMMAND_LEN
#define MAX_COMMAND_LEN
Definition: keys.c:88
Reply_Many
@ Reply_Many
Definition: client.h:146
on_keybinding_entry_key_key_press_event
gboolean on_keybinding_entry_key_key_press_event(GtkWidget *widget, GdkEventKey *event, gpointer user_data)
Respond to a key press in the "Key" input box.
Definition: keys.c:1952
in
static GInputStream * in
Definition: client.c:71
KEYF_ANY
#define KEYF_ANY
Don't care about modifiers.
Definition: keys.c:149
run_label
static GtkWidget * run_label
Definition: keys.c:51
keybinding_checkbutton_shift
static GtkWidget * keybinding_checkbutton_shift
Definition: keys.c:54
parse_keys_file
static int parse_keys_file(GInputStream *in, unsigned int scope_flag)
Opens a file and loads the keybinds contained in it.
Definition: keys.c:504
runkeysym
static guint32 runkeysym[2]
Definition: keys.c:121
proto.h
MAX_BUF
#define MAX_BUF
Definition: client.h:40
keybinding_button_update
static GtkWidget * keybinding_button_update
Definition: keys.c:58
KLIST_KEY
@ KLIST_KEY
Definition: keys.c:76
on_keybinding_button_update_clicked
void on_keybinding_button_update_clicked(GtkButton *button, gpointer user_data)
Implements the "Update Binding" button to update the currently selected keybinding to match the curre...
Definition: keys.c:2333
KEYF_R_CHAR
#define KEYF_R_CHAR
Character specific.
Definition: keys.c:154
focusoutfunc
void focusoutfunc(GtkWidget *widget, GdkEventKey *event, GtkWidget *window)
When the main window looses its focus, act as if all keys have been released.
Definition: keys.c:1532
cancelkeysym
static guint32 cancelkeysym
Definition: keys.c:123
ClientSocket::servername
char * servername
Definition: client.h:135
gtk_complete_command
void gtk_complete_command(void)
Executes when the TAB key is pressed while the command input box has focus to give hints on what comm...
Definition: keys.c:1776
on_keybinding_button_clear_clicked
void on_keybinding_button_clear_clicked(GtkButton *button, gpointer user_data)
Implements the "Clear Fields" button function on the keybinding dialog.
Definition: keys.c:2524
gtk2proto.h
show_keys
static void show_keys(void)
Shows all the keybindings.
Definition: keys.c:1031
keybind::command
char * command
Command string bound to a key.
Definition: keys.c:105
complete_command
const char * complete_command(const char *command)
Player has entered 'command' and hit tab to complete it.
Definition: p_cmd.c:630
cur_history_position
static int cur_history_position
Definition: keys.c:91
LOG
void LOG(LogLevel level, const char *origin, const char *format,...)
Log messages of a certain importance to stderr.
Definition: misc.c:111
Command_Mode
@ Command_Mode
Definition: client.h:146
keybind_insert
static int keybind_insert(guint32 keysym, unsigned int flags, const char *command)
Updates the keys array with the keybinding that is passed.
Definition: keys.c:229
send_reply
void send_reply(const char *text)
Sends a reply to the server.
Definition: commands.c:1613
config_dir
const char * config_dir
Definition: client.c:52
Player_Struct::alt_on
guint32 alt_on
True if fire key is pressed.
Definition: client.h:358
clear_run
void clear_run()
Definition: player.c:118
KEYHASH
#define KEYHASH
Definition: keys.c:158
keybind_remove
static int keybind_remove(struct keybind *entry)
Definition: keys.c:283
kb_scope_togglebutton_global
static GtkWidget * kb_scope_togglebutton_global
Definition: keys.c:52
draw_ext_info
void draw_ext_info(int orig_color, int type, int subtype, const char *message)
A message processor that accepts messages along with meta information color and type.
Definition: info.c:915
csocket
ClientSocket csocket
Definition: client.c:70
KLIST_COMMAND
@ KLIST_COMMAND
Definition: keys.c:76
NDI_BLACK
#define NDI_BLACK
Definition: newclient.h:224
image.h
KEYF_R_GLOBAL
#define KEYF_R_GLOBAL
Save at user's file.
Definition: keys.c:153
on_keybinding_button_close_clicked
void on_keybinding_button_close_clicked(GtkButton *button, gpointer user_data)
Deactivates the keybinding dialog when the "Close Window" button is clicked.
Definition: keys.c:2382
Player_Struct::no_echo
guint32 no_echo
If TRUE, don't echo keystrokes.
Definition: client.h:359
configure_keys
static void configure_keys(guint32 keysym)
Definition: keys.c:1372
kb_scope_togglebutton_character
static GtkWidget * kb_scope_togglebutton_character
Definition: keys.c:52
keybinding_checkbutton_alt
static GtkWidget * keybinding_checkbutton_alt
Definition: keys.c:55
KLIST_KEY_ENTRY
@ KLIST_KEY_ENTRY
Definition: keys.c:77
altkeysym
static guint32 altkeysym[2]
Definition: keys.c:122
keys_init
void keys_init(GtkWidget *window_root)
One-time initialization of windows and signals for the keybindings dialog.
Definition: keys.c:650
prevkeysym
static guint32 prevkeysym
Definition: keys.c:122
Player_Struct::name
char * name
Name of PC, set and freed in account.c play_character() (using data returned from server to AccountPl...
Definition: client.h:370
KLIST_EDIT
@ KLIST_EDIT
Definition: keys.c:76
draw_prompt
void draw_prompt(const char *str)
Draws a prompt.
Definition: keys.c:1719
p_cmd.h
keybinding_entry_command
static GtkWidget * keybinding_entry_command
Definition: keys.c:57
x_set_echo
void x_set_echo(void)
Definition: keys.c:1710
keyrelfunc
void keyrelfunc(GtkWidget *widget, GdkEventKey *event, GtkWidget *window)
GTK callback function used to handle client key release events.
Definition: keys.c:1558
dialog_xml
GtkBuilder * dialog_xml
Definition: main.c:108
stop_run
void stop_run()
Definition: player.c:141
keys_char
static struct keybind * keys_char[KEYHASH]
Definition: keys.c:168
reset_keybinding_status
void reset_keybinding_status(void)
Reset the state of the keybinding dialog.
Definition: keys.c:2494
MAX_HISTORY
#define MAX_HISTORY
Definition: keys.c:87
LOG_ERROR
@ LOG_ERROR
Warning that something definitely didn't work.
Definition: client.h:439
unbind_usage
static void unbind_usage(void)
Show help for the unbind command in the message pane.
Definition: keys.c:1460
main.h
keybinding_checkbutton_any
static GtkWidget * keybinding_checkbutton_any
Definition: keys.c:53
completekeysym
static guint32 completekeysym
Definition: keys.c:122
scroll_history_position
static int scroll_history_position
Definition: keys.c:91
cpl
Client_Player cpl
Player object.
Definition: client.c:69
MSG_TYPE_CLIENT_CONFIG
#define MSG_TYPE_CLIENT_CONFIG
Local configuration issues.
Definition: newclient.h:633
KLIST_SCOPE
@ KLIST_SCOPE
Definition: keys.c:76
keybinding_checkbutton_edit
static GtkWidget * keybinding_checkbutton_edit
Definition: keys.c:56
NDI_WHITE
#define NDI_WHITE
Definition: newclient.h:225
CONFIG_POPUPS
#define CONFIG_POPUPS
Definition: client.h:191
keybinding_selection
static GtkTreeSelection * keybinding_selection
Definition: keys.c:62
unbind_key
void unbind_key(const char *params)
Definition: keys.c:1471
KEYF_MOD_ALT
#define KEYF_MOD_ALT
For ALT key modifier.
Definition: keys.c:142
MSG_TYPE_CLIENT_NOTICE
#define MSG_TYPE_CLIENT_NOTICE
Non-critical note to player.
Definition: newclient.h:638
save_keys
static void save_keys(void)
Saves the keybindings into the user's .crossfire/keys file.
Definition: keys.c:1277
fire_dir
void fire_dir(int dir)
Definition: player.c:125
fire_label
static GtkWidget * fire_label
Definition: keys.c:51
keybinding_button_remove
static GtkWidget * keybinding_button_remove
Definition: keys.c:58
nextkeysym
static guint32 nextkeysym
Definition: keys.c:122
get_key_info
static char * get_key_info(struct keybind *kb, int save_mode)
Definition: keys.c:994
Metaserver_Select
@ Metaserver_Select
Definition: client.h:147
Player_Struct::count
guint32 count
Repeat count on command.
Definition: client.h:360
keybind::next
struct keybind * next
Definition: keys.c:106
use_config
gint16 use_config[CONFIG_NUMS]
Definition: client.h:245
MSG_TYPE_CLIENT_QUERY
#define MSG_TYPE_CLIENT_QUERY
handle_query() and prompts
Definition: newclient.h:636
gtk_command_history
void gtk_command_history(int direction)
Deals with command history.
Definition: keys.c:1729
entry_commands
GtkWidget * entry_commands
Definition: keys.c:65
ClientSocket::command_sent
guint16 command_sent
Definition: client.h:127
firekeysym
static guint32 firekeysym[2]
Definition: keys.c:121
draw_message_window
void draw_message_window(int redraw)
Updates the stats pane - hp, sp, etc labels.
Definition: stats.c:459
CONFIG_DEBOUNCE
#define CONFIG_DEBOUNCE
Definition: client.h:219
window_root
GtkWidget * window_root
In main.c.
Definition: main.c:109
on_kb_scope_togglebutton_character_toggled
void on_kb_scope_togglebutton_character_toggled(GtkToggleButton *toggle_button, gpointer user_data)
Called when "This character" is clicked.
Definition: keys.c:2156
get_key_modchars
static void get_key_modchars(struct keybind *kb, int save_mode, char *buf)
Definition: keys.c:956
metakeysym
static guint32 metakeysym[2]
Definition: keys.c:122
keybinding_selection_func
gboolean keybinding_selection_func(GtkTreeSelection *selection, GtkTreeModel *model, GtkTreePath *path, gboolean path_currently_selected, gpointer userdata)
Called when the user clicks one of the entries in the list of keybindings and places information abou...
Definition: keys.c:2416
on_keybinding_button_remove_clicked
void on_keybinding_button_remove_clicked(GtkButton *button, gpointer user_data)
Implements the "Remove Binding" button function that unbinds the currently selected keybinding.
Definition: keys.c:2200
directions
const char *const directions[9]
256-length array to keep track of when commands were sent to the server
Definition: player.c:41
KEYF_MOD_META
#define KEYF_MOD_META
For Meta key modifier.
Definition: keys.c:143
keybinding_button_bind
static GtkWidget * keybinding_button_bind
Definition: keys.c:59
LOG_DEBUG
@ LOG_DEBUG
Useful debugging information.
Definition: client.h:436
bind_flags
static int bind_flags
Definition: keys.c:125
on_keybinding_checkbutton_any_clicked
void on_keybinding_checkbutton_any_clicked(GtkCheckButton *cb, gpointer user_data)
Deactivate the modifier checkboxes if "Any" is selected.
Definition: keys.c:2392
debounce
static bool debounce
When a key is held down, prevent multiple commands from being sent without server acknowledgement by ...
Definition: keys.c:182
client.h
keybinding_checkbutton_meta
static GtkWidget * keybinding_checkbutton_meta
Definition: keys.c:55
make_path_to_file
int make_path_to_file(char *filename)
If any directories in the given path doesn't exist, they are created.
Definition: misc.c:87
KLIST_MODS
@ KLIST_MODS
Definition: keys.c:76
parse_keybind_line
static void parse_keybind_line(char *buf, int line, unsigned int scope_flag)
This function is common to both gdk and x11 client.
Definition: keys.c:317
bind_buf
static char bind_buf[MAX_BUF]
Definition: keys.c:126
keybind::direction
gint8 direction
-1 non-direction key, else >= 0.
Definition: keys.c:103
parse_key_release
static void parse_key_release(guint32 keysym)
The only things we actually care about is the run and fire keys.
Definition: keys.c:805
bind_key
void bind_key(char *params)
Implements the "bind" command when entered as a text command.
Definition: keys.c:1095
window_xml
GtkBuilder * window_xml
Definition: main.c:108