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 struct keybind;
41 static int keybind_remove(struct keybind *entry);
42 static void keybind_free(struct keybind **entry);
43 
49 static GtkWidget *fire_label, *run_label, *keybinding_window,
58 
59 static GtkListStore *keybinding_store;
60 static GtkTreeSelection *keybinding_selection;
61 
62 GtkWidget *spinbutton_count;
63 GtkWidget *entry_commands;
73 enum {
76 };
85 #define MAX_HISTORY 50
86 #define MAX_COMMAND_LEN 256
88 
99 struct keybind {
100  guint8 flags;
101  gint8 direction;
102  guint32 keysym;
103  char *command;
104  struct keybind *next;
105 };
106 
107 
108 /***********************************************************************
109  *
110  * Key board input translations are handled here. We don't deal with
111  * the events, but rather KeyCodes and KeySyms.
112  *
113  * It would be nice to deal with only KeySyms, but many keyboards
114  * have keys that do not correspond to a KeySym, so we do need to
115  * support KeyCodes.
116  *
117  ***********************************************************************/
118 
122 
123 static int bind_flags = 0;
124 static char bind_buf[MAX_BUF];
125 
126 /*
127  * Key modifiers
128  *
129  * The Run, Fire, Alt and/or Meta keys can be used to qualify a key
130  * (i.e. a keybinding of the key 's' with the KEYF_RUN and KEYF_FIRE
131  * flags set will only match if both Run and Fire are held while 's' is
132  * pressed).
133  *
134  * If the user wants a key to match no matter the state of the modifier
135  * keys, the KEYF_ANY flag must be set in the binding.
136  */
137 
138 #define KEYF_MOD_SHIFT (1 << 0)
139 #define KEYF_MOD_CTRL (1 << 1)
140 #define KEYF_MOD_ALT (1 << 2)
141 #define KEYF_MOD_META (1 << 3)
142 #define KEYF_MOD_MASK (KEYF_MOD_SHIFT | \
143  KEYF_MOD_CTRL | \
144  KEYF_MOD_ALT | \
145  KEYF_MOD_META)
146 
147 #define KEYF_ANY (1 << 4)
148 #define KEYF_EDIT (1 << 5)
150 /* Keybinding's scope, decides where the binding will be saved */
151 #define KEYF_R_GLOBAL (1 << 6)
152 #define KEYF_R_CHAR (1 << 7)
154 extern const char *const directions[9];
155 
156 #define KEYHASH 257
157 
167 
173 #define EKEYBIND_NOMEM 1
174 
180 static bool debounce = false;
181 
198 static struct keybind *keybind_find(guint32 keysym, unsigned int flags,
199  int scope) {
200  struct keybind *kb;
201  kb = scope ? keys_global[keysym % KEYHASH] : keys_char[keysym % KEYHASH];
202  while (kb != NULL) {
203  if (kb->keysym == 0 || kb->keysym == keysym) {
204  if ((kb->flags & KEYF_ANY) || (flags & KEYF_ANY)) {
205  return kb;
206  }
207  if ((kb->flags & KEYF_MOD_MASK) == (flags & KEYF_MOD_MASK)) {
208  return kb;
209  }
210  }
211  kb = kb->next;
212  }
213 
214  return NULL;
215 }
216 
227 static int keybind_insert(guint32 keysym, unsigned int flags,
228  const char *command) {
229  struct keybind **next_ptr, *kb;
230  int slot;
231  int i;
232  int dir;
233 
235  while (kb != NULL) {
236  /*
237  * Keep the last binding instead of the first (backwards compatible).
238  *
239  * Also, if the new binding has the ANY flag, remove all matching
240  * previous bindings and keep this one.
241  */
242  LOG(LOG_DEBUG, "gtk-v2::keybind_insert",
243  "Overwriting previous binding for key %s with command %s ",
244  gdk_keyval_name(keysym), kb->command);
245  keybind_remove(kb);
246  keybind_free(&kb);
248  }
249 
250  slot = keysym % KEYHASH;
251 
252  next_ptr = (flags & KEYF_R_GLOBAL) ? &keys_global[slot] : &keys_char[slot];
253  while (*next_ptr) {
254  next_ptr = &(*next_ptr)->next;
255  }
256  *next_ptr = calloc(1, sizeof(**next_ptr));
257  if (*next_ptr == NULL) {
258  return -EKEYBIND_NOMEM;
259  }
260 
261  (*next_ptr)->keysym = keysym;
262  (*next_ptr)->flags = flags;
263  (*next_ptr)->command = g_strdup(command);
264 
265  /*
266  * Try to find out if the command is a direction command. If so, keep
267  * track of this fact, so in fire or run mode, things work correctly.
268  */
269  dir = -1;
270  for (i = 0; i < 9; i++) {
271  if (!strcmp(command, directions[i])) {
272  dir = i;
273  break;
274  }
275  }
276  (*next_ptr)->direction = dir;
277 
278  return 0;
279 }
280 
281 static int keybind_remove(struct keybind *entry) {
282  struct keybind **next_ptr;
283  int slot;
284 
285  slot = entry->keysym % KEYHASH;
286 
287  next_ptr = (entry->flags & KEYF_R_GLOBAL) ? &keys_global[slot] :
288  &keys_char[slot];
289  while (*next_ptr) {
290  if (*next_ptr == entry) {
291  *next_ptr = entry->next;
292  return 0;
293  }
294  next_ptr = &(*next_ptr)->next;
295  }
296 
297  /* No such key entry */
298  return -1;
299 }
300 
301 static void keybind_free(struct keybind **entry) {
302  free((*entry)->command);
303  (*entry)->command = NULL;
304  free(*entry);
305  *entry = NULL;
306 }
307 
315 static void parse_keybind_line(char *buf, int line, unsigned int scope_flag) {
316  char *cp, *cpnext;
317  guint32 keysym, low_keysym;
318  int flags;
319 
320  /*
321  * There may be a rare error case when cp is used uninitialized. So let's
322  * be safe
323  */
324  cp = NULL;
325 
326  if (buf[0] == '\0' || buf[0] == '#' || buf[0] == '\n') {
327  return;
328  }
329  cpnext = strchr(buf, ' ');
330  if (cpnext == NULL) {
331  LOG(LOG_WARNING, "gtk-v2::parse_keybind_line",
332  "Line %d (%s) corrupted in keybinding file.", line, buf);
333  return;
334  }
335  /* Special keybinding line */
336  if (buf[0] == '!') {
337  char *cp1;
338  while (*cpnext == ' ') {
339  ++cpnext;
340  }
341  cp = strchr(cpnext, ' ');
342  if (!cp) {
343  LOG(LOG_WARNING, "gtk-v2::parse_keybind_line",
344  "Line %d (%s) corrupted in keybinding file.", line, buf);
345  return;
346  }
347  *cp++ = 0; /* Null terminate it */
348  cp1 = strchr(cp, ' ');
349  if (!cp1) {
350  LOG(LOG_WARNING, "gtk-v2::parse_keybind_line",
351  "Line %d (%s) corrupted in keybinding file.", line, buf);
352  return;
353  }
354  *cp1++ = 0; /* Null terminate it */
355  keysym = gdk_keyval_from_name(cp);
356  /* As of now, all these keys must have keysyms */
357  if (keysym == 0) {
358  LOG(LOG_WARNING, "gtk-v2::parse_keybind_line",
359  "Could not convert %s into keysym", cp);
360  return;
361  }
362  if (!strcmp(cpnext, "commandkey")) {
364  return;
365  }
366  if (!strcmp(cpnext, "altkey0")) {
367  altkeysym[0] = keysym;
368  return;
369  }
370  if (!strcmp(cpnext, "altkey1")) {
371  altkeysym[1] = keysym;
372  return;
373  }
374  if (!strcmp(cpnext, "firekey0")) {
375  firekeysym[0] = keysym;
376  return;
377  }
378  if (!strcmp(cpnext, "firekey1")) {
379  firekeysym[1] = keysym;
380  return;
381  }
382  if (!strcmp(cpnext, "metakey0")) {
383  metakeysym[0] = keysym;
384  return;
385  }
386  if (!strcmp(cpnext, "metakey1")) {
387  metakeysym[1] = keysym;
388  return;
389  }
390  if (!strcmp(cpnext, "runkey0")) {
391  runkeysym[0] = keysym;
392  return;
393  }
394  if (!strcmp(cpnext, "runkey1")) {
395  runkeysym[1] = keysym;
396  return;
397  }
398  if (!strcmp(cpnext, "completekey")) {
400  return;
401  }
402  if (!strcmp(cpnext, "nextkey")) {
403  nextkeysym = keysym;
404  return;
405  }
406  if (!strcmp(cpnext, "prevkey")) {
407  prevkeysym = keysym;
408  return;
409  }
410  } else {
411  *cpnext++ = '\0';
412  keysym = gdk_keyval_from_name(buf);
413  if (!keysym) {
414  LOG(LOG_WARNING, "gtk-v2::parse_keybind_line",
415  "Unable to convert line %d (%s) into keysym", line, buf);
416  return;
417  }
418  cp = cpnext;
419  cpnext = strchr(cp, ' ');
420  if (cpnext == NULL) {
421  LOG(LOG_WARNING, "gtk-v2::parse_keybind_line",
422  "Line %d (%s) corrupted in keybinding file.", line, cp);
423  return;
424  }
425  *cpnext++ = '\0';
426 
427  cp = cpnext;
428  cpnext = strchr(cp, ' ');
429  if (cpnext == NULL) {
430  LOG(LOG_WARNING, "gtk-v2::parse_keybind_line",
431  "Line %d (%s) corrupted in keybinding file.", line, cp);
432  return;
433  }
434  *cpnext++ = '\0';
435 
436  flags = 0;
437  low_keysym = gdk_keyval_to_lower(keysym);
438  if (low_keysym != keysym) {
439  /* This binding is uppercase, switch to lowercase and flag the shift modifier */
441  keysym = low_keysym;
442  }
443  while (*cp != '\0') {
444  switch (*cp) {
445  case 'A':
446  flags |= KEYF_ANY;
447  break;
448  case 'E':
449  flags |= KEYF_EDIT;
450  break;
451  case 'F':
453  break;
454  case 'L': /* A is used, so using L for alt */
455  flags |= KEYF_MOD_ALT;
456  break;
457  case 'M':
458  flags |= KEYF_MOD_META;
459  break;
460  case 'N':
461  /* Nothing to do */
462  break;
463  case 'R':
464  flags |= KEYF_MOD_CTRL;
465  break;
466  case 'S':
467  LOG(LOG_WARNING, "gtk-v2::parse_keybind_line",
468  "Deprecated flag (S) ignored at line %d in key binding file", line);
469  break;
470  default:
471  LOG(LOG_WARNING, "gtk-v2::parse_keybind_line",
472  "Unknown flag (%c) line %d in key binding file",
473  *cp, line);
474  }
475  cp++;
476  }
477 
478  if (strlen(cpnext) > (sizeof(bind_buf) - 1)) {
479  cpnext[sizeof(bind_buf) - 1] = '\0';
480  LOG(LOG_WARNING, "gtk-v2::parse_keybind_line",
481  "Command too long! Truncated.");
482  }
483 
484  flags |= scope_flag; /* add the corresponding scope flag */
485 
486  // If there is a trailing CR, remove it.
487  cpnext[strcspn(cpnext, "\r")] = 0;
488 
489  keybind_insert(keysym, flags, cpnext);
490 
491  } /* else if not special binding line */
492 }
493 
502 static int parse_keys_file(GInputStream *in, unsigned int scope_flag) {
503  GDataInputStream *stream = g_data_input_stream_new(in);
504  int line_no = 0;
505  char *line;
506  while ((line = g_data_input_stream_read_line(stream, NULL, NULL, NULL)) != NULL) {
507  line_no++;
508  parse_keybind_line(line, line_no, scope_flag);
509  }
510 
511  return 0;
512 }
513 
518  LOG(LOG_DEBUG, "init_default_keybindings", "Loading default keybindings");
519  GInputStream *in = g_resources_open_stream("/org/crossfire/client/common/def-keys", 0, NULL);
520  if (in == NULL) {
521  g_error("could not load default keybindings");
522  }
524  g_object_unref(in);
525 }
526 
532 void keybindings_init(const char *character_name) {
533  char buf[BIG_BUF];
534  int i;
535 
536  /* Clear out the bind history. */
537  for (i = 0; i < MAX_HISTORY; i++) {
538  history[i][0] = 0;
539  }
540 
541  commandkeysym = GDK_KEY_apostrophe;
542  firekeysym[0] = GDK_KEY_Shift_L;
543  firekeysym[1] = GDK_KEY_Shift_R;
544  runkeysym[0] = GDK_KEY_Control_L;
545  runkeysym[1] = GDK_KEY_Control_R;
546  metakeysym[0] = GDK_KEY_Meta_L;
547  metakeysym[1] = GDK_KEY_Meta_R;
548  altkeysym[0] = GDK_KEY_Alt_L;
549  altkeysym[1] = GDK_KEY_Alt_R;
550 
551  completekeysym = GDK_KEY_Tab;
552  cancelkeysym = GDK_KEY_Escape;
553 
554  /*
555  * Don't set these to anything by default. At least on Sun keyboards, the
556  * keysym for up on both the keypad and arrow keys is the same, so player
557  * needs to rebind this so we get proper keycode. Very unfriendly to log
558  * in and not be able to move north/south.
559  */
560  nextkeysym = NoSymbol;
561  prevkeysym = NoSymbol;
562 
563  for (i = 0; i < KEYHASH; i++) {
564  while (keys_global[i]) {
566  }
567 
568  while (keys_char[i]) {
570  }
571  }
572 
573  /*
574  * If we were supplied with a character name, store it so that we
575  * can load and save a character-specific keys file.
576  */
577  if (cpl.name) {
578  free(cpl.name);
579  cpl.name = NULL;
580  }
581  if (character_name) {
582  cpl.name = g_strdup(character_name);
583  }
584 
585  /*
586  * We now try to load the keybindings. First load defaults.
587  * Then go through the more specific files in the home directory:
588  * 1) user wide "~/.crossfire/keys".
589  * 2) and, if character name is known, "~/.crossfire/<name>.keys"
590  *
591  * The format is described in the def_keys file. Note that this file is
592  * the same as what it was in the server distribution. To convert bindings
593  * in character files to this format, all that needs to be done is remove
594  * the 'key ' at the start of each line.
595  */
596 
598 
599  /* Try to load global keybindings. */
600  snprintf(buf, sizeof(buf), "%s/keys", config_dir);
601  GFile *f = g_file_new_for_path(buf);
602  GFileInputStream * fs = g_file_read(f, NULL, NULL);
603  if (fs != NULL) {
604  GInputStream *in = G_INPUT_STREAM(fs);
605  if (in != NULL) {
606  LOG(LOG_DEBUG, "keybindings_init", "Loading global keybindings");
608  g_object_unref(in);
609  }
610  g_object_unref(fs);
611  }
612  g_object_unref(f);
613 
614  /* Try to load the character-specific keybindings. */
615  if (cpl.name) {
616  snprintf(buf, sizeof(buf), "%s/%s.%s.keys", config_dir,
618  GFile *f = g_file_new_for_path(buf);
619  GFileInputStream * fs = g_file_read(f, NULL, NULL);
620  if (fs != NULL) {
621  GInputStream *in = G_INPUT_STREAM(fs);
622  if (in != NULL) {
623  LOG(LOG_DEBUG, "keybindings_init", "Loading character keybindings for '%s'", cpl.name);
625  g_object_unref(in);
626  }
627  g_object_unref(fs);
628  } else {
629  LOG(LOG_DEBUG, "keybindings_init", "No character keybindings for '%s' found", cpl.name);
630  }
631  g_object_unref(f);
632  } else {
633  LOG(LOG_DEBUG, "keybindings_init", "No character name");
634  }
635 }
636 
637 static void on_count_changed(GtkSpinButton *spinbutton, gpointer *data) {
638  cpl.count = gtk_spin_button_get_value_as_int(spinbutton);
639 }
640 
648 void keys_init(GtkWidget *window_root) {
649  GtkTreeViewColumn *column;
650  GtkCellRenderer *renderer;
651  GtkWidget *widget;
652  int i;
653 
654  fire_label = GTK_WIDGET(gtk_builder_get_object(window_xml, "fire_label"));
655  run_label = GTK_WIDGET(gtk_builder_get_object(window_xml, "run_label"));
656  entry_commands = GTK_WIDGET(gtk_builder_get_object(window_xml,
657  "entry_commands"));
658  spinbutton_count = GTK_WIDGET(gtk_builder_get_object(window_xml,
659  "spinbutton_count"));
660  g_signal_connect(spinbutton_count, "value-changed", G_CALLBACK(on_count_changed), NULL);
661 
662  g_signal_connect((gpointer) entry_commands, "activate",
663  G_CALLBACK(on_entry_commands_activate), NULL);
664 
665  keybinding_window = GTK_WIDGET(gtk_builder_get_object(dialog_xml,
666  "keybinding_window"));
667 
669  GTK_WIDGET(gtk_builder_get_object(dialog_xml, "kb_scope_togglebutton_global"));
671  GTK_WIDGET(gtk_builder_get_object(dialog_xml,
672  "kb_scope_togglebutton_character"));
674  GTK_WIDGET(gtk_builder_get_object(dialog_xml, "keybinding_checkbutton_any"));
676  GTK_WIDGET(gtk_builder_get_object(dialog_xml,
677  "keybinding_checkbutton_control"));
679  GTK_WIDGET(gtk_builder_get_object(dialog_xml, "keybinding_checkbutton_shift"));
681  GTK_WIDGET(gtk_builder_get_object(dialog_xml, "keybinding_checkbutton_alt"));
683  GTK_WIDGET(gtk_builder_get_object(dialog_xml, "keybinding_checkbutton_meta"));
685  GTK_WIDGET(gtk_builder_get_object(dialog_xml,
686  "keybinding_checkbutton_stayinedit"));
688  GTK_WIDGET(gtk_builder_get_object(dialog_xml, "keybinding_entry_key"));
690  GTK_WIDGET(gtk_builder_get_object(dialog_xml, "keybinding_entry_command"));
692  GTK_WIDGET(gtk_builder_get_object(dialog_xml, "keybinding_treeview"));
694  GTK_WIDGET(gtk_builder_get_object(dialog_xml, "keybinding_button_remove"));
696  GTK_WIDGET(gtk_builder_get_object(dialog_xml, "keybinding_button_update"));
698  GTK_WIDGET(gtk_builder_get_object(dialog_xml, "keybinding_button_bind"));
699 
700  g_signal_connect((gpointer) keybinding_window, "delete_event",
701  G_CALLBACK(gtk_widget_hide_on_delete), NULL);
702  g_signal_connect((gpointer) keybinding_entry_key, "key_press_event",
703  G_CALLBACK(on_keybinding_entry_key_key_press_event), NULL);
704  g_signal_connect((gpointer) keybinding_button_remove, "clicked",
705  G_CALLBACK(on_keybinding_button_remove_clicked), NULL);
706  g_signal_connect((gpointer) keybinding_button_update, "clicked",
707  G_CALLBACK(on_keybinding_button_update_clicked), NULL);
708  g_signal_connect((gpointer) keybinding_button_bind, "clicked",
709  G_CALLBACK(on_keybinding_button_bind_clicked), NULL);
710 
711  g_signal_connect((gpointer) kb_scope_togglebutton_character, "toggled",
713  g_signal_connect((gpointer) kb_scope_togglebutton_global, "toggled",
714  G_CALLBACK(on_kb_scope_togglebutton_global_toggled), NULL);
715 
716  g_signal_connect((gpointer) keybinding_checkbutton_any, "clicked",
717  G_CALLBACK(on_keybinding_checkbutton_any_clicked), NULL);
718 
719  widget = GTK_WIDGET(gtk_builder_get_object(dialog_xml,
720  "keybinding_button_clear"));
721  g_signal_connect((gpointer) widget, "clicked",
722  G_CALLBACK(on_keybinding_button_clear_clicked), NULL);
723 
724  widget = GTK_WIDGET(gtk_builder_get_object(dialog_xml,
725  "keybinding_button_close"));
726  g_signal_connect((gpointer) widget, "clicked",
727  G_CALLBACK(on_keybinding_button_close_clicked), NULL);
728 
729  gtk_widget_set_sensitive(keybinding_button_remove, FALSE);
730  gtk_widget_set_sensitive(keybinding_button_update, FALSE);
731  keybinding_store = gtk_list_store_new(7,
732  G_TYPE_INT,
733  G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING,
734  G_TYPE_POINTER
735  );
736  gtk_tree_view_set_model(GTK_TREE_VIEW(keybinding_treeview),
737  GTK_TREE_MODEL(keybinding_store));
738 
739  renderer = gtk_cell_renderer_text_new();
740  column = gtk_tree_view_column_new_with_attributes("Key", renderer,
741  "text", KLIST_KEY,
742  NULL);
743  gtk_tree_view_column_set_sort_column_id(column, KLIST_KEY);
744  gtk_tree_view_append_column(GTK_TREE_VIEW(keybinding_treeview), column);
745 
746  renderer = gtk_cell_renderer_text_new();
747  column = gtk_tree_view_column_new_with_attributes("Modifiers", renderer,
748  "text", KLIST_MODS,
749  NULL);
750  gtk_tree_view_column_set_sort_column_id(column, KLIST_MODS);
751  gtk_tree_view_append_column(GTK_TREE_VIEW(keybinding_treeview), column);
752 
753  renderer = gtk_cell_renderer_text_new();
754  column = gtk_tree_view_column_new_with_attributes("Scope", renderer,
755  "text", KLIST_SCOPE,
756  NULL);
757  gtk_tree_view_column_set_sort_column_id(column, KLIST_SCOPE);
758  gtk_tree_view_append_column(GTK_TREE_VIEW(keybinding_treeview), column);
759 
760  renderer = gtk_cell_renderer_text_new();
761  column = gtk_tree_view_column_new_with_attributes("Edit Mode", renderer,
762  "text", KLIST_EDIT,
763  NULL);
764  gtk_tree_view_column_set_sort_column_id(column, KLIST_EDIT);
765  gtk_tree_view_append_column(GTK_TREE_VIEW(keybinding_treeview), column);
766 
767  renderer = gtk_cell_renderer_text_new();
768  column = gtk_tree_view_column_new_with_attributes("Command", renderer,
769  "text", KLIST_COMMAND,
770  NULL);
771  gtk_tree_view_column_set_sort_column_id(column, KLIST_COMMAND);
772  gtk_tree_view_append_column(GTK_TREE_VIEW(keybinding_treeview), column);
773 
774 
775  keybinding_selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(
777  gtk_tree_selection_set_mode(keybinding_selection, GTK_SELECTION_BROWSE);
778  gtk_tree_selection_set_select_function(keybinding_selection,
779  keybinding_selection_func, NULL, NULL);
780 
781  gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(keybinding_store),
782  KLIST_KEY,
783  GTK_SORT_ASCENDING);
784 
785  for (i = 0; i < KEYHASH; i++) {
786  keys_global[i] = NULL;
787  keys_char[i] = NULL;
788  }
789 }
790 
803 static void parse_key_release(guint32 keysym) {
804 
805  /*
806  * Only send stop firing/running commands if we are in actual play mode.
807  * Something smart does need to be done when the character enters a non
808  * play mode with fire or run mode already set, however.
809  */
810  if (keysym == firekeysym[0] || keysym == firekeysym[1]) {
811  cpl.fire_on = 0;
812  clear_fire();
813  gtk_label_set_text(GTK_LABEL(fire_label), " ");
814  } else if (keysym == runkeysym[0] || keysym == runkeysym[1]) {
815  cpl.run_on = 0;
816  clear_run();
817  gtk_label_set_text(GTK_LABEL(run_label), " ");
818  } else if (keysym == altkeysym[0] || keysym == altkeysym[1]) {
819  cpl.alt_on = 0;
820  } else if (keysym == metakeysym[0] || keysym == metakeysym[1]) {
821  cpl.meta_on = 0;
822  }
823  /*
824  * Firing is handled on server side. However, to keep more like the old
825  * version, if you release the direction key, you want the firing to stop.
826  * This should do that.
827  */
828  else if (cpl.fire_on) {
829  clear_fire();
830  }
831 }
832 
839 static void parse_key(char key, guint32 keysym) {
840  struct keybind *kb;
841  int present_flags = 0;
842  char buf[MAX_BUF], tmpbuf[MAX_BUF];
843 
844  /* We handle the Shift key separately */
845  keysym = gdk_keyval_to_lower(keysym);
846 
847  if (keysym == commandkeysym) {
848  gtk_widget_grab_focus(GTK_WIDGET(entry_commands));
849  gtk_entry_set_visibility(GTK_ENTRY(entry_commands), 1);
851  cpl.no_echo = FALSE;
852  return;
853  }
854  if (keysym == altkeysym[0] || keysym == altkeysym[1]) {
855  cpl.alt_on = 1;
856  return;
857  }
858  if (keysym == metakeysym[0] || keysym == metakeysym[1]) {
859  cpl.meta_on = 1;
860  return;
861  }
862  if (keysym == firekeysym[0] || keysym == firekeysym[1]) {
863  cpl.fire_on = 1;
864  gtk_label_set_text(GTK_LABEL(fire_label), "Fire");
865  return;
866  }
867  if (keysym == runkeysym[0] || keysym == runkeysym[1]) {
868  cpl.run_on = 1;
869  gtk_label_set_text(GTK_LABEL(run_label), "Run");
870  return;
871  }
872 
873  present_flags = 0;
874  if (cpl.run_on) {
875  present_flags |= KEYF_MOD_CTRL;
876  }
877  if (cpl.fire_on) {
878  present_flags |= KEYF_MOD_SHIFT;
879  }
880  if (cpl.alt_on) {
881  present_flags |= KEYF_MOD_ALT;
882  }
883  if (cpl.meta_on) {
884  present_flags |= KEYF_MOD_META;
885  }
886 
887  kb = keybind_find(keysym, present_flags, 0); /* char scope */
888  if (kb == NULL) {
889  kb = keybind_find(keysym, present_flags, 1); /* global scope */
890  }
891  if (kb != NULL) {
892  if (kb->flags & KEYF_EDIT) {
893  strcpy(cpl.input_text, kb->command);
895  gtk_entry_set_text(GTK_ENTRY(entry_commands), cpl.input_text);
896  gtk_widget_grab_focus(GTK_WIDGET(entry_commands));
897  gtk_editable_select_region(GTK_EDITABLE(entry_commands), 0, 0);
898  gtk_editable_set_position(GTK_EDITABLE(entry_commands), -1);
899  return;
900  }
901 
902  if (kb->direction >= 0) {
903  if (cpl.fire_on) {
904  snprintf(buf, sizeof(buf), "fire %s", kb->command);
905  fire_dir(kb->direction);
906  } else if (cpl.run_on) {
907  snprintf(buf, sizeof(buf), "run %s", kb->command);
908  run_dir(kb->direction);
909  } else {
911  }
912  } else {
914  }
915  return;
916  }
917 
918  if (key >= '0' && key <= '9') {
919  cpl.count = cpl.count * 10 + (key - '0');
920  if (cpl.count > 100000) {
921  cpl.count %= 100000;
922  }
923  gtk_spin_button_set_value(GTK_SPIN_BUTTON(spinbutton_count), (float) cpl.count);
924  return;
925  }
926  tmpbuf[0] = 0;
927  if (cpl.fire_on) {
928  strcat(tmpbuf, "fire+");
929  }
930  if (cpl.run_on) {
931  strcat(tmpbuf, "run+");
932  }
933  if (cpl.alt_on) {
934  strcat(tmpbuf, "alt+");
935  }
936  if (cpl.meta_on) {
937  strcat(tmpbuf, "meta+");
938  }
939 
940  snprintf(buf, sizeof(buf),
941  "Key %s%s is not bound to any command. Use 'bind' to associate this keypress with a command",
942  tmpbuf, keysym == NoSymbol ? "unknown" : gdk_keyval_name(keysym));
943 #ifdef WIN32
944  if ((65513 != keysym) && (65511 != keysym))
945 #endif
947  cpl.count = 0;
948 }
949 
950 static void get_key_modchars(struct keybind *kb, int save_mode, char *buf) {
951  int bi = 0;
952 
953  if (kb->flags & KEYF_ANY) {
954  buf[bi++] = 'A';
955  }
956  if (save_mode || !(kb->flags & KEYF_ANY)) {
957  if ((kb->flags & KEYF_MOD_MASK) == 0) {
958  buf[bi++] = 'N';
959  }
960  if (kb->flags & KEYF_MOD_SHIFT) {
961  buf[bi++] = 'F';
962  }
963  if (kb->flags & KEYF_MOD_CTRL) {
964  buf[bi++] = 'R';
965  }
966  if (kb->flags & KEYF_MOD_ALT) {
967  buf[bi++] = 'L';
968  }
969  if (kb->flags & KEYF_MOD_META) {
970  buf[bi++] = 'M';
971  }
972  }
973  if (kb->flags & KEYF_EDIT) {
974  buf[bi++] = 'E';
975  }
976 
977  buf[bi] = '\0';
978 }
979 
988 static char *get_key_info(struct keybind *kb, int save_mode) {
989  /* bind buf is the maximum space allowed for a
990  * bound command. We will add additional data to
991  * it so we increase its size by MAX_BUF*/
992  static char buf[MAX_BUF + sizeof(bind_buf)];
993 
994  char buff[MAX_BUF];
995 
996  get_key_modchars(kb, save_mode, buff);
997 
998  if (save_mode) {
999  if (kb->keysym == NoSymbol) {
1000  snprintf(buf, sizeof(buf), "(null) %i %s %s",
1001  0, buff, kb->command);
1002  } else {
1003  snprintf(buf, sizeof(buf), "%s %i %s %s",
1004  gdk_keyval_name(kb->keysym),
1005  0, buff, kb->command);
1006  }
1007  } else {
1008  if (kb->keysym == NoSymbol) {
1009  snprintf(buf, sizeof(buf), "key (null) %s %s",
1010  buff, kb->command);
1011  } else {
1012  snprintf(buf, sizeof(buf), "key %s %s %s",
1013  gdk_keyval_name(kb->keysym),
1014  buff, kb->command);
1015  }
1016  }
1017  return buf;
1018 }
1019 
1025 static void show_keys(void) {
1026  int i, j, count = 1;
1027  struct keybind *kb;
1028  char buf[MAX_BUF];
1029 
1030  snprintf(buf, sizeof(buf), "Commandkey %s",
1031  commandkeysym == NoSymbol ? "unknown" : gdk_keyval_name(commandkeysym));
1033 
1034  snprintf(buf, sizeof(buf), "Firekeys 1: %s, 2: %s",
1035  firekeysym[0] == NoSymbol ? "unknown" : gdk_keyval_name(firekeysym[0]),
1036  firekeysym[1] == NoSymbol ? "unknown" : gdk_keyval_name(firekeysym[1]));
1038 
1039  snprintf(buf, sizeof(buf), "Altkeys 1: %s, 2: %s",
1040  altkeysym[0] == NoSymbol ? "unknown" : gdk_keyval_name(altkeysym[0]),
1041  altkeysym[1] == NoSymbol ? "unknown" : gdk_keyval_name(altkeysym[1]));
1043 
1044  snprintf(buf, sizeof(buf), "Metakeys 1: %s, 2: %s",
1045  metakeysym[0] == NoSymbol ? "unknown" : gdk_keyval_name(metakeysym[0]),
1046  metakeysym[1] == NoSymbol ? "unknown" : gdk_keyval_name(metakeysym[1]));
1048 
1049  snprintf(buf, sizeof(buf), "Runkeys 1: %s, 2: %s",
1050  runkeysym[0] == NoSymbol ? "unknown" : gdk_keyval_name(runkeysym[0]),
1051  runkeysym[1] == NoSymbol ? "unknown" : gdk_keyval_name(runkeysym[1]));
1053 
1054  snprintf(buf, sizeof(buf), "Command Completion Key %s",
1055  completekeysym == NoSymbol ? "unknown" : gdk_keyval_name(completekeysym));
1057 
1058  snprintf(buf, sizeof(buf), "Next Command in History Key %s",
1059  nextkeysym == NoSymbol ? "unknown" : gdk_keyval_name(nextkeysym));
1061 
1062  snprintf(buf, sizeof(buf), "Previous Command in History Key %s",
1063  prevkeysym == NoSymbol ? "unknown" : gdk_keyval_name(prevkeysym));
1065 
1066  /*
1067  * Perhaps we should start at 8, so that we only show 'active' keybindings?
1068  */
1069  for (i = 0; i < KEYHASH; i++) {
1070  for (j = 0; j < 2; j++) {
1071  for (kb = (j == 0) ? keys_global[i] : keys_char[i]; kb != NULL; kb = kb->next) {
1072  snprintf(buf, sizeof(buf), "%3d %s", count, get_key_info(kb, 0));
1073  draw_ext_info(
1075  count++;
1076  }
1077  }
1078  }
1079 }
1080 
1089 void bind_key(char *params) {
1090  char buf[MAX_BUF + 16];
1091 
1092  if (!params) {
1094  "Usage: 'bind -ei {<commandline>,commandkey,firekey{1,2},runkey{1,2},altkey{1,2},metakey{1,2},completekey,nextkey,prevkey}'\n"
1095  "Where\n"
1096  " -e means enter edit mode\n"
1097  " -g means this binding should be global (used for all your characters)\n"
1098  " -i means ignore modifier keys (keybinding works no matter if Ctrl/Alt etc are held)");
1099  return;
1100  }
1101 
1102  /* Skip over any spaces we may have */
1103  while (*params == ' ') {
1104  params++;
1105  }
1106 
1107  if (!strcmp(params, "commandkey")) {
1110  "Push key to bind new commandkey.");
1112  return;
1113  }
1114 
1115  if (!strcmp(params, "firekey1")) {
1116  bind_keysym = &firekeysym[0];
1118  "Push key to bind new firekey 1.");
1120  return;
1121  }
1122  if (!strcmp(params, "firekey2")) {
1123  bind_keysym = &firekeysym[1];
1125  "Push key to bind new firekey 2.");
1127  return;
1128  }
1129  if (!strcmp(params, "metakey1")) {
1130  bind_keysym = &metakeysym[0];
1132  "Push key to bind new metakey 1.");
1134  return;
1135  }
1136  if (!strcmp(params, "metakey2")) {
1137  bind_keysym = &metakeysym[1];
1139  "Push key to bind new metakey 2.");
1141  return;
1142  }
1143  if (!strcmp(params, "altkey1")) {
1144  bind_keysym = &altkeysym[0];
1146  "Push key to bind new altkey 1.");
1148  return;
1149  }
1150  if (!strcmp(params, "altkey2")) {
1151  bind_keysym = &altkeysym[1];
1153  "Push key to bind new altkey 2.");
1155  return;
1156  }
1157  if (!strcmp(params, "runkey1")) {
1158  bind_keysym = &runkeysym[0];
1160  "Push key to bind new runkey 1.");
1162  return;
1163  }
1164 
1165  if (!strcmp(params, "runkey2")) {
1166  bind_keysym = &runkeysym[1];
1168  "Push key to bind new runkey 2.");
1170  return;
1171  }
1172 
1173  if (!strcmp(params, "completekey")) {
1176  "Push key to bind new command completion key");
1178  return;
1179  }
1180 
1181  if (!strcmp(params, "prevkey")) {
1184  "Push key to bind new previous command in history key.");
1186  return;
1187  }
1188 
1189  if (!strcmp(params, "nextkey")) {
1192  "Push key to bind new next command in history key.");
1194  return;
1195  }
1196  bind_keysym = NULL;
1197 
1198  bind_flags = 0;
1199  if (params[0] == '-') {
1200  for (params++; *params != ' '; params++)
1201  switch (*params) {
1202  case 'e':
1203  bind_flags |= KEYF_EDIT;
1204  break;
1205  case 'i':
1206  bind_flags |= KEYF_ANY;
1207  break;
1208  case 'g':
1210  break;
1211  case '\0':
1212  draw_ext_info(
1214  "Use unbind to remove bindings.");
1215  return;
1216  default:
1217  snprintf(buf, sizeof(buf),
1218  "Unsupported or invalid bind flag: '%c'", *params);
1220  return;
1221  }
1222  params++;
1223  }
1224 
1225  if (!params[0]) {
1227  "Use unbind to remove bindings.");
1228  return;
1229  }
1230 
1231  if (strlen(params) >= sizeof(bind_buf)) {
1232  params[sizeof(bind_buf) - 1] = '\0';
1234  "Keybinding too long! Truncated:");
1236  }
1237  snprintf(buf, sizeof(buf), "Push key to bind '%s'.", params);
1239 
1240  strcpy(bind_buf, params);
1242  return;
1243 }
1244 
1257 static void save_individual_key(FILE *fp, struct keybind *kb, KeyCode kc) {
1258  while (kb) {
1259  fprintf(fp, "%s\n", get_key_info(kb, 1));
1260  kb = kb->next;
1261  }
1262 }
1263 
1271 static void save_keys(void) {
1272  char buf[MAX_BUF], buf2[MAX_BUF];
1273  int i;
1274  FILE *fp;
1275 
1276  /* If we are logged in open file to save character specific bindings */
1277  if (cpl.name) {
1278  snprintf(buf, sizeof(buf), "%s/%s.%s.keys", config_dir,
1280  LOG(LOG_INFO, "gtk-v2::save_keys",
1281  "Saving character specific keybindings to %s", buf);
1282 
1283  if (make_path_to_file(buf) == -1) {
1284  LOG(LOG_WARNING, "gtk-v2::save_keys", "Could not create %s", buf);
1285  }
1286 
1287  fp = fopen(buf, "w");
1288  if (fp == NULL) {
1289  snprintf(buf2, sizeof(buf2),
1290  "Could not open %s, character bindings not saved\n", buf);
1292  } else {
1293  for (i = 0; i < KEYHASH; i++) {
1294  save_individual_key(fp, keys_char[i], 0);
1295  }
1296  fclose(fp);
1297  }
1298  }
1299 
1300  /* Open file to save global user bindings */
1301  snprintf(buf, sizeof(buf), "%s/keys", config_dir);
1302  LOG(LOG_INFO, "gtk-v2::save_keys",
1303  "Saving global user's keybindings to %s", buf);
1304 
1305  if (make_path_to_file(buf) == -1) {
1306  LOG(LOG_WARNING, "gtk-v2::save_keys", "Could not create %s", buf);
1307  } else {
1308  fp = fopen(buf, "w");
1309  if (fp == NULL) {
1310  snprintf(buf2, sizeof(buf2),
1311  "Could not open %s, global key bindings not saved\n", buf);
1313  } else {
1314  /* Save default bindings as part of the global scope */
1315  if (firekeysym[0] != GDK_KEY_Shift_L && firekeysym[0] != NoSymbol)
1316  fprintf(fp, "! firekey0 %s %d\n",
1317  gdk_keyval_name(firekeysym[0]), 0);
1318  if (firekeysym[1] != GDK_KEY_Shift_R && firekeysym[1] != NoSymbol)
1319  fprintf(fp, "! firekey1 %s %d\n",
1320  gdk_keyval_name(firekeysym[1]), 0);
1321  if (metakeysym[0] != GDK_KEY_Shift_L && metakeysym[0] != NoSymbol)
1322  fprintf(fp, "! metakey0 %s %d\n",
1323  gdk_keyval_name(metakeysym[0]), 0);
1324  if (metakeysym[1] != GDK_KEY_Shift_R && metakeysym[1] != NoSymbol)
1325  fprintf(fp, "! metakey1 %s %d\n",
1326  gdk_keyval_name(metakeysym[1]), 0);
1327  if (altkeysym[0] != GDK_KEY_Shift_L && altkeysym[0] != NoSymbol)
1328  fprintf(fp, "! altkey0 %s %d\n",
1329  gdk_keyval_name(altkeysym[0]), 0);
1330  if (altkeysym[1] != GDK_KEY_Shift_R && altkeysym[1] != NoSymbol)
1331  fprintf(fp, "! altkey1 %s %d\n",
1332  gdk_keyval_name(altkeysym[1]), 0);
1333  if (runkeysym[0] != GDK_KEY_Control_L && runkeysym[0] != NoSymbol)
1334  fprintf(fp, "! runkey0 %s %d\n",
1335  gdk_keyval_name(runkeysym[0]), 0);
1336  if (runkeysym[1] != GDK_KEY_Control_R && runkeysym[1] != NoSymbol)
1337  fprintf(fp, "! runkey1 %s %d\n",
1338  gdk_keyval_name(runkeysym[1]), 0);
1339  if (completekeysym != GDK_KEY_Tab && completekeysym != NoSymbol)
1340  fprintf(fp, "! completekey %s %d\n",
1341  gdk_keyval_name(completekeysym), 0);
1342  /* No defaults for these, so if it is set to anything, assume its valid */
1343  if (nextkeysym != NoSymbol)
1344  fprintf(fp, "! nextkey %s %d\n",
1345  gdk_keyval_name(nextkeysym), 0);
1346  if (prevkeysym != NoSymbol)
1347  fprintf(fp, "! prevkey %s %d\n",
1348  gdk_keyval_name(prevkeysym), 0);
1349 
1350  for (i = 0; i < KEYHASH; i++) {
1351  save_individual_key(fp, keys_global[i], 0);
1352  }
1353  fclose(fp);
1354  }
1355  }
1356 
1357  /* Should probably check return value on all writes to be sure, but... */
1359  "Key bindings saved.");
1360 }
1361 
1366 static void configure_keys(guint32 keysym) {
1367  char buf[MAX_BUF];
1368  struct keybind *kb;
1369 
1370  /* We handle the Shift key separately */
1371  keysym = gdk_keyval_to_lower(keysym);
1372 
1373  /*
1374  * I think that basically if we are not rebinding the special control keys
1375  * (in which case bind_keysym would be set to something) we just want to
1376  * handle these keypresses as normal events.
1377  */
1378  if (bind_keysym == NULL) {
1379  if (keysym == altkeysym[0] || keysym == altkeysym[1]) {
1380  cpl.alt_on = 1;
1381  return;
1382  }
1383  if (keysym == metakeysym[0] || keysym == metakeysym[1]) {
1384  cpl.meta_on = 1;
1385  return;
1386  }
1387  if (keysym == firekeysym[0] || keysym == firekeysym[1]) {
1388  cpl.fire_on = 1;
1390  return;
1391  }
1392  if (keysym == runkeysym[0] || keysym == runkeysym[1]) {
1393  cpl.run_on = 1;
1395  return;
1396  }
1397  }
1398 
1399  /*
1400  * Take shift/control keys into account when binding keys.
1401  */
1402  if (!(bind_flags & KEYF_ANY)) {
1403  if (cpl.fire_on) {
1405  }
1406  if (cpl.run_on) {
1408  }
1409  if (cpl.meta_on) {
1411  }
1412  if (cpl.alt_on) {
1414  }
1415  }
1416 
1417  /* Reset state now. We might return early if bind fails. */
1419 
1420  if (bind_keysym != NULL) {
1421  *bind_keysym = keysym;
1422  bind_keysym = NULL;
1423  } else {
1425  if (kb) {
1426  snprintf(buf, sizeof(buf),
1427  "Error: Key already used for command \"%s\". Use unbind first.",
1428  kb->command);
1429  draw_ext_info(
1431  return;
1432  } else {
1434  }
1435  }
1436 
1437  snprintf(buf, sizeof(buf), "Bound to key '%s' (%i)",
1438  keysym == NoSymbol ? "unknown" : gdk_keyval_name(keysym), keysym);
1441 
1442  /*
1443  * Do this each time a new key is bound. This way, we are never actually
1444  * storing any information that needs to be saved when the connection dies
1445  * or the player quits.
1446  */
1447  save_keys();
1448  return;
1449 }
1450 
1454 static void unbind_usage(void) {
1456  "Usage: 'unbind <entry_number>' or");
1458  "Usage: 'unbind' to show existing bindings");
1459 }
1460 
1465 void unbind_key(const char *params) {
1466  int count = 0, keyentry, slot, j;
1467  int res;
1468  struct keybind *kb;
1469  char buf[MAX_BUF];
1470 
1471  if (params == NULL) {
1472  show_keys();
1473  return;
1474  }
1475 
1476  /* Skip over any spaces we may have */
1477  while (*params == ' ') {
1478  params++;
1479  }
1480 
1481  if (params[0] == '\0') {
1482  show_keys();
1483  return;
1484  }
1485 
1486  if ((keyentry = atoi(params)) == 0) {
1487  unbind_usage();
1488  return;
1489  }
1490 
1491  for (slot = 0; slot < KEYHASH; slot++) {
1492  for (j = 0; j < 2; j++) {
1493  for (kb = (j == 0) ? keys_global[slot] : keys_char[slot]; kb != NULL;
1494  kb = kb->next) {
1495  count++;
1496 
1497  if (keyentry == count) {
1498  /* We found the key we want to unbind */
1499  snprintf(buf, sizeof(buf), "Removing binding: %3d %s",
1500  count, get_key_info(kb, 0));
1502  MSG_TYPE_CLIENT_CONFIG, buf);
1503  res = keybind_remove(kb);
1504  if (res < 0)
1505  LOG(LOG_ERROR, "gtk-v2::unbind_key",
1506  "found number entry, but could not find actual key");
1507  keybind_free(&kb);
1508  save_keys();
1509  return;
1510  }
1511  }
1512  }
1513  }
1514 
1515  /* Not found */
1516  /* Makes things look better to draw the blank line */
1519  "Not found. Try 'unbind' with no options to find entry.");
1520  return;
1521 }
1522 
1526 void focusoutfunc(GtkWidget *widget, GdkEventKey *event, GtkWidget *window) {
1527  if (cpl.fire_on == 1) {
1528  cpl.fire_on = 0;
1529  clear_fire();
1530  gtk_label_set_text(GTK_LABEL(fire_label), " ");
1531  }
1532  if (cpl.run_on == 1) {
1533  cpl.run_on = 0;
1534  clear_run();
1535  gtk_label_set_text(GTK_LABEL(run_label), " ");
1536  }
1537  if (cpl.alt_on == 1) {
1538  cpl.alt_on = 0;
1539  }
1540  if (cpl.meta_on == 1) {
1541  cpl.meta_on = 0;
1542  }
1543 }
1544 
1552 void keyrelfunc(GtkWidget *widget, GdkEventKey *event, GtkWidget *window) {
1553  if (event->keyval > 0 && !gtk_widget_has_focus(entry_commands)) {
1554  parse_key_release(event->keyval);
1555  debounce = false;
1556  }
1557  g_signal_stop_emission_by_name(GTK_WIDGET(window), "key_release_event");
1558 }
1559 
1567 void keyfunc(GtkWidget *widget, GdkEventKey *event, GtkWidget *window) {
1568  char *text;
1569 
1570  if (!use_config[CONFIG_POPUPS]) {
1571  if (((cpl.input_state == Reply_One) || (cpl.input_state == Reply_Many))
1572  && (event->keyval == cancelkeysym)) {
1573 
1574  /*
1575  * Player hit cancel button during input. Disconnect it (code from
1576  * menubar)
1577  */
1578 
1580 
1581  g_signal_stop_emission_by_name(
1582  GTK_WIDGET(window), "key_press_event");
1583  return;
1584  }
1585  if (cpl.input_state == Reply_One) {
1586  text = gdk_keyval_name(event->keyval);
1587  send_reply(text);
1589  g_signal_stop_emission_by_name(
1590  GTK_WIDGET(window), "key_press_event");
1591  return;
1592  } else if (cpl.input_state == Reply_Many) {
1593  if (gtk_widget_has_focus(entry_commands)) {
1594  gtk_widget_event(GTK_WIDGET(entry_commands), (GdkEvent *)event);
1595  } else {
1596  gtk_widget_grab_focus(GTK_WIDGET(entry_commands));
1597  }
1598  g_signal_stop_emission_by_name(
1599  GTK_WIDGET(window), "key_press_event");
1600  return;
1601  }
1602  }
1603  /*
1604  * Better check for really weirdo keys, X doesnt like keyval 0 so avoid
1605  * handling these key values.
1606  */
1607  if (event->keyval > 0) {
1608  if (gtk_widget_has_focus(entry_commands)) {
1609  if (event->keyval == completekeysym) {
1611  }
1612  if (event->keyval == prevkeysym || event->keyval == nextkeysym) {
1613  gtk_command_history(event->keyval == nextkeysym ? 0 : 1);
1614  } else {
1615  gtk_widget_event(GTK_WIDGET(entry_commands), (GdkEvent *)event);
1616  }
1617  } else {
1618  switch (cpl.input_state) {
1619  case Playing:
1620  /*
1621  * Specials - do command history - many times, the player
1622  * will want to go the previous command when nothing is
1623  * entered in the command window.
1624  */
1625  if ((event->keyval == prevkeysym)
1626  || (event->keyval == nextkeysym)) {
1627  gtk_command_history(event->keyval == nextkeysym ? 0 : 1);
1628  } else {
1629  if (cpl.run_on) {
1630  if (!(event->state & GDK_CONTROL_MASK)) {
1631  /* printf("Run is on while ctrl is not\n"); */
1632  gtk_label_set_text(GTK_LABEL(run_label), " ");
1633  cpl.run_on = 0;
1634  stop_run();
1635  }
1636  }
1637  if (cpl.fire_on) {
1638  if (!(event->state & GDK_SHIFT_MASK)) {
1639  /* printf("Fire is on while shift is not\n");*/
1640  gtk_label_set_text(GTK_LABEL(fire_label), " ");
1641  cpl.fire_on = 0;
1642  stop_fire();
1643  }
1644  }
1645 
1647  debounce = false;
1648  }
1649 
1650  if (!debounce) {
1651  parse_key(event->string[0], event->keyval);
1652  debounce = true;
1653  }
1654  }
1655  break;
1656 
1657  case Configure_Keys:
1658  configure_keys(event->keyval);
1659  break;
1660 
1661  case Command_Mode:
1662  if (event->keyval == completekeysym) {
1664  }
1665  if ((event->keyval == prevkeysym)
1666  || (event->keyval == nextkeysym)) {
1667  gtk_command_history(event->keyval == nextkeysym ? 0 : 1);
1668  } else {
1669  gtk_widget_grab_focus(GTK_WIDGET(entry_commands));
1670  /*
1671  * When running in split windows mode, entry_commands
1672  * can't get focus because it is in a different
1673  * window. So we have to pass the event to it
1674  * explicitly.
1675  */
1676  if (gtk_widget_has_focus(entry_commands) == 0)
1677  gtk_widget_event(
1678  GTK_WIDGET(entry_commands), (GdkEvent *)event);
1679  }
1680  /*
1681  * Don't pass signal along to default handlers -
1682  * otherwise, we get get crashes in the clist area (gtk
1683  * fault I believe)
1684  */
1685  break;
1686 
1687  case Metaserver_Select:
1688  gtk_widget_grab_focus(GTK_WIDGET(entry_commands));
1689  break;
1690 
1691  default:
1692  LOG(LOG_ERROR, "gtk-v2::keyfunc",
1693  "Unknown input state: %d", cpl.input_state);
1694  }
1695  }
1696  }
1697  g_signal_stop_emission_by_name(
1698  GTK_WIDGET(window), "key_press_event");
1699 }
1700 
1704 void x_set_echo(void) {
1705  gtk_entry_set_visibility(GTK_ENTRY(entry_commands), !cpl.no_echo);
1706 }
1707 
1713 void draw_prompt(const char *str) {
1715  gtk_widget_grab_focus(GTK_WIDGET(entry_commands));
1716 }
1717 
1724  int i = scroll_history_position;
1725  if (direction) {
1726  i--;
1727  if (i < 0) {
1728  i += MAX_HISTORY;
1729  }
1730  if (i == cur_history_position) {
1731  return;
1732  }
1733  } else {
1734  i++;
1735  if (i >= MAX_HISTORY) {
1736  i = 0;
1737  }
1738  if (i == cur_history_position) {
1739  /*
1740  * User has forwarded to what should be current entry - reset it
1741  * now.
1742  */
1743  gtk_entry_set_text(GTK_ENTRY(entry_commands), "");
1744  gtk_editable_set_position(GTK_EDITABLE(entry_commands), 0);
1746  return;
1747  }
1748  }
1749 
1750  if (history[i][0] == 0) {
1751  return;
1752  }
1753 
1755  /* fprintf(stderr, "resetting postion to %d, data = %s\n", i, history[i]);*/
1756  gtk_entry_set_text(GTK_ENTRY(entry_commands), history[i]);
1757  gtk_widget_grab_focus(GTK_WIDGET(entry_commands));
1758  gtk_editable_select_region(GTK_EDITABLE(entry_commands), 0, 0);
1759  gtk_editable_set_position(GTK_EDITABLE(entry_commands), -1);
1760 
1762 }
1763 
1771  const gchar *entry_text, *newcommand;
1772 
1773  entry_text = gtk_entry_get_text(GTK_ENTRY(entry_commands));
1774  newcommand = complete_command(entry_text);
1775  /* value differ, so update window */
1776  if (newcommand != NULL) {
1777  gtk_entry_set_text(GTK_ENTRY(entry_commands), newcommand);
1778  gtk_widget_grab_focus(GTK_WIDGET(entry_commands));
1779  gtk_editable_select_region(GTK_EDITABLE(entry_commands), 0, 0);
1780  gtk_editable_set_position(GTK_EDITABLE(entry_commands), -1);
1781  }
1782 }
1783 
1791 void on_entry_commands_activate(GtkEntry *entry, gpointer user_data) {
1792  const gchar *entry_text;
1793  extern GtkWidget *treeview_look;
1794 
1795  /* Next reply will reset this as necessary */
1796  if (!use_config[CONFIG_POPUPS]) {
1797  gtk_entry_set_visibility(GTK_ENTRY(entry), TRUE);
1798  }
1799 
1800  entry_text = gtk_entry_get_text(GTK_ENTRY(entry));
1801 
1803  strcpy(cpl.input_text, entry_text);
1804  } else if (cpl.input_state == Reply_One || cpl.input_state == Reply_Many) {
1806  strcpy(cpl.input_text, entry_text);
1807  if (cpl.input_state == Reply_One) {
1808  cpl.input_text[1] = 0;
1809  }
1810 
1812 
1813  } else {
1815  /* No reason to do anything for a null string */
1816  if (entry_text[0] != 0) {
1817  strncpy(history[cur_history_position], entry_text, MAX_COMMAND_LEN);
1822  extended_command(entry_text);
1823  }
1824  }
1825  gtk_entry_set_text(GTK_ENTRY(entry), "");
1826 
1827  /*
1828  * This grab focus is really just so the entry box doesn't have focus -
1829  * this way, keypresses are used to play the game, and not as stuff that
1830  * goes into the entry box. It doesn't make much difference what widget
1831  * this is set to, as long as it is something that can get focus.
1832  */
1833  gtk_widget_grab_focus(GTK_WIDGET(treeview_look));
1834 
1837  /*
1838  * This is the gtk_main that is started up by get_metaserver The client
1839  * will start another one once it is connected to a crossfire server
1840  */
1841  gtk_main_quit();
1842  }
1843 }
1844 
1858  int i, j;
1859  struct keybind *kb;
1860  char *modifier_label, *scope_label;
1861  GtkTreeIter iter;
1862 
1863  gtk_list_store_clear(keybinding_store);
1864  for (i = 0; i < KEYHASH; i++) {
1865  for (j = 0; j < 2; j++) {
1866  for (kb = (j == 0) ? keys_global[i] : keys_char[i]; kb != NULL; kb = kb->next) {
1867  if (j == 0) {
1868  kb->flags |= KEYF_R_GLOBAL;
1869  } else {
1870  kb->flags |= KEYF_R_CHAR;
1871  }
1872 
1873  if (kb->flags & KEYF_ANY) {
1874  modifier_label = "Any";
1875  } else if ((kb->flags & KEYF_MOD_MASK) == 0) {
1876  modifier_label = "None";
1877  } else {
1878  if (kb->flags & KEYF_MOD_ALT) {
1879  modifier_label = "Alt";
1880  if (kb->flags & (KEYF_MOD_SHIFT | KEYF_MOD_CTRL | KEYF_MOD_META)) {
1881  modifier_label = " + ";
1882  }
1883  }
1884  if (kb->flags & KEYF_MOD_SHIFT) {
1885  modifier_label = "Fire";
1886  if (kb->flags & (KEYF_MOD_CTRL | KEYF_MOD_META)) {
1887  modifier_label = " + ";
1888  }
1889  }
1890  if (kb->flags & KEYF_MOD_CTRL) {
1891  modifier_label = "Run";
1892  if (kb->flags & KEYF_MOD_META) {
1893  modifier_label = " + ";
1894  }
1895  }
1896  if (kb->flags & KEYF_MOD_META) {
1897  modifier_label = "Meta";
1898  }
1899  }
1900  if (!(kb->flags & KEYF_R_GLOBAL)) {
1901  scope_label = "char";
1902  } else {
1903  scope_label = "global";
1904  }
1905  gtk_list_store_append(keybinding_store, &iter);
1906  gtk_list_store_set(keybinding_store, &iter,
1907  KLIST_ENTRY, i,
1908  KLIST_KEY, gdk_keyval_name(kb->keysym),
1909  KLIST_MODS, modifier_label,
1910  KLIST_SCOPE, scope_label,
1911  KLIST_EDIT, (kb->flags & KEYF_EDIT) ? "Yes" : "No",
1912  KLIST_COMMAND, kb->command,
1913  KLIST_KEY_ENTRY, kb,
1914  -1);
1915  }
1916  }
1917  }
1919 }
1920 
1927 void on_keybindings_activate(GtkMenuItem *menuitem, gpointer user_data) {
1928  gtk_widget_show(keybinding_window);
1930 }
1931 
1944 gboolean
1946  GdkEventKey *event,
1947  gpointer user_data) {
1948  gtk_entry_set_text(
1949  GTK_ENTRY(keybinding_entry_key), gdk_keyval_name(event->keyval));
1950  /*
1951  * This code is basically taken from the GTKv1 client. However, at some
1952  * level it is broken, since the control/shift/etc masks are hardcoded, yet
1953  * we do let the users redefine them.
1954  *
1955  * The clearing of the modifiers is disabled. In my basic testing, I
1956  * checked the modifiers and then pressed the key - have those modifiers go
1957  * away I think is less intuitive.
1958  */
1959  if (event->state & GDK_CONTROL_MASK)
1960  gtk_toggle_button_set_active(
1961  GTK_TOGGLE_BUTTON(keybinding_checkbutton_control), TRUE);
1962 
1963 #if 0
1964  else
1965  gtk_toggle_button_set_active(
1966  GTK_TOGGLE_BUTTON(keybinding_checkbutton_control), FALSE);
1967 #endif
1968 
1969  if (event->state & GDK_SHIFT_MASK)
1970  gtk_toggle_button_set_active(
1971  GTK_TOGGLE_BUTTON(keybinding_checkbutton_shift), TRUE);
1972 
1973 #if 0
1974  else {
1975  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(keybinding_checkbutton_shift),
1976  FALSE);
1977  }
1978 
1979  /* The GDK_MOD_MASK* will likely correspond to alt and meta, yet there is
1980  * no way to be sure what goes to what, so easiest to just not allow them.
1981  */
1982  gtk_toggle_button_set_active(
1983  GTK_TOGGLE_BUTTON(keybinding_checkbutton_alt), FALSE);
1984  gtk_toggle_button_set_active(
1985  GTK_TOGGLE_BUTTON(keybinding_checkbutton_meta), FALSE);
1986 #endif
1987 
1988  /* Returning TRUE prevents widget from getting this event */
1989  return TRUE;
1990 }
1991 
1998 void toggle_buttons_scope(int scope) {
1999  int state_u, state_c;
2000 
2001  state_u = gtk_toggle_button_get_active(
2002  GTK_TOGGLE_BUTTON(kb_scope_togglebutton_global));
2003  state_c = gtk_toggle_button_get_active(
2004  GTK_TOGGLE_BUTTON(kb_scope_togglebutton_character));
2005  /* If the states of the buttons are not already what we are asked for, or if
2006  * they are equal (which is inconsistent) then update them. Deactivate the
2007  * callbacks for the "toggled" events temporarily to avoid an infinite loop.
2008  */
2009  if (state_u != scope || state_u == state_c) {
2010  g_signal_handlers_block_by_func(
2011  GTK_TOGGLE_BUTTON(kb_scope_togglebutton_character),
2012  G_CALLBACK(on_kb_scope_togglebutton_character_toggled), NULL);
2013  g_signal_handlers_block_by_func(
2014  GTK_TOGGLE_BUTTON(kb_scope_togglebutton_global),
2015  G_CALLBACK(on_kb_scope_togglebutton_global_toggled), NULL);
2016 
2017  gtk_toggle_button_set_active(
2018  GTK_TOGGLE_BUTTON(kb_scope_togglebutton_character), !scope);
2019  gtk_toggle_button_set_active(
2020  GTK_TOGGLE_BUTTON(kb_scope_togglebutton_global), scope);
2021 
2022  g_signal_handlers_unblock_by_func(
2023  GTK_TOGGLE_BUTTON(kb_scope_togglebutton_character),
2024  G_CALLBACK(on_kb_scope_togglebutton_character_toggled), NULL);
2025  g_signal_handlers_unblock_by_func(
2026  GTK_TOGGLE_BUTTON(kb_scope_togglebutton_global),
2027  G_CALLBACK(on_kb_scope_togglebutton_global_toggled), NULL);
2028  }
2029 }
2030 
2038 static int keybind_overwrite_confirm(struct keybind *kb) {
2039  GtkWidget *dialog, *label;
2040  int result;
2041  char buf[MAX_BUF], buf2[MAX_BUF];
2042 
2043  dialog = gtk_dialog_new_with_buttons(
2044  "Key already in use",
2045  GTK_WINDOW(keybinding_window),
2046  GTK_DIALOG_MODAL,
2047  GTK_STOCK_YES, 1,
2048  GTK_STOCK_NO, 2,
2049  NULL);
2050  get_key_modchars(kb, 1, buf2);
2051  snprintf(buf, sizeof(buf), "Overwrite this binding?\n (%s) %s\n%s",
2052  buf2, gdk_keyval_name(kb->keysym), kb->command);
2053  label = gtk_label_new(buf);
2054  gtk_box_pack_start(
2055  GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))),
2056  label, TRUE, TRUE, 0);
2057  gtk_widget_show_all(dialog);
2058 
2059  result = gtk_dialog_run(GTK_DIALOG(dialog));
2060  gtk_widget_destroy(dialog);
2061  return (result == 1);
2062 }
2063 
2073 void toggle_keybind_scope(int scope, struct keybind *kb) {
2074  struct keybind *kb_old, **next_ptr;
2075  int ret, flags;
2076  char buf[MAX_BUF];
2077 
2078  /* First check for matching bindings in the new scope */
2079  kb_old = keybind_find(kb->keysym, kb->flags, scope);
2080  while (kb_old) {
2081  if (!keybind_overwrite_confirm(kb_old)) {
2082  /* Restore all bindings and buttons state.
2083  * Need to call keybindings_init() because we may have already
2084  * removed some bindings from memory */
2085  toggle_buttons_scope(!scope);
2088  return;
2089  }
2090  /* Completely remove the old binding */
2091  keybind_remove(kb_old);
2092  keybind_free(&kb_old);
2093  kb_old = keybind_find(kb->keysym, kb->flags, scope);
2094  }
2095 
2096  /* If the new scope is 'global' we remove the binding from keys_char (don't
2097  * free it), switch scope flags and rehash in keys_global.
2098  *
2099  * Else just make a copy into keys_char only switching the state flags.
2100  */
2101  if (scope) {
2102  if ((kb->flags & KEYF_R_GLOBAL) == 0) {
2103  /* Remove kb from keys_char, don't free it. */
2104  ret = keybind_remove(kb);
2105  if (ret == -1) {
2107  "\nCould not remove keybind. Operation failed.\n");
2108  toggle_buttons_scope(!scope);
2111  return;
2112  }
2113  /* Place the modified kb in keys_global */
2114  kb->flags ^= KEYF_R_CHAR;
2115  kb->flags |= KEYF_R_GLOBAL;
2116  next_ptr = &keys_global[kb->keysym % KEYHASH];
2117  kb->next = NULL;
2118 
2119  if (*next_ptr) {
2120  while ((*next_ptr)->next) {
2121  next_ptr = &(*next_ptr)->next;
2122  }
2123  (*next_ptr)->next = kb;
2124  } else {
2125  keys_global[kb->keysym % KEYHASH] = kb;
2126  }
2127  }
2128  } else {
2129  if ((kb->flags & KEYF_R_GLOBAL) != 0) {
2130  /* Copy the selected binding in the char's scope with the right flags. */
2131  snprintf(buf, sizeof(buf), "%s", kb->command);
2132  flags = kb->flags;
2133  flags |= KEYF_R_CHAR;
2134  flags ^= KEYF_R_GLOBAL;
2135  keybind_insert(kb->keysym, flags, buf);
2136  }
2137  }
2138  save_keys();
2140 }
2141 
2149 void on_kb_scope_togglebutton_character_toggled(GtkToggleButton *toggle_button,
2150  gpointer user_data) {
2151  GtkTreeModel *model;
2152  GtkTreeIter iter;
2153  struct keybind *kb;
2154  gboolean scope;
2155  if (gtk_tree_selection_get_selected(keybinding_selection, &model, &iter)) {
2156  gtk_tree_model_get(model, &iter, KLIST_KEY_ENTRY, &kb, -1);
2157  scope = !gtk_toggle_button_get_active(
2158  GTK_TOGGLE_BUTTON(kb_scope_togglebutton_character));
2159  toggle_buttons_scope(scope);
2160  toggle_keybind_scope(scope, kb);
2161  }
2162 }
2163 
2171 void on_kb_scope_togglebutton_global_toggled(GtkToggleButton *toggle_button,
2172  gpointer user_data) {
2173  GtkTreeModel *model;
2174  GtkTreeIter iter;
2175  struct keybind *kb;
2176  gboolean scope;
2177  if (gtk_tree_selection_get_selected(keybinding_selection, &model, &iter)) {
2178  gtk_tree_model_get(model, &iter, KLIST_KEY_ENTRY, &kb, -1);
2179  scope = gtk_toggle_button_get_active(
2180  GTK_TOGGLE_BUTTON(kb_scope_togglebutton_global));
2181  toggle_buttons_scope(scope);
2182  toggle_keybind_scope(scope, kb);
2183  }
2184 }
2185 
2194  gpointer user_data) {
2195  GtkTreeModel *model;
2196  GtkTreeIter iter;
2197  struct keybind *kb;
2198  int res;
2199 
2200  if (!gtk_tree_selection_get_selected(keybinding_selection, &model, &iter)) {
2201  LOG(LOG_ERROR, "keys.c::on_keybinding_button_remove_clicked",
2202  "Function called with nothing selected\n");
2203  return;
2204  }
2205  gtk_tree_model_get(model, &iter, KLIST_KEY_ENTRY, &kb, -1);
2206  res = keybind_remove(kb);
2207  if (res < 0)
2208  LOG(LOG_ERROR, "keys.c::on_keybinding_button_remove_clicked",
2209  "Unable to find matching key entry\n");
2210  keybind_free(&kb);
2211 
2212  save_keys();
2214 }
2215 
2225 static void keybinding_get_data(guint32 *keysym, guint8 *flags,
2226  const char **command) {
2227  static char bind_buf[MAX_BUF];
2228  const char *ed;
2229  *flags = 0;
2230 
2231  if (gtk_toggle_button_get_active(
2232  GTK_TOGGLE_BUTTON(keybinding_checkbutton_any))) {
2233  *flags |= KEYF_ANY;
2234  }
2235 
2236  if (gtk_toggle_button_get_active(
2237  GTK_TOGGLE_BUTTON(kb_scope_togglebutton_global))) {
2238  *flags |= KEYF_R_GLOBAL;
2239  }
2240 
2241  if (gtk_toggle_button_get_active(
2242  GTK_TOGGLE_BUTTON(keybinding_checkbutton_control))) {
2243  *flags |= KEYF_MOD_CTRL;
2244  }
2245  if (gtk_toggle_button_get_active(
2246  GTK_TOGGLE_BUTTON(keybinding_checkbutton_shift))) {
2247  *flags |= KEYF_MOD_SHIFT;
2248  }
2249  if (gtk_toggle_button_get_active(
2250  GTK_TOGGLE_BUTTON(keybinding_checkbutton_alt))) {
2251  *flags |= KEYF_MOD_ALT;
2252  }
2253  if (gtk_toggle_button_get_active(
2254  GTK_TOGGLE_BUTTON(keybinding_checkbutton_meta))) {
2255  *flags |= KEYF_MOD_META;
2256  }
2257  if (gtk_toggle_button_get_active(
2258  GTK_TOGGLE_BUTTON(keybinding_checkbutton_edit))) {
2259  *flags |= KEYF_EDIT;
2260  }
2261 
2262  ed = gtk_entry_get_text(GTK_ENTRY(keybinding_entry_command));
2263  if (strlen(ed) >= sizeof(bind_buf)) {
2265  "Keybinding too long! Truncated.");
2266  strncpy(bind_buf, ed, MAX_BUF - 1);
2267  bind_buf[MAX_BUF - 1] = 0;
2268  *command = bind_buf;
2269  } else {
2270  *command = ed;
2271  }
2272 
2273  /*
2274  * This isn't ideal - when the key is pressed, we convert it to a string,
2275  * and now we are converting it back. It'd be nice to tuck the keysym
2276  * itself away someplace.
2277  */
2278  *keysym = gdk_keyval_from_name(
2279  gtk_entry_get_text(GTK_ENTRY(keybinding_entry_key)));
2280  if (*keysym == GDK_KEY_VoidSymbol) {
2281  LOG(LOG_ERROR, "keys.c::keybinding_get_data",
2282  "Cannot get valid keysym from selection");
2283  }
2284 }
2285 
2292 void on_keybinding_button_bind_clicked(GtkButton *button, gpointer user_data) {
2293  guint32 keysym;
2294  guint8 flags;
2295  const char *command;
2296  struct keybind *kb;
2297 
2299 
2300  /* keybind_insert will do a g_strdup of command for us */
2302  if (kb && (!keybind_overwrite_confirm(kb))) {
2303  return;
2304  }
2306 
2307  /*
2308  * I think it is more appropriate to clear the fields once the user adds
2309  * it. I suppose the ideal case would be to select the newly inserted
2310  * keybinding.
2311  */
2313  save_keys();
2315 }
2316 
2327  gpointer user_data) {
2328  GtkTreeIter iter;
2329  struct keybind *kb;
2330  GtkTreeModel *model;
2331  guint32 keysym;
2332  guint8 flags;
2333  const char *buf;
2334  int res;
2335 
2336  if (gtk_tree_selection_get_selected(keybinding_selection, &model, &iter)) {
2337  gtk_tree_model_get(model, &iter, KLIST_KEY_ENTRY, &kb, -1);
2338 
2339  if (!kb) {
2340  LOG(LOG_ERROR, "keys.c::on_keybinding_button_update_clicked",
2341  "Unable to get key_entry structure\n");
2342  return;
2343  }
2344 
2345  /* We need to rehash the binding (remove the old and add the
2346  * new) since the keysym might have changed. */
2347 
2348  keybind_remove(kb);
2349 
2350  keybinding_get_data(&keysym, &flags, &buf);
2351 
2352  res = keybind_insert(keysym, flags, buf);
2353  if (res == 0) {
2354  keybind_free(&kb);
2355  } else {
2356  /* Re-enter old binding if the update failed */
2357  keybind_insert(kb->keysym, kb->flags, kb->command);
2358  // FIXME: Popup dialog key in use
2359  }
2360 
2361  save_keys();
2363  } else {
2364  LOG(LOG_ERROR, "keys.c::on_keybinding_button_update_clicked",
2365  "Nothing selected to update\n");
2366  }
2367 }
2368 
2375 void on_keybinding_button_close_clicked(GtkButton *button, gpointer user_data) {
2376  gtk_widget_hide(keybinding_window);
2377 }
2378 
2386  gpointer user_data) {
2387  gboolean enabled;
2388 
2389  enabled = !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cb));
2390 
2391  gtk_widget_set_sensitive(GTK_WIDGET(keybinding_checkbutton_control), enabled);
2392  gtk_widget_set_sensitive(GTK_WIDGET(keybinding_checkbutton_shift), enabled);
2393  gtk_widget_set_sensitive(GTK_WIDGET(keybinding_checkbutton_alt), enabled);
2394  gtk_widget_set_sensitive(GTK_WIDGET(keybinding_checkbutton_meta), enabled);
2395 }
2396 
2410  GtkTreeSelection *selection,
2411  GtkTreeModel *model,
2412  GtkTreePath *path,
2413  gboolean path_currently_selected,
2414  gpointer userdata) {
2415  GtkTreeIter iter;
2416  struct keybind *kb;
2417 
2418  gtk_widget_set_sensitive(keybinding_button_remove, TRUE);
2419  gtk_widget_set_sensitive(keybinding_button_update, TRUE);
2420 
2421  if (gtk_tree_model_get_iter(model, &iter, path)) {
2422 
2423  gtk_tree_model_get(model, &iter, KLIST_KEY_ENTRY, &kb, -1);
2424 
2425  if (!kb) {
2426  LOG(LOG_ERROR, "keys.c::keybinding_selection_func",
2427  "Unable to get key_entry structure\n");
2428  return FALSE;
2429  }
2430  if (kb->flags & KEYF_ANY)
2431  gtk_toggle_button_set_active(
2432  GTK_TOGGLE_BUTTON(keybinding_checkbutton_any), TRUE);
2433  else
2434  gtk_toggle_button_set_active(
2435  GTK_TOGGLE_BUTTON(keybinding_checkbutton_any), FALSE);
2436 
2437  if (kb->flags & KEYF_MOD_CTRL)
2438  gtk_toggle_button_set_active(
2439  GTK_TOGGLE_BUTTON(keybinding_checkbutton_control), TRUE);
2440  else
2441  gtk_toggle_button_set_active(
2442  GTK_TOGGLE_BUTTON(keybinding_checkbutton_control), FALSE);
2443 
2444  if (kb->flags & KEYF_MOD_SHIFT)
2445  gtk_toggle_button_set_active(
2446  GTK_TOGGLE_BUTTON(keybinding_checkbutton_shift), TRUE);
2447  else
2448  gtk_toggle_button_set_active(
2449  GTK_TOGGLE_BUTTON(keybinding_checkbutton_shift), FALSE);
2450 
2451  if (kb->flags & KEYF_MOD_ALT)
2452  gtk_toggle_button_set_active(
2453  GTK_TOGGLE_BUTTON(keybinding_checkbutton_alt), TRUE);
2454  else
2455  gtk_toggle_button_set_active(
2456  GTK_TOGGLE_BUTTON(keybinding_checkbutton_alt), FALSE);
2457 
2458  if (kb->flags & KEYF_MOD_META)
2459  gtk_toggle_button_set_active(
2460  GTK_TOGGLE_BUTTON(keybinding_checkbutton_meta), TRUE);
2461  else
2462  gtk_toggle_button_set_active(
2463  GTK_TOGGLE_BUTTON(keybinding_checkbutton_meta), FALSE);
2464 
2465  if (kb->flags & KEYF_EDIT)
2466  gtk_toggle_button_set_active(
2467  GTK_TOGGLE_BUTTON(keybinding_checkbutton_edit), TRUE);
2468  else
2469  gtk_toggle_button_set_active(
2470  GTK_TOGGLE_BUTTON(keybinding_checkbutton_edit), FALSE);
2471 
2472  gtk_entry_set_text(
2473  GTK_ENTRY(keybinding_entry_key), gdk_keyval_name(kb->keysym));
2474  gtk_entry_set_text(
2475  GTK_ENTRY(keybinding_entry_command), kb->command);
2476 
2478  }
2479  return TRUE;
2480 }
2481 
2488  gtk_toggle_button_set_active(
2489  GTK_TOGGLE_BUTTON(keybinding_checkbutton_any), FALSE);
2490  gtk_toggle_button_set_active(
2491  GTK_TOGGLE_BUTTON(keybinding_checkbutton_control), FALSE);
2492  gtk_toggle_button_set_active(
2493  GTK_TOGGLE_BUTTON(keybinding_checkbutton_shift), FALSE);
2494  gtk_toggle_button_set_active(
2495  GTK_TOGGLE_BUTTON(keybinding_checkbutton_alt), FALSE);
2496  gtk_toggle_button_set_active(
2497  GTK_TOGGLE_BUTTON(keybinding_checkbutton_meta), FALSE);
2498  gtk_toggle_button_set_active(
2499  GTK_TOGGLE_BUTTON(keybinding_checkbutton_edit), FALSE);
2500  gtk_entry_set_text(GTK_ENTRY(keybinding_entry_key), "");
2501  gtk_entry_set_text(GTK_ENTRY(keybinding_entry_command), "");
2502 
2503  toggle_buttons_scope(FALSE);
2504 
2505  gtk_widget_set_sensitive(keybinding_button_remove, FALSE);
2506  gtk_widget_set_sensitive(keybinding_button_update, FALSE);
2507 }
2508 
2517 void on_keybinding_button_clear_clicked(GtkButton *button, gpointer user_data) {
2518  GtkTreeModel *model;
2519  GtkTreeIter iter;
2520 
2521  /*
2522  * As the cleared state is not supposed to have a keybinding selected,
2523  * deselect the currently selected keybinding if there is one.
2524  */
2525  if (gtk_tree_selection_get_selected(keybinding_selection, &model, &iter)) {
2526  gtk_tree_selection_unselect_iter(keybinding_selection, &iter);
2527  }
2528  reset_keybinding_status(); /* Clear inputs and reset buttons. */
2529 }
2530 
run_dir
void run_dir(int dir)
Definition: player.c:150
keybinding_checkbutton_control
static GtkWidget * keybinding_checkbutton_control
Definition: keys.c:52
keybind_overwrite_confirm
static int keybind_overwrite_confirm(struct keybind *kb)
Definition: keys.c:2038
LOG_INFO
@ LOG_INFO
Minor, non-harmful issues.
Definition: client.h:434
update_keybinding_list
void update_keybinding_list(void)
Definition: keys.c:1857
MSG_TYPE_CLIENT
#define MSG_TYPE_CLIENT
Definition: newclient.h:387
keybinding_window
static GtkWidget * keybinding_window
Definition: keys.c:49
save_individual_key
static void save_individual_key(FILE *fp, struct keybind *kb, KeyCode kc)
Definition: keys.c:1257
LOG_WARNING
@ LOG_WARNING
Warning that something might not work.
Definition: client.h:435
Playing
@ Playing
Definition: client.h:145
init_default_keybindings
static void init_default_keybindings()
Definition: keys.c:517
keybinding_store
static GtkListStore * keybinding_store
Definition: keys.c:59
on_entry_commands_activate
void on_entry_commands_activate(GtkEntry *entry, gpointer user_data)
Definition: keys.c:1791
keyfunc
void keyfunc(GtkWidget *widget, GdkEventKey *event, GtkWidget *window)
Definition: keys.c:1567
on_keybindings_activate
void on_keybindings_activate(GtkMenuItem *menuitem, gpointer user_data)
Definition: keys.c:1927
keybind_free
static void keybind_free(struct keybind **entry)
Definition: keys.c:301
Player_Struct::fire_on
guint32 fire_on
Definition: client.h:352
keybinding_get_data
static void keybinding_get_data(guint32 *keysym, guint8 *flags, const char **command)
Definition: keys.c:2225
BIG_BUF
#define BIG_BUF
Definition: client.h:41
on_count_changed
static void on_count_changed(GtkSpinButton *spinbutton, gpointer *data)
Definition: keys.c:637
ClientSocket::command_received
guint16 command_received
Definition: client.h:127
keybindings_init
void keybindings_init(const char *character_name)
Definition: keys.c:532
KEYF_MOD_SHIFT
#define KEYF_MOD_SHIFT
Definition: keys.c:138
Player_Struct::input_state
Input_State input_state
Definition: client.h:339
client_disconnect
void client_disconnect()
Definition: client.c:175
keybind::keysym
guint32 keysym
Definition: keys.c:102
keys_global
static struct keybind * keys_global[KEYHASH]
Definition: keys.c:166
extended_command
void extended_command(const char *ocommand)
Definition: p_cmd.c:515
keybinding_entry_key
static GtkWidget * keybinding_entry_key
Definition: keys.c:54
Player_Struct::run_on
guint32 run_on
Definition: client.h:353
EKEYBIND_NOMEM
#define EKEYBIND_NOMEM
Definition: keys.c:173
Configure_Keys
@ Configure_Keys
Definition: client.h:146
keybinding_treeview
static GtkWidget * keybinding_treeview
Definition: keys.c:55
parse_key
static void parse_key(char key, guint32 keysym)
Definition: keys.c:839
KEYF_MOD_MASK
#define KEYF_MOD_MASK
Definition: keys.c:142
Player_Struct::meta_on
guint32 meta_on
Definition: client.h:354
on_keybinding_button_bind_clicked
void on_keybinding_button_bind_clicked(GtkButton *button, gpointer user_data)
Definition: keys.c:2292
toggle_buttons_scope
void toggle_buttons_scope(int scope)
Definition: keys.c:1998
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)
Definition: keys.c:2171
toggle_keybind_scope
void toggle_keybind_scope(int scope, struct keybind *kb)
Definition: keys.c:2073
stop_fire
void stop_fire()
Definition: player.c:108
history
char history[MAX_HISTORY][MAX_COMMAND_LEN]
Definition: keys.c:87
treeview_look
GtkWidget * treeview_look
Definition: inventory.c:38
keybind_find
static struct keybind * keybind_find(guint32 keysym, unsigned int flags, int scope)
Definition: keys.c:198
NDI_RED
#define NDI_RED
Definition: newclient.h:224
keybind
Definition: keys.c:99
KEYF_EDIT
#define KEYF_EDIT
Definition: keys.c:148
bind_keysym
static guint32 * bind_keysym
Definition: keys.c:119
keybind::flags
guint8 flags
Definition: keys.c:100
KEYF_MOD_CTRL
#define KEYF_MOD_CTRL
Definition: keys.c:139
Player_Struct::input_text
char input_text[MAX_BUF]
Definition: client.h:341
clear_fire
void clear_fire()
Definition: player.c:115
MSG_TYPE_CLIENT_ERROR
#define MSG_TYPE_CLIENT_ERROR
Definition: newclient.h:638
KLIST_ENTRY
@ KLIST_ENTRY
Definition: keys.c:74
commandkeysym
static guint32 commandkeysym
Definition: keys.c:119
spinbutton_count
GtkWidget * spinbutton_count
Definition: keys.c:62
MAX_COMMAND_LEN
#define MAX_COMMAND_LEN
Definition: keys.c:86
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)
Definition: keys.c:1945
in
static GInputStream * in
Definition: client.c:71
KEYF_ANY
#define KEYF_ANY
Definition: keys.c:147
run_label
static GtkWidget * run_label
Definition: keys.c:49
keybinding_checkbutton_shift
static GtkWidget * keybinding_checkbutton_shift
Definition: keys.c:52
parse_keys_file
static int parse_keys_file(GInputStream *in, unsigned int scope_flag)
Definition: keys.c:502
runkeysym
static guint32 runkeysym[2]
Definition: keys.c:119
proto.h
MAX_BUF
#define MAX_BUF
Definition: client.h:40
keybinding_button_update
static GtkWidget * keybinding_button_update
Definition: keys.c:56
KLIST_KEY
@ KLIST_KEY
Definition: keys.c:74
on_keybinding_button_update_clicked
void on_keybinding_button_update_clicked(GtkButton *button, gpointer user_data)
Definition: keys.c:2326
KEYF_R_CHAR
#define KEYF_R_CHAR
Definition: keys.c:152
focusoutfunc
void focusoutfunc(GtkWidget *widget, GdkEventKey *event, GtkWidget *window)
Definition: keys.c:1526
cancelkeysym
static guint32 cancelkeysym
Definition: keys.c:121
ClientSocket::servername
char * servername
Definition: client.h:135
gtk_complete_command
void gtk_complete_command(void)
Definition: keys.c:1770
on_keybinding_button_clear_clicked
void on_keybinding_button_clear_clicked(GtkButton *button, gpointer user_data)
Definition: keys.c:2517
gtk2proto.h
show_keys
static void show_keys(void)
Definition: keys.c:1025
keybind::command
char * command
Definition: keys.c:103
complete_command
const char * complete_command(const char *command)
Definition: p_cmd.c:614
cur_history_position
static int cur_history_position
Definition: keys.c:89
LOG
void LOG(LogLevel level, const char *origin, const char *format,...)
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)
Definition: keys.c:227
send_reply
void send_reply(const char *text)
Definition: commands.c:1612
config_dir
const char * config_dir
Definition: client.c:52
Player_Struct::alt_on
guint32 alt_on
Definition: client.h:355
clear_run
void clear_run()
Definition: player.c:122
KEYHASH
#define KEYHASH
Definition: keys.c:156
keybind_remove
static int keybind_remove(struct keybind *entry)
Definition: keys.c:281
kb_scope_togglebutton_global
static GtkWidget * kb_scope_togglebutton_global
Definition: keys.c:50
draw_ext_info
void draw_ext_info(int orig_color, int type, int subtype, const char *message)
Definition: info.c:915
csocket
ClientSocket csocket
Definition: client.c:70
KLIST_COMMAND
@ KLIST_COMMAND
Definition: keys.c:74
NDI_BLACK
#define NDI_BLACK
Definition: newclient.h:221
image.h
KEYF_R_GLOBAL
#define KEYF_R_GLOBAL
Definition: keys.c:151
on_keybinding_button_close_clicked
void on_keybinding_button_close_clicked(GtkButton *button, gpointer user_data)
Definition: keys.c:2375
Player_Struct::no_echo
guint32 no_echo
Definition: client.h:356
configure_keys
static void configure_keys(guint32 keysym)
Definition: keys.c:1366
kb_scope_togglebutton_character
static GtkWidget * kb_scope_togglebutton_character
Definition: keys.c:50
keybinding_checkbutton_alt
static GtkWidget * keybinding_checkbutton_alt
Definition: keys.c:53
KLIST_KEY_ENTRY
@ KLIST_KEY_ENTRY
Definition: keys.c:75
altkeysym
static guint32 altkeysym[2]
Definition: keys.c:120
keys_init
void keys_init(GtkWidget *window_root)
Definition: keys.c:648
prevkeysym
static guint32 prevkeysym
Definition: keys.c:120
Player_Struct::name
char * name
Definition: client.h:367
KLIST_EDIT
@ KLIST_EDIT
Definition: keys.c:74
draw_prompt
void draw_prompt(const char *str)
Definition: keys.c:1713
p_cmd.h
keybinding_entry_command
static GtkWidget * keybinding_entry_command
Definition: keys.c:55
x_set_echo
void x_set_echo(void)
Definition: keys.c:1704
keyrelfunc
void keyrelfunc(GtkWidget *widget, GdkEventKey *event, GtkWidget *window)
Definition: keys.c:1552
dialog_xml
GtkBuilder * dialog_xml
Definition: main.c:102
stop_run
void stop_run()
Definition: player.c:145
keys_char
static struct keybind * keys_char[KEYHASH]
Definition: keys.c:166
reset_keybinding_status
void reset_keybinding_status(void)
Definition: keys.c:2487
MAX_HISTORY
#define MAX_HISTORY
Definition: keys.c:85
LOG_ERROR
@ LOG_ERROR
Warning that something definitely didn't work.
Definition: client.h:436
unbind_usage
static void unbind_usage(void)
Definition: keys.c:1454
main.h
keybinding_checkbutton_any
static GtkWidget * keybinding_checkbutton_any
Definition: keys.c:51
completekeysym
static guint32 completekeysym
Definition: keys.c:120
scroll_history_position
static int scroll_history_position
Definition: keys.c:89
cpl
Client_Player cpl
Definition: client.c:69
MSG_TYPE_CLIENT_CONFIG
#define MSG_TYPE_CLIENT_CONFIG
Definition: newclient.h:630
KLIST_SCOPE
@ KLIST_SCOPE
Definition: keys.c:74
keybinding_checkbutton_edit
static GtkWidget * keybinding_checkbutton_edit
Definition: keys.c:54
NDI_WHITE
#define NDI_WHITE
Definition: newclient.h:222
CONFIG_POPUPS
#define CONFIG_POPUPS
Definition: client.h:191
keybinding_selection
static GtkTreeSelection * keybinding_selection
Definition: keys.c:60
unbind_key
void unbind_key(const char *params)
Definition: keys.c:1465
KEYF_MOD_ALT
#define KEYF_MOD_ALT
Definition: keys.c:140
MSG_TYPE_CLIENT_NOTICE
#define MSG_TYPE_CLIENT_NOTICE
Definition: newclient.h:635
save_keys
static void save_keys(void)
Definition: keys.c:1271
fire_dir
void fire_dir(int dir)
Definition: player.c:129
fire_label
static GtkWidget * fire_label
Definition: keys.c:49
keybinding_button_remove
static GtkWidget * keybinding_button_remove
Definition: keys.c:56
nextkeysym
static guint32 nextkeysym
Definition: keys.c:120
get_key_info
static char * get_key_info(struct keybind *kb, int save_mode)
Definition: keys.c:988
Metaserver_Select
@ Metaserver_Select
Definition: client.h:147
Player_Struct::count
guint32 count
Definition: client.h:357
keybind::next
struct keybind * next
Definition: keys.c:104
use_config
gint16 use_config[CONFIG_NUMS]
Definition: client.h:242
MSG_TYPE_CLIENT_QUERY
#define MSG_TYPE_CLIENT_QUERY
Definition: newclient.h:633
gtk_command_history
void gtk_command_history(int direction)
Definition: keys.c:1723
entry_commands
GtkWidget * entry_commands
Definition: keys.c:63
ClientSocket::command_sent
guint16 command_sent
Definition: client.h:127
firekeysym
static guint32 firekeysym[2]
Definition: keys.c:119
draw_message_window
void draw_message_window(int redraw)
Definition: stats.c:459
window_root
GtkWidget * window_root
Definition: main.c:103
on_kb_scope_togglebutton_character_toggled
void on_kb_scope_togglebutton_character_toggled(GtkToggleButton *toggle_button, gpointer user_data)
Definition: keys.c:2149
get_key_modchars
static void get_key_modchars(struct keybind *kb, int save_mode, char *buf)
Definition: keys.c:950
metakeysym
static guint32 metakeysym[2]
Definition: keys.c:120
keybinding_selection_func
gboolean keybinding_selection_func(GtkTreeSelection *selection, GtkTreeModel *model, GtkTreePath *path, gboolean path_currently_selected, gpointer userdata)
Definition: keys.c:2409
on_keybinding_button_remove_clicked
void on_keybinding_button_remove_clicked(GtkButton *button, gpointer user_data)
Definition: keys.c:2193
directions
const char *const directions[9]
Definition: player.c:41
KEYF_MOD_META
#define KEYF_MOD_META
Definition: keys.c:141
keybinding_button_bind
static GtkWidget * keybinding_button_bind
Definition: keys.c:57
LOG_DEBUG
@ LOG_DEBUG
Useful debugging information.
Definition: client.h:433
bind_flags
static int bind_flags
Definition: keys.c:123
on_keybinding_checkbutton_any_clicked
void on_keybinding_checkbutton_any_clicked(GtkCheckButton *cb, gpointer user_data)
Definition: keys.c:2385
debounce
static bool debounce
Definition: keys.c:180
client.h
keybinding_checkbutton_meta
static GtkWidget * keybinding_checkbutton_meta
Definition: keys.c:53
make_path_to_file
int make_path_to_file(char *filename)
Definition: misc.c:87
KLIST_MODS
@ KLIST_MODS
Definition: keys.c:74
parse_keybind_line
static void parse_keybind_line(char *buf, int line, unsigned int scope_flag)
Definition: keys.c:315
bind_buf
static char bind_buf[MAX_BUF]
Definition: keys.c:124
keybind::direction
gint8 direction
Definition: keys.c:101
parse_key_release
static void parse_key_release(guint32 keysym)
Definition: keys.c:803
bind_key
void bind_key(char *params)
Definition: keys.c:1089
window_xml
GtkBuilder * window_xml
Definition: main.c:102