Skip to content

Commit a3d9102

Browse files
Copilotlijy91
andauthored
Refactor KeyboardMonitor to use generic event system (#16)
* Initial plan * Refactor KeyboardMonitor to use generic event system Co-authored-by: lijy91 <[email protected]> --------- Co-authored-by: copilot-swe-agent[bot] <[email protected]> Co-authored-by: lijy91 <[email protected]>
1 parent 70e4187 commit a3d9102

File tree

7 files changed

+175
-117
lines changed

7 files changed

+175
-117
lines changed

src/capi/keyboard_monitor_c.cpp

Lines changed: 44 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,32 @@
11
#include "keyboard_monitor_c.h"
22
#include "../keyboard_monitor.h"
3+
#include "../keyboard_events.h"
34
#include <memory>
45

56
// Internal structure to hold C API state
67
struct native_keyboard_monitor_t {
78
std::unique_ptr<nativeapi::KeyboardMonitor> cpp_monitor;
8-
std::unique_ptr<nativeapi::KeyboardEventHandler> event_handler;
99

1010
// Store C callback functions and user data
1111
native_key_pressed_callback_t on_key_pressed;
1212
native_key_released_callback_t on_key_released;
1313
native_modifier_keys_changed_callback_t on_modifier_keys_changed;
1414
void* user_data;
1515

16+
// Store listener IDs for cleanup
17+
size_t key_pressed_listener_id;
18+
size_t key_released_listener_id;
19+
size_t modifier_keys_listener_id;
20+
1621
native_keyboard_monitor_t()
1722
: cpp_monitor(nullptr),
18-
event_handler(nullptr),
1923
on_key_pressed(nullptr),
2024
on_key_released(nullptr),
2125
on_modifier_keys_changed(nullptr),
22-
user_data(nullptr) {}
26+
user_data(nullptr),
27+
key_pressed_listener_id(0),
28+
key_released_listener_id(0),
29+
modifier_keys_listener_id(0) {}
2330
};
2431

2532
// Helper function to convert C++ ModifierKey enum to C enum
@@ -88,41 +95,49 @@ bool native_keyboard_monitor_set_callbacks(
8895
return false;
8996
}
9097

98+
// Remove existing listeners if any
99+
if (monitor->key_pressed_listener_id > 0) {
100+
monitor->cpp_monitor->RemoveListener(monitor->key_pressed_listener_id);
101+
}
102+
if (monitor->key_released_listener_id > 0) {
103+
monitor->cpp_monitor->RemoveListener(monitor->key_released_listener_id);
104+
}
105+
if (monitor->modifier_keys_listener_id > 0) {
106+
monitor->cpp_monitor->RemoveListener(monitor->modifier_keys_listener_id);
107+
}
108+
91109
// Store the C callbacks and user data
92110
monitor->on_key_pressed = on_key_pressed;
93111
monitor->on_key_released = on_key_released;
94112
monitor->on_modifier_keys_changed = on_modifier_keys_changed;
95113
monitor->user_data = user_data;
96114

97115
try {
98-
// Create C++ lambda callbacks that call the C callbacks
99-
auto key_pressed_callback = [monitor](int keycode) {
100-
if (monitor->on_key_pressed) {
101-
monitor->on_key_pressed(keycode, monitor->user_data);
102-
}
103-
};
104-
105-
auto key_released_callback = [monitor](int keycode) {
106-
if (monitor->on_key_released) {
107-
monitor->on_key_released(keycode, monitor->user_data);
108-
}
109-
};
110-
111-
auto modifier_keys_changed_callback = [monitor](uint32_t modifier_keys) {
112-
if (monitor->on_modifier_keys_changed) {
113-
uint32_t c_modifier_keys = convert_modifier_keys_to_c(modifier_keys);
114-
monitor->on_modifier_keys_changed(c_modifier_keys, monitor->user_data);
115-
}
116-
};
116+
// Add event listeners with callback lambdas
117+
if (on_key_pressed) {
118+
monitor->key_pressed_listener_id = monitor->cpp_monitor->AddListener<nativeapi::KeyPressedEvent>(
119+
[monitor](const nativeapi::KeyPressedEvent& event) {
120+
monitor->on_key_pressed(event.GetKeycode(), monitor->user_data);
121+
}
122+
);
123+
}
117124

118-
// Create the event handler with the lambda callbacks
119-
monitor->event_handler = std::make_unique<nativeapi::KeyboardEventHandler>(
120-
key_pressed_callback,
121-
key_released_callback,
122-
modifier_keys_changed_callback);
125+
if (on_key_released) {
126+
monitor->key_released_listener_id = monitor->cpp_monitor->AddListener<nativeapi::KeyReleasedEvent>(
127+
[monitor](const nativeapi::KeyReleasedEvent& event) {
128+
monitor->on_key_released(event.GetKeycode(), monitor->user_data);
129+
}
130+
);
131+
}
123132

124-
// Set the event handler on the keyboard monitor
125-
monitor->cpp_monitor->SetEventHandler(monitor->event_handler.get());
133+
if (on_modifier_keys_changed) {
134+
monitor->modifier_keys_listener_id = monitor->cpp_monitor->AddListener<nativeapi::ModifierKeysChangedEvent>(
135+
[monitor](const nativeapi::ModifierKeysChangedEvent& event) {
136+
uint32_t c_modifier_keys = convert_modifier_keys_to_c(event.GetModifierKeys());
137+
monitor->on_modifier_keys_changed(c_modifier_keys, monitor->user_data);
138+
}
139+
);
140+
}
126141

127142
return true;
128143
} catch (...) {

src/keyboard_events.h

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
#pragma once
2+
3+
#include "event.h"
4+
#include "keyboard_monitor.h"
5+
6+
namespace nativeapi {
7+
8+
/**
9+
* Event fired when a key is pressed.
10+
*/
11+
class KeyPressedEvent : public TypedEvent<KeyPressedEvent> {
12+
public:
13+
explicit KeyPressedEvent(int keycode) : keycode_(keycode) {}
14+
15+
int GetKeycode() const { return keycode_; }
16+
17+
std::string GetTypeName() const override { return "KeyPressedEvent"; }
18+
19+
private:
20+
int keycode_;
21+
};
22+
23+
/**
24+
* Event fired when a key is released.
25+
*/
26+
class KeyReleasedEvent : public TypedEvent<KeyReleasedEvent> {
27+
public:
28+
explicit KeyReleasedEvent(int keycode) : keycode_(keycode) {}
29+
30+
int GetKeycode() const { return keycode_; }
31+
32+
std::string GetTypeName() const override { return "KeyReleasedEvent"; }
33+
34+
private:
35+
int keycode_;
36+
};
37+
38+
/**
39+
* Event fired when modifier keys change.
40+
*/
41+
class ModifierKeysChangedEvent : public TypedEvent<ModifierKeysChangedEvent> {
42+
public:
43+
explicit ModifierKeysChangedEvent(uint32_t modifier_keys) : modifier_keys_(modifier_keys) {}
44+
45+
uint32_t GetModifierKeys() const { return modifier_keys_; }
46+
47+
std::string GetTypeName() const override { return "ModifierKeysChangedEvent"; }
48+
49+
private:
50+
uint32_t modifier_keys_;
51+
};
52+
53+
} // namespace nativeapi

src/keyboard_monitor.cpp

Lines changed: 0 additions & 35 deletions
This file was deleted.

src/keyboard_monitor.h

Lines changed: 39 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@
44
#include <memory>
55
#include <string>
66

7+
#include "event_dispatcher.h"
8+
#include "keyboard_events.h"
9+
710
namespace nativeapi {
811

912
enum class ModifierKey : uint32_t {
@@ -18,37 +21,42 @@ enum class ModifierKey : uint32_t {
1821
ScrollLock = 1 << 7
1922
};
2023

21-
// KeyboardEventHandler uses callbacks to handle keyboard events.
22-
class KeyboardEventHandler {
23-
public:
24-
// Constructor that takes callbacks for keyboard events
25-
KeyboardEventHandler(
26-
std::function<void(int)> onKeyPressedCallback,
27-
std::function<void(int)> onKeyReleasedCallback,
28-
std::function<void(uint32_t)> onModifierKeysChangedCallback);
29-
30-
// Handle key pressed event
31-
void OnKeyPressed(int keycode);
32-
33-
// Handle key released event
34-
void OnKeyReleased(int keycode);
24+
// Bitwise operators for ModifierKey enum
25+
inline ModifierKey operator|(ModifierKey a, ModifierKey b) {
26+
return static_cast<ModifierKey>(static_cast<uint32_t>(a) | static_cast<uint32_t>(b));
27+
}
3528

36-
// Handle modifier keys changed event
37-
void OnModifierKeysChanged(uint32_t modifier_keys);
38-
39-
private:
40-
std::function<void(int)> onKeyPressedCallback_;
41-
std::function<void(int)> onKeyReleasedCallback_;
42-
std::function<void(uint32_t)> onModifierKeysChangedCallback_;
43-
};
29+
inline ModifierKey operator&(ModifierKey a, ModifierKey b) {
30+
return static_cast<ModifierKey>(static_cast<uint32_t>(a) & static_cast<uint32_t>(b));
31+
}
4432

4533
class KeyboardMonitor {
4634
public:
4735
KeyboardMonitor();
4836
virtual ~KeyboardMonitor();
4937

50-
// Set the event handler for the keyboard monitor
51-
void SetEventHandler(KeyboardEventHandler* event_handler);
38+
// Add a listener for keyboard events
39+
template<typename EventType>
40+
size_t AddListener(TypedEventListener<EventType>* listener) {
41+
return event_dispatcher_.AddListener(listener);
42+
}
43+
44+
// Add a callback-based listener for keyboard events
45+
template<typename EventType>
46+
size_t AddListener(std::function<void(const EventType&)> callback) {
47+
return event_dispatcher_.AddListener(std::move(callback));
48+
}
49+
50+
// Remove a listener by ID
51+
bool RemoveListener(size_t listener_id) {
52+
return event_dispatcher_.RemoveListener(listener_id);
53+
}
54+
55+
// Remove all listeners for a specific event type
56+
template<typename EventType>
57+
void RemoveAllListeners() {
58+
event_dispatcher_.RemoveAllListeners<EventType>();
59+
}
5260

5361
// Start the keyboard monitor
5462
void Start();
@@ -59,13 +67,17 @@ class KeyboardMonitor {
5967
// Check if the keyboard monitor is monitoring
6068
bool IsMonitoring() const;
6169

62-
// Get the event handler
63-
KeyboardEventHandler* GetEventHandler() const { return event_handler_; }
70+
// Get access to the event dispatcher for advanced usage
71+
EventDispatcher& GetEventDispatcher() { return event_dispatcher_; }
6472

6573
private:
6674
class Impl;
6775
std::unique_ptr<Impl> impl_;
68-
KeyboardEventHandler* event_handler_;
76+
EventDispatcher event_dispatcher_;
77+
78+
// Internal method for dispatching events from platform code
79+
void DispatchEvent(const Event& event);
80+
friend class Impl;
6981
};
7082

7183
} // namespace nativeapi

src/platform/linux/keyboard_monitor_linux.cpp

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ class KeyboardMonitor::Impl {
3737
uint32_t GetModifierState();
3838
};
3939

40-
KeyboardMonitor::KeyboardMonitor() : impl_(std::make_unique<Impl>(this)), event_handler_(nullptr) {}
40+
KeyboardMonitor::KeyboardMonitor() : impl_(std::make_unique<Impl>(this)), event_dispatcher_() {}
4141

4242
KeyboardMonitor::~KeyboardMonitor() {
4343
Stop();
@@ -154,15 +154,18 @@ void KeyboardMonitor::Impl::MonitoringLoop() {
154154
if (XGetEventData(display_, &event.xcookie)) {
155155
XIDeviceEvent* xi_event = (XIDeviceEvent*)event.xcookie.data;
156156

157-
auto* eventHandler = monitor_->GetEventHandler();
158-
if (eventHandler) {
159-
if (xi_event->evtype == XI_KeyPress) {
160-
eventHandler->OnKeyPressed(xi_event->detail);
161-
eventHandler->OnModifierKeysChanged(GetModifierState());
162-
} else if (xi_event->evtype == XI_KeyRelease) {
163-
eventHandler->OnKeyReleased(xi_event->detail);
164-
eventHandler->OnModifierKeysChanged(GetModifierState());
165-
}
157+
if (xi_event->evtype == XI_KeyPress) {
158+
KeyPressedEvent key_event(xi_event->detail);
159+
monitor_->DispatchEvent(key_event);
160+
161+
ModifierKeysChangedEvent modifier_event(GetModifierState());
162+
monitor_->DispatchEvent(modifier_event);
163+
} else if (xi_event->evtype == XI_KeyRelease) {
164+
KeyReleasedEvent key_event(xi_event->detail);
165+
monitor_->DispatchEvent(key_event);
166+
167+
ModifierKeysChangedEvent modifier_event(GetModifierState());
168+
monitor_->DispatchEvent(modifier_event);
166169
}
167170

168171
XFreeEventData(display_, &event.xcookie);
@@ -213,4 +216,8 @@ bool KeyboardMonitor::IsMonitoring() const {
213216
return impl_->monitoring_;
214217
}
215218

219+
void KeyboardMonitor::DispatchEvent(const Event& event) {
220+
event_dispatcher_.DispatchSync(event);
221+
}
222+
216223
} // namespace nativeapi

src/platform/macos/keyboard_monitor_macos.mm

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
KeyboardMonitor* monitor_;
2020
};
2121

22-
KeyboardMonitor::KeyboardMonitor() : impl_(std::make_unique<Impl>(this)), event_handler_(nullptr) {}
22+
KeyboardMonitor::KeyboardMonitor() : impl_(std::make_unique<Impl>(this)), event_dispatcher_() {}
2323

2424
KeyboardMonitor::~KeyboardMonitor() {
2525
Stop();
@@ -34,17 +34,15 @@ static CGEventRef keyboardEventCallback(CGEventTapProxy proxy,
3434
if (!monitor)
3535
return event;
3636

37-
auto* eventHandler = monitor->GetEventHandler();
38-
if (!eventHandler)
39-
return event;
40-
4137
// Get the key code
4238
CGKeyCode keyCode = (CGKeyCode)CGEventGetIntegerValueField(event, kCGKeyboardEventKeycode);
4339

4440
if (type == kCGEventKeyDown) {
45-
eventHandler->OnKeyPressed(keyCode);
41+
KeyPressedEvent key_event(keyCode);
42+
monitor->DispatchEvent(key_event);
4643
} else if (type == kCGEventKeyUp) {
47-
eventHandler->OnKeyReleased(keyCode);
44+
KeyReleasedEvent key_event(keyCode);
45+
monitor->DispatchEvent(key_event);
4846
} else if (type == kCGEventFlagsChanged) {
4947
CGEventFlags flags = CGEventGetFlags(event);
5048
uint32_t modifier_keys = static_cast<uint32_t>(ModifierKey::None);
@@ -69,7 +67,8 @@ static CGEventRef keyboardEventCallback(CGEventTapProxy proxy,
6967
if (flags & kCGEventFlagMaskNumericPad) {
7068
modifier_keys |= static_cast<uint32_t>(ModifierKey::NumLock);
7169
}
72-
eventHandler->OnModifierKeysChanged(modifier_keys);
70+
ModifierKeysChangedEvent modifier_event(modifier_keys);
71+
monitor->DispatchEvent(modifier_event);
7372
}
7473
return event;
7574
}
@@ -131,4 +130,8 @@ static CGEventRef keyboardEventCallback(CGEventTapProxy proxy,
131130
return impl_->eventTap != nullptr;
132131
}
133132

133+
void KeyboardMonitor::DispatchEvent(const Event& event) {
134+
event_dispatcher_.DispatchSync(event);
135+
}
136+
134137
} // namespace nativeapi

0 commit comments

Comments
 (0)