From 53809dc93eedff577e59c461551bd74f75ec7a64 Mon Sep 17 00:00:00 2001 From: eidheim Date: Sun, 22 Aug 2021 20:24:26 +0200 Subject: [PATCH] Two or more menu actions can now have the same keybinding --- src/menu.cpp | 34 +++++++++++++++++++++++++++------- src/menu.hpp | 1 + src/source.cpp | 2 +- src/window.cpp | 14 +++++++++++--- 4 files changed, 40 insertions(+), 11 deletions(-) diff --git a/src/menu.cpp b/src/menu.cpp index 416ad23..2f819a7 100644 --- a/src/menu.cpp +++ b/src/menu.cpp @@ -1,5 +1,6 @@ #include "menu.hpp" #include "config.hpp" +#include "terminal.hpp" #include #include @@ -578,14 +579,33 @@ void Menu::add_action(const std::string &name, const std::function &acti void Menu::set_keys() { auto application = Glib::RefPtr::cast_dynamic(Gtk::Application::get_default()); - for(auto &key : Config::get().menu.keys) { - if(actions.find(key.first) != actions.end()) { - if(!key.second.empty()) - application->set_accel_for_action("app." + key.first, key.second); + accelerators_with_multiple_actions.clear(); + + for(auto &action_and_key : Config::get().menu.keys) { + auto it = actions.find(action_and_key.first); + if(it != actions.end()) { + if(!action_and_key.second.empty()) { + application->set_accel_for_action("app." + action_and_key.first, action_and_key.second); + + guint key = 0; + GdkModifierType modifier = static_cast(0); + gtk_accelerator_parse(action_and_key.second.c_str(), &key, &modifier); + if(key == 0 && modifier == 0) + Terminal::get().async_print("\e[31mError\e[m: could not parse key string \"" + action_and_key.second + "\" for action " + action_and_key.first + "\n", true); + else + accelerators_with_multiple_actions[std::make_pair(key, modifier)].emplace_back(it->second); + } else - application->unset_accels_for_action("app." + key.first); + application->unset_accels_for_action("app." + action_and_key.first); } } + + for(auto it = accelerators_with_multiple_actions.begin(); it != accelerators_with_multiple_actions.end();) { + if(it->second.size() < 2) + it = accelerators_with_multiple_actions.erase(it); + else + ++it; + } } void Menu::build() { @@ -602,7 +622,7 @@ void Menu::build() { ptr = Glib::RefPtr::cast_dynamic(object); right_click_selected_menu = std::make_unique(ptr); } - catch(const Glib::Error &ex) { - std::cerr << "building menu failed: " << ex.what(); + catch(const Glib::Error &e) { + std::cerr << "building menu failed: " << e.what(); } } diff --git a/src/menu.hpp b/src/menu.hpp index be2336c..224ea73 100644 --- a/src/menu.hpp +++ b/src/menu.hpp @@ -15,6 +15,7 @@ public: void add_action(const std::string &name, const std::function &action); std::unordered_map> actions; + std::map, std::vector>> accelerators_with_multiple_actions; void set_keys(); void build(); diff --git a/src/source.cpp b/src/source.cpp index f80f43c..9f05fbe 100644 --- a/src/source.cpp +++ b/src/source.cpp @@ -2597,7 +2597,7 @@ bool Source::View::on_key_press_event(GdkEventKey *event) { guint keyval_without_state; gdk_keymap_translate_keyboard_state(gdk_keymap_get_default(), event->hardware_keycode, (GdkModifierType)0, 0, &keyval_without_state, nullptr, nullptr, nullptr); for(auto &snippet : *snippets) { - if((snippet.key == event->keyval || snippet.key == keyval_without_state) && (event->state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK | GDK_MOD1_MASK | GDK_META_MASK)) == snippet.modifier) { + if(snippet.key == keyval_without_state && (event->state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK | GDK_MOD1_MASK | GDK_META_MASK)) == snippet.modifier) { insert_snippet(get_buffer()->get_insert()->get_iter(), snippet.body); return true; } diff --git a/src/window.cpp b/src/window.cpp index ffd4498..a4e791a 100644 --- a/src/window.cpp +++ b/src/window.cpp @@ -1939,7 +1939,7 @@ bool Window::on_key_press_event(GdkEventKey *event) { guint keyval_without_state; gdk_keymap_translate_keyboard_state(gdk_keymap_get_default(), event->hardware_keycode, (GdkModifierType)0, 0, &keyval_without_state, nullptr, nullptr, nullptr); for(auto &command : Commands::get().commands) { - if((command.key == event->keyval || command.key == keyval_without_state) && (event->state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK | GDK_MOD1_MASK | GDK_META_MASK)) == command.modifier) { + if(command.key == keyval_without_state && (event->state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK | GDK_MOD1_MASK | GDK_META_MASK)) == command.modifier) { auto view = Notebook::get().get_current_view(); auto view_folder = Project::get_preferably_view_folder(); auto path = view ? view->file_path : view_folder; @@ -2021,9 +2021,8 @@ bool Window::on_key_press_event(GdkEventKey *event) { } } - if(event->keyval == GDK_KEY_Escape) { + if(event->keyval == GDK_KEY_Escape) EntryBox::get().hide(); - } #ifdef __APPLE__ //For Apple's Command-left, right, up, down keys else if((event->state & GDK_META_MASK) > 0 && (event->state & GDK_MOD1_MASK) == 0) { if(event->keyval == GDK_KEY_Left || event->keyval == GDK_KEY_KP_Left) { @@ -2056,6 +2055,15 @@ bool Window::on_key_press_event(GdkEventKey *event) { return true; } + auto it = Menu::get().accelerators_with_multiple_actions.find(std::make_pair(keyval_without_state, static_cast(event->state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK | GDK_MOD1_MASK | GDK_META_MASK)))); + if(it != Menu::get().accelerators_with_multiple_actions.end()) { + // Copy actions since accelerators_with_multiple_actions might change during activations + auto actions = it->second; + for(auto &action : actions) + action->activate(); + return true; + } + return Gtk::ApplicationWindow::on_key_press_event(event); }