4 Copyright (C) 1995, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
5 2007, 2009, 2011, 2012, 2013
6 The Free Software Foundation, Inc.
10 Andrew Borodin <aborodin@vmail.ru>, 2012, 2013
12 This file is part of the Midnight Commander.
14 The Midnight Commander is free software: you can redistribute it
15 and/or modify it under the terms of the GNU General Public License as
16 published by the Free Software Foundation, either version 3 of the License,
17 or (at your option) any later version.
19 The Midnight Commander is distributed in the hope that it will be useful,
20 but WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 GNU General Public License for more details.
24 You should have received a copy of the GNU General Public License
25 along with this program. If not, see <http://www.gnu.org/licenses/>.
29 * \brief Source: learn keys module
36 #include "lib/global.h"
38 #include "lib/tty/tty.h"
39 #include "lib/tty/key.h"
40 #include "lib/mcconfig.h"
41 #include "lib/strescape.h"
42 #include "lib/strutil.h"
43 #include "lib/util.h" /* convert_controls() */
44 #include "lib/widget.h"
49 /*** global variables ****************************************************************************/
51 /*** file scope macro definitions ****************************************************************/
59 /*** file scope type declarations ****************************************************************/
69 /*** file scope variables ************************************************************************/
71 static WDialog
*learn_dlg
;
72 static const char *learn_title
= N_("Learn keys");
74 static learnkey_t
*learnkeys
= NULL
;
75 static int learn_total
;
77 static gboolean learnchanged
= FALSE
;
79 /*** file scope functions ************************************************************************/
80 /* --------------------------------------------------------------------------------------------- */
83 learn_button (WButton
* button
, int action
)
90 d
= create_message (D_ERROR
, _("Teach me a key"),
91 _("Please press the %s\n"
92 "and then wait until this message disappears.\n\n"
93 "Then, press it again to see if OK appears\n"
94 "next to its button.\n\n"
95 "If you want to escape, press a single Escape key\n"
96 "and wait as well."), _(key_name_conv_tab
[action
- B_USER
].longname
));
98 if (learnkeys
[action
- B_USER
].sequence
!= NULL
)
100 g_free (learnkeys
[action
- B_USER
].sequence
);
101 learnkeys
[action
- B_USER
].sequence
= NULL
;
107 /* Esc hides the dialog and do not allow definitions of
110 gboolean seq_ok
= FALSE
;
112 if (*seq
!= '\0' && strcmp (seq
, "\\e") != 0 && strcmp (seq
, "\\e\\e") != 0
113 && strcmp (seq
, "^m") != 0 && strcmp (seq
, "^i") != 0
114 && (seq
[1] != '\0' || *seq
< ' ' || *seq
> '~'))
117 learnkeys
[action
- B_USER
].sequence
= seq
;
118 seq
= convert_controls (seq
);
119 seq_ok
= define_sequence (key_name_conv_tab
[action
- B_USER
].code
, seq
, MCKEY_NOACTION
);
123 message (D_NORMAL
, _("Cannot accept this key"), _("You have entered \"%s\""), seq
);
131 dlg_select_widget (learnkeys
[action
- B_USER
].button
);
133 return 0; /* Do not kill learn_dlg */
136 /* --------------------------------------------------------------------------------------------- */
139 learn_move (gboolean right
)
143 totalcols
= (learn_total
- 1) / ROWS
+ 1;
144 for (i
= 0; i
< learn_total
; i
++)
145 if (learnkeys
[i
].button
== WIDGET (learn_dlg
->current
->data
))
149 if (i
< learn_total
- ROWS
)
158 else if (i
+ (totalcols
- 1) * ROWS
>= learn_total
)
159 i
+= (totalcols
- 2) * ROWS
;
161 i
+= (totalcols
- 1) * ROWS
;
163 dlg_select_widget (learnkeys
[i
].button
);
170 /* --------------------------------------------------------------------------------------------- */
173 learn_check_key (int c
)
177 for (i
= 0; i
< learn_total
; i
++)
179 if (key_name_conv_tab
[i
].code
!= c
|| learnkeys
[i
].ok
)
182 dlg_select_widget (learnkeys
[i
].button
);
183 /* TRANSLATORS: This label appears near learned keys. Keep it short. */
184 label_set_text (LABEL (learnkeys
[i
].label
), _("OK"));
185 learnkeys
[i
].ok
= TRUE
;
187 if (learnok
>= learn_total
)
189 learn_dlg
->ret_value
= B_CANCEL
;
192 if (query_dialog (learn_title
,
194 ("It seems that all your keys already\n"
195 "work fine. That's great."), D_ERROR
, 2,
196 _("&Save"), _("&Discard")) == 0)
197 learn_dlg
->ret_value
= B_ENTER
;
201 message (D_ERROR
, learn_title
,
203 ("Great! You have a complete terminal database!\n"
204 "All your keys work well."));
206 dlg_stop (learn_dlg
);
215 return learn_move (FALSE
);
218 return learn_move (TRUE
);
220 dlg_one_down (learn_dlg
);
223 dlg_one_up (learn_dlg
);
227 /* Prevent from disappearing if a non-defined sequence is pressed
228 and contains a button hotkey. Only recognize hotkeys with ALT. */
229 return (c
< 255 && g_ascii_isalnum (c
));
232 /* --------------------------------------------------------------------------------------------- */
235 learn_callback (Widget
* w
, Widget
* sender
, widget_msg_t msg
, int parm
, void *data
)
240 return learn_check_key (parm
) ? MSG_HANDLED
: MSG_NOT_HANDLED
;
243 return dlg_default_callback (w
, sender
, msg
, parm
, data
);
247 /* --------------------------------------------------------------------------------------------- */
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
, dialog_colors
, learn_callback
, NULL
,
280 "[Learn keys]", learn_title
, DLG_CENTER
);
282 /* find first unshown button */
283 for (key
= key_name_conv_tab
, learn_total
= 0;
284 key
->name
!= NULL
&& strcmp (key
->name
, "kpleft") != 0; key
++, learn_total
++)
288 learnchanged
= FALSE
;
290 learnkeys
= g_new (learnkey_t
, learn_total
);
295 /* add buttons and "OK" labels */
296 for (i
= 0; i
< learn_total
; i
++)
298 char buffer
[BUF_TINY
];
302 learnkeys
[i
].ok
= FALSE
;
303 learnkeys
[i
].sequence
= NULL
;
305 label
= _(key_name_conv_tab
[i
].longname
);
306 padding
= 16 - str_term_width1 (label
);
307 padding
= max (0, padding
);
308 g_snprintf (buffer
, sizeof (buffer
), "%s%*s", label
, padding
, "");
310 learnkeys
[i
].button
=
311 WIDGET (button_new (y
, x
, B_USER
+ i
, NARROW_BUTTON
, buffer
, learn_button
));
312 learnkeys
[i
].label
= WIDGET (label_new (y
, x
+ 19, ""));
313 add_widget (learn_dlg
, learnkeys
[i
].button
);
314 add_widget (learn_dlg
, learnkeys
[i
].label
);
324 add_widget (learn_dlg
, hline_new (dlg_height
- 8, -1, -1));
325 add_widget (learn_dlg
,
326 label_new (dlg_height
- 7, 5,
327 _("Press all the keys mentioned here. After you have done it, check\n"
328 "which keys are not marked with OK. Press space on the missing\n"
329 "key, or click with the mouse to define it. Move around with Tab.")));
330 add_widget (learn_dlg
, hline_new (dlg_height
- 4, -1, -1));
332 bl0
= str_term_width1 (b0
) + 5; /* default button */
333 bl1
= str_term_width1 (b1
) + 3; /* normal button */
334 bx0
= (dlg_width
- (bl0
+ bl1
+ 1)) / 2;
336 add_widget (learn_dlg
, button_new (dlg_height
- 3, bx0
, B_ENTER
, DEFPUSH_BUTTON
, b0
, NULL
));
337 add_widget (learn_dlg
, button_new (dlg_height
- 3, bx1
, B_CANCEL
, NORMAL_BUTTON
, b1
, NULL
));
340 /* --------------------------------------------------------------------------------------------- */
345 dlg_destroy (learn_dlg
);
349 /* --------------------------------------------------------------------------------------------- */
356 gboolean profile_changed
= FALSE
;
358 section
= g_strconcat ("terminal:", getenv ("TERM"), (char *) NULL
);
360 for (i
= 0; i
< learn_total
; i
++)
361 if (learnkeys
[i
].sequence
!= NULL
)
365 esc_str
= strutils_escape (learnkeys
[i
].sequence
, -1, ";\\", TRUE
);
366 mc_config_set_string_raw_value (mc_main_config
, section
, key_name_conv_tab
[i
].name
,
370 profile_changed
= TRUE
;
373 /* On the one hand no good idea to save the complete setup but
374 * without 'Auto save setup' the new key-definitions will not be
375 * saved unless the user does an 'Options/Save Setup'.
376 * On the other hand a save-button that does not save anything to
377 * disk is much worse.
380 mc_config_save_file (mc_main_config
, NULL
);
385 /* --------------------------------------------------------------------------------------------- */
386 /*** public functions ****************************************************************************/
387 /* --------------------------------------------------------------------------------------------- */
392 int save_old_esc_mode
= old_esc_mode
;
393 gboolean save_alternate_plus_minus
= mc_global
.tty
.alternate_plus_minus
;
396 /* old_esc_mode cannot work in learn keys dialog */
399 /* don't translate KP_ADD, KP_SUBTRACT and
400 KP_MULTIPLY to '+', '-' and '*' in
402 mc_global
.tty
.alternate_plus_minus
= TRUE
;
403 application_keypad_mode ();
406 result
= dlg_run (learn_dlg
);
408 old_esc_mode
= save_old_esc_mode
;
409 mc_global
.tty
.alternate_plus_minus
= save_alternate_plus_minus
;
411 if (!mc_global
.tty
.alternate_plus_minus
)
412 numeric_keypad_mode ();
414 if (result
== B_ENTER
)
420 /* --------------------------------------------------------------------------------------------- */