diff options
author | Zaggy1024 <zaggy1024@gmail.com> | 2022-10-24 19:05:40 -0500 |
---|---|---|
committer | Sam Atkins <atkinssj@gmail.com> | 2022-11-14 16:08:11 +0000 |
commit | 967dfa79563f5fa83aa27275bd57fc616a57ce55 (patch) | |
tree | eaf721787d55543ba48eed0752954c4c47662ed0 /Userland/Libraries | |
parent | 8e7c7e0a2a0279764c4aedd59e29943b7935039d (diff) | |
download | serenity-967dfa79563f5fa83aa27275bd57fc616a57ce55.zip |
LibGUI: Handle Action keyboard shortcuts in Widget keydown
Widgets can now prevent shortcut Actions from being called, which
allows text input keydown handlers to override single key shortcuts.
Diffstat (limited to 'Userland/Libraries')
-rw-r--r-- | Userland/Libraries/LibGUI/Action.cpp | 16 | ||||
-rw-r--r-- | Userland/Libraries/LibGUI/Action.h | 1 | ||||
-rw-r--r-- | Userland/Libraries/LibGUI/ConnectionToWindowServer.cpp | 10 | ||||
-rw-r--r-- | Userland/Libraries/LibGUI/Widget.cpp | 12 | ||||
-rw-r--r-- | Userland/Libraries/LibGUI/Window.cpp | 44 | ||||
-rw-r--r-- | Userland/Libraries/LibGUI/Window.h | 2 |
6 files changed, 72 insertions, 13 deletions
diff --git a/Userland/Libraries/LibGUI/Action.cpp b/Userland/Libraries/LibGUI/Action.cpp index 1ac2417b75..5408c02ac0 100644 --- a/Userland/Libraries/LibGUI/Action.cpp +++ b/Userland/Libraries/LibGUI/Action.cpp @@ -125,6 +125,22 @@ Action::~Action() } } +void Action::process_event(Window& window, Event& event) +{ + if (is_enabled()) { + flash_menubar_menu(window); + activate(); + event.accept(); + return; + } + if (swallow_key_event_when_disabled()) { + event.accept(); + return; + } + + event.ignore(); +} + void Action::activate(Core::Object* activator) { if (!on_activation) diff --git a/Userland/Libraries/LibGUI/Action.h b/Userland/Libraries/LibGUI/Action.h index 87c5762b6b..efe0f1c5fe 100644 --- a/Userland/Libraries/LibGUI/Action.h +++ b/Userland/Libraries/LibGUI/Action.h @@ -97,6 +97,7 @@ public: Function<void(Action&)> on_activation; void activate(Core::Object* activator = nullptr); + void process_event(Window& window, Event& event); void flash_menubar_menu(GUI::Window& window); bool is_enabled() const { return m_enabled; } diff --git a/Userland/Libraries/LibGUI/ConnectionToWindowServer.cpp b/Userland/Libraries/LibGUI/ConnectionToWindowServer.cpp index 6a29e66a62..e9060080b9 100644 --- a/Userland/Libraries/LibGUI/ConnectionToWindowServer.cpp +++ b/Userland/Libraries/LibGUI/ConnectionToWindowServer.cpp @@ -188,16 +188,6 @@ void ConnectionToWindowServer::key_down(i32 window_id, u32 code_point, u32 key, auto key_event = make<KeyEvent>(Event::KeyDown, (KeyCode)key, modifiers, code_point, scancode); - if (auto* action = action_for_shortcut(*window, Shortcut(key_event->modifiers(), key_event->key()))) { - if (action->is_enabled()) { - action->flash_menubar_menu(*window); - action->activate(); - return; - } - if (action->swallow_key_event_when_disabled()) - return; - } - bool focused_widget_accepts_emoji_input = window->focused_widget() && window->focused_widget()->on_emoji_input; if (!window->blocks_emoji_input() && focused_widget_accepts_emoji_input && (modifiers == (Mod_Ctrl | Mod_Alt)) && key == Key_Space) { auto emoji_input_dialog = EmojiInputDialog::construct(window); diff --git a/Userland/Libraries/LibGUI/Widget.cpp b/Userland/Libraries/LibGUI/Widget.cpp index 1def39c505..b92e0e6a98 100644 --- a/Userland/Libraries/LibGUI/Widget.cpp +++ b/Userland/Libraries/LibGUI/Widget.cpp @@ -344,10 +344,22 @@ void Widget::event(Core::Event& event) void Widget::handle_keydown_event(KeyEvent& event) { keydown_event(event); + if (event.is_accepted()) + return; + + if (auto action = Action::find_action_for_shortcut(*this, Shortcut(event.modifiers(), event.key()))) { + action->process_event(*window(), event); + if (event.is_accepted()) + return; + } + if (event.key() == KeyCode::Key_Menu) { ContextMenuEvent c_event(window_relative_rect().bottom_right(), screen_relative_rect().bottom_right()); dispatch_event(c_event); + return; } + + event.ignore(); } void Widget::handle_paint_event(PaintEvent& event) diff --git a/Userland/Libraries/LibGUI/Window.cpp b/Userland/Libraries/LibGUI/Window.cpp index 9d930f1cc2..417096cf12 100644 --- a/Userland/Libraries/LibGUI/Window.cpp +++ b/Userland/Libraries/LibGUI/Window.cpp @@ -454,6 +454,37 @@ void Window::handle_multi_paint_event(MultiPaintEvent& event) ConnectionToWindowServer::the().async_did_finish_painting(m_window_id, rects); } +void Window::propagate_shortcuts_up_to_application(KeyEvent& event, Widget* widget) +{ + VERIFY(event.type() == Event::KeyDown); + auto shortcut = Shortcut(event.modifiers(), event.key()); + Action* action = nullptr; + + if (widget) { + VERIFY(widget->window() == this); + + do { + action = widget->action_for_shortcut(shortcut); + if (action) + break; + + widget = widget->parent_widget(); + } while (widget); + } + + if (!action) + action = action_for_shortcut(shortcut); + if (!action) + action = Application::the()->action_for_shortcut(shortcut); + + if (action) { + action->process_event(*this, event); + return; + } + + event.ignore(); +} + void Window::handle_key_event(KeyEvent& event) { if (!m_focused_widget && event.type() == Event::KeyDown && event.key() == Key_Tab && !event.ctrl() && !event.alt() && !event.super()) { @@ -465,9 +496,16 @@ void Window::handle_key_event(KeyEvent& event) return default_return_key_widget()->dispatch_event(event, this); if (m_focused_widget) - return m_focused_widget->dispatch_event(event, this); - if (m_main_widget) - return m_main_widget->dispatch_event(event, this); + m_focused_widget->dispatch_event(event, this); + else if (m_main_widget) + m_main_widget->dispatch_event(event, this); + + if (event.is_accepted()) + return; + + // Only process shortcuts if this is a keydown event. + if (event.type() == Event::KeyDown) + propagate_shortcuts_up_to_application(event, nullptr); } void Window::handle_resize_event(ResizeEvent& event) diff --git a/Userland/Libraries/LibGUI/Window.h b/Userland/Libraries/LibGUI/Window.h index 68c4b372c8..55e60a26db 100644 --- a/Userland/Libraries/LibGUI/Window.h +++ b/Userland/Libraries/LibGUI/Window.h @@ -234,6 +234,8 @@ public: void set_always_on_top(bool always_on_top = true); + void propagate_shortcuts_up_to_application(KeyEvent& event, Widget* widget); + protected: Window(Core::Object* parent = nullptr); virtual void wm_event(WMEvent&); |