Crossfire Client, Branch
R11627
|
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