| Flutter Linux Embedder |

fl_keyboard_manager.cc
Go to the documentation of this file.
1 // Copyright 2013 The Flutter Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "flutter/shell/platform/linux/fl_keyboard_manager.h"
6
7 #include <array>
8 #include <cinttypes>
9 #include <memory>
10 #include <string>
11
12 #include "flutter/shell/platform/linux/fl_key_channel_responder.h"
13 #include "flutter/shell/platform/linux/fl_key_embedder_responder.h"
14 #include "flutter/shell/platform/linux/key_mapping.h"
15 #include "flutter/shell/platform/linux/public/flutter_linux/fl_method_channel.h"
16 #include "flutter/shell/platform/linux/public/flutter_linux/fl_standard_method_codec.h"
17
18 // Turn on this flag to print complete layout data when switching IMEs. The data
19 // is used in unit tests.
20 #define DEBUG_PRINT_LAYOUT
21
22 static constexpr char kChannelName[] = "flutter/keyboard";
23 static constexpr char kGetKeyboardStateMethod[] = "getKeyboardState";
24
25 /* Declarations of private classes */
26
27 G_DECLARE_FINAL_TYPE(FlKeyboardPendingEvent,
28 fl_keyboard_pending_event,
29 FL,
30 KEYBOARD_PENDING_EVENT,
31 GObject);
32
33 #define FL_TYPE_KEYBOARD_MANAGER_USER_DATA \
34 fl_keyboard_manager_user_data_get_type()
35 G_DECLARE_FINAL_TYPE(FlKeyboardManagerUserData,
36 fl_keyboard_manager_user_data,
37 FL,
38 KEYBOARD_MANAGER_USER_DATA,
39 GObject);
40
41 /* End declarations */
42
43 namespace {
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.
49 constexpr 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.
53 typedef std::array<uint64_t, kLayoutSize> DerivedGroupLayout;
54 // Describes the derived layout of the entire keyboard.
55 //
56 // Maps from group ID to group layout.
57 typedef std::map<guint8, DerivedGroupLayout> DerivedLayout;
58
59 // Context variables for the foreach call used to dispatch events to responders.
60 typedef struct {
61 FlKeyEvent* event;
62 uint64_t specified_logical_key;
63 FlKeyboardManagerUserData* user_data;
64 } DispatchToResponderLoopContext;
65
66 bool 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`.
72 void 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
97 static 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
123 struct _FlKeyboardPendingEvent {
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
145 G_DEFINE_TYPE(FlKeyboardPendingEvent, fl_keyboard_pending_event, G_TYPE_OBJECT)
146
147 static 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
159 static void fl_keyboard_pending_event_class_init(
160 FlKeyboardPendingEventClass* klass) {
161 G_OBJECT_CLASS(klass)->dispose = fl_keyboard_pending_event_dispose;
162 }
163
164 static 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.
168 static uint64_t fl_keyboard_manager_get_event_hash(FlKeyEvent* event) {
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.
184 static 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
207 struct _FlKeyboardManagerUserData {
208 GObject parent_instance;
209
210 // A weak reference to the owner manager.
211 FlKeyboardManager* manager;
212 uint64_t sequence_id;
213 };
214
215 G_DEFINE_TYPE(FlKeyboardManagerUserData,
216 fl_keyboard_manager_user_data,
217 G_TYPE_OBJECT)
218
219 static 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
229 static void fl_keyboard_manager_user_data_class_init(
230 FlKeyboardManagerUserDataClass* klass) {
231 G_OBJECT_CLASS(klass)->dispose = fl_keyboard_manager_user_data_dispose;
232 }
233
234 static void fl_keyboard_manager_user_data_init(
235 FlKeyboardManagerUserData* self) {}
236
237 // Creates a new FlKeyboardManagerUserData private class with all information.
238 static 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
255 struct _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*>>
294 logical_to_mandatory_goals;
295
296 // The channel used by the framework to query the keyboard pressed state.
297 FlMethodChannel* channel;
298 };
299
300 G_DEFINE_TYPE(FlKeyboardManager, fl_keyboard_manager, G_TYPE_OBJECT);
301
302 static void fl_keyboard_manager_dispose(GObject* object);
303
304 static void fl_keyboard_manager_class_init(FlKeyboardManagerClass* klass) {
305 G_OBJECT_CLASS(klass)->dispose = fl_keyboard_manager_dispose;
306 }
307
308 static void fl_keyboard_manager_init(FlKeyboardManager* self) {
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
330 static void fl_keyboard_manager_dispose(GObject* object) {
331 FlKeyboardManager* self = FL_KEYBOARD_MANAGER(object);
332
333 if (self->view_delegate != nullptr) {
334 fl_keyboard_view_delegate_subscribe_to_layout_change(self->view_delegate,
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.
359 static 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.
382 static 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.
392 static 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.
402 static bool fl_keyboard_manager_remove_redispatched(FlKeyboardManager* self,
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.
418 static 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 &&
444 !fl_keyboard_view_delegate_text_filter_key_press(
445 self->view_delegate, pending->event.get());
446 if (should_redispatch) {
447 g_ptr_array_add(self->pending_redispatches, pending);
448 fl_keyboard_view_delegate_redispatch_event(self->view_delegate,
449 std::move(pending->event));
450 } else {
451 g_object_unref(pending);
452 }
453 }
454 }
455
456 static 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.
468 static void guarantee_layout(FlKeyboardManager* self, FlKeyEvent* event) {
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.
544 FlMethodResponse* get_keyboard_state(FlKeyboardManager* self) {
545 g_autoptr(FlValue) result = fl_value_new_map();
546
547 GHashTable* pressing_records =
548 fl_keyboard_view_delegate_get_keyboard_state(self->view_delegate);
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.
565 static 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
585 FlKeyboardManager* fl_keyboard_manager_new(
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;
594 g_object_add_weak_pointer(
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(
602 [self](const FlutterKeyEvent* event, FlutterKeyEventCallback callback,
603 void* user_data) {
604 g_return_if_fail(self->view_delegate != nullptr);
605 fl_keyboard_view_delegate_send_key_event(self->view_delegate, event,
606 callback, user_data);
607 })));
608 g_ptr_array_add(self->responder_list,
609 FL_KEY_RESPONDER(fl_key_channel_responder_new(
610 fl_keyboard_view_delegate_get_messenger(view_delegate))));
611
612 fl_keyboard_view_delegate_subscribe_to_layout_change(
613 self->view_delegate, [self]() { self->derived_layout->clear(); });
614
615 // Setup the flutter/keyboard channel.
616 g_autoptr(FlStandardMethodCodec) codec = fl_standard_method_codec_new();
617 self->channel =
618 fl_method_channel_new(messenger, kChannelName, FL_METHOD_CODEC(codec));
619 fl_method_channel_set_method_call_handler(self->channel, method_call_handler,
620 self, nullptr);
621 return self;
622 }
623
624 // The loop body to dispatch an event to a responder.
625 static void dispatch_to_responder(gpointer responder_data,
626 gpointer foreach_data_ptr) {
627 DispatchToResponderLoopContext* context =
628 reinterpret_cast<DispatchToResponderLoopContext*>(foreach_data_ptr);
629 FlKeyResponder* responder = FL_KEY_RESPONDER(responder_data);
630 fl_key_responder_handle_event(
631 responder, context->event, responder_handle_event_callback,
632 context->user_data, context->specified_logical_key);
633 }
634
635 gboolean fl_keyboard_manager_handle_event(FlKeyboardManager* self,
636 FlKeyEvent* event) {
637 g_return_val_if_fail(FL_IS_KEYBOARD_MANAGER(self), FALSE);
638 g_return_val_if_fail(event != nullptr, FALSE);
639 g_return_val_if_fail(self->view_delegate != nullptr, FALSE);
640
641 guarantee_layout(self, event);
642
643 uint64_t incoming_hash = fl_keyboard_manager_get_event_hash(event);
644 if (fl_keyboard_manager_remove_redispatched(self, incoming_hash)) {
645 return FALSE;
646 }
647
648 FlKeyboardPendingEvent* pending = fl_keyboard_pending_event_new(
649 std::unique_ptr<FlKeyEvent>(event), ++self->last_sequence_id,
650 self->responder_list->len);
651
652 g_ptr_array_add(self->pending_responds, pending);
653 FlKeyboardManagerUserData* user_data =
654 fl_keyboard_manager_user_data_new(self, pending->sequence_id);
655 DispatchToResponderLoopContext data{
656 .event = event,
657 .specified_logical_key =
658 get_logical_key_from_layout(event, *self->derived_layout),
659 .user_data = user_data,
660 };
661 g_ptr_array_foreach(self->responder_list, dispatch_to_responder, &data);
662
663 return TRUE;
664 }
665
666 gboolean fl_keyboard_manager_is_state_clear(FlKeyboardManager* self) {
667 g_return_val_if_fail(FL_IS_KEYBOARD_MANAGER(self), FALSE);
668 return self->pending_responds->len == 0 &&
669 self->pending_redispatches->len == 0;
670 }
671
672 void fl_keyboard_manager_sync_modifier_if_needed(FlKeyboardManager* self,
673 guint state,
674 double event_time) {
675 g_return_if_fail(FL_IS_KEYBOARD_MANAGER(self));
676
677 // The embedder responder is the first element in
678 // FlKeyboardManager.responder_list.
679 FlKeyEmbedderResponder* responder =
680 FL_KEY_EMBEDDER_RESPONDER(g_ptr_array_index(self->responder_list, 0));
681 fl_key_embedder_responder_sync_modifiers_if_needed(responder, state,
682 event_time);
683 }
684
685 GHashTable* fl_keyboard_manager_get_pressed_state(FlKeyboardManager* self) {
686 g_return_val_if_fail(FL_IS_KEYBOARD_MANAGER(self), nullptr);
687
688 // The embedder responder is the first element in
689 // FlKeyboardManager.responder_list.
690 FlKeyEmbedderResponder* responder =
691 FL_KEY_EMBEDDER_RESPONDER(g_ptr_array_index(self->responder_list, 0));
692 return fl_key_embedder_responder_get_pressed_state(responder);
693 }
_FlKeyEvent::time
guint32 time
Definition: fl_key_event.h:33
_FlKeyboardPendingEvent::any_handled
bool any_handled
Definition: fl_keyboard_manager.cc:138
if
if(end==-1)
Definition: fl_accessible_text_field.cc:42
event
FlKeyEvent * event
Definition: fl_key_channel_responder.cc:118
_FlKeyboardManager::channel
FlMethodChannel * channel
Definition: fl_keyboard_manager.cc:297
fl_keyboard_pending_event_class_init
static void fl_keyboard_pending_event_class_init(FlKeyboardPendingEventClass *klass)
Definition: fl_keyboard_manager.cc:159
layout_goals
const std::vector< LayoutGoal > layout_goals
Definition: key_mapping.g.cc:462
_FlKeyboardManager::pending_redispatches
GPtrArray * pending_redispatches
Definition: fl_keyboard_manager.cc:275
guarantee_layout
static void guarantee_layout(FlKeyboardManager *self, FlKeyEvent *event)
Definition: fl_keyboard_manager.cc:468
fl_method_channel_new
G_MODULE_EXPORT FlMethodChannel * fl_method_channel_new(FlBinaryMessenger *messenger, const gchar *name, FlMethodCodec *codec)
Definition: fl_method_channel.cc:112
compare_pending_by_sequence_id
static gboolean compare_pending_by_sequence_id(gconstpointer pending, gconstpointer needle_sequence_id)
Definition: fl_keyboard_manager.cc:382
fl_keyboard_pending_event_init
static void fl_keyboard_pending_event_init(FlKeyboardPendingEvent *self)
Definition: fl_keyboard_manager.cc:164
fl_key_embedder_responder_get_pressed_state
GHashTable * fl_key_embedder_responder_get_pressed_state(FlKeyEmbedderResponder *self)
Definition: fl_key_embedder_responder.cc:889
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)
Definition: fl_keyboard_manager.cc:184
G_DECLARE_FINAL_TYPE
G_DECLARE_FINAL_TYPE(FlKeyboardPendingEvent, fl_keyboard_pending_event, FL, KEYBOARD_PENDING_EVENT, GObject)
fl_keyboard_view_delegate_subscribe_to_layout_change
void fl_keyboard_view_delegate_subscribe_to_layout_change(FlKeyboardViewDelegate *self, KeyboardLayoutNotifier notifier)
Definition: fl_keyboard_view_delegate.cc:52
LayoutGoal
Definition: key_mapping.h:40
_FlKeyboardManagerUserData::parent_instance
GObject parent_instance
Definition: fl_keyboard_manager.cc:208
fl_method_not_implemented_response_new
G_MODULE_EXPORT FlMethodNotImplementedResponse * fl_method_not_implemented_response_new()
Definition: fl_method_response.cc:179
fl_standard_method_codec_new
G_MODULE_EXPORT FlStandardMethodCodec * fl_standard_method_codec_new()
Definition: fl_standard_method_codec.cc:248
_FlKeyboardManager::pending_responds
GPtrArray * pending_responds
Definition: fl_keyboard_manager.cc:270
fl_keyboard_manager.h
fl_key_embedder_responder.h
fl_method_channel.h
kGetKeyboardStateMethod
static constexpr char kGetKeyboardStateMethod[]
Definition: fl_keyboard_manager.cc:23
FlValue
typedefG_BEGIN_DECLS struct _FlValue FlValue
Definition: fl_value.h:40
LayoutGoal::keycode
uint16_t keycode
Definition: key_mapping.h:42
get_keyboard_state
FlMethodResponse * get_keyboard_state(FlKeyboardManager *self)
Definition: fl_keyboard_manager.cc:544
_FlKeyboardManager::last_sequence_id
uint64_t last_sequence_id
Definition: fl_keyboard_manager.cc:278
_FlKeyboardPendingEvent::hash
uint64_t hash
Definition: fl_keyboard_manager.cc:142
fl_keyboard_manager_dispose
static void fl_keyboard_manager_dispose(GObject *object)
Definition: fl_keyboard_manager.cc:330
responder_handle_event_callback
static void responder_handle_event_callback(bool handled, gpointer user_data_ptr)
Definition: fl_keyboard_manager.cc:418
LayoutGoal::logical_key
uint64_t logical_key
Definition: key_mapping.h:45
user_data
FlKeyEvent uint64_t FlKeyResponderAsyncCallback gpointer user_data
Definition: fl_key_channel_responder.cc:121
fl_value_set_take
G_MODULE_EXPORT void fl_value_set_take(FlValue *self, FlValue *key, FlValue *value)
Definition: fl_value.cc:578
fl_keyboard_manager_remove_redispatched
static bool fl_keyboard_manager_remove_redispatched(FlKeyboardManager *self, uint64_t hash)
Definition: fl_keyboard_manager.cc:402
fl_value_new_int
G_MODULE_EXPORT FlValue * fl_value_new_int(int64_t value)
Definition: fl_value.cc:251
fl_keyboard_manager_is_state_clear
gboolean fl_keyboard_manager_is_state_clear(FlKeyboardManager *self)
Definition: fl_keyboard_manager.cc:666
_FlKeyboardManager::responder_list
GPtrArray * responder_list
Definition: fl_keyboard_manager.cc:263
_FlKeyboardManagerUserData
Definition: fl_keyboard_manager.cc:207
fl_method_success_response_new
G_MODULE_EXPORT FlMethodSuccessResponse * fl_method_success_response_new(FlValue *result)
Definition: fl_method_response.cc:126
_FlKeyEvent
Definition: fl_key_event.h:31
G_DEFINE_TYPE
G_DEFINE_TYPE(FlKeyboardManagerUserData, fl_keyboard_manager_user_data, G_TYPE_OBJECT) static void fl_keyboard_manager_user_data_dispose(GObject *object)
Definition: fl_keyboard_manager.cc:215
state
AtkStateType state
Definition: fl_accessible_node.cc:10
fl_key_channel_responder_new
FlKeyChannelResponder * fl_key_channel_responder_new(FlBinaryMessenger *messenger, FlKeyChannelResponderMock *mock)
Definition: fl_key_channel_responder.cc:186
_FlKeyboardManager::parent_instance
GObject parent_instance
Definition: fl_keyboard_manager.cc:256
_FlKeyboardPendingEvent::sequence_id
uint64_t sequence_id
Definition: fl_keyboard_manager.cc:134
_FlKeyboardManagerUserData::sequence_id
uint64_t sequence_id
Definition: fl_keyboard_manager.cc:212
fl_keyboard_view_delegate_lookup_key
guint fl_keyboard_view_delegate_lookup_key(FlKeyboardViewDelegate *self, const GdkKeymapKey *key)
Definition: fl_keyboard_view_delegate.cc:61
fl_keyboard_manager_handle_event
gboolean fl_keyboard_manager_handle_event(FlKeyboardManager *self, FlKeyEvent *event)
Definition: fl_keyboard_manager.cc:635
dispatch_to_responder
static void dispatch_to_responder(gpointer responder_data, gpointer foreach_data_ptr)
Definition: fl_keyboard_manager.cc:625
_FlKeyboardPendingEvent::parent_instance
GObject parent_instance
Definition: fl_keyboard_manager.cc:124
fl_keyboard_manager_get_event_hash
static uint64_t fl_keyboard_manager_get_event_hash(FlKeyEvent *event)
Definition: fl_keyboard_manager.cc:168
fl_method_call_respond
G_MODULE_EXPORT gboolean fl_method_call_respond(FlMethodCall *self, FlMethodResponse *response, GError **error)
Definition: fl_method_call.cc:77
get_logical_key_from_layout
static uint64_t get_logical_key_from_layout(const FlKeyEvent *event, const DerivedLayout &layout)
Definition: fl_keyboard_manager.cc:97
fl_keyboard_view_delegate_redispatch_event
void fl_keyboard_view_delegate_redispatch_event(FlKeyboardViewDelegate *self, std::unique_ptr< FlKeyEvent > event)
Definition: fl_keyboard_view_delegate.cc:42
fl_value_new_map
G_MODULE_EXPORT FlValue * fl_value_new_map()
Definition: fl_value.cc:355
fl_keyboard_manager_init
static void fl_keyboard_manager_init(FlKeyboardManager *self)
Definition: fl_keyboard_manager.cc:308
fl_key_embedder_responder_new
FlKeyEmbedderResponder * fl_key_embedder_responder_new(EmbedderSendKeyEvent send_key_event)
Definition: fl_key_embedder_responder.cc:262
_FlKeyEvent::keycode
guint16 keycode
Definition: fl_key_event.h:37
method_call
G_BEGIN_DECLS G_MODULE_EXPORT FlMethodCall * method_call
Definition: fl_method_channel.h:120
fl_keyboard_manager_user_data_init
static void fl_keyboard_manager_user_data_init(FlKeyboardManagerUserData *self)
Definition: fl_keyboard_manager.cc:234
fl_key_responder_handle_event
void fl_key_responder_handle_event(FlKeyResponder *self, FlKeyEvent *event, FlKeyResponderAsyncCallback callback, gpointer user_data, uint64_t specified_logical_key)
Definition: fl_key_responder.cc:11
convert_key_to_char
static uint16_t convert_key_to_char(FlKeyboardViewDelegate *view_delegate, guint keycode, gint group, gint level)
Definition: fl_keyboard_manager.cc:456
fl_method_call_get_name
const G_MODULE_EXPORT gchar * fl_method_call_get_name(FlMethodCall *self)
Definition: fl_method_call.cc:67
key_mapping.h
TRUE
return TRUE
Definition: fl_pixel_buffer_texture_test.cc:53
fl_keyboard_pending_event_dispose
static void fl_keyboard_pending_event_dispose(GObject *object)
Definition: fl_keyboard_manager.cc:147
_FlKeyboardManager::derived_layout
std::unique_ptr< DerivedLayout > derived_layout
Definition: fl_keyboard_manager.cc:285
g_object_add_weak_pointer
g_object_add_weak_pointer(G_OBJECT(self), reinterpret_cast< gpointer * >(&self->engine))
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_)
Definition: fl_keyboard_manager.cc:359
fl_keyboard_view_delegate_text_filter_key_press
gboolean fl_keyboard_view_delegate_text_filter_key_press(FlKeyboardViewDelegate *self, FlKeyEvent *event)
Definition: fl_keyboard_view_delegate.cc:25
fl_key_embedder_responder_sync_modifiers_if_needed
void fl_key_embedder_responder_sync_modifiers_if_needed(FlKeyEmbedderResponder *responder, guint state, double event_time)
Definition: fl_key_embedder_responder.cc:872
kChannelName
static constexpr char kChannelName[]
Definition: fl_keyboard_manager.cc:22
FL
FL
Definition: fl_binary_messenger.cc:27
_FlKeyboardPendingEvent::event
std::unique_ptr< FlKeyEvent > event
Definition: fl_keyboard_manager.cc:129
fl_standard_method_codec.h
fl_keyboard_manager_new
FlKeyboardManager * fl_keyboard_manager_new(FlBinaryMessenger *messenger, FlKeyboardViewDelegate *view_delegate)
Definition: fl_keyboard_manager.cc:585
fl_key_event_dispose
void fl_key_event_dispose(FlKeyEvent *event)
Definition: fl_key_event.cc:33
fl_keyboard_manager_user_data_class_init
static void fl_keyboard_manager_user_data_class_init(FlKeyboardManagerUserDataClass *klass)
Definition: fl_keyboard_manager.cc:229
fl_keyboard_manager_sync_modifier_if_needed
void fl_keyboard_manager_sync_modifier_if_needed(FlKeyboardManager *self, guint state, double event_time)
Definition: fl_keyboard_manager.cc:672
fl_keyboard_manager_class_init
static void fl_keyboard_manager_class_init(FlKeyboardManagerClass *klass)
Definition: fl_keyboard_manager.cc:304
fl_method_channel_set_method_call_handler
G_MODULE_EXPORT void fl_method_channel_set_method_call_handler(FlMethodChannel *self, FlMethodChannelMethodCallHandler handler, gpointer user_data, GDestroyNotify destroy_notify)
Definition: fl_method_channel.cc:134
self
GdkEvent FlView * self
Definition: fl_view.cc:100
fl_keyboard_manager_get_pressed_state
GHashTable * fl_keyboard_manager_get_pressed_state(FlKeyboardManager *self)
Definition: fl_keyboard_manager.cc:685
_FlKeyboardManager::view_delegate
FlKeyboardViewDelegate * view_delegate
Definition: fl_keyboard_manager.cc:258
result
GAsyncResult * result
Definition: fl_text_input_plugin.cc:106
error
const uint8_t uint32_t uint32_t GError ** error
Definition: fl_pixel_buffer_texture_test.cc:40
_FlKeyboardManagerUserData::manager
FlKeyboardManager * manager
Definition: fl_keyboard_manager.cc:211
fl_keyboard_manager_user_data_new
static FlKeyboardManagerUserData * fl_keyboard_manager_user_data_new(FlKeyboardManager *manager, uint64_t sequence_id)
Definition: fl_keyboard_manager.cc:238
fl_keyboard_view_delegate_get_messenger
FlBinaryMessenger * fl_keyboard_view_delegate_get_messenger(FlKeyboardViewDelegate *self)
Definition: fl_keyboard_view_delegate.cc:35
buffer
static const uint8_t buffer[]
Definition: fl_pixel_buffer_texture_test.cc:44
specified_logical_key
FlKeyEvent uint64_t specified_logical_key
Definition: fl_key_channel_responder.cc:119
_FlKeyboardPendingEvent
Definition: fl_keyboard_manager.cc:123
callback
FlKeyEvent uint64_t FlKeyResponderAsyncCallback callback
Definition: fl_key_channel_responder.cc:120
fl_key_channel_responder.h
_FlKeyboardManager
Definition: fl_keyboard_manager.cc:255
_FlKeyboardManager::keycode_to_goals
std::unique_ptr< std::map< uint16_t, const LayoutGoal * > > keycode_to_goals
Definition: fl_keyboard_manager.cc:289
method_call_handler
static void method_call_handler(FlMethodChannel *channel, FlMethodCall *method_call, gpointer user_data)
Definition: fl_keyboard_manager.cc:565
fl_keyboard_view_delegate_send_key_event
void fl_keyboard_view_delegate_send_key_event(FlKeyboardViewDelegate *self, const FlutterKeyEvent *event, FlutterKeyEventCallback callback, void *user_data)
Definition: fl_keyboard_view_delegate.cc:14
fl_keyboard_view_delegate_get_keyboard_state
GHashTable * fl_keyboard_view_delegate_get_keyboard_state(FlKeyboardViewDelegate *self)
Definition: fl_keyboard_view_delegate.cc:68
value
uint8_t value
Definition: fl_standard_message_codec.cc:41
compare_pending_by_hash
static gboolean compare_pending_by_hash(gconstpointer pending, gconstpointer needle_hash)
Definition: fl_keyboard_manager.cc:392
_FlKeyboardManager::logical_to_mandatory_goals
std::unique_ptr< std::map< uint64_t, const LayoutGoal * > > logical_to_mandatory_goals
Definition: fl_keyboard_manager.cc:294
_FlKeyboardPendingEvent::unreplied
size_t unreplied
Definition: fl_keyboard_manager.cc:136
FlKeyboardManager
typedefG_BEGIN_DECLS struct _FlKeyboardManager FlKeyboardManager
Definition: fl_key_responder.h:17