22 #include <gdk/gdkkeysyms.h>
28 #include <gdk/gdkwin32.h>
87 #define MAX_HISTORY 50
88 #define MAX_COMMAND_LEN 256
140 #define KEYF_MOD_SHIFT (1 << 0)
141 #define KEYF_MOD_CTRL (1 << 1)
142 #define KEYF_MOD_ALT (1 << 2)
143 #define KEYF_MOD_META (1 << 3)
144 #define KEYF_MOD_MASK (KEYF_MOD_SHIFT | \
149 #define KEYF_ANY (1 << 4)
150 #define KEYF_EDIT (1 << 5)
153 #define KEYF_R_GLOBAL (1 << 6)
154 #define KEYF_R_CHAR (1 << 7)
156 extern const char *const directions[9];
175 #define EKEYBIND_NOMEM 1
231 struct keybind **next_ptr, *kb;
245 "Overwriting previous binding for key %s with command %s ",
256 next_ptr = &(*next_ptr)->
next;
258 *next_ptr = calloc(1,
sizeof(**next_ptr));
259 if (*next_ptr == NULL) {
263 (*next_ptr)->keysym =
keysym;
264 (*next_ptr)->flags =
flags;
265 (*next_ptr)->command = g_strdup(
command);
272 for (i = 0; i < 9; i++) {
278 (*next_ptr)->direction = dir;
292 if (*next_ptr == entry) {
293 *next_ptr = entry->
next;
296 next_ptr = &(*next_ptr)->
next;
304 free((*entry)->command);
305 (*entry)->command = NULL;
319 guint32
keysym, low_keysym;
328 if (buf[0] ==
'\0' || buf[0] ==
'#' || buf[0] ==
'\n') {
331 cpnext = strchr(buf,
' ');
332 if (cpnext == NULL) {
334 "Line %d (%s) corrupted in keybinding file.", line, buf);
340 while (*cpnext ==
' ') {
343 cp = strchr(cpnext,
' ');
346 "Line %d (%s) corrupted in keybinding file.", line, buf);
350 cp1 = strchr(cp,
' ');
353 "Line %d (%s) corrupted in keybinding file.", line, buf);
357 keysym = gdk_keyval_from_name(cp);
361 "Could not convert %s into keysym", cp);
364 if (!strcmp(cpnext,
"commandkey")) {
368 if (!strcmp(cpnext,
"altkey0")) {
372 if (!strcmp(cpnext,
"altkey1")) {
376 if (!strcmp(cpnext,
"firekey0")) {
380 if (!strcmp(cpnext,
"firekey1")) {
384 if (!strcmp(cpnext,
"metakey0")) {
388 if (!strcmp(cpnext,
"metakey1")) {
392 if (!strcmp(cpnext,
"runkey0")) {
396 if (!strcmp(cpnext,
"runkey1")) {
400 if (!strcmp(cpnext,
"completekey")) {
404 if (!strcmp(cpnext,
"nextkey")) {
408 if (!strcmp(cpnext,
"prevkey")) {
414 keysym = gdk_keyval_from_name(buf);
417 "Unable to convert line %d (%s) into keysym", line, buf);
421 cpnext = strchr(cp,
' ');
422 if (cpnext == NULL) {
424 "Line %d (%s) corrupted in keybinding file.", line, cp);
430 cpnext = strchr(cp,
' ');
431 if (cpnext == NULL) {
433 "Line %d (%s) corrupted in keybinding file.", line, cp);
439 low_keysym = gdk_keyval_to_lower(
keysym);
440 if (low_keysym !=
keysym) {
445 while (*cp !=
'\0') {
470 "Deprecated flag (S) ignored at line %d in key binding file", line);
474 "Unknown flag (%c) line %d in key binding file",
480 if (strlen(cpnext) > (
sizeof(
bind_buf) - 1)) {
481 cpnext[
sizeof(
bind_buf) - 1] =
'\0';
483 "Command too long! Truncated.");
489 cpnext[strcspn(cpnext,
"\r")] = 0;
505 GDataInputStream *stream = g_data_input_stream_new(
in);
508 while ((line = g_data_input_stream_read_line(stream, NULL, NULL, NULL)) != NULL) {
520 LOG(
LOG_DEBUG,
"init_default_keybindings",
"Loading default keybindings");
521 GInputStream *
in = g_resources_open_stream(
"/org/crossfire/client/common/def-keys", 0, NULL);
523 g_error(
"could not load default keybindings");
565 for (i = 0; i <
KEYHASH; i++) {
583 if (character_name) {
584 cpl.
name = g_strdup(character_name);
602 snprintf(buf,
sizeof(buf),
"%s/keys",
config_dir);
603 GFile *f = g_file_new_for_path(buf);
604 GFileInputStream * fs = g_file_read(f, NULL, NULL);
606 GInputStream *
in = G_INPUT_STREAM(fs);
608 LOG(
LOG_DEBUG,
"keybindings_init",
"Loading global keybindings");
618 snprintf(buf,
sizeof(buf),
"%s/%s.%s.keys",
config_dir,
620 GFile *f = g_file_new_for_path(buf);
621 GFileInputStream * fs = g_file_read(f, NULL, NULL);
623 GInputStream *
in = G_INPUT_STREAM(fs);
635 LOG(
LOG_DEBUG,
"keybindings_init",
"No character name");
640 cpl.
count = gtk_spin_button_get_value_as_int(spinbutton);
651 GtkTreeViewColumn *column;
652 GtkCellRenderer *renderer;
661 "spinbutton_count"));
668 "keybinding_window"));
671 GTK_WIDGET(gtk_builder_get_object(
dialog_xml,
"kb_scope_togglebutton_global"));
674 "kb_scope_togglebutton_character"));
676 GTK_WIDGET(gtk_builder_get_object(
dialog_xml,
"keybinding_checkbutton_any"));
679 "keybinding_checkbutton_control"));
681 GTK_WIDGET(gtk_builder_get_object(
dialog_xml,
"keybinding_checkbutton_shift"));
683 GTK_WIDGET(gtk_builder_get_object(
dialog_xml,
"keybinding_checkbutton_alt"));
685 GTK_WIDGET(gtk_builder_get_object(
dialog_xml,
"keybinding_checkbutton_meta"));
688 "keybinding_checkbutton_stayinedit"));
690 GTK_WIDGET(gtk_builder_get_object(
dialog_xml,
"keybinding_entry_key"));
692 GTK_WIDGET(gtk_builder_get_object(
dialog_xml,
"keybinding_entry_command"));
694 GTK_WIDGET(gtk_builder_get_object(
dialog_xml,
"keybinding_treeview"));
696 GTK_WIDGET(gtk_builder_get_object(
dialog_xml,
"keybinding_button_remove"));
698 GTK_WIDGET(gtk_builder_get_object(
dialog_xml,
"keybinding_button_update"));
700 GTK_WIDGET(gtk_builder_get_object(
dialog_xml,
"keybinding_button_bind"));
703 G_CALLBACK(gtk_widget_hide_on_delete), NULL);
721 widget = GTK_WIDGET(gtk_builder_get_object(
dialog_xml,
722 "keybinding_button_clear"));
723 g_signal_connect((gpointer) widget,
"clicked",
726 widget = GTK_WIDGET(gtk_builder_get_object(
dialog_xml,
727 "keybinding_button_close"));
728 g_signal_connect((gpointer) widget,
"clicked",
735 G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING,
741 renderer = gtk_cell_renderer_text_new();
742 column = gtk_tree_view_column_new_with_attributes(
"Key", renderer,
745 gtk_tree_view_column_set_sort_column_id(column,
KLIST_KEY);
748 renderer = gtk_cell_renderer_text_new();
749 column = gtk_tree_view_column_new_with_attributes(
"Modifiers", renderer,
752 gtk_tree_view_column_set_sort_column_id(column,
KLIST_MODS);
755 renderer = gtk_cell_renderer_text_new();
756 column = gtk_tree_view_column_new_with_attributes(
"Scope", renderer,
759 gtk_tree_view_column_set_sort_column_id(column,
KLIST_SCOPE);
762 renderer = gtk_cell_renderer_text_new();
763 column = gtk_tree_view_column_new_with_attributes(
"Edit Mode", renderer,
766 gtk_tree_view_column_set_sort_column_id(column,
KLIST_EDIT);
769 renderer = gtk_cell_renderer_text_new();
770 column = gtk_tree_view_column_new_with_attributes(
"Command", renderer,
773 gtk_tree_view_column_set_sort_column_id(column,
KLIST_COMMAND);
787 for (i = 0; i <
KEYHASH; i++) {
815 gtk_label_set_text(GTK_LABEL(
fire_label),
" ");
819 gtk_label_set_text(GTK_LABEL(
run_label),
" ");
843 int present_flags = 0;
866 gtk_label_set_text(GTK_LABEL(
fire_label),
"Fire");
871 gtk_label_set_text(GTK_LABEL(
run_label),
"Run");
889 const bool numkey = key >=
'0' && key <=
'9';
910 snprintf(buf,
sizeof(buf),
"fire %s", kb->
command);
914 snprintf(buf,
sizeof(buf),
"run %s", kb->
command);
934 strcat(tmpbuf,
"fire+");
937 strcat(tmpbuf,
"run+");
940 strcat(tmpbuf,
"alt+");
943 strcat(tmpbuf,
"meta+");
946 snprintf(buf,
sizeof(buf),
947 "Key %s%s is not bound to any command. Use 'bind' to associate this keypress with a command",
948 tmpbuf,
keysym == NoSymbol ?
"unknown" : gdk_keyval_name(
keysym));
1005 if (kb->
keysym == NoSymbol) {
1006 snprintf(buf,
sizeof(buf),
"(null) %i %s %s",
1009 snprintf(buf,
sizeof(buf),
"%s %i %s %s",
1010 gdk_keyval_name(kb->
keysym),
1014 if (kb->
keysym == NoSymbol) {
1015 snprintf(buf,
sizeof(buf),
"key (null) %s %s",
1018 snprintf(buf,
sizeof(buf),
"key %s %s %s",
1019 gdk_keyval_name(kb->
keysym),
1032 int i, j, count = 1;
1036 snprintf(buf,
sizeof(buf),
"Commandkey %s",
1040 snprintf(buf,
sizeof(buf),
"Firekeys 1: %s, 2: %s",
1045 snprintf(buf,
sizeof(buf),
"Altkeys 1: %s, 2: %s",
1050 snprintf(buf,
sizeof(buf),
"Metakeys 1: %s, 2: %s",
1055 snprintf(buf,
sizeof(buf),
"Runkeys 1: %s, 2: %s",
1060 snprintf(buf,
sizeof(buf),
"Command Completion Key %s",
1064 snprintf(buf,
sizeof(buf),
"Next Command in History Key %s",
1068 snprintf(buf,
sizeof(buf),
"Previous Command in History Key %s",
1075 for (i = 0; i <
KEYHASH; i++) {
1076 for (j = 0; j < 2; j++) {
1078 snprintf(buf,
sizeof(buf),
"%3d %s", count,
get_key_info(kb, 0));
1100 "Usage: 'bind -ei {<commandline>,commandkey,firekey{1,2},runkey{1,2},altkey{1,2},metakey{1,2},completekey,nextkey,prevkey}'\n"
1102 " -e means enter edit mode\n"
1103 " -g means this binding should be global (used for all your characters)\n"
1104 " -i means ignore modifier keys (keybinding works no matter if Ctrl/Alt etc are held)");
1109 while (*params ==
' ') {
1113 if (!strcmp(params,
"commandkey")) {
1116 "Push key to bind new commandkey.");
1121 if (!strcmp(params,
"firekey1")) {
1124 "Push key to bind new firekey 1.");
1128 if (!strcmp(params,
"firekey2")) {
1131 "Push key to bind new firekey 2.");
1135 if (!strcmp(params,
"metakey1")) {
1138 "Push key to bind new metakey 1.");
1142 if (!strcmp(params,
"metakey2")) {
1145 "Push key to bind new metakey 2.");
1149 if (!strcmp(params,
"altkey1")) {
1152 "Push key to bind new altkey 1.");
1156 if (!strcmp(params,
"altkey2")) {
1159 "Push key to bind new altkey 2.");
1163 if (!strcmp(params,
"runkey1")) {
1166 "Push key to bind new runkey 1.");
1171 if (!strcmp(params,
"runkey2")) {
1174 "Push key to bind new runkey 2.");
1179 if (!strcmp(params,
"completekey")) {
1182 "Push key to bind new command completion key");
1187 if (!strcmp(params,
"prevkey")) {
1190 "Push key to bind new previous command in history key.");
1195 if (!strcmp(params,
"nextkey")) {
1198 "Push key to bind new next command in history key.");
1205 if (params[0] ==
'-') {
1206 for (params++; *params !=
' '; params++)
1220 "Use unbind to remove bindings.");
1223 snprintf(buf,
sizeof(buf),
1224 "Unsupported or invalid bind flag: '%c'", *params);
1233 "Use unbind to remove bindings.");
1237 if (strlen(params) >=
sizeof(
bind_buf)) {
1238 params[
sizeof(
bind_buf) - 1] =
'\0';
1240 "Keybinding too long! Truncated:");
1243 snprintf(buf,
sizeof(buf),
"Push key to bind '%s'.", params);
1284 snprintf(buf,
sizeof(buf),
"%s/%s.%s.keys",
config_dir,
1287 "Saving character specific keybindings to %s", buf);
1290 LOG(
LOG_WARNING,
"gtk-v2::save_keys",
"Could not create %s", buf);
1293 fp = fopen(buf,
"w");
1295 snprintf(buf2,
sizeof(buf2),
1296 "Could not open %s, character bindings not saved\n", buf);
1299 for (i = 0; i <
KEYHASH; i++) {
1307 snprintf(buf,
sizeof(buf),
"%s/keys",
config_dir);
1309 "Saving global user's keybindings to %s", buf);
1312 LOG(
LOG_WARNING,
"gtk-v2::save_keys",
"Could not create %s", buf);
1314 fp = fopen(buf,
"w");
1316 snprintf(buf2,
sizeof(buf2),
1317 "Could not open %s, global key bindings not saved\n", buf);
1322 fprintf(fp,
"! firekey0 %s %d\n",
1325 fprintf(fp,
"! firekey1 %s %d\n",
1328 fprintf(fp,
"! metakey0 %s %d\n",
1331 fprintf(fp,
"! metakey1 %s %d\n",
1334 fprintf(fp,
"! altkey0 %s %d\n",
1337 fprintf(fp,
"! altkey1 %s %d\n",
1340 fprintf(fp,
"! runkey0 %s %d\n",
1343 fprintf(fp,
"! runkey1 %s %d\n",
1346 fprintf(fp,
"! completekey %s %d\n",
1350 fprintf(fp,
"! nextkey %s %d\n",
1353 fprintf(fp,
"! prevkey %s %d\n",
1356 for (i = 0; i <
KEYHASH; i++) {
1365 "Key bindings saved.");
1432 snprintf(buf,
sizeof(buf),
1433 "Error: Key already used for command \"%s\". Use unbind first.",
1443 snprintf(buf,
sizeof(buf),
"Bound to key '%s' (%i)",
1462 "Usage: 'unbind <entry_number>' or");
1464 "Usage: 'unbind' to show existing bindings");
1472 int count = 0, keyentry, slot, j;
1477 if (params == NULL) {
1483 while (*params ==
' ') {
1487 if (params[0] ==
'\0') {
1492 if ((keyentry = atoi(params)) == 0) {
1497 for (slot = 0; slot <
KEYHASH; slot++) {
1498 for (j = 0; j < 2; j++) {
1503 if (keyentry == count) {
1505 snprintf(buf,
sizeof(buf),
"Removing binding: %3d %s",
1512 "found number entry, but could not find actual key");
1525 "Not found. Try 'unbind' with no options to find entry.");
1532 void focusoutfunc(GtkWidget *widget, GdkEventKey *event, GtkWidget *window) {
1536 gtk_label_set_text(GTK_LABEL(
fire_label),
" ");
1541 gtk_label_set_text(GTK_LABEL(
run_label),
" ");
1558 void keyrelfunc(GtkWidget *widget, GdkEventKey *event, GtkWidget *window) {
1559 if (event->keyval > 0 && !gtk_widget_has_focus(
entry_commands)) {
1563 g_signal_stop_emission_by_name(GTK_WIDGET(window),
"key_release_event");
1573 void keyfunc(GtkWidget *widget, GdkEventKey *event, GtkWidget *window) {
1587 g_signal_stop_emission_by_name(
1588 GTK_WIDGET(window),
"key_press_event");
1592 text = gdk_keyval_name(event->keyval);
1595 g_signal_stop_emission_by_name(
1596 GTK_WIDGET(window),
"key_press_event");
1604 g_signal_stop_emission_by_name(
1605 GTK_WIDGET(window),
"key_press_event");
1613 if (event->keyval > 0) {
1636 if (!(event->state & GDK_CONTROL_MASK)) {
1638 gtk_label_set_text(GTK_LABEL(
run_label),
" ");
1644 if (!(event->state & GDK_SHIFT_MASK)) {
1646 gtk_label_set_text(GTK_LABEL(
fire_label),
" ");
1657 parse_key(event->string[0], event->keyval);
1703 g_signal_stop_emission_by_name(
1704 GTK_WIDGET(window),
"key_press_event");
1777 const gchar *entry_text, *newcommand;
1782 if (newcommand != NULL) {
1798 const gchar *entry_text;
1803 gtk_entry_set_visibility(GTK_ENTRY(entry), TRUE);
1806 entry_text = gtk_entry_get_text(GTK_ENTRY(entry));
1822 if (entry_text[0] != 0) {
1832 gtk_entry_set_text(GTK_ENTRY(entry),
"");
1867 char *modifier_label, *scope_label;
1871 for (i = 0; i <
KEYHASH; i++) {
1872 for (j = 0; j < 2; j++) {
1881 modifier_label =
"Any";
1883 modifier_label =
"None";
1886 modifier_label =
"Alt";
1888 modifier_label =
" + ";
1892 modifier_label =
"Fire";
1894 modifier_label =
" + ";
1898 modifier_label =
"Run";
1900 modifier_label =
" + ";
1904 modifier_label =
"Meta";
1908 scope_label =
"char";
1910 scope_label =
"global";
1954 gpointer user_data) {
1966 if (event->state & GDK_CONTROL_MASK)
1967 gtk_toggle_button_set_active(
1972 gtk_toggle_button_set_active(
1976 if (event->state & GDK_SHIFT_MASK)
1977 gtk_toggle_button_set_active(
1989 gtk_toggle_button_set_active(
1991 gtk_toggle_button_set_active(
2006 int state_u, state_c;
2008 state_u = gtk_toggle_button_get_active(
2010 state_c = gtk_toggle_button_get_active(
2016 if (state_u != scope || state_u == state_c) {
2017 g_signal_handlers_block_by_func(
2020 g_signal_handlers_block_by_func(
2024 gtk_toggle_button_set_active(
2026 gtk_toggle_button_set_active(
2029 g_signal_handlers_unblock_by_func(
2032 g_signal_handlers_unblock_by_func(
2046 GtkWidget *dialog, *label;
2050 dialog = gtk_dialog_new_with_buttons(
2051 "Key already in use",
2058 snprintf(buf,
sizeof(buf),
"Overwrite this binding?\n (%s) %s\n%s",
2060 label = gtk_label_new(buf);
2062 GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))),
2063 label, TRUE, TRUE, 0);
2064 gtk_widget_show_all(dialog);
2066 result = gtk_dialog_run(GTK_DIALOG(dialog));
2067 gtk_widget_destroy(dialog);
2068 return (result == 1);
2081 struct keybind *kb_old, **next_ptr;
2114 "\nCould not remove keybind. Operation failed.\n");
2127 while ((*next_ptr)->next) {
2128 next_ptr = &(*next_ptr)->
next;
2130 (*next_ptr)->
next = kb;
2138 snprintf(buf,
sizeof(buf),
"%s", kb->
command);
2157 gpointer user_data) {
2158 GtkTreeModel *model;
2164 scope = !gtk_toggle_button_get_active(
2179 gpointer user_data) {
2180 GtkTreeModel *model;
2186 scope = gtk_toggle_button_get_active(
2201 gpointer user_data) {
2202 GtkTreeModel *model;
2208 LOG(
LOG_ERROR,
"keys.c::on_keybinding_button_remove_clicked",
2209 "Function called with nothing selected\n");
2215 LOG(
LOG_ERROR,
"keys.c::on_keybinding_button_remove_clicked",
2216 "Unable to find matching key entry\n");
2238 if (gtk_toggle_button_get_active(
2243 if (gtk_toggle_button_get_active(
2248 if (gtk_toggle_button_get_active(
2252 if (gtk_toggle_button_get_active(
2256 if (gtk_toggle_button_get_active(
2260 if (gtk_toggle_button_get_active(
2264 if (gtk_toggle_button_get_active(
2270 if (strlen(ed) >=
sizeof(
bind_buf)) {
2272 "Keybinding too long! Truncated.");
2285 *
keysym = gdk_keyval_from_name(
2287 if (*
keysym == GDK_KEY_VoidSymbol) {
2289 "Cannot get valid keysym from selection");
2334 gpointer user_data) {
2337 GtkTreeModel *model;
2347 LOG(
LOG_ERROR,
"keys.c::on_keybinding_button_update_clicked",
2348 "Unable to get key_entry structure\n");
2371 LOG(
LOG_ERROR,
"keys.c::on_keybinding_button_update_clicked",
2372 "Nothing selected to update\n");
2393 gpointer user_data) {
2396 enabled = !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cb));
2417 GtkTreeSelection *selection,
2418 GtkTreeModel *model,
2420 gboolean path_currently_selected,
2421 gpointer userdata) {
2428 if (gtk_tree_model_get_iter(model, &iter, path)) {
2434 "Unable to get key_entry structure\n");
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(
2473 gtk_toggle_button_set_active(
2476 gtk_toggle_button_set_active(
2495 gtk_toggle_button_set_active(
2497 gtk_toggle_button_set_active(
2499 gtk_toggle_button_set_active(
2501 gtk_toggle_button_set_active(
2503 gtk_toggle_button_set_active(
2505 gtk_toggle_button_set_active(
2525 GtkTreeModel *model;