2005-09-15 09:58:31 -04:00
|
|
|
/* Hotkeys handling. */
|
|
|
|
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
#include "config.h"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
#include "elinks.h"
|
|
|
|
|
|
|
|
#include "bfu/hotkey.h"
|
|
|
|
#include "bfu/menu.h"
|
|
|
|
#include "config/kbdbind.h"
|
|
|
|
#include "intl/gettext/libintl.h"
|
|
|
|
#include "terminal/draw.h"
|
|
|
|
#include "terminal/terminal.h"
|
|
|
|
#include "terminal/window.h"
|
|
|
|
#include "util/conv.h"
|
|
|
|
#include "util/memory.h"
|
|
|
|
|
|
|
|
|
|
|
|
/* Return position (starting at 1) of the first tilde in text,
|
|
|
|
* or 0 if not found. */
|
|
|
|
static inline int
|
|
|
|
find_hotkey_pos(unsigned char *text)
|
|
|
|
{
|
|
|
|
if (text && *text) {
|
|
|
|
unsigned char *p = strchr(text, '~');
|
|
|
|
|
|
|
|
if (p) return (int) (p - text) + 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
init_hotkeys(struct terminal *term, struct menu *menu)
|
|
|
|
{
|
|
|
|
struct menu_item *mi;
|
|
|
|
|
|
|
|
#ifdef CONFIG_DEBUG
|
|
|
|
/* hotkey debugging */
|
|
|
|
if (menu->hotkeys) {
|
|
|
|
struct menu_item *used_hotkeys[255];
|
|
|
|
|
|
|
|
memset(used_hotkeys, 0, sizeof(used_hotkeys));
|
|
|
|
|
|
|
|
foreach_menu_item(mi, menu->items) {
|
|
|
|
unsigned char *text = mi->text;
|
|
|
|
|
|
|
|
if (!mi_has_left_text(mi)) continue;
|
|
|
|
if (mi_text_translate(mi)) text = _(text, term);
|
|
|
|
if (!*text) continue;
|
|
|
|
|
|
|
|
if (mi->hotkey_state != HKS_CACHED && !mi->hotkey_pos)
|
|
|
|
mi->hotkey_pos = find_hotkey_pos(text);
|
|
|
|
|
|
|
|
/* Negative value for hotkey_pos means the key is already
|
|
|
|
* used by another entry. We mark it to be able to highlight
|
|
|
|
* this hotkey in menus. --Zas */
|
|
|
|
if (mi->hotkey_pos) {
|
|
|
|
struct menu_item **used = &used_hotkeys[toupper(text[mi->hotkey_pos])];
|
|
|
|
|
|
|
|
if (*used) {
|
|
|
|
mi->hotkey_pos = -mi->hotkey_pos;
|
|
|
|
if ((*used)->hotkey_pos > 0)
|
|
|
|
(*used)->hotkey_pos = -(*used)->hotkey_pos;
|
|
|
|
}
|
|
|
|
|
|
|
|
*used = mi;
|
|
|
|
mi->hotkey_state = HKS_CACHED;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
foreach_menu_item(mi, menu->items) {
|
|
|
|
if (!menu->hotkeys) {
|
|
|
|
mi->hotkey_pos = 0;
|
|
|
|
mi->hotkey_state = HKS_IGNORE;
|
|
|
|
} else if (mi->hotkey_state != HKS_CACHED
|
|
|
|
&& !mi->hotkey_pos) {
|
|
|
|
unsigned char *text = mi->text;
|
|
|
|
|
|
|
|
if (!mi_has_left_text(mi)) continue;
|
|
|
|
if (mi_text_translate(mi)) text = _(text, term);
|
|
|
|
if (!*text) continue;
|
|
|
|
|
|
|
|
mi->hotkey_pos = find_hotkey_pos(text);
|
|
|
|
|
|
|
|
if (mi->hotkey_pos)
|
|
|
|
mi->hotkey_state = HKS_CACHED;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef CONFIG_NLS
|
|
|
|
void
|
|
|
|
clear_hotkeys_cache(struct menu *menu)
|
|
|
|
{
|
|
|
|
struct menu_item *item;
|
|
|
|
|
|
|
|
foreach_menu_item(item, menu->items) {
|
|
|
|
item->hotkey_state = menu->hotkeys ? HKS_SHOW : HKS_IGNORE;
|
|
|
|
item->hotkey_pos = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
void
|
|
|
|
refresh_hotkeys(struct terminal *term, struct menu *menu)
|
|
|
|
{
|
|
|
|
#ifdef CONFIG_NLS
|
|
|
|
if (current_language != menu->lang) {
|
|
|
|
clear_hotkeys_cache(menu);
|
|
|
|
init_hotkeys(term, menu);
|
|
|
|
menu->lang = current_language;
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
init_hotkeys(term, menu);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2006-08-13 16:45:41 -04:00
|
|
|
check_hotkeys_common(struct menu *menu, term_event_char_T hotkey, struct terminal *term,
|
2006-01-06 15:34:57 -05:00
|
|
|
int check_mode)
|
2005-09-15 09:58:31 -04:00
|
|
|
{
|
2006-09-17 09:12:47 -04:00
|
|
|
#ifdef CONFIG_UTF8
|
2006-08-13 16:45:41 -04:00
|
|
|
unicode_val_T key = unicode_fold_label_case(hotkey);
|
2008-12-28 10:42:29 -05:00
|
|
|
int codepage = get_terminal_codepage(term);
|
2006-08-13 16:45:41 -04:00
|
|
|
#else
|
2005-09-15 09:58:31 -04:00
|
|
|
unsigned char key = toupper(hotkey);
|
2006-08-13 16:45:41 -04:00
|
|
|
#endif
|
2005-09-15 09:58:31 -04:00
|
|
|
int i = menu->selected;
|
|
|
|
int start;
|
|
|
|
|
|
|
|
if (menu->size < 1) return 0;
|
|
|
|
|
|
|
|
i %= menu->size;
|
|
|
|
if (i < 0) i += menu->size;
|
|
|
|
|
|
|
|
start = i;
|
|
|
|
do {
|
2006-01-06 15:34:57 -05:00
|
|
|
struct menu_item *item;
|
|
|
|
unsigned char *text;
|
2006-09-17 09:12:47 -04:00
|
|
|
#ifdef CONFIG_UTF8
|
2006-08-13 16:45:41 -04:00
|
|
|
unicode_val_T items_hotkey;
|
|
|
|
#endif
|
2006-01-06 15:37:36 -05:00
|
|
|
int found;
|
2006-01-06 15:34:57 -05:00
|
|
|
|
2005-09-15 09:58:31 -04:00
|
|
|
if (++i == menu->size) i = 0;
|
|
|
|
|
2006-01-06 15:34:57 -05:00
|
|
|
item = &menu->items[i];
|
|
|
|
|
|
|
|
if (!mi_has_left_text(item)) continue;
|
|
|
|
|
|
|
|
text = item->text;
|
|
|
|
if (mi_text_translate(item)) text = _(text, term);
|
|
|
|
if (!text || !*text) continue;
|
|
|
|
|
2006-08-13 16:45:41 -04:00
|
|
|
/* Change @text to point to the character that should
|
|
|
|
* be compared to @key. */
|
2006-01-06 15:34:57 -05:00
|
|
|
if (check_mode == 0) {
|
|
|
|
/* Does the key (upcased) matches one of the
|
|
|
|
* hotkeys in menu ? */
|
|
|
|
int key_pos = item->hotkey_pos;
|
|
|
|
|
|
|
|
#ifdef CONFIG_DEBUG
|
|
|
|
if (key_pos < 0) key_pos = -key_pos;
|
|
|
|
#endif
|
2006-08-13 16:45:41 -04:00
|
|
|
if (!key_pos) continue;
|
|
|
|
text += key_pos;
|
2006-01-06 15:34:57 -05:00
|
|
|
} else {
|
|
|
|
/* Does the key (upcased) matches first letter
|
|
|
|
* of menu item left text ? */
|
|
|
|
}
|
|
|
|
|
2006-08-13 16:45:41 -04:00
|
|
|
/* Compare @key to the character to which @text points. */
|
2006-09-17 09:12:47 -04:00
|
|
|
#ifdef CONFIG_UTF8
|
2006-08-13 16:45:41 -04:00
|
|
|
items_hotkey = cp_to_unicode(codepage, &text,
|
|
|
|
strchr(text, '\0'));
|
2006-09-17 12:54:37 -04:00
|
|
|
/* items_hotkey can be UCS_NO_CHAR only if the text of
|
|
|
|
* the menu item is not in the expected codepage. */
|
|
|
|
assert(items_hotkey != UCS_NO_CHAR);
|
|
|
|
if_assert_failed continue;
|
2006-08-13 16:45:41 -04:00
|
|
|
found = (unicode_fold_label_case(items_hotkey) == key);
|
|
|
|
#else
|
|
|
|
found = (toupper(*text) == key);
|
2006-09-28 18:07:54 -04:00
|
|
|
#endif
|
2006-08-13 16:45:41 -04:00
|
|
|
|
2006-01-06 15:37:36 -05:00
|
|
|
if (found) {
|
2005-09-15 09:58:31 -04:00
|
|
|
menu->selected = i;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
} while (i != start);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Returns true if a hotkey was found in the menu, and set menu->selected. */
|
|
|
|
int
|
2006-08-13 16:45:41 -04:00
|
|
|
check_hotkeys(struct menu *menu, term_event_char_T key, struct terminal *term)
|
2005-09-15 09:58:31 -04:00
|
|
|
{
|
2006-01-06 15:34:57 -05:00
|
|
|
return check_hotkeys_common(menu, key, term, 0);
|
2005-09-15 09:58:31 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Search if first letter of an entry in menu matches the key (caseless comp.).
|
|
|
|
* It searchs in all entries, from selected entry to bottom and then from top
|
|
|
|
* to selected entry.
|
|
|
|
* It returns 1 if found and set menu->selected. */
|
|
|
|
int
|
2006-08-13 16:45:41 -04:00
|
|
|
check_not_so_hot_keys(struct menu *menu, term_event_char_T key, struct terminal *term)
|
2005-09-15 09:58:31 -04:00
|
|
|
{
|
2006-01-06 15:34:57 -05:00
|
|
|
return check_hotkeys_common(menu, key, term, 1);
|
2005-09-15 09:58:31 -04:00
|
|
|
}
|