LibGUI: Move shortcut actions from GEventLoop to GApplications.

I'm gonna want to have nested event loops sooner or later, so let's not
pollute GEventLoop with things that are meant to work globally.

This patch also changes key events to pass around their modifiers as a
bitfield all the way around the system instead of breaking them up.
This commit is contained in:
Andreas Kling 2019-03-03 12:32:15 +01:00
parent 725b57fe1f
commit 5e40aa4f1a
Notes: sideshowbarker 2024-07-19 15:33:48 +09:00
11 changed files with 63 additions and 55 deletions

View File

@ -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; }
};

View File

@ -1,5 +1,5 @@
#include <LibGUI/GAction.h>
#include <LibGUI/GEventLoop.h>
#include <LibGUI/GApplication.h>
GAction::GAction(const String& text, const String& custom_data, Function<void(const GAction&)> on_activation_callback)
: on_activation(move(on_activation_callback))
@ -32,13 +32,13 @@ GAction::GAction(const String& text, const GShortcut& shortcut, RetainPtr<Graphi
, m_icon(move(icon))
, m_shortcut(shortcut)
{
GEventLoop::register_action_with_shortcut(Badge<GAction>(), *this);
GApplication::the().register_shortcut_action(Badge<GAction>(), *this);
}
GAction::~GAction()
{
if (m_shortcut.is_valid())
GEventLoop::unregister_action_with_shortcut(Badge<GAction>(), *this);
GApplication::the().unregister_shortcut_action(Badge<GAction>(), *this);
}
void GAction::activate()

View File

@ -1,6 +1,7 @@
#include <LibGUI/GApplication.h>
#include <LibGUI/GEventLoop.h>
#include <LibGUI/GMenuBar.h>
#include <LibGUI/GAction.h>
static GApplication* s_the;
@ -42,3 +43,20 @@ void GApplication::set_menubar(OwnPtr<GMenuBar>&& menubar)
m_menubar->notify_added_to_application(Badge<GApplication>());
}
void GApplication::register_shortcut_action(Badge<GAction>, GAction& action)
{
m_shortcut_actions.set(action.shortcut(), &action);
}
void GApplication::unregister_shortcut_action(Badge<GAction>, 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;
}

View File

@ -1,7 +1,12 @@
#pragma once
#include <AK/Badge.h>
#include <AK/OwnPtr.h>
#include <AK/HashMap.h>
#include <LibGUI/GShortcut.h>
class GAction;
class GKeyEvent;
class GEventLoop;
class GMenuBar;
@ -15,8 +20,13 @@ public:
void quit(int);
void set_menubar(OwnPtr<GMenuBar>&&);
GAction* action_for_key_event(const GKeyEvent&);
void register_shortcut_action(Badge<GAction>, GAction&);
void unregister_shortcut_action(Badge<GAction>, GAction&);
private:
OwnPtr<GEventLoop> m_event_loop;
OwnPtr<GMenuBar> m_menubar;
HashMap<GShortcut, GAction*> m_shortcut_actions;
};

View File

@ -4,6 +4,7 @@
#include <SharedGraphics/Rect.h>
#include <AK/AKString.h>
#include <AK/Types.h>
#include <Kernel/KeyCode.h>
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;
};

View File

@ -2,6 +2,7 @@
#include "GEvent.h"
#include "GObject.h"
#include "GWindow.h"
#include <LibGUI/GApplication.h>
#include <LibGUI/GAction.h>
#include <LibGUI/GNotifier.h>
#include <LibGUI/GMenu.h>
@ -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<GKeyEvent>(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<GKeyEvent>(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>, GAction& action)
{
g_actions->set(action.shortcut(), &action);
}
void GEventLoop::unregister_action_with_shortcut(Badge<GAction>, GAction& action)
{
g_actions->remove(action.shortcut());
}

View File

@ -41,9 +41,6 @@ public:
pid_t server_pid() const { return m_server_pid; }
static void register_action_with_shortcut(Badge<GAction>, GAction&);
static void unregister_action_with_shortcut(Badge<GAction>, GAction&);
private:
void wait_for_event();
bool drain_messages_from_server();

View File

@ -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 };
};

View File

@ -4,6 +4,7 @@
#include <SharedGraphics/Rect.h>
#include <AK/AKString.h>
#include <AK/Types.h>
#include <Kernel/KeyCode.h>
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 {

View File

@ -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<WSKeyEvent>(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<WSKeyEvent>(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));
}

View File

@ -98,17 +98,13 @@ void WSWindow::on_message(WSMessage& message)
server_message.type = WSAPI_ServerMessage::Type::KeyDown;
server_message.key.character = static_cast<WSKeyEvent&>(message).character();
server_message.key.key = static_cast<WSKeyEvent&>(message).key();
server_message.key.alt = static_cast<WSKeyEvent&>(message).alt();
server_message.key.ctrl = static_cast<WSKeyEvent&>(message).ctrl();
server_message.key.shift = static_cast<WSKeyEvent&>(message).shift();
server_message.key.modifiers = static_cast<WSKeyEvent&>(message).modifiers();
break;
case WSMessage::KeyUp:
server_message.type = WSAPI_ServerMessage::Type::KeyUp;
server_message.key.character = static_cast<WSKeyEvent&>(message).character();
server_message.key.key = static_cast<WSKeyEvent&>(message).key();
server_message.key.alt = static_cast<WSKeyEvent&>(message).alt();
server_message.key.ctrl = static_cast<WSKeyEvent&>(message).ctrl();
server_message.key.shift = static_cast<WSKeyEvent&>(message).shift();
server_message.key.modifiers = static_cast<WSKeyEvent&>(message).modifiers();
break;
case WSMessage::WindowActivated:
server_message.type = WSAPI_ServerMessage::Type::WindowActivated;