@@ -113,10 +113,11 @@ void mb_shell::menu_item_normal_widget::render(ui::nanovg_context ctx) {
113113
114114 // Draw hotkey
115115 if (item.hotkey && !item.hotkey ->empty ()) {
116- ctx.fillColor (nvgRGBAf (c, c, c, *opacity / 255 .f * 0.7 )); // Slightly dimmed
117- ctx.fontSize (font_size * 0.9 ); // Slightly smaller font
116+ auto t = ctx.transaction ();
117+ ctx.fillColor (nvgRGBAf (c, c, c, *opacity / 255 .f * 0.7 ));
118+ ctx.fontSize (font_size * 0.9 );
118119 ctx.textAlign (NVG_ALIGN_RIGHT | NVG_ALIGN_MIDDLE);
119-
120+ ctx. fontFace ( " monospace " );
120121 auto hotkey_x = right_x - hotkey_padding;
121122 ctx.text (round (hotkey_x), round (*y + *height / 2 ), item.hotkey ->c_str (),
122123 nullptr );
@@ -146,8 +147,10 @@ float mb_shell::menu_item_normal_widget::measure_width(
146147
147148 // Hotkey
148149 if (item.hotkey && !item.hotkey ->empty ()) {
150+ auto t = ctx.vg .transaction ();
149151 ctx.vg .fontSize (font_size * 0.9 );
150152 auto hotkey_padding = config::current->context_menu .theme .hotkey_padding ;
153+ ctx.vg .fontFace (" monospace" );
151154 width +=
152155 ctx.vg .measureText (item.hotkey ->c_str ()).first + hotkey_padding * 2 ;
153156 }
@@ -378,18 +381,18 @@ void mb_shell::menu_widget::update(ui::update_context &ctx) {
378381 (!owner_rt->focused_widget .has_value () && rendering_submenus.empty ()));
379382
380383 if (should_handle_keyboard) {
381- auto move_key = [&](this auto &self, bool next) -> void {
384+ auto move_key = [&](this auto &self, bool next, auto &items ) -> void {
382385 auto focused_item = std::ranges::find_if (
383- item_widgets , [](const auto &item) { return item->focused (); });
384- if (focused_item != item_widgets .end ()) {
386+ items , [](const auto &item) { return item->focused (); });
387+ if (focused_item != items .end ()) {
385388 if (next) {
386389 focused_item++;
387- if (focused_item == item_widgets .end ()) {
388- focused_item = item_widgets .begin ();
390+ if (focused_item == items .end ()) {
391+ focused_item = items .begin ();
389392 }
390393 } else {
391- if (focused_item == item_widgets .begin ()) {
392- focused_item = item_widgets .end () - 1 ;
394+ if (focused_item == items .begin ()) {
395+ focused_item = items .end () - 1 ;
393396 } else {
394397 focused_item--;
395398 }
@@ -401,22 +404,22 @@ void mb_shell::menu_widget::update(ui::update_context &ctx) {
401404 (*focused_item)->template downcast <menu_item_normal_widget>()) {
402405 if (wid->item .disabled ||
403406 wid->item .type == mb_shell::menu_item::type::spacer) {
404- self (next);
407+ self (next, items );
405408 return ;
406409 }
407410 } else {
408- self (next);
411+ self (next, items );
409412 }
410413 } else {
411- if (!item_widgets .empty ()) {
412- item_widgets .front ()->set_focus (true );
414+ if (!items .empty ()) {
415+ items .front ()->set_focus (true );
413416 }
414417 }
415418 };
416419 if (ctx.key_pressed (GLFW_KEY_UP)) {
417- move_key (false );
420+ move_key (false , item_widgets );
418421 } else if (ctx.key_pressed (GLFW_KEY_DOWN)) {
419- move_key (true );
422+ move_key (true , item_widgets );
420423 } else if (ctx.key_pressed (GLFW_KEY_LEFT)) {
421424 // close submenu on left key
422425 if (parent_menu) {
@@ -458,6 +461,103 @@ void mb_shell::menu_widget::update(ui::update_context &ctx) {
458461 }
459462 }
460463 }
464+ } else {
465+ auto menus_matching_key =
466+ item_widgets | std::views::filter ([&](const auto &item) {
467+ if (auto wid = item->template downcast <menu_item_normal_widget>()) {
468+ if (!wid->item .hotkey )
469+ return false ;
470+ auto hotkey = *wid->item .hotkey | std::views::split (' +' ) |
471+ std::views::transform ([](const auto &c) {
472+ auto s = std::string (c.begin (), c.end ());
473+ // trim whitespace
474+ s.erase (s.find_last_not_of (" \t\n\r " ) + 1 );
475+ s.erase (0 , s.find_first_not_of (" \t\n\r " ));
476+ return s;
477+ });
478+
479+ static auto translate_map = std::unordered_map<std::string, int >{
480+ {" ctrl" , GLFW_KEY_LEFT_CONTROL},
481+ {" shift" , GLFW_KEY_LEFT_SHIFT},
482+ {" alt" , GLFW_KEY_LEFT_ALT},
483+ {" win" , GLFW_KEY_LEFT_SUPER},
484+ {" a" , GLFW_KEY_A},
485+ {" b" , GLFW_KEY_B},
486+ {" c" , GLFW_KEY_C},
487+ {" d" , GLFW_KEY_D},
488+ {" e" , GLFW_KEY_E},
489+ {" f" , GLFW_KEY_F},
490+ {" g" , GLFW_KEY_G},
491+ {" h" , GLFW_KEY_H},
492+ {" i" , GLFW_KEY_I},
493+ {" j" , GLFW_KEY_J},
494+ {" k" , GLFW_KEY_K},
495+ {" l" , GLFW_KEY_L},
496+ {" m" , GLFW_KEY_M},
497+ {" n" , GLFW_KEY_N},
498+ {" o" , GLFW_KEY_O},
499+ {" p" , GLFW_KEY_P},
500+ {" q" , GLFW_KEY_Q},
501+ {" r" , GLFW_KEY_R},
502+ {" s" , GLFW_KEY_S},
503+ {" t" , GLFW_KEY_T},
504+ {" u" , GLFW_KEY_U},
505+ {" v" , GLFW_KEY_V},
506+ {" w" , GLFW_KEY_W},
507+ {" x" , GLFW_KEY_X},
508+ {" y" , GLFW_KEY_Y},
509+ {" z" , GLFW_KEY_Z},
510+ {" 0" , GLFW_KEY_0},
511+ {" 1" , GLFW_KEY_1},
512+ {" 2" , GLFW_KEY_2},
513+ {" 3" , GLFW_KEY_3},
514+ {" 4" , GLFW_KEY_4},
515+ {" 5" , GLFW_KEY_5},
516+ {" 6" , GLFW_KEY_6},
517+ {" 7" , GLFW_KEY_7},
518+ {" 8" , GLFW_KEY_8},
519+ {" 9" , GLFW_KEY_9},
520+ };
521+
522+ auto key_combination = std::vector<int >();
523+ for (const auto &key : hotkey) {
524+ if (auto it = translate_map.find (
525+ std::string (key) | std::views::transform (::tolower) |
526+ std::ranges::to<std::string>());
527+ it != translate_map.end ()) {
528+ key_combination.push_back (it->second );
529+ } else {
530+ // If the key is not found, we can ignore it
531+ return false ;
532+ }
533+ }
534+
535+ return std::ranges::all_of (key_combination, [&](int key) {
536+ return ctx.key_pressed (key);
537+ });
538+ }
539+ return false ;
540+ }) |
541+ std::ranges::to<std::vector>();
542+
543+ if (menus_matching_key.size () == 1 ) {
544+ auto wid = menus_matching_key.front ()
545+ ->downcast <mb_shell::menu_item_normal_widget>();
546+ if (wid && wid->item .action ) {
547+ try {
548+ wid->item .action .value ()();
549+ } catch (std::exception &e) {
550+ std::cerr << " Error in action: " << e.what () << std::endl;
551+ }
552+ } else if (wid && wid->item .submenu && !wid->submenu_wid ) {
553+ wid->show_submenu (ctx);
554+ current_submenu->set_focus ();
555+ }
556+ } else if (menus_matching_key.size () > 1 ) {
557+ move_key (!ctx.key_pressed (GLFW_KEY_LEFT_SHIFT) &&
558+ !ctx.key_pressed (GLFW_KEY_RIGHT_SHIFT),
559+ menus_matching_key);
560+ }
461561 }
462562 }
463563}
0 commit comments