diff --git a/Kernel/KeyCode.h b/Kernel/KeyCode.h index 4394bd2f607..558ebcfcdcd 100644 --- a/Kernel/KeyCode.h +++ b/Kernel/KeyCode.h @@ -113,6 +113,8 @@ enum KeyModifier { Mod_Alt = 0x01, Mod_Ctrl = 0x02, Mod_Shift = 0x04, + Mod_Mask = 0x07, + Is_Press = 0x80, }; @@ -123,5 +125,6 @@ struct KeyEvent { bool alt() const { return flags & Mod_Alt; } bool ctrl() const { return flags & Mod_Ctrl; } bool shift() const { return flags & Mod_Shift; } + unsigned modifiers() const { return flags & Mod_Mask; } bool is_press() const { return flags & Is_Press; } }; diff --git a/LibGUI/GAction.cpp b/LibGUI/GAction.cpp index 770c5ebc5d6..5a0106530dc 100644 --- a/LibGUI/GAction.cpp +++ b/LibGUI/GAction.cpp @@ -1,5 +1,5 @@ #include -#include +#include GAction::GAction(const String& text, const String& custom_data, Function on_activation_callback) : on_activation(move(on_activation_callback)) @@ -32,13 +32,13 @@ GAction::GAction(const String& text, const GShortcut& shortcut, RetainPtr(), *this); + GApplication::the().register_shortcut_action(Badge(), *this); } GAction::~GAction() { if (m_shortcut.is_valid()) - GEventLoop::unregister_action_with_shortcut(Badge(), *this); + GApplication::the().unregister_shortcut_action(Badge(), *this); } void GAction::activate() diff --git a/LibGUI/GApplication.cpp b/LibGUI/GApplication.cpp index 3c1567ef366..9fc3eabfde0 100644 --- a/LibGUI/GApplication.cpp +++ b/LibGUI/GApplication.cpp @@ -1,6 +1,7 @@ #include #include #include +#include static GApplication* s_the; @@ -42,3 +43,20 @@ void GApplication::set_menubar(OwnPtr&& menubar) m_menubar->notify_added_to_application(Badge()); } +void GApplication::register_shortcut_action(Badge, GAction& action) +{ + m_shortcut_actions.set(action.shortcut(), &action); +} + +void GApplication::unregister_shortcut_action(Badge, GAction& action) +{ + m_shortcut_actions.remove(action.shortcut()); +} + +GAction* GApplication::action_for_key_event(const GKeyEvent& event) +{ + auto it = m_shortcut_actions.find(GShortcut(event.modifiers(), (KeyCode)event.key())); + if (it == m_shortcut_actions.end()) + return nullptr; + return (*it).value; +} diff --git a/LibGUI/GApplication.h b/LibGUI/GApplication.h index 723eeec3e4e..694f19e4d21 100644 --- a/LibGUI/GApplication.h +++ b/LibGUI/GApplication.h @@ -1,7 +1,12 @@ #pragma once +#include #include +#include +#include +class GAction; +class GKeyEvent; class GEventLoop; class GMenuBar; @@ -15,8 +20,13 @@ public: void quit(int); void set_menubar(OwnPtr&&); + GAction* action_for_key_event(const GKeyEvent&); + + void register_shortcut_action(Badge, GAction&); + void unregister_shortcut_action(Badge, GAction&); private: OwnPtr m_event_loop; OwnPtr m_menubar; + HashMap m_shortcut_actions; }; diff --git a/LibGUI/GEvent.h b/LibGUI/GEvent.h index 86fce807ae6..278835e9bed 100644 --- a/LibGUI/GEvent.h +++ b/LibGUI/GEvent.h @@ -4,6 +4,7 @@ #include #include #include +#include class GEvent { public: @@ -112,24 +113,24 @@ enum GMouseButton : byte { class GKeyEvent final : public GEvent { public: - GKeyEvent(Type type, int key) + GKeyEvent(Type type, int key, byte modifiers) : GEvent(type) , m_key(key) + , m_modifiers(modifiers) { } int key() const { return m_key; } - bool ctrl() const { return m_ctrl; } - bool alt() const { return m_alt; } - bool shift() const { return m_shift; } + bool ctrl() const { return m_modifiers & Mod_Ctrl; } + bool alt() const { return m_modifiers & Mod_Alt; } + bool shift() const { return m_modifiers & Mod_Shift; } + byte modifiers() const { return m_modifiers; } String text() const { return m_text; } private: friend class GEventLoop; int m_key { 0 }; - bool m_ctrl { false }; - bool m_alt { false }; - bool m_shift { false }; + byte m_modifiers { 0 }; String m_text; }; diff --git a/LibGUI/GEventLoop.cpp b/LibGUI/GEventLoop.cpp index 7e671e7ab7d..64bb5041b6b 100644 --- a/LibGUI/GEventLoop.cpp +++ b/LibGUI/GEventLoop.cpp @@ -2,6 +2,7 @@ #include "GEvent.h" #include "GObject.h" #include "GWindow.h" +#include #include #include #include @@ -153,20 +154,14 @@ void GEventLoop::handle_key_event(const WSAPI_ServerMessage& event, GWindow& win #ifdef GEVENTLOOP_DEBUG dbgprintf("WID=%x KeyEvent character=0x%b\n", event.window_id, event.key.character); #endif - - unsigned modifiers = (event.key.alt * Mod_Alt) + (event.key.ctrl * Mod_Ctrl) + (event.key.shift * Mod_Shift); - auto it = g_actions->find(GShortcut(modifiers, (KeyCode)event.key.key)); - if (it != g_actions->end()) { - (*it).value->activate(); - return; - } - - auto key_event = make(event.type == WSAPI_ServerMessage::Type::KeyDown ? GEvent::KeyDown : GEvent::KeyUp, event.key.key); - key_event->m_alt = event.key.alt; - key_event->m_ctrl = event.key.ctrl; - key_event->m_shift = event.key.shift; + auto key_event = make(event.type == WSAPI_ServerMessage::Type::KeyDown ? GEvent::KeyDown : GEvent::KeyUp, event.key.key, event.key.modifiers); if (event.key.character != '\0') key_event->m_text = String(&event.key.character, 1); + + if (auto* action = GApplication::the().action_for_key_event(*key_event)) { + action->activate(); + return; + } post_event(window, move(key_event)); } @@ -455,13 +450,3 @@ WSAPI_ServerMessage GEventLoop::sync_request(const WSAPI_ClientMessage& request, ASSERT(success); return response; } - -void GEventLoop::register_action_with_shortcut(Badge, GAction& action) -{ - g_actions->set(action.shortcut(), &action); -} - -void GEventLoop::unregister_action_with_shortcut(Badge, GAction& action) -{ - g_actions->remove(action.shortcut()); -} diff --git a/LibGUI/GEventLoop.h b/LibGUI/GEventLoop.h index ab79a5ba4bb..af7eb565d5a 100644 --- a/LibGUI/GEventLoop.h +++ b/LibGUI/GEventLoop.h @@ -41,9 +41,6 @@ public: pid_t server_pid() const { return m_server_pid; } - static void register_action_with_shortcut(Badge, GAction&); - static void unregister_action_with_shortcut(Badge, GAction&); - private: void wait_for_event(); bool drain_messages_from_server(); diff --git a/LibGUI/GShortcut.h b/LibGUI/GShortcut.h index 7675a6ef30d..bae66dc4d50 100644 --- a/LibGUI/GShortcut.h +++ b/LibGUI/GShortcut.h @@ -7,14 +7,14 @@ class GShortcut { public: GShortcut() { } - GShortcut(unsigned modifiers, KeyCode key) + GShortcut(byte modifiers, KeyCode key) : m_modifiers(modifiers) , m_key(key) { } bool is_valid() const { return m_key != KeyCode::Key_Invalid; } - unsigned modifiers() const { return m_modifiers; } + byte modifiers() const { return m_modifiers; } KeyCode key() const { return m_key; } String to_string() const; @@ -25,7 +25,7 @@ public: } private: - unsigned m_modifiers { 0 }; + byte m_modifiers { 0 }; KeyCode m_key { KeyCode::Key_Invalid }; }; diff --git a/WindowServer/WSMessage.h b/WindowServer/WSMessage.h index 125bd2ef900..9981eb19af5 100644 --- a/WindowServer/WSMessage.h +++ b/WindowServer/WSMessage.h @@ -4,6 +4,7 @@ #include #include #include +#include class WSMessage { public: @@ -450,27 +451,27 @@ enum class MouseButton : byte { class WSKeyEvent final : public WSMessage { public: - WSKeyEvent(Type type, int key, char character) + WSKeyEvent(Type type, int key, char character, byte modifiers) : WSMessage(type) , m_key(key) , m_character(character) + , m_modifiers(modifiers) { } int key() const { return m_key; } - bool ctrl() const { return m_ctrl; } - bool alt() const { return m_alt; } - bool shift() const { return m_shift; } + bool ctrl() const { return m_modifiers & Mod_Ctrl; } + bool alt() const { return m_modifiers & Mod_Alt; } + bool shift() const { return m_modifiers & Mod_Shift; } + byte modifiers() const { return m_modifiers; } char character() const { return m_character; } private: friend class WSMessageLoop; friend class WSScreen; int m_key { 0 }; - bool m_ctrl { false }; - bool m_alt { false }; - bool m_shift { false }; char m_character { 0 }; + byte m_modifiers { 0 }; }; class WSMouseEvent final : public WSMessage { diff --git a/WindowServer/WSScreen.cpp b/WindowServer/WSScreen.cpp index 04d31cd51d9..96cc2c4b9b1 100644 --- a/WindowServer/WSScreen.cpp +++ b/WindowServer/WSScreen.cpp @@ -94,10 +94,7 @@ void WSScreen::on_receive_mouse_data(int dx, int dy, bool left_button, bool righ void WSScreen::on_receive_keyboard_data(KeyEvent kernel_event) { - auto message = make(kernel_event.is_press() ? WSMessage::KeyDown : WSMessage::KeyUp, kernel_event.key, kernel_event.character); - message->m_shift = kernel_event.shift(); - message->m_ctrl = kernel_event.ctrl(); - message->m_alt = kernel_event.alt(); + auto message = make(kernel_event.is_press() ? WSMessage::KeyDown : WSMessage::KeyUp, kernel_event.key, kernel_event.character, kernel_event.modifiers()); WSMessageLoop::the().post_message(WSWindowManager::the(), move(message)); } diff --git a/WindowServer/WSWindow.cpp b/WindowServer/WSWindow.cpp index 93158783063..dfca71e6fcb 100644 --- a/WindowServer/WSWindow.cpp +++ b/WindowServer/WSWindow.cpp @@ -98,17 +98,13 @@ void WSWindow::on_message(WSMessage& message) server_message.type = WSAPI_ServerMessage::Type::KeyDown; server_message.key.character = static_cast(message).character(); server_message.key.key = static_cast(message).key(); - server_message.key.alt = static_cast(message).alt(); - server_message.key.ctrl = static_cast(message).ctrl(); - server_message.key.shift = static_cast(message).shift(); + server_message.key.modifiers = static_cast(message).modifiers(); break; case WSMessage::KeyUp: server_message.type = WSAPI_ServerMessage::Type::KeyUp; server_message.key.character = static_cast(message).character(); server_message.key.key = static_cast(message).key(); - server_message.key.alt = static_cast(message).alt(); - server_message.key.ctrl = static_cast(message).ctrl(); - server_message.key.shift = static_cast(message).shift(); + server_message.key.modifiers = static_cast(message).modifiers(); break; case WSMessage::WindowActivated: server_message.type = WSAPI_ServerMessage::Type::WindowActivated;