mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 22:37:35 +00:00
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.
This commit is contained in:
parent
8e7c7e0a2a
commit
967dfa7956
6 changed files with 72 additions and 13 deletions
|
@ -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)
|
void Action::activate(Core::Object* activator)
|
||||||
{
|
{
|
||||||
if (!on_activation)
|
if (!on_activation)
|
||||||
|
|
|
@ -97,6 +97,7 @@ public:
|
||||||
Function<void(Action&)> on_activation;
|
Function<void(Action&)> on_activation;
|
||||||
|
|
||||||
void activate(Core::Object* activator = nullptr);
|
void activate(Core::Object* activator = nullptr);
|
||||||
|
void process_event(Window& window, Event& event);
|
||||||
void flash_menubar_menu(GUI::Window& window);
|
void flash_menubar_menu(GUI::Window& window);
|
||||||
|
|
||||||
bool is_enabled() const { return m_enabled; }
|
bool is_enabled() const { return m_enabled; }
|
||||||
|
|
|
@ -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);
|
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;
|
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) {
|
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);
|
auto emoji_input_dialog = EmojiInputDialog::construct(window);
|
||||||
|
|
|
@ -344,10 +344,22 @@ void Widget::event(Core::Event& event)
|
||||||
void Widget::handle_keydown_event(KeyEvent& event)
|
void Widget::handle_keydown_event(KeyEvent& event)
|
||||||
{
|
{
|
||||||
keydown_event(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) {
|
if (event.key() == KeyCode::Key_Menu) {
|
||||||
ContextMenuEvent c_event(window_relative_rect().bottom_right(), screen_relative_rect().bottom_right());
|
ContextMenuEvent c_event(window_relative_rect().bottom_right(), screen_relative_rect().bottom_right());
|
||||||
dispatch_event(c_event);
|
dispatch_event(c_event);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
event.ignore();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Widget::handle_paint_event(PaintEvent& event)
|
void Widget::handle_paint_event(PaintEvent& event)
|
||||||
|
|
|
@ -454,6 +454,37 @@ void Window::handle_multi_paint_event(MultiPaintEvent& event)
|
||||||
ConnectionToWindowServer::the().async_did_finish_painting(m_window_id, rects);
|
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)
|
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()) {
|
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);
|
return default_return_key_widget()->dispatch_event(event, this);
|
||||||
|
|
||||||
if (m_focused_widget)
|
if (m_focused_widget)
|
||||||
return m_focused_widget->dispatch_event(event, this);
|
m_focused_widget->dispatch_event(event, this);
|
||||||
if (m_main_widget)
|
else if (m_main_widget)
|
||||||
return m_main_widget->dispatch_event(event, this);
|
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)
|
void Window::handle_resize_event(ResizeEvent& event)
|
||||||
|
|
|
@ -234,6 +234,8 @@ public:
|
||||||
|
|
||||||
void set_always_on_top(bool always_on_top = true);
|
void set_always_on_top(bool always_on_top = true);
|
||||||
|
|
||||||
|
void propagate_shortcuts_up_to_application(KeyEvent& event, Widget* widget);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Window(Core::Object* parent = nullptr);
|
Window(Core::Object* parent = nullptr);
|
||||||
virtual void wm_event(WMEvent&);
|
virtual void wm_event(WMEvent&);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue