22 #include <gdk/gdkkeysyms.h>
28 #include <gdk/gdkwin32.h>
85 #define MAX_HISTORY 50
86 #define MAX_COMMAND_LEN 256
138 #define KEYF_MOD_SHIFT (1 << 0)
139 #define KEYF_MOD_CTRL (1 << 1)
140 #define KEYF_MOD_ALT (1 << 2)
141 #define KEYF_MOD_META (1 << 3)
142 #define KEYF_MOD_MASK (KEYF_MOD_SHIFT | \
147 #define KEYF_ANY (1 << 4)
148 #define KEYF_EDIT (1 << 5)
151 #define KEYF_R_GLOBAL (1 << 6)
152 #define KEYF_R_CHAR (1 << 7)
154 extern const char *const directions[9];
173 #define EKEYBIND_NOMEM 1
229 struct keybind **next_ptr, *kb;
243 "Overwriting previous binding for key %s with command %s ",
254 next_ptr = &(*next_ptr)->
next;
256 *next_ptr = calloc(1,
sizeof(**next_ptr));
257 if (*next_ptr == NULL) {
261 (*next_ptr)->keysym =
keysym;
262 (*next_ptr)->flags =
flags;
263 (*next_ptr)->command = g_strdup(
command);
270 for (i = 0; i < 9; i++) {
276 (*next_ptr)->direction = dir;
290 if (*next_ptr == entry) {
291 *next_ptr = entry->
next;
294 next_ptr = &(*next_ptr)->
next;
302 free((*entry)->command);
303 (*entry)->command = NULL;
317 guint32
keysym, low_keysym;
326 if (buf[0] ==
'\0' || buf[0] ==
'#' || buf[0] ==
'\n') {
329 cpnext = strchr(buf,
' ');
330 if (cpnext == NULL) {
332 "Line %d (%s) corrupted in keybinding file.", line, buf);
338 while (*cpnext ==
' ') {
341 cp = strchr(cpnext,
' ');
344 "Line %d (%s) corrupted in keybinding file.", line, buf);
348 cp1 = strchr(cp,
' ');
351 "Line %d (%s) corrupted in keybinding file.", line, buf);
355 keysym = gdk_keyval_from_name(cp);
359 "Could not convert %s into keysym", cp);
362 if (!strcmp(cpnext,
"commandkey")) {
366 if (!strcmp(cpnext,
"altkey0")) {
370 if (!strcmp(cpnext,
"altkey1")) {
374 if (!strcmp(cpnext,
"firekey0")) {
378 if (!strcmp(cpnext,
"firekey1")) {
382 if (!strcmp(cpnext,
"metakey0")) {
386 if (!strcmp(cpnext,
"metakey1")) {
390 if (!strcmp(cpnext,
"runkey0")) {
394 if (!strcmp(cpnext,
"runkey1")) {
398 if (!strcmp(cpnext,
"completekey")) {
402 if (!strcmp(cpnext,
"nextkey")) {
406 if (!strcmp(cpnext,
"prevkey")) {
412 keysym = gdk_keyval_from_name(buf);
415 "Unable to convert line %d (%s) into keysym", line, buf);
419 cpnext = strchr(cp,
' ');
420 if (cpnext == NULL) {
422 "Line %d (%s) corrupted in keybinding file.", line, cp);
428 cpnext = strchr(cp,
' ');
429 if (cpnext == NULL) {
431 "Line %d (%s) corrupted in keybinding file.", line, cp);
437 low_keysym = gdk_keyval_to_lower(
keysym);
438 if (low_keysym !=
keysym) {
443 while (*cp !=
'\0') {
468 "Deprecated flag (S) ignored at line %d in key binding file", line);
472 "Unknown flag (%c) line %d in key binding file",
478 if (strlen(cpnext) > (
sizeof(
bind_buf) - 1)) {
479 cpnext[
sizeof(
bind_buf) - 1] =
'\0';
481 "Command too long! Truncated.");
487 cpnext[strcspn(cpnext,
"\r")] = 0;
503 GDataInputStream *stream = g_data_input_stream_new(
in);
506 while ((line = g_data_input_stream_read_line(stream, NULL, NULL, NULL)) != NULL) {
518 LOG(
LOG_DEBUG,
"init_default_keybindings",
"Loading default keybindings");
519 GInputStream *
in = g_resources_open_stream(
"/org/crossfire/client/common/def-keys", 0, NULL);
521 g_error(
"could not load default keybindings");
563 for (i = 0; i <
KEYHASH; i++) {
581 if (character_name) {
582 cpl.
name = g_strdup(character_name);
600 snprintf(buf,
sizeof(buf),
"%s/keys",
config_dir);
601 GFile *f = g_file_new_for_path(buf);
602 GFileInputStream * fs = g_file_read(f, NULL, NULL);
604 GInputStream *
in = G_INPUT_STREAM(fs);
606 LOG(
LOG_DEBUG,
"keybindings_init",
"Loading global keybindings");
616 snprintf(buf,
sizeof(buf),
"%s/%s.%s.keys",
config_dir,
618 GFile *f = g_file_new_for_path(buf);
619 GFileInputStream * fs = g_file_read(f, NULL, NULL);
621 GInputStream *
in = G_INPUT_STREAM(fs);
633 LOG(
LOG_DEBUG,
"keybindings_init",
"No character name");
638 cpl.
count = gtk_spin_button_get_value_as_int(spinbutton);
649 GtkTreeViewColumn *column;
650 GtkCellRenderer *renderer;
659 "spinbutton_count"));
666 "keybinding_window"));
669 GTK_WIDGET(gtk_builder_get_object(
dialog_xml,
"kb_scope_togglebutton_global"));
672 "kb_scope_togglebutton_character"));
674 GTK_WIDGET(gtk_builder_get_object(
dialog_xml,
"keybinding_checkbutton_any"));
677 "keybinding_checkbutton_control"));
679 GTK_WIDGET(gtk_builder_get_object(
dialog_xml,
"keybinding_checkbutton_shift"));
681 GTK_WIDGET(gtk_builder_get_object(
dialog_xml,
"keybinding_checkbutton_alt"));
683 GTK_WIDGET(gtk_builder_get_object(
dialog_xml,
"keybinding_checkbutton_meta"));
686 "keybinding_checkbutton_stayinedit"));
688 GTK_WIDGET(gtk_builder_get_object(
dialog_xml,
"keybinding_entry_key"));
690 GTK_WIDGET(gtk_builder_get_object(
dialog_xml,
"keybinding_entry_command"));
692 GTK_WIDGET(gtk_builder_get_object(
dialog_xml,
"keybinding_treeview"));
694 GTK_WIDGET(gtk_builder_get_object(
dialog_xml,
"keybinding_button_remove"));
696 GTK_WIDGET(gtk_builder_get_object(
dialog_xml,
"keybinding_button_update"));
698 GTK_WIDGET(gtk_builder_get_object(
dialog_xml,
"keybinding_button_bind"));
701 G_CALLBACK(gtk_widget_hide_on_delete), NULL);
719 widget = GTK_WIDGET(gtk_builder_get_object(
dialog_xml,
720 "keybinding_button_clear"));
721 g_signal_connect((gpointer) widget,
"clicked",
724 widget = GTK_WIDGET(gtk_builder_get_object(
dialog_xml,
725 "keybinding_button_close"));
726 g_signal_connect((gpointer) widget,
"clicked",
733 G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING,
739 renderer = gtk_cell_renderer_text_new();
740 column = gtk_tree_view_column_new_with_attributes(
"Key", renderer,
743 gtk_tree_view_column_set_sort_column_id(column,
KLIST_KEY);
746 renderer = gtk_cell_renderer_text_new();
747 column = gtk_tree_view_column_new_with_attributes(
"Modifiers", renderer,
750 gtk_tree_view_column_set_sort_column_id(column,
KLIST_MODS);
753 renderer = gtk_cell_renderer_text_new();
754 column = gtk_tree_view_column_new_with_attributes(
"Scope", renderer,
757 gtk_tree_view_column_set_sort_column_id(column,
KLIST_SCOPE);
760 renderer = gtk_cell_renderer_text_new();
761 column = gtk_tree_view_column_new_with_attributes(
"Edit Mode", renderer,
764 gtk_tree_view_column_set_sort_column_id(column,
KLIST_EDIT);
767 renderer = gtk_cell_renderer_text_new();
768 column = gtk_tree_view_column_new_with_attributes(
"Command", renderer,
771 gtk_tree_view_column_set_sort_column_id(column,
KLIST_COMMAND);
785 for (i = 0; i <
KEYHASH; i++) {
813 gtk_label_set_text(GTK_LABEL(
fire_label),
" ");
817 gtk_label_set_text(GTK_LABEL(
run_label),
" ");
841 int present_flags = 0;
864 gtk_label_set_text(GTK_LABEL(
fire_label),
"Fire");
869 gtk_label_set_text(GTK_LABEL(
run_label),
"Run");
904 snprintf(buf,
sizeof(buf),
"fire %s", kb->
command);
907 snprintf(buf,
sizeof(buf),
"run %s", kb->
command);
918 if (key >=
'0' && key <=
'9') {
928 strcat(tmpbuf,
"fire+");
931 strcat(tmpbuf,
"run+");
934 strcat(tmpbuf,
"alt+");
937 strcat(tmpbuf,
"meta+");
940 snprintf(buf,
sizeof(buf),
941 "Key %s%s is not bound to any command. Use 'bind' to associate this keypress with a command",
942 tmpbuf,
keysym == NoSymbol ?
"unknown" : gdk_keyval_name(
keysym));
999 if (kb->
keysym == NoSymbol) {
1000 snprintf(buf,
sizeof(buf),
"(null) %i %s %s",
1003 snprintf(buf,
sizeof(buf),
"%s %i %s %s",
1004 gdk_keyval_name(kb->
keysym),
1008 if (kb->
keysym == NoSymbol) {
1009 snprintf(buf,
sizeof(buf),
"key (null) %s %s",
1012 snprintf(buf,
sizeof(buf),
"key %s %s %s",
1013 gdk_keyval_name(kb->
keysym),
1026 int i, j, count = 1;
1030 snprintf(buf,
sizeof(buf),
"Commandkey %s",
1034 snprintf(buf,
sizeof(buf),
"Firekeys 1: %s, 2: %s",
1039 snprintf(buf,
sizeof(buf),
"Altkeys 1: %s, 2: %s",
1044 snprintf(buf,
sizeof(buf),
"Metakeys 1: %s, 2: %s",
1049 snprintf(buf,
sizeof(buf),
"Runkeys 1: %s, 2: %s",
1054 snprintf(buf,
sizeof(buf),
"Command Completion Key %s",
1058 snprintf(buf,
sizeof(buf),
"Next Command in History Key %s",
1062 snprintf(buf,
sizeof(buf),
"Previous Command in History Key %s",
1069 for (i = 0; i <
KEYHASH; i++) {
1070 for (j = 0; j < 2; j++) {
1072 snprintf(buf,
sizeof(buf),
"%3d %s", count,
get_key_info(kb, 0));
1094 "Usage: 'bind -ei {<commandline>,commandkey,firekey{1,2},runkey{1,2},altkey{1,2},metakey{1,2},completekey,nextkey,prevkey}'\n"
1096 " -e means enter edit mode\n"
1097 " -g means this binding should be global (used for all your characters)\n"
1098 " -i means ignore modifier keys (keybinding works no matter if Ctrl/Alt etc are held)");
1103 while (*params ==
' ') {
1107 if (!strcmp(params,
"commandkey")) {
1110 "Push key to bind new commandkey.");
1115 if (!strcmp(params,
"firekey1")) {
1118 "Push key to bind new firekey 1.");
1122 if (!strcmp(params,
"firekey2")) {
1125 "Push key to bind new firekey 2.");
1129 if (!strcmp(params,
"metakey1")) {
1132 "Push key to bind new metakey 1.");
1136 if (!strcmp(params,
"metakey2")) {
1139 "Push key to bind new metakey 2.");
1143 if (!strcmp(params,
"altkey1")) {
1146 "Push key to bind new altkey 1.");
1150 if (!strcmp(params,
"altkey2")) {
1153 "Push key to bind new altkey 2.");
1157 if (!strcmp(params,
"runkey1")) {
1160 "Push key to bind new runkey 1.");
1165 if (!strcmp(params,
"runkey2")) {
1168 "Push key to bind new runkey 2.");
1173 if (!strcmp(params,
"completekey")) {
1176 "Push key to bind new command completion key");
1181 if (!strcmp(params,
"prevkey")) {
1184 "Push key to bind new previous command in history key.");
1189 if (!strcmp(params,
"nextkey")) {
1192 "Push key to bind new next command in history key.");
1199 if (params[0] ==
'-') {
1200 for (params++; *params !=
' '; params++)
1214 "Use unbind to remove bindings.");
1217 snprintf(buf,
sizeof(buf),
1218 "Unsupported or invalid bind flag: '%c'", *params);
1227 "Use unbind to remove bindings.");
1231 if (strlen(params) >=
sizeof(
bind_buf)) {
1232 params[
sizeof(
bind_buf) - 1] =
'\0';
1234 "Keybinding too long! Truncated:");
1237 snprintf(buf,
sizeof(buf),
"Push key to bind '%s'.", params);
1278 snprintf(buf,
sizeof(buf),
"%s/%s.%s.keys",
config_dir,
1281 "Saving character specific keybindings to %s", buf);
1284 LOG(
LOG_WARNING,
"gtk-v2::save_keys",
"Could not create %s", buf);
1287 fp = fopen(buf,
"w");
1289 snprintf(buf2,
sizeof(buf2),
1290 "Could not open %s, character bindings not saved\n", buf);
1293 for (i = 0; i <
KEYHASH; i++) {
1301 snprintf(buf,
sizeof(buf),
"%s/keys",
config_dir);
1303 "Saving global user's keybindings to %s", buf);
1306 LOG(
LOG_WARNING,
"gtk-v2::save_keys",
"Could not create %s", buf);
1308 fp = fopen(buf,
"w");
1310 snprintf(buf2,
sizeof(buf2),
1311 "Could not open %s, global key bindings not saved\n", buf);
1316 fprintf(fp,
"! firekey0 %s %d\n",
1319 fprintf(fp,
"! firekey1 %s %d\n",
1322 fprintf(fp,
"! metakey0 %s %d\n",
1325 fprintf(fp,
"! metakey1 %s %d\n",
1328 fprintf(fp,
"! altkey0 %s %d\n",
1331 fprintf(fp,
"! altkey1 %s %d\n",
1334 fprintf(fp,
"! runkey0 %s %d\n",
1337 fprintf(fp,
"! runkey1 %s %d\n",
1340 fprintf(fp,
"! completekey %s %d\n",
1344 fprintf(fp,
"! nextkey %s %d\n",
1347 fprintf(fp,
"! prevkey %s %d\n",
1350 for (i = 0; i <
KEYHASH; i++) {
1359 "Key bindings saved.");
1426 snprintf(buf,
sizeof(buf),
1427 "Error: Key already used for command \"%s\". Use unbind first.",
1437 snprintf(buf,
sizeof(buf),
"Bound to key '%s' (%i)",
1456 "Usage: 'unbind <entry_number>' or");
1458 "Usage: 'unbind' to show existing bindings");
1466 int count = 0, keyentry, slot, j;
1471 if (params == NULL) {
1477 while (*params ==
' ') {
1481 if (params[0] ==
'\0') {
1486 if ((keyentry = atoi(params)) == 0) {
1491 for (slot = 0; slot <
KEYHASH; slot++) {
1492 for (j = 0; j < 2; j++) {
1497 if (keyentry == count) {
1499 snprintf(buf,
sizeof(buf),
"Removing binding: %3d %s",
1506 "found number entry, but could not find actual key");
1519 "Not found. Try 'unbind' with no options to find entry.");
1526 void focusoutfunc(GtkWidget *widget, GdkEventKey *event, GtkWidget *window) {
1530 gtk_label_set_text(GTK_LABEL(
fire_label),
" ");
1535 gtk_label_set_text(GTK_LABEL(
run_label),
" ");
1552 void keyrelfunc(GtkWidget *widget, GdkEventKey *event, GtkWidget *window) {
1553 if (event->keyval > 0 && !gtk_widget_has_focus(
entry_commands)) {
1557 g_signal_stop_emission_by_name(GTK_WIDGET(window),
"key_release_event");
1567 void keyfunc(GtkWidget *widget, GdkEventKey *event, GtkWidget *window) {
1581 g_signal_stop_emission_by_name(
1582 GTK_WIDGET(window),
"key_press_event");
1586 text = gdk_keyval_name(event->keyval);
1589 g_signal_stop_emission_by_name(
1590 GTK_WIDGET(window),
"key_press_event");
1598 g_signal_stop_emission_by_name(
1599 GTK_WIDGET(window),
"key_press_event");
1607 if (event->keyval > 0) {
1630 if (!(event->state & GDK_CONTROL_MASK)) {
1632 gtk_label_set_text(GTK_LABEL(
run_label),
" ");
1638 if (!(event->state & GDK_SHIFT_MASK)) {
1640 gtk_label_set_text(GTK_LABEL(
fire_label),
" ");
1651 parse_key(event->string[0], event->keyval);
1697 g_signal_stop_emission_by_name(
1698 GTK_WIDGET(window),
"key_press_event");
1771 const gchar *entry_text, *newcommand;
1776 if (newcommand != NULL) {
1792 const gchar *entry_text;
1797 gtk_entry_set_visibility(GTK_ENTRY(entry), TRUE);
1800 entry_text = gtk_entry_get_text(GTK_ENTRY(entry));
1816 if (entry_text[0] != 0) {
1825 gtk_entry_set_text(GTK_ENTRY(entry),
"");
1860 char *modifier_label, *scope_label;
1864 for (i = 0; i <
KEYHASH; i++) {
1865 for (j = 0; j < 2; j++) {
1874 modifier_label =
"Any";
1876 modifier_label =
"None";
1879 modifier_label =
"Alt";
1881 modifier_label =
" + ";
1885 modifier_label =
"Fire";
1887 modifier_label =
" + ";
1891 modifier_label =
"Run";
1893 modifier_label =
" + ";
1897 modifier_label =
"Meta";
1901 scope_label =
"char";
1903 scope_label =
"global";
1947 gpointer user_data) {
1959 if (event->state & GDK_CONTROL_MASK)
1960 gtk_toggle_button_set_active(
1965 gtk_toggle_button_set_active(
1969 if (event->state & GDK_SHIFT_MASK)
1970 gtk_toggle_button_set_active(
1982 gtk_toggle_button_set_active(
1984 gtk_toggle_button_set_active(
1999 int state_u, state_c;
2001 state_u = gtk_toggle_button_get_active(
2003 state_c = gtk_toggle_button_get_active(
2009 if (state_u != scope || state_u == state_c) {
2010 g_signal_handlers_block_by_func(
2013 g_signal_handlers_block_by_func(
2017 gtk_toggle_button_set_active(
2019 gtk_toggle_button_set_active(
2022 g_signal_handlers_unblock_by_func(
2025 g_signal_handlers_unblock_by_func(
2039 GtkWidget *dialog, *label;
2043 dialog = gtk_dialog_new_with_buttons(
2044 "Key already in use",
2051 snprintf(buf,
sizeof(buf),
"Overwrite this binding?\n (%s) %s\n%s",
2053 label = gtk_label_new(buf);
2055 GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))),
2056 label, TRUE, TRUE, 0);
2057 gtk_widget_show_all(dialog);
2059 result = gtk_dialog_run(GTK_DIALOG(dialog));
2060 gtk_widget_destroy(dialog);
2061 return (result == 1);
2074 struct keybind *kb_old, **next_ptr;
2107 "\nCould not remove keybind. Operation failed.\n");
2120 while ((*next_ptr)->next) {
2121 next_ptr = &(*next_ptr)->
next;
2123 (*next_ptr)->
next = kb;
2131 snprintf(buf,
sizeof(buf),
"%s", kb->
command);
2150 gpointer user_data) {
2151 GtkTreeModel *model;
2157 scope = !gtk_toggle_button_get_active(
2172 gpointer user_data) {
2173 GtkTreeModel *model;
2179 scope = gtk_toggle_button_get_active(
2194 gpointer user_data) {
2195 GtkTreeModel *model;
2201 LOG(
LOG_ERROR,
"keys.c::on_keybinding_button_remove_clicked",
2202 "Function called with nothing selected\n");
2208 LOG(
LOG_ERROR,
"keys.c::on_keybinding_button_remove_clicked",
2209 "Unable to find matching key entry\n");
2231 if (gtk_toggle_button_get_active(
2236 if (gtk_toggle_button_get_active(
2241 if (gtk_toggle_button_get_active(
2245 if (gtk_toggle_button_get_active(
2249 if (gtk_toggle_button_get_active(
2253 if (gtk_toggle_button_get_active(
2257 if (gtk_toggle_button_get_active(
2263 if (strlen(ed) >=
sizeof(
bind_buf)) {
2265 "Keybinding too long! Truncated.");
2278 *
keysym = gdk_keyval_from_name(
2280 if (*
keysym == GDK_KEY_VoidSymbol) {
2282 "Cannot get valid keysym from selection");
2327 gpointer user_data) {
2330 GtkTreeModel *model;
2340 LOG(
LOG_ERROR,
"keys.c::on_keybinding_button_update_clicked",
2341 "Unable to get key_entry structure\n");
2364 LOG(
LOG_ERROR,
"keys.c::on_keybinding_button_update_clicked",
2365 "Nothing selected to update\n");
2386 gpointer user_data) {
2389 enabled = !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cb));
2410 GtkTreeSelection *selection,
2411 GtkTreeModel *model,
2413 gboolean path_currently_selected,
2414 gpointer userdata) {
2421 if (gtk_tree_model_get_iter(model, &iter, path)) {
2427 "Unable to get key_entry structure\n");
2431 gtk_toggle_button_set_active(
2434 gtk_toggle_button_set_active(
2438 gtk_toggle_button_set_active(
2441 gtk_toggle_button_set_active(
2445 gtk_toggle_button_set_active(
2448 gtk_toggle_button_set_active(
2452 gtk_toggle_button_set_active(
2455 gtk_toggle_button_set_active(
2459 gtk_toggle_button_set_active(
2462 gtk_toggle_button_set_active(
2466 gtk_toggle_button_set_active(
2469 gtk_toggle_button_set_active(
2488 gtk_toggle_button_set_active(
2490 gtk_toggle_button_set_active(
2492 gtk_toggle_button_set_active(
2494 gtk_toggle_button_set_active(
2496 gtk_toggle_button_set_active(
2498 gtk_toggle_button_set_active(
2518 GtkTreeModel *model;