4 Copyright (C) 1995-2021
5 Free Software Foundation, Inc.
9 Andrew Borodin <aborodin@vmail.ru>, 2012, 2013
11 This file is part of the Midnight Commander.
13 The Midnight Commander is free software: you can redistribute it
14 and/or modify it under the terms of the GNU General Public License as
15 published by the Free Software Foundation, either version 3 of the License,
16 or (at your option) any later version.
18 The Midnight Commander is distributed in the hope that it will be useful,
19 but WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 GNU General Public License for more details.
23 You should have received a copy of the GNU General Public License
24 along with this program. If not, see <http://www.gnu.org/licenses/>.
28 * \brief Source: learn keys module
35 #include "lib/global.h"
37 #include "lib/tty/tty.h"
38 #include "lib/tty/key.h"
39 #include "lib/mcconfig.h"
40 #include "lib/strescape.h"
41 #include "lib/strutil.h"
42 #include "lib/util.h" /* convert_controls() */
43 #include "lib/widget.h"
48 /*** global variables ****************************************************************************/
50 /*** file scope macro definitions ****************************************************************/
58 /*** file scope type declarations ****************************************************************/
68 /*** file scope variables ************************************************************************/
70 static WDialog
*learn_dlg
;
71 static const char *learn_title
= N_("Learn keys");
73 static learnkey_t
*learnkeys
= NULL
;
74 static int learn_total
;
76 static gboolean learnchanged
= FALSE
;
78 /*** file scope functions ************************************************************************/
79 /* --------------------------------------------------------------------------------------------- */
82 learn_button (WButton
* button
, int action
)
89 d
= create_message (D_ERROR
, _("Teach me a key"),
90 _("Please press the %s\n"
91 "and then wait until this message disappears.\n\n"
92 "Then, press it again to see if OK appears\n"
93 "next to its button.\n\n"
94 "If you want to escape, press a single Escape key\n"
95 "and wait as well."), _(key_name_conv_tab
[action
- B_USER
].longname
));
97 if (learnkeys
[action
- B_USER
].sequence
!= NULL
)
98 MC_PTR_FREE (learnkeys
[action
- B_USER
].sequence
);
103 /* Esc hides the dialog and do not allow definitions of
106 gboolean seq_ok
= FALSE
;
108 if (*seq
!= '\0' && strcmp (seq
, "\\e") != 0 && strcmp (seq
, "\\e\\e") != 0
109 && strcmp (seq
, "^m") != 0 && strcmp (seq
, "^i") != 0
110 && (seq
[1] != '\0' || *seq
< ' ' || *seq
> '~'))
113 learnkeys
[action
- B_USER
].sequence
= seq
;
114 seq
= convert_controls (seq
);
115 seq_ok
= define_sequence (key_name_conv_tab
[action
- B_USER
].code
, seq
, MCKEY_NOACTION
);
119 message (D_NORMAL
, _("Cannot accept this key"), _("You have entered \"%s\""), seq
);
125 widget_destroy (WIDGET (d
));
127 widget_select (learnkeys
[action
- B_USER
].button
);
129 return 0; /* Do not kill learn_dlg */
132 /* --------------------------------------------------------------------------------------------- */
135 learn_move (gboolean right
)
139 totalcols
= (learn_total
- 1) / ROWS
+ 1;
140 for (i
= 0; i
< learn_total
; i
++)
141 if (learnkeys
[i
].button
== WIDGET (GROUP (learn_dlg
)->current
->data
))
145 if (i
< learn_total
- ROWS
)
154 else if (i
+ (totalcols
- 1) * ROWS
>= learn_total
)
155 i
+= (totalcols
- 2) * ROWS
;
157 i
+= (totalcols
- 1) * ROWS
;
159 widget_select (learnkeys
[i
].button
);
166 /* --------------------------------------------------------------------------------------------- */
169 learn_check_key (int c
)
173 for (i
= 0; i
< learn_total
; i
++)
175 if (key_name_conv_tab
[i
].code
!= c
|| learnkeys
[i
].ok
)
178 widget_select (learnkeys
[i
].button
);
179 /* TRANSLATORS: This label appears near learned keys. Keep it short. */
180 label_set_text (LABEL (learnkeys
[i
].label
), _("OK"));
181 learnkeys
[i
].ok
= TRUE
;
183 if (learnok
>= learn_total
)
185 learn_dlg
->ret_value
= B_CANCEL
;
188 if (query_dialog (learn_title
,
190 ("It seems that all your keys already\n"
191 "work fine. That's great."), D_ERROR
, 2,
192 _("&Save"), _("&Discard")) == 0)
193 learn_dlg
->ret_value
= B_ENTER
;
197 message (D_ERROR
, learn_title
, "%s",
199 ("Great! You have a complete terminal database!\n"
200 "All your keys work well."));
202 dlg_stop (learn_dlg
);
211 return learn_move (FALSE
);
214 return learn_move (TRUE
);
216 group_select_next_widget (GROUP (learn_dlg
));
219 group_select_prev_widget (GROUP (learn_dlg
));
225 /* Prevent from disappearing if a non-defined sequence is pressed
226 and contains a button hotkey. Only recognize hotkeys with ALT. */
227 return (c
< 255 && g_ascii_isalnum (c
));
230 /* --------------------------------------------------------------------------------------------- */
233 learn_callback (Widget
* w
, Widget
* sender
, widget_msg_t msg
, int parm
, void *data
)
238 return learn_check_key (parm
) ? MSG_HANDLED
: MSG_NOT_HANDLED
;
241 return dlg_default_callback (w
, sender
, msg
, parm
, data
);
245 /* --------------------------------------------------------------------------------------------- */
252 const int dlg_width
= 78;
253 const int dlg_height
= 23;
257 const char *b0
= N_("&Save");
258 const char *b1
= N_("&Cancel");
262 const key_code_name_t
*key
;
265 static gboolean i18n_flag
= FALSE
;
268 learn_title
= _(learn_title
);
274 #endif /* ENABLE_NLS */
279 dlg_create (TRUE
, 0, 0, dlg_height
, dlg_width
, WPOS_CENTER
, FALSE
, dialog_colors
,
280 learn_callback
, NULL
, "[Learn keys]", learn_title
);
281 g
= GROUP (learn_dlg
);
283 /* find first unshown button */
284 for (key
= key_name_conv_tab
, learn_total
= 0;
285 key
->name
!= NULL
&& strcmp (key
->name
, "kpleft") != 0; key
++, learn_total
++)
289 learnchanged
= FALSE
;
291 learnkeys
= g_new (learnkey_t
, learn_total
);
296 /* add buttons and "OK" labels */
297 for (i
= 0; i
< learn_total
; i
++)
299 char buffer
[BUF_TINY
];
303 learnkeys
[i
].ok
= FALSE
;
304 learnkeys
[i
].sequence
= NULL
;
306 label
= _(key_name_conv_tab
[i
].longname
);
307 padding
= 16 - str_term_width1 (label
);
308 padding
= MAX (0, padding
);
309 g_snprintf (buffer
, sizeof (buffer
), "%s%*s", label
, padding
, "");
311 learnkeys
[i
].button
=
312 WIDGET (button_new (y
, x
, B_USER
+ i
, NARROW_BUTTON
, buffer
, learn_button
));
313 learnkeys
[i
].label
= WIDGET (label_new (y
, x
+ 19, ""));
314 group_add_widget (g
, learnkeys
[i
].button
);
315 group_add_widget (g
, learnkeys
[i
].label
);
325 group_add_widget (g
, hline_new (dlg_height
- 8, -1, -1));
326 group_add_widget (g
, label_new (dlg_height
- 7, 5,
328 ("Press all the keys mentioned here. After you have done it, check\n"
329 "which keys are not marked with OK. Press space on the missing\n"
330 "key, or click with the mouse to define it. Move around with Tab.")));
331 group_add_widget (g
, hline_new (dlg_height
- 4, -1, -1));
333 bl0
= str_term_width1 (b0
) + 5; /* default button */
334 bl1
= str_term_width1 (b1
) + 3; /* normal button */
335 bx0
= (dlg_width
- (bl0
+ bl1
+ 1)) / 2;
337 group_add_widget (g
, button_new (dlg_height
- 3, bx0
, B_ENTER
, DEFPUSH_BUTTON
, b0
, NULL
));
338 group_add_widget (g
, button_new (dlg_height
- 3, bx1
, B_CANCEL
, NORMAL_BUTTON
, b1
, NULL
));
341 /* --------------------------------------------------------------------------------------------- */
346 widget_destroy (WIDGET (learn_dlg
));
350 /* --------------------------------------------------------------------------------------------- */
357 gboolean profile_changed
= FALSE
;
359 section
= g_strconcat ("terminal:", getenv ("TERM"), (char *) NULL
);
361 for (i
= 0; i
< learn_total
; i
++)
362 if (learnkeys
[i
].sequence
!= NULL
)
366 esc_str
= strutils_escape (learnkeys
[i
].sequence
, -1, ";\\", TRUE
);
367 mc_config_set_string_raw_value (mc_global
.main_config
, section
,
368 key_name_conv_tab
[i
].name
, esc_str
);
371 profile_changed
= TRUE
;
374 /* On the one hand no good idea to save the complete setup but
375 * without 'Auto save setup' the new key-definitions will not be
376 * saved unless the user does an 'Options/Save Setup'.
377 * On the other hand a save-button that does not save anything to
378 * disk is much worse.
381 mc_config_save_file (mc_global
.main_config
, NULL
);
386 /* --------------------------------------------------------------------------------------------- */
387 /*** public functions ****************************************************************************/
388 /* --------------------------------------------------------------------------------------------- */
393 gboolean save_old_esc_mode
= old_esc_mode
;
394 gboolean save_alternate_plus_minus
= mc_global
.tty
.alternate_plus_minus
;
397 /* old_esc_mode cannot work in learn keys dialog */
400 /* don't translate KP_ADD, KP_SUBTRACT and
401 KP_MULTIPLY to '+', '-' and '*' in
403 mc_global
.tty
.alternate_plus_minus
= TRUE
;
404 application_keypad_mode ();
407 result
= dlg_run (learn_dlg
);
409 old_esc_mode
= save_old_esc_mode
;
410 mc_global
.tty
.alternate_plus_minus
= save_alternate_plus_minus
;
412 if (!mc_global
.tty
.alternate_plus_minus
)
413 numeric_keypad_mode ();
415 if (result
== B_ENTER
)
421 /* --------------------------------------------------------------------------------------------- */