Crossfire Client, Trunk  R20922
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 
181 static bool debounce = false;
182 
199 static struct keybind *keybind_find(guint32 keysym, unsigned int flags,
200  int scope) {
201  struct keybind *kb;
202  kb = scope ? keys_global[keysym % KEYHASH] : keys_char[keysym % KEYHASH];
203  while (kb != NULL) {
204  if (kb->keysym == 0 || kb->keysym == keysym) {
205  if ((kb->flags & KEYF_ANY) || (flags & KEYF_ANY)) {
206  return kb;
207  }
208  if ((kb->flags & KEYF_MOD_MASK) == (flags & KEYF_MOD_MASK)) {
209  return kb;
210  }
211  }
212  kb = kb->next;
213  }
214 
215  return NULL;
216 }
217 
228 static int keybind_insert(guint32 keysym, unsigned int flags,
229  const char *command) {
230  struct keybind **next_ptr, *kb;
231  int slot;
232  int i;
233  int dir;
234 
235  kb = keybind_find(keysym, flags, (flags & KEYF_R_GLOBAL));
236  while (kb != NULL) {
237  /*
238  * Keep the last binding instead of the first (backwards compatible).
239  *
240  * Also, if the new binding has the ANY flag, remove all matching
241  * previous bindings and keep this one.
242  */
243  LOG(LOG_DEBUG, "gtk-v2::keybind_insert",
244  "Overwriting previous binding for key %s with command %s ",
245  gdk_keyval_name(keysym), kb->command);
246  keybind_remove(kb);
247  keybind_free(&kb);
248  kb = keybind_find(keysym, flags, (flags & KEYF_R_GLOBAL));
249  }
250 
251  slot = keysym % KEYHASH;
252 
253  next_ptr = (flags & KEYF_R_GLOBAL) ? &keys_global[slot] : &keys_char[slot];
254  while (*next_ptr) {
255  next_ptr = &(*next_ptr)->next;
256  }
257  *next_ptr = calloc(1, sizeof(**next_ptr));
258  if (*next_ptr == NULL) {
259  return -EKEYBIND_NOMEM;
260  }
261 
262  (*next_ptr)->keysym = keysym;
263  (*next_ptr)->flags = flags;
264  (*next_ptr)->command = g_strdup(command);
265 
266  /*
267  * Try to find out if the command is a direction command. If so, keep
268  * track of this fact, so in fire or run mode, things work correctly.
269  */
270  dir = -1;
271  for (i = 0; i < 9; i++) {
272  if (!strcmp(command, directions[i])) {
273  dir = i;
274  break;
275  }
276  }
277  (*next_ptr)->direction = dir;
278 
279  return 0;
280 }
281 
282 static int keybind_remove(struct keybind *entry) {
283  struct keybind **next_ptr;
284  int slot;
285 
286  slot = entry->keysym % KEYHASH;
287 
288  next_ptr = (entry->flags & KEYF_R_GLOBAL) ? &keys_global[slot] :
289  &keys_char[slot];
290  while (*next_ptr) {
291  if (*next_ptr == entry) {
292  *next_ptr = entry->next;
293  return 0;
294  }
295  next_ptr = &(*next_ptr)->next;
296  }
297 
298  /* No such key entry */
299  return -1;
300 }
301 
302 static void keybind_free(struct keybind **entry) {
303  free((*entry)->command);
304  (*entry)->command = NULL;
305  free(*entry);
306  *entry = NULL;
307 }
308 
316 static void parse_keybind_line(char *buf, int line, unsigned int scope_flag) {
317  char *cp, *cpnext;
318  guint32 keysym, low_keysym;
319  int flags;
320 
321  /*
322  * There may be a rare error case when cp is used uninitialized. So let's
323  * be safe
324  */
325  cp = NULL;
326 
327  if (buf[0] == '#' || buf[0] == '\n') {
328  return;
329  }
330  cpnext = strchr(buf, ' ');
331  if (cpnext == NULL) {
332  LOG(LOG_WARNING, "gtk-v2::parse_keybind_line",
333  "Line %d (%s) corrupted in keybinding file.", line, buf);
334  return;
335  }
336  /* Special keybinding line */
337  if (buf[0] == '!') {
338  char *cp1;
339  while (*cpnext == ' ') {
340  ++cpnext;
341  }
342  cp = strchr(cpnext, ' ');
343  if (!cp) {
344  LOG(LOG_WARNING, "gtk-v2::parse_keybind_line",
345  "Line %d (%s) corrupted in keybinding file.", line, buf);
346  return;
347  }
348  *cp++ = 0; /* Null terminate it */
349  cp1 = strchr(cp, ' ');
350  if (!cp1) {
351  LOG(LOG_WARNING, "gtk-v2::parse_keybind_line",
352  "Line %d (%s) corrupted in keybinding file.", line, buf);
353  return;
354  }
355  *cp1++ = 0; /* Null terminate it */
356  keysym = gdk_keyval_from_name(cp);
357  /* As of now, all these keys must have keysyms */
358  if (keysym == 0) {
359  LOG(LOG_WARNING, "gtk-v2::parse_keybind_line",
360  "Could not convert %s into keysym", cp);
361  return;
362  }
363  if (!strcmp(cpnext, "commandkey")) {
365  return;
366  }
367  if (!strcmp(cpnext, "altkey0")) {
368  altkeysym[0] = keysym;
369  return;
370  }
371  if (!strcmp(cpnext, "altkey1")) {
372  altkeysym[1] = keysym;
373  return;
374  }
375  if (!strcmp(cpnext, "firekey0")) {
376  firekeysym[0] = keysym;
377  return;
378  }
379  if (!strcmp(cpnext, "firekey1")) {
380  firekeysym[1] = keysym;
381  return;
382  }
383  if (!strcmp(cpnext, "metakey0")) {
384  metakeysym[0] = keysym;
385  return;
386  }
387  if (!strcmp(cpnext, "metakey1")) {
388  metakeysym[1] = keysym;
389  return;
390  }
391  if (!strcmp(cpnext, "runkey0")) {
392  runkeysym[0] = keysym;
393  return;
394  }
395  if (!strcmp(cpnext, "runkey1")) {
396  runkeysym[1] = keysym;
397  return;
398  }
399  if (!strcmp(cpnext, "completekey")) {
401  return;
402  }
403  if (!strcmp(cpnext, "nextkey")) {
404  nextkeysym = keysym;
405  return;
406  }
407  if (!strcmp(cpnext, "prevkey")) {
408  prevkeysym = keysym;
409  return;
410  }
411  } else {
412  *cpnext++ = '\0';
413  keysym = gdk_keyval_from_name(buf);
414  if (!keysym) {
415  LOG(LOG_WARNING, "gtk-v2::parse_keybind_line",
416  "Unable to convert line %d (%s) into keysym", line, cp);
417  return;
418  }
419  cp = cpnext;
420  cpnext = strchr(cp, ' ');
421  if (cpnext == NULL) {
422  LOG(LOG_WARNING, "gtk-v2::parse_keybind_line",
423  "Line %d (%s) corrupted in keybinding file.", line, cp);
424  return;
425  }
426  *cpnext++ = '\0';
427 
428  cp = cpnext;
429  cpnext = strchr(cp, ' ');
430  if (cpnext == NULL) {
431  LOG(LOG_WARNING, "gtk-v2::parse_keybind_line",
432  "Line %d (%s) corrupted in keybinding file.", line, cp);
433  return;
434  }
435  *cpnext++ = '\0';
436 
437  flags = 0;
438  low_keysym = gdk_keyval_to_lower(keysym);
439  if (low_keysym != keysym) {
440  /* This binding is uppercase, switch to lowercase and flag the shift modifier */
441  flags |= KEYF_MOD_SHIFT;
442  keysym = low_keysym;
443  }
444  while (*cp != '\0') {
445  switch (*cp) {
446  case 'A':
447  flags |= KEYF_ANY;
448  break;
449  case 'E':
450  flags |= KEYF_EDIT;
451  break;
452  case 'F':
453  flags |= KEYF_MOD_SHIFT;
454  break;
455  case 'L': /* A is used, so using L for alt */
456  flags |= KEYF_MOD_ALT;
457  break;
458  case 'M':
459  flags |= KEYF_MOD_META;
460  break;
461  case 'N':
462  /* Nothing to do */
463  break;
464  case 'R':
465  flags |= KEYF_MOD_CTRL;
466  break;
467  case 'S':
468  LOG(LOG_WARNING, "gtk-v2::parse_keybind_line",
469  "Deprecated flag (S) ignored at line %d in key binding file", line);
470  break;
471  default:
472  LOG(LOG_WARNING, "gtk-v2::parse_keybind_line",
473  "Unknown flag (%c) line %d in key binding file",
474  *cp, line);
475  }
476  cp++;
477  }
478 
479  /* Rest of the line is the actual command. Lets kill the newline */
480  cpnext[strlen(cpnext) - 1] = '\0';
481  if (strlen(cpnext) > (sizeof(bind_buf) - 1)) {
482  cpnext[sizeof(bind_buf) - 1] = '\0';
483  LOG(LOG_WARNING, "gtk-v2::parse_keybind_line",
484  "Command too long! Truncated.");
485  }
486 
487  flags |= scope_flag; /* add the corresponding scope flag */
488  keybind_insert(keysym, flags, cpnext);
489 
490  } /* else if not special binding line */
491 }
492 
497  LOG(LOG_DEBUG, "init_default_keybindings", "Loading default keybindings");
498  for (size_t i = 0; i < sizeof(def_keys) / sizeof(char *); i++) {
499  char *nextline = g_strdup(def_keys[i]);
500  parse_keybind_line(nextline, i, KEYF_R_GLOBAL);
501  free(nextline);
502  }
503 }
504 
513 static int parse_keys_file(char *filename, unsigned int scope_flag) {
514  FILE *fp;
515  char buf[BIG_BUF];
516  int line = 0;
517 
518  fp = fopen(filename, "r");
519  if (fp == NULL) {
520  return -1;
521  }
522 
523  LOG(LOG_DEBUG, "init_keys", "Reading %s keybindings from '%s'",
524  scope_flag == KEYF_R_GLOBAL ? "global" : "character", filename);
525 
526  while (fgets(buf, BIG_BUF, fp)) {
527  line++;
528  buf[BIG_BUF - 1] = '\0';
529  parse_keybind_line(buf, line, scope_flag);
530  }
531 
532  fclose(fp);
533  return 0;
534 }
535 
541 void keybindings_init(const char *character_name) {
542  char buf[BIG_BUF];
543  int i;
544 
545  /* Clear out the bind history. */
546  for (i = 0; i < MAX_HISTORY; i++) {
547  history[i][0] = 0;
548  }
549 
550  commandkeysym = GDK_apostrophe;
551  firekeysym[0] = GDK_Shift_L;
552  firekeysym[1] = GDK_Shift_R;
553  runkeysym[0] = GDK_Control_L;
554  runkeysym[1] = GDK_Control_R;
555  metakeysym[0] = GDK_Meta_L;
556  metakeysym[1] = GDK_Meta_R;
557  altkeysym[0] = GDK_Alt_L;
558  altkeysym[1] = GDK_Alt_R;
559 
560  completekeysym = GDK_Tab;
561  cancelkeysym = GDK_Escape;
562 
563  /*
564  * Don't set these to anything by default. At least on Sun keyboards, the
565  * keysym for up on both the keypad and arrow keys is the same, so player
566  * needs to rebind this so we get proper keycode. Very unfriendly to log
567  * in and not be able to move north/south.
568  */
569  nextkeysym = NoSymbol;
570  prevkeysym = NoSymbol;
571 
572  for (i = 0; i < KEYHASH; i++) {
573  while (keys_global[i]) {
574  keybind_remove(keys_global[i]);
575  }
576 
577  while (keys_char[i]) {
578  keybind_remove(keys_char[i]);
579  }
580  }
581 
582  /*
583  * If we were supplied with a character name, store it so that we
584  * can load and save a character-specific keys file.
585  */
586  if (cpl.name) {
587  free(cpl.name);
588  cpl.name = NULL;
589  }
590  if (character_name) {
591  cpl.name = g_strdup(character_name);
592  }
593 
594  /*
595  * We now try to load the keybindings. First load defaults.
596  * Then go through the more specific files in the home directory:
597  * 1) user wide "~/.crossfire/keys".
598  * 2) and, if character name is known, "~/.crossfire/<name>.keys"
599  *
600  * The format is described in the def_keys file. Note that this file is
601  * the same as what it was in the server distribution. To convert bindings
602  * in character files to this format, all that needs to be done is remove
603  * the 'key ' at the start of each line.
604  */
605 
607 
608  /* Try to load global keybindings. */
609  snprintf(buf, sizeof(buf), "%s/keys", config_dir);
611 
612  /* Try to load the character-specific keybindings. */
613  if (cpl.name) {
614  snprintf(buf, sizeof(buf), "%s/%s.%s.keys", config_dir,
617  }
618 }
619 
620 
628 void keys_init(GtkWidget *window_root) {
629  GtkTreeViewColumn *column;
630  GtkCellRenderer *renderer;
631  GtkWidget *widget;
632  int i;
633 
634  fire_label = GTK_WIDGET(gtk_builder_get_object(window_xml, "fire_label"));
635  run_label = GTK_WIDGET(gtk_builder_get_object(window_xml, "run_label"));
636  entry_commands = GTK_WIDGET(gtk_builder_get_object(window_xml,
637  "entry_commands"));
638  spinbutton_count = GTK_WIDGET(gtk_builder_get_object(window_xml,
639  "spinbutton_count"));
640 
641  g_signal_connect((gpointer) entry_commands, "activate",
642  G_CALLBACK(on_entry_commands_activate), NULL);
643 
644  keybinding_window = GTK_WIDGET(gtk_builder_get_object(dialog_xml,
645  "keybinding_window"));
646 
648  GTK_WIDGET(gtk_builder_get_object(dialog_xml, "kb_scope_togglebutton_global"));
650  GTK_WIDGET(gtk_builder_get_object(dialog_xml,
651  "kb_scope_togglebutton_character"));
653  GTK_WIDGET(gtk_builder_get_object(dialog_xml, "keybinding_checkbutton_any"));
655  GTK_WIDGET(gtk_builder_get_object(dialog_xml,
656  "keybinding_checkbutton_control"));
658  GTK_WIDGET(gtk_builder_get_object(dialog_xml, "keybinding_checkbutton_shift"));
660  GTK_WIDGET(gtk_builder_get_object(dialog_xml, "keybinding_checkbutton_alt"));
662  GTK_WIDGET(gtk_builder_get_object(dialog_xml, "keybinding_checkbutton_meta"));
664  GTK_WIDGET(gtk_builder_get_object(dialog_xml,
665  "keybinding_checkbutton_stayinedit"));
667  GTK_WIDGET(gtk_builder_get_object(dialog_xml, "keybinding_entry_key"));
669  GTK_WIDGET(gtk_builder_get_object(dialog_xml, "keybinding_entry_command"));
671  GTK_WIDGET(gtk_builder_get_object(dialog_xml, "keybinding_treeview"));
673  GTK_WIDGET(gtk_builder_get_object(dialog_xml, "keybinding_button_remove"));
675  GTK_WIDGET(gtk_builder_get_object(dialog_xml, "keybinding_button_update"));
677  GTK_WIDGET(gtk_builder_get_object(dialog_xml, "keybinding_button_bind"));
678 
679  g_signal_connect((gpointer) keybinding_window, "delete_event",
680  G_CALLBACK(gtk_widget_hide_on_delete), NULL);
681  g_signal_connect((gpointer) keybinding_entry_key, "key_press_event",
682  G_CALLBACK(on_keybinding_entry_key_key_press_event), NULL);
683  g_signal_connect((gpointer) keybinding_button_remove, "clicked",
684  G_CALLBACK(on_keybinding_button_remove_clicked), NULL);
685  g_signal_connect((gpointer) keybinding_button_update, "clicked",
686  G_CALLBACK(on_keybinding_button_update_clicked), NULL);
687  g_signal_connect((gpointer) keybinding_button_bind, "clicked",
688  G_CALLBACK(on_keybinding_button_bind_clicked), NULL);
689 
690  g_signal_connect((gpointer) kb_scope_togglebutton_character, "toggled",
692  g_signal_connect((gpointer) kb_scope_togglebutton_global, "toggled",
693  G_CALLBACK(on_kb_scope_togglebutton_global_toggled), NULL);
694 
695  g_signal_connect((gpointer) keybinding_checkbutton_any, "clicked",
696  G_CALLBACK(on_keybinding_checkbutton_any_clicked), NULL);
697 
698  widget = GTK_WIDGET(gtk_builder_get_object(dialog_xml,
699  "keybinding_button_clear"));
700  g_signal_connect((gpointer) widget, "clicked",
701  G_CALLBACK(on_keybinding_button_clear_clicked), NULL);
702 
703  widget = GTK_WIDGET(gtk_builder_get_object(dialog_xml,
704  "keybinding_button_close"));
705  g_signal_connect((gpointer) widget, "clicked",
706  G_CALLBACK(on_keybinding_button_close_clicked), NULL);
707 
708  gtk_widget_set_sensitive(keybinding_button_remove, FALSE);
709  gtk_widget_set_sensitive(keybinding_button_update, FALSE);
710  keybinding_store = gtk_list_store_new(7,
711  G_TYPE_INT,
712  G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING,
713  G_TYPE_POINTER
714  );
715  gtk_tree_view_set_model(GTK_TREE_VIEW(keybinding_treeview),
716  GTK_TREE_MODEL(keybinding_store));
717 
718  renderer = gtk_cell_renderer_text_new();
719  column = gtk_tree_view_column_new_with_attributes("Key", renderer,
720  "text", KLIST_KEY,
721  NULL);
722  gtk_tree_view_column_set_sort_column_id(column, KLIST_KEY);
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("Modifiers", renderer,
727  "text", KLIST_MODS,
728  NULL);
729  gtk_tree_view_column_set_sort_column_id(column, KLIST_MODS);
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("Scope", renderer,
734  "text", KLIST_SCOPE,
735  NULL);
736  gtk_tree_view_column_set_sort_column_id(column, KLIST_SCOPE);
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("Edit Mode", renderer,
741  "text", KLIST_EDIT,
742  NULL);
743  gtk_tree_view_column_set_sort_column_id(column, KLIST_EDIT);
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("Command", renderer,
748  "text", KLIST_COMMAND,
749  NULL);
750  gtk_tree_view_column_set_sort_column_id(column, KLIST_COMMAND);
751  gtk_tree_view_append_column(GTK_TREE_VIEW(keybinding_treeview), column);
752 
753 
754  keybinding_selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(
756  gtk_tree_selection_set_mode(keybinding_selection, GTK_SELECTION_BROWSE);
757  gtk_tree_selection_set_select_function(keybinding_selection,
758  keybinding_selection_func, NULL, NULL);
759 
760  gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(keybinding_store),
761  KLIST_KEY,
762  GTK_SORT_ASCENDING);
763 
764  for (i = 0; i < KEYHASH; i++) {
765  keys_global[i] = NULL;
766  keys_char[i] = NULL;
767  }
768 }
769 
782 static void parse_key_release(guint32 keysym) {
783 
784  /*
785  * Only send stop firing/running commands if we are in actual play mode.
786  * Something smart does need to be done when the character enters a non
787  * play mode with fire or run mode already set, however.
788  */
789  if (keysym == firekeysym[0] || keysym == firekeysym[1]) {
790  cpl.fire_on = 0;
791  clear_fire();
792  gtk_label_set_text(GTK_LABEL(fire_label), " ");
793  } else if (keysym == runkeysym[0] || keysym == runkeysym[1]) {
794  cpl.run_on = 0;
795  if (use_config[CONFIG_ECHO])
797  "stop run");
798  clear_run();
799  gtk_label_set_text(GTK_LABEL(run_label), " ");
800  } else if (keysym == altkeysym[0] || keysym == altkeysym[1]) {
801  cpl.alt_on = 0;
802  } else if (keysym == metakeysym[0] || keysym == metakeysym[1]) {
803  cpl.meta_on = 0;
804  }
805  /*
806  * Firing is handled on server side. However, to keep more like the old
807  * version, if you release the direction key, you want the firing to stop.
808  * This should do that.
809  */
810  else if (cpl.fire_on) {
811  clear_fire();
812  }
813 }
814 
821 static void parse_key(char key, guint32 keysym) {
822  struct keybind *kb;
823  int present_flags = 0;
824  char buf[MAX_BUF], tmpbuf[MAX_BUF];
825 
826  /* We handle the Shift key separately */
827  keysym = gdk_keyval_to_lower(keysym);
828 
829  if (keysym == commandkeysym) {
830  gtk_widget_grab_focus(GTK_WIDGET(entry_commands));
831  gtk_entry_set_visibility(GTK_ENTRY(entry_commands), 1);
833  cpl.no_echo = FALSE;
834  return;
835  }
836  if (keysym == altkeysym[0] || keysym == altkeysym[1]) {
837  cpl.alt_on = 1;
838  return;
839  }
840  if (keysym == metakeysym[0] || keysym == metakeysym[1]) {
841  cpl.meta_on = 1;
842  return;
843  }
844  if (keysym == firekeysym[0] || keysym == firekeysym[1]) {
845  cpl.fire_on = 1;
846  gtk_label_set_text(GTK_LABEL(fire_label), "Fire");
847  return;
848  }
849  if (keysym == runkeysym[0] || keysym == runkeysym[1]) {
850  cpl.run_on = 1;
851  gtk_label_set_text(GTK_LABEL(run_label), "Run");
852  return;
853  }
854 
855  present_flags = 0;
856  if (cpl.run_on) {
857  present_flags |= KEYF_MOD_CTRL;
858  }
859  if (cpl.fire_on) {
860  present_flags |= KEYF_MOD_SHIFT;
861  }
862  if (cpl.alt_on) {
863  present_flags |= KEYF_MOD_ALT;
864  }
865  if (cpl.meta_on) {
866  present_flags |= KEYF_MOD_META;
867  }
868 
869  kb = keybind_find(keysym, present_flags, 0); /* char scope */
870  if (kb == NULL) {
871  kb = keybind_find(keysym, present_flags, 1); /* global scope */
872  }
873  if (kb != NULL) {
874  if (kb->flags & KEYF_EDIT) {
875  strcpy(cpl.input_text, kb->command);
877  gtk_entry_set_text(GTK_ENTRY(entry_commands), cpl.input_text);
878  gtk_widget_grab_focus(GTK_WIDGET(entry_commands));
879  gtk_editable_select_region(GTK_EDITABLE(entry_commands), 0, 0);
880  gtk_editable_set_position(GTK_EDITABLE(entry_commands), -1);
881  return;
882  }
883 
884  /* Some spells (dimension door) need a valid count value */
885  cpl.count = gtk_spin_button_get_value_as_int(
886  GTK_SPIN_BUTTON(spinbutton_count));
887 
888  if (kb->direction >= 0) {
889  if (cpl.fire_on) {
890  snprintf(buf, sizeof(buf), "fire %s", kb->command);
891  fire_dir(kb->direction);
892  } else if (cpl.run_on) {
893  snprintf(buf, sizeof(buf), "run %s", kb->command);
894  run_dir(kb->direction);
895  } else {
897  }
898  if (use_config[CONFIG_ECHO])
901  kb->command);
902  } else {
903  if (use_config[CONFIG_ECHO])
906  kb->command);
908  }
909  return;
910  }
911 
912  if (key >= '0' && key <= '9') {
913  cpl.count = cpl.count * 10 + (key - '0');
914  if (cpl.count > 100000) {
915  cpl.count %= 100000;
916  }
917  gtk_spin_button_set_value(GTK_SPIN_BUTTON(spinbutton_count), (float) cpl.count);
918  return;
919  }
920  tmpbuf[0] = 0;
921  if (cpl.fire_on) {
922  strcat(tmpbuf, "fire+");
923  }
924  if (cpl.run_on) {
925  strcat(tmpbuf, "run+");
926  }
927  if (cpl.alt_on) {
928  strcat(tmpbuf, "alt+");
929  }
930  if (cpl.meta_on) {
931  strcat(tmpbuf, "meta+");
932  }
933 
934  snprintf(buf, sizeof(buf),
935  "Key %s%s is not bound to any command. Use 'bind' to associate this keypress with a command",
936  tmpbuf, keysym == NoSymbol ? "unknown" : gdk_keyval_name(keysym));
937 #ifdef WIN32
938  if ((65513 != keysym) && (65511 != keysym))
939 #endif
941  cpl.count = 0;
942 }
943 
944 static void get_key_modchars(struct keybind *kb, int save_mode, char *buf) {
945  int bi = 0;
946 
947  if (kb->flags & KEYF_ANY) {
948  buf[bi++] = 'A';
949  }
950  if (save_mode || !(kb->flags & KEYF_ANY)) {
951  if ((kb->flags & KEYF_MOD_MASK) == 0) {
952  buf[bi++] = 'N';
953  }
954  if (kb->flags & KEYF_MOD_SHIFT) {
955  buf[bi++] = 'F';
956  }
957  if (kb->flags & KEYF_MOD_CTRL) {
958  buf[bi++] = 'R';
959  }
960  if (kb->flags & KEYF_MOD_ALT) {
961  buf[bi++] = 'L';
962  }
963  if (kb->flags & KEYF_MOD_META) {
964  buf[bi++] = 'M';
965  }
966  }
967  if (kb->flags & KEYF_EDIT) {
968  buf[bi++] = 'E';
969  }
970 
971  buf[bi] = '\0';
972 }
973 
982 static char *get_key_info(struct keybind *kb, int save_mode) {
983  /* bind buf is the maximum space allowed for a
984  * bound command. We will add additional data to
985  * it so we increase its size by MAX_BUF*/
986  static char buf[MAX_BUF + sizeof(bind_buf)];
987 
988  char buff[MAX_BUF];
989 
990  get_key_modchars(kb, save_mode, buff);
991 
992  if (save_mode) {
993  if (kb->keysym == NoSymbol) {
994  snprintf(buf, sizeof(buf), "(null) %i %s %s",
995  0, buff, kb->command);
996  } else {
997  snprintf(buf, sizeof(buf), "%s %i %s %s",
998  gdk_keyval_name(kb->keysym),
999  0, buff, kb->command);
1000  }
1001  } else {
1002  if (kb->keysym == NoSymbol) {
1003  snprintf(buf, sizeof(buf), "key (null) %s %s",
1004  buff, kb->command);
1005  } else {
1006  snprintf(buf, sizeof(buf), "key %s %s %s",
1007  gdk_keyval_name(kb->keysym),
1008  buff, kb->command);
1009  }
1010  }
1011  return buf;
1012 }
1013 
1019 static void show_keys(void) {
1020  int i, j, count = 1;
1021  struct keybind *kb;
1022  char buf[MAX_BUF];
1023 
1024  snprintf(buf, sizeof(buf), "Commandkey %s",
1025  commandkeysym == NoSymbol ? "unknown" : gdk_keyval_name(commandkeysym));
1027 
1028  snprintf(buf, sizeof(buf), "Firekeys 1: %s, 2: %s",
1029  firekeysym[0] == NoSymbol ? "unknown" : gdk_keyval_name(firekeysym[0]),
1030  firekeysym[1] == NoSymbol ? "unknown" : gdk_keyval_name(firekeysym[1]));
1032 
1033  snprintf(buf, sizeof(buf), "Altkeys 1: %s, 2: %s",
1034  altkeysym[0] == NoSymbol ? "unknown" : gdk_keyval_name(altkeysym[0]),
1035  altkeysym[1] == NoSymbol ? "unknown" : gdk_keyval_name(altkeysym[1]));
1037 
1038  snprintf(buf, sizeof(buf), "Metakeys 1: %s, 2: %s",
1039  metakeysym[0] == NoSymbol ? "unknown" : gdk_keyval_name(metakeysym[0]),
1040  metakeysym[1] == NoSymbol ? "unknown" : gdk_keyval_name(metakeysym[1]));
1042 
1043  snprintf(buf, sizeof(buf), "Runkeys 1: %s, 2: %s",
1044  runkeysym[0] == NoSymbol ? "unknown" : gdk_keyval_name(runkeysym[0]),
1045  runkeysym[1] == NoSymbol ? "unknown" : gdk_keyval_name(runkeysym[1]));
1047 
1048  snprintf(buf, sizeof(buf), "Command Completion Key %s",
1049  completekeysym == NoSymbol ? "unknown" : gdk_keyval_name(completekeysym));
1051 
1052  snprintf(buf, sizeof(buf), "Next Command in History Key %s",
1053  nextkeysym == NoSymbol ? "unknown" : gdk_keyval_name(nextkeysym));
1055 
1056  snprintf(buf, sizeof(buf), "Previous Command in History Key %s",
1057  prevkeysym == NoSymbol ? "unknown" : gdk_keyval_name(prevkeysym));
1059 
1060  /*
1061  * Perhaps we should start at 8, so that we only show 'active' keybindings?
1062  */
1063  for (i = 0; i < KEYHASH; i++) {
1064  for (j = 0; j < 2; j++) {
1065  for (kb = (j == 0) ? keys_global[i] : keys_char[i]; kb != NULL; kb = kb->next) {
1066  snprintf(buf, sizeof(buf), "%3d %s", count, get_key_info(kb, 0));
1067  draw_ext_info(
1069  count++;
1070  }
1071  }
1072  }
1073 }
1074 
1083 void bind_key(char *params) {
1084  char buf[MAX_BUF + 16];
1085 
1086  if (!params) {
1088  "Usage: 'bind -ei {<commandline>,commandkey,firekey{1,2},runkey{1,2},altkey{1,2},metakey{1,2},completekey,nextkey,prevkey}'\n"
1089  "Where\n"
1090  " -e means enter edit mode\n"
1091  " -g means this binding should be global (used for all your characters)\n"
1092  " -i means ignore modifier keys (keybinding works no matter if Ctrl/Alt etc are held)");
1093  return;
1094  }
1095 
1096  /* Skip over any spaces we may have */
1097  while (*params == ' ') {
1098  params++;
1099  }
1100 
1101  if (!strcmp(params, "commandkey")) {
1104  "Push key to bind new commandkey.");
1106  return;
1107  }
1108 
1109  if (!strcmp(params, "firekey1")) {
1110  bind_keysym = &firekeysym[0];
1112  "Push key to bind new firekey 1.");
1114  return;
1115  }
1116  if (!strcmp(params, "firekey2")) {
1117  bind_keysym = &firekeysym[1];
1119  "Push key to bind new firekey 2.");
1121  return;
1122  }
1123  if (!strcmp(params, "metakey1")) {
1124  bind_keysym = &metakeysym[0];
1126  "Push key to bind new metakey 1.");
1128  return;
1129  }
1130  if (!strcmp(params, "metakey2")) {
1131  bind_keysym = &metakeysym[1];
1133  "Push key to bind new metakey 2.");
1135  return;
1136  }
1137  if (!strcmp(params, "altkey1")) {
1138  bind_keysym = &altkeysym[0];
1140  "Push key to bind new altkey 1.");
1142  return;
1143  }
1144  if (!strcmp(params, "altkey2")) {
1145  bind_keysym = &altkeysym[1];
1147  "Push key to bind new altkey 2.");
1149  return;
1150  }
1151  if (!strcmp(params, "runkey1")) {
1152  bind_keysym = &runkeysym[0];
1154  "Push key to bind new runkey 1.");
1156  return;
1157  }
1158 
1159  if (!strcmp(params, "runkey2")) {
1160  bind_keysym = &runkeysym[1];
1162  "Push key to bind new runkey 2.");
1164  return;
1165  }
1166 
1167  if (!strcmp(params, "completekey")) {
1170  "Push key to bind new command completion key");
1172  return;
1173  }
1174 
1175  if (!strcmp(params, "prevkey")) {
1178  "Push key to bind new previous command in history key.");
1180  return;
1181  }
1182 
1183  if (!strcmp(params, "nextkey")) {
1186  "Push key to bind new next command in history key.");
1188  return;
1189  }
1190  bind_keysym = NULL;
1191 
1192  bind_flags = 0;
1193  if (params[0] == '-') {
1194  for (params++; *params != ' '; params++)
1195  switch (*params) {
1196  case 'e':
1197  bind_flags |= KEYF_EDIT;
1198  break;
1199  case 'i':
1200  bind_flags |= KEYF_ANY;
1201  break;
1202  case 'g':
1204  break;
1205  case '\0':
1206  draw_ext_info(
1208  "Use unbind to remove bindings.");
1209  return;
1210  default:
1211  snprintf(buf, sizeof(buf),
1212  "Unsupported or invalid bind flag: '%c'", *params);
1214  return;
1215  }
1216  params++;
1217  }
1218 
1219  if (!params[0]) {
1221  "Use unbind to remove bindings.");
1222  return;
1223  }
1224 
1225  if (strlen(params) >= sizeof(bind_buf)) {
1226  params[sizeof(bind_buf) - 1] = '\0';
1228  "Keybinding too long! Truncated:");
1230  }
1231  snprintf(buf, sizeof(buf), "Push key to bind '%s'.", params);
1233 
1234  strcpy(bind_buf, params);
1236  return;
1237 }
1238 
1251 static void save_individual_key(FILE *fp, struct keybind *kb, KeyCode kc) {
1252  while (kb) {
1253  fprintf(fp, "%s\n", get_key_info(kb, 1));
1254  kb = kb->next;
1255  }
1256 }
1257 
1265 static void save_keys(void) {
1266  char buf[MAX_BUF], buf2[MAX_BUF];
1267  int i;
1268  FILE *fp;
1269 
1270  /* If we are logged in open file to save character specific bindings */
1271  if (cpl.name) {
1272  snprintf(buf, sizeof(buf), "%s/%s.%s.keys", config_dir,
1274  LOG(LOG_INFO, "gtk-v2::save_keys",
1275  "Saving character specific keybindings to %s", buf);
1276 
1277  if (make_path_to_file(buf) == -1) {
1278  LOG(LOG_WARNING, "gtk-v2::save_keys", "Could not create %s", buf);
1279  }
1280 
1281  fp = fopen(buf, "w");
1282  if (fp == NULL) {
1283  snprintf(buf2, sizeof(buf2),
1284  "Could not open %s, character bindings not saved\n", buf);
1286  } else {
1287  for (i = 0; i < KEYHASH; i++) {
1288  save_individual_key(fp, keys_char[i], 0);
1289  }
1290  fclose(fp);
1291  }
1292  }
1293 
1294  /* Open file to save global user bindings */
1295  snprintf(buf, sizeof(buf), "%s/keys", config_dir);
1296  LOG(LOG_INFO, "gtk-v2::save_keys",
1297  "Saving global user's keybindings to %s", buf);
1298 
1299  if (make_path_to_file(buf) == -1) {
1300  LOG(LOG_WARNING, "gtk-v2::save_keys", "Could not create %s", buf);
1301  } else {
1302  fp = fopen(buf, "w");
1303  if (fp == NULL) {
1304  snprintf(buf2, sizeof(buf2),
1305  "Could not open %s, global key bindings not saved\n", buf);
1307  } else {
1308  /* Save default bindings as part of the global scope */
1309  if (firekeysym[0] != GDK_Shift_L && firekeysym[0] != NoSymbol)
1310  fprintf(fp, "! firekey0 %s %d\n",
1311  gdk_keyval_name(firekeysym[0]), 0);
1312  if (firekeysym[1] != GDK_Shift_R && firekeysym[1] != NoSymbol)
1313  fprintf(fp, "! firekey1 %s %d\n",
1314  gdk_keyval_name(firekeysym[1]), 0);
1315  if (metakeysym[0] != GDK_Shift_L && metakeysym[0] != NoSymbol)
1316  fprintf(fp, "! metakey0 %s %d\n",
1317  gdk_keyval_name(metakeysym[0]), 0);
1318  if (metakeysym[1] != GDK_Shift_R && metakeysym[1] != NoSymbol)
1319  fprintf(fp, "! metakey1 %s %d\n",
1320  gdk_keyval_name(metakeysym[1]), 0);
1321  if (altkeysym[0] != GDK_Shift_L && altkeysym[0] != NoSymbol)
1322  fprintf(fp, "! altkey0 %s %d\n",
1323  gdk_keyval_name(altkeysym[0]), 0);
1324  if (altkeysym[1] != GDK_Shift_R && altkeysym[1] != NoSymbol)
1325  fprintf(fp, "! altkey1 %s %d\n",
1326  gdk_keyval_name(altkeysym[1]), 0);
1327  if (runkeysym[0] != GDK_Control_L && runkeysym[0] != NoSymbol)
1328  fprintf(fp, "! runkey0 %s %d\n",
1329  gdk_keyval_name(runkeysym[0]), 0);
1330  if (runkeysym[1] != GDK_Control_R && runkeysym[1] != NoSymbol)
1331  fprintf(fp, "! runkey1 %s %d\n",
1332  gdk_keyval_name(runkeysym[1]), 0);
1333  if (completekeysym != GDK_Tab && completekeysym != NoSymbol)
1334  fprintf(fp, "! completekey %s %d\n",
1335  gdk_keyval_name(completekeysym), 0);
1336  /* No defaults for these, so if it is set to anything, assume its valid */
1337  if (nextkeysym != NoSymbol)
1338  fprintf(fp, "! nextkey %s %d\n",
1339  gdk_keyval_name(nextkeysym), 0);
1340  if (prevkeysym != NoSymbol)
1341  fprintf(fp, "! prevkey %s %d\n",
1342  gdk_keyval_name(prevkeysym), 0);
1343 
1344  for (i = 0; i < KEYHASH; i++) {
1345  save_individual_key(fp, keys_global[i], 0);
1346  }
1347  fclose(fp);
1348  }
1349  }
1350 
1351  /* Should probably check return value on all writes to be sure, but... */
1353  "Key bindings saved.");
1354 }
1355 
1360 static void configure_keys(guint32 keysym) {
1361  char buf[MAX_BUF];
1362  struct keybind *kb;
1363 
1364  /* We handle the Shift key separately */
1365  keysym = gdk_keyval_to_lower(keysym);
1366 
1367  /*
1368  * I think that basically if we are not rebinding the special control keys
1369  * (in which case bind_keysym would be set to something) we just want to
1370  * handle these keypresses as normal events.
1371  */
1372  if (bind_keysym == NULL) {
1373  if (keysym == altkeysym[0] || keysym == altkeysym[1]) {
1374  cpl.alt_on = 1;
1375  return;
1376  }
1377  if (keysym == metakeysym[0] || keysym == metakeysym[1]) {
1378  cpl.meta_on = 1;
1379  return;
1380  }
1381  if (keysym == firekeysym[0] || keysym == firekeysym[1]) {
1382  cpl.fire_on = 1;
1384  return;
1385  }
1386  if (keysym == runkeysym[0] || keysym == runkeysym[1]) {
1387  cpl.run_on = 1;
1389  return;
1390  }
1391  }
1392 
1393  /*
1394  * Take shift/control keys into account when binding keys.
1395  */
1396  if (!(bind_flags & KEYF_ANY)) {
1397  if (cpl.fire_on) {
1399  }
1400  if (cpl.run_on) {
1402  }
1403  if (cpl.meta_on) {
1405  }
1406  if (cpl.alt_on) {
1408  }
1409  }
1410 
1411  /* Reset state now. We might return early if bind fails. */
1413 
1414  if (bind_keysym != NULL) {
1415  *bind_keysym = keysym;
1416  bind_keysym = NULL;
1417  } else {
1418  kb = keybind_find(keysym, bind_flags, (bind_flags & KEYF_R_GLOBAL));
1419  if (kb) {
1420  snprintf(buf, sizeof(buf),
1421  "Error: Key already used for command \"%s\". Use unbind first.",
1422  kb->command);
1423  draw_ext_info(
1425  return;
1426  } else {
1428  }
1429  }
1430 
1431  snprintf(buf, sizeof(buf), "Bound to key '%s' (%i)",
1432  keysym == NoSymbol ? "unknown" : gdk_keyval_name(keysym), keysym);
1435 
1436  /*
1437  * Do this each time a new key is bound. This way, we are never actually
1438  * storing any information that needs to be saved when the connection dies
1439  * or the player quits.
1440  */
1441  save_keys();
1442  return;
1443 }
1444 
1448 static void unbind_usage(void) {
1450  "Usage: 'unbind <entry_number>' or");
1452  "Usage: 'unbind' to show existing bindings");
1453 }
1454 
1459 void unbind_key(const char *params) {
1460  int count = 0, keyentry, slot, j;
1461  int res;
1462  struct keybind *kb;
1463  char buf[MAX_BUF];
1464 
1465  if (params == NULL) {
1466  show_keys();
1467  return;
1468  }
1469 
1470  /* Skip over any spaces we may have */
1471  while (*params == ' ') {
1472  params++;
1473  }
1474 
1475  if (params[0] == '\0') {
1476  show_keys();
1477  return;
1478  }
1479 
1480  if ((keyentry = atoi(params)) == 0) {
1481  unbind_usage();
1482  return;
1483  }
1484 
1485  for (slot = 0; slot < KEYHASH; slot++) {
1486  for (j = 0; j < 2; j++) {
1487  for (kb = (j == 0) ? keys_global[slot] : keys_char[slot]; kb != NULL;
1488  kb = kb->next) {
1489  count++;
1490 
1491  if (keyentry == count) {
1492  /* We found the key we want to unbind */
1493  snprintf(buf, sizeof(buf), "Removing binding: %3d %s",
1494  count, get_key_info(kb, 0));
1496  MSG_TYPE_CLIENT_CONFIG, buf);
1497  res = keybind_remove(kb);
1498  if (res < 0)
1499  LOG(LOG_ERROR, "gtk-v2::unbind_key",
1500  "found number entry, but could not find actual key");
1501  keybind_free(&kb);
1502  save_keys();
1503  return;
1504  }
1505  }
1506  }
1507  }
1508 
1509  /* Not found */
1510  /* Makes things look better to draw the blank line */
1513  "Not found. Try 'unbind' with no options to find entry.");
1514  return;
1515 }
1516 
1520 void focusoutfunc(GtkWidget *widget, GdkEventKey *event, GtkWidget *window) {
1521  if (cpl.fire_on == 1) {
1522  cpl.fire_on = 0;
1523  clear_fire();
1524  gtk_label_set_text(GTK_LABEL(fire_label), " ");
1525  }
1526  if (cpl.run_on == 1) {
1527  cpl.run_on = 0;
1528  if (use_config[CONFIG_ECHO])
1530  "stop run");
1531  clear_run();
1532  gtk_label_set_text(GTK_LABEL(run_label), " ");
1533  }
1534  if (cpl.alt_on == 1) {
1535  cpl.alt_on = 0;
1536  }
1537  if (cpl.meta_on == 1) {
1538  cpl.meta_on = 0;
1539  }
1540 }
1541 
1549 void keyrelfunc(GtkWidget *widget, GdkEventKey *event, GtkWidget *window) {
1550  if (event->keyval > 0 && !gtk_widget_has_focus(entry_commands)) {
1551  parse_key_release(event->keyval);
1552  debounce = false;
1553  }
1554  g_signal_stop_emission_by_name(GTK_OBJECT(window), "key_release_event");
1555 }
1556 
1564 void keyfunc(GtkWidget *widget, GdkEventKey *event, GtkWidget *window) {
1565  char *text;
1566 
1567  if (!use_config[CONFIG_POPUPS]) {
1568  if (((cpl.input_state == Reply_One) || (cpl.input_state == Reply_Many))
1569  && (event->keyval == cancelkeysym)) {
1570 
1571  /*
1572  * Player hit cancel button during input. Disconnect it (code from
1573  * menubar)
1574  */
1575 
1577 
1578  g_signal_stop_emission_by_name(
1579  GTK_OBJECT(window), "key_press_event");
1580  return;
1581  }
1582  if (cpl.input_state == Reply_One) {
1583  text = gdk_keyval_name(event->keyval);
1584  send_reply(text);
1586  g_signal_stop_emission_by_name(
1587  GTK_OBJECT(window), "key_press_event");
1588  return;
1589  } else if (cpl.input_state == Reply_Many) {
1590  if (gtk_widget_has_focus(entry_commands)) {
1591  gtk_widget_event(GTK_WIDGET(entry_commands), (GdkEvent *)event);
1592  } else {
1593  gtk_widget_grab_focus(GTK_WIDGET(entry_commands));
1594  }
1595  g_signal_stop_emission_by_name(
1596  GTK_OBJECT(window), "key_press_event");
1597  return;
1598  }
1599  }
1600  /*
1601  * Better check for really weirdo keys, X doesnt like keyval 0 so avoid
1602  * handling these key values.
1603  */
1604  if (event->keyval > 0) {
1605  if (gtk_widget_has_focus(entry_commands)) {
1606  if (event->keyval == completekeysym) {
1608  }
1609  if (event->keyval == prevkeysym || event->keyval == nextkeysym) {
1610  gtk_command_history(event->keyval == nextkeysym ? 0 : 1);
1611  } else {
1612  gtk_widget_event(GTK_WIDGET(entry_commands), (GdkEvent *)event);
1613  }
1614  } else {
1615  switch (cpl.input_state) {
1616  case Playing:
1617  /*
1618  * Specials - do command history - many times, the player
1619  * will want to go the previous command when nothing is
1620  * entered in the command window.
1621  */
1622  if ((event->keyval == prevkeysym)
1623  || (event->keyval == nextkeysym)) {
1624  gtk_command_history(event->keyval == nextkeysym ? 0 : 1);
1625  } else {
1626  if (cpl.run_on) {
1627  if (!(event->state & GDK_CONTROL_MASK)) {
1628  /* printf("Run is on while ctrl is not\n"); */
1629  gtk_label_set_text(GTK_LABEL(run_label), " ");
1630  cpl.run_on = 0;
1631  stop_run();
1632  }
1633  }
1634  if (cpl.fire_on) {
1635  if (!(event->state & GDK_SHIFT_MASK)) {
1636  /* printf("Fire is on while shift is not\n");*/
1637  gtk_label_set_text(GTK_LABEL(fire_label), " ");
1638  cpl.fire_on = 0;
1639  stop_fire();
1640  }
1641  }
1642 
1644  debounce = false;
1645  }
1646 
1647  if (!debounce) {
1648  parse_key(event->string[0], event->keyval);
1649  debounce = true;
1650  }
1651  }
1652  break;
1653 
1654  case Configure_Keys:
1655  configure_keys(event->keyval);
1656  break;
1657 
1658  case Command_Mode:
1659  if (event->keyval == completekeysym) {
1661  }
1662  if ((event->keyval == prevkeysym)
1663  || (event->keyval == nextkeysym)) {
1664  gtk_command_history(event->keyval == nextkeysym ? 0 : 1);
1665  } else {
1666  gtk_widget_grab_focus(GTK_WIDGET(entry_commands));
1667  /*
1668  * When running in split windows mode, entry_commands
1669  * can't get focus because it is in a different
1670  * window. So we have to pass the event to it
1671  * explicitly.
1672  */
1673  if (gtk_widget_has_focus(entry_commands) == 0)
1674  gtk_widget_event(
1675  GTK_WIDGET(entry_commands), (GdkEvent *)event);
1676  }
1677  /*
1678  * Don't pass signal along to default handlers -
1679  * otherwise, we get get crashes in the clist area (gtk
1680  * fault I believe)
1681  */
1682  break;
1683 
1684  case Metaserver_Select:
1685  gtk_widget_grab_focus(GTK_WIDGET(entry_commands));
1686  break;
1687 
1688  default:
1689  LOG(LOG_ERROR, "gtk-v2::keyfunc",
1690  "Unknown input state: %d", cpl.input_state);
1691  }
1692  }
1693  }
1694  g_signal_stop_emission_by_name(
1695  GTK_OBJECT(window), "key_press_event");
1696 }
1697 
1701 void x_set_echo(void) {
1702  gtk_entry_set_visibility(GTK_ENTRY(entry_commands), !cpl.no_echo);
1703 }
1704 
1710 void draw_prompt(const char *str) {
1712  gtk_widget_grab_focus(GTK_WIDGET(entry_commands));
1713 }
1714 
1721  int i = scroll_history_position;
1722  if (direction) {
1723  i--;
1724  if (i < 0) {
1725  i += MAX_HISTORY;
1726  }
1727  if (i == cur_history_position) {
1728  return;
1729  }
1730  } else {
1731  i++;
1732  if (i >= MAX_HISTORY) {
1733  i = 0;
1734  }
1735  if (i == cur_history_position) {
1736  /*
1737  * User has forwarded to what should be current entry - reset it
1738  * now.
1739  */
1740  gtk_entry_set_text(GTK_ENTRY(entry_commands), "");
1741  gtk_editable_set_position(GTK_EDITABLE(entry_commands), 0);
1743  return;
1744  }
1745  }
1746 
1747  if (history[i][0] == 0) {
1748  return;
1749  }
1750 
1752  /* fprintf(stderr, "resetting postion to %d, data = %s\n", i, history[i]);*/
1753  gtk_entry_set_text(GTK_ENTRY(entry_commands), history[i]);
1754  gtk_widget_grab_focus(GTK_WIDGET(entry_commands));
1755  gtk_editable_select_region(GTK_EDITABLE(entry_commands), 0, 0);
1756  gtk_editable_set_position(GTK_EDITABLE(entry_commands), -1);
1757 
1759 }
1760 
1768  const gchar *entry_text, *newcommand;
1769 
1770  entry_text = gtk_entry_get_text(GTK_ENTRY(entry_commands));
1771  newcommand = complete_command(entry_text);
1772  /* value differ, so update window */
1773  if (newcommand != NULL) {
1774  gtk_entry_set_text(GTK_ENTRY(entry_commands), newcommand);
1775  gtk_widget_grab_focus(GTK_WIDGET(entry_commands));
1776  gtk_editable_select_region(GTK_EDITABLE(entry_commands), 0, 0);
1777  gtk_editable_set_position(GTK_EDITABLE(entry_commands), -1);
1778  }
1779 }
1780 
1788 void on_entry_commands_activate(GtkEntry *entry, gpointer user_data) {
1789  const gchar *entry_text;
1790  extern GtkWidget *treeview_look;
1791 
1792  /* Next reply will reset this as necessary */
1793  if (!use_config[CONFIG_POPUPS]) {
1794  gtk_entry_set_visibility(GTK_ENTRY(entry), TRUE);
1795  }
1796 
1797  entry_text = gtk_entry_get_text(GTK_ENTRY(entry));
1798 
1800  strcpy(cpl.input_text, entry_text);
1801  } else if (cpl.input_state == Reply_One || cpl.input_state == Reply_Many) {
1803  strcpy(cpl.input_text, entry_text);
1804  if (cpl.input_state == Reply_One) {
1805  cpl.input_text[1] = 0;
1806  }
1807 
1809 
1810  } else {
1812  /* Some spells (dimension door) need a valid count value */
1813  cpl.count = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(spinbutton_count));
1814 
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);
1819  cur_history_position++;
1820  cur_history_position %= MAX_HISTORY;
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_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 
2298  keybinding_get_data(&keysym, &flags, &command);
2299 
2300  /* keybind_insert will do a g_strdup of command for us */
2301  kb = keybind_find(keysym, flags, (flags & KEYF_R_GLOBAL));
2302  if (kb && (!keybind_overwrite_confirm(kb))) {
2303  return;
2304  }
2305  keybind_insert(keysym, flags, command);
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 
static int keybind_overwrite_confirm(struct keybind *kb)
Definition: keys.c:2038
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:2149
void on_keybinding_checkbutton_any_clicked(GtkCheckButton *cb, gpointer user_data)
Definition: keys.c:2385
GtkBuilder * window_xml
Definition: main.c:93
static GtkWidget * keybinding_button_bind
Definition: keys.c:50
void toggle_buttons_scope(int scope)
Definition: keys.c:1998
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:2409
#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:982
static guint32 firekeysym[2]
Definition: keys.c:120
void on_entry_commands_activate(GtkEntry *entry, gpointer user_data)
Definition: keys.c:1788
void on_keybindings_activate(GtkMenuItem *menuitem, gpointer user_data)
Definition: keys.c:1927
static GtkWidget * keybinding_checkbutton_edit
Definition: keys.c:50
void toggle_keybind_scope(int scope, struct keybind *kb)
Definition: keys.c:2073
#define MAX_COMMAND_LEN
Definition: keys.c:87
void gtk_command_history(int direction)
Definition: keys.c:1720
void on_keybinding_button_remove_clicked(GtkButton *button, gpointer user_data)
Definition: keys.c:2193
void run_dir(int dir)
Definition: player.c:135
#define CONFIG_POPUPS
Definition: client.h:193
void on_keybinding_button_clear_clicked(GtkButton *button, gpointer user_data)
Definition: keys.c:2517
guint32 keysym
Definition: keys.c:103
void keyfunc(GtkWidget *widget, GdkEventKey *event, GtkWidget *window)
Definition: keys.c:1564
static void show_keys(void)
Definition: keys.c:1019
static struct keybind * keybind_find(guint32 keysym, unsigned int flags, int scope)
Definition: keys.c:199
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:228
ClientSocket csocket
Definition: client.c:67
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:1857
gboolean on_keybinding_entry_key_key_press_event(GtkWidget *widget, GdkEventKey *event, gpointer user_data)
Definition: keys.c:1945
#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:2326
#define NDI_BLACK
Definition: newclient.h:221
const char *const directions[9]
Definition: player.c:36
#define KEYF_MOD_META
Definition: keys.c:142
guint32 meta_on
Definition: client.h:356
static void init_default_keybindings()
Definition: keys.c:496
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:1251
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:178
void on_keybinding_button_bind_clicked(GtkButton *button, gpointer user_data)
Definition: keys.c:2292
#define MSG_TYPE_CLIENT_ERROR
Definition: newclient.h:667
#define NDI_RED
Definition: newclient.h:224
void gtk_complete_command(void)
Definition: keys.c:1767
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:1701
static GtkWidget * kb_scope_togglebutton_global
Definition: keys.c:50
GtkWidget * window_root
Definition: main.c:94
static GtkWidget * fire_label
Definition: keys.c:50
#define MSG_TYPE_CLIENT_NOTICE
Definition: newclient.h:664
Definition: keys.c:75
void draw_message_window(int redraw)
Definition: stats.c:459
void clear_fire()
Definition: player.c:100
static int scroll_history_position
Definition: keys.c:90
static int parse_keys_file(char *filename, unsigned int scope_flag)
Definition: keys.c:513
static void save_keys(void)
Definition: keys.c:1265
Client_Player cpl
Definition: client.c:66
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:628
void send_reply(const char *text)
Definition: commands.c:1598
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:282
Warning that something definitely didn&#39;t work.
Definition: client.h:444
void stop_fire()
Definition: player.c:93
static guint32 commandkeysym
Definition: keys.c:120
static int bind_flags
Definition: keys.c:124
static bool debounce
Definition: keys.c:181
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:1360
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:782
#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:1520
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:302
void on_keybinding_button_close_clicked(GtkButton *button, gpointer user_data)
Definition: keys.c:2375
int command_sent
Definition: client.h:123
char * command
Definition: keys.c:104
static void unbind_usage(void)
Definition: keys.c:1448
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
int command_received
Definition: client.h:123
static guint32 cancelkeysym
Definition: keys.c:120
static void parse_key(char key, guint32 keysym)
Definition: keys.c:821
#define KEYF_R_GLOBAL
Definition: keys.c:152
static void get_key_modchars(struct keybind *kb, int save_mode, char *buf)
Definition: keys.c:944
#define KEYF_EDIT
Definition: keys.c:149
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:316
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:1083
void unbind_key(const char *params)
Definition: keys.c:1459
#define CONFIG_ECHO
Definition: client.h:186
void on_kb_scope_togglebutton_global_toggled(GtkToggleButton *toggle_button, gpointer user_data)
Definition: keys.c:2171
void reset_keybinding_status(void)
Definition: keys.c:2487
void draw_prompt(const char *str)
Definition: keys.c:1710
GtkBuilder * dialog_xml
Definition: main.c:93
Useful debugging information.
Definition: client.h:441
static GtkWidget * keybinding_entry_command
Definition: keys.c:50
void clear_run()
Definition: player.c:107
void stop_run()
Definition: player.c:130
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:114
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:1549
static void keybinding_get_data(guint32 *keysym, guint8 *flags, const char **command)
Definition: keys.c:2225
#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:541