📄 fkeys.c
字号:
/* X-Chat * Copyright (C) 1998 Peter Zelezny. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */#include <stdio.h>#include <stdlib.h>#include <sys/types.h>#include <sys/stat.h>#include <unistd.h>#include <string.h>#include "../../config.h"#ifdef HAVE_STRINGS_H#include <strings.h>#endif#include <fcntl.h>#include <ctype.h>#include "fe-gtk.h"#include "../common/xchat.h"#include "../common/xchatc.h"#include "../common/cfgfiles.h"#include "../common/userlist.h"#include "../common/outbound.h"#include "../common/util.h"#include "../common/text.h"#include <gdk/gdkkeysyms.h>#include "gtkutil.h"#include "menu.h"#include "xtext.h"#include "wins.h"#include "palette.h"#include "maingui.h"#include "textgui.h"#include "fkeys.h"static int tab_nick_comp (GtkWidget * t, int shift);static void nick_comp_chng (GtkWidget * t, int updown);static void replace_handle (GtkWidget * wid);/***************** Key Binding Code ******************//* NOTES: To add a new action: 1) inc KEY_MAX_ACTIONS 2) write the function at the bottom of this file (with all the others) FIXME: Write about calling and returning 3) Add it to key_actions --AGL *//* Remember that the *number* of actions is this *plus* 1 --AGL */#define KEY_MAX_ACTIONS 12/* These are cp'ed from history.c --AGL */#define STATE_SHIFT GDK_SHIFT_MASK#define STATE_ALT GDK_MOD1_MASK#define STATE_CTRL GDK_CONTROL_MASKstruct key_binding{ int keyval; /* GDK keynumber */ char *keyname; /* String with the name of the function */ int action; /* Index into key_actions */ int mod; /* Flags of STATE_* above */ char *data1, *data2; /* Pointers to strings, these must be freed */ struct key_binding *next;};struct key_action{ int (*handler) (GtkWidget * wid, GdkEventKey * evt, char *d1, char *d2, struct session * sess); char *name; char *help;};static int key_load_kbs (char *);static void key_load_defaults ();static void key_save_kbs (char *);static int key_action_handle_command (GtkWidget * wid, GdkEventKey * evt, char *d1, char *d2, struct session *sess);static int key_action_page_switch (GtkWidget * wid, GdkEventKey * evt, char *d1, char *d2, struct session *sess);int key_action_insert (GtkWidget * wid, GdkEventKey * evt, char *d1, char *d2, struct session *sess);static int key_action_scroll_page (GtkWidget * wid, GdkEventKey * evt, char *d1, char *d2, struct session *sess);static int key_action_set_buffer (GtkWidget * wid, GdkEventKey * evt, char *d1, char *d2, struct session *sess);static int key_action_history_up (GtkWidget * wid, GdkEventKey * evt, char *d1, char *d2, struct session *sess);static int key_action_history_down (GtkWidget * wid, GdkEventKey * evt, char *d1, char *d2, struct session *sess);static int key_action_tab_comp (GtkWidget * wid, GdkEventKey * evt, char *d1, char *d2, struct session *sess);static int key_action_comp_chng (GtkWidget * wid, GdkEventKey * evt, char *d1, char *d2, struct session *sess);static int key_action_replace (GtkWidget * wid, GdkEventKey * evt, char *d1, char *d2, struct session *sess);static int key_action_move_tab_left (GtkWidget * wid, GdkEventKey * evt, char *d1, char *d2, struct session *sess);static int key_action_move_tab_right (GtkWidget * wid, GdkEventKey * evt, char *d1, char *d2, struct session *sess);static int key_action_put_history (GtkWidget * wid, GdkEventKey * evt, char *d1, char *d2, struct session *sess);static GtkWidget *key_dialog;static struct key_binding *keys_root = NULL;static struct key_action key_actions[KEY_MAX_ACTIONS + 1] = { {key_action_handle_command, "Run Command", N_("The \002Run Command\002 action runs the data in Data 1 as if it has been typed into the entry box where you pressed the key sequence. Thus it can contain text (which will be sent to the channel/person), commands or user commands. When run all \002\\n\002 characters in Data 1 are used to deliminate seperate commands so it is possible to run more than one command. If you want a \002\\\002 in the actual text run then enter \002\\\\\002")}, {key_action_page_switch, "Change Page", N_("The \002Change Page\002 command switches between pages in the notebook. Set Data 1 to the page you want to switch to. If Data 2 is set to anything then the switch will be relative to the current position")}, {key_action_insert, "Insert in Buffer", N_("The \002Insert in Buffer\002 command will insert the contents of Data 1 into the entry where the key sequence was pressed at the current cursor position")}, {key_action_scroll_page, "Scroll Page", N_("The \002Scroll Page\002 command scrolls the text widget up or down one page. If Data 1 is set to anything the page scrolls up, else it scrolls down")}, {key_action_set_buffer, "Set Buffer", N_("The \002Set Buffer\002 command sets the entry where the key sequence was entered to the contents of Data 1")}, {key_action_history_up, "Last Command", N_("The \002Last Command\002 command sets the entry to contain the last command entered - the same as pressing up in a shell")}, {key_action_history_down, "Next Command", N_("The \002Next Command\002 command sets the entry to contain the next command entered - the same as pressing down in a shell")}, {key_action_tab_comp, "Complete nick/command", N_("This command changes the text in the entry to finish an incomplete nickname or command. If Data 1 is set then double-tabbing in a string will select the last nick, not the next")}, {key_action_comp_chng, "Change Selected Nick", N_("This command scrolls up and down through the list of nicks. If Data 1 is set to anything it will scroll up, else it scrolls down")}, {key_action_replace, "Check For Replace", N_("This command checks the last work entered in the entry against the replace list and replaces it if it finds a match")}, {key_action_move_tab_left, "Move front tab left", N_("This command move the front tab left by one")}, {key_action_move_tab_right, "Move front tab right", N_("This command move the front tab right by one")}, {key_action_put_history, "Push input line into history", N_("Push input line into history but doesn't send to server")},};voidkey_init (){ keys_root = NULL; if (key_load_kbs (NULL) == 1) { key_load_defaults (); if (key_load_kbs (NULL) == 1) gtkutil_simpledialog (_("There was an error loading key bindings configuration")); }}static char *key_get_key_name (int keyval){ return gdk_keyval_name (gdk_keyval_to_lower (keyval));}/* Ok, here are the NOTES key_handle_key_press now handles all the key presses and history_keypress is now defunct. It goes thru the linked list keys_root and finds a matching key. It runs the action func and switches on these values: 0) Return 1) Find next 2) stop signal and return * history_keypress is now dead (and gone) * key_handle_key_press now takes its role * All the possible actions are in a struct called key_actions (in fkeys.c) * it is made of {function, name, desc} * key bindings can pass 2 *text* strings to the handler. If more options are nee ded a format can be put on one of these options * key actions are passed { the entry widget the Gdk event data 1 data 2 session struct } * key bindings are stored in a linked list of key_binding structs * which looks like { int keyval; GDK keynumber char *keyname; String with the name of the function int action; Index into key_actions int mod; Flags of STATE_* above char *data1, *data2; Pointers to strings, these must be freed struct key_binding *next; } * remember that is (data1 || data2) != NULL then they need to be free()'ed --AGL */intkey_handle_key_press (GtkWidget * wid, GdkEventKey * evt, struct session *sess){ struct key_binding *kb, *last = NULL; int keyval = evt->keyval; int mod, n; mod = evt->state & (STATE_CTRL | STATE_ALT | STATE_SHIFT); kb = keys_root; while (kb) { if (kb->keyval == keyval && kb->mod == mod) { if (kb->action < 0 || kb->action > KEY_MAX_ACTIONS) return 0; /* Bump this binding to the top of the list */ if (last != NULL) { last->next = kb->next; kb->next = keys_root; keys_root = kb; } /* Run the function */ n = key_actions[kb->action].handler (wid, evt, kb->data1, kb->data2, sess); switch (n) { case 0: return 1; case 2: gtk_signal_emit_stop_by_name (GTK_OBJECT (wid), "key_press_event"); return 1; } } last = kb; kb = kb->next; } /* check if it's a return or enter */ if ((evt->keyval == GDK_Return) || (evt->keyval == GDK_KP_Enter /*&& mod == 0*/)) handle_inputgad (wid, sess); if (evt->keyval == GDK_KP_Enter) gtk_signal_emit_stop_by_name (GTK_OBJECT (wid), "key_press_event"); return 1;}/* Walks keys_root and free()'s everything *//*static voidkey_free_all (){ struct key_binding *cur, *next; cur = keys_root; while (cur) { next = cur->next; if (cur->data1) free (cur->data1); if (cur->data2) free (cur->data2); free (cur); cur = next; } keys_root = NULL;}*//* Turns mod flags into a C-A-S string */static char *key_make_mod_str (int mod, char *buf){ int i = 0; if (mod & STATE_CTRL) { if (i) buf[i++] = '-'; buf[i++] = 'C'; } if (mod & STATE_ALT) { if (i) buf[i++] = '-'; buf[i++] = 'A'; } if (mod & STATE_SHIFT) { if (i) buf[i++] = '-'; buf[i++] = 'S'; } buf[i] = 0; return buf;}/* ***** GUI code here ******************* *//* NOTE: The key_dialog defin is above --AGL */static GtkWidget *key_dialog_act_menu, *key_dialog_kb_clist;static GtkWidget *key_dialog_tog_c, *key_dialog_tog_s, *key_dialog_tog_a;static GtkWidget *key_dialog_ent_key, *key_dialog_ent_d1, *key_dialog_ent_d2;static GtkWidget *key_dialog_text;static voidkey_load_defaults (){ char def[] = /* This is the default config */ "A\nminus\nChange Page\nD1:-1\nD2:Relative\n\n" "A\n9\nChange Page\nD1:9\nD2!\n\n" "A\n8\nChange Page\nD1:8\nD2!\n\n" "A\n7\nChange Page\nD1:7\nD2!\n\n" "A\n6\nChange Page\nD1:6\nD2!\n\n" "A\n5\nChange Page\nD1:5\nD2!\n\n" "A\n4\nChange Page\nD1:4\nD2!\n\n" "A\n3\nChange Page\nD1:3\nD2!\n\n" "A\n2\nChange Page\nD1:2\nD2!\n\n" "A\n1\nChange Page\nD1:1\nD2!\n\n" "C\no\nInsert in Buffer\nD1:%O\nD2!\n\n" "C\nb\nInsert in Buffer\nD1:%B\nD2!\n\n" "C\nk\nInsert in Buffer\nD1:%C\nD2!\n\n" "S\nNext\nChange Selected Nick\nD1!\nD2!\n\n" "S\nPrior\nChange Selected Nick\nD1:Up\nD2!\n\n" "None\nNext\nScroll Page\nD1!\nD2!\n\n" "None\nPrior\nScroll Page\nD1:Up\nD2!\n\n" "None\nDown\nNext Command\nD1!\nD2!\n\n" "None\nUp\nLast Command\nD1!\nD2!\n\n" "None\nTab\nComplete nick/command\nD1!\nD2!\n\n" "None\nspace\nCheck For Replace\nD1!\nD2!\n\n" "None\nReturn\nCheck For Replace\nD1!\nD2!\n\n" "A\nequal\nChange Page\nD1:1\nD2:Relative\n\n" "C\nTab\nComplete nick/command\nD1:Up\nD2!\n\n" "A\nLeft\nMove front tab left\nD1!\nD2!\n\n" "A\nRight\nMove front tab right\nD1!\nD2!\n\n"; char buf[512]; int fd; snprintf (buf, 512, "%s/keybindings.conf", get_xdir ()); fd = open (buf, O_CREAT | O_TRUNC | O_WRONLY | OFLAGS, 0x180); if (fd < 0) /* ???!!! */ return; write (fd, def, strlen (def)); close (fd);}static voidkey_dialog_close (){ key_dialog = NULL; key_save_kbs (NULL);}static voidkey_dialog_add_new (GtkWidget * button, GtkCList * list){ gchar *strs[] = { "", _("<none>"), _("<none>"), _("<none>"), _("<none>") }; struct key_binding *kb; kb = malloc (sizeof (struct key_binding)); kb->keyval = 0; kb->keyname = NULL; kb->action = -1; kb->mod = 0; kb->data1 = kb->data2 = NULL; kb->next = keys_root; keys_root = kb; gtk_clist_set_row_data (GTK_CLIST (list), gtk_clist_append (GTK_CLIST (list), strs), kb);}static voidkey_dialog_delete (GtkWidget * button, GtkCList * list){ struct key_binding *kb, *cur, *last; int row = gtkutil_clist_selection ((GtkWidget *) list); if (row != -1) { kb = gtk_clist_get_row_data (list, row); cur = keys_root; last = NULL; while (cur) { if (cur == kb) { if (last) last->next = kb->next; else keys_root = kb->next; if (kb->data1) free (kb->data1); if (kb->data2) free (kb->data2); free (kb); gtk_clist_remove (list, row); return; } last = cur; cur = cur->next; } printf (_("*** key_dialog_delete: couldn't find kb in list!\n")); /*if (getenv ("XCHAT_DEBUG")) abort ();*/ }}static voidkey_dialog_sel_act (GtkWidget * un, int num){ int row = gtkutil_clist_selection (key_dialog_kb_clist); struct key_binding *kb; if (row != -1) { kb = gtk_clist_get_row_data (GTK_CLIST (key_dialog_kb_clist), row); kb->action = num; gtk_clist_set_text (GTK_CLIST (key_dialog_kb_clist), row, 2, _(key_actions[num].name)); if (key_actions[num].help) { gtk_xtext_clear (GTK_XTEXT (key_dialog_text)); PrintTextRaw (key_dialog_text, _(key_actions[num].help), 0); } }}static voidkey_dialog_sel_row (GtkWidget * clist, gint row, gint column, GdkEventButton * evt, gpointer data){ struct key_binding *kb = gtk_clist_get_row_data (GTK_CLIST (clist), row); if (kb == NULL) { printf ("*** key_dialog_sel_row: kb == NULL\n"); abort (); } if (kb->action > -1 && kb->action <= KEY_MAX_ACTIONS) { gtk_option_menu_set_history (GTK_OPTION_MENU (key_dialog_act_menu), kb->action); if (key_actions[kb->action].help) { gtk_xtext_clear (GTK_XTEXT (key_dialog_text)); PrintTextRaw (key_dialog_text, _(key_actions[kb->action].help), 0); } } gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (key_dialog_tog_c), (kb->mod & STATE_CTRL) == STATE_CTRL); gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (key_dialog_tog_s), (kb->mod & STATE_SHIFT) == STATE_SHIFT); gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (key_dialog_tog_a), (kb->mod & STATE_ALT) == STATE_ALT); if (kb->data1) gtk_entry_set_text (GTK_ENTRY (key_dialog_ent_d1), kb->data1); else gtk_entry_set_text (GTK_ENTRY (key_dialog_ent_d1), ""); if (kb->data2) gtk_entry_set_text (GTK_ENTRY (key_dialog_ent_d2), kb->data2); else gtk_entry_set_text (GTK_ENTRY (key_dialog_ent_d2), ""); if (kb->keyname) gtk_entry_set_text (GTK_ENTRY (key_dialog_ent_key), kb->keyname); else gtk_entry_set_text (GTK_ENTRY (key_dialog_ent_key), "");}static voidkey_dialog_tog_key (GtkWidget * tog, int kstate){ int state = GTK_TOGGLE_BUTTON (tog)->active; int row = gtkutil_clist_selection (key_dialog_kb_clist); struct key_binding *kb; char buf[32]; if (row == -1) return; kb = gtk_clist_get_row_data (GTK_CLIST (key_dialog_kb_clist), row); if (state) kb->mod |= kstate; else kb->mod &= ~kstate; gtk_clist_set_text (GTK_CLIST (key_dialog_kb_clist), row, 0, key_make_mod_str (kb->mod, buf));}static GtkWidget *key_dialog_make_toggle (char *label, void *callback, void *option, GtkWidget * box){ GtkWidget *wid; wid = gtk_check_button_new_with_label (label); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (wid), 0); gtk_signal_connect (GTK_OBJECT (wid), "toggled", GTK_SIGNAL_FUNC (callback), option); gtk_widget_show (wid); gtk_box_pack_end (GTK_BOX (box), wid, 0, 0, 0); return wid;}static GtkWidget *key_dialog_make_entry (char *label, char *act, void *callback, void *option, GtkWidget * box){ GtkWidget *wid, *hbox;; hbox = gtk_hbox_new (0, 2); if (label) { wid = gtk_label_new (label); gtk_widget_show (wid); gtk_box_pack_start (GTK_BOX (hbox), wid, 0, 0, 0); } wid = gtk_entry_new (); if (act) { gtk_signal_connect (GTK_OBJECT (wid), act, GTK_SIGNAL_FUNC (callback), option); } gtk_box_pack_start (GTK_BOX (hbox), wid, 0, 0, 0); gtk_widget_show (wid); gtk_widget_show (hbox); gtk_box_pack_start (GTK_BOX (box), hbox, 0, 0, 0); return wid;}static voidkey_dialog_set_key (GtkWidget * entry, GdkEventKey * evt, void *none){ int row = gtkutil_clist_selection (key_dialog_kb_clist); struct key_binding *kb; gtk_entry_set_text (GTK_ENTRY (entry), ""); if (row == -1) return; kb = gtk_clist_get_row_data (GTK_CLIST (key_dialog_kb_clist), row); kb->keyval = evt->keyval; kb->keyname = key_get_key_name (kb->keyval); gtk_clist_set_text (GTK_CLIST (key_dialog_kb_clist), row, 1, kb->keyname); gtk_entry_set_text (GTK_ENTRY (entry), kb->keyname); gtk_signal_emit_stop_by_name (GTK_OBJECT (entry), "key_press_event");}static voidkey_dialog_set_data (GtkWidget * entry, int d){ char *text = gtk_entry_get_text (GTK_ENTRY (entry)); int row = gtkutil_clist_selection (key_dialog_kb_clist); struct key_binding *kb; char *buf; int len = strlen (text); len++; if (row == -1) return; kb = gtk_clist_get_row_data (GTK_CLIST (key_dialog_kb_clist), row); if (d == 0) { /* using data1 */ if (kb->data1) free (kb->data1); buf = (char *) malloc (len); memcpy (buf, text, len); kb->data1 = buf; gtk_clist_set_text (GTK_CLIST (key_dialog_kb_clist), row, 3, text); } else { if (kb->data2) free (kb->data2); buf = (char *) malloc (len); memcpy (buf, text, len); kb->data2 = buf; gtk_clist_set_text (GTK_CLIST (key_dialog_kb_clist), row, 4, text); }}voidkey_dialog_show (){ GtkWidget *vbox, *hbox, *list, *vbox2, *wid, *wid2, *wid3, *hbox2; struct key_binding *kb; gchar *titles[] = { _("Mod"), _("Key"), _("Action"), "1", "2" }; char temp[32];
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -