1010#include " flutter/shell/platform/linux/public/flutter_linux/fl_basic_message_channel.h"
1111#include " flutter/shell/platform/linux/public/flutter_linux/fl_json_message_codec.h"
1212
13+ // Definition of the FlKeyEventPlugin GObject class.
14+
15+ struct _FlKeyEventPlugin {
16+ GObject parent_instance;
17+
18+ FlBasicMessageChannel* channel = nullptr ;
19+ FlTextInputPlugin* text_input_plugin = nullptr ;
20+ FlKeyEventPluginCallback response_callback = nullptr ;
21+ GPtrArray* pending_events;
22+ };
23+
24+ G_DEFINE_TYPE (FlKeyEventPlugin, fl_key_event_plugin, G_TYPE_OBJECT)
25+
26+ namespace {
27+
1328static constexpr char kChannelName [] = " flutter/keyevent" ;
1429static constexpr char kTypeKey [] = " type" ;
1530static constexpr char kTypeValueUp [] = " keyup" ;
@@ -29,13 +44,11 @@ static constexpr uint64_t kMaxPendingEvents = 1000;
2944// Declare and define a private pair object to bind the id and the event
3045// together.
3146
32- G_BEGIN_DECLS
3347G_DECLARE_FINAL_TYPE (FlKeyEventPair,
3448 fl_key_event_pair,
3549 FL,
3650 KEY_EVENT_PAIR,
3751 GObject);
38- G_END_DECLS
3952
4053struct _FlKeyEventPair {
4154 GObject parent_instance;
@@ -46,18 +59,27 @@ struct _FlKeyEventPair {
4659
4760G_DEFINE_TYPE (FlKeyEventPair, fl_key_event_pair, G_TYPE_OBJECT)
4861
62+ // Dispose method for FlKeyEventPair.
4963static void fl_key_event_pair_dispose (GObject* object) {
64+ // Redundant, but added so that we don't get a warning about unused function
65+ // for FL_IS_KEY_EVENT_PAIR.
5066 g_return_if_fail (FL_IS_KEY_EVENT_PAIR (object));
67+
5168 FlKeyEventPair* self = FL_KEY_EVENT_PAIR (object);
52- gdk_event_free (reinterpret_cast <GdkEvent*>(self->event ));
69+ g_clear_pointer (&self->event , gdk_event_free);
70+ G_OBJECT_CLASS (fl_key_event_pair_parent_class)->dispose (object);
5371}
5472
73+ // Class Initialization method for FlKeyEventPair class.
5574static void fl_key_event_pair_class_init (FlKeyEventPairClass* klass) {
5675 G_OBJECT_CLASS (klass)->dispose = fl_key_event_pair_dispose;
5776}
5877
78+ // Initialization for FlKeyEventPair instances.
5979static void fl_key_event_pair_init (FlKeyEventPair* self) {}
6080
81+ // Creates a new FlKeyEventPair instance, given a unique ID, and an event struct
82+ // to keep.
6183FlKeyEventPair* fl_key_event_pair_new (uint64_t id, GdkEventKey* event) {
6284 FlKeyEventPair* self =
6385 FL_KEY_EVENT_PAIR (g_object_new (fl_key_event_pair_get_type (), nullptr ));
@@ -72,14 +94,11 @@ FlKeyEventPair* fl_key_event_pair_new(uint64_t id, GdkEventKey* event) {
7294}
7395
7496// Declare and define a private class to hold response data from the framework.
75-
76- G_BEGIN_DECLS
7797G_DECLARE_FINAL_TYPE (FlKeyEventResponseData,
7898 fl_key_event_response_data,
7999 FL,
80100 KEY_EVENT_RESPONSE_DATA,
81101 GObject);
82- G_END_DECLS
83102
84103struct _FlKeyEventResponseData {
85104 GObject parent_instance;
@@ -89,8 +108,10 @@ struct _FlKeyEventResponseData {
89108 gpointer user_data;
90109};
91110
111+ // Definition for FlKeyEventResponseData private class.
92112G_DEFINE_TYPE (FlKeyEventResponseData, fl_key_event_response_data, G_TYPE_OBJECT)
93113
114+ // Dispose method for FlKeyEventResponseData private class.
94115static void fl_key_event_response_data_dispose (GObject* object) {
95116 g_return_if_fail (FL_IS_KEY_EVENT_RESPONSE_DATA (object));
96117 FlKeyEventResponseData* self = FL_KEY_EVENT_RESPONSE_DATA (object);
@@ -99,13 +120,18 @@ static void fl_key_event_response_data_dispose(GObject* object) {
99120 reinterpret_cast <gpointer*>(&(self->plugin )));
100121}
101122
123+ // Class initialization method for FlKeyEventResponseData private class.
102124static void fl_key_event_response_data_class_init (
103125 FlKeyEventResponseDataClass* klass) {
104126 G_OBJECT_CLASS (klass)->dispose = fl_key_event_response_data_dispose;
105127}
106128
129+ // Instance initialization method for FlKeyEventResponseData private class.
107130static void fl_key_event_response_data_init (FlKeyEventResponseData* self) {}
108131
132+ // Creates a new FlKeyEventResponseData private class with a plugin that created
133+ // the request, a unique ID for tracking, and optional user data.
134+ // Will keep a weak pointer to the plugin.
109135FlKeyEventResponseData* fl_key_event_response_data_new (FlKeyEventPlugin* plugin,
110136 uint64_t id,
111137 gpointer user_data) {
@@ -122,64 +148,9 @@ FlKeyEventResponseData* fl_key_event_response_data_new(FlKeyEventPlugin* plugin,
122148 return self;
123149}
124150
125- // Definition of the FlKeyEventPlugin GObject class.
126-
127- struct _FlKeyEventPlugin {
128- GObject parent_instance;
129-
130- FlBasicMessageChannel* channel = nullptr ;
131- FlTextInputPlugin* text_input_plugin = nullptr ;
132- FlKeyEventPluginCallback response_callback = nullptr ;
133- GPtrArray* pending_events;
134- };
135-
136- G_DEFINE_TYPE (FlKeyEventPlugin, fl_key_event_plugin, G_TYPE_OBJECT)
137-
138- static void fl_key_event_plugin_dispose(GObject* object) {
139- FlKeyEventPlugin* self = FL_KEY_EVENT_PLUGIN (object);
140-
141- g_clear_object (&self->channel );
142- g_object_remove_weak_pointer (
143- G_OBJECT (self->text_input_plugin ),
144- reinterpret_cast <gpointer*>(&(self->text_input_plugin )));
145- g_ptr_array_free (self->pending_events , TRUE );
146-
147- G_OBJECT_CLASS (fl_key_event_plugin_parent_class)->dispose (object);
148- }
149-
150- static void fl_key_event_plugin_class_init (FlKeyEventPluginClass* klass) {
151- G_OBJECT_CLASS (klass)->dispose = fl_key_event_plugin_dispose;
152- }
153-
154- static void fl_key_event_plugin_init (FlKeyEventPlugin* self) {}
155-
156- FlKeyEventPlugin* fl_key_event_plugin_new (
157- FlBinaryMessenger* messenger,
158- FlTextInputPlugin* text_input_plugin,
159- FlKeyEventPluginCallback response_callback,
160- const char * channel_name) {
161- g_return_val_if_fail (FL_IS_BINARY_MESSENGER (messenger), nullptr );
162- g_return_val_if_fail (FL_IS_TEXT_INPUT_PLUGIN (text_input_plugin), nullptr );
163-
164- FlKeyEventPlugin* self = FL_KEY_EVENT_PLUGIN (
165- g_object_new (fl_key_event_plugin_get_type (), nullptr ));
166-
167- g_autoptr (FlJsonMessageCodec) codec = fl_json_message_codec_new ();
168- self->channel = fl_basic_message_channel_new (
169- messenger, channel_name == nullptr ? kChannelName : channel_name,
170- FL_MESSAGE_CODEC (codec));
171- self->response_callback = response_callback;
172- // Add a weak pointer so we know if the text input plugin goes away.
173- g_object_add_weak_pointer (
174- G_OBJECT (text_input_plugin),
175- reinterpret_cast <gpointer*>(&(self->text_input_plugin )));
176- self->text_input_plugin = text_input_plugin;
177-
178- self->pending_events = g_ptr_array_new_with_free_func (g_object_unref);
179- return self;
180- }
181-
182- uint64_t fl_get_event_id (GdkEventKey* event) {
151+ // Calculates a unique ID for a given GdkEventKey object to use for
152+ // identification of responses from the framework.
153+ static uint64_t get_event_id (GdkEventKey* event) {
183154 // Combine the event timestamp, the type of event, and the hardware keycode
184155 // (scan code) of the event to come up with a unique id for this event that
185156 // can be derived solely from the event data itself, so that we can identify
@@ -189,7 +160,8 @@ uint64_t fl_get_event_id(GdkEventKey* event) {
189160 (static_cast <uint64_t >(event->hardware_keycode ) & 0xffff ) << 48 ;
190161}
191162
192- GdkEventKey* fl_find_pending_event (FlKeyEventPlugin* self, uint64_t id) {
163+ // Finds an event in the event queue that was sent to the framework by its ID.
164+ static GdkEventKey* find_pending_event (FlKeyEventPlugin* self, uint64_t id) {
193165 if (self->pending_events ->len == 0 ||
194166 FL_KEY_EVENT_PAIR (g_ptr_array_index (self->pending_events , 0 ))->id != id) {
195167 return nullptr ;
@@ -198,7 +170,8 @@ GdkEventKey* fl_find_pending_event(FlKeyEventPlugin* self, uint64_t id) {
198170 return FL_KEY_EVENT_PAIR (g_ptr_array_index (self->pending_events , 0 ))->event ;
199171}
200172
201- void fl_remove_pending_event (FlKeyEventPlugin* self, uint64_t id) {
173+ // Removes an event from the pending event queue.
174+ static void remove_pending_event (FlKeyEventPlugin* self, uint64_t id) {
202175 if (self->pending_events ->len == 0 ||
203176 FL_KEY_EVENT_PAIR (g_ptr_array_index (self->pending_events , 0 ))->id != id) {
204177 g_warning (
@@ -210,9 +183,11 @@ void fl_remove_pending_event(FlKeyEventPlugin* self, uint64_t id) {
210183 g_ptr_array_remove_index (self->pending_events , 0 );
211184}
212185
213- void fl_add_pending_event (FlKeyEventPlugin* self,
214- uint64_t id,
215- GdkEventKey* event) {
186+ // Adds an GdkEventKey to the pending event queue, with a unique ID, and the
187+ // plugin that added it.
188+ static void add_pending_event (FlKeyEventPlugin* self,
189+ uint64_t id,
190+ GdkEventKey* event) {
216191 if (self->pending_events ->len > kMaxPendingEvents ) {
217192 g_warning (
218193 " There are %d keyboard events that have not yet received a "
@@ -222,14 +197,18 @@ void fl_add_pending_event(FlKeyEventPlugin* self,
222197 g_ptr_array_add (self->pending_events , fl_key_event_pair_new (id, event));
223198}
224199
225- void fl_handle_response (GObject* object,
226- GAsyncResult* result,
227- gpointer user_data) {
200+ // Handles a response from the framework to a key event sent to the framework
201+ // earlier.
202+ static void handle_response (GObject* object,
203+ GAsyncResult* result,
204+ gpointer user_data) {
228205 g_autoptr (FlKeyEventResponseData) data =
229206 FL_KEY_EVENT_RESPONSE_DATA (user_data);
230207
231208 // Will also return if the weak pointer has been destroyed.
232- g_return_if_fail (FL_IS_KEY_EVENT_PLUGIN (data->plugin ));
209+ if (data->plugin == nullptr ) {
210+ return ;
211+ }
233212
234213 FlKeyEventPlugin* self = data->plugin ;
235214
@@ -238,14 +217,13 @@ void fl_handle_response(GObject* object,
238217 FlValue* message =
239218 fl_basic_message_channel_send_finish (messageChannel, result, &error);
240219 if (error != nullptr ) {
241- g_error (" Unable to retrieve framework response: %s" , error->message );
242- g_error_free (error);
220+ g_warning (" Unable to retrieve framework response: %s" , error->message );
243221 return ;
244222 }
245223 g_autoptr (FlValue) handled_value = fl_value_lookup_string (message, " handled" );
246- bool handled = false ;
224+ bool handled = FALSE ;
247225 if (handled_value != nullptr ) {
248- GdkEventKey* event = fl_find_pending_event (self, data->id );
226+ GdkEventKey* event = find_pending_event (self, data->id );
249227 if (event == nullptr ) {
250228 g_warning (
251229 " Event response for event id %ld received, but event was received "
@@ -273,33 +251,88 @@ void fl_handle_response(GObject* object,
273251 if (handled) {
274252 // Because the event was handled, we no longer need to track it. Unhandled
275253 // events will be removed when the event is re-dispatched to the window.
276- fl_remove_pending_event (self, data->id );
254+ remove_pending_event (self, data->id );
277255 }
278256
279257 if (self->response_callback != nullptr ) {
280258 self->response_callback (object, message, handled, data->user_data );
281259 }
282260}
283261
262+ // Disposes of an FlKeyEventPlugin instance.
263+ static void fl_key_event_plugin_dispose (GObject* object) {
264+ FlKeyEventPlugin* self = FL_KEY_EVENT_PLUGIN (object);
265+
266+ g_clear_object (&self->channel );
267+ g_object_remove_weak_pointer (
268+ G_OBJECT (self->text_input_plugin ),
269+ reinterpret_cast <gpointer*>(&(self->text_input_plugin )));
270+ g_ptr_array_free (self->pending_events , TRUE );
271+
272+ G_OBJECT_CLASS (fl_key_event_plugin_parent_class)->dispose (object);
273+ }
274+
275+ } // namespace
276+
277+ // Initializes the FlKeyEventPlugin class methods.
278+ static void fl_key_event_plugin_class_init (FlKeyEventPluginClass* klass) {
279+ G_OBJECT_CLASS (klass)->dispose = fl_key_event_plugin_dispose;
280+ }
281+
282+ // Initializes an FlKeyEventPlugin instance.
283+ static void fl_key_event_plugin_init (FlKeyEventPlugin* self) {}
284+
285+ // Creates a new FlKeyEventPlugin instance, with a messenger used to send
286+ // messages to the framework, an FlTextInputPlugin used to handle key events
287+ // that the framework doesn't handle. Mainly for testing purposes, it also takes
288+ // an optional callback to call when a response is received, and an optional
289+ // channel name to use when sending messages.
290+ FlKeyEventPlugin* fl_key_event_plugin_new (
291+ FlBinaryMessenger* messenger,
292+ FlTextInputPlugin* text_input_plugin,
293+ FlKeyEventPluginCallback response_callback,
294+ const char * channel_name) {
295+ g_return_val_if_fail (FL_IS_BINARY_MESSENGER (messenger), nullptr );
296+ g_return_val_if_fail (FL_IS_TEXT_INPUT_PLUGIN (text_input_plugin), nullptr );
297+
298+ FlKeyEventPlugin* self = FL_KEY_EVENT_PLUGIN (
299+ g_object_new (fl_key_event_plugin_get_type (), nullptr ));
300+
301+ g_autoptr (FlJsonMessageCodec) codec = fl_json_message_codec_new ();
302+ self->channel = fl_basic_message_channel_new (
303+ messenger, channel_name == nullptr ? kChannelName : channel_name,
304+ FL_MESSAGE_CODEC (codec));
305+ self->response_callback = response_callback;
306+ // Add a weak pointer so we know if the text input plugin goes away.
307+ g_object_add_weak_pointer (
308+ G_OBJECT (text_input_plugin),
309+ reinterpret_cast <gpointer*>(&(self->text_input_plugin )));
310+ self->text_input_plugin = text_input_plugin;
311+
312+ self->pending_events = g_ptr_array_new_with_free_func (g_object_unref);
313+ return self;
314+ }
315+
316+ // Sends a key event to the framework.
284317bool fl_key_event_plugin_send_key_event (FlKeyEventPlugin* self,
285318 GdkEventKey* event,
286319 gpointer user_data) {
287- g_return_val_if_fail (FL_IS_KEY_EVENT_PLUGIN (self), false );
288- g_return_val_if_fail (event != nullptr , false );
320+ g_return_val_if_fail (FL_IS_KEY_EVENT_PLUGIN (self), FALSE );
321+ g_return_val_if_fail (event != nullptr , FALSE );
289322
290323 // Get an ID for the event, so we can match them up when we get a response
291324 // from the framework. Use the event time, type, and hardware keycode as a
292325 // unique ID, since they are part of the event structure that we can look up
293326 // when we receive a random event that may or may not have been
294327 // tracked/produced by this code.
295- uint64_t id = fl_get_event_id (event);
328+ uint64_t id = get_event_id (event);
296329 if (self->pending_events ->len != 0 &&
297330 FL_KEY_EVENT_PAIR (g_ptr_array_index (self->pending_events , 0 ))->id == id) {
298331 // If the event is at the head of the queue of pending events we've seen,
299332 // and has the same id, then we know that this is a re-dispatched event, and
300333 // we shouldn't respond to it, but we should remove it from tracking.
301- fl_remove_pending_event (self, id);
302- return false ;
334+ remove_pending_event (self, id);
335+ return FALSE ;
303336 }
304337
305338 const gchar* type;
@@ -311,7 +344,7 @@ bool fl_key_event_plugin_send_key_event(FlKeyEventPlugin* self,
311344 type = kTypeValueUp ;
312345 break ;
313346 default :
314- return false ;
347+ return FALSE ;
315348 }
316349
317350 int64_t scan_code = event->hardware_keycode ;
@@ -345,9 +378,9 @@ bool fl_key_event_plugin_send_key_event(FlKeyEventPlugin* self,
345378 // Remove lock states from state mask.
346379 guint state = event->state & ~(GDK_LOCK_MASK | GDK_MOD2_MASK);
347380
348- static bool shift_lock_pressed = false ;
349- static bool caps_lock_pressed = false ;
350- static bool num_lock_pressed = false ;
381+ static bool shift_lock_pressed = FALSE ;
382+ static bool caps_lock_pressed = FALSE ;
383+ static bool num_lock_pressed = FALSE ;
351384 switch (event->keyval ) {
352385 case GDK_KEY_Num_Lock:
353386 num_lock_pressed = event->type == GDK_KEY_PRESS;
@@ -381,13 +414,13 @@ bool fl_key_event_plugin_send_key_event(FlKeyEventPlugin* self,
381414 }
382415
383416 // Track the event as pending a response from the framework.
384- fl_add_pending_event (self, id, event);
417+ add_pending_event (self, id, event);
385418 FlKeyEventResponseData* data =
386419 fl_key_event_response_data_new (self, id, user_data);
387420 // Send the message off to the framework for handling (or not).
388421 fl_basic_message_channel_send (self->channel , message, nullptr ,
389- fl_handle_response , data);
422+ handle_response , data);
390423 // Return true before we know what the framework will do, because if it
391424 // doesn't handle the key, we'll re-dispatch it later.
392- return true ;
425+ return TRUE ;
393426}
0 commit comments