Crossfire Client, Trunk  R20612
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 #include "def-keys.h"
36 
37 #include "image.h"
38 #include "gtk2proto.h"
39 #include "p_cmd.h"
40 
41 struct keybind;
42 static int keybind_remove(struct keybind *entry);
43 static void keybind_free(struct keybind **entry);
44 
50 static GtkWidget *fire_label, *run_label, *keybinding_window,
59 
60 static GtkListStore *keybinding_store;
61 static GtkTreeSelection *keybinding_selection;
62 
63 GtkWidget *spinbutton_count;
64 GtkWidget *entry_commands;
74 enum {
77 };
86 #define MAX_HISTORY 50
87 #define MAX_COMMAND_LEN 256
89 
100 struct keybind {
101  guint8 flags;
102  gint8 direction;
103  guint32 keysym;
104  char *command;
105  struct keybind *next;
106 };
107 
108 
109 /***********************************************************************
110  *
111  * Key board input translations are handled here. We don't deal with
112  * the events, but rather KeyCodes and KeySyms.
113  *
114  * It would be nice to deal with only KeySyms, but many keyboards
115  * have keys that do not correspond to a KeySym, so we do need to
116  * support KeyCodes.
117  *
118  ***********************************************************************/
119 
122  cancelkeysym;
123 
124 static int bind_flags = 0;
125 static char bind_buf[MAX_BUF];
126 
127 /*
128  * Key modifiers
129  *
130  * The Run, Fire, Alt and/or Meta keys can be used to qualify a key
131  * (i.e. a keybinding of the key 's' with the KEYF_RUN and KEYF_FIRE
132  * flags set will only match if both Run and Fire are held while 's' is
133  * pressed).
134  *
135  * If the user wants a key to match no matter the state of the modifier
136  * keys, the KEYF_ANY flag must be set in the binding.
137  */
138 
139 #define KEYF_MOD_SHIFT (1 << 0)
140 #define KEYF_MOD_CTRL (1 << 1)
141 #define KEYF_MOD_ALT (1 << 2)
142 #define KEYF_MOD_META (1 << 3)
143 #define KEYF_MOD_MASK (KEYF_MOD_SHIFT | \
144  KEYF_MOD_CTRL | \
145  KEYF_MOD_ALT | \
146  KEYF_MOD_META)
147 
148 #define KEYF_ANY (1 << 4)
149 #define KEYF_EDIT (1 << 5)
151 /* Keybinding's scope, decides where the binding will be saved */
152 #define KEYF_R_GLOBAL (1 << 6)
153 #define KEYF_R_CHAR (1 << 7)
155 extern const char *const directions[9];
156 
157 #define KEYHASH 257
158 
168 
174 #define EKEYBIND_NOMEM 1
175 
192 static struct keybind *keybind_find(guint32 keysym, unsigned int flags,
193  int scope) {
194  struct keybind *kb;
195  kb = scope ? keys_global[keysym % KEYHASH] : keys_char[keysym % KEYHASH];
196  while (kb != NULL) {
197  if (kb->keysym == 0 || kb->keysym == keysym) {
198  if ((kb->flags & KEYF_ANY) || (flags & KEYF_ANY)) {
199  return kb;
200  }
201  if ((kb->flags & KEYF_MOD_MASK) == (flags & KEYF_MOD_MASK)) {
202  return kb;
203  }
204  }
205  kb = kb->next;
206  }
207 
208  return NULL;
209 }
210 
221 static int keybind_insert(guint32 keysym, unsigned int flags,
222  const char *command) {
223  struct keybind **next_ptr, *kb;
224  int slot;
225  int i;
226  int dir;
227 
228  kb = keybind_find(keysym, flags, (flags & KEYF_R_GLOBAL));
229  while (kb != NULL) {
230  /*
231  * Keep the last binding instead of the first (backwards compatible).
232  *
233  * Also, if the new binding has the ANY flag, remove all matching
234  * previous bindings and keep this one.
235  */
236  LOG(LOG_DEBUG, "gtk-v2::keybind_insert",
237  "Overwriting previous binding for key %s with command %s ",
238  gdk_keyval_name(keysym), kb->command);
239  keybind_remove(kb);
240  keybind_free(&kb);
241  kb = keybind_find(keysym, flags, (flags & KEYF_R_GLOBAL));
242  }
243 
244  slot = keysym % KEYHASH;
245 
246  next_ptr = (flags & KEYF_R_GLOBAL) ? &keys_global[slot] : &keys_char[slot];
247  while (*next_ptr) {
248  next_ptr = &(*next_ptr)->next;
249  }
250  *next_ptr = calloc(1, sizeof(**next_ptr));
251  if (*next_ptr == NULL) {
252  return -EKEYBIND_NOMEM;
253  }
254 
255  (*next_ptr)->keysym = keysym;
256  (*next_ptr)->flags = flags;
257  (*next_ptr)->command = g_strdup(command);
258 
259  /*
260  * Try to find out if the command is a direction command. If so, keep
261  * track of this fact, so in fire or run mode, things work correctly.
262  */
263  dir = -1;
264  for (i = 0; i < 9; i++) {
265  if (!strcmp(command, directions[i])) {
266  dir = i;
267  break;
268  }
269  }
270  (*next_ptr)->direction = dir;
271 
272  return 0;
273 }
274 
275 static int keybind_remove(struct keybind *entry) {
276  struct keybind **next_ptr;
277  int slot;
278 
279  slot = entry->keysym % KEYHASH;
280 
281  next_ptr = (entry->flags & KEYF_R_GLOBAL) ? &keys_global[slot] :
282  &keys_char[slot];
283  while (*next_ptr) {
284  if (*next_ptr == entry) {
285  *next_ptr = entry->next;
286  return 0;
287  }
288  next_ptr = &(*next_ptr)->next;
289  }
290 
291  /* No such key entry */
292  return -1;
293 }
294 
295 static void keybind_free(struct keybind **entry) {
296  free((*entry)->command);
297  (*entry)->command = NULL;
298  free(*entry);
299  *entry = NULL;
300 }
301 
309 static void parse_keybind_line(char *buf, int line, unsigned int scope_flag) {
310  char *cp, *cpnext;
311  guint32 keysym, low_keysym;
312  int flags;
313 
314  /*
315  * There may be a rare error case when cp is used uninitialized. So let's
316  * be safe
317  */
318  cp = NULL;
319 
320  if (buf[0] == '#' || buf[0] == '\n') {
321  return;
322  }
323  cpnext = strchr(buf, ' ');
324  if (cpnext == NULL) {
325  LOG(LOG_WARNING, "gtk-v2::parse_keybind_line",
326  "Line %d (%s) corrupted in keybinding file.", line, buf);
327  return;
328  }
329  /* Special keybinding line */
330  if (buf[0] == '!') {
331  char *cp1;
332  while (*cpnext == ' ') {
333  ++cpnext;
334  }
335  cp = strchr(cpnext, ' ');
336  if (!cp) {
337  LOG(LOG_WARNING, "gtk-v2::parse_keybind_line",
338  "Line %d (%s) corrupted in keybinding file.", line, buf);
339  return;
340  }
341  *cp++ = 0; /* Null terminate it */
342  cp1 = strchr(cp, ' ');
343  if (!cp1) {
344  LOG(LOG_WARNING, "gtk-v2::parse_keybind_line",
345  "Line %d (%s) corrupted in keybinding file.", line, buf);
346  return;
347  }
348  *cp1++ = 0; /* Null terminate it */
349  keysym = gdk_keyval_from_name(cp);
350  /* As of now, all these keys must have keysyms */
351  if (keysym == 0) {
352  LOG(LOG_WARNING, "gtk-v2::parse_keybind_line",
353  "Could not convert %s into keysym", cp);
354  return;
355  }
356  if (!strcmp(cpnext, "commandkey")) {
358  return;
359  }
360  if (!strcmp(cpnext, "altkey0")) {
361  altkeysym[0] = keysym;
362  return;
363  }
364  if (!strcmp(cpnext, "altkey1")) {
365  altkeysym[1] = keysym;
366  return;
367  }
368  if (!strcmp(cpnext, "firekey0")) {
369  firekeysym[0] = keysym;
370  return;
371  }
372  if (!strcmp(cpnext, "firekey1")) {
373  firekeysym[1] = keysym;
374  return;
375  }
376  if (!strcmp(cpnext, "metakey0")) {
377  metakeysym[0] = keysym;
378  return;
379  }
380  if (!strcmp(cpnext, "metakey1")) {
381  metakeysym[1] = keysym;
382  return;
383  }
384  if (!strcmp(cpnext, "runkey0")) {
385  runkeysym[0] = keysym;
386  return;
387  }
388  if (!strcmp(cpnext, "runkey1")) {
389  runkeysym[1] = keysym;
390  return;
391  }
392  if (!strcmp(cpnext, "completekey")) {
394  return;
395  }
396  if (!strcmp(cpnext, "nextkey")) {
397  nextkeysym = keysym;
398  return;
399  }
400  if (!strcmp(cpnext, "prevkey")) {
401  prevkeysym = keysym;
402  return;
403  }
404  } else {
405  *cpnext++ = '\0';
406  keysym = gdk_keyval_from_name(buf);
407  if (!keysym) {
408  LOG(LOG_WARNING, "gtk-v2::parse_keybind_line",
409  "Unable to convert line %d (%s) into keysym", line, cp);
410  return;
411  }
412  cp = cpnext;
413  cpnext = strchr(cp, ' ');
414  if (cpnext == NULL) {
415  LOG(LOG_WARNING, "gtk-v2::parse_keybind_line",
416  "Line %d (%s) corrupted in keybinding file.", line, cp);
417  return;
418  }
419  *cpnext++ = '\0';
420 
421  cp = cpnext;
422  cpnext = strchr(cp, ' ');
423  if (cpnext == NULL) {
424  LOG(LOG_WARNING, "gtk-v2::parse_keybind_line",
425  "Line %d (%s) corrupted in keybinding file.", line, cp);
426  return;
427  }
428  *cpnext++ = '\0';
429 
430  flags = 0;
431  low_keysym = gdk_keyval_to_lower(keysym);
432  if (low_keysym != keysym) {
433  /* This binding is uppercase, switch to lowercase and flag the shift modifier */
434  flags |= KEYF_MOD_SHIFT;
435  keysym = low_keysym;
436  }
437  while (*cp != '\0') {
438  switch (*cp) {
439  case 'A':
440  flags |= KEYF_ANY;
441  break;
442  case 'E':
443  flags |= KEYF_EDIT;
444  break;
445  case 'F':
446  flags |= KEYF_MOD_SHIFT;
447  break;
448  case 'L': /* A is used, so using L for alt */
449  flags |= KEYF_MOD_ALT;
450  break;
451  case 'M':
452  flags |= KEYF_MOD_META;
453  break;
454  case 'N':
455  /* Nothing to do */
456  break;
457  case 'R':
458  flags |= KEYF_MOD_CTRL;
459  break;
460  case 'S':
461  LOG(LOG_WARNING, "gtk-v2::parse_keybind_line",
462  "Deprecated flag (S) ignored at line %d in key binding file", line);
463  break;
464  default:
465  LOG(LOG_WARNING, "gtk-v2::parse_keybind_line",
466  "Unknown flag (%c) line %d in key binding file",
467  *cp, line);
468  }
469  cp++;
470  }
471 
472  /* Rest of the line is the actual command. Lets kill the newline */
473  cpnext[strlen(cpnext) - 1] = '\0';
474  if (strlen(cpnext) > (sizeof(bind_buf) - 1)) {
475  cpnext[sizeof(bind_buf) - 1] = '\0';
476  LOG(LOG_WARNING, "gtk-v2::parse_keybind_line",
477  "Command too long! Truncated.");
478  }
479 
480  flags |= scope_flag; /* add the corresponding scope flag */
481  keybind_insert(keysym, flags, cpnext);
482 
483  } /* else if not special binding line */
484 }
485 
490  LOG(LOG_DEBUG, "init_default_keybindings", "Loading default keybindings");
491  for (size_t i = 0; i < sizeof(def_keys) / sizeof(char *); i++) {
492  char *nextline = g_strdup(def_keys[i]);
493  parse_keybind_line(nextline, i, KEYF_R_GLOBAL);
494  free(nextline);
495  }
496 }
497 
506 static int parse_keys_file(char *filename, unsigned int scope_flag) {
507  FILE *fp;
508  char buf[BIG_BUF];
509  int line = 0;
510 
511  fp = fopen(filename, "r");
512  if (fp == NULL) {
513  return -1;
514  }
515 
516  LOG(LOG_DEBUG, "init_keys", "Reading %s keybindings from '%s'",
517  scope_flag == KEYF_R_GLOBAL ? "global" : "character", filename);
518 
519  while (fgets(buf, BIG_BUF, fp)) {
520  line++;
521  buf[BIG_BUF - 1] = '\0';
522  parse_keybind_line(buf, line, scope_flag);
523  }
524 
525  fclose(fp);
526  return 0;
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_apostrophe;
544  firekeysym[0] = GDK_Shift_L;
545  firekeysym[1] = GDK_Shift_R;
546  runkeysym[0] = GDK_Control_L;
547  runkeysym[1] = GDK_Control_R;
548  metakeysym[0] = GDK_Meta_L;
549  metakeysym[1] = GDK_Meta_R;
550  altkeysym[0] = GDK_Alt_L;
551  altkeysym[1] = GDK_Alt_R;
552 
553  completekeysym = GDK_Tab;
554  cancelkeysym = GDK_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]) {
567  keybind_remove(keys_global[i]);
568  }
569 
570  while (keys_char[i]) {
571  keybind_remove(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);
604 
605  /* Try to load the character-specific keybindings. */
606  if (cpl.name) {
607  snprintf(buf, sizeof(buf), "%s/%s.%s.keys", config_dir,
610  }
611 }
612 
613 
621 void keys_init(GtkWidget *window_root) {
622  GtkTreeViewColumn *column;
623  GtkCellRenderer *renderer;
624  GtkWidget *widget;
625  int i;
626 
627  fire_label = GTK_WIDGET(gtk_builder_get_object(window_xml, "fire_label"));
628  run_label = GTK_WIDGET(gtk_builder_get_object(window_xml, "run_label"));
629  entry_commands = GTK_WIDGET(gtk_builder_get_object(window_xml,
630  "entry_commands"));
631  spinbutton_count = GTK_WIDGET(gtk_builder_get_object(window_xml,
632  "spinbutton_count"));
633 
634  g_signal_connect((gpointer) entry_commands, "activate",
635  G_CALLBACK(on_entry_commands_activate), NULL);
636 
637  keybinding_window = GTK_WIDGET(gtk_builder_get_object(dialog_xml,
638  "keybinding_window"));
639 
641  GTK_WIDGET(gtk_builder_get_object(dialog_xml, "kb_scope_togglebutton_global"));
643  GTK_WIDGET(gtk_builder_get_object(dialog_xml,
644  "kb_scope_togglebutton_character"));
646  GTK_WIDGET(gtk_builder_get_object(dialog_xml, "keybinding_checkbutton_any"));
648  GTK_WIDGET(gtk_builder_get_object(dialog_xml,
649  "keybinding_checkbutton_control"));
651  GTK_WIDGET(gtk_builder_get_object(dialog_xml, "keybinding_checkbutton_shift"));
653  GTK_WIDGET(gtk_builder_get_object(dialog_xml, "keybinding_checkbutton_alt"));
655  GTK_WIDGET(gtk_builder_get_object(dialog_xml, "keybinding_checkbutton_meta"));
657  GTK_WIDGET(gtk_builder_get_object(dialog_xml,
658  "keybinding_checkbutton_stayinedit"));
660  GTK_WIDGET(gtk_builder_get_object(dialog_xml, "keybinding_entry_key"));
662  GTK_WIDGET(gtk_builder_get_object(dialog_xml, "keybinding_entry_command"));
664  GTK_WIDGET(gtk_builder_get_object(dialog_xml, "keybinding_treeview"));
666  GTK_WIDGET(gtk_builder_get_object(dialog_xml, "keybinding_button_remove"));
668  GTK_WIDGET(gtk_builder_get_object(dialog_xml, "keybinding_button_update"));
670  GTK_WIDGET(gtk_builder_get_object(dialog_xml, "keybinding_button_bind"));
671 
672  g_signal_connect((gpointer) keybinding_window, "delete_event",
673  G_CALLBACK(gtk_widget_hide_on_delete), NULL);
674  g_signal_connect((gpointer) keybinding_entry_key, "key_press_event",
675  G_CALLBACK(on_keybinding_entry_key_key_press_event), NULL);
676  g_signal_connect((gpointer) keybinding_button_remove, "clicked",
677  G_CALLBACK(on_keybinding_button_remove_clicked), NULL);
678  g_signal_connect((gpointer) keybinding_button_update, "clicked",
679  G_CALLBACK(on_keybinding_button_update_clicked), NULL);
680  g_signal_connect((gpointer) keybinding_button_bind, "clicked",
681  G_CALLBACK(on_keybinding_button_bind_clicked), NULL);
682 
683  g_signal_connect((gpointer) kb_scope_togglebutton_character, "toggled",
685  g_signal_connect((gpointer) kb_scope_togglebutton_global, "toggled",
686  G_CALLBACK(on_kb_scope_togglebutton_global_toggled), NULL);
687 
688  g_signal_connect((gpointer) keybinding_checkbutton_any, "clicked",
689  G_CALLBACK(on_keybinding_checkbutton_any_clicked), NULL);
690 
691  widget = GTK_WIDGET(gtk_builder_get_object(dialog_xml,
692  "keybinding_button_clear"));
693  g_signal_connect((gpointer) widget, "clicked",
694  G_CALLBACK(on_keybinding_button_clear_clicked), NULL);
695 
696  widget = GTK_WIDGET(gtk_builder_get_object(dialog_xml,
697  "keybinding_button_close"));
698  g_signal_connect((gpointer) widget, "clicked",
699  G_CALLBACK(on_keybinding_button_close_clicked), NULL);
700 
701  gtk_widget_set_sensitive(keybinding_button_remove, FALSE);
702  gtk_widget_set_sensitive(keybinding_button_update, FALSE);
703  keybinding_store = gtk_list_store_new(7,
704  G_TYPE_INT,
705  G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING,
706  G_TYPE_POINTER
707  );
708  gtk_tree_view_set_model(GTK_TREE_VIEW(keybinding_treeview),
709  GTK_TREE_MODEL(keybinding_store));
710 
711  renderer = gtk_cell_renderer_text_new();
712  column = gtk_tree_view_column_new_with_attributes("Key", renderer,
713  "text", KLIST_KEY,
714  NULL);
715  gtk_tree_view_column_set_sort_column_id(column, KLIST_KEY);
716  gtk_tree_view_append_column(GTK_TREE_VIEW(keybinding_treeview), column);
717 
718  renderer = gtk_cell_renderer_text_new();
719  column = gtk_tree_view_column_new_with_attributes("Modifiers", renderer,
720  "text", KLIST_MODS,
721  NULL);
722  gtk_tree_view_column_set_sort_column_id(column, KLIST_MODS);
723  gtk_tree_view_append_column(GTK_TREE_VIEW(keybinding_treeview), column);
724 
725  renderer = gtk_cell_renderer_text_new();
726  column = gtk_tree_view_column_new_with_attributes("Scope", renderer,
727  "text", KLIST_SCOPE,
728  NULL);
729  gtk_tree_view_column_set_sort_column_id(column, KLIST_SCOPE);
730  gtk_tree_view_append_column(GTK_TREE_VIEW(keybinding_treeview), column);
731 
732  renderer = gtk_cell_renderer_text_new();
733  column = gtk_tree_view_column_new_with_attributes("Edit Mode", renderer,
734  "text", KLIST_EDIT,
735  NULL);
736  gtk_tree_view_column_set_sort_column_id(column, KLIST_EDIT);
737  gtk_tree_view_append_column(GTK_TREE_VIEW(keybinding_treeview), column);
738 
739  renderer = gtk_cell_renderer_text_new();
740  column = gtk_tree_view_column_new_with_attributes("Command", renderer,
741  "text", KLIST_COMMAND,
742  NULL);
743  gtk_tree_view_column_set_sort_column_id(column, KLIST_COMMAND);
744  gtk_tree_view_append_column(GTK_TREE_VIEW(keybinding_treeview), column);
745 
746 
747  keybinding_selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(
749  gtk_tree_selection_set_mode(keybinding_selection, GTK_SELECTION_BROWSE);
750  gtk_tree_selection_set_select_function(keybinding_selection,
751  keybinding_selection_func, NULL, NULL);
752 
753  gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(keybinding_store),
754  KLIST_KEY,
755  GTK_SORT_ASCENDING);
756 
757  for (i = 0; i < KEYHASH; i++) {
758  keys_global[i] = NULL;
759  keys_char[i] = NULL;
760  }
761 }
762 
775 static void parse_key_release(guint32 keysym) {
776 
777  /*
778  * Only send stop firing/running commands if we are in actual play mode.
779  * Something smart does need to be done when the character enters a non
780  * play mode with fire or run mode already set, however.
781  */
782  if (keysym == firekeysym[0] || keysym == firekeysym[1]) {
783  cpl.fire_on = 0;
784  clear_fire();
785  gtk_label_set_text(GTK_LABEL(fire_label), " ");
786  } else if (keysym == runkeysym[0] || keysym == runkeysym[1]) {
787  cpl.run_on = 0;
788  if (use_config[CONFIG_ECHO])
790  "stop run");
791  clear_run();
792  gtk_label_set_text(GTK_LABEL(run_label), " ");
793  } else if (keysym == altkeysym[0] || keysym == altkeysym[1]) {
794  cpl.alt_on = 0;
795  } else if (keysym == metakeysym[0] || keysym == metakeysym[1]) {
796  cpl.meta_on = 0;
797  }
798  /*
799  * Firing is handled on server side. However, to keep more like the old
800  * version, if you release the direction key, you want the firing to stop.
801  * This should do that.
802  */
803  else if (cpl.fire_on) {
804  clear_fire();
805  }
806 }
807 
814 static void parse_key(char key, guint32 keysym) {
815  struct keybind *kb;
816  int present_flags = 0;
817  char buf[MAX_BUF], tmpbuf[MAX_BUF];
818 
819  /* We handle the Shift key separately */
820  keysym = gdk_keyval_to_lower(keysym);
821 
822  if (keysym == commandkeysym) {
823  gtk_widget_grab_focus(GTK_WIDGET(entry_commands));
824  gtk_entry_set_visibility(GTK_ENTRY(entry_commands), 1);
826  cpl.no_echo = FALSE;
827  return;
828  }
829  if (keysym == altkeysym[0] || keysym == altkeysym[1]) {
830  cpl.alt_on = 1;
831  return;
832  }
833  if (keysym == metakeysym[0] || keysym == metakeysym[1]) {
834  cpl.meta_on = 1;
835  return;
836  }
837  if (keysym == firekeysym[0] || keysym == firekeysym[1]) {
838  cpl.fire_on = 1;
839  gtk_label_set_text(GTK_LABEL(fire_label), "Fire");
840  return;
841  }
842  if (keysym == runkeysym[0] || keysym == runkeysym[1]) {
843  cpl.run_on = 1;
844  gtk_label_set_text(GTK_LABEL(run_label), "Run");
845  return;
846  }
847 
848  present_flags = 0;
849  if (cpl.run_on) {
850  present_flags |= KEYF_MOD_CTRL;
851  }
852  if (cpl.fire_on) {
853  present_flags |= KEYF_MOD_SHIFT;
854  }
855  if (cpl.alt_on) {
856  present_flags |= KEYF_MOD_ALT;
857  }
858  if (cpl.meta_on) {
859  present_flags |= KEYF_MOD_META;
860  }
861 
862  kb = keybind_find(keysym, present_flags, 0); /* char scope */
863  if (kb == NULL) {
864  kb = keybind_find(keysym, present_flags, 1); /* global scope */
865  }
866  if (kb != NULL) {
867  if (kb->flags & KEYF_EDIT) {
868  strcpy(cpl.input_text, kb->command);
870  gtk_entry_set_text(GTK_ENTRY(entry_commands), cpl.input_text);
871  gtk_widget_grab_focus(GTK_WIDGET(entry_commands));
872  gtk_editable_select_region(GTK_EDITABLE(entry_commands), 0, 0);
873  gtk_editable_set_position(GTK_EDITABLE(entry_commands), -1);
874  return;
875  }
876 
877  /* Some spells (dimension door) need a valid count value */
878  cpl.count = gtk_spin_button_get_value_as_int(
879  GTK_SPIN_BUTTON(spinbutton_count));
880 
881  if (kb->direction >= 0) {
882  if (cpl.fire_on) {
883  snprintf(buf, sizeof(buf), "fire %s", kb->command);
884  fire_dir(kb->direction);
885  } else if (cpl.run_on) {
886  snprintf(buf, sizeof(buf), "run %s", kb->command);
887  run_dir(kb->direction);
888  } else {
890  }
891  if (use_config[CONFIG_ECHO])
894  kb->command);
895  } else {
896  if (use_config[CONFIG_ECHO])
899  kb->command);
901  }
902  return;
903  }
904 
905  if (key >= '0' && key <= '9') {
906  cpl.count = cpl.count * 10 + (key - '0');
907  if (cpl.count > 100000) {
908  cpl.count %= 100000;
909  }
910  gtk_spin_button_set_value(GTK_SPIN_BUTTON(spinbutton_count), (float) cpl.count);
911  return;
912  }
913  tmpbuf[0] = 0;
914  if (cpl.fire_on) {
915  strcat(tmpbuf, "fire+");
916  }
917  if (cpl.run_on) {
918  strcat(tmpbuf, "run+");
919  }
920  if (cpl.alt_on) {
921  strcat(tmpbuf, "alt+");
922  }
923  if (cpl.meta_on) {
924  strcat(tmpbuf, "meta+");
925  }
926 
927  snprintf(buf, sizeof(buf),
928  "Key %s%s is not bound to any command. Use 'bind' to associate this keypress with a command",
929  tmpbuf, keysym == NoSymbol ? "unknown" : gdk_keyval_name(keysym));
930 #ifdef WIN32
931  if ((65513 != keysym) && (65511 != keysym))
932 #endif
934  cpl.count = 0;
935 }
936 
937 static void get_key_modchars(struct keybind *kb, int save_mode, char *buf) {
938  int bi = 0;
939 
940  if (kb->flags & KEYF_ANY) {
941  buf[bi++] = 'A';
942  }
943  if (save_mode || !(kb->flags & KEYF_ANY)) {
944  if ((kb->flags & KEYF_MOD_MASK) == 0) {
945  buf[bi++] = 'N';
946  }
947  if (kb->flags & KEYF_MOD_SHIFT) {
948  buf[bi++] = 'F';
949  }
950  if (kb->flags & KEYF_MOD_CTRL) {
951  buf[bi++] = 'R';
952  }
953  if (kb->flags & KEYF_MOD_ALT) {
954  buf[bi++] = 'L';
955  }
956  if (kb->flags & KEYF_MOD_META) {
957  buf[bi++] = 'M';
958  }
959  }
960  if (kb->flags & KEYF_EDIT) {
961  buf[bi++] = 'E';
962  }
963 
964  buf[bi] = '\0';
965 }
966 
975 static char *get_key_info(struct keybind *kb, int save_mode) {
976  /* bind buf is the maximum space allowed for a
977  * bound command. We will add additional data to
978  * it so we increase its size by MAX_BUF*/
979  static char buf[MAX_BUF + sizeof(bind_buf)];
980 
981  char buff[MAX_BUF];
982 
983  get_key_modchars(kb, save_mode, buff);
984 
985  if (save_mode) {
986  if (kb->keysym == NoSymbol) {
987  snprintf(buf, sizeof(buf), "(null) %i %s %s",
988  0, buff, kb->command);
989  } else {
990  snprintf(buf, sizeof(buf), "%s %i %s %s",
991  gdk_keyval_name(kb->keysym),
992  0, buff, kb->command);
993  }
994  } else {
995  if (kb->keysym == NoSymbol) {
996  snprintf(buf, sizeof(buf), "key (null) %s %s",
997  buff, kb->command);
998  } else {
999  snprintf(buf, sizeof(buf), "key %s %s %s",
1000  gdk_keyval_name(kb->keysym),
1001  buff, kb->command);
1002  }
1003  }
1004  return buf;
1005 }
1006 
1012 static void show_keys(void) {
1013  int i, j, count = 1;
1014  struct keybind *kb;
1015  char buf[MAX_BUF];
1016 
1017  snprintf(buf, sizeof(buf), "Commandkey %s",
1018  commandkeysym == NoSymbol ? "unknown" : gdk_keyval_name(commandkeysym));
1020 
1021  snprintf(buf, sizeof(buf), "Firekeys 1: %s, 2: %s",
1022  firekeysym[0] == NoSymbol ? "unknown" : gdk_keyval_name(firekeysym[0]),
1023  firekeysym[1] == NoSymbol ? "unknown" : gdk_keyval_name(firekeysym[1]));
1025 
1026  snprintf(buf, sizeof(buf), "Altkeys 1: %s, 2: %s",
1027  altkeysym[0] == NoSymbol ? "unknown" : gdk_keyval_name(altkeysym[0]),
1028  altkeysym[1] == NoSymbol ? "unknown" : gdk_keyval_name(altkeysym[1]));
1030 
1031  snprintf(buf, sizeof(buf), "Metakeys 1: %s, 2: %s",
1032  metakeysym[0] == NoSymbol ? "unknown" : gdk_keyval_name(metakeysym[0]),
1033  metakeysym[1] == NoSymbol ? "unknown" : gdk_keyval_name(metakeysym[1]));
1035 
1036  snprintf(buf, sizeof(buf), "Runkeys 1: %s, 2: %s",
1037  runkeysym[0] == NoSymbol ? "unknown" : gdk_keyval_name(runkeysym[0]),
1038  runkeysym[1] == NoSymbol ? "unknown" : gdk_keyval_name(runkeysym[1]));
1040 
1041  snprintf(buf, sizeof(buf), "Command Completion Key %s",
1042  completekeysym == NoSymbol ? "unknown" : gdk_keyval_name(completekeysym));
1044 
1045  snprintf(buf, sizeof(buf), "Next Command in History Key %s",
1046  nextkeysym == NoSymbol ? "unknown" : gdk_keyval_name(nextkeysym));
1048 
1049  snprintf(buf, sizeof(buf), "Previous Command in History Key %s",
1050  prevkeysym == NoSymbol ? "unknown" : gdk_keyval_name(prevkeysym));
1052 
1053  /*
1054  * Perhaps we should start at 8, so that we only show 'active' keybindings?
1055  */
1056  for (i = 0; i < KEYHASH; i++) {
1057  for (j = 0; j < 2; j++) {
1058  for (kb = (j == 0) ? keys_global[i] : keys_char[i]; kb != NULL; kb = kb->next) {
1059  snprintf(buf, sizeof(buf), "%3d %s", count, get_key_info(kb, 0));
1060  draw_ext_info(
1062  count++;
1063  }
1064  }
1065  }
1066 }
1067 
1076 void bind_key(char *params) {
1077  char buf[MAX_BUF + 16];
1078 
1079  if (!params) {
1081  "Usage: 'bind -ei {<commandline>,commandkey,firekey{1,2},runkey{1,2},altkey{1,2},metakey{1,2},completekey,nextkey,prevkey}'\n"
1082  "Where\n"
1083  " -e means enter edit mode\n"
1084  " -g means this binding should be global (used for all your characters)\n"
1085  " -i means ignore modifier keys (keybinding works no matter if Ctrl/Alt etc are held)");
1086  return;
1087  }
1088 
1089  /* Skip over any spaces we may have */
1090  while (*params == ' ') {
1091  params++;
1092  }
1093 
1094  if (!strcmp(params, "commandkey")) {
1097  "Push key to bind new commandkey.");
1099  return;
1100  }
1101 
1102  if (!strcmp(params, "firekey1")) {
1103  bind_keysym = &firekeysym[0];
1105  "Push key to bind new firekey 1.");
1107  return;
1108  }
1109  if (!strcmp(params, "firekey2")) {
1110  bind_keysym = &firekeysym[1];
1112  "Push key to bind new firekey 2.");
1114  return;
1115  }
1116  if (!strcmp(params, "metakey1")) {
1117  bind_keysym = &metakeysym[0];
1119  "Push key to bind new metakey 1.");
1121  return;
1122  }
1123  if (!strcmp(params, "metakey2")) {
1124  bind_keysym = &metakeysym[1];
1126  "Push key to bind new metakey 2.");
1128  return;
1129  }
1130  if (!strcmp(params, "altkey1")) {
1131  bind_keysym = &altkeysym[0];
1133  "Push key to bind new altkey 1.");
1135  return;
1136  }
1137  if (!strcmp(params, "altkey2")) {
1138  bind_keysym = &altkeysym[1];
1140  "Push key to bind new altkey 2.");
1142  return;
1143  }
1144  if (!strcmp(params, "runkey1")) {
1145  bind_keysym = &runkeysym[0];
1147  "Push key to bind new runkey 1.");
1149  return;
1150  }
1151 
1152  if (!strcmp(params, "runkey2")) {
1153  bind_keysym = &runkeysym[1];
1155  "Push key to bind new runkey 2.");
1157  return;
1158  }
1159 
1160  if (!strcmp(params, "completekey")) {
1163  "Push key to bind new command completion key");
1165  return;
1166  }
1167 
1168  if (!strcmp(params, "prevkey")) {
1171  "Push key to bind new previous command in history key.");
1173  return;
1174  }
1175 
1176  if (!strcmp(params, "nextkey")) {
1179  "Push key to bind new next command in history key.");
1181  return;
1182  }
1183  bind_keysym = NULL;
1184 
1185  bind_flags = 0;
1186  if (params[0] == '-') {
1187  for (params++; *params != ' '; params++)
1188  switch (*params) {
1189  case 'e':
1190  bind_flags |= KEYF_EDIT;
1191  break;
1192  case 'i':
1193  bind_flags |= KEYF_ANY;
1194  break;
1195  case 'g':
1197  break;
1198  case '\0':
1199  draw_ext_info(
1201  "Use unbind to remove bindings.");
1202  return;
1203  default:
1204  snprintf(buf, sizeof(buf),
1205  "Unsupported or invalid bind flag: '%c'", *params);
1207  return;
1208  }
1209  params++;
1210  }
1211 
1212  if (!params[0]) {
1214  "Use unbind to remove bindings.");
1215  return;
1216  }
1217 
1218  if (strlen(params) >= sizeof(bind_buf)) {
1219  params[sizeof(bind_buf) - 1] = '\0';
1221  "Keybinding too long! Truncated:");
1223  }
1224  snprintf(buf, sizeof(buf), "Push key to bind '%s'.", params);
1226 
1227  strcpy(bind_buf, params);
1229  return;
1230 }
1231 
1244 static void save_individual_key(FILE *fp, struct keybind *kb, KeyCode kc) {
1245  while (kb) {
1246  fprintf(fp, "%s\n", get_key_info(kb, 1));
1247  kb = kb->next;
1248  }
1249 }
1250 
1258 static void save_keys(void) {
1259  char buf[MAX_BUF], buf2[MAX_BUF];
1260  int i;
1261  FILE *fp;
1262 
1263  /* If we are logged in open file to save character specific bindings */
1264  if (cpl.name) {
1265  snprintf(buf, sizeof(buf), "%s/%s.%s.keys", config_dir,
1267  LOG(LOG_INFO, "gtk-v2::save_keys",
1268  "Saving character specific keybindings to %s", buf);
1269 
1270  if (make_path_to_file(buf) == -1) {
1271  LOG(LOG_WARNING, "gtk-v2::save_keys", "Could not create %s", buf);
1272  }
1273 
1274  fp = fopen(buf, "w");
1275  if (fp == NULL) {
1276  snprintf(buf2, sizeof(buf2),
1277  "Could not open %s, character bindings not saved\n", buf);
1279  } else {
1280  for (i = 0; i < KEYHASH; i++) {
1281  save_individual_key(fp, keys_char[i], 0);
1282  }
1283  fclose(fp);
1284  }
1285  }
1286 
1287  /* Open file to save global user bindings */
1288  snprintf(buf, sizeof(buf), "%s/keys", config_dir);
1289  LOG(LOG_INFO, "gtk-v2::save_keys",
1290  "Saving global user's keybindings to %s", buf);
1291 
1292  if (make_path_to_file(buf) == -1) {
1293  LOG(LOG_WARNING, "gtk-v2::save_keys", "Could not create %s", buf);
1294  } else {
1295  fp = fopen(buf, "w");
1296  if (fp == NULL) {
1297  snprintf(buf2, sizeof(buf2),
1298  "Could not open %s, global key bindings not saved\n", buf);
1300  } else {
1301  /* Save default bindings as part of the global scope */
1302  if (firekeysym[0] != GDK_Shift_L && firekeysym[0] != NoSymbol)
1303  fprintf(fp, "! firekey0 %s %d\n",
1304  gdk_keyval_name(firekeysym[0]), 0);
1305  if (firekeysym[1] != GDK_Shift_R && firekeysym[1] != NoSymbol)
1306  fprintf(fp, "! firekey1 %s %d\n",
1307  gdk_keyval_name(firekeysym[1]), 0);
1308  if (metakeysym[0] != GDK_Shift_L && metakeysym[0] != NoSymbol)
1309  fprintf(fp, "! metakey0 %s %d\n",
1310  gdk_keyval_name(metakeysym[0]), 0);
1311  if (metakeysym[1] != GDK_Shift_R && metakeysym[1] != NoSymbol)
1312  fprintf(fp, "! metakey1 %s %d\n",
1313  gdk_keyval_name(metakeysym[1]), 0);
1314  if (altkeysym[0] != GDK_Shift_L && altkeysym[0] != NoSymbol)
1315  fprintf(fp, "! altkey0 %s %d\n",
1316  gdk_keyval_name(altkeysym[0]), 0);
1317  if (altkeysym[1] != GDK_Shift_R && altkeysym[1] != NoSymbol)
1318  fprintf(fp, "! altkey1 %s %d\n",
1319  gdk_keyval_name(altkeysym[1]), 0);
1320  if (runkeysym[0] != GDK_Control_L && runkeysym[0] != NoSymbol)
1321  fprintf(fp, "! runkey0 %s %d\n",
1322  gdk_keyval_name(runkeysym[0]), 0);
1323  if (runkeysym[1] != GDK_Control_R && runkeysym[1] != NoSymbol)
1324  fprintf(fp, "! runkey1 %s %d\n",
1325  gdk_keyval_name(runkeysym[1]), 0);
1326  if (completekeysym != GDK_Tab && completekeysym != NoSymbol)
1327  fprintf(fp, "! completekey %s %d\n",
1328  gdk_keyval_name(completekeysym), 0);
1329  /* No defaults for these, so if it is set to anything, assume its valid */
1330  if (nextkeysym != NoSymbol)
1331  fprintf(fp, "! nextkey %s %d\n",
1332  gdk_keyval_name(nextkeysym), 0);
1333  if (prevkeysym != NoSymbol)
1334  fprintf(fp, "! prevkey %s %d\n",
1335  gdk_keyval_name(prevkeysym), 0);
1336 
1337  for (i = 0; i < KEYHASH; i++) {
1338  save_individual_key(fp, keys_global[i], 0);
1339  }
1340  fclose(fp);
1341  }
1342  }
1343 
1344  /* Should probably check return value on all writes to be sure, but... */
1346  "Key bindings saved.");
1347 }
1348 
1353 static void configure_keys(guint32 keysym) {
1354  char buf[MAX_BUF];
1355  struct keybind *kb;
1356 
1357  /* We handle the Shift key separately */
1358  keysym = gdk_keyval_to_lower(keysym);
1359 
1360  /*
1361  * I think that basically if we are not rebinding the special control keys
1362  * (in which case bind_keysym would be set to something) we just want to
1363  * handle these keypresses as normal events.
1364  */
1365  if (bind_keysym == NULL) {
1366  if (keysym == altkeysym[0] || keysym == altkeysym[1]) {
1367  cpl.alt_on = 1;
1368  return;
1369  }
1370  if (keysym == metakeysym[0] || keysym == metakeysym[1]) {
1371  cpl.meta_on = 1;
1372  return;
1373  }
1374  if (keysym == firekeysym[0] || keysym == firekeysym[1]) {
1375  cpl.fire_on = 1;
1377  return;
1378  }
1379  if (keysym == runkeysym[0] || keysym == runkeysym[1]) {
1380  cpl.run_on = 1;
1382  return;
1383  }
1384  }
1385 
1386  /*
1387  * Take shift/control keys into account when binding keys.
1388  */
1389  if (!(bind_flags & KEYF_ANY)) {
1390  if (cpl.fire_on) {
1392  }
1393  if (cpl.run_on) {
1395  }
1396  if (cpl.meta_on) {
1398  }
1399  if (cpl.alt_on) {
1401  }
1402  }
1403 
1404  /* Reset state now. We might return early if bind fails. */
1406 
1407  if (bind_keysym != NULL) {
1408  *bind_keysym = keysym;
1409  bind_keysym = NULL;
1410  } else {
1411  kb = keybind_find(keysym, bind_flags, (bind_flags & KEYF_R_GLOBAL));
1412  if (kb) {
1413  snprintf(buf, sizeof(buf),
1414  "Error: Key already used for command \"%s\". Use unbind first.",
1415  kb->command);
1416  draw_ext_info(
1418  return;
1419  } else {
1421  }
1422  }
1423 
1424  snprintf(buf, sizeof(buf), "Bound to key '%s' (%i)",
1425  keysym == NoSymbol ? "unknown" : gdk_keyval_name(keysym), keysym);
1428 
1429  /*
1430  * Do this each time a new key is bound. This way, we are never actually
1431  * storing any information that needs to be saved when the connection dies
1432  * or the player quits.
1433  */
1434  save_keys();
1435  return;
1436 }
1437 
1441 static void unbind_usage(void) {
1443  "Usage: 'unbind <entry_number>' or");
1445  "Usage: 'unbind' to show existing bindings");
1446 }
1447 
1452 void unbind_key(const char *params) {
1453  int count = 0, keyentry, slot, j;
1454  int res;
1455  struct keybind *kb;
1456  char buf[MAX_BUF];
1457 
1458  if (params == NULL) {
1459  show_keys();
1460  return;
1461  }
1462 
1463  /* Skip over any spaces we may have */
1464  while (*params == ' ') {
1465  params++;
1466  }
1467 
1468  if (params[0] == '\0') {
1469  show_keys();
1470  return;
1471  }
1472 
1473  if ((keyentry = atoi(params)) == 0) {
1474  unbind_usage();
1475  return;
1476  }
1477 
1478  for (slot = 0; slot < KEYHASH; slot++) {
1479  for (j = 0; j < 2; j++) {
1480  for (kb = (j == 0) ? keys_global[slot] : keys_char[slot]; kb != NULL;
1481  kb = kb->next) {
1482  count++;
1483 
1484  if (keyentry == count) {
1485  /* We found the key we want to unbind */
1486  snprintf(buf, sizeof(buf), "Removing binding: %3d %s",
1487  count, get_key_info(kb, 0));
1489  MSG_TYPE_CLIENT_CONFIG, buf);
1490  res = keybind_remove(kb);
1491  if (res < 0)
1492  LOG(LOG_ERROR, "gtk-v2::unbind_key",
1493  "found number entry, but could not find actual key");
1494  keybind_free(&kb);
1495  save_keys();
1496  return;
1497  }
1498  }
1499  }
1500  }
1501 
1502  /* Not found */
1503  /* Makes things look better to draw the blank line */
1506  "Not found. Try 'unbind' with no options to find entry.");
1507  return;
1508 }
1509 
1513 void focusoutfunc(GtkWidget *widget, GdkEventKey *event, GtkWidget *window) {
1514  if (cpl.fire_on == 1) {
1515  cpl.fire_on = 0;
1516  clear_fire();
1517  gtk_label_set_text(GTK_LABEL(fire_label), " ");
1518  }
1519  if (cpl.run_on == 1) {
1520  cpl.run_on = 0;
1521  if (use_config[CONFIG_ECHO])
1523  "stop run");
1524  clear_run();
1525  gtk_label_set_text(GTK_LABEL(run_label), " ");
1526  }
1527  if (cpl.alt_on == 1) {
1528  cpl.alt_on = 0;
1529  }
1530  if (cpl.meta_on == 1) {
1531  cpl.meta_on = 0;
1532  }
1533 }
1534 
1542 void keyrelfunc(GtkWidget *widget, GdkEventKey *event, GtkWidget *window) {
1543  if (event->keyval > 0 && !gtk_widget_has_focus(entry_commands)) {
1544  parse_key_release(event->keyval);
1545  }
1546  g_signal_stop_emission_by_name(GTK_OBJECT(window), "key_release_event");
1547 }
1548 
1556 void keyfunc(GtkWidget *widget, GdkEventKey *event, GtkWidget *window) {
1557  char *text;
1558 
1559  if (!use_config[CONFIG_POPUPS]) {
1560  if (((cpl.input_state == Reply_One) || (cpl.input_state == Reply_Many))
1561  && (event->keyval == cancelkeysym)) {
1562 
1563  /*
1564  * Player hit cancel button during input. Disconnect it (code from
1565  * menubar)
1566  */
1567 
1569 
1570  g_signal_stop_emission_by_name(
1571  GTK_OBJECT(window), "key_press_event");
1572  return;
1573  }
1574  if (cpl.input_state == Reply_One) {
1575  text = gdk_keyval_name(event->keyval);
1576  send_reply(text);
1578  g_signal_stop_emission_by_name(
1579  GTK_OBJECT(window), "key_press_event");
1580  return;
1581  } else if (cpl.input_state == Reply_Many) {
1582  if (gtk_widget_has_focus(entry_commands)) {
1583  gtk_widget_event(GTK_WIDGET(entry_commands), (GdkEvent *)event);
1584  } else {
1585  gtk_widget_grab_focus(GTK_WIDGET(entry_commands));
1586  }
1587  g_signal_stop_emission_by_name(
1588  GTK_OBJECT(window), "key_press_event");
1589  return;
1590  }
1591  }
1592  /*
1593  * Better check for really weirdo keys, X doesnt like keyval 0 so avoid
1594  * handling these key values.
1595  */
1596  if (event->keyval > 0) {
1597  if (gtk_widget_has_focus(entry_commands)) {
1598  if (event->keyval == completekeysym) {
1600  }
1601  if (event->keyval == prevkeysym || event->keyval == nextkeysym) {
1602  gtk_command_history(event->keyval == nextkeysym ? 0 : 1);
1603  } else {
1604  gtk_widget_event(GTK_WIDGET(entry_commands), (GdkEvent *)event);
1605  }
1606  } else {
1607  switch (cpl.input_state) {
1608  case Playing:
1609  /*
1610  * Specials - do command history - many times, the player
1611  * will want to go the previous command when nothing is
1612  * entered in the command window.
1613  */
1614  if ((event->keyval == prevkeysym)
1615  || (event->keyval == nextkeysym)) {
1616  gtk_command_history(event->keyval == nextkeysym ? 0 : 1);
1617  } else {
1618  if (cpl.run_on) {
1619  if (!(event->state & GDK_CONTROL_MASK)) {
1620  /* printf("Run is on while ctrl is not\n"); */
1621  gtk_label_set_text(GTK_LABEL(run_label), " ");
1622  cpl.run_on = 0;
1623  stop_run();
1624  }
1625  }
1626  if (cpl.fire_on) {
1627  if (!(event->state & GDK_SHIFT_MASK)) {
1628  /* printf("Fire is on while shift is not\n");*/
1629  gtk_label_set_text(GTK_LABEL(fire_label), " ");
1630  cpl.fire_on = 0;
1631  stop_fire();
1632  }
1633  }
1634 
1635  parse_key(event->string[0], event->keyval);
1636  }
1637  break;
1638 
1639  case Configure_Keys:
1640  configure_keys(event->keyval);
1641  break;
1642 
1643  case Command_Mode:
1644  if (event->keyval == completekeysym) {
1646  }
1647  if ((event->keyval == prevkeysym)
1648  || (event->keyval == nextkeysym)) {
1649  gtk_command_history(event->keyval == nextkeysym ? 0 : 1);
1650  } else {
1651  gtk_widget_grab_focus(GTK_WIDGET(entry_commands));
1652  /*
1653  * When running in split windows mode, entry_commands
1654  * can't get focus because it is in a different
1655  * window. So we have to pass the event to it
1656  * explicitly.
1657  */
1658  if (gtk_widget_has_focus(entry_commands) == 0)
1659  gtk_widget_event(
1660  GTK_WIDGET(entry_commands), (GdkEvent *)event);
1661  }
1662  /*
1663  * Don't pass signal along to default handlers -
1664  * otherwise, we get get crashes in the clist area (gtk
1665  * fault I believe)
1666  */
1667  break;
1668 
1669  case Metaserver_Select:
1670  gtk_widget_grab_focus(GTK_WIDGET(entry_commands));
1671  break;
1672 
1673  default:
1674  LOG(LOG_ERROR, "gtk-v2::keyfunc",
1675  "Unknown input state: %d", cpl.input_state);
1676  }
1677  }
1678  }
1679  g_signal_stop_emission_by_name(
1680  GTK_OBJECT(window), "key_press_event");
1681 }
1682 
1686 void x_set_echo(void) {
1687  gtk_entry_set_visibility(GTK_ENTRY(entry_commands), !cpl.no_echo);
1688 }
1689 
1695 void draw_prompt(const char *str) {
1697  gtk_widget_grab_focus(GTK_WIDGET(entry_commands));
1698 }
1699 
1706  int i = scroll_history_position;
1707  if (direction) {
1708  i--;
1709  if (i < 0) {
1710  i += MAX_HISTORY;
1711  }
1712  if (i == cur_history_position) {
1713  return;
1714  }
1715  } else {
1716  i++;
1717  if (i >= MAX_HISTORY) {
1718  i = 0;
1719  }
1720  if (i == cur_history_position) {
1721  /*
1722  * User has forwarded to what should be current entry - reset it
1723  * now.
1724  */
1725  gtk_entry_set_text(GTK_ENTRY(entry_commands), "");
1726  gtk_editable_set_position(GTK_EDITABLE(entry_commands), 0);
1728  return;
1729  }
1730  }
1731 
1732  if (history[i][0] == 0) {
1733  return;
1734  }
1735 
1737  /* fprintf(stderr, "resetting postion to %d, data = %s\n", i, history[i]);*/
1738  gtk_entry_set_text(GTK_ENTRY(entry_commands), history[i]);
1739  gtk_widget_grab_focus(GTK_WIDGET(entry_commands));
1740  gtk_editable_select_region(GTK_EDITABLE(entry_commands), 0, 0);
1741  gtk_editable_set_position(GTK_EDITABLE(entry_commands), -1);
1742 
1744 }
1745 
1753  const gchar *entry_text, *newcommand;
1754 
1755  entry_text = gtk_entry_get_text(GTK_ENTRY(entry_commands));
1756  newcommand = complete_command(entry_text);
1757  /* value differ, so update window */
1758  if (newcommand != NULL) {
1759  gtk_entry_set_text(GTK_ENTRY(entry_commands), newcommand);
1760  gtk_widget_grab_focus(GTK_WIDGET(entry_commands));
1761  gtk_editable_select_region(GTK_EDITABLE(entry_commands), 0, 0);
1762  gtk_editable_set_position(GTK_EDITABLE(entry_commands), -1);
1763  }
1764 }
1765 
1773 void on_entry_commands_activate(GtkEntry *entry, gpointer user_data) {
1774  const gchar *entry_text;
1775  extern GtkWidget *treeview_look;
1776 
1777  /* Next reply will reset this as necessary */
1778  if (!use_config[CONFIG_POPUPS]) {
1779  gtk_entry_set_visibility(GTK_ENTRY(entry), TRUE);
1780  }
1781 
1782  entry_text = gtk_entry_get_text(GTK_ENTRY(entry));
1783 
1785  strcpy(cpl.input_text, entry_text);
1786  } else if (cpl.input_state == Reply_One || cpl.input_state == Reply_Many) {
1788  strcpy(cpl.input_text, entry_text);
1789  if (cpl.input_state == Reply_One) {
1790  cpl.input_text[1] = 0;
1791  }
1792 
1794 
1795  } else {
1797  /* Some spells (dimension door) need a valid count value */
1798  cpl.count = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(spinbutton_count));
1799 
1800  /* No reason to do anything for a null string */
1801  if (entry_text[0] != 0) {
1802  strncpy(history[cur_history_position], entry_text, MAX_COMMAND_LEN);
1804  cur_history_position++;
1805  cur_history_position %= MAX_HISTORY;
1807  extended_command(entry_text);
1808  }
1809  }
1810  gtk_entry_set_text(GTK_ENTRY(entry), "");
1811 
1812  /*
1813  * This grab focus is really just so the entry box doesn't have focus -
1814  * this way, keypresses are used to play the game, and not as stuff that
1815  * goes into the entry box. It doesn't make much difference what widget
1816  * this is set to, as long as it is something that can get focus.
1817  */
1818  gtk_widget_grab_focus(GTK_WIDGET(treeview_look));
1819 
1822  /*
1823  * This is the gtk_main that is started up by get_metaserver The client
1824  * will start another one once it is connected to a crossfire server
1825  */
1826  gtk_main_quit();
1827  }
1828 }
1829 
1843  int i, j;
1844  struct keybind *kb;
1845  char *modifier_label, *scope_label;
1846  GtkTreeIter iter;
1847 
1848  gtk_list_store_clear(keybinding_store);
1849  for (i = 0; i < KEYHASH; i++) {
1850  for (j = 0; j < 2; j++) {
1851  for (kb = (j == 0) ? keys_global[i] : keys_char[i]; kb != NULL; kb = kb->next) {
1852  if (j == 0) {
1853  kb->flags |= KEYF_R_GLOBAL;
1854  } else {
1855  kb->flags |= KEYF_R_CHAR;
1856  }
1857 
1858  if (kb->flags & KEYF_ANY) {
1859  modifier_label = "Any";
1860  } else if ((kb->flags & KEYF_MOD_MASK) == 0) {
1861  modifier_label = "None";
1862  } else {
1863  if (kb->flags & KEYF_MOD_ALT) {
1864  modifier_label = "Alt";
1865  if (kb->flags & (KEYF_MOD_SHIFT | KEYF_MOD_CTRL | KEYF_MOD_META)) {
1866  modifier_label = " + ";
1867  }
1868  }
1869  if (kb->flags & KEYF_MOD_SHIFT) {
1870  modifier_label = "Fire";
1871  if (kb->flags & (KEYF_MOD_CTRL | KEYF_MOD_META)) {
1872  modifier_label = " + ";
1873  }
1874  }
1875  if (kb->flags & KEYF_MOD_CTRL) {
1876  modifier_label = "Run";
1877  if (kb->flags & KEYF_MOD_META) {
1878  modifier_label = " + ";
1879  }
1880  }
1881  if (kb->flags & KEYF_MOD_META) {
1882  modifier_label = "Meta";
1883  }
1884  }
1885  if (!(kb->flags & KEYF_R_GLOBAL)) {
1886  scope_label = "char";
1887  } else {
1888  scope_label = "global";
1889  }
1890  gtk_list_store_append(keybinding_store, &iter);
1891  gtk_list_store_set(keybinding_store, &iter,
1892  KLIST_ENTRY, i,
1893  KLIST_KEY, gdk_keyval_name(kb->keysym),
1894  KLIST_MODS, modifier_label,
1895  KLIST_SCOPE, scope_label,
1896  KLIST_EDIT, (kb->flags & KEYF_EDIT) ? "Yes" : "No",
1897  KLIST_COMMAND, kb->command,
1898  KLIST_KEY_ENTRY, kb,
1899  -1);
1900  }
1901  }
1902  }
1904 }
1905 
1912 void on_keybindings_activate(GtkMenuItem *menuitem, gpointer user_data) {
1913  gtk_widget_show(keybinding_window);
1915 }
1916 
1929 gboolean
1931  GdkEventKey *event,
1932  gpointer user_data) {
1933  gtk_entry_set_text(
1934  GTK_ENTRY(keybinding_entry_key), gdk_keyval_name(event->keyval));
1935  /*
1936  * This code is basically taken from the GTKv1 client. However, at some
1937  * level it is broken, since the control/shift/etc masks are hardcoded, yet
1938  * we do let the users redefine them.
1939  *
1940  * The clearing of the modifiers is disabled. In my basic testing, I
1941  * checked the modifiers and then pressed the key - have those modifiers go
1942  * away I think is less intuitive.
1943  */
1944  if (event->state & GDK_CONTROL_MASK)
1945  gtk_toggle_button_set_active(
1946  GTK_TOGGLE_BUTTON(keybinding_checkbutton_control), TRUE);
1947 
1948 #if 0
1949  else
1950  gtk_toggle_button_set_active(
1951  GTK_TOGGLE_BUTTON(keybinding_checkbutton_control), FALSE);
1952 #endif
1953 
1954  if (event->state & GDK_SHIFT_MASK)
1955  gtk_toggle_button_set_active(
1956  GTK_TOGGLE_BUTTON(keybinding_checkbutton_shift), TRUE);
1957 
1958 #if 0
1959  else {
1960  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(keybinding_checkbutton_shift),
1961  FALSE);
1962  }
1963 
1964  /* The GDK_MOD_MASK* will likely correspond to alt and meta, yet there is
1965  * no way to be sure what goes to what, so easiest to just not allow them.
1966  */
1967  gtk_toggle_button_set_active(
1968  GTK_TOGGLE_BUTTON(keybinding_checkbutton_alt), FALSE);
1969  gtk_toggle_button_set_active(
1970  GTK_TOGGLE_BUTTON(keybinding_checkbutton_meta), FALSE);
1971 #endif
1972 
1973  /* Returning TRUE prevents widget from getting this event */
1974  return TRUE;
1975 }
1976 
1983 void toggle_buttons_scope(int scope) {
1984  int state_u, state_c;
1985 
1986  state_u = gtk_toggle_button_get_active(
1987  GTK_TOGGLE_BUTTON(kb_scope_togglebutton_global));
1988  state_c = gtk_toggle_button_get_active(
1989  GTK_TOGGLE_BUTTON(kb_scope_togglebutton_character));
1990  /* If the states of the buttons are not already what we are asked for, or if
1991  * they are equal (which is inconsistent) then update them. Deactivate the
1992  * callbacks for the "toggled" events temporarily to avoid an infinite loop.
1993  */
1994  if (state_u != scope || state_u == state_c) {
1995  g_signal_handlers_block_by_func(
1996  GTK_TOGGLE_BUTTON(kb_scope_togglebutton_character),
1997  G_CALLBACK(on_kb_scope_togglebutton_character_toggled), NULL);
1998  g_signal_handlers_block_by_func(
1999  GTK_TOGGLE_BUTTON(kb_scope_togglebutton_global),
2000  G_CALLBACK(on_kb_scope_togglebutton_global_toggled), NULL);
2001 
2002  gtk_toggle_button_set_active(
2003  GTK_TOGGLE_BUTTON(kb_scope_togglebutton_character), !scope);
2004  gtk_toggle_button_set_active(
2005  GTK_TOGGLE_BUTTON(kb_scope_togglebutton_global), scope);
2006 
2007  g_signal_handlers_unblock_by_func(
2008  GTK_TOGGLE_BUTTON(kb_scope_togglebutton_character),
2009  G_CALLBACK(on_kb_scope_togglebutton_character_toggled), NULL);
2010  g_signal_handlers_unblock_by_func(
2011  GTK_TOGGLE_BUTTON(kb_scope_togglebutton_global),
2012  G_CALLBACK(on_kb_scope_togglebutton_global_toggled), NULL);
2013  }
2014 }
2015 
2023 static int keybind_overwrite_confirm(struct keybind *kb) {
2024  GtkWidget *dialog, *label;
2025  int result;
2026  char buf[MAX_BUF], buf2[MAX_BUF];
2027 
2028  dialog = gtk_dialog_new_with_buttons(
2029  "Key already in use",
2030  GTK_WINDOW(keybinding_window),
2031  GTK_DIALOG_MODAL,
2032  GTK_STOCK_YES, 1,
2033  GTK_STOCK_NO, 2,
2034  NULL);
2035  get_key_modchars(kb, 1, buf2);
2036  snprintf(buf, sizeof(buf), "Overwrite this binding?\n (%s) %s\n%s",
2037  buf2, gdk_keyval_name(kb->keysym), kb->command);
2038  label = gtk_label_new(buf);
2039  gtk_box_pack_start(
2040  GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))),
2041  label, TRUE, TRUE, 0);
2042  gtk_widget_show_all(dialog);
2043 
2044  result = gtk_dialog_run(GTK_DIALOG(dialog));
2045  gtk_widget_destroy(dialog);
2046  return (result == 1);
2047 }
2048 
2058 void toggle_keybind_scope(int scope, struct keybind *kb) {
2059  struct keybind *kb_old, **next_ptr;
2060  int ret, flags;
2061  char buf[MAX_BUF];
2062 
2063  /* First check for matching bindings in the new scope */
2064  kb_old = keybind_find(kb->keysym, kb->flags, scope);
2065  while (kb_old) {
2066  if (!keybind_overwrite_confirm(kb_old)) {
2067  /* Restore all bindings and buttons state.
2068  * Need to call keybindings_init() because we may have already
2069  * removed some bindings from memory */
2070  toggle_buttons_scope(!scope);
2073  return;
2074  }
2075  /* Completely remove the old binding */
2076  keybind_remove(kb_old);
2077  keybind_free(&kb_old);
2078  kb_old = keybind_find(kb->keysym, kb->flags, scope);
2079  }
2080 
2081  /* If the new scope is 'global' we remove the binding from keys_char (don't
2082  * free it), switch scope flags and rehash in keys_global.
2083  *
2084  * Else just make a copy into keys_char only switching the state flags.
2085  */
2086  if (scope) {
2087  if ((kb->flags & KEYF_R_GLOBAL) == 0) {
2088  /* Remove kb from keys_char, don't free it. */
2089  ret = keybind_remove(kb);
2090  if (ret == -1) {
2092  "\nCould not remove keybind. Operation failed.\n");
2093  toggle_buttons_scope(!scope);
2096  return;
2097  }
2098  /* Place the modified kb in keys_global */
2099  kb->flags ^= KEYF_R_CHAR;
2100  kb->flags |= KEYF_R_GLOBAL;
2101  next_ptr = &keys_global[kb->keysym % KEYHASH];
2102  kb->next = NULL;
2103 
2104  if (*next_ptr) {
2105  while ((*next_ptr)->next) {
2106  next_ptr = &(*next_ptr)->next;
2107  }
2108  (*next_ptr)->next = kb;
2109  } else {
2110  keys_global[kb->keysym % KEYHASH] = kb;
2111  }
2112  }
2113  } else {
2114  if ((kb->flags & KEYF_R_GLOBAL) != 0) {
2115  /* Copy the selected binding in the char's scope with the right flags. */
2116  snprintf(buf, sizeof(buf), "%s", kb->command);
2117  flags = kb->flags;
2118  flags |= KEYF_R_CHAR;
2119  flags ^= KEYF_R_GLOBAL;
2120  keybind_insert(kb->keysym, flags, buf);
2121  }
2122  }
2123  save_keys();
2125 }
2126 
2134 void on_kb_scope_togglebutton_character_toggled(GtkToggleButton *toggle_button,
2135  gpointer user_data) {
2136  GtkTreeModel *model;
2137  GtkTreeIter iter;
2138  struct keybind *kb;
2139  gboolean scope;
2140  if (gtk_tree_selection_get_selected(keybinding_selection, &model, &iter)) {
2141  gtk_tree_model_get(model, &iter, KLIST_KEY_ENTRY, &kb, -1);
2142  scope = !gtk_toggle_button_get_active(
2143  GTK_TOGGLE_BUTTON(kb_scope_togglebutton_character));
2144  toggle_buttons_scope(scope);
2145  toggle_keybind_scope(scope, kb);
2146  }
2147 }
2148 
2156 void on_kb_scope_togglebutton_global_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_global));
2166  toggle_buttons_scope(scope);
2167  toggle_keybind_scope(scope, kb);
2168  }
2169 }
2170 
2179  gpointer user_data) {
2180  GtkTreeModel *model;
2181  GtkTreeIter iter;
2182  struct keybind *kb;
2183  int res;
2184 
2185  if (!gtk_tree_selection_get_selected(keybinding_selection, &model, &iter)) {
2186  LOG(LOG_ERROR, "keys.c::on_keybinding_button_remove_clicked",
2187  "Function called with nothing selected\n");
2188  return;
2189  }
2190  gtk_tree_model_get(model, &iter, KLIST_KEY_ENTRY, &kb, -1);
2191  res = keybind_remove(kb);
2192  if (res < 0)
2193  LOG(LOG_ERROR, "keys.c::on_keybinding_button_remove_clicked",
2194  "Unable to find matching key entry\n");
2195  keybind_free(&kb);
2196 
2197  save_keys();
2199 }
2200 
2210 static void keybinding_get_data(guint32 *keysym, guint8 *flags,
2211  const char **command) {
2212  static char bind_buf[MAX_BUF];
2213  const char *ed;
2214  *flags = 0;
2215 
2216  if (gtk_toggle_button_get_active(
2217  GTK_TOGGLE_BUTTON(keybinding_checkbutton_any))) {
2218  *flags |= KEYF_ANY;
2219  }
2220 
2221  if (gtk_toggle_button_get_active(
2222  GTK_TOGGLE_BUTTON(kb_scope_togglebutton_global))) {
2223  *flags |= KEYF_R_GLOBAL;
2224  }
2225 
2226  if (gtk_toggle_button_get_active(
2227  GTK_TOGGLE_BUTTON(keybinding_checkbutton_control))) {
2228  *flags |= KEYF_MOD_CTRL;
2229  }
2230  if (gtk_toggle_button_get_active(
2231  GTK_TOGGLE_BUTTON(keybinding_checkbutton_shift))) {
2232  *flags |= KEYF_MOD_SHIFT;
2233  }
2234  if (gtk_toggle_button_get_active(
2235  GTK_TOGGLE_BUTTON(keybinding_checkbutton_alt))) {
2236  *flags |= KEYF_MOD_ALT;
2237  }
2238  if (gtk_toggle_button_get_active(
2239  GTK_TOGGLE_BUTTON(keybinding_checkbutton_meta))) {
2240  *flags |= KEYF_MOD_META;
2241  }
2242  if (gtk_toggle_button_get_active(
2243  GTK_TOGGLE_BUTTON(keybinding_checkbutton_edit))) {
2244  *flags |= KEYF_EDIT;
2245  }
2246 
2247  ed = gtk_entry_get_text(GTK_ENTRY(keybinding_entry_command));
2248  if (strlen(ed) >= sizeof(bind_buf)) {
2250  "Keybinding too long! Truncated.");
2251  strncpy(bind_buf, ed, MAX_BUF - 1);
2252  bind_buf[MAX_BUF - 1] = 0;
2253  *command = bind_buf;
2254  } else {
2255  *command = ed;
2256  }
2257 
2258  /*
2259  * This isn't ideal - when the key is pressed, we convert it to a string,
2260  * and now we are converting it back. It'd be nice to tuck the keysym
2261  * itself away someplace.
2262  */
2263  *keysym = gdk_keyval_from_name(
2264  gtk_entry_get_text(GTK_ENTRY(keybinding_entry_key)));
2265  if (*keysym == GDK_VoidSymbol) {
2266  LOG(LOG_ERROR, "keys.c::keybinding_get_data",
2267  "Cannot get valid keysym from selection");
2268  }
2269 }
2270 
2277 void on_keybinding_button_bind_clicked(GtkButton *button, gpointer user_data) {
2278  guint32 keysym;
2279  guint8 flags;
2280  const char *command;
2281  struct keybind *kb;
2282 
2283  keybinding_get_data(&keysym, &flags, &command);
2284 
2285  /* keybind_insert will do a g_strdup of command for us */
2286  kb = keybind_find(keysym, flags, (flags & KEYF_R_GLOBAL));
2287  if (kb && (!keybind_overwrite_confirm(kb))) {
2288  return;
2289  }
2290  keybind_insert(keysym, flags, command);
2291 
2292  /*
2293  * I think it is more appropriate to clear the fields once the user adds
2294  * it. I suppose the ideal case would be to select the newly inserted
2295  * keybinding.
2296  */
2298  save_keys();
2300 }
2301 
2312  gpointer user_data) {
2313  GtkTreeIter iter;
2314  struct keybind *kb;
2315  GtkTreeModel *model;
2316  guint32 keysym;
2317  guint8 flags;
2318  const char *buf;
2319  int res;
2320 
2321  if (gtk_tree_selection_get_selected(keybinding_selection, &model, &iter)) {
2322  gtk_tree_model_get(model, &iter, KLIST_KEY_ENTRY, &kb, -1);
2323 
2324  if (!kb) {
2325  LOG(LOG_ERROR, "keys.c::on_keybinding_button_update_clicked",
2326  "Unable to get key_entry structure\n");
2327  return;
2328  }
2329 
2330  /* We need to rehash the binding (remove the old and add the
2331  * new) since the keysym might have changed. */
2332 
2333  keybind_remove(kb);
2334 
2335  keybinding_get_data(&keysym, &flags, &buf);
2336 
2337  res = keybind_insert(keysym, flags, buf);
2338  if (res == 0) {
2339  keybind_free(&kb);
2340  } else {
2341  /* Re-enter old binding if the update failed */
2342  keybind_insert(kb->keysym, kb->flags, kb->command);
2343  // FIXME: Popup dialog key in use
2344  }
2345 
2346  save_keys();
2348  } else {
2349  LOG(LOG_ERROR, "keys.c::on_keybinding_button_update_clicked",
2350  "Nothing selected to update\n");
2351  }
2352 }
2353 
2360 void on_keybinding_button_close_clicked(GtkButton *button, gpointer user_data) {
2361  gtk_widget_hide(keybinding_window);
2362 }
2363 
2371  gpointer user_data) {
2372  gboolean enabled;
2373 
2374  enabled = !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cb));
2375 
2376  gtk_widget_set_sensitive(GTK_WIDGET(keybinding_checkbutton_control), enabled);
2377  gtk_widget_set_sensitive(GTK_WIDGET(keybinding_checkbutton_shift), enabled);
2378  gtk_widget_set_sensitive(GTK_WIDGET(keybinding_checkbutton_alt), enabled);
2379  gtk_widget_set_sensitive(GTK_WIDGET(keybinding_checkbutton_meta), enabled);
2380 }
2381 
2395  GtkTreeSelection *selection,
2396  GtkTreeModel *model,
2397  GtkTreePath *path,
2398  gboolean path_currently_selected,
2399  gpointer userdata) {
2400  GtkTreeIter iter;
2401  struct keybind *kb;
2402 
2403  gtk_widget_set_sensitive(keybinding_button_remove, TRUE);
2404  gtk_widget_set_sensitive(keybinding_button_update, TRUE);
2405 
2406  if (gtk_tree_model_get_iter(model, &iter, path)) {
2407 
2408  gtk_tree_model_get(model, &iter, KLIST_KEY_ENTRY, &kb, -1);
2409 
2410  if (!kb) {
2411  LOG(LOG_ERROR, "keys.c::keybinding_selection_func",
2412  "Unable to get key_entry structure\n");
2413  return FALSE;
2414  }
2415  if (kb->flags & KEYF_ANY)
2416  gtk_toggle_button_set_active(
2417  GTK_TOGGLE_BUTTON(keybinding_checkbutton_any), TRUE);
2418  else
2419  gtk_toggle_button_set_active(
2420  GTK_TOGGLE_BUTTON(keybinding_checkbutton_any), FALSE);
2421 
2422  if (kb->flags & KEYF_MOD_CTRL)
2423  gtk_toggle_button_set_active(
2424  GTK_TOGGLE_BUTTON(keybinding_checkbutton_control), TRUE);
2425  else
2426  gtk_toggle_button_set_active(
2427  GTK_TOGGLE_BUTTON(keybinding_checkbutton_control), FALSE);
2428 
2429  if (kb->flags & KEYF_MOD_SHIFT)
2430  gtk_toggle_button_set_active(
2431  GTK_TOGGLE_BUTTON(keybinding_checkbutton_shift), TRUE);
2432  else
2433  gtk_toggle_button_set_active(
2434  GTK_TOGGLE_BUTTON(keybinding_checkbutton_shift), FALSE);
2435 
2436  if (kb->flags & KEYF_MOD_ALT)
2437  gtk_toggle_button_set_active(
2438  GTK_TOGGLE_BUTTON(keybinding_checkbutton_alt), TRUE);
2439  else
2440  gtk_toggle_button_set_active(
2441  GTK_TOGGLE_BUTTON(keybinding_checkbutton_alt), FALSE);
2442 
2443  if (kb->flags & KEYF_MOD_META)
2444  gtk_toggle_button_set_active(
2445  GTK_TOGGLE_BUTTON(keybinding_checkbutton_meta), TRUE);
2446  else
2447  gtk_toggle_button_set_active(
2448  GTK_TOGGLE_BUTTON(keybinding_checkbutton_meta), FALSE);
2449 
2450  if (kb->flags & KEYF_EDIT)
2451  gtk_toggle_button_set_active(
2452  GTK_TOGGLE_BUTTON(keybinding_checkbutton_edit), TRUE);
2453  else
2454  gtk_toggle_button_set_active(
2455  GTK_TOGGLE_BUTTON(keybinding_checkbutton_edit), FALSE);
2456 
2457  gtk_entry_set_text(
2458  GTK_ENTRY(keybinding_entry_key), gdk_keyval_name(kb->keysym));
2459  gtk_entry_set_text(
2460  GTK_ENTRY(keybinding_entry_command), kb->command);
2461 
2463  }
2464  return TRUE;
2465 }
2466 
2473  gtk_toggle_button_set_active(
2474  GTK_TOGGLE_BUTTON(keybinding_checkbutton_any), FALSE);
2475  gtk_toggle_button_set_active(
2476  GTK_TOGGLE_BUTTON(keybinding_checkbutton_control), FALSE);
2477  gtk_toggle_button_set_active(
2478  GTK_TOGGLE_BUTTON(keybinding_checkbutton_shift), FALSE);
2479  gtk_toggle_button_set_active(
2480  GTK_TOGGLE_BUTTON(keybinding_checkbutton_alt), FALSE);
2481  gtk_toggle_button_set_active(
2482  GTK_TOGGLE_BUTTON(keybinding_checkbutton_meta), FALSE);
2483  gtk_toggle_button_set_active(
2484  GTK_TOGGLE_BUTTON(keybinding_checkbutton_edit), FALSE);
2485  gtk_entry_set_text(GTK_ENTRY(keybinding_entry_key), "");
2486  gtk_entry_set_text(GTK_ENTRY(keybinding_entry_command), "");
2487 
2488  toggle_buttons_scope(FALSE);
2489 
2490  gtk_widget_set_sensitive(keybinding_button_remove, FALSE);
2491  gtk_widget_set_sensitive(keybinding_button_update, FALSE);
2492 }
2493 
2502 void on_keybinding_button_clear_clicked(GtkButton *button, gpointer user_data) {
2503  GtkTreeModel *model;
2504  GtkTreeIter iter;
2505 
2506  /*
2507  * As the cleared state is not supposed to have a keybinding selected,
2508  * deselect the currently selected keybinding if there is one.
2509  */
2510  if (gtk_tree_selection_get_selected(keybinding_selection, &model, &iter)) {
2511  gtk_tree_selection_unselect_iter(keybinding_selection, &iter);
2512  }
2513  reset_keybinding_status(); /* Clear inputs and reset buttons. */
2514 }
2515 
static int keybind_overwrite_confirm(struct keybind *kb)
Definition: keys.c:2023
GtkWidget * spinbutton_count
Definition: keys.c:63
static guint32 altkeysym[2]
Definition: keys.c:120
void on_kb_scope_togglebutton_character_toggled(GtkToggleButton *toggle_button, gpointer user_data)
Definition: keys.c:2134
void on_keybinding_checkbutton_any_clicked(GtkCheckButton *cb, gpointer user_data)
Definition: keys.c:2370
GtkBuilder * window_xml
Definition: main.c:86
static GtkWidget * keybinding_button_bind
Definition: keys.c:50
void toggle_buttons_scope(int scope)
Definition: keys.c:1983
gint16 use_config[CONFIG_NUMS]
Definition: init.c:40
#define KEYF_ANY
Definition: keys.c:148
static guint32 * bind_keysym
Definition: keys.c:120
gboolean keybinding_selection_func(GtkTreeSelection *selection, GtkTreeModel *model, GtkTreePath *path, gboolean path_currently_selected, gpointer userdata)
Definition: keys.c:2394
#define NDI_WHITE
Definition: newclient.h:222
GtkWidget * entry_commands
Definition: keys.c:64
static char * get_key_info(struct keybind *kb, int save_mode)
Definition: keys.c:975
static guint32 firekeysym[2]
Definition: keys.c:120
void on_entry_commands_activate(GtkEntry *entry, gpointer user_data)
Definition: keys.c:1773
void on_keybindings_activate(GtkMenuItem *menuitem, gpointer user_data)
Definition: keys.c:1912
static GtkWidget * keybinding_checkbutton_edit
Definition: keys.c:50
void toggle_keybind_scope(int scope, struct keybind *kb)
Definition: keys.c:2058
#define MAX_COMMAND_LEN
Definition: keys.c:87
void gtk_command_history(int direction)
Definition: keys.c:1705
void on_keybinding_button_remove_clicked(GtkButton *button, gpointer user_data)
Definition: keys.c:2178
void run_dir(int dir)
Definition: player.c:133
#define CONFIG_POPUPS
Definition: client.h:193
void on_keybinding_button_clear_clicked(GtkButton *button, gpointer user_data)
Definition: keys.c:2502
guint32 keysym
Definition: keys.c:103
void keyfunc(GtkWidget *widget, GdkEventKey *event, GtkWidget *window)
Definition: keys.c:1556
static void show_keys(void)
Definition: keys.c:1012
static struct keybind * keybind_find(guint32 keysym, unsigned int flags, int scope)
Definition: keys.c:192
Warning that something might not work.
Definition: client.h:443
#define MSG_TYPE_CLIENT_QUERY
Definition: newclient.h:662
guint8 flags
Definition: keys.c:101
static int keybind_insert(guint32 keysym, unsigned int flags, const char *command)
Definition: keys.c:221
ClientSocket csocket
Definition: client.c:69
int make_path_to_file(char *filename)
Definition: misc.c:85
static GtkWidget * keybinding_checkbutton_shift
Definition: keys.c:50
void update_keybinding_list(void)
Definition: keys.c:1842
gboolean on_keybinding_entry_key_key_press_event(GtkWidget *widget, GdkEventKey *event, gpointer user_data)
Definition: keys.c:1930
#define MSG_TYPE_CLIENT
Definition: newclient.h:395
static int cur_history_position
Definition: keys.c:90
#define KEYHASH
Definition: keys.c:157
static GtkWidget * keybinding_checkbutton_control
Definition: keys.c:50
GtkWidget * treeview_look
Definition: inventory.c:38
void on_keybinding_button_update_clicked(GtkButton *button, gpointer user_data)
Definition: keys.c:2311
#define NDI_BLACK
Definition: newclient.h:221
const char *const directions[9]
Definition: player.c:34
#define KEYF_MOD_META
Definition: keys.c:142
guint32 meta_on
Definition: client.h:356
static void init_default_keybindings()
Definition: keys.c:489
static GtkWidget * keybinding_checkbutton_alt
Definition: keys.c:50
static guint32 completekeysym
Definition: keys.c:120
static guint32 prevkeysym
Definition: keys.c:120
static void save_individual_key(FILE *fp, struct keybind *kb, KeyCode kc)
Definition: keys.c:1244
guint32 alt_on
Definition: client.h:357
void LOG(LogLevel level, const char *origin, const char *format,...)
Definition: misc.c:109
void client_disconnect()
Definition: client.c:180
void on_keybinding_button_bind_clicked(GtkButton *button, gpointer user_data)
Definition: keys.c:2277
#define MSG_TYPE_CLIENT_ERROR
Definition: newclient.h:667
#define NDI_RED
Definition: newclient.h:224
void gtk_complete_command(void)
Definition: keys.c:1752
static GtkWidget * keybinding_treeview
Definition: keys.c:50
char * servername
Definition: client.h:131
#define KEYF_MOD_SHIFT
Definition: keys.c:139
void x_set_echo(void)
Definition: keys.c:1686
static GtkWidget * kb_scope_togglebutton_global
Definition: keys.c:50
GtkWidget * window_root
Definition: main.c:87
static GtkWidget * fire_label
Definition: keys.c:50
#define MSG_TYPE_CLIENT_NOTICE
Definition: newclient.h:664
void draw_message_window(int redraw)
Definition: stats.c:459
void clear_fire()
Definition: player.c:98
static int scroll_history_position
Definition: keys.c:90
static int parse_keys_file(char *filename, unsigned int scope_flag)
Definition: keys.c:506
static void save_keys(void)
Definition: keys.c:1258
Client_Player cpl
Definition: client.c:68
static GtkTreeSelection * keybinding_selection
Definition: keys.c:61
#define KEYF_MOD_ALT
Definition: keys.c:141
static guint32 nextkeysym
Definition: keys.c:120
static struct keybind * keys_char[KEYHASH]
Definition: keys.c:167
#define KEYF_MOD_MASK
Definition: keys.c:143
#define MAX_BUF
Definition: client.h:40
const char * config_dir
Definition: client.c:52
void extended_command(const char *ocommand)
Definition: p_cmd.c:484
void keys_init(GtkWidget *window_root)
Definition: keys.c:621
void send_reply(const char *text)
Definition: commands.c:1584
static GtkWidget * run_label
Definition: keys.c:50
const char * complete_command(const char *command)
Definition: p_cmd.c:583
guint32 count
Definition: client.h:359
static GtkWidget * keybinding_button_remove
Definition: keys.c:50
static int keybind_remove(struct keybind *entry)
Definition: keys.c:275
Warning that something definitely didn't work.
Definition: client.h:444
void stop_fire()
Definition: player.c:91
static guint32 commandkeysym
Definition: keys.c:120
static int bind_flags
Definition: keys.c:124
static GtkWidget * keybinding_checkbutton_meta
Definition: keys.c:50
static guint32 runkeysym[2]
Definition: keys.c:120
guint32 run_on
Definition: client.h:355
static GtkWidget * keybinding_button_update
Definition: keys.c:50
static void configure_keys(guint32 keysym)
Definition: keys.c:1353
gint8 direction
Definition: keys.c:102
#define KEYF_R_CHAR
Definition: keys.c:153
static struct keybind * keys_global[KEYHASH]
Definition: keys.c:167
static void parse_key_release(guint32 keysym)
Definition: keys.c:775
#define BIG_BUF
Definition: client.h:41
static guint32 metakeysym[2]
Definition: keys.c:120
void focusoutfunc(GtkWidget *widget, GdkEventKey *event, GtkWidget *window)
Definition: keys.c:1513
void draw_ext_info(int orig_color, int type, int subtype, const char *message)
Definition: info.c:932
static void keybind_free(struct keybind **entry)
Definition: keys.c:295
void on_keybinding_button_close_clicked(GtkButton *button, gpointer user_data)
Definition: keys.c:2360
char * command
Definition: keys.c:104
static void unbind_usage(void)
Definition: keys.c:1441
static GtkListStore * keybinding_store
Definition: keys.c:60
Input_State input_state
Definition: client.h:341
static char bind_buf[MAX_BUF]
Definition: keys.c:125
static guint32 cancelkeysym
Definition: keys.c:120
static void parse_key(char key, guint32 keysym)
Definition: keys.c:814
#define KEYF_R_GLOBAL
Definition: keys.c:152
static void get_key_modchars(struct keybind *kb, int save_mode, char *buf)
Definition: keys.c:937
#define KEYF_EDIT
Definition: keys.c:149
Definition: keys.c:75
char input_text[MAX_BUF]
Definition: client.h:343
static GtkWidget * kb_scope_togglebutton_character
Definition: keys.c:50
#define EKEYBIND_NOMEM
Definition: keys.c:174
static GtkWidget * keybinding_window
Definition: keys.c:50
static void parse_keybind_line(char *buf, int line, unsigned int scope_flag)
Definition: keys.c:309
Definition: keys.c:100
static GtkWidget * keybinding_checkbutton_any
Definition: keys.c:50
guint32 no_echo
Definition: client.h:358
void bind_key(char *params)
Definition: keys.c:1076
void unbind_key(const char *params)
Definition: keys.c:1452
#define CONFIG_ECHO
Definition: client.h:186
void on_kb_scope_togglebutton_global_toggled(GtkToggleButton *toggle_button, gpointer user_data)
Definition: keys.c:2156
void reset_keybinding_status(void)
Definition: keys.c:2472
void draw_prompt(const char *str)
Definition: keys.c:1695
GtkBuilder * dialog_xml
Definition: main.c:86
Useful debugging information.
Definition: client.h:441
static GtkWidget * keybinding_entry_command
Definition: keys.c:50
void clear_run()
Definition: player.c:105
void stop_run()
Definition: player.c:128
char * name
Definition: client.h:369
struct keybind * next
Definition: keys.c:105
guint32 fire_on
Definition: client.h:354
Minor, non-harmful issues.
Definition: client.h:442
void fire_dir(int dir)
Definition: player.c:112
char history[MAX_HISTORY][MAX_COMMAND_LEN]
Definition: keys.c:88
static GtkWidget * keybinding_entry_key
Definition: keys.c:50
void keyrelfunc(GtkWidget *widget, GdkEventKey *event, GtkWidget *window)
Definition: keys.c:1542
static void keybinding_get_data(guint32 *keysym, guint8 *flags, const char **command)
Definition: keys.c:2210
#define KEYF_MOD_CTRL
Definition: keys.c:140
#define MAX_HISTORY
Definition: keys.c:86
#define MSG_TYPE_CLIENT_CONFIG
Definition: newclient.h:659
void keybindings_init(const char *character_name)
Definition: keys.c:534