Move send_key_event from FlKeyboardViewDelegate to FlKeyboardManager. (flutter/engine#56020)

Ideally the tests would mock FlEngine, but I wasn't able to get it
working so I've added fl_keyboard_manager_set_send_key_event_handler for
now.
This commit is contained in:
Robert Ancell 2024-10-23 22:05:09 +13:00 committed by GitHub
parent 026062f08b
commit bb8679e23f
6 changed files with 113 additions and 127 deletions

View File

@ -116,8 +116,13 @@ static FlKeyboardManagerUserData* fl_keyboard_manager_user_data_new(
struct _FlKeyboardManager {
GObject parent_instance;
GWeakRef engine;
GWeakRef view_delegate;
FlKeyboardManagerSendKeyEventHandler send_key_event_handler;
gpointer send_key_event_handler_user_data;
FlKeyboardManagerLookupKeyHandler lookup_key_handler;
gpointer lookup_key_handler_user_data;
@ -410,6 +415,7 @@ static void guarantee_layout(FlKeyboardManager* self, FlKeyEvent* event) {
static void fl_keyboard_manager_dispose(GObject* object) {
FlKeyboardManager* self = FL_KEYBOARD_MANAGER(object);
g_weak_ref_clear(&self->engine);
g_weak_ref_clear(&self->view_delegate);
self->keycode_to_goals.reset();
@ -458,29 +464,34 @@ static void fl_keyboard_manager_init(FlKeyboardManager* self) {
}
FlKeyboardManager* fl_keyboard_manager_new(
FlBinaryMessenger* messenger,
FlEngine* engine,
FlKeyboardViewDelegate* view_delegate) {
g_return_val_if_fail(FL_IS_KEYBOARD_VIEW_DELEGATE(view_delegate), nullptr);
FlKeyboardManager* self = FL_KEYBOARD_MANAGER(
g_object_new(fl_keyboard_manager_get_type(), nullptr));
g_weak_ref_init(&self->engine, engine);
g_weak_ref_init(&self->view_delegate, view_delegate);
self->key_embedder_responder = fl_key_embedder_responder_new(
[](const FlutterKeyEvent* event, FlutterKeyEventCallback callback,
void* callback_user_data, void* send_key_event_user_data) {
FlKeyboardManager* self = FL_KEYBOARD_MANAGER(send_key_event_user_data);
g_autoptr(FlKeyboardViewDelegate) view_delegate =
FL_KEYBOARD_VIEW_DELEGATE(g_weak_ref_get(&self->view_delegate));
if (view_delegate == nullptr) {
return;
if (self->send_key_event_handler != nullptr) {
self->send_key_event_handler(event, callback, callback_user_data,
self->send_key_event_handler_user_data);
} else {
g_autoptr(FlEngine) engine = FL_ENGINE(g_weak_ref_get(&self->engine));
if (engine != nullptr) {
fl_engine_send_key_event(engine, event, callback,
callback_user_data);
}
}
fl_keyboard_view_delegate_send_key_event(view_delegate, event, callback,
callback_user_data);
},
self);
self->key_channel_responder = fl_key_channel_responder_new(messenger);
self->key_channel_responder =
fl_key_channel_responder_new(fl_engine_get_binary_messenger(engine));
return self;
}
@ -536,6 +547,15 @@ GHashTable* fl_keyboard_manager_get_pressed_state(FlKeyboardManager* self) {
self->key_embedder_responder);
}
void fl_keyboard_manager_set_send_key_event_handler(
FlKeyboardManager* self,
FlKeyboardManagerSendKeyEventHandler send_key_event_handler,
gpointer user_data) {
g_return_if_fail(FL_IS_KEYBOARD_MANAGER(self));
self->send_key_event_handler = send_key_event_handler;
self->send_key_event_handler_user_data = user_data;
}
void fl_keyboard_manager_set_lookup_key_handler(
FlKeyboardManager* self,
FlKeyboardManagerLookupKeyHandler lookup_key_handler,

View File

@ -8,7 +8,7 @@
#include <gdk/gdk.h>
#include "flutter/shell/platform/linux/fl_keyboard_view_delegate.h"
#include "flutter/shell/platform/linux/public/flutter_linux/fl_binary_messenger.h"
#include "flutter/shell/platform/linux/public/flutter_linux/fl_engine.h"
G_BEGIN_DECLS
@ -36,7 +36,7 @@ G_DECLARE_FINAL_TYPE(FlKeyboardManager,
/**
* fl_keyboard_manager_new:
* @messenger: an #FlBinaryMessenger.
* @engine: an #FlEngine.
* @view_delegate: An interface that the manager requires to communicate with
* the platform. Usually implemented by FlView.
*
@ -45,7 +45,7 @@ G_DECLARE_FINAL_TYPE(FlKeyboardManager,
* Returns: a new #FlKeyboardManager.
*/
FlKeyboardManager* fl_keyboard_manager_new(
FlBinaryMessenger* messenger,
FlEngine* engine,
FlKeyboardViewDelegate* view_delegate);
/**
@ -94,6 +94,23 @@ void fl_keyboard_manager_sync_modifier_if_needed(FlKeyboardManager* manager,
*/
GHashTable* fl_keyboard_manager_get_pressed_state(FlKeyboardManager* manager);
typedef void (*FlKeyboardManagerSendKeyEventHandler)(
const FlutterKeyEvent* event,
FlutterKeyEventCallback callback,
void* callback_user_data,
gpointer user_data);
/**
* fl_keyboard_manager_set_send_key_event_handler:
* @manager: the #FlKeyboardManager self.
*
* Set the handler for sending events, for testing purposes only.
*/
void fl_keyboard_manager_set_send_key_event_handler(
FlKeyboardManager* manager,
FlKeyboardManagerSendKeyEventHandler send_key_event_handler,
gpointer user_data);
typedef guint (*FlKeyboardManagerLookupKeyHandler)(const GdkKeymapKey* key,
gpointer user_data);

View File

@ -233,6 +233,10 @@ static void fl_mock_binary_messenger_set_warns_on_channel_overflow(
// Mock implementation. Do nothing.
}
static void fl_mock_binary_messenger_shutdown(FlBinaryMessenger* messenger) {
// Mock implementation. Do nothing.
}
static void fl_mock_key_binary_messenger_iface_init(
FlBinaryMessengerInterface* iface) {
iface->set_message_handler_on_channel =
@ -257,6 +261,7 @@ static void fl_mock_key_binary_messenger_iface_init(
iface->resize_channel = fl_mock_binary_messenger_resize_channel;
iface->set_warns_on_channel_overflow =
fl_mock_binary_messenger_set_warns_on_channel_overflow;
iface->shutdown = fl_mock_binary_messenger_shutdown;
}
static FlMockKeyBinaryMessenger* fl_mock_key_binary_messenger_new() {
@ -279,9 +284,6 @@ static void fl_mock_key_binary_messenger_set_callback_handler(
struct _FlMockViewDelegate {
GObject parent_instance;
FlMockKeyBinaryMessenger* messenger;
EmbedderCallHandler embedder_handler;
bool text_filter_result;
};
@ -297,30 +299,7 @@ G_DEFINE_TYPE_WITH_CODE(
static void fl_mock_view_delegate_init(FlMockViewDelegate* self) {}
static void fl_mock_view_delegate_dispose(GObject* object) {
FlMockViewDelegate* self = FL_MOCK_VIEW_DELEGATE(object);
g_clear_object(&self->messenger);
G_OBJECT_CLASS(fl_mock_view_delegate_parent_class)->dispose(object);
}
static void fl_mock_view_delegate_class_init(FlMockViewDelegateClass* klass) {
G_OBJECT_CLASS(klass)->dispose = fl_mock_view_delegate_dispose;
}
static void fl_mock_view_keyboard_send_key_event(
FlKeyboardViewDelegate* view_delegate,
const FlutterKeyEvent* event,
FlutterKeyEventCallback callback,
void* user_data) {
FlMockViewDelegate* self = FL_MOCK_VIEW_DELEGATE(view_delegate);
self->embedder_handler(event, [callback, user_data](bool handled) {
if (callback != nullptr) {
callback(handled, user_data);
}
});
}
static void fl_mock_view_delegate_class_init(FlMockViewDelegateClass* klass) {}
static gboolean fl_mock_view_keyboard_text_filter_key_press(
FlKeyboardViewDelegate* view_delegate,
@ -331,7 +310,6 @@ static gboolean fl_mock_view_keyboard_text_filter_key_press(
static void fl_mock_view_keyboard_delegate_iface_init(
FlKeyboardViewDelegateInterface* iface) {
iface->send_key_event = fl_mock_view_keyboard_send_key_event;
iface->text_filter_key_press = fl_mock_view_keyboard_text_filter_key_press;
}
@ -342,16 +320,9 @@ static FlMockViewDelegate* fl_mock_view_delegate_new() {
// Added to stop compiler complaining about an unused function.
FL_IS_MOCK_VIEW_DELEGATE(self);
self->messenger = fl_mock_key_binary_messenger_new();
return self;
}
static void fl_mock_view_set_embedder_handler(FlMockViewDelegate* self,
EmbedderCallHandler handler) {
self->embedder_handler = std::move(handler);
}
static void fl_mock_view_set_text_filter_result(FlMockViewDelegate* self,
bool result) {
self->text_filter_result = result;
@ -362,14 +333,31 @@ static void fl_mock_view_set_text_filter_result(FlMockViewDelegate* self,
class KeyboardTester {
public:
KeyboardTester() {
messenger_ = fl_mock_key_binary_messenger_new();
view_ = fl_mock_view_delegate_new();
respondToEmbedderCallsWith(false);
respondToChannelCallsWith(false);
respondToTextInputWith(false);
setLayout(kLayoutUs);
manager_ = fl_keyboard_manager_new(FL_BINARY_MESSENGER(view_->messenger),
FL_KEYBOARD_VIEW_DELEGATE(view_));
engine_ = FL_ENGINE(g_object_new(fl_engine_get_type(), "binary-messenger",
FL_BINARY_MESSENGER(messenger_), nullptr));
manager_ =
fl_keyboard_manager_new(engine_, FL_KEYBOARD_VIEW_DELEGATE(view_));
fl_keyboard_manager_set_send_key_event_handler(
manager_,
[](const FlutterKeyEvent* event, FlutterKeyEventCallback callback,
void* callback_user_data, gpointer user_data) {
KeyboardTester* self = reinterpret_cast<KeyboardTester*>(user_data);
self->embedder_handler_(event,
[callback, callback_user_data](bool handled) {
if (callback != nullptr) {
callback(handled, callback_user_data);
}
});
},
this);
fl_keyboard_manager_set_lookup_key_handler(
manager_,
[](const GdkKeymapKey* key, gpointer user_data) {
@ -394,6 +382,8 @@ class KeyboardTester {
~KeyboardTester() {
g_clear_object(&view_);
g_clear_object(&messenger_);
g_clear_object(&engine_);
g_clear_object(&manager_);
g_clear_pointer(&redispatched_events_, g_ptr_array_unref);
}
@ -432,53 +422,51 @@ class KeyboardTester {
}
void respondToEmbedderCallsWith(bool response) {
fl_mock_view_set_embedder_handler(
view_, [response, this](const FlutterKeyEvent* event,
const AsyncKeyCallback& callback) {
EXPECT_FALSE(during_redispatch_);
callback(response);
});
embedder_handler_ = [response, this](const FlutterKeyEvent* event,
const AsyncKeyCallback& callback) {
EXPECT_FALSE(during_redispatch_);
callback(response);
};
}
void recordEmbedderCallsTo(std::vector<CallRecord>& storage) {
fl_mock_view_set_embedder_handler(
view_, [&storage, this](const FlutterKeyEvent* event,
AsyncKeyCallback callback) {
EXPECT_FALSE(during_redispatch_);
auto new_event = std::make_unique<FlutterKeyEvent>(*event);
char* new_event_character = cloneString(event->character);
new_event->character = new_event_character;
storage.push_back(CallRecord{
.type = CallRecord::kKeyCallEmbedder,
.callback = std::move(callback),
.event = std::move(new_event),
.event_character = std::unique_ptr<char[]>(new_event_character),
});
});
embedder_handler_ = [&storage, this](const FlutterKeyEvent* event,
AsyncKeyCallback callback) {
EXPECT_FALSE(during_redispatch_);
auto new_event = std::make_unique<FlutterKeyEvent>(*event);
char* new_event_character = cloneString(event->character);
new_event->character = new_event_character;
storage.push_back(CallRecord{
.type = CallRecord::kKeyCallEmbedder,
.callback = std::move(callback),
.event = std::move(new_event),
.event_character = std::unique_ptr<char[]>(new_event_character),
});
};
}
void respondToEmbedderCallsWithAndRecordsTo(
bool response,
std::vector<CallRecord>& storage) {
fl_mock_view_set_embedder_handler(
view_, [&storage, response, this](const FlutterKeyEvent* event,
const AsyncKeyCallback& callback) {
EXPECT_FALSE(during_redispatch_);
auto new_event = std::make_unique<FlutterKeyEvent>(*event);
char* new_event_character = cloneString(event->character);
new_event->character = new_event_character;
storage.push_back(CallRecord{
.type = CallRecord::kKeyCallEmbedder,
.event = std::move(new_event),
.event_character = std::unique_ptr<char[]>(new_event_character),
});
callback(response);
});
embedder_handler_ = [&storage, response, this](
const FlutterKeyEvent* event,
const AsyncKeyCallback& callback) {
EXPECT_FALSE(during_redispatch_);
auto new_event = std::make_unique<FlutterKeyEvent>(*event);
char* new_event_character = cloneString(event->character);
new_event->character = new_event_character;
storage.push_back(CallRecord{
.type = CallRecord::kKeyCallEmbedder,
.event = std::move(new_event),
.event_character = std::unique_ptr<char[]>(new_event_character),
});
callback(response);
};
}
void respondToChannelCallsWith(bool response) {
fl_mock_key_binary_messenger_set_callback_handler(
view_->messenger, [response, this](const AsyncKeyCallback& callback) {
messenger_, [response, this](const AsyncKeyCallback& callback) {
EXPECT_FALSE(during_redispatch_);
callback(response);
});
@ -486,7 +474,7 @@ class KeyboardTester {
void recordChannelCallsTo(std::vector<CallRecord>& storage) {
fl_mock_key_binary_messenger_set_callback_handler(
view_->messenger, [&storage, this](AsyncKeyCallback callback) {
messenger_, [&storage, this](AsyncKeyCallback callback) {
EXPECT_FALSE(during_redispatch_);
storage.push_back(CallRecord{
.type = CallRecord::kKeyCallChannel,
@ -519,10 +507,13 @@ class KeyboardTester {
private:
FlMockViewDelegate* view_;
FlMockKeyBinaryMessenger* messenger_ = nullptr;
FlEngine* engine_ = nullptr;
FlKeyboardManager* manager_ = nullptr;
GPtrArray* redispatched_events_ = nullptr;
bool during_redispatch_ = false;
const MockLayoutData* layout_data_;
EmbedderCallHandler embedder_handler_;
static gboolean _flushChannelMessagesCb(gpointer data) {
g_autoptr(GMainLoop) loop = reinterpret_cast<GMainLoop*>(data);

View File

@ -11,17 +11,6 @@ G_DEFINE_INTERFACE(FlKeyboardViewDelegate,
static void fl_keyboard_view_delegate_default_init(
FlKeyboardViewDelegateInterface* iface) {}
void fl_keyboard_view_delegate_send_key_event(FlKeyboardViewDelegate* self,
const FlutterKeyEvent* event,
FlutterKeyEventCallback callback,
void* user_data) {
g_return_if_fail(FL_IS_KEYBOARD_VIEW_DELEGATE(self));
g_return_if_fail(event != nullptr);
FL_KEYBOARD_VIEW_DELEGATE_GET_IFACE(self)->send_key_event(
self, event, callback, user_data);
}
gboolean fl_keyboard_view_delegate_text_filter_key_press(
FlKeyboardViewDelegate* self,
FlKeyEvent* event) {

View File

@ -34,34 +34,12 @@ G_DECLARE_INTERFACE(FlKeyboardViewDelegate,
struct _FlKeyboardViewDelegateInterface {
GTypeInterface g_iface;
void (*send_key_event)(FlKeyboardViewDelegate* delegate,
const FlutterKeyEvent* event,
FlutterKeyEventCallback callback,
void* user_data);
gboolean (*text_filter_key_press)(FlKeyboardViewDelegate* delegate,
FlKeyEvent* event);
GHashTable* (*get_keyboard_state)(FlKeyboardViewDelegate* delegate);
};
/**
* fl_keyboard_view_delegate_send_key_event:
*
* Handles `FlKeyboardHandler`'s request to send a `FlutterKeyEvent` through the
* embedder API to the framework.
*
* The ownership of the `event` is kept by the keyboard handler, and the `event`
* might be immediately destroyed after this function returns.
*
* The `callback` must eventually be called exactly once with the event result
* and the `user_data`.
*/
void fl_keyboard_view_delegate_send_key_event(FlKeyboardViewDelegate* delegate,
const FlutterKeyEvent* event,
FlutterKeyEventCallback callback,
void* user_data);
/**
* fl_keyboard_view_delegate_text_filter_key_press:
*

View File

@ -151,7 +151,7 @@ static void init_keyboard(FlView* self) {
fl_keyboard_handler_new(messenger, FL_KEYBOARD_VIEW_DELEGATE(self));
g_clear_object(&self->keyboard_manager);
self->keyboard_manager =
fl_keyboard_manager_new(messenger, FL_KEYBOARD_VIEW_DELEGATE(self));
fl_keyboard_manager_new(self->engine, FL_KEYBOARD_VIEW_DELEGATE(self));
}
static void init_scrolling(FlView* self) {
@ -364,15 +364,6 @@ static void fl_view_plugin_registry_iface_init(
static void fl_view_keyboard_delegate_iface_init(
FlKeyboardViewDelegateInterface* iface) {
iface->send_key_event =
[](FlKeyboardViewDelegate* view_delegate, const FlutterKeyEvent* event,
FlutterKeyEventCallback callback, void* user_data) {
FlView* self = FL_VIEW(view_delegate);
if (self->engine != nullptr) {
fl_engine_send_key_event(self->engine, event, callback, user_data);
};
};
iface->text_filter_key_press = [](FlKeyboardViewDelegate* view_delegate,
FlKeyEvent* event) {
FlView* self = FL_VIEW(view_delegate);