Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
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
22static constexpr char kChannelName[] = "flutter/keyboard";
23static constexpr char kGetKeyboardStateMethod[] = "getKeyboardState";
24
25/* Declarations of private classes */
26
27G_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()
35G_DECLARE_FINAL_TYPE(FlKeyboardManagerUserData,
36 fl_keyboard_manager_user_data,
37 FL,
38 KEYBOARD_MANAGER_USER_DATA,
39 GObject);
40
41/* End declarations */
42
43namespace {
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
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
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).
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
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
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.
271
272 // An array of #FlKeyboardPendingEvent.
273 //
274 // Its elements are unreferenced when removed.
276
277 // The last sequence ID used. Increased by 1 by every use.
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.
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.
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) {
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
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)
G_DECLARE_FINAL_TYPE(FlKeyboardPendingEvent, fl_keyboard_pending_event, FL, KEYBOARD_PENDING_EVENT, GObject)
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
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