menu: allow for Unicode accelerators

This commit is contained in:
Alex Chernika 2026-04-13 23:06:08 +02:00
parent cea22422d5
commit 1c646af144
No known key found for this signature in database
GPG key ID: 6029FAD8ABFB076A
3 changed files with 32 additions and 34 deletions

View file

@ -23,7 +23,7 @@ struct menuitem {
char *text;
char *icon_name;
const char *arrow;
char accelerator;
uint32_t accelerator;
struct menu *parent;
struct menu *submenu;
bool selectable;
@ -78,7 +78,7 @@ void menu_item_select_previous(void);
* Return: a boolean value that represents whether the newly selected item
* needs to be executed.
*/
bool menu_item_select_by_accelerator(char accelerator);
bool menu_item_select_by_accelerator(uint32_t accelerator);
void menu_submenu_enter(void);
void menu_submenu_leave(void);

View file

@ -419,20 +419,6 @@ handle_change_vt_key(struct keyboard *keyboard,
return false;
}
static char
keysym_to_char(uint32_t keysym)
{
if (keysym >= 0x0020 && keysym <= 0x00FF) {
return (char)keysym;
}
if (keysym >= XKB_KEY_KP_0 && keysym <= XKB_KEY_KP_9) {
return (char)('0' + (keysym - XKB_KEY_KP_0));
}
return '\0';
}
static void
handle_menu_keys(struct keysyms *syms)
{
@ -454,15 +440,17 @@ handle_menu_keys(struct keysyms *syms)
break;
case XKB_KEY_Return:
case XKB_KEY_KP_Enter:
menu_call_selected_actions();
if (!menu_call_selected_actions()) {
menu_submenu_enter();
};
break;
case XKB_KEY_Escape:
menu_close_root();
cursor_update_focus();
break;
default: {
char accelerator = keysym_to_char(syms->syms[i]);
if (accelerator == '\0') {
uint32_t accelerator = xkb_keysym_to_utf32(syms->syms[i]);
if (accelerator == 0) {
continue;
}
if (menu_item_select_by_accelerator(accelerator)) {

View file

@ -8,7 +8,9 @@
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <uchar.h>
#include <unistd.h>
#include <wctype.h>
#include <wlr/types/wlr_scene.h>
#include <wlr/types/wlr_xdg_shell.h>
#include <wlr/util/log.h>
@ -131,7 +133,7 @@ validate(void)
}
static struct menuitem *
item_create(struct menu *menu, const char *text, const char *icon_name, bool show_arrow)
item_create(struct menu *menu, char *text, const char *icon_name, bool show_arrow)
{
assert(menu);
assert(text);
@ -145,26 +147,34 @@ item_create(struct menu *menu, const char *text, const char *icon_name, bool sho
menuitem->arrow = show_arrow ? "" : NULL;
const char *it = text;
/* Skip emojis and whitespace */
while (*it != '\0') {
unsigned char c = (unsigned char)*it;
if (isspace(c) || c > 127) {
it++;
} else {
break;
}
}
menuitem->accelerator = tolower(*it);
uint32_t accelerator = 0;
while (*it != '\0') {
if (*it == '_') {
menuitem->accelerator = tolower(*(it + 1));
char32_t codepoint = 0;
mbstate_t state = {0};
size_t bytes = mbrtoc32(&codepoint, it + 1, MB_CUR_MAX, &state);
if (bytes > 0 && bytes <= 4) {
accelerator = (uint32_t)towlower((wint_t)codepoint);
}
break;
}
it++;
}
/* Fallback to the first character of the label */
if (accelerator == 0 && text[0] != '\0') {
char32_t codepoint = 0;
mbstate_t state = {0};
size_t bytes = mbrtoc32(&codepoint, text, MB_CUR_MAX, &state);
if (bytes > 0 && bytes <= 4) {
accelerator = (uint32_t)towlower((wint_t)codepoint);
}
}
menuitem->accelerator = accelerator;
#if HAVE_LIBSFDO
if (rc.menu_show_icons && !string_null_or_empty(icon_name)) {
menuitem->icon_name = xstrdup(icon_name);
@ -1483,7 +1493,7 @@ menu_item_select_previous(void)
}
bool
menu_item_select_by_accelerator(char accelerator)
menu_item_select_by_accelerator(uint32_t accelerator)
{
struct menu *menu = get_selection_leaf();
if (!menu || wl_list_empty(&menu->menuitems)) {