Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
Classes | Macros | Functions | Variables
fl_keyboard_manager.cc File Reference
#include "flutter/shell/platform/linux/fl_keyboard_manager.h"
#include <array>
#include <cinttypes>
#include <memory>
#include <string>
#include "flutter/shell/platform/linux/fl_key_channel_responder.h"
#include "flutter/shell/platform/linux/fl_key_embedder_responder.h"
#include "flutter/shell/platform/linux/key_mapping.h"
#include "flutter/shell/platform/linux/public/flutter_linux/fl_method_channel.h"
#include "flutter/shell/platform/linux/public/flutter_linux/fl_standard_method_codec.h"

Go to the source code of this file.

Classes

struct  _FlKeyboardPendingEvent
 
struct  _FlKeyboardManagerUserData
 
struct  _FlKeyboardManager
 

Macros

#define DEBUG_PRINT_LAYOUT
 
#define FL_TYPE_KEYBOARD_MANAGER_USER_DATA    fl_keyboard_manager_user_data_get_type()
 

Functions

 G_DECLARE_FINAL_TYPE (FlKeyboardPendingEvent, fl_keyboard_pending_event, FL, KEYBOARD_PENDING_EVENT, GObject)
 
 G_DECLARE_FINAL_TYPE (FlKeyboardManagerUserData, fl_keyboard_manager_user_data, FL, KEYBOARD_MANAGER_USER_DATA, GObject)
 
static uint64_t get_logical_key_from_layout (const FlKeyEvent *event, const DerivedLayout &layout)
 
static void fl_keyboard_pending_event_dispose (GObject *object)
 
static void fl_keyboard_pending_event_class_init (FlKeyboardPendingEventClass *klass)
 
static void fl_keyboard_pending_event_init (FlKeyboardPendingEvent *self)
 
static uint64_t fl_keyboard_manager_get_event_hash (FlKeyEvent *event)
 
static FlKeyboardPendingEvent * fl_keyboard_pending_event_new (std::unique_ptr< FlKeyEvent > event, uint64_t sequence_id, size_t to_reply)
 
 G_DEFINE_TYPE (FlKeyboardManagerUserData, fl_keyboard_manager_user_data, G_TYPE_OBJECT) static void fl_keyboard_manager_user_data_dispose(GObject *object)
 
static void fl_keyboard_manager_user_data_class_init (FlKeyboardManagerUserDataClass *klass)
 
static void fl_keyboard_manager_user_data_init (FlKeyboardManagerUserData *self)
 
static FlKeyboardManagerUserData * fl_keyboard_manager_user_data_new (FlKeyboardManager *manager, uint64_t sequence_id)
 
 G_DEFINE_TYPE (FlKeyboardManager, fl_keyboard_manager, G_TYPE_OBJECT)
 
static void fl_keyboard_manager_dispose (GObject *object)
 
static void fl_keyboard_manager_class_init (FlKeyboardManagerClass *klass)
 
static void fl_keyboard_manager_init (FlKeyboardManager *self)
 
static gboolean g_ptr_array_find_with_equal_func1 (GPtrArray *haystack, gconstpointer needle, GEqualFunc equal_func, guint *index_)
 
static gboolean compare_pending_by_sequence_id (gconstpointer pending, gconstpointer needle_sequence_id)
 
static gboolean compare_pending_by_hash (gconstpointer pending, gconstpointer needle_hash)
 
static bool fl_keyboard_manager_remove_redispatched (FlKeyboardManager *self, uint64_t hash)
 
static void responder_handle_event_callback (bool handled, gpointer user_data_ptr)
 
static uint16_t convert_key_to_char (FlKeyboardViewDelegate *view_delegate, guint keycode, gint group, gint level)
 
static void guarantee_layout (FlKeyboardManager *self, FlKeyEvent *event)
 
FlMethodResponse * get_keyboard_state (FlKeyboardManager *self)
 
static void method_call_handler (FlMethodChannel *channel, FlMethodCall *method_call, gpointer user_data)
 
FlKeyboardManagerfl_keyboard_manager_new (FlBinaryMessenger *messenger, FlKeyboardViewDelegate *view_delegate)
 
static void dispatch_to_responder (gpointer responder_data, gpointer foreach_data_ptr)
 
gboolean fl_keyboard_manager_handle_event (FlKeyboardManager *self, FlKeyEvent *event)
 
gboolean fl_keyboard_manager_is_state_clear (FlKeyboardManager *self)
 
void fl_keyboard_manager_sync_modifier_if_needed (FlKeyboardManager *self, guint state, double event_time)
 
GHashTable * fl_keyboard_manager_get_pressed_state (FlKeyboardManager *self)
 

Variables

static constexpr char kChannelName [] = "flutter/keyboard"
 
static constexpr char kGetKeyboardStateMethod [] = "getKeyboardState"
 

Macro Definition Documentation

◆ DEBUG_PRINT_LAYOUT

#define DEBUG_PRINT_LAYOUT

Definition at line 20 of file fl_keyboard_manager.cc.

◆ FL_TYPE_KEYBOARD_MANAGER_USER_DATA

#define FL_TYPE_KEYBOARD_MANAGER_USER_DATA    fl_keyboard_manager_user_data_get_type()

Definition at line 33 of file fl_keyboard_manager.cc.

43 {
44
45// The maxiumum keycode in a derived layout.
46//
47// Although X supports higher keycodes, Flutter only cares about standard keys,
48// which are below this.
49constexpr size_t kLayoutSize = 128;
50// Describes the derived layout of a keyboard group.
51//
52// Maps from keycode to logical key. Value being 0 stands for empty.
53typedef std::array<uint64_t, kLayoutSize> DerivedGroupLayout;
54// Describes the derived layout of the entire keyboard.
55//
56// Maps from group ID to group layout.
57typedef std::map<guint8, DerivedGroupLayout> DerivedLayout;
58
59// Context variables for the foreach call used to dispatch events to responders.
60typedef struct {
62 uint64_t specified_logical_key;
63 FlKeyboardManagerUserData* user_data;
64} DispatchToResponderLoopContext;
65
66bool is_eascii(uint16_t character) {
67 return character < 256;
68}
69
70#ifdef DEBUG_PRINT_LAYOUT
71// Prints layout entries that will be parsed by `MockLayoutData`.
72void debug_format_layout_data(std::string& debug_layout_data,
73 uint16_t keycode,
74 uint16_t clue1,
75 uint16_t clue2) {
76 if (keycode % 4 == 0) {
77 debug_layout_data.append(" ");
78 }
79
80 constexpr int kBufferSize = 30;
81 char buffer[kBufferSize];
82 buffer[0] = 0;
83 buffer[kBufferSize - 1] = 0;
84
85 snprintf(buffer, kBufferSize, "0x%04x, 0x%04x, ", clue1, clue2);
86 debug_layout_data.append(buffer);
87
88 if (keycode % 4 == 3) {
89 snprintf(buffer, kBufferSize, " // 0x%02x", keycode);
90 debug_layout_data.append(buffer);
91 }
92}
93#endif
94
95} // namespace
96
97static uint64_t get_logical_key_from_layout(const FlKeyEvent* event,
98 const DerivedLayout& layout) {
99 guint8 group = event->group;
100 guint16 keycode = event->keycode;
101 if (keycode >= kLayoutSize) {
102 return 0;
103 }
104
105 auto found_group_layout = layout.find(group);
106 if (found_group_layout != layout.end()) {
107 return found_group_layout->second[keycode];
108 }
109 return 0;
110}
111
112/* Define FlKeyboardPendingEvent */
113
114/**
115 * FlKeyboardPendingEvent:
116 * A record for events that have been received by the manager, but
117 * dispatched to other objects, whose results have yet to return.
118 *
119 * This object is used by both the "pending_responds" list and the
120 * "pending_redispatches" list.
121 */
122
124 GObject parent_instance;
125
126 // The target event.
127 //
128 // This is freed by #FlKeyboardPendingEvent if not null.
129 std::unique_ptr<FlKeyEvent> event;
130
131 // Self-incrementing ID attached to an event sent to the framework.
132 //
133 // Used to identify pending responds.
134 uint64_t sequence_id;
135 // The number of responders that haven't replied.
136 size_t unreplied;
137 // Whether any replied responders reported true (handled).
138 bool any_handled;
139
140 // A value calculated out of critical event information that can be used
141 // to identify redispatched events.
142 uint64_t hash;
143};
144
145G_DEFINE_TYPE(FlKeyboardPendingEvent, fl_keyboard_pending_event, G_TYPE_OBJECT)
146
147static void fl_keyboard_pending_event_dispose(GObject* object) {
148 // Redundant, but added so that we don't get a warning about unused function
149 // for FL_IS_KEYBOARD_PENDING_EVENT.
150 g_return_if_fail(FL_IS_KEYBOARD_PENDING_EVENT(object));
151
152 FlKeyboardPendingEvent* self = FL_KEYBOARD_PENDING_EVENT(object);
153 if (self->event != nullptr) {
154 fl_key_event_dispose(self->event.release());
155 }
156 G_OBJECT_CLASS(fl_keyboard_pending_event_parent_class)->dispose(object);
157}
158
160 FlKeyboardPendingEventClass* klass) {
161 G_OBJECT_CLASS(klass)->dispose = fl_keyboard_pending_event_dispose;
162}
163
164static void fl_keyboard_pending_event_init(FlKeyboardPendingEvent* self) {}
165
166// Calculates a unique ID for a given FlKeyEvent object to use for
167// identification of responses from the framework.
169 // Combine the event timestamp, the type of event, and the hardware keycode
170 // (scan code) of the event to come up with a unique id for this event that
171 // can be derived solely from the event data itself, so that we can identify
172 // whether or not we have seen this event already.
173 guint64 type =
174 static_cast<uint64_t>(event->is_press ? GDK_KEY_PRESS : GDK_KEY_RELEASE);
175 guint64 keycode = static_cast<uint64_t>(event->keycode);
176 return (event->time & 0xffffffff) | ((type & 0xffff) << 32) |
177 ((keycode & 0xffff) << 48);
178}
179
180// Create a new FlKeyboardPendingEvent by providing the target event,
181// the sequence ID, and the number of responders that will reply.
182//
183// This will acquire the ownership of the event.
184static FlKeyboardPendingEvent* fl_keyboard_pending_event_new(
185 std::unique_ptr<FlKeyEvent> event,
186 uint64_t sequence_id,
187 size_t to_reply) {
188 FlKeyboardPendingEvent* self = FL_KEYBOARD_PENDING_EVENT(
189 g_object_new(fl_keyboard_pending_event_get_type(), nullptr));
190
191 self->event = std::move(event);
192 self->sequence_id = sequence_id;
193 self->unreplied = to_reply;
194 self->any_handled = false;
195 self->hash = fl_keyboard_manager_get_event_hash(self->event.get());
196 return self;
197}
198
199/* Define FlKeyboardManagerUserData */
200
201/**
202 * FlKeyboardManagerUserData:
203 * The user_data used when #FlKeyboardManager sends event to
204 * responders.
205 */
206
208 GObject parent_instance;
209
210 // A weak reference to the owner manager.
212 uint64_t sequence_id;
213};
214
215G_DEFINE_TYPE(FlKeyboardManagerUserData,
216 fl_keyboard_manager_user_data,
217 G_TYPE_OBJECT)
218
219static void fl_keyboard_manager_user_data_dispose(GObject* object) {
220 g_return_if_fail(FL_IS_KEYBOARD_MANAGER_USER_DATA(object));
221 FlKeyboardManagerUserData* self = FL_KEYBOARD_MANAGER_USER_DATA(object);
222 if (self->manager != nullptr) {
223 g_object_remove_weak_pointer(G_OBJECT(self->manager),
224 reinterpret_cast<gpointer*>(&(self->manager)));
225 self->manager = nullptr;
226 }
227}
228
230 FlKeyboardManagerUserDataClass* klass) {
231 G_OBJECT_CLASS(klass)->dispose = fl_keyboard_manager_user_data_dispose;
232}
233
235 FlKeyboardManagerUserData* self) {}
236
237// Creates a new FlKeyboardManagerUserData private class with all information.
238static FlKeyboardManagerUserData* fl_keyboard_manager_user_data_new(
239 FlKeyboardManager* manager,
240 uint64_t sequence_id) {
241 FlKeyboardManagerUserData* self = FL_KEYBOARD_MANAGER_USER_DATA(
242 g_object_new(fl_keyboard_manager_user_data_get_type(), nullptr));
243
244 self->manager = manager;
245 // Add a weak pointer so we can know if the key event responder disappeared
246 // while the framework was responding.
247 g_object_add_weak_pointer(G_OBJECT(manager),
248 reinterpret_cast<gpointer*>(&(self->manager)));
249 self->sequence_id = sequence_id;
250 return self;
251}
252
253/* Define FlKeyboardManager */
254
255struct _FlKeyboardManager {
256 GObject parent_instance;
257
258 FlKeyboardViewDelegate* view_delegate;
259
260 // An array of #FlKeyResponder. Elements are added with
261 // #fl_keyboard_manager_add_responder immediately after initialization and are
262 // automatically released on dispose.
263 GPtrArray* responder_list;
264
265 // An array of #FlKeyboardPendingEvent.
266 //
267 // Its elements are *not* unreferenced when removed. When FlKeyboardManager is
268 // disposed, this array will be set with a free_func so that the elements are
269 // unreferenced when removed.
270 GPtrArray* pending_responds;
271
272 // An array of #FlKeyboardPendingEvent.
273 //
274 // Its elements are unreferenced when removed.
275 GPtrArray* pending_redispatches;
276
277 // The last sequence ID used. Increased by 1 by every use.
278 uint64_t last_sequence_id;
279
280 // Record the derived layout.
281 //
282 // It is cleared when the platform reports a layout switch. Each entry,
283 // which corresponds to a group, is only initialized on the arrival of the
284 // first event for that group that has a goal keycode.
285 std::unique_ptr<DerivedLayout> derived_layout;
286 // A static map from keycodes to all layout goals.
287 //
288 // It is set up when the manager is initialized and is not changed ever after.
289 std::unique_ptr<std::map<uint16_t, const LayoutGoal*>> keycode_to_goals;
290 // A static map from logical keys to all mandatory layout goals.
291 //
292 // It is set up when the manager is initialized and is not changed ever after.
293 std::unique_ptr<std::map<uint64_t, const LayoutGoal*>>
295
296 // The channel used by the framework to query the keyboard pressed state.
297 FlMethodChannel* channel;
298};
299
300G_DEFINE_TYPE(FlKeyboardManager, fl_keyboard_manager, G_TYPE_OBJECT);
301
302static void fl_keyboard_manager_dispose(GObject* object);
303
304static void fl_keyboard_manager_class_init(FlKeyboardManagerClass* klass) {
305 G_OBJECT_CLASS(klass)->dispose = fl_keyboard_manager_dispose;
306}
307
309 self->derived_layout = std::make_unique<DerivedLayout>();
310
311 self->keycode_to_goals =
312 std::make_unique<std::map<uint16_t, const LayoutGoal*>>();
313 self->logical_to_mandatory_goals =
314 std::make_unique<std::map<uint64_t, const LayoutGoal*>>();
315 for (const LayoutGoal& goal : layout_goals) {
316 (*self->keycode_to_goals)[goal.keycode] = &goal;
317 if (goal.mandatory) {
318 (*self->logical_to_mandatory_goals)[goal.logical_key] = &goal;
319 }
320 }
321
322 self->responder_list = g_ptr_array_new_with_free_func(g_object_unref);
323
324 self->pending_responds = g_ptr_array_new();
325 self->pending_redispatches = g_ptr_array_new_with_free_func(g_object_unref);
326
327 self->last_sequence_id = 1;
328}
329
330static void fl_keyboard_manager_dispose(GObject* object) {
331 FlKeyboardManager* self = FL_KEYBOARD_MANAGER(object);
332
333 if (self->view_delegate != nullptr) {
335 nullptr);
336 g_object_remove_weak_pointer(
337 G_OBJECT(self->view_delegate),
338 reinterpret_cast<gpointer*>(&(self->view_delegate)));
339 self->view_delegate = nullptr;
340 }
341
342 self->derived_layout.reset();
343 self->keycode_to_goals.reset();
344 self->logical_to_mandatory_goals.reset();
345
346 g_ptr_array_free(self->responder_list, TRUE);
347 g_ptr_array_set_free_func(self->pending_responds, g_object_unref);
348 g_ptr_array_free(self->pending_responds, TRUE);
349 g_ptr_array_free(self->pending_redispatches, TRUE);
350
351 G_OBJECT_CLASS(fl_keyboard_manager_parent_class)->dispose(object);
352}
353
354/* Implement FlKeyboardManager */
355
356// This is an exact copy of g_ptr_array_find_with_equal_func. Somehow CI
357// reports that can not find symbol g_ptr_array_find_with_equal_func, despite
358// the fact that it runs well locally.
359static gboolean g_ptr_array_find_with_equal_func1(GPtrArray* haystack,
360 gconstpointer needle,
361 GEqualFunc equal_func,
362 guint* index_) {
363 guint i;
364 g_return_val_if_fail(haystack != NULL, FALSE);
365 if (equal_func == NULL) {
366 equal_func = g_direct_equal;
367 }
368 for (i = 0; i < haystack->len; i++) {
369 if (equal_func(g_ptr_array_index(haystack, i), needle)) {
370 if (index_ != NULL) {
371 *index_ = i;
372 }
373 return TRUE;
374 }
375 }
376
377 return FALSE;
378}
379
380// Compare a #FlKeyboardPendingEvent with the given sequence_id. The needle
381// should be a pointer to uint64_t sequence_id.
382static gboolean compare_pending_by_sequence_id(
383 gconstpointer pending,
384 gconstpointer needle_sequence_id) {
385 uint64_t sequence_id = *reinterpret_cast<const uint64_t*>(needle_sequence_id);
386 return static_cast<const FlKeyboardPendingEvent*>(pending)->sequence_id ==
387 sequence_id;
388}
389
390// Compare a #FlKeyboardPendingEvent with the given hash. The #needle should be
391// a pointer to uint64_t hash.
392static gboolean compare_pending_by_hash(gconstpointer pending,
393 gconstpointer needle_hash) {
394 uint64_t hash = *reinterpret_cast<const uint64_t*>(needle_hash);
395 return static_cast<const FlKeyboardPendingEvent*>(pending)->hash == hash;
396}
397
398// Try to remove a pending event from `pending_redispatches` with the target
399// hash.
400//
401// Returns true if the event is found and removed.
403 uint64_t hash) {
404 guint result_index;
405 gboolean found = g_ptr_array_find_with_equal_func1(
406 self->pending_redispatches, static_cast<const uint64_t*>(&hash),
407 compare_pending_by_hash, &result_index);
408 if (found) {
409 // The removed object is freed due to `pending_redispatches`'s free_func.
410 g_ptr_array_remove_index_fast(self->pending_redispatches, result_index);
411 return TRUE;
412 } else {
413 return FALSE;
414 }
415}
416
417// The callback used by a responder after the event was dispatched.
418static void responder_handle_event_callback(bool handled,
419 gpointer user_data_ptr) {
420 g_return_if_fail(FL_IS_KEYBOARD_MANAGER_USER_DATA(user_data_ptr));
421 FlKeyboardManagerUserData* user_data =
422 FL_KEYBOARD_MANAGER_USER_DATA(user_data_ptr);
423 FlKeyboardManager* self = user_data->manager;
424 g_return_if_fail(self->view_delegate != nullptr);
425
426 guint result_index = -1;
427 gboolean found = g_ptr_array_find_with_equal_func1(
428 self->pending_responds, &user_data->sequence_id,
429 compare_pending_by_sequence_id, &result_index);
430 g_return_if_fail(found);
431 FlKeyboardPendingEvent* pending = FL_KEYBOARD_PENDING_EVENT(
432 g_ptr_array_index(self->pending_responds, result_index));
433 g_return_if_fail(pending != nullptr);
434 g_return_if_fail(pending->unreplied > 0);
435 pending->unreplied -= 1;
436 pending->any_handled = pending->any_handled || handled;
437 // All responders have replied.
438 if (pending->unreplied == 0) {
439 g_object_unref(user_data_ptr);
440 gpointer removed =
441 g_ptr_array_remove_index_fast(self->pending_responds, result_index);
442 g_return_if_fail(removed == pending);
443 bool should_redispatch = !pending->any_handled &&
445 self->view_delegate, pending->event.get());
446 if (should_redispatch) {
447 g_ptr_array_add(self->pending_redispatches, pending);
449 std::move(pending->event));
450 } else {
451 g_object_unref(pending);
452 }
453 }
454}
455
456static uint16_t convert_key_to_char(FlKeyboardViewDelegate* view_delegate,
457 guint keycode,
458 gint group,
459 gint level) {
460 GdkKeymapKey key = {keycode, group, level};
461 constexpr int kBmpMax = 0xD7FF;
462 guint origin = fl_keyboard_view_delegate_lookup_key(view_delegate, &key);
463 return origin < kBmpMax ? origin : 0xFFFF;
464}
465
466// Make sure that Flutter has derived the layout for the group of the event,
467// if the event contains a goal keycode.
469 guint8 group = event->group;
470 if (self->derived_layout->find(group) != self->derived_layout->end()) {
471 return;
472 }
473 if (self->keycode_to_goals->find(event->keycode) ==
474 self->keycode_to_goals->end()) {
475 return;
476 }
477
478 DerivedGroupLayout& layout = (*self->derived_layout)[group];
479
480 // Clone all mandatory goals. Each goal is removed from this cloned map when
481 // fulfilled, and the remaining ones will be assigned to a default position.
482 std::map<uint64_t, const LayoutGoal*> remaining_mandatory_goals =
483 *self->logical_to_mandatory_goals;
484
485#ifdef DEBUG_PRINT_LAYOUT
486 std::string debug_layout_data;
487 for (uint16_t keycode = 0; keycode < 128; keycode += 1) {
488 std::vector<uint16_t> this_key_clues = {
489 convert_key_to_char(self->view_delegate, keycode, group, 0),
490 convert_key_to_char(self->view_delegate, keycode, group, 1), // Shift
491 };
492 debug_format_layout_data(debug_layout_data, keycode, this_key_clues[0],
493 this_key_clues[1]);
494 }
495#endif
496
497 // It's important to only traverse layout goals instead of all keycodes.
498 // Some key codes outside of the standard keyboard also gives alpha-numeric
499 // letters, and will therefore take over mandatory goals from standard
500 // keyboard keys if they come first. Example: French keyboard digit 1.
501 for (const LayoutGoal& keycode_goal : layout_goals) {
502 uint16_t keycode = keycode_goal.keycode;
503 std::vector<uint16_t> this_key_clues = {
504 convert_key_to_char(self->view_delegate, keycode, group, 0),
505 convert_key_to_char(self->view_delegate, keycode, group, 1), // Shift
506 };
507
508 // The logical key should be the first available clue from below:
509 //
510 // - Mandatory goal, if it matches any clue. This ensures that all alnum
511 // keys can be found somewhere.
512 // - US layout, if neither clue of the key is EASCII. This ensures that
513 // there are no non-latin logical keys.
514 // - A value derived on the fly from keycode & keyval.
515 for (uint16_t clue : this_key_clues) {
516 auto matching_goal = remaining_mandatory_goals.find(clue);
517 if (matching_goal != remaining_mandatory_goals.end()) {
518 // Found a key that produces a mandatory char. Use it.
519 g_return_if_fail(layout[keycode] == 0);
520 layout[keycode] = clue;
521 remaining_mandatory_goals.erase(matching_goal);
522 break;
523 }
524 }
525 bool has_any_eascii =
526 is_eascii(this_key_clues[0]) || is_eascii(this_key_clues[1]);
527 // See if any produced char meets the requirement as a logical key.
528 if (layout[keycode] == 0 && !has_any_eascii) {
529 auto found_us_layout = self->keycode_to_goals->find(keycode);
530 if (found_us_layout != self->keycode_to_goals->end()) {
531 layout[keycode] = found_us_layout->second->logical_key;
532 }
533 }
534 }
535
536 // Ensure all mandatory goals are assigned.
537 for (const auto mandatory_goal_iter : remaining_mandatory_goals) {
538 const LayoutGoal* goal = mandatory_goal_iter.second;
539 layout[goal->keycode] = goal->logical_key;
540 }
541}
542
543// Returns the keyboard pressed state.
544FlMethodResponse* get_keyboard_state(FlKeyboardManager* self) {
545 g_autoptr(FlValue) result = fl_value_new_map();
546
547 GHashTable* pressing_records =
549
550 g_hash_table_foreach(
551 pressing_records,
552 [](gpointer key, gpointer value, gpointer user_data) {
553 int64_t physical_key = reinterpret_cast<int64_t>(key);
554 int64_t logical_key = reinterpret_cast<int64_t>(value);
555 FlValue* fl_value_map = reinterpret_cast<FlValue*>(user_data);
556
557 fl_value_set_take(fl_value_map, fl_value_new_int(physical_key),
558 fl_value_new_int(logical_key));
559 },
560 result);
561 return FL_METHOD_RESPONSE(fl_method_success_response_new(result));
562}
563
564// Called when a method call on flutter/keyboard is received from Flutter.
565static void method_call_handler(FlMethodChannel* channel,
566 FlMethodCall* method_call,
567 gpointer user_data) {
568 FlKeyboardManager* self = FL_KEYBOARD_MANAGER(user_data);
569
570 const gchar* method = fl_method_call_get_name(method_call);
571
572 g_autoptr(FlMethodResponse) response = nullptr;
573 if (strcmp(method, kGetKeyboardStateMethod) == 0) {
574 response = get_keyboard_state(self);
575 } else {
576 response = FL_METHOD_RESPONSE(fl_method_not_implemented_response_new());
577 }
578
579 g_autoptr(GError) error = nullptr;
580 if (!fl_method_call_respond(method_call, response, &error)) {
581 g_warning("Failed to send method call response: %s", error->message);
582 }
583}
584
586 FlBinaryMessenger* messenger,
587 FlKeyboardViewDelegate* view_delegate) {
588 g_return_val_if_fail(FL_IS_KEYBOARD_VIEW_DELEGATE(view_delegate), nullptr);
589
590 FlKeyboardManager* self = FL_KEYBOARD_MANAGER(
591 g_object_new(fl_keyboard_manager_get_type(), nullptr));
592
593 self->view_delegate = view_delegate;
595 G_OBJECT(view_delegate),
596 reinterpret_cast<gpointer*>(&(self->view_delegate)));
597
598 // The embedder responder must be added before the channel responder.
599 g_ptr_array_add(
600 self->responder_list,
601 FL_KEY_RESPONDER(fl_key_embedder_responder_new(
603 void* callback_user_data, void* send_key_event_user_data) {
604 FlKeyboardManager* self =
605 FL_KEYBOARD_MANAGER(send_key_event_user_data);
606 g_return_if_fail(self->view_delegate != nullptr);
608 self->view_delegate, event, callback, callback_user_data);
609 },
610 self)));
611 g_ptr_array_add(self->responder_list,
612 FL_KEY_RESPONDER(fl_key_channel_responder_new(
614
616 self->view_delegate, [self]() { self->derived_layout->clear(); });
617
618 // Setup the flutter/keyboard channel.
619 g_autoptr(FlStandardMethodCodec) codec = fl_standard_method_codec_new();
620 self->channel =
621 fl_method_channel_new(messenger, kChannelName, FL_METHOD_CODEC(codec));
623 self, nullptr);
624 return self;
625}
626
627// The loop body to dispatch an event to a responder.
628static void dispatch_to_responder(gpointer responder_data,
629 gpointer foreach_data_ptr) {
630 DispatchToResponderLoopContext* context =
631 reinterpret_cast<DispatchToResponderLoopContext*>(foreach_data_ptr);
632 FlKeyResponder* responder = FL_KEY_RESPONDER(responder_data);
634 responder, context->event, responder_handle_event_callback,
635 context->user_data, context->specified_logical_key);
636}
637
639 FlKeyEvent* event) {
640 g_return_val_if_fail(FL_IS_KEYBOARD_MANAGER(self), FALSE);
641 g_return_val_if_fail(event != nullptr, FALSE);
642 g_return_val_if_fail(self->view_delegate != nullptr, FALSE);
643
644 guarantee_layout(self, event);
645
646 uint64_t incoming_hash = fl_keyboard_manager_get_event_hash(event);
647 if (fl_keyboard_manager_remove_redispatched(self, incoming_hash)) {
648 return FALSE;
649 }
650
651 FlKeyboardPendingEvent* pending = fl_keyboard_pending_event_new(
652 std::unique_ptr<FlKeyEvent>(event), ++self->last_sequence_id,
653 self->responder_list->len);
654
655 g_ptr_array_add(self->pending_responds, pending);
656 FlKeyboardManagerUserData* user_data =
657 fl_keyboard_manager_user_data_new(self, pending->sequence_id);
658 DispatchToResponderLoopContext data{
659 .event = event,
660 .specified_logical_key =
661 get_logical_key_from_layout(event, *self->derived_layout),
662 .user_data = user_data,
663 };
664 g_ptr_array_foreach(self->responder_list, dispatch_to_responder, &data);
665
666 return TRUE;
667}
668
670 g_return_val_if_fail(FL_IS_KEYBOARD_MANAGER(self), FALSE);
671 return self->pending_responds->len == 0 &&
672 self->pending_redispatches->len == 0;
673}
674
676 guint state,
677 double event_time) {
678 g_return_if_fail(FL_IS_KEYBOARD_MANAGER(self));
679
680 // The embedder responder is the first element in
681 // FlKeyboardManager.responder_list.
682 FlKeyEmbedderResponder* responder =
683 FL_KEY_EMBEDDER_RESPONDER(g_ptr_array_index(self->responder_list, 0));
685 event_time);
686}
687
689 g_return_val_if_fail(FL_IS_KEYBOARD_MANAGER(self), nullptr);
690
691 // The embedder responder is the first element in
692 // FlKeyboardManager.responder_list.
693 FlKeyEmbedderResponder* responder =
694 FL_KEY_EMBEDDER_RESPONDER(g_ptr_array_index(self->responder_list, 0));
696}
static uint32_t hash(const SkShaderBase::GradientInfo &v)
static const size_t kBufferSize
Definition SkString.cpp:27
void(* FlutterKeyEventCallback)(bool, void *)
Definition embedder.h:1153
AtkStateType state
FlKeyEvent uint64_t specified_logical_key
FlKeyEvent uint64_t FlKeyResponderAsyncCallback callback
FlKeyChannelResponder * fl_key_channel_responder_new(FlBinaryMessenger *messenger, FlKeyChannelResponderMock *mock)
FlKeyEvent * event
GHashTable * fl_key_embedder_responder_get_pressed_state(FlKeyEmbedderResponder *self)
FlKeyEmbedderResponder * fl_key_embedder_responder_new(EmbedderSendKeyEvent send_key_event, void *send_key_event_user_data)
void fl_key_embedder_responder_sync_modifiers_if_needed(FlKeyEmbedderResponder *responder, guint state, double event_time)
void fl_key_event_dispose(FlKeyEvent *event)
void fl_key_responder_handle_event(FlKeyResponder *self, FlKeyEvent *event, FlKeyResponderAsyncCallback callback, gpointer user_data, uint64_t specified_logical_key)
typedefG_BEGIN_DECLS struct _FlKeyboardManager FlKeyboardManager
gboolean fl_keyboard_manager_is_state_clear(FlKeyboardManager *self)
static void fl_keyboard_manager_class_init(FlKeyboardManagerClass *klass)
static void fl_keyboard_manager_dispose(GObject *object)
static FlKeyboardPendingEvent * fl_keyboard_pending_event_new(std::unique_ptr< FlKeyEvent > event, uint64_t sequence_id, size_t to_reply)
static void fl_keyboard_manager_user_data_init(FlKeyboardManagerUserData *self)
static uint64_t get_logical_key_from_layout(const FlKeyEvent *event, const DerivedLayout &layout)
G_DEFINE_TYPE(FlKeyboardManagerUserData, fl_keyboard_manager_user_data, G_TYPE_OBJECT) static void fl_keyboard_manager_user_data_dispose(GObject *object)
static uint64_t fl_keyboard_manager_get_event_hash(FlKeyEvent *event)
static void guarantee_layout(FlKeyboardManager *self, FlKeyEvent *event)
static FlKeyboardManagerUserData * fl_keyboard_manager_user_data_new(FlKeyboardManager *manager, uint64_t sequence_id)
gboolean fl_keyboard_manager_handle_event(FlKeyboardManager *self, FlKeyEvent *event)
GHashTable * fl_keyboard_manager_get_pressed_state(FlKeyboardManager *self)
static void fl_keyboard_manager_user_data_class_init(FlKeyboardManagerUserDataClass *klass)
static void fl_keyboard_manager_init(FlKeyboardManager *self)
static void method_call_handler(FlMethodChannel *channel, FlMethodCall *method_call, gpointer user_data)
static void dispatch_to_responder(gpointer responder_data, gpointer foreach_data_ptr)
static constexpr char kChannelName[]
FlMethodResponse * get_keyboard_state(FlKeyboardManager *self)
static void fl_keyboard_pending_event_class_init(FlKeyboardPendingEventClass *klass)
static gboolean g_ptr_array_find_with_equal_func1(GPtrArray *haystack, gconstpointer needle, GEqualFunc equal_func, guint *index_)
static void responder_handle_event_callback(bool handled, gpointer user_data_ptr)
static gboolean compare_pending_by_hash(gconstpointer pending, gconstpointer needle_hash)
static constexpr char kGetKeyboardStateMethod[]
static gboolean compare_pending_by_sequence_id(gconstpointer pending, gconstpointer needle_sequence_id)
static void fl_keyboard_pending_event_dispose(GObject *object)
FlKeyboardManager * fl_keyboard_manager_new(FlBinaryMessenger *messenger, FlKeyboardViewDelegate *view_delegate)
static bool fl_keyboard_manager_remove_redispatched(FlKeyboardManager *self, uint64_t hash)
static void fl_keyboard_pending_event_init(FlKeyboardPendingEvent *self)
void fl_keyboard_manager_sync_modifier_if_needed(FlKeyboardManager *self, guint state, double event_time)
static uint16_t convert_key_to_char(FlKeyboardViewDelegate *view_delegate, guint keycode, gint group, gint level)
GHashTable * fl_keyboard_view_delegate_get_keyboard_state(FlKeyboardViewDelegate *self)
void fl_keyboard_view_delegate_send_key_event(FlKeyboardViewDelegate *self, const FlutterKeyEvent *event, FlutterKeyEventCallback callback, void *user_data)
FlBinaryMessenger * fl_keyboard_view_delegate_get_messenger(FlKeyboardViewDelegate *self)
void fl_keyboard_view_delegate_subscribe_to_layout_change(FlKeyboardViewDelegate *self, KeyboardLayoutNotifier notifier)
guint fl_keyboard_view_delegate_lookup_key(FlKeyboardViewDelegate *self, const GdkKeymapKey *key)
gboolean fl_keyboard_view_delegate_text_filter_key_press(FlKeyboardViewDelegate *self, FlKeyEvent *event)
void fl_keyboard_view_delegate_redispatch_event(FlKeyboardViewDelegate *self, std::unique_ptr< FlKeyEvent > event)
G_MODULE_EXPORT const gchar * fl_method_call_get_name(FlMethodCall *self)
G_MODULE_EXPORT gboolean fl_method_call_respond(FlMethodCall *self, FlMethodResponse *response, GError **error)
G_MODULE_EXPORT FlMethodChannel * fl_method_channel_new(FlBinaryMessenger *messenger, const gchar *name, FlMethodCodec *codec)
G_MODULE_EXPORT void fl_method_channel_set_method_call_handler(FlMethodChannel *self, FlMethodChannelMethodCallHandler handler, gpointer user_data, GDestroyNotify destroy_notify)
G_BEGIN_DECLS G_MODULE_EXPORT FlMethodCall * method_call
G_MODULE_EXPORT FlMethodSuccessResponse * fl_method_success_response_new(FlValue *result)
G_MODULE_EXPORT FlMethodNotImplementedResponse * fl_method_not_implemented_response_new()
static const uint8_t buffer[]
const uint8_t uint32_t uint32_t GError ** error
uint8_t value
G_MODULE_EXPORT FlStandardMethodCodec * fl_standard_method_codec_new()
GAsyncResult * result
G_MODULE_EXPORT FlValue * fl_value_new_map()
Definition fl_value.cc:366
G_MODULE_EXPORT void fl_value_set_take(FlValue *self, FlValue *key, FlValue *value)
Definition fl_value.cc:618
G_MODULE_EXPORT FlValue * fl_value_new_int(int64_t value)
Definition fl_value.cc:262
typedefG_BEGIN_DECLS struct _FlValue FlValue
Definition fl_value.h:42
g_object_add_weak_pointer(G_OBJECT(self), reinterpret_cast< gpointer * >(&self->engine))
const std::vector< LayoutGoal > layout_goals
return FALSE
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font manager
Definition switches.h:218
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot data
Definition switches.h:41
uint16_t keycode
Definition key_mapping.h:42
uint64_t logical_key
Definition key_mapping.h:45
guint32 time
guint16 keycode
FlMethodChannel * channel
std::unique_ptr< DerivedLayout > derived_layout
FlKeyboardViewDelegate * view_delegate
std::unique_ptr< std::map< uint64_t, const LayoutGoal * > > logical_to_mandatory_goals
std::unique_ptr< std::map< uint16_t, const LayoutGoal * > > keycode_to_goals
std::unique_ptr< FlKeyEvent > event

Function Documentation

◆ compare_pending_by_hash()

static gboolean compare_pending_by_hash ( gconstpointer  pending,
gconstpointer  needle_hash 
)
static

Definition at line 392 of file fl_keyboard_manager.cc.

393 {
394 uint64_t hash = *reinterpret_cast<const uint64_t*>(needle_hash);
395 return static_cast<const FlKeyboardPendingEvent*>(pending)->hash == hash;
396}

◆ compare_pending_by_sequence_id()

static gboolean compare_pending_by_sequence_id ( gconstpointer  pending,
gconstpointer  needle_sequence_id 
)
static

Definition at line 382 of file fl_keyboard_manager.cc.

384 {
385 uint64_t sequence_id = *reinterpret_cast<const uint64_t*>(needle_sequence_id);
386 return static_cast<const FlKeyboardPendingEvent*>(pending)->sequence_id ==
387 sequence_id;
388}

◆ convert_key_to_char()

static uint16_t convert_key_to_char ( FlKeyboardViewDelegate *  view_delegate,
guint  keycode,
gint  group,
gint  level 
)
static

Definition at line 456 of file fl_keyboard_manager.cc.

459 {
460 GdkKeymapKey key = {keycode, group, level};
461 constexpr int kBmpMax = 0xD7FF;
462 guint origin = fl_keyboard_view_delegate_lookup_key(view_delegate, &key);
463 return origin < kBmpMax ? origin : 0xFFFF;
464}

◆ dispatch_to_responder()

static void dispatch_to_responder ( gpointer  responder_data,
gpointer  foreach_data_ptr 
)
static

Definition at line 628 of file fl_keyboard_manager.cc.

629 {
630 DispatchToResponderLoopContext* context =
631 reinterpret_cast<DispatchToResponderLoopContext*>(foreach_data_ptr);
632 FlKeyResponder* responder = FL_KEY_RESPONDER(responder_data);
634 responder, context->event, responder_handle_event_callback,
635 context->user_data, context->specified_logical_key);
636}

◆ fl_keyboard_manager_class_init()

static void fl_keyboard_manager_class_init ( FlKeyboardManagerClass *  klass)
static

Definition at line 304 of file fl_keyboard_manager.cc.

304 {
305 G_OBJECT_CLASS(klass)->dispose = fl_keyboard_manager_dispose;
306}

◆ fl_keyboard_manager_dispose()

static void fl_keyboard_manager_dispose ( GObject *  object)
static

Definition at line 330 of file fl_keyboard_manager.cc.

330 {
331 FlKeyboardManager* self = FL_KEYBOARD_MANAGER(object);
332
333 if (self->view_delegate != nullptr) {
335 nullptr);
336 g_object_remove_weak_pointer(
337 G_OBJECT(self->view_delegate),
338 reinterpret_cast<gpointer*>(&(self->view_delegate)));
339 self->view_delegate = nullptr;
340 }
341
342 self->derived_layout.reset();
343 self->keycode_to_goals.reset();
344 self->logical_to_mandatory_goals.reset();
345
346 g_ptr_array_free(self->responder_list, TRUE);
347 g_ptr_array_set_free_func(self->pending_responds, g_object_unref);
348 g_ptr_array_free(self->pending_responds, TRUE);
349 g_ptr_array_free(self->pending_redispatches, TRUE);
350
351 G_OBJECT_CLASS(fl_keyboard_manager_parent_class)->dispose(object);
352}

◆ fl_keyboard_manager_get_event_hash()

static uint64_t fl_keyboard_manager_get_event_hash ( FlKeyEvent event)
static

Definition at line 168 of file fl_keyboard_manager.cc.

168 {
169 // Combine the event timestamp, the type of event, and the hardware keycode
170 // (scan code) of the event to come up with a unique id for this event that
171 // can be derived solely from the event data itself, so that we can identify
172 // whether or not we have seen this event already.
173 guint64 type =
174 static_cast<uint64_t>(event->is_press ? GDK_KEY_PRESS : GDK_KEY_RELEASE);
175 guint64 keycode = static_cast<uint64_t>(event->keycode);
176 return (event->time & 0xffffffff) | ((type & 0xffff) << 32) |
177 ((keycode & 0xffff) << 48);
178}

◆ fl_keyboard_manager_get_pressed_state()

GHashTable * fl_keyboard_manager_get_pressed_state ( FlKeyboardManager manager)

fl_keyboard_manager_get_pressed_state: @manager: the FlKeyboardManager self.

Returns the keyboard pressed state. The hash table contains one entry per pressed keys, mapping from the logical key to the physical key.*

Definition at line 688 of file fl_keyboard_manager.cc.

688 {
689 g_return_val_if_fail(FL_IS_KEYBOARD_MANAGER(self), nullptr);
690
691 // The embedder responder is the first element in
692 // FlKeyboardManager.responder_list.
693 FlKeyEmbedderResponder* responder =
694 FL_KEY_EMBEDDER_RESPONDER(g_ptr_array_index(self->responder_list, 0));
696}

◆ fl_keyboard_manager_handle_event()

gboolean fl_keyboard_manager_handle_event ( FlKeyboardManager manager,
FlKeyEvent event 
)

fl_keyboard_manager_handle_event: @manager: the FlKeyboardManager self. @event: the event to be dispatched. It is usually a wrap of a GdkEventKey. This event will be managed and released by FlKeyboardManager.

Make the manager process a system key event. This might eventually send messages to the framework, trigger text input effects, or redispatch the event back to the system.

Definition at line 638 of file fl_keyboard_manager.cc.

639 {
640 g_return_val_if_fail(FL_IS_KEYBOARD_MANAGER(self), FALSE);
641 g_return_val_if_fail(event != nullptr, FALSE);
642 g_return_val_if_fail(self->view_delegate != nullptr, FALSE);
643
645
646 uint64_t incoming_hash = fl_keyboard_manager_get_event_hash(event);
647 if (fl_keyboard_manager_remove_redispatched(self, incoming_hash)) {
648 return FALSE;
649 }
650
651 FlKeyboardPendingEvent* pending = fl_keyboard_pending_event_new(
652 std::unique_ptr<FlKeyEvent>(event), ++self->last_sequence_id,
653 self->responder_list->len);
654
655 g_ptr_array_add(self->pending_responds, pending);
656 FlKeyboardManagerUserData* user_data =
657 fl_keyboard_manager_user_data_new(self, pending->sequence_id);
658 DispatchToResponderLoopContext data{
659 .event = event,
660 .specified_logical_key =
661 get_logical_key_from_layout(event, *self->derived_layout),
662 .user_data = user_data,
663 };
664 g_ptr_array_foreach(self->responder_list, dispatch_to_responder, &data);
665
666 return TRUE;
667}

◆ fl_keyboard_manager_init()

static void fl_keyboard_manager_init ( FlKeyboardManager self)
static

Definition at line 308 of file fl_keyboard_manager.cc.

308 {
309 self->derived_layout = std::make_unique<DerivedLayout>();
310
311 self->keycode_to_goals =
312 std::make_unique<std::map<uint16_t, const LayoutGoal*>>();
313 self->logical_to_mandatory_goals =
314 std::make_unique<std::map<uint64_t, const LayoutGoal*>>();
315 for (const LayoutGoal& goal : layout_goals) {
316 (*self->keycode_to_goals)[goal.keycode] = &goal;
317 if (goal.mandatory) {
318 (*self->logical_to_mandatory_goals)[goal.logical_key] = &goal;
319 }
320 }
321
322 self->responder_list = g_ptr_array_new_with_free_func(g_object_unref);
323
324 self->pending_responds = g_ptr_array_new();
325 self->pending_redispatches = g_ptr_array_new_with_free_func(g_object_unref);
326
327 self->last_sequence_id = 1;
328}

◆ fl_keyboard_manager_is_state_clear()

gboolean fl_keyboard_manager_is_state_clear ( FlKeyboardManager manager)

fl_keyboard_manager_is_state_clear: @manager: the FlKeyboardManager self.

A debug-only method that queries whether the manager's various states are cleared, i.e. no pending events for redispatching or for responding.

Returns: true if the manager's various states are cleared.

Definition at line 669 of file fl_keyboard_manager.cc.

669 {
670 g_return_val_if_fail(FL_IS_KEYBOARD_MANAGER(self), FALSE);
671 return self->pending_responds->len == 0 &&
672 self->pending_redispatches->len == 0;
673}

◆ fl_keyboard_manager_new()

FlKeyboardManager * fl_keyboard_manager_new ( FlBinaryMessenger *  messenger,
FlKeyboardViewDelegate *  view_delegate 
)

FlKeyboardManager:

Processes keyboard events and cooperate with TextInputPlugin.

A keyboard event goes through a few sections, each can choose to handle the event, and only unhandled events can move to the next section:

  • Keyboard: Dispatch to the embedder responder and the channel responder simultaneously. After both responders have responded (asynchronously), the event is considered handled if either responder handles it.
  • Text input: Events are sent to IM filter (usually owned by TextInputPlugin) and are handled synchronously.
  • Redispatching: Events are inserted back to the system for redispatching. fl_keyboard_manager_new: @view_delegate: An interface that the manager requires to communicate with the platform. Usually implemented by FlView.

Create a new FlKeyboardManager.

Returns: a new FlKeyboardManager.

Definition at line 585 of file fl_keyboard_manager.cc.

587 {
588 g_return_val_if_fail(FL_IS_KEYBOARD_VIEW_DELEGATE(view_delegate), nullptr);
589
590 FlKeyboardManager* self = FL_KEYBOARD_MANAGER(
591 g_object_new(fl_keyboard_manager_get_type(), nullptr));
592
593 self->view_delegate = view_delegate;
595 G_OBJECT(view_delegate),
596 reinterpret_cast<gpointer*>(&(self->view_delegate)));
597
598 // The embedder responder must be added before the channel responder.
599 g_ptr_array_add(
600 self->responder_list,
601 FL_KEY_RESPONDER(fl_key_embedder_responder_new(
603 void* callback_user_data, void* send_key_event_user_data) {
605 FL_KEYBOARD_MANAGER(send_key_event_user_data);
606 g_return_if_fail(self->view_delegate != nullptr);
608 self->view_delegate, event, callback, callback_user_data);
609 },
610 self)));
611 g_ptr_array_add(self->responder_list,
612 FL_KEY_RESPONDER(fl_key_channel_responder_new(
614
616 self->view_delegate, [self]() { self->derived_layout->clear(); });
617
618 // Setup the flutter/keyboard channel.
619 g_autoptr(FlStandardMethodCodec) codec = fl_standard_method_codec_new();
620 self->channel =
621 fl_method_channel_new(messenger, kChannelName, FL_METHOD_CODEC(codec));
623 self, nullptr);
624 return self;
625}

◆ fl_keyboard_manager_remove_redispatched()

static bool fl_keyboard_manager_remove_redispatched ( FlKeyboardManager self,
uint64_t  hash 
)
static

Definition at line 402 of file fl_keyboard_manager.cc.

403 {
404 guint result_index;
405 gboolean found = g_ptr_array_find_with_equal_func1(
406 self->pending_redispatches, static_cast<const uint64_t*>(&hash),
407 compare_pending_by_hash, &result_index);
408 if (found) {
409 // The removed object is freed due to `pending_redispatches`'s free_func.
410 g_ptr_array_remove_index_fast(self->pending_redispatches, result_index);
411 return TRUE;
412 } else {
413 return FALSE;
414 }
415}

◆ fl_keyboard_manager_sync_modifier_if_needed()

void fl_keyboard_manager_sync_modifier_if_needed ( FlKeyboardManager manager,
guint  state,
double  event_time 
)

fl_keyboard_manager_sync_modifier_if_needed: @manager: the FlKeyboardManager self. @state: the state of the modifiers mask. @event_time: the time attribute of the incoming GDK event.

If needed, synthesize modifier keys up and down event by comparing their current pressing states with the given modifiers mask.

Definition at line 675 of file fl_keyboard_manager.cc.

677 {
678 g_return_if_fail(FL_IS_KEYBOARD_MANAGER(self));
679
680 // The embedder responder is the first element in
681 // FlKeyboardManager.responder_list.
682 FlKeyEmbedderResponder* responder =
683 FL_KEY_EMBEDDER_RESPONDER(g_ptr_array_index(self->responder_list, 0));
685 event_time);
686}

◆ fl_keyboard_manager_user_data_class_init()

static void fl_keyboard_manager_user_data_class_init ( FlKeyboardManagerUserDataClass *  klass)
static

Definition at line 229 of file fl_keyboard_manager.cc.

230 {
231 G_OBJECT_CLASS(klass)->dispose = fl_keyboard_manager_user_data_dispose;
232}

◆ fl_keyboard_manager_user_data_init()

static void fl_keyboard_manager_user_data_init ( FlKeyboardManagerUserData *  self)
static

Definition at line 234 of file fl_keyboard_manager.cc.

235 {}

◆ fl_keyboard_manager_user_data_new()

static FlKeyboardManagerUserData * fl_keyboard_manager_user_data_new ( FlKeyboardManager manager,
uint64_t  sequence_id 
)
static

Definition at line 238 of file fl_keyboard_manager.cc.

240 {
241 FlKeyboardManagerUserData* self = FL_KEYBOARD_MANAGER_USER_DATA(
242 g_object_new(fl_keyboard_manager_user_data_get_type(), nullptr));
243
244 self->manager = manager;
245 // Add a weak pointer so we can know if the key event responder disappeared
246 // while the framework was responding.
247 g_object_add_weak_pointer(G_OBJECT(manager),
248 reinterpret_cast<gpointer*>(&(self->manager)));
249 self->sequence_id = sequence_id;
250 return self;
251}

◆ fl_keyboard_pending_event_class_init()

static void fl_keyboard_pending_event_class_init ( FlKeyboardPendingEventClass *  klass)
static

Definition at line 159 of file fl_keyboard_manager.cc.

160 {
161 G_OBJECT_CLASS(klass)->dispose = fl_keyboard_pending_event_dispose;
162}

◆ fl_keyboard_pending_event_dispose()

static void fl_keyboard_pending_event_dispose ( GObject *  object)
static

Definition at line 147 of file fl_keyboard_manager.cc.

147 {
148 // Redundant, but added so that we don't get a warning about unused function
149 // for FL_IS_KEYBOARD_PENDING_EVENT.
150 g_return_if_fail(FL_IS_KEYBOARD_PENDING_EVENT(object));
151
152 FlKeyboardPendingEvent* self = FL_KEYBOARD_PENDING_EVENT(object);
153 if (self->event != nullptr) {
154 fl_key_event_dispose(self->event.release());
155 }
156 G_OBJECT_CLASS(fl_keyboard_pending_event_parent_class)->dispose(object);
157}

◆ fl_keyboard_pending_event_init()

static void fl_keyboard_pending_event_init ( FlKeyboardPendingEvent *  self)
static

Definition at line 164 of file fl_keyboard_manager.cc.

164{}

◆ fl_keyboard_pending_event_new()

static FlKeyboardPendingEvent * fl_keyboard_pending_event_new ( std::unique_ptr< FlKeyEvent event,
uint64_t  sequence_id,
size_t  to_reply 
)
static

Definition at line 184 of file fl_keyboard_manager.cc.

187 {
188 FlKeyboardPendingEvent* self = FL_KEYBOARD_PENDING_EVENT(
189 g_object_new(fl_keyboard_pending_event_get_type(), nullptr));
190
191 self->event = std::move(event);
192 self->sequence_id = sequence_id;
193 self->unreplied = to_reply;
194 self->any_handled = false;
195 self->hash = fl_keyboard_manager_get_event_hash(self->event.get());
196 return self;
197}

◆ G_DECLARE_FINAL_TYPE() [1/2]

G_DECLARE_FINAL_TYPE ( FlKeyboardManagerUserData  ,
fl_keyboard_manager_user_data  ,
FL  ,
KEYBOARD_MANAGER_USER_DATA  ,
GObject   
)

◆ G_DECLARE_FINAL_TYPE() [2/2]

G_DECLARE_FINAL_TYPE ( FlKeyboardPendingEvent  ,
fl_keyboard_pending_event  ,
FL  ,
KEYBOARD_PENDING_EVENT  ,
GObject   
)

◆ G_DEFINE_TYPE() [1/2]

G_DEFINE_TYPE ( FlKeyboardManager  ,
fl_keyboard_manager  ,
G_TYPE_OBJECT   
)

◆ G_DEFINE_TYPE() [2/2]

G_DEFINE_TYPE ( FlKeyboardManagerUserData  ,
fl_keyboard_manager_user_data  ,
G_TYPE_OBJECT   
)

Definition at line 215 of file fl_keyboard_manager.cc.

219 {
220 g_return_if_fail(FL_IS_KEYBOARD_MANAGER_USER_DATA(object));
221 FlKeyboardManagerUserData* self = FL_KEYBOARD_MANAGER_USER_DATA(object);
222 if (self->manager != nullptr) {
223 g_object_remove_weak_pointer(G_OBJECT(self->manager),
224 reinterpret_cast<gpointer*>(&(self->manager)));
225 self->manager = nullptr;
226 }
227}

◆ g_ptr_array_find_with_equal_func1()

static gboolean g_ptr_array_find_with_equal_func1 ( GPtrArray *  haystack,
gconstpointer  needle,
GEqualFunc  equal_func,
guint *  index_ 
)
static

Definition at line 359 of file fl_keyboard_manager.cc.

362 {
363 guint i;
364 g_return_val_if_fail(haystack != NULL, FALSE);
365 if (equal_func == NULL) {
366 equal_func = g_direct_equal;
367 }
368 for (i = 0; i < haystack->len; i++) {
369 if (equal_func(g_ptr_array_index(haystack, i), needle)) {
370 if (index_ != NULL) {
371 *index_ = i;
372 }
373 return TRUE;
374 }
375 }
376
377 return FALSE;
378}

◆ get_keyboard_state()

FlMethodResponse * get_keyboard_state ( FlKeyboardManager self)

Definition at line 544 of file fl_keyboard_manager.cc.

544 {
545 g_autoptr(FlValue) result = fl_value_new_map();
546
547 GHashTable* pressing_records =
549
550 g_hash_table_foreach(
551 pressing_records,
552 [](gpointer key, gpointer value, gpointer user_data) {
553 int64_t physical_key = reinterpret_cast<int64_t>(key);
554 int64_t logical_key = reinterpret_cast<int64_t>(value);
555 FlValue* fl_value_map = reinterpret_cast<FlValue*>(user_data);
556
557 fl_value_set_take(fl_value_map, fl_value_new_int(physical_key),
558 fl_value_new_int(logical_key));
559 },
560 result);
561 return FL_METHOD_RESPONSE(fl_method_success_response_new(result));
562}

◆ get_logical_key_from_layout()

static uint64_t get_logical_key_from_layout ( const FlKeyEvent event,
const DerivedLayout &  layout 
)
static

Definition at line 97 of file fl_keyboard_manager.cc.

98 {
99 guint8 group = event->group;
100 guint16 keycode = event->keycode;
101 if (keycode >= kLayoutSize) {
102 return 0;
103 }
104
105 auto found_group_layout = layout.find(group);
106 if (found_group_layout != layout.end()) {
107 return found_group_layout->second[keycode];
108 }
109 return 0;
110}

◆ guarantee_layout()

static void guarantee_layout ( FlKeyboardManager self,
FlKeyEvent event 
)
static

Definition at line 468 of file fl_keyboard_manager.cc.

468 {
469 guint8 group = event->group;
470 if (self->derived_layout->find(group) != self->derived_layout->end()) {
471 return;
472 }
473 if (self->keycode_to_goals->find(event->keycode) ==
474 self->keycode_to_goals->end()) {
475 return;
476 }
477
478 DerivedGroupLayout& layout = (*self->derived_layout)[group];
479
480 // Clone all mandatory goals. Each goal is removed from this cloned map when
481 // fulfilled, and the remaining ones will be assigned to a default position.
482 std::map<uint64_t, const LayoutGoal*> remaining_mandatory_goals =
483 *self->logical_to_mandatory_goals;
484
485#ifdef DEBUG_PRINT_LAYOUT
486 std::string debug_layout_data;
487 for (uint16_t keycode = 0; keycode < 128; keycode += 1) {
488 std::vector<uint16_t> this_key_clues = {
489 convert_key_to_char(self->view_delegate, keycode, group, 0),
490 convert_key_to_char(self->view_delegate, keycode, group, 1), // Shift
491 };
492 debug_format_layout_data(debug_layout_data, keycode, this_key_clues[0],
493 this_key_clues[1]);
494 }
495#endif
496
497 // It's important to only traverse layout goals instead of all keycodes.
498 // Some key codes outside of the standard keyboard also gives alpha-numeric
499 // letters, and will therefore take over mandatory goals from standard
500 // keyboard keys if they come first. Example: French keyboard digit 1.
501 for (const LayoutGoal& keycode_goal : layout_goals) {
502 uint16_t keycode = keycode_goal.keycode;
503 std::vector<uint16_t> this_key_clues = {
504 convert_key_to_char(self->view_delegate, keycode, group, 0),
505 convert_key_to_char(self->view_delegate, keycode, group, 1), // Shift
506 };
507
508 // The logical key should be the first available clue from below:
509 //
510 // - Mandatory goal, if it matches any clue. This ensures that all alnum
511 // keys can be found somewhere.
512 // - US layout, if neither clue of the key is EASCII. This ensures that
513 // there are no non-latin logical keys.
514 // - A value derived on the fly from keycode & keyval.
515 for (uint16_t clue : this_key_clues) {
516 auto matching_goal = remaining_mandatory_goals.find(clue);
517 if (matching_goal != remaining_mandatory_goals.end()) {
518 // Found a key that produces a mandatory char. Use it.
519 g_return_if_fail(layout[keycode] == 0);
520 layout[keycode] = clue;
521 remaining_mandatory_goals.erase(matching_goal);
522 break;
523 }
524 }
525 bool has_any_eascii =
526 is_eascii(this_key_clues[0]) || is_eascii(this_key_clues[1]);
527 // See if any produced char meets the requirement as a logical key.
528 if (layout[keycode] == 0 && !has_any_eascii) {
529 auto found_us_layout = self->keycode_to_goals->find(keycode);
530 if (found_us_layout != self->keycode_to_goals->end()) {
531 layout[keycode] = found_us_layout->second->logical_key;
532 }
533 }
534 }
535
536 // Ensure all mandatory goals are assigned.
537 for (const auto mandatory_goal_iter : remaining_mandatory_goals) {
538 const LayoutGoal* goal = mandatory_goal_iter.second;
539 layout[goal->keycode] = goal->logical_key;
540 }
541}

◆ method_call_handler()

static void method_call_handler ( FlMethodChannel *  channel,
FlMethodCall *  method_call,
gpointer  user_data 
)
static

Definition at line 565 of file fl_keyboard_manager.cc.

567 {
568 FlKeyboardManager* self = FL_KEYBOARD_MANAGER(user_data);
569
570 const gchar* method = fl_method_call_get_name(method_call);
571
572 g_autoptr(FlMethodResponse) response = nullptr;
573 if (strcmp(method, kGetKeyboardStateMethod) == 0) {
574 response = get_keyboard_state(self);
575 } else {
576 response = FL_METHOD_RESPONSE(fl_method_not_implemented_response_new());
577 }
578
579 g_autoptr(GError) error = nullptr;
580 if (!fl_method_call_respond(method_call, response, &error)) {
581 g_warning("Failed to send method call response: %s", error->message);
582 }
583}

◆ responder_handle_event_callback()

static void responder_handle_event_callback ( bool  handled,
gpointer  user_data_ptr 
)
static

Definition at line 418 of file fl_keyboard_manager.cc.

419 {
420 g_return_if_fail(FL_IS_KEYBOARD_MANAGER_USER_DATA(user_data_ptr));
421 FlKeyboardManagerUserData* user_data =
422 FL_KEYBOARD_MANAGER_USER_DATA(user_data_ptr);
423 FlKeyboardManager* self = user_data->manager;
424 g_return_if_fail(self->view_delegate != nullptr);
425
426 guint result_index = -1;
427 gboolean found = g_ptr_array_find_with_equal_func1(
428 self->pending_responds, &user_data->sequence_id,
429 compare_pending_by_sequence_id, &result_index);
430 g_return_if_fail(found);
431 FlKeyboardPendingEvent* pending = FL_KEYBOARD_PENDING_EVENT(
432 g_ptr_array_index(self->pending_responds, result_index));
433 g_return_if_fail(pending != nullptr);
434 g_return_if_fail(pending->unreplied > 0);
435 pending->unreplied -= 1;
436 pending->any_handled = pending->any_handled || handled;
437 // All responders have replied.
438 if (pending->unreplied == 0) {
439 g_object_unref(user_data_ptr);
440 gpointer removed =
441 g_ptr_array_remove_index_fast(self->pending_responds, result_index);
442 g_return_if_fail(removed == pending);
443 bool should_redispatch = !pending->any_handled &&
445 self->view_delegate, pending->event.get());
446 if (should_redispatch) {
447 g_ptr_array_add(self->pending_redispatches, pending);
449 std::move(pending->event));
450 } else {
451 g_object_unref(pending);
452 }
453 }
454}

Variable Documentation

◆ kChannelName

constexpr char kChannelName[] = "flutter/keyboard"
staticconstexpr

Definition at line 22 of file fl_keyboard_manager.cc.

◆ kGetKeyboardStateMethod

constexpr char kGetKeyboardStateMethod[] = "getKeyboardState"
staticconstexpr

Definition at line 23 of file fl_keyboard_manager.cc.