4 Copyright (C) 1995-2016
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
);
127 dlg_select_widget (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 (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 dlg_select_widget (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 dlg_select_widget (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
,
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 dlg_one_down (learn_dlg
);
219 dlg_one_up (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 /* --------------------------------------------------------------------------------------------- */
250 const int dlg_width
= 78;
251 const int dlg_height
= 23;
255 const char *b0
= N_("&Save");
256 const char *b1
= N_("&Cancel");
260 const key_code_name_t
*key
;
263 static gboolean i18n_flag
= FALSE
;
266 learn_title
= _(learn_title
);
272 #endif /* ENABLE_NLS */
277 dlg_create (TRUE
, 0, 0, dlg_height
, dlg_width
, WPOS_CENTER
, FALSE
, dialog_colors
,
278 learn_callback
, NULL
, "[Learn keys]", learn_title
);
280 /* find first unshown button */
281 for (key
= key_name_conv_tab
, learn_total
= 0;
282 key
->name
!= NULL
&& strcmp (key
->name
, "kpleft") != 0; key
++, learn_total
++)
286 learnchanged
= FALSE
;
288 learnkeys
= g_new (learnkey_t
, learn_total
);
293 /* add buttons and "OK" labels */
294 for (i
= 0; i
< learn_total
; i
++)
296 char buffer
[BUF_TINY
];
300 learnkeys
[i
].ok
= FALSE
;
301 learnkeys
[i
].sequence
= NULL
;
303 label
= _(key_name_conv_tab
[i
].longname
);
304 padding
= 16 - str_term_width1 (label
);
305 padding
= MAX (0, padding
);
306 g_snprintf (buffer
, sizeof (buffer
), "%s%*s", label
, padding
, "");
308 learnkeys
[i
].button
=
309 WIDGET (button_new (y
, x
, B_USER
+ i
, NARROW_BUTTON
, buffer
, learn_button
));
310 learnkeys
[i
].label
= WIDGET (label_new (y
, x
+ 19, ""));
311 add_widget (learn_dlg
, learnkeys
[i
].button
);
312 add_widget (learn_dlg
, learnkeys
[i
].label
);
322 add_widget (learn_dlg
, hline_new (dlg_height
- 8, -1, -1));
323 add_widget (learn_dlg
,
324 label_new (dlg_height
- 7, 5,
325 _("Press all the keys mentioned here. After you have done it, check\n"
326 "which keys are not marked with OK. Press space on the missing\n"
327 "key, or click with the mouse to define it. Move around with Tab.")));
328 add_widget (learn_dlg
, hline_new (dlg_height
- 4, -1, -1));
330 bl0
= str_term_width1 (b0
) + 5; /* default button */
331 bl1
= str_term_width1 (b1
) + 3; /* normal button */
332 bx0
= (dlg_width
- (bl0
+ bl1
+ 1)) / 2;
334 add_widget (learn_dlg
, button_new (dlg_height
- 3, bx0
, B_ENTER
, DEFPUSH_BUTTON
, b0
, NULL
));
335 add_widget (learn_dlg
, button_new (dlg_height
- 3, bx1
, B_CANCEL
, NORMAL_BUTTON
, b1
, NULL
));
338 /* --------------------------------------------------------------------------------------------- */
343 dlg_destroy (learn_dlg
);
347 /* --------------------------------------------------------------------------------------------- */
354 gboolean profile_changed
= FALSE
;
356 section
= g_strconcat ("terminal:", getenv ("TERM"), (char *) NULL
);
358 for (i
= 0; i
< learn_total
; i
++)
359 if (learnkeys
[i
].sequence
!= NULL
)
363 esc_str
= strutils_escape (learnkeys
[i
].sequence
, -1, ";\\", TRUE
);
364 mc_config_set_string_raw_value (mc_global
.main_config
, section
,
365 key_name_conv_tab
[i
].name
, esc_str
);
368 profile_changed
= TRUE
;
371 /* On the one hand no good idea to save the complete setup but
372 * without 'Auto save setup' the new key-definitions will not be
373 * saved unless the user does an 'Options/Save Setup'.
374 * On the other hand a save-button that does not save anything to
375 * disk is much worse.
378 mc_config_save_file (mc_global
.main_config
, NULL
);
383 /* --------------------------------------------------------------------------------------------- */
384 /*** public functions ****************************************************************************/
385 /* --------------------------------------------------------------------------------------------- */
390 int save_old_esc_mode
= old_esc_mode
;
391 gboolean save_alternate_plus_minus
= mc_global
.tty
.alternate_plus_minus
;
394 /* old_esc_mode cannot work in learn keys dialog */
397 /* don't translate KP_ADD, KP_SUBTRACT and
398 KP_MULTIPLY to '+', '-' and '*' in
400 mc_global
.tty
.alternate_plus_minus
= TRUE
;
401 application_keypad_mode ();
404 result
= dlg_run (learn_dlg
);
406 old_esc_mode
= save_old_esc_mode
;
407 mc_global
.tty
.alternate_plus_minus
= save_alternate_plus_minus
;
409 if (!mc_global
.tty
.alternate_plus_minus
)
410 numeric_keypad_mode ();
412 if (result
== B_ENTER
)
418 /* --------------------------------------------------------------------------------------------- */