Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 44 additions & 29 deletions src/capi/keyboard_monitor_c.cpp
Original file line number Diff line number Diff line change
@@ -1,25 +1,32 @@
#include "keyboard_monitor_c.h"
#include "../keyboard_monitor.h"
#include "../keyboard_events.h"
#include <memory>

// Internal structure to hold C API state
struct native_keyboard_monitor_t {
std::unique_ptr<nativeapi::KeyboardMonitor> cpp_monitor;
std::unique_ptr<nativeapi::KeyboardEventHandler> event_handler;

// Store C callback functions and user data
native_key_pressed_callback_t on_key_pressed;
native_key_released_callback_t on_key_released;
native_modifier_keys_changed_callback_t on_modifier_keys_changed;
void* user_data;

// Store listener IDs for cleanup
size_t key_pressed_listener_id;
size_t key_released_listener_id;
size_t modifier_keys_listener_id;

native_keyboard_monitor_t()
: cpp_monitor(nullptr),
event_handler(nullptr),
on_key_pressed(nullptr),
on_key_released(nullptr),
on_modifier_keys_changed(nullptr),
user_data(nullptr) {}
user_data(nullptr),
key_pressed_listener_id(0),
key_released_listener_id(0),
modifier_keys_listener_id(0) {}
};

// Helper function to convert C++ ModifierKey enum to C enum
Expand Down Expand Up @@ -88,41 +95,49 @@ bool native_keyboard_monitor_set_callbacks(
return false;
}

// Remove existing listeners if any
if (monitor->key_pressed_listener_id > 0) {
monitor->cpp_monitor->RemoveListener(monitor->key_pressed_listener_id);
}
if (monitor->key_released_listener_id > 0) {
monitor->cpp_monitor->RemoveListener(monitor->key_released_listener_id);
}
if (monitor->modifier_keys_listener_id > 0) {
monitor->cpp_monitor->RemoveListener(monitor->modifier_keys_listener_id);
}

// Store the C callbacks and user data
monitor->on_key_pressed = on_key_pressed;
monitor->on_key_released = on_key_released;
monitor->on_modifier_keys_changed = on_modifier_keys_changed;
monitor->user_data = user_data;

try {
// Create C++ lambda callbacks that call the C callbacks
auto key_pressed_callback = [monitor](int keycode) {
if (monitor->on_key_pressed) {
monitor->on_key_pressed(keycode, monitor->user_data);
}
};

auto key_released_callback = [monitor](int keycode) {
if (monitor->on_key_released) {
monitor->on_key_released(keycode, monitor->user_data);
}
};

auto modifier_keys_changed_callback = [monitor](uint32_t modifier_keys) {
if (monitor->on_modifier_keys_changed) {
uint32_t c_modifier_keys = convert_modifier_keys_to_c(modifier_keys);
monitor->on_modifier_keys_changed(c_modifier_keys, monitor->user_data);
}
};
// Add event listeners with callback lambdas
if (on_key_pressed) {
monitor->key_pressed_listener_id = monitor->cpp_monitor->AddListener<nativeapi::KeyPressedEvent>(
[monitor](const nativeapi::KeyPressedEvent& event) {
monitor->on_key_pressed(event.GetKeycode(), monitor->user_data);
}
);
}

// Create the event handler with the lambda callbacks
monitor->event_handler = std::make_unique<nativeapi::KeyboardEventHandler>(
key_pressed_callback,
key_released_callback,
modifier_keys_changed_callback);
if (on_key_released) {
monitor->key_released_listener_id = monitor->cpp_monitor->AddListener<nativeapi::KeyReleasedEvent>(
[monitor](const nativeapi::KeyReleasedEvent& event) {
monitor->on_key_released(event.GetKeycode(), monitor->user_data);
}
);
}

// Set the event handler on the keyboard monitor
monitor->cpp_monitor->SetEventHandler(monitor->event_handler.get());
if (on_modifier_keys_changed) {
monitor->modifier_keys_listener_id = monitor->cpp_monitor->AddListener<nativeapi::ModifierKeysChangedEvent>(
[monitor](const nativeapi::ModifierKeysChangedEvent& event) {
uint32_t c_modifier_keys = convert_modifier_keys_to_c(event.GetModifierKeys());
monitor->on_modifier_keys_changed(c_modifier_keys, monitor->user_data);
}
);
}

return true;
} catch (...) {
Expand Down
53 changes: 53 additions & 0 deletions src/keyboard_events.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
#pragma once

#include "event.h"
#include "keyboard_monitor.h"

namespace nativeapi {

/**
* Event fired when a key is pressed.
*/
class KeyPressedEvent : public TypedEvent<KeyPressedEvent> {
public:
explicit KeyPressedEvent(int keycode) : keycode_(keycode) {}

int GetKeycode() const { return keycode_; }

std::string GetTypeName() const override { return "KeyPressedEvent"; }

private:
int keycode_;
};

/**
* Event fired when a key is released.
*/
class KeyReleasedEvent : public TypedEvent<KeyReleasedEvent> {
public:
explicit KeyReleasedEvent(int keycode) : keycode_(keycode) {}

int GetKeycode() const { return keycode_; }

std::string GetTypeName() const override { return "KeyReleasedEvent"; }

private:
int keycode_;
};

/**
* Event fired when modifier keys change.
*/
class ModifierKeysChangedEvent : public TypedEvent<ModifierKeysChangedEvent> {
public:
explicit ModifierKeysChangedEvent(uint32_t modifier_keys) : modifier_keys_(modifier_keys) {}

uint32_t GetModifierKeys() const { return modifier_keys_; }

std::string GetTypeName() const override { return "ModifierKeysChangedEvent"; }

private:
uint32_t modifier_keys_;
};

} // namespace nativeapi
35 changes: 0 additions & 35 deletions src/keyboard_monitor.cpp

This file was deleted.

66 changes: 39 additions & 27 deletions src/keyboard_monitor.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
#include <memory>
#include <string>

#include "event_dispatcher.h"
#include "keyboard_events.h"

namespace nativeapi {

enum class ModifierKey : uint32_t {
Expand All @@ -18,37 +21,42 @@ enum class ModifierKey : uint32_t {
ScrollLock = 1 << 7
};

// KeyboardEventHandler uses callbacks to handle keyboard events.
class KeyboardEventHandler {
public:
// Constructor that takes callbacks for keyboard events
KeyboardEventHandler(
std::function<void(int)> onKeyPressedCallback,
std::function<void(int)> onKeyReleasedCallback,
std::function<void(uint32_t)> onModifierKeysChangedCallback);

// Handle key pressed event
void OnKeyPressed(int keycode);

// Handle key released event
void OnKeyReleased(int keycode);
// Bitwise operators for ModifierKey enum
inline ModifierKey operator|(ModifierKey a, ModifierKey b) {
return static_cast<ModifierKey>(static_cast<uint32_t>(a) | static_cast<uint32_t>(b));
}

// Handle modifier keys changed event
void OnModifierKeysChanged(uint32_t modifier_keys);

private:
std::function<void(int)> onKeyPressedCallback_;
std::function<void(int)> onKeyReleasedCallback_;
std::function<void(uint32_t)> onModifierKeysChangedCallback_;
};
inline ModifierKey operator&(ModifierKey a, ModifierKey b) {
return static_cast<ModifierKey>(static_cast<uint32_t>(a) & static_cast<uint32_t>(b));
}

class KeyboardMonitor {
public:
KeyboardMonitor();
virtual ~KeyboardMonitor();

// Set the event handler for the keyboard monitor
void SetEventHandler(KeyboardEventHandler* event_handler);
// Add a listener for keyboard events
template<typename EventType>
size_t AddListener(TypedEventListener<EventType>* listener) {
return event_dispatcher_.AddListener(listener);
}

// Add a callback-based listener for keyboard events
template<typename EventType>
size_t AddListener(std::function<void(const EventType&)> callback) {
return event_dispatcher_.AddListener(std::move(callback));
}

// Remove a listener by ID
bool RemoveListener(size_t listener_id) {
return event_dispatcher_.RemoveListener(listener_id);
}

// Remove all listeners for a specific event type
template<typename EventType>
void RemoveAllListeners() {
event_dispatcher_.RemoveAllListeners<EventType>();
}

// Start the keyboard monitor
void Start();
Expand All @@ -59,13 +67,17 @@ class KeyboardMonitor {
// Check if the keyboard monitor is monitoring
bool IsMonitoring() const;

// Get the event handler
KeyboardEventHandler* GetEventHandler() const { return event_handler_; }
// Get access to the event dispatcher for advanced usage
EventDispatcher& GetEventDispatcher() { return event_dispatcher_; }

private:
class Impl;
std::unique_ptr<Impl> impl_;
KeyboardEventHandler* event_handler_;
EventDispatcher event_dispatcher_;

// Internal method for dispatching events from platform code
void DispatchEvent(const Event& event);
friend class Impl;
};

} // namespace nativeapi
27 changes: 17 additions & 10 deletions src/platform/linux/keyboard_monitor_linux.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ class KeyboardMonitor::Impl {
uint32_t GetModifierState();
};

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

KeyboardMonitor::~KeyboardMonitor() {
Stop();
Expand Down Expand Up @@ -154,15 +154,18 @@ void KeyboardMonitor::Impl::MonitoringLoop() {
if (XGetEventData(display_, &event.xcookie)) {
XIDeviceEvent* xi_event = (XIDeviceEvent*)event.xcookie.data;

auto* eventHandler = monitor_->GetEventHandler();
if (eventHandler) {
if (xi_event->evtype == XI_KeyPress) {
eventHandler->OnKeyPressed(xi_event->detail);
eventHandler->OnModifierKeysChanged(GetModifierState());
} else if (xi_event->evtype == XI_KeyRelease) {
eventHandler->OnKeyReleased(xi_event->detail);
eventHandler->OnModifierKeysChanged(GetModifierState());
}
if (xi_event->evtype == XI_KeyPress) {
KeyPressedEvent key_event(xi_event->detail);
monitor_->DispatchEvent(key_event);

ModifierKeysChangedEvent modifier_event(GetModifierState());
monitor_->DispatchEvent(modifier_event);
} else if (xi_event->evtype == XI_KeyRelease) {
KeyReleasedEvent key_event(xi_event->detail);
monitor_->DispatchEvent(key_event);

ModifierKeysChangedEvent modifier_event(GetModifierState());
monitor_->DispatchEvent(modifier_event);
}

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

void KeyboardMonitor::DispatchEvent(const Event& event) {
event_dispatcher_.DispatchSync(event);
}

} // namespace nativeapi
19 changes: 11 additions & 8 deletions src/platform/macos/keyboard_monitor_macos.mm
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
KeyboardMonitor* monitor_;
};

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

KeyboardMonitor::~KeyboardMonitor() {
Stop();
Expand All @@ -34,17 +34,15 @@ static CGEventRef keyboardEventCallback(CGEventTapProxy proxy,
if (!monitor)
return event;

auto* eventHandler = monitor->GetEventHandler();
if (!eventHandler)
return event;

// Get the key code
CGKeyCode keyCode = (CGKeyCode)CGEventGetIntegerValueField(event, kCGKeyboardEventKeycode);

if (type == kCGEventKeyDown) {
eventHandler->OnKeyPressed(keyCode);
KeyPressedEvent key_event(keyCode);
monitor->DispatchEvent(key_event);
} else if (type == kCGEventKeyUp) {
eventHandler->OnKeyReleased(keyCode);
KeyReleasedEvent key_event(keyCode);
monitor->DispatchEvent(key_event);
} else if (type == kCGEventFlagsChanged) {
CGEventFlags flags = CGEventGetFlags(event);
uint32_t modifier_keys = static_cast<uint32_t>(ModifierKey::None);
Expand All @@ -69,7 +67,8 @@ static CGEventRef keyboardEventCallback(CGEventTapProxy proxy,
if (flags & kCGEventFlagMaskNumericPad) {
modifier_keys |= static_cast<uint32_t>(ModifierKey::NumLock);
}
eventHandler->OnModifierKeysChanged(modifier_keys);
ModifierKeysChangedEvent modifier_event(modifier_keys);
monitor->DispatchEvent(modifier_event);
}
return event;
}
Expand Down Expand Up @@ -131,4 +130,8 @@ static CGEventRef keyboardEventCallback(CGEventTapProxy proxy,
return impl_->eventTap != nullptr;
}

void KeyboardMonitor::DispatchEvent(const Event& event) {
event_dispatcher_.DispatchSync(event);
}

} // namespace nativeapi
Loading