Crossfire Client, Branch  R11627
keys.c
Go to the documentation of this file.
00001 const char * const rcsid_gtk2_keys_c =
00002     "$Id: keys.c 10827 2008-12-04 05:12:23Z kbulgrien $";
00003 /*
00004     Crossfire client, a client program for the crossfire program.
00005 
00006     Copyright (C) 2005 Mark Wedel & Crossfire Development Team
00007 
00008     This program is free software; you can redistribute it and/or modify
00009     it under the terms of the GNU General Public License as published by
00010     the Free Software Foundation; either version 2 of the License, or
00011     (at your option) any later version.
00012 
00013     This program is distributed in the hope that it will be useful,
00014     but WITHOUT ANY WARRANTY; without even the implied warranty of
00015     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016     GNU General Public License for more details.
00017 
00018     You should have received a copy of the GNU General Public License
00019     along with this program; if not, write to the Free Software
00020     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00021 
00022     The author can be reached via e-mail to crossfire@metalforge.org
00023 */
00024 
00031 #include <config.h>
00032 #include <stdlib.h>
00033 #include <sys/stat.h>
00034 #ifndef WIN32
00035 #include <unistd.h>
00036 #endif
00037 
00038 /* Pick up the gtk headers we need */
00039 #include <gtk/gtk.h>
00040 #include <glade/glade.h>
00041 #ifndef WIN32
00042 #include <gdk/gdkx.h>
00043 #else
00044 #include <gdk/gdkwin32.h>
00045 #define NoSymbol 0L                     
00046 typedef int KeyCode;                    
00047 #endif
00048 #include <gdk/gdkkeysyms.h>
00049 
00050 #include "client-types.h"
00051 #include "main.h"
00052 #include "client.h"
00053 #include "proto.h"
00054 #include "def-keys.h"
00055 
00056 #include "image.h"
00057 #include "gtk2proto.h"
00058 #include "p_cmd.h"
00059 
00065 static GtkWidget *fire_label, *run_label, *keybinding_window,
00066     *keybinding_checkbutton_control, *keybinding_checkbutton_shift,
00067     *keybinding_checkbutton_alt, *keybinding_checkbutton_meta,
00068     *keybinding_checkbutton_edit, *keybinding_entry_key,
00069     *keybinding_entry_command, *keybinding_treeview,
00070     *keybinding_button_remove, *keybinding_button_update,
00071     *keybinding_button_bind;
00072 
00073 static GtkListStore *keybinding_store;  
00074 static GtkTreeSelection *keybinding_selection;
00075 
00076 GtkWidget *spinbutton_count;
00077 GtkWidget *entry_commands;
00087 enum {
00088     KLIST_ENTRY, KLIST_KEY, KLIST_MODS, KLIST_EDIT, KLIST_COMMAND,
00089     KLIST_KEY_ENTRY
00090 };
00099 #define MAX_HISTORY 50
00100 #define MAX_COMMAND_LEN 256
00101 char history[MAX_HISTORY][MAX_COMMAND_LEN];
00102 
00103 static int cur_history_position=0, scroll_history_position=0;
00113 typedef struct Keys {
00114     uint8       flags;                  
00115     sint8       direction;              
00116     uint32      keysym;                 
00117     char        *command;               
00118     struct Keys *next;
00119 } Key_Entry;
00124 /***********************************************************************
00125  *
00126  * Key board input translations are handled here.  We don't deal with
00127  * the events, but rather KeyCodes and KeySyms.
00128  *
00129  * It would be nice to deal with only KeySyms, but many keyboards
00130  * have keys that do not correspond to a KeySym, so we do need to
00131  * support KeyCodes.
00132  *
00133  ***********************************************************************/
00134 
00135 static uint32 firekeysym[2], runkeysym[2], commandkeysym, *bind_keysym,
00136    prevkeysym, nextkeysym, completekeysym, altkeysym[2], metakeysym[2],
00137    cancelkeysym;
00138 
00139 static int bind_flags=0;
00140 static char bind_buf[MAX_BUF];
00141 
00142 #define KEYF_NORMAL     0x01            
00143 #define KEYF_FIRE       0x02            
00144 #define KEYF_RUN        0x04            
00145 #define KEYF_EDIT       0x08            
00146 #define KEYF_STANDARD   0x10            
00147 #define KEYF_ALT        0x20            
00148 #define KEYF_META       0x40            
00149 #define KEYF_MODIFIERS  0x67            
00152 extern const char *const directions[9];
00153 
00154 #define KEYHASH 257
00155 static Key_Entry *keys[KEYHASH];        
00176 static void insert_key(uint32 keysym, int flags, const char *command)
00177 {
00178     Key_Entry *newkey;
00179     int i, direction=-1, slot;
00180 
00181     slot = keysym % KEYHASH;
00182 
00183     if (keys[slot]==NULL) {
00184         keys[slot]=malloc(sizeof(Key_Entry));
00185         keys[slot]->command=NULL;
00186         keys[slot]->next=NULL;
00187         newkey=keys[slot];
00188     } else {
00189         newkey=keys[slot];
00190         while (newkey->next!=NULL)
00191             newkey = newkey->next;
00192         newkey->next = calloc(1, sizeof(Key_Entry));
00193         newkey = newkey->next;
00194     }
00195     /*
00196      * Try to find out if the command is a direction command.  If so, keep
00197      * track of this fact, so in fire or run mode, things work correctly.
00198      */
00199     for (i=0; i<9; i++)
00200         if (!strcmp(command, directions[i])) {
00201             direction=i;
00202             break;
00203         }
00204 
00205     newkey->keysym = keysym;
00206     newkey->flags = flags;
00207     newkey->command = strdup_local(command);
00208     newkey->direction = direction;
00209 }
00210 
00218 static void parse_keybind_line(char *buf, int line, int standard)
00219 {
00220     char *cp, *cpnext;
00221     uint32 keysym;
00222     int flags;
00223 
00224     /*
00225      * There may be a rare error case when cp is used uninitialized. So let's
00226      * be safe
00227      */
00228     cp = NULL;
00229 
00230     if (buf[0]=='#' || buf[0]=='\n') return;
00231     if ((cpnext = strchr(buf,' '))==NULL) {
00232         LOG(LOG_WARNING,"gtk::parse_keybind_line","Line %d (%s) corrupted in keybinding file.", line,buf);
00233         return;
00234     }
00235     /* Special keybinding line */
00236     if (buf[0] == '!') {
00237         char *cp1;
00238         while (*cpnext == ' ') ++cpnext;
00239         cp = strchr(cpnext, ' ');
00240         if (!cp) {
00241             LOG(LOG_WARNING,"gtk::parse_keybind_line","Line %d (%s) corrupted in keybinding file.", line,buf);
00242             return;
00243         }
00244         *cp++ = 0;  /* Null terminate it */
00245         cp1 = strchr(cp, ' ');
00246         if (!cp1) {
00247             LOG(LOG_WARNING,"gtk::parse_keybind_line","Line %d (%s) corrupted in keybinding file.", line,buf);
00248             return;
00249         }
00250         *cp1 ++ = 0;/* Null terminate it */
00251         keysym = gdk_keyval_from_name(cp);
00252         /* As of now, all these keys must have keysyms */
00253         if (keysym == 0) {
00254             LOG(LOG_WARNING,"gtk::parse_keybind_line","Could not convert %s into keysym", cp);
00255             return;
00256         }
00257         if (!strcmp(cpnext,"commandkey")) {
00258             commandkeysym = keysym;
00259             return;
00260         }
00261         if (!strcmp(cpnext,"altkey0")) {
00262             altkeysym[0] = keysym;
00263             return;
00264         }
00265         if (!strcmp(cpnext,"altkey1")) {
00266             altkeysym[1] = keysym;
00267             return;
00268         }
00269         if (!strcmp(cpnext,"firekey0")) {
00270             firekeysym[0] = keysym;
00271             return;
00272         }
00273         if (!strcmp(cpnext,"firekey1")) {
00274             firekeysym[1] = keysym;
00275             return;
00276         }
00277         if (!strcmp(cpnext,"metakey0")) {
00278             metakeysym[0] = keysym;
00279             return;
00280         }
00281         if (!strcmp(cpnext,"metakey1")) {
00282             metakeysym[1] = keysym;
00283             return;
00284         }
00285         if (!strcmp(cpnext,"runkey0")) {
00286             runkeysym[0] = keysym;
00287             return;
00288         }
00289         if (!strcmp(cpnext,"runkey1")) {
00290             runkeysym[1] = keysym;
00291             return;
00292         }
00293         if (!strcmp(cpnext,"completekey")) {
00294             completekeysym = keysym;
00295             return;
00296         }
00297         if (!strcmp(cpnext,"nextkey")) {
00298             nextkeysym = keysym;
00299             return;
00300         }
00301         if (!strcmp(cpnext,"prevkey")) {
00302             prevkeysym = keysym;
00303             return;
00304         }
00305     } else {
00306         if (standard) standard=KEYF_STANDARD;
00307         else standard=0;
00308 
00309         *cpnext++ = '\0';
00310         keysym = gdk_keyval_from_name(buf);
00311         if (!keysym) {
00312             LOG(LOG_WARNING,"gtk::parse_keybind_line","Unable to convert line %d (%s) into keysym", line, cp);
00313             return;
00314         }
00315         cp = cpnext;
00316         if ((cpnext = strchr(cp,' '))==NULL) {
00317             LOG(LOG_WARNING,"gtk::parse_keybind_line","Line %d (%s) corrupted in keybinding file.", line, cp);
00318             return;
00319         }
00320         *cpnext++ = '\0';
00321 
00322         cp = cpnext;
00323         if ((cpnext = strchr(cp,' '))==NULL) {
00324             LOG(LOG_WARNING,"gtk::parse_keybind_line","Line %d (%s) corrupted in keybinding file.", line, cp);
00325             return;
00326         }
00327         *cpnext++ = '\0';
00328         flags = 0;
00329         while (*cp!='\0') {
00330             switch (*cp) {
00331                 case 'A':
00332                     flags |= KEYF_NORMAL | KEYF_FIRE | KEYF_RUN
00333                                          | KEYF_META | KEYF_ALT;
00334                     break;
00335                 case 'E':
00336                     flags |= KEYF_EDIT;
00337                     break;
00338                 case 'F':
00339                     flags |= KEYF_FIRE;
00340                     break;
00341                 case 'L':   /* A is used, so using L for alt */
00342                     flags |= KEYF_ALT;
00343                     break;
00344                 case 'M':
00345                     flags |= KEYF_META;
00346                     break;
00347                 case 'N':
00348                     flags |= KEYF_NORMAL;
00349                     break;
00350                 case 'R':
00351                     flags |= KEYF_RUN;
00352                     break;
00353                 case 'S':
00354                     flags |= KEYF_STANDARD;
00355                     break;
00356                 default:
00357                     LOG(LOG_WARNING,"gtk::parse_keybind_line","Unknown flag (%c) line %d in key binding file",
00358                             *cp, line);
00359             }
00360             cp++;
00361         }
00362 
00363         /* Rest of the line is the actual command.  Lets kill the newline */
00364         cpnext[strlen(cpnext)-1]='\0';
00365         if (strlen(cpnext)>(sizeof(bind_buf)-1)){
00366             cpnext[sizeof(bind_buf)-1]='\0';
00367             LOG(LOG_WARNING,"gtk::parse_keybind_line","Command too long! Truncated.");
00368         }
00369 
00370         insert_key(keysym, flags | standard, cpnext);
00371     } /* else if not special binding line */
00372 }
00373 
00378 static void init_default_keybindings(void)
00379 {
00380     char buf[MAX_BUF];
00381     int i;
00382 
00383     for(i=0;i< sizeof(def_keys)/sizeof(char *);i++) {
00384         strcpy(buf,def_keys[i]);
00385         parse_keybind_line(buf,i,1);
00386     }
00387 }
00388 
00398 void keys_init(GtkWidget *window_root)
00399 {
00400     int i, line = 0;
00401     FILE *fp;
00402     char buf[BIG_BUF];
00403     GtkTreeViewColumn *column;
00404     GtkCellRenderer *renderer;
00405     GladeXML *xml_tree;
00406     GtkWidget *widget;
00407 
00408     for (i = 0; i < MAX_HISTORY; i++)   /* Clear out the bind history log */
00409         history[i][0] = 0;
00410 
00411     commandkeysym  = GDK_apostrophe;
00412     firekeysym[0]  = GDK_Shift_L;
00413     firekeysym[1]  = GDK_Shift_R;
00414     runkeysym[0]   = GDK_Control_L;
00415     runkeysym[1]   = GDK_Control_R;
00416     metakeysym[0]  = GDK_Meta_L;
00417     metakeysym[1]  = GDK_Meta_R;
00418     altkeysym[0]   = GDK_Alt_L;
00419     altkeysym[1]   = GDK_Alt_R;
00420 
00421     completekeysym = GDK_Tab;
00422     cancelkeysym   = GDK_Escape;
00423 
00424     /*
00425      * Don't set these to anything by default.  At least on Sun keyboards, the
00426      * keysym for up on both the keypad and arrow keys is the same, so player
00427      * needs to rebind this so we get proper keycode.  Very unfriendly to log
00428      * in and not be able to move north/south.
00429      */
00430     nextkeysym = NoSymbol;
00431     prevkeysym = NoSymbol;
00432 
00433     for (i=0; i<KEYHASH; i++) {
00434         keys[i] = NULL;
00435     }
00436 
00437     /*
00438      * We now try to load the keybindings.  First place to look is the users
00439      * home directory, "~/.crossfire/keys".  Using a directory seems like a
00440      * good idea, in the future, additional stuff may be stored.
00441      *
00442      * The format is described in the def_keys file.  Note that this file is
00443      * the same as what it was in the server distribution.  To convert bindings
00444      * in character files to this format, all that needs to be done is remove
00445      * the 'key ' at the start of each line.
00446      *
00447      * We need at least one of these keybinding files to exist - this is where
00448      * the various commands are defined.  In theory, we actually don't need to
00449      * have any of these defined -- the player could just bind everything.
00450      * Probably not a good idea, however.
00451      */
00452 
00453 #if 0
00454     /* For Windows, use player name if defined for key file */
00455     /* FIXME:  keys_init() is called long before the player logs in, so until
00456      * that is fixed, it is pointless to have this code check for cpl.name
00457      * being set.  Also, it is completely inappropriate for this to be a
00458      * Windows only feature.
00459      */
00460     if ( strlen( cpl.name ) )
00461         sprintf( buf, "%s/.crossfire/%s.keys", getenv( "HOME" ), cpl.name );
00462     else
00463         sprintf(buf,"%s/.crossfire/keys", getenv("HOME"));
00464 #else
00465     snprintf(buf, sizeof(buf), "%s/.crossfire/keys", getenv("HOME"));
00466 #endif
00467 
00468     xml_tree = glade_get_widget_tree(GTK_WIDGET(window_root));
00469 
00470     fire_label = glade_xml_get_widget(xml_tree, "fire_label");
00471     run_label = glade_xml_get_widget(xml_tree, "run_label");
00472     entry_commands = glade_xml_get_widget(xml_tree, "entry_commands");
00473     spinbutton_count = glade_xml_get_widget(xml_tree, "spinbutton_count");
00474 
00475     g_signal_connect ((gpointer) entry_commands, "activate",
00476         G_CALLBACK (on_entry_commands_activate), NULL);
00477 
00478     keybinding_window = glade_xml_get_widget(dialog_xml, "keybinding_window");
00479     xml_tree = glade_get_widget_tree(GTK_WIDGET(keybinding_window));
00480 
00481     keybinding_checkbutton_control =
00482         glade_xml_get_widget(xml_tree, "keybinding_checkbutton_control");
00483     keybinding_checkbutton_shift =
00484         glade_xml_get_widget(xml_tree, "keybinding_checkbutton_shift");
00485     keybinding_checkbutton_alt =
00486         glade_xml_get_widget(xml_tree, "keybinding_checkbutton_alt");
00487     keybinding_checkbutton_meta =
00488         glade_xml_get_widget(xml_tree, "keybinding_checkbutton_meta");
00489     keybinding_checkbutton_edit =
00490         glade_xml_get_widget(xml_tree, "keybinding_checkbutton_stayinedit");
00491     keybinding_entry_key =
00492         glade_xml_get_widget(xml_tree, "keybinding_entry_key");
00493     keybinding_entry_command =
00494         glade_xml_get_widget(xml_tree, "keybinding_entry_command");
00495     keybinding_treeview =
00496         glade_xml_get_widget(xml_tree, "keybinding_treeview");
00497     keybinding_button_remove =
00498         glade_xml_get_widget(xml_tree, "keybinding_button_remove");
00499     keybinding_button_update =
00500         glade_xml_get_widget(xml_tree, "keybinding_button_update");
00501     keybinding_button_bind =
00502         glade_xml_get_widget(xml_tree, "keybinding_button_bind");
00503 
00504     g_signal_connect ((gpointer) keybinding_entry_key, "key_press_event",
00505         G_CALLBACK (on_keybinding_entry_key_key_press_event), NULL);
00506     g_signal_connect ((gpointer) keybinding_button_remove, "clicked",
00507         G_CALLBACK (on_keybinding_button_remove_clicked), NULL);
00508     g_signal_connect ((gpointer) keybinding_button_update, "clicked",
00509         G_CALLBACK (on_keybinding_button_update_clicked), NULL);
00510     g_signal_connect ((gpointer) keybinding_button_bind, "clicked",
00511         G_CALLBACK (on_keybinding_button_bind_clicked), NULL);
00512 
00513     widget = glade_xml_get_widget(xml_tree, "keybinding_button_clear");
00514     g_signal_connect ((gpointer) widget, "clicked",
00515         G_CALLBACK (on_keybinding_button_clear_clicked), NULL);
00516 
00517     widget = glade_xml_get_widget(xml_tree, "keybinding_button_close");
00518     g_signal_connect ((gpointer) widget, "clicked",
00519         G_CALLBACK (on_keybinding_button_close_clicked), NULL);
00520 
00521     gtk_widget_set_sensitive(keybinding_button_remove, FALSE);
00522     gtk_widget_set_sensitive(keybinding_button_update, FALSE);
00523     keybinding_store = gtk_list_store_new(6,
00524                                           G_TYPE_INT,
00525                                           G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING,
00526                                           G_TYPE_POINTER
00527                                           );
00528     gtk_tree_view_set_model(GTK_TREE_VIEW(keybinding_treeview), GTK_TREE_MODEL(keybinding_store));
00529 
00530     renderer = gtk_cell_renderer_text_new ();
00531     column = gtk_tree_view_column_new_with_attributes ("Key", renderer,
00532                                                       "text", KLIST_KEY,
00533                                                       NULL);
00534     gtk_tree_view_column_set_sort_column_id(column, KLIST_KEY);
00535     gtk_tree_view_append_column (GTK_TREE_VIEW (keybinding_treeview), column);
00536 
00537     renderer = gtk_cell_renderer_text_new ();
00538     column = gtk_tree_view_column_new_with_attributes ("Modifiers", renderer,
00539                                                       "text", KLIST_MODS,
00540                                                       NULL);
00541     gtk_tree_view_column_set_sort_column_id(column, KLIST_MODS);
00542     gtk_tree_view_append_column (GTK_TREE_VIEW (keybinding_treeview), column);
00543 
00544     renderer = gtk_cell_renderer_text_new ();
00545     column = gtk_tree_view_column_new_with_attributes ("Edit Mode", renderer,
00546                                                       "text", KLIST_EDIT,
00547                                                       NULL);
00548     gtk_tree_view_column_set_sort_column_id(column, KLIST_EDIT);
00549     gtk_tree_view_append_column (GTK_TREE_VIEW (keybinding_treeview), column);
00550 
00551     renderer = gtk_cell_renderer_text_new ();
00552     column = gtk_tree_view_column_new_with_attributes ("Command", renderer,
00553                                                       "text", KLIST_COMMAND,
00554                                                       NULL);
00555     gtk_tree_view_column_set_sort_column_id(column, KLIST_COMMAND);
00556     gtk_tree_view_append_column (GTK_TREE_VIEW (keybinding_treeview), column);
00557 
00558 
00559     keybinding_selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(keybinding_treeview));
00560     gtk_tree_selection_set_mode (keybinding_selection, GTK_SELECTION_BROWSE);
00561     gtk_tree_selection_set_select_function(keybinding_selection, keybinding_selection_func, NULL, NULL);
00562 
00563     gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(keybinding_store),
00564                                              KLIST_KEY,
00565                                              GTK_SORT_ASCENDING);
00566 
00567     if ((fp=fopen(buf,"r"))==NULL) {
00568         LOG(LOG_INFO,"gtk::init_keys","Could not open ~/.crossfire/keys, trying to load global bindings");
00569         if (client_libdir==NULL) {
00570             init_default_keybindings();
00571             return;
00572         }
00573         snprintf(buf, sizeof(buf), "%s/def_keys", client_libdir);
00574         if ((fp=fopen(buf,"r"))==NULL) {
00575             init_default_keybindings();
00576             return;
00577         }
00578     }
00579     while (fgets(buf, BIG_BUF, fp)) {
00580         line++;
00581     buf[BIG_BUF-1]='\0';
00582         parse_keybind_line(buf,line,0);
00583     }
00584     fclose(fp);
00585 }
00586 
00599 static void parse_key_release(uint32 ks) {
00600 
00601     /*
00602      * Only send stop firing/running commands if we are in actual play mode.
00603      * Something smart does need to be done when the character enters a non
00604      * play mode with fire or run mode already set, however.
00605      */
00606     if (ks==firekeysym[0] || ks==firekeysym[1]) {
00607         cpl.fire_on=0;
00608         clear_fire();
00609         gtk_label_set (GTK_LABEL(fire_label),"    ");
00610     }
00611     else if (ks==runkeysym[0] || ks==runkeysym[1]) {
00612         cpl.run_on=0;
00613         if (use_config[CONFIG_ECHO]) draw_info("stop run",NDI_BLACK);
00614         clear_run();
00615         gtk_label_set (GTK_LABEL(run_label),"   ");
00616     }
00617     else if (ks==altkeysym[0] || ks==altkeysym[1]) {
00618         cpl.alt_on=0;
00619     }
00620     else if (ks==metakeysym[0] || ks==metakeysym[1]) {
00621         cpl.meta_on=0;
00622     }
00623     /*
00624      * Firing is handled on server side.  However, to keep more like the old
00625      * version, if you release the direction key, you want the firing to stop.
00626      * This should do that.
00627      */
00628     else if (cpl.fire_on)
00629         clear_fire();
00630 }
00631 
00638 static void parse_key(char key, uint32 keysym)
00639 {
00640     Key_Entry *keyentry, *first_match=NULL;
00641     int present_flags=0;
00642     char buf[MAX_BUF], tmpbuf[MAX_BUF];
00643 
00644     if (keysym==commandkeysym) {
00645         gtk_widget_grab_focus (GTK_WIDGET(entry_commands));
00646         gtk_entry_set_visibility(GTK_ENTRY(entry_commands), 1);
00647         cpl.input_state = Command_Mode;
00648         cpl.no_echo=FALSE;
00649         return;
00650     }
00651     if (keysym==altkeysym[0] ||keysym==altkeysym[1]) {
00652         cpl.alt_on=1;
00653         return;
00654     }
00655     if (keysym==metakeysym[0] ||keysym==metakeysym[1]) {
00656         cpl.meta_on=1;
00657         return;
00658     }
00659     if (keysym==firekeysym[0] ||keysym==firekeysym[1]) {
00660         cpl.fire_on=1;
00661         gtk_label_set (GTK_LABEL(fire_label),"Fire");
00662         return;
00663     }
00664     if (keysym==runkeysym[0] || keysym==runkeysym[1]) {
00665         cpl.run_on=1;
00666         gtk_label_set (GTK_LABEL(run_label),"Run");
00667         return;
00668     }
00669 
00670     if (cpl.run_on) present_flags |= KEYF_RUN;
00671     if (cpl.fire_on) present_flags |= KEYF_FIRE;
00672     if (cpl.alt_on) present_flags |= KEYF_ALT;
00673     if (cpl.meta_on) present_flags |= KEYF_META;
00674     if (present_flags == 0) present_flags = KEYF_NORMAL;
00675 
00676     keyentry = keys[keysym % KEYHASH];
00677     while (keyentry!=NULL) {
00678         if ((keyentry->keysym!=0 && keyentry->keysym!=keysym) ||
00679             (!(keyentry->flags & present_flags))) {
00680                 keyentry=keyentry->next;
00681                 continue;
00682         }
00683         first_match = keyentry;
00684 
00685         /* Try to find a prefect match */
00686         if ((keyentry->flags & KEYF_MODIFIERS)!= present_flags) {
00687             keyentry=keyentry->next;
00688             continue;
00689         }
00690         else break;
00691     }
00692     if (first_match!=NULL) {
00693         if (first_match->flags & KEYF_EDIT) {
00694             strcpy(cpl.input_text, first_match->command);
00695             cpl.input_state = Command_Mode;
00696             gtk_entry_set_text(GTK_ENTRY(entry_commands),cpl.input_text);
00697             gtk_widget_grab_focus (GTK_WIDGET(entry_commands));
00698             gtk_editable_select_region(GTK_EDITABLE(entry_commands), 0, 0);
00699             gtk_editable_set_position(GTK_EDITABLE(entry_commands), -1);
00700             return;
00701         }
00702 
00703         if (first_match->direction>=0) {
00704             if (cpl.fire_on) {
00705                 snprintf(buf, sizeof(buf), "fire %s", first_match->command);
00706                 /* Some spells (dimension door) need a valid count value */
00707                 cpl.count = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON(spinbutton_count));
00708                 fire_dir(first_match->direction);
00709             }
00710             else if (cpl.run_on) {
00711                 run_dir(first_match->direction);
00712                 snprintf(buf, sizeof(buf), "run %s", first_match->command);
00713             }
00714             else {
00715                 extended_command(first_match->command);
00716             }
00717             if (use_config[CONFIG_ECHO]) draw_info(first_match->command,NDI_BLACK);
00718         }
00719         else {
00720             if (use_config[CONFIG_ECHO]) draw_info(first_match->command,NDI_BLACK);
00721             extended_command(first_match->command);
00722         }
00723         return;
00724     }
00725     if (key>='0' && key<='9') {
00726         cpl.count = cpl.count*10 + (key-'0');
00727         if (cpl.count>100000) cpl.count%=100000;
00728         gtk_spin_button_set_value (GTK_SPIN_BUTTON(spinbutton_count), (float) cpl.count );
00729         return;
00730     }
00731     tmpbuf[0]=0;
00732     if (cpl.fire_on) strcat(tmpbuf,"fire+");
00733     if (cpl.run_on) strcat(tmpbuf,"run+");
00734     if (cpl.alt_on) strcat(tmpbuf,"alt+");
00735     if (cpl.meta_on) strcat(tmpbuf,"meta+");
00736 
00737     snprintf(buf, sizeof(buf), "Key %s%s is not bound to any command.  Use bind to associate this keypress with a command",
00738             tmpbuf, keysym==NoSymbol? "unknown": gdk_keyval_name(keysym));
00739 #ifdef WIN32
00740        if ( ( 65513 != keysym ) && ( 65511 != keysym ) )
00741 #endif
00742     draw_info(buf,NDI_BLACK);
00743     cpl.count=0;
00744 }
00745 
00754 static char * get_key_info(Key_Entry *key, int save_mode)
00755 {
00756     /* bind buf is the maximum space allowed for a
00757      * binded command. We will add additional datas to
00758      * it so we increase by MAX_BUF*/
00759     static char buf[MAX_BUF+sizeof(bind_buf)];
00760 
00761     char buff[MAX_BUF];
00762     int bi=0;
00763 
00764     if ((key->flags & KEYF_MODIFIERS) == KEYF_MODIFIERS)
00765         buff[bi++] ='A';
00766     else {
00767         if (key->flags & KEYF_NORMAL)
00768           buff[bi++] ='N';
00769         if (key->flags & KEYF_FIRE)
00770           buff[bi++] ='F';
00771         if (key->flags & KEYF_RUN)
00772           buff[bi++] ='R';
00773         if (key->flags & KEYF_ALT)
00774           buff[bi++] ='L';
00775         if (key->flags & KEYF_META)
00776           buff[bi++] ='M';
00777     }
00778     if (key->flags & KEYF_EDIT)
00779         buff[bi++] ='E';
00780     if (key->flags & KEYF_STANDARD)
00781         buff[bi++] ='S';
00782 
00783     buff[bi]='\0';
00784     if (save_mode) {
00785         if(key->keysym == NoSymbol) {
00786           snprintf(buf, sizeof(buf), "(null) %i %s %s",
00787                 0,buff, key->command);
00788         }
00789         else {
00790           snprintf(buf, sizeof(buf), "%s %i %s %s",
00791                     gdk_keyval_name(key->keysym), 0,
00792                     buff, key->command);
00793         }
00794     }
00795     else {
00796         if(key->keysym == NoSymbol) {
00797           snprintf(buf, sizeof(buf), "key (null) %s %s",
00798                 buff, key->command);
00799         }
00800         else {
00801           snprintf(buf, sizeof(buf), "key %s %s %s",
00802                     gdk_keyval_name(key->keysym),
00803                     buff, key->command);
00804         }
00805     }
00806     return buf;
00807 }
00808 
00814 static void show_keys(int allbindings)
00815 {
00816     int i, count=1;
00817     Key_Entry *key;
00818     char buf[MAX_BUF];
00819 
00820     snprintf(buf, sizeof(buf), "Commandkey %s",
00821             commandkeysym==NoSymbol?"unknown":gdk_keyval_name(commandkeysym));
00822     draw_info(buf,NDI_BLACK);
00823 
00824     snprintf(buf, sizeof(buf), "Firekeys 1: %s, 2: %s",
00825             firekeysym[0]==NoSymbol?"unknown":gdk_keyval_name(firekeysym[0]),
00826             firekeysym[1]==NoSymbol?"unknown":gdk_keyval_name(firekeysym[1]));
00827     draw_info(buf,NDI_BLACK);
00828 
00829     snprintf(buf, sizeof(buf), "Altkeys 1: %s, 2: %s",
00830             altkeysym[0]==NoSymbol?"unknown":gdk_keyval_name(altkeysym[0]),
00831             altkeysym[1]==NoSymbol?"unknown":gdk_keyval_name(altkeysym[1]));
00832     draw_info(buf,NDI_BLACK);
00833 
00834     snprintf(buf, sizeof(buf), "Metakeys 1: %s, 2: %s",
00835             metakeysym[0]==NoSymbol?"unknown":gdk_keyval_name(metakeysym[0]),
00836             metakeysym[1]==NoSymbol?"unknown":gdk_keyval_name(metakeysym[1]));
00837     draw_info(buf,NDI_BLACK);
00838 
00839     snprintf(buf, sizeof(buf), "Runkeys 1: %s, 2: %s",
00840             runkeysym[0]==NoSymbol?"unknown":gdk_keyval_name(runkeysym[0]),
00841             runkeysym[1]==NoSymbol?"unknown":gdk_keyval_name(runkeysym[1]));
00842     draw_info(buf,NDI_BLACK);
00843 
00844     snprintf(buf, sizeof(buf), "Command Completion Key %s",
00845             completekeysym==NoSymbol?"unknown":gdk_keyval_name(completekeysym));
00846     draw_info(buf,NDI_BLACK);
00847 
00848     snprintf(buf, sizeof(buf), "Next Command in History Key %s",
00849             nextkeysym==NoSymbol?"unknown":gdk_keyval_name(nextkeysym));
00850     draw_info(buf,NDI_BLACK);
00851 
00852     snprintf(buf, sizeof(buf), "Previous Command in History Key %s",
00853             prevkeysym==NoSymbol?"unknown":gdk_keyval_name(prevkeysym));
00854     draw_info(buf,NDI_BLACK);
00855 
00856     /*
00857      * Perhaps we should start at 8, so that we only show 'active' keybindings?
00858      */
00859     for (i=0; i<KEYHASH; i++) {
00860         for (key=keys[i]; key!=NULL; key =key->next) {
00861             if (key->flags & KEYF_STANDARD && !allbindings) continue;
00862 
00863             snprintf(buf, sizeof(buf), "%3d %s",count,  get_key_info(key,0));
00864             draw_info(buf,NDI_BLACK);
00865             count++;
00866         }
00867     }
00868 }
00869 
00878 void bind_key(char *params)
00879 {
00880     char buf[MAX_BUF + 16];
00881 
00882     if (!params) {
00883         draw_info("Usage: bind [-aefmnr] {<commandline>/commandkey/firekey{1/2}"
00884                   "/runkey{1/2}/altkey{1/2}/metakey{1/2}"
00885                   "completekey/nextkey/prevkey}",NDI_BLACK);
00886         return;
00887     }
00888 
00889     /* Skip over any spaces we may have */
00890     while (*params==' ') params++;
00891 
00892     if (!strcmp(params, "commandkey")) {
00893         bind_keysym = &commandkeysym;
00894         draw_info("Push key to bind new commandkey.",NDI_BLACK);
00895         cpl.input_state = Configure_Keys;
00896         return;
00897     }
00898 
00899     if (!strcmp(params, "firekey1")) {
00900         bind_keysym = & firekeysym[0];
00901         draw_info("Push key to bind new firekey 1.",NDI_BLACK);
00902         cpl.input_state = Configure_Keys;
00903         return;
00904     }
00905     if (!strcmp(params, "firekey2")) {
00906         bind_keysym = & firekeysym[1];
00907         draw_info("Push key to bind new firekey 2.",NDI_BLACK);
00908         cpl.input_state = Configure_Keys;
00909         return;
00910     }
00911     if (!strcmp(params, "metakey1")) {
00912         bind_keysym = & metakeysym[0];
00913         draw_info("Push key to bind new metakey 1.",NDI_BLACK);
00914         cpl.input_state = Configure_Keys;
00915         return;
00916     }
00917     if (!strcmp(params, "metakey2")) {
00918         bind_keysym = & metakeysym[1];
00919         draw_info("Push key to bind new metakey 2.",NDI_BLACK);
00920         cpl.input_state = Configure_Keys;
00921         return;
00922     }
00923     if (!strcmp(params, "altkey1")) {
00924         bind_keysym = & altkeysym[0];
00925         draw_info("Push key to bind new altkey 1.",NDI_BLACK);
00926         cpl.input_state = Configure_Keys;
00927         return;
00928     }
00929     if (!strcmp(params, "altkey2")) {
00930         bind_keysym = & altkeysym[1];
00931         draw_info("Push key to bind new altkey 2.",NDI_BLACK);
00932         cpl.input_state = Configure_Keys;
00933         return;
00934     }
00935     if (!strcmp(params, "runkey1")) {
00936         bind_keysym = &runkeysym[0];
00937         draw_info("Push key to bind new runkey 1.",NDI_BLACK);
00938         cpl.input_state = Configure_Keys;
00939         return;
00940     }
00941 
00942     if (!strcmp(params, "runkey2")) {
00943         bind_keysym = &runkeysym[1];
00944         draw_info("Push key to bind new runkey 2.",NDI_BLACK);
00945         cpl.input_state = Configure_Keys;
00946         return;
00947     }
00948 
00949     if (!strcmp(params, "completekey")) {
00950         bind_keysym = &completekeysym;
00951         draw_info("Push key to bind new command completeion key",NDI_BLACK);
00952         cpl.input_state = Configure_Keys;
00953         return;
00954     }
00955 
00956     if (!strcmp(params, "prevkey")) {
00957         bind_keysym = &prevkeysym;
00958         draw_info("Push key to bind new previous command in history key.",NDI_BLACK);
00959         cpl.input_state = Configure_Keys;
00960         return;
00961     }
00962 
00963     if (!strcmp(params, "nextkey")) {
00964         bind_keysym = &nextkeysym;
00965         draw_info("Push key to bind new next command in history key.",NDI_BLACK);
00966         cpl.input_state = Configure_Keys;
00967         return;
00968     }
00969 
00970     if (params[0] != '-')
00971         bind_flags = KEYF_MODIFIERS;
00972     else {
00973         bind_flags =0;
00974         bind_keysym=NULL;
00975         for (params++; *params != ' '; params++)
00976         switch (*params) {
00977             case 'a':
00978                 bind_flags |= KEYF_ALT;
00979                 break;
00980             case 'e':
00981                 bind_flags |= KEYF_EDIT;
00982                 break;
00983             case 'f':
00984                 bind_flags |= KEYF_FIRE;
00985                 break;
00986             case 'm':
00987                 bind_flags |= KEYF_META;
00988                 break;
00989             case 'n':
00990                 bind_flags |= KEYF_NORMAL;
00991                 break;
00992             case 'r':
00993                 bind_flags |= KEYF_RUN;
00994                 break;
00995             case '\0':
00996                 draw_info("Use unbind to remove bindings.",NDI_BLACK);
00997                 return;
00998             default:
00999                 snprintf(buf, sizeof(buf), "Unsupported or invalid bind flag: '%c'", *params);
01000                 draw_info(buf,NDI_BLACK);
01001                 return;
01002         }
01003         params++;
01004     }
01005 
01006     if (! (bind_flags & KEYF_MODIFIERS))
01007         bind_flags |= KEYF_MODIFIERS;
01008 
01009     if (!params[0]) {
01010         draw_info("Use unbind to remove bindings.",NDI_BLACK);
01011         return;
01012     }
01013 
01014     if (strlen(params) >= sizeof(bind_buf)) {
01015         params[sizeof(bind_buf) - 1] = '\0';
01016         draw_info("Keybinding too long! Truncated:",NDI_RED);
01017         draw_info(params,NDI_RED);
01018     }
01019     snprintf(buf, sizeof(buf), "Push key to bind '%s'.", params);
01020     draw_info(buf,NDI_BLACK);
01021 
01022     strcpy(bind_buf, params);
01023     cpl.input_state = Configure_Keys;
01024     return;
01025 }
01026 
01039 static void save_individual_key(FILE *fp, Key_Entry *key, KeyCode kc)
01040 {
01041     if (key==NULL) return;
01042     fprintf(fp, "%s\n", get_key_info(key, 1));
01043     save_individual_key(fp, key->next, kc);
01044 }
01045 
01055 static void save_keys(void)
01056 {
01057     char buf[MAX_BUF], buf2[MAX_BUF];
01058     int i;
01059     FILE *fp;
01060 
01061 #if 0
01062     /* Use player's name if available */
01063     /* FIXME:  keys_init() is called long before the player logs in, so until
01064      * that is fixed, it is pointless to have this code check for cpl.name
01065      * being set so that a file is written that cannot be opened by under
01066      * the existing code structure.  That just means the keybindings saved
01067      * while logged in would be inaccessible until the file was copied to
01068      * the regular keys file.  Also, this was originally under #ifdef WIN32,
01069      * but is completely inappropriate for this to be a Windows only feature.
01070      */
01071     if ( strlen( cpl.name ) )
01072         sprintf( buf,"%s/.crossfire/%s.keys", getenv("HOME"), cpl.name );
01073     else
01074         sprintf( buf,"%s/.crossfire/keys", getenv("HOME") );
01075 #else
01076     snprintf(buf, sizeof(buf), "%s/.crossfire/keys", getenv("HOME"));
01077 #endif
01078 
01079     if (make_path_to_file(buf)==-1) {
01080         LOG(LOG_WARNING,"gtk::save_keys","Could not create %s", buf);
01081         return;
01082     }
01083     if ((fp=fopen(buf,"w"))==NULL) {
01084         snprintf(buf2, sizeof(buf2), "Could not open %s, key bindings not saved\n", buf);
01085         draw_info(buf2,NDI_BLACK);
01086         return;
01087     }
01088     if (commandkeysym != GDK_apostrophe && commandkeysym != NoSymbol) {
01089         fprintf(fp, "! commandkey %s %d\n",
01090                 gdk_keyval_name(commandkeysym), 0);
01091     }
01092     if (firekeysym[0] != GDK_Shift_L && firekeysym[0] != NoSymbol) {
01093         fprintf(fp, "! firekey0 %s %d\n",
01094                 gdk_keyval_name(firekeysym[0]), 0);
01095     }
01096     if (firekeysym[1] != GDK_Shift_R && firekeysym[1] != NoSymbol) {
01097         fprintf(fp, "! firekey1 %s %d\n",
01098                 gdk_keyval_name(firekeysym[1]), 0);
01099     }
01100     if (metakeysym[0] != GDK_Shift_L && metakeysym[0] != NoSymbol) {
01101         fprintf(fp, "! metakey0 %s %d\n",
01102                 gdk_keyval_name(metakeysym[0]), 0);
01103     }
01104     if (metakeysym[1] != GDK_Shift_R && metakeysym[1] != NoSymbol) {
01105         fprintf(fp, "! metakey1 %s %d\n",
01106                 gdk_keyval_name(metakeysym[1]), 0);
01107     }
01108     if (altkeysym[0] != GDK_Shift_L && altkeysym[0] != NoSymbol) {
01109         fprintf(fp, "! altkey0 %s %d\n",
01110                 gdk_keyval_name(altkeysym[0]), 0);
01111     }
01112     if (altkeysym[1] != GDK_Shift_R && altkeysym[1] != NoSymbol) {
01113         fprintf(fp, "! altkey1 %s %d\n",
01114                 gdk_keyval_name(altkeysym[1]), 0);
01115     }
01116     if (runkeysym[0] != GDK_Control_L && runkeysym[0] != NoSymbol) {
01117         fprintf(fp, "! runkey0 %s %d\n",
01118                 gdk_keyval_name(runkeysym[0]), 0);
01119     }
01120     if (runkeysym[1] != GDK_Control_R && runkeysym[1] != NoSymbol) {
01121         fprintf(fp, "! runkey1 %s %d\n",
01122                 gdk_keyval_name(runkeysym[1]), 0);
01123     }
01124     if (completekeysym != GDK_Tab && completekeysym != NoSymbol) {
01125         fprintf(fp, "! completekey %s %d\n",
01126                 gdk_keyval_name(completekeysym), 0);
01127     }
01128     /* No defaults for these, so if it is set to anything, assume its valid */
01129     if (nextkeysym != NoSymbol) {
01130         fprintf(fp, "! nextkey %s %d\n",
01131                 gdk_keyval_name(nextkeysym), 0);
01132     }
01133     if (prevkeysym != NoSymbol) {
01134         fprintf(fp, "! prevkey %s %d\n",
01135                 gdk_keyval_name(prevkeysym), 0);
01136     }
01137 
01138     for (i = 0; i < KEYHASH; i++) {
01139         save_individual_key(fp, keys[i], 0);
01140     }
01141     fclose(fp);
01142     /* Should probably check return value on all writes to be sure, but... */
01143     draw_info("Key bindings saved.",NDI_BLACK);
01144 }
01145 
01150 static void configure_keys(uint32 keysym)
01151 {
01152     char buf[MAX_BUF];
01153     Key_Entry *keyentry, *first_match=NULL;
01154 
01155     /*
01156      * I think that basically if we are not rebinding the special control keys
01157      * (in which case bind_kesym would be set to something) we just want to
01158      * handle these keypresses as normal events.
01159      */
01160     if (bind_keysym==NULL) {
01161         if(keysym == altkeysym[0] || keysym == altkeysym[1]) {
01162             cpl.alt_on =1;
01163             return;
01164         }
01165         if(keysym == metakeysym[0] || keysym == metakeysym[1]) {
01166             cpl.meta_on =1;
01167             return;
01168         }
01169         if(keysym == firekeysym[0] || keysym == firekeysym[1]) {
01170             cpl.fire_on =1;
01171             draw_message_window(0);
01172             return;
01173         }
01174         if(keysym == runkeysym[0] || keysym == runkeysym[1]) {
01175             cpl.run_on =1;
01176             draw_message_window(0);
01177             return;
01178         }
01179     }
01180     cpl.input_state = Playing;
01181     /*
01182      * Try to be clever - take into account shift/control keys being held down
01183      * when binding keys - in this way, player does not have to use -f and -r
01184      * flags to bind for many simple binds.
01185      */
01186     if ((cpl.fire_on || cpl.run_on || cpl.meta_on || cpl.alt_on) &&
01187       (bind_flags & KEYF_MODIFIERS)==KEYF_MODIFIERS) {
01188         bind_flags &= ~KEYF_MODIFIERS;
01189         if (cpl.fire_on) bind_flags |= KEYF_FIRE;
01190         if (cpl.run_on) bind_flags |= KEYF_RUN;
01191         if (cpl.meta_on) bind_flags |= KEYF_META;
01192         if (cpl.alt_on) bind_flags |= KEYF_ALT;
01193     }
01194 
01195     if (bind_keysym!=NULL) {
01196         *bind_keysym=keysym;
01197         bind_keysym=NULL;
01198     }
01199     else {
01200         keyentry = keys[keysym % KEYHASH];
01201         while (keyentry!=NULL) {
01202             if ((keyentry->keysym!=0 && keyentry->keysym!=keysym) ||
01203                 (!(keyentry->flags & bind_flags))) {
01204                     keyentry=keyentry->next;
01205                     continue;
01206             }
01207             first_match = keyentry;
01208 
01209             /* Try to find a prefect match */
01210             if ((keyentry->flags & KEYF_MODIFIERS)!= bind_flags) {
01211                 keyentry=keyentry->next;
01212                 continue;
01213             }
01214             else break;
01215         }
01216         if (first_match) {
01217             snprintf(buf, sizeof(buf), "Warning: Keybind %s may conflict with new binding.", first_match->command);
01218             draw_info(buf,NDI_RED);
01219         }
01220 
01221         insert_key(keysym, bind_flags, bind_buf);
01222     }
01223 
01224     snprintf(buf, sizeof(buf), "Binded to key '%s' (%i)",
01225           keysym==NoSymbol?"unknown":gdk_keyval_name(keysym), keysym);
01226     draw_info(buf,NDI_BLACK);
01227     cpl.fire_on=0;
01228     cpl.run_on=0;
01229     draw_message_window(0);
01230 
01231     /*
01232      * Do this each time a new key is bound.  This way, we are never actually
01233      * storing any information that needs to be saved when the connection dies
01234      * or the player quits.
01235      */
01236     save_keys();
01237     return;
01238 }
01239 
01243 static void unbind_usage(void)
01244 {
01245     draw_info("Usage: unbind <entry_number> or",NDI_BLACK);
01246     draw_info("Usage: unbind [-a] [-g] to show existing bindings", NDI_BLACK);
01247     draw_info("    -a shows all (global) bindings", NDI_BLACK);
01248     draw_info("    -g unbinds a global binding", NDI_BLACK);
01249 }
01250 
01255 void unbind_key(const char *params)
01256 {
01257     int count=0, keyentry, onkey,global=0;
01258     Key_Entry *key, *tmp;
01259     char buf[MAX_BUF];
01260 
01261     if (params==NULL || params[0]=='\0') {
01262         show_keys(0);
01263         return;
01264     }
01265 
01266     /* Skip over any spaces we may have */
01267     while (*params==' ') params++;
01268 
01269     if (!strcmp(params,"-a")) {
01270         show_keys(1);
01271         return;
01272     }
01273     if (!strncmp(params,"-g",2)) {
01274         global=1;
01275         if (!(params=strchr(params,' ')))  {
01276             unbind_usage();
01277             return;
01278         }
01279     }
01280     if ((keyentry=atoi(params))==0) {
01281         unbind_usage();
01282         return;
01283     }
01284 
01285     for (onkey=0; onkey<KEYHASH; onkey++) {
01286         for (key=keys[onkey]; key; key =key->next) {
01287             if (global || !(key->flags&KEYF_STANDARD)) count++;
01288             /* We found the key we want to unbind */
01289             if (keyentry==count) {
01290 
01291                 /* If it is the first entry, it is easy */
01292                 if (key == keys[onkey]) {
01293                     keys[onkey] = key->next;
01294                     goto unbinded;
01295                 }
01296                 /*
01297                  * Otherwise, we need to figure out where in the link list the
01298                  * entry is.
01299                  */
01300                 for (tmp=keys[onkey]; tmp->next!=NULL; tmp=tmp->next) {
01301                     if (tmp->next == key) {
01302                         tmp->next =key->next;
01303                         goto unbinded;
01304                     }
01305                 }
01306                 LOG(LOG_ERROR, "gtk:unbind_key",
01307                     "found number entry, but could not find actual key");
01308             }
01309         }
01310     }
01311     /* Makes things look better to draw the blank line */
01312     draw_info("",NDI_BLACK);
01313     draw_info("Not found. Try 'unbind' with no options to find entry.",
01314         NDI_BLACK);
01315     return;
01316     /*
01317      * Found. Now remove it.
01318      */
01319 unbinded:
01320     snprintf(buf, sizeof(buf), "Removed binding: %3d %s", count, get_key_info(key,0));
01321 
01322     draw_info(buf,NDI_BLACK);
01323     free(key->command);
01324     free(key);
01325     save_keys();
01326 }
01327 
01335 void keyrelfunc(GtkWidget *widget, GdkEventKey *event, GtkWidget *window)
01336 {
01337     if (event->keyval > 0 && ! GTK_WIDGET_HAS_FOCUS(entry_commands)) {
01338         parse_key_release(event->keyval);
01339     }
01340     g_signal_stop_emission_by_name(GTK_OBJECT (window), "key_release_event");
01341 }
01342 
01350 void keyfunc(GtkWidget *widget, GdkEventKey *event, GtkWidget *window) {
01351     char *text;
01352 
01353     if (!use_config[CONFIG_POPUPS]) {
01354         if ( ((cpl.input_state == Reply_One) || (cpl.input_state == Reply_Many))
01355         && (event->keyval == cancelkeysym) ) {
01356 
01357             /*
01358              * Player hit cancel button during input. Disconnect it (code from
01359              * menubar)
01360              */
01361 
01362             extern gint csocket_fd;
01363 
01364 #ifdef WIN32
01365             closesocket(csocket.fd);
01366 #else
01367             close(csocket.fd);
01368 #endif
01369             csocket.fd = -1;
01370             if (csocket_fd) {
01371                 gdk_input_remove(csocket_fd);
01372                 csocket_fd=0;
01373                 gtk_main_quit();
01374             }
01375             g_signal_stop_emission_by_name(
01376                 GTK_OBJECT (window), "key_press_event");
01377             return;
01378         }
01379         if  (cpl.input_state == Reply_One) {
01380             text = gdk_keyval_name(event->keyval);
01381             send_reply(text);
01382             cpl.input_state = Playing;
01383             g_signal_stop_emission_by_name(
01384                 GTK_OBJECT (window), "key_press_event");
01385             return;
01386         }
01387         else if (cpl.input_state == Reply_Many) {
01388             if (GTK_WIDGET_HAS_FOCUS (entry_commands))
01389                 gtk_widget_event(GTK_WIDGET(entry_commands), (GdkEvent*)event);
01390             else
01391                 gtk_widget_grab_focus (GTK_WIDGET(entry_commands));
01392             g_signal_stop_emission_by_name(
01393                 GTK_OBJECT (window), "key_press_event");
01394             return;
01395         }
01396     }
01397     /*
01398      * Better check for really weirdo keys, X doesnt like keyval 0 so avoid
01399      * handling these key values.
01400      */
01401     if (event->keyval > 0) {
01402         if (GTK_WIDGET_HAS_FOCUS (entry_commands)) {
01403             if (event->keyval == completekeysym)
01404                 gtk_complete_command();
01405             if (event->keyval == prevkeysym || event->keyval == nextkeysym)
01406                 gtk_command_history(event->keyval == nextkeysym?0:1);
01407             else
01408                 gtk_widget_event(GTK_WIDGET(entry_commands), (GdkEvent*)event);
01409         } else {
01410             switch(cpl.input_state) {
01411                 case Playing:
01412                     /*
01413                      * Specials - do command history - many times, the player
01414                      * will want to go the previous command when nothing is
01415                      * entered in the command window.
01416                      */
01417                     if (event->keyval == prevkeysym
01418                     ||  event->keyval == nextkeysym) {
01419                         gtk_command_history(event->keyval == nextkeysym?0:1);
01420                     } else {
01421                         if (cpl.run_on) {
01422                             if (!(event->state & GDK_CONTROL_MASK)) {
01423                                 /* printf("Run is on while ctrl is not\n"); */
01424                                 gtk_label_set (GTK_LABEL(run_label),"   ");
01425                                 cpl.run_on=0;
01426                                 stop_run();
01427                             }
01428                         }
01429                         if (cpl.fire_on) {
01430                             if (!(event->state & GDK_SHIFT_MASK)) {
01431                                 /* printf("Fire is on while shift is not\n");*/
01432                                 gtk_label_set (GTK_LABEL(fire_label),"   ");
01433                                 cpl.fire_on = 0;
01434                                 stop_fire();
01435                             }
01436                         }
01437 
01438                         if ( (event->state & GDK_CONTROL_MASK)
01439                         && (event->state & GDK_SHIFT_MASK)
01440                         && (event->keyval==GDK_i || event->keyval==GDK_I) ) {
01441                             reset_map();
01442                         }
01443 
01444                         parse_key(event->string[0], event->keyval);
01445                     }
01446                     break;
01447 
01448                 case Configure_Keys:
01449                     configure_keys(event->keyval);
01450                     break;
01451 
01452                 case Command_Mode:
01453                     if ( event->keyval == completekeysym )
01454                         gtk_complete_command();
01455                     if ( event->keyval == prevkeysym
01456                     ||   event->keyval == nextkeysym )
01457                         gtk_command_history(event->keyval == nextkeysym?0:1);
01458                     else {
01459                         gtk_widget_grab_focus (GTK_WIDGET(entry_commands));
01460                         /*
01461                          * When running in split windows mode, entry_commands
01462                          * can't get focus because it is in a different
01463                          * window.  So we have to pass the event to it
01464                          * explicitly.
01465                          */
01466                         if (GTK_WIDGET_HAS_FOCUS(entry_commands) == 0)
01467                             gtk_widget_event(
01468                                 GTK_WIDGET(entry_commands), (GdkEvent*)event);
01469                     }
01470                     /*
01471                      * Don't pass signal along to default handlers -
01472                      * otherwise, we get get crashes in the clist area (gtk
01473                      * fault I believe)
01474                      */
01475                     break;
01476 
01477                 case Metaserver_Select:
01478                     gtk_widget_grab_focus (GTK_WIDGET(entry_commands));
01479                     break;
01480 
01481                 default:
01482                     LOG(LOG_ERROR, "gtk:keyfunc",
01483                         "Unknown input state: %d", cpl.input_state);
01484             }
01485         }
01486     }
01487     g_signal_stop_emission_by_name(
01488         GTK_OBJECT (window), "key_press_event");
01489 }
01490 
01496 void draw_keybindings (GtkWidget *keylist) {
01497     int i, count=1;
01498     Key_Entry *key;
01499     int allbindings=0;
01500     char buff[MAX_BUF];
01501     int bi=0;
01502     char buffer[5][MAX_BUF];
01503     char *buffers[5];
01504     gint tmprow;
01505 
01506     gtk_clist_clear (GTK_CLIST(keylist));
01507     for (i=0; i<KEYHASH; i++) {
01508         for (key=keys[i]; key!=NULL; key =key->next) {
01509             if (key->flags & KEYF_STANDARD && !allbindings) continue;
01510 
01511             bi=0;
01512 
01513             if ((key->flags & KEYF_MODIFIERS) == KEYF_MODIFIERS)
01514                 buff[bi++] ='A';
01515             else {
01516                 if (key->flags & KEYF_NORMAL)
01517                     buff[bi++] ='N';
01518                 if (key->flags & KEYF_FIRE)
01519                     buff[bi++] ='F';
01520                 if (key->flags & KEYF_RUN)
01521                     buff[bi++] ='R';
01522                 if (key->flags & KEYF_ALT)
01523                     buff[bi++] ='L';
01524                 if (key->flags & KEYF_META)
01525                     buff[bi++] ='M';
01526             }
01527             if (key->flags & KEYF_EDIT)
01528                 buff[bi++] ='E';
01529             if (key->flags & KEYF_STANDARD)
01530                 buff[bi++] ='S';
01531 
01532             buff[bi]='\0';
01533 
01534             if(key->keysym != NoSymbol) {
01535                 snprintf(buffer[0], sizeof(buffer[0]), "%i",count);
01536                 snprintf(buffer[1], sizeof(buffer[1]), "%s", gdk_keyval_name(key->keysym));
01537                 snprintf(buffer[2], sizeof(buffer[2]), "%i",i);
01538                 snprintf(buffer[3], sizeof(buffer[3]), "%s",buff);
01539                 snprintf(buffer[4], sizeof(buffer[4]), "%s", key->command);
01540                 buffers[0] = buffer[0];
01541                 buffers[1] = buffer[1];
01542                 buffers[2] = buffer[2];
01543                 buffers[3] = buffer[3];
01544                 buffers[4] = buffer[4];
01545                 tmprow = gtk_clist_append (GTK_CLIST (keylist), buffers);
01546             }
01547             count++;
01548         }
01549     }
01550 }
01551 
01555 void x_set_echo(void)
01556 {
01557     gtk_entry_set_visibility(GTK_ENTRY(entry_commands), !cpl.no_echo);
01558 }
01559 
01565 void draw_prompt(const char *str)
01566 {
01567     draw_info(str, NDI_WHITE);
01568     gtk_widget_grab_focus (GTK_WIDGET(entry_commands));
01569 }
01570 
01576 void gtk_command_history(int direction)
01577 {
01578     int i=scroll_history_position;
01579     if (direction) {
01580         i--;
01581         if (i<0) i+=MAX_HISTORY;
01582         if (i == cur_history_position) return;
01583     } else {
01584         i++;
01585         if (i>=MAX_HISTORY) i = 0;
01586         if (i == cur_history_position) {
01587             /*
01588              * User has forwarded to what should be current entry - reset it
01589              * now.
01590              */
01591             gtk_entry_set_text(GTK_ENTRY(entry_commands), "");
01592             gtk_entry_set_position(GTK_ENTRY(entry_commands), 0);
01593             scroll_history_position=cur_history_position;
01594             return;
01595         }
01596     }
01597 
01598     if (history[i][0] == 0) return;
01599 
01600     scroll_history_position=i;
01601 /*  fprintf(stderr,"resetting postion to %d, data = %s\n", i, history[i]);*/
01602     gtk_entry_set_text(GTK_ENTRY(entry_commands), history[i]);
01603     gtk_widget_grab_focus (GTK_WIDGET(entry_commands));
01604     gtk_editable_select_region(GTK_EDITABLE(entry_commands), 0, 0);
01605     gtk_editable_set_position(GTK_EDITABLE(entry_commands), -1);
01606 
01607     cpl.input_state = Command_Mode;
01608 }
01609 
01616 void gtk_complete_command(void)
01617 {
01618     const gchar *entry_text, *newcommand;
01619 
01620     entry_text = gtk_entry_get_text(GTK_ENTRY(entry_commands));
01621     newcommand = complete_command(entry_text);
01622     /* value differ, so update window */
01623     if (newcommand != NULL) {
01624         gtk_entry_set_text(GTK_ENTRY(entry_commands), newcommand);
01625         gtk_widget_grab_focus (GTK_WIDGET(entry_commands));
01626         gtk_editable_select_region(GTK_EDITABLE(entry_commands), 0, 0);
01627         gtk_editable_set_position(GTK_EDITABLE(entry_commands), -1);
01628     }
01629 }
01630 
01638 void
01639 on_entry_commands_activate             (GtkEntry        *entry,
01640                                         gpointer         user_data)
01641 {
01642     const gchar *entry_text;
01643     extern GtkWidget *treeview_look;
01644 
01645     /* Next reply will reset this as necessary */
01646     if (!use_config[CONFIG_POPUPS])
01647         gtk_entry_set_visibility(GTK_ENTRY(entry), TRUE);
01648 
01649     entry_text = gtk_entry_get_text(GTK_ENTRY(entry));
01650 
01651     if (cpl.input_state==Metaserver_Select) {
01652         strcpy(cpl.input_text, entry_text);
01653     } else if (cpl.input_state == Reply_One || cpl.input_state == Reply_Many) {
01654         cpl.input_state = Playing;
01655         strcpy(cpl.input_text, entry_text);
01656         if (cpl.input_state == Reply_One)
01657             cpl.input_text[1] = 0;
01658 
01659         send_reply(cpl.input_text);
01660 
01661     } else {
01662         cpl.input_state = Playing;
01663         /* No reason to do anything for a null string */
01664         if (entry_text[0] != 0) {
01665             strncpy(history[cur_history_position], entry_text, MAX_COMMAND_LEN);
01666             history[cur_history_position][MAX_COMMAND_LEN-1] = 0;
01667             cur_history_position++;
01668             cur_history_position %= MAX_HISTORY;
01669             scroll_history_position = cur_history_position;
01670             extended_command(entry_text);
01671         }
01672     }
01673     gtk_entry_set_text(GTK_ENTRY(entry),"");
01674 
01675     /*
01676      * This grab focus is really just so the entry box doesn't have focus -
01677      * this way, keypresses are used to play the game, and not as stuff that
01678      * goes into the entry box.  It doesn't make much difference what widget
01679      * this is set to, as long as it is something that can get focus.
01680      */
01681     gtk_widget_grab_focus (GTK_WIDGET(treeview_look));
01682 
01683     if( cpl.input_state == Metaserver_Select)
01684     {
01685         cpl.input_state= Playing;
01686         /*
01687          * This is the gtk_main that is started up by get_metaserver The client
01688          * will start another one once it is connected to a crossfire server
01689          */
01690         gtk_main_quit();
01691     }
01692 }
01693 
01706 void update_keybinding_list(void)
01707 {
01708     int i, allbindings=0;
01709     Key_Entry *key;
01710     char    modifier_buf[256];
01711     GtkTreeIter iter;
01712 
01713     gtk_list_store_clear(keybinding_store);
01714 
01715     for (i=0; i<KEYHASH; i++) {
01716         for (key=keys[i]; key!=NULL; key =key->next) {
01717             if (key->flags & KEYF_STANDARD && !allbindings) continue;
01718 
01719             modifier_buf[0] = 0;
01720 
01721             if ((key->flags & KEYF_MODIFIERS) != KEYF_MODIFIERS) {
01722                 if (key->flags & KEYF_ALT)  strcat(modifier_buf,"Alt ");
01723                 if (key->flags & KEYF_FIRE)  strcat(modifier_buf,"Fire ");
01724                 if (key->flags & KEYF_RUN)  strcat(modifier_buf,"Run ");
01725                 if (key->flags & KEYF_META)  strcat(modifier_buf,"Meta ");
01726             } else {
01727               strcat(modifier_buf, "All ");
01728             }
01729             if (key->flags & KEYF_STANDARD)  strcat(modifier_buf,"(Standard) ");
01730             gtk_list_store_append(keybinding_store, &iter);
01731             gtk_list_store_set(keybinding_store, &iter,
01732                                KLIST_ENTRY, i,
01733                                KLIST_KEY,  gdk_keyval_name(key->keysym),
01734                                KLIST_MODS, modifier_buf,
01735                                KLIST_EDIT, (key->flags & KEYF_EDIT) ? "Yes":"No",
01736                                KLIST_COMMAND, key->command,
01737                                KLIST_KEY_ENTRY, key,
01738                                -1);
01739         }
01740     }
01741     reset_keybinding_status();
01742 }
01743 
01750 void
01751 on_keybindings_activate                (GtkMenuItem     *menuitem,
01752                                         gpointer         user_data)
01753 {
01754     gtk_widget_show(keybinding_window);
01755     update_keybinding_list();
01756 }
01757 
01770 gboolean
01771 on_keybinding_entry_key_key_press_event(GtkWidget       *widget,
01772                                         GdkEventKey     *event,
01773                                         gpointer         user_data)
01774 {
01775     gtk_entry_set_text(
01776         GTK_ENTRY(keybinding_entry_key), gdk_keyval_name(event->keyval));
01777     /*
01778      * This code is basically taken from the GTKv1 client.  However, at some
01779      * level it is broken, since the control/shift/etc masks are hardcoded, yet
01780      * we do let the users redefine them.
01781      *
01782      * The clearing of the modifiers is disabled.  In my basic testing, I
01783      * checked the modifiers and then pressed the key - have those modifiers go
01784      * away I think is less intuitive.
01785      */
01786     if (event->state & GDK_CONTROL_MASK)
01787         gtk_toggle_button_set_active(
01788             GTK_TOGGLE_BUTTON(keybinding_checkbutton_control), TRUE);
01789 
01790 #if 0
01791     else
01792         gtk_toggle_button_set_active(
01793             GTK_TOGGLE_BUTTON(keybinding_checkbutton_control), FALSE);
01794 #endif
01795 
01796     if (event->state & GDK_SHIFT_MASK)
01797         gtk_toggle_button_set_active(
01798             GTK_TOGGLE_BUTTON(keybinding_checkbutton_shift), TRUE);
01799 
01800 #if 0
01801     else
01802         gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(keybinding_checkbutton_shift), FALSE);
01803 
01804     /* The GDK_MOD_MASK* will likely correspond to alt and meta, yet there is
01805      * no way to be sure what goes to what, so easiest to just not allow them.
01806      */
01807     gtk_toggle_button_set_active(
01808         GTK_TOGGLE_BUTTON(keybinding_checkbutton_alt), FALSE);
01809     gtk_toggle_button_set_active(
01810         GTK_TOGGLE_BUTTON(keybinding_checkbutton_meta), FALSE);
01811 #endif
01812 
01813     /* Returning TRUE prevents widget from getting this event */
01814     return TRUE;
01815 }
01816 
01824 void
01825 on_keybinding_button_remove_clicked    (GtkButton       *button,
01826                                         gpointer         user_data)
01827 {
01828     GtkTreeModel    *model;
01829     GtkTreeIter iter;
01830     Key_Entry   *entry, *key, *tmp;
01831     int onkey;
01832 
01833     if (!gtk_tree_selection_get_selected(keybinding_selection, &model, &iter)) {
01834         LOG(LOG_ERROR, "keys.c:on_keybinding_button_remove_clicked",
01835             "Function called with nothing selected\n");
01836         return;
01837     }
01838     gtk_tree_model_get(model, &iter, KLIST_KEY_ENTRY, &entry, -1);
01839     for (onkey = 0; onkey < KEYHASH; onkey++) {
01840         for (key = keys[onkey]; key; key = key->next) {
01841             if (key == entry) {
01842                 /*
01843                  * This code is directly from unbind_key() above If it is the
01844                  * first entry, it is easy
01845                  */
01846                 if (key == keys[onkey]) {
01847                     keys[onkey] = key->next;
01848                     goto unbinded;
01849                 }
01850                 /*
01851                  * Otherwise, we need to figure out where in the link list the
01852                  * entry is.
01853                  */
01854                 for (tmp = keys[onkey]; tmp->next != NULL; tmp = tmp->next) {
01855                     if (tmp->next == key) {
01856                         tmp->next = key->next;
01857                         goto unbinded;
01858                     }
01859                 }
01860             }
01861         }
01862     }
01863     LOG(LOG_ERROR, "keys.c:on_keybinding_button_remove_clicked",
01864         "Unable to find matching key entry\n");
01865 
01866 unbinded:
01867     free(key->command);
01868     free(key);
01869     save_keys();
01870     update_keybinding_list();
01871 }
01872 
01882 static void keybinding_get_data(uint32 *keysym, uint8 *flags, const char **command)
01883 {
01884     static char bind_buf[MAX_BUF];
01885     const char *ed;
01886     *flags = 0;
01887 
01888     if (gtk_toggle_button_get_active(
01889         GTK_TOGGLE_BUTTON(keybinding_checkbutton_control)))
01890             *flags |= KEYF_RUN;
01891 
01892     if (gtk_toggle_button_get_active(
01893         GTK_TOGGLE_BUTTON(keybinding_checkbutton_shift)))
01894             *flags |= KEYF_FIRE;
01895 
01896     if (gtk_toggle_button_get_active(
01897         GTK_TOGGLE_BUTTON(keybinding_checkbutton_alt)))
01898             *flags |= KEYF_ALT;
01899 
01900     if (gtk_toggle_button_get_active(
01901         GTK_TOGGLE_BUTTON(keybinding_checkbutton_meta)))
01902             *flags |= KEYF_META;
01903 
01904     /* Set the KEYF_NORMAL flag when either none or all of the Run, Fire, Alt,
01905      * Meta checkboxes are checked. This closely matches the combined existing
01906      * logic in the parse_key() and get_key_info() functions.
01907      */
01908     if (! *flags || (*flags | KEYF_NORMAL) == KEYF_MODIFIERS)
01909       *flags |= KEYF_NORMAL;
01910 
01911     if (gtk_toggle_button_get_active(
01912         GTK_TOGGLE_BUTTON(keybinding_checkbutton_edit)))
01913             *flags |= KEYF_EDIT;
01914 
01915     ed = gtk_entry_get_text(GTK_ENTRY(keybinding_entry_command));
01916     if (strlen(ed) >= sizeof(bind_buf)) {
01917         draw_info("Keybinding too long! Truncated.",NDI_RED);
01918         strncpy(bind_buf, ed, MAX_BUF-1);
01919         bind_buf[MAX_BUF-1] = 0;
01920         *command = bind_buf;
01921     } else {
01922         *command = ed;
01923     }
01924 
01925     /*
01926      * This isn't ideal - when the key is pressed, we convert it to a string,
01927      * and now we are converting it back.  It'd be nice to tuck the keysym
01928      * itself away someplace.
01929      */
01930     *keysym = gdk_keyval_from_name(
01931         gtk_entry_get_text(GTK_ENTRY(keybinding_entry_key)));
01932     if (*keysym == GDK_VoidSymbol) {
01933         LOG(LOG_ERROR, "keys.c:keybinding_get_data",
01934             "Cannot get valid keysym from selection");
01935     }
01936 }
01937 
01944 void
01945 on_keybinding_button_bind_clicked      (GtkButton       *button,
01946                                         gpointer         user_data)
01947 {
01948     uint32  keysym;
01949     uint8   flags;
01950     const char *command;
01951 
01952     keybinding_get_data(&keysym, &flags, &command);
01953 
01954     /* insert_key will do a strdup of command for us */
01955     insert_key(keysym, flags, command);
01956 
01957     /*
01958      * I think it is more appropriate to clear the fields once the user adds
01959      * it.  I suppose the ideal case would be to select the newly inserted
01960      * keybinding.
01961      */
01962     reset_keybinding_status();
01963     update_keybinding_list();
01964     save_keys();
01965 }
01966 
01976 void
01977 on_keybinding_button_update_clicked    (GtkButton       *button,
01978                                         gpointer         user_data)
01979 {
01980     GtkTreeIter iter;
01981     Key_Entry   *entry;
01982     GtkTreeModel    *model;
01983     const char *buf;
01984 
01985     if (gtk_tree_selection_get_selected(keybinding_selection, &model, &iter)) {
01986         gtk_tree_model_get(model, &iter, KLIST_KEY_ENTRY, &entry, -1);
01987 
01988         if (!entry) {
01989             LOG(LOG_ERROR, "keys.c:on_keybinding_button_update_clicked",
01990                 "Unable to get key_entry structure\n");
01991             return;
01992         }
01993         free(entry->command);
01994         keybinding_get_data(&entry->keysym, &entry->flags, &buf);
01995         entry->command = strdup_local(buf);
01996         update_keybinding_list();
01997         save_keys();
01998     } else {
01999         LOG(LOG_ERROR, "keys.c:on_keybinding_button_update_clicked",
02000             "Nothing selected to update\n");
02001     }
02002 }
02003 
02010 void
02011 on_keybinding_button_close_clicked     (GtkButton       *button,
02012                                         gpointer         user_data)
02013 {
02014     gtk_widget_hide(keybinding_window);
02015 }
02016 
02029 gboolean keybinding_selection_func (
02030                       GtkTreeSelection *selection,
02031                       GtkTreeModel     *model,
02032                       GtkTreePath      *path,
02033                       gboolean          path_currently_selected,
02034                       gpointer          userdata)
02035 {
02036     GtkTreeIter iter;
02037     Key_Entry   *entry;
02038 
02039     gtk_widget_set_sensitive(keybinding_button_remove, TRUE);
02040     gtk_widget_set_sensitive(keybinding_button_update, TRUE);
02041 
02042     if (gtk_tree_model_get_iter(model, &iter, path)) {
02043 
02044         gtk_tree_model_get(model, &iter, KLIST_KEY_ENTRY, &entry, -1);
02045 
02046         if (!entry) {
02047             LOG(LOG_ERROR, "keys.c:keybinding_selection_func",
02048                 "Unable to get key_entry structure\n");
02049             return FALSE;
02050         }
02051         if (entry->flags & KEYF_RUN)
02052             gtk_toggle_button_set_active(
02053                 GTK_TOGGLE_BUTTON(keybinding_checkbutton_control), TRUE);
02054         else
02055             gtk_toggle_button_set_active(
02056                 GTK_TOGGLE_BUTTON(keybinding_checkbutton_control), FALSE);
02057 
02058         if (entry->flags & KEYF_FIRE)
02059             gtk_toggle_button_set_active(
02060                 GTK_TOGGLE_BUTTON(keybinding_checkbutton_shift), TRUE);
02061         else
02062             gtk_toggle_button_set_active(
02063                 GTK_TOGGLE_BUTTON(keybinding_checkbutton_shift), FALSE);
02064 
02065         if (entry->flags & KEYF_ALT)
02066             gtk_toggle_button_set_active(
02067                 GTK_TOGGLE_BUTTON(keybinding_checkbutton_alt), TRUE);
02068         else
02069             gtk_toggle_button_set_active(
02070                 GTK_TOGGLE_BUTTON(keybinding_checkbutton_alt), FALSE);
02071 
02072         if (entry->flags & KEYF_META)
02073             gtk_toggle_button_set_active(
02074                 GTK_TOGGLE_BUTTON(keybinding_checkbutton_meta), TRUE);
02075         else
02076             gtk_toggle_button_set_active(
02077                 GTK_TOGGLE_BUTTON(keybinding_checkbutton_meta), FALSE);
02078 
02079         if (entry->flags & KEYF_EDIT)
02080             gtk_toggle_button_set_active(
02081                 GTK_TOGGLE_BUTTON(keybinding_checkbutton_edit), TRUE);
02082         else
02083             gtk_toggle_button_set_active(
02084                 GTK_TOGGLE_BUTTON(keybinding_checkbutton_edit), FALSE);
02085 
02086         gtk_entry_set_text(
02087             GTK_ENTRY(keybinding_entry_key), gdk_keyval_name(entry->keysym));
02088         gtk_entry_set_text(
02089             GTK_ENTRY(keybinding_entry_command), entry->command);
02090     }
02091     return TRUE;
02092 }
02093 
02099 void reset_keybinding_status(void)
02100 {
02101     gtk_toggle_button_set_active(
02102         GTK_TOGGLE_BUTTON(keybinding_checkbutton_control), FALSE);
02103     gtk_toggle_button_set_active(
02104         GTK_TOGGLE_BUTTON(keybinding_checkbutton_shift), FALSE);
02105     gtk_toggle_button_set_active(
02106         GTK_TOGGLE_BUTTON(keybinding_checkbutton_alt), FALSE);
02107     gtk_toggle_button_set_active(
02108         GTK_TOGGLE_BUTTON(keybinding_checkbutton_meta), FALSE);
02109     gtk_toggle_button_set_active(
02110         GTK_TOGGLE_BUTTON(keybinding_checkbutton_edit), FALSE);
02111     gtk_entry_set_text (GTK_ENTRY(keybinding_entry_key), "");
02112     gtk_entry_set_text (GTK_ENTRY(keybinding_entry_command), "");
02113     gtk_widget_set_sensitive(keybinding_button_remove, FALSE);
02114     gtk_widget_set_sensitive(keybinding_button_update, FALSE);
02115 }
02116 
02125 void
02126 on_keybinding_button_clear_clicked     (GtkButton       *button,
02127                                         gpointer         user_data)
02128 {
02129     GtkTreeModel    *model;
02130     GtkTreeIter iter;
02131 
02132     /*
02133      * As the cleared state is not supposed to have a keybinding selected,
02134      * deselect the currently selected keybinding if there is one.
02135      */
02136     if (gtk_tree_selection_get_selected(keybinding_selection, &model, &iter)) {
02137         gtk_tree_selection_unselect_iter (keybinding_selection, &iter);
02138     }
02139     reset_keybinding_status();          /* Clear inputs and reset buttons. */
02140 }
02141