| Flutter Linux Embedder |

fl_text_input_handler_test.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 <utility>
6
7 #include "flutter/shell/platform/linux/fl_binary_messenger_private.h"
8 #include "flutter/shell/platform/linux/fl_method_codec_private.h"
9 #include "flutter/shell/platform/linux/fl_text_input_handler.h"
10 #include "flutter/shell/platform/linux/testing/fl_mock_binary_messenger.h"
11 #include "flutter/shell/platform/linux/testing/fl_test.h"
12 #include "flutter/shell/platform/linux/testing/mock_im_context.h"
13 #include "flutter/shell/platform/linux/testing/mock_text_input_view_delegate.h"
14 #include "flutter/testing/testing.h"
15
16 #include "gmock/gmock.h"
17 #include "gtest/gtest.h"
18
19 static FlValue* build_map(std::map<const gchar*, FlValue*> args) {
20 FlValue* value = fl_value_new_map();
21 for (auto it = args.begin(); it != args.end(); ++it) {
22 fl_value_set_string_take(value, it->first, it->second);
23 }
24 return value;
25 }
26
27 static FlValue* build_list(std::vector<FlValue*> args) {
28 FlValue* value = fl_value_new_list();
29 for (auto it = args.begin(); it != args.end(); ++it) {
30 fl_value_append_take(value, *it);
31 }
32 return value;
33 }
34
35 struct InputConfig {
36 int64_t client_id = -1;
37 const gchar* input_type = "TextInputType.text";
38 const gchar* input_action = "TextInputAction.none";
39 gboolean enable_delta_model = false;
40 };
41
42 static FlValue* build_input_config(InputConfig config) {
43 return build_list({
44 fl_value_new_int(config.client_id),
45 build_map({
46 {"inputAction", fl_value_new_string(config.input_action)},
47 {"inputType", build_map({
48 {"name", fl_value_new_string(config.input_type)},
49 })},
50 {"enableDeltaModel", fl_value_new_bool(config.enable_delta_model)},
51 }),
52 });
53 }
54
55 struct EditingState {
56 const gchar* text = "";
57 int selection_base = -1;
58 int selection_extent = -1;
59 int composing_base = -1;
60 int composing_extent = -1;
61 };
62
63 static FlValue* build_editing_state(EditingState state) {
64 return build_map({
65 {"text", fl_value_new_string(state.text)},
66 {"selectionBase", fl_value_new_int(state.selection_base)},
67 {"selectionExtent", fl_value_new_int(state.selection_extent)},
68 {"selectionAffinity", fl_value_new_string("TextAffinity.downstream")},
69 {"selectionIsDirectional", fl_value_new_bool(false)},
70 {"composingBase", fl_value_new_int(state.composing_base)},
71 {"composingExtent", fl_value_new_int(state.composing_extent)},
72 });
73 }
74
75 struct EditingDelta {
76 const gchar* old_text = "";
77 const gchar* delta_text = "";
78 int delta_start = -1;
79 int delta_end = -1;
80 int selection_base = -1;
81 int selection_extent = -1;
82 int composing_base = -1;
83 int composing_extent = -1;
84 };
85
86 static FlValue* build_editing_delta(EditingDelta delta) {
87 return build_map({
88 {"oldText", fl_value_new_string(delta.old_text)},
89 {"deltaText", fl_value_new_string(delta.delta_text)},
90 {"deltaStart", fl_value_new_int(delta.delta_start)},
91 {"deltaEnd", fl_value_new_int(delta.delta_end)},
92 {"selectionBase", fl_value_new_int(delta.selection_base)},
93 {"selectionExtent", fl_value_new_int(delta.selection_extent)},
94 {"selectionAffinity", fl_value_new_string("TextAffinity.downstream")},
95 {"selectionIsDirectional", fl_value_new_bool(false)},
96 {"composingBase", fl_value_new_int(delta.composing_base)},
97 {"composingExtent", fl_value_new_int(delta.composing_extent)},
98 });
99 }
100
101 static void set_client(FlMockBinaryMessenger* messenger, InputConfig config) {
102 gboolean called = FALSE;
103 g_autoptr(FlValue) args = build_input_config(config);
104 fl_mock_binary_messenger_invoke_json_method(
105 messenger, "flutter/textinput", "TextInput.setClient", args,
106 [](FlMockBinaryMessenger* messenger, FlMethodResponse* response,
107 gpointer user_data) {
108 gboolean* called = static_cast<gboolean*>(user_data);
109 *called = TRUE;
110
111 EXPECT_TRUE(FL_IS_METHOD_SUCCESS_RESPONSE(response));
112
113 g_autoptr(FlValue) expected_result = fl_value_new_null();
114 EXPECT_TRUE(fl_value_equal(fl_method_success_response_get_result(
115 FL_METHOD_SUCCESS_RESPONSE(response)),
116 expected_result));
117 },
118 &called);
119 EXPECT_TRUE(called);
120 }
121
122 static void set_editing_state(FlMockBinaryMessenger* messenger,
123 EditingState state) {
124 gboolean called = FALSE;
125 g_autoptr(FlValue) args = build_editing_state(state);
126 fl_mock_binary_messenger_invoke_json_method(
127 messenger, "flutter/textinput", "TextInput.setEditingState", args,
128 [](FlMockBinaryMessenger* messenger, FlMethodResponse* response,
129 gpointer user_data) {
130 gboolean* called = static_cast<gboolean*>(user_data);
131 *called = TRUE;
132
133 EXPECT_TRUE(FL_IS_METHOD_SUCCESS_RESPONSE(response));
134
135 g_autoptr(FlValue) expected_result = fl_value_new_null();
136 EXPECT_TRUE(fl_value_equal(fl_method_success_response_get_result(
137 FL_METHOD_SUCCESS_RESPONSE(response)),
138 expected_result));
139 },
140 &called);
141 EXPECT_TRUE(called);
142 }
143
144 static void send_key_event(FlTextInputHandler* handler,
145 gint keyval,
146 gint state = 0) {
147 GdkEvent* gdk_event = gdk_event_new(GDK_KEY_PRESS);
148 gdk_event->key.keyval = keyval;
149 gdk_event->key.state = state;
150 g_autoptr(FlKeyEvent) key_event = fl_key_event_new_from_gdk_event(gdk_event);
151 fl_text_input_handler_filter_keypress(handler, key_event);
152 }
153
154 TEST(FlTextInputHandlerTest, MessageHandler) {
155 g_autoptr(FlMockBinaryMessenger) messenger = fl_mock_binary_messenger_new();
156 ::testing::NiceMock<flutter::testing::MockIMContext> context;
157 ::testing::NiceMock<flutter::testing::MockTextInputViewDelegate> delegate;
158
159 g_autoptr(FlTextInputHandler) handler = fl_text_input_handler_new(
160 FL_BINARY_MESSENGER(messenger), context, delegate);
161 EXPECT_NE(handler, nullptr);
162
163 EXPECT_TRUE(
164 fl_mock_binary_messenger_has_handler(messenger, "flutter/textinput"));
165
166 fl_binary_messenger_shutdown(FL_BINARY_MESSENGER(messenger));
167 }
168
169 TEST(FlTextInputHandlerTest, SetClient) {
170 g_autoptr(FlMockBinaryMessenger) messenger = fl_mock_binary_messenger_new();
171 ::testing::NiceMock<flutter::testing::MockIMContext> context;
172 ::testing::NiceMock<flutter::testing::MockTextInputViewDelegate> delegate;
173
174 g_autoptr(FlTextInputHandler) handler = fl_text_input_handler_new(
175 FL_BINARY_MESSENGER(messenger), context, delegate);
176 EXPECT_NE(handler, nullptr);
177
178 set_client(messenger, {.client_id = 1});
179
180 fl_binary_messenger_shutdown(FL_BINARY_MESSENGER(messenger));
181 }
182
183 TEST(FlTextInputHandlerTest, Show) {
184 g_autoptr(FlMockBinaryMessenger) messenger = fl_mock_binary_messenger_new();
185 ::testing::NiceMock<flutter::testing::MockIMContext> context;
186 ::testing::NiceMock<flutter::testing::MockTextInputViewDelegate> delegate;
187
188 g_autoptr(FlTextInputHandler) handler = fl_text_input_handler_new(
189 FL_BINARY_MESSENGER(messenger), context, delegate);
190 EXPECT_NE(handler, nullptr);
191
192 EXPECT_CALL(context,
193 gtk_im_context_focus_in(::testing::Eq<GtkIMContext*>(context)));
194
195 gboolean called = FALSE;
196 fl_mock_binary_messenger_invoke_json_method(
197 messenger, "flutter/textinput", "TextInput.show", nullptr,
198 [](FlMockBinaryMessenger* messenger, FlMethodResponse* response,
199 gpointer user_data) {
200 gboolean* called = static_cast<gboolean*>(user_data);
201 *called = TRUE;
202
203 EXPECT_TRUE(FL_IS_METHOD_SUCCESS_RESPONSE(response));
204
205 g_autoptr(FlValue) expected_result = fl_value_new_null();
206 EXPECT_TRUE(fl_value_equal(fl_method_success_response_get_result(
207 FL_METHOD_SUCCESS_RESPONSE(response)),
208 expected_result));
209 },
210 &called);
211 EXPECT_TRUE(called);
212
213 fl_binary_messenger_shutdown(FL_BINARY_MESSENGER(messenger));
214 }
215
216 TEST(FlTextInputHandlerTest, Hide) {
217 g_autoptr(FlMockBinaryMessenger) messenger = fl_mock_binary_messenger_new();
218 ::testing::NiceMock<flutter::testing::MockIMContext> context;
219 ::testing::NiceMock<flutter::testing::MockTextInputViewDelegate> delegate;
220
221 g_autoptr(FlTextInputHandler) handler = fl_text_input_handler_new(
222 FL_BINARY_MESSENGER(messenger), context, delegate);
223 EXPECT_NE(handler, nullptr);
224
225 EXPECT_CALL(context,
226 gtk_im_context_focus_out(::testing::Eq<GtkIMContext*>(context)));
227
228 gboolean called = FALSE;
229 fl_mock_binary_messenger_invoke_json_method(
230 messenger, "flutter/textinput", "TextInput.hide", nullptr,
231 [](FlMockBinaryMessenger* messenger, FlMethodResponse* response,
232 gpointer user_data) {
233 gboolean* called = static_cast<gboolean*>(user_data);
234 *called = TRUE;
235
236 EXPECT_TRUE(FL_IS_METHOD_SUCCESS_RESPONSE(response));
237
238 g_autoptr(FlValue) expected_result = fl_value_new_null();
239 EXPECT_TRUE(fl_value_equal(fl_method_success_response_get_result(
240 FL_METHOD_SUCCESS_RESPONSE(response)),
241 expected_result));
242 },
243 &called);
244 EXPECT_TRUE(called);
245
246 fl_binary_messenger_shutdown(FL_BINARY_MESSENGER(messenger));
247 }
248
249 TEST(FlTextInputHandlerTest, ClearClient) {
250 g_autoptr(FlMockBinaryMessenger) messenger = fl_mock_binary_messenger_new();
251 ::testing::NiceMock<flutter::testing::MockIMContext> context;
252 ::testing::NiceMock<flutter::testing::MockTextInputViewDelegate> delegate;
253
254 g_autoptr(FlTextInputHandler) handler = fl_text_input_handler_new(
255 FL_BINARY_MESSENGER(messenger), context, delegate);
256 EXPECT_NE(handler, nullptr);
257
258 gboolean called = FALSE;
259 fl_mock_binary_messenger_invoke_json_method(
260 messenger, "flutter/textinput", "TextInput.clearClient", nullptr,
261 [](FlMockBinaryMessenger* messenger, FlMethodResponse* response,
262 gpointer user_data) {
263 gboolean* called = static_cast<gboolean*>(user_data);
264 *called = TRUE;
265
266 EXPECT_TRUE(FL_IS_METHOD_SUCCESS_RESPONSE(response));
267
268 g_autoptr(FlValue) expected_result = fl_value_new_null();
269 EXPECT_TRUE(fl_value_equal(fl_method_success_response_get_result(
270 FL_METHOD_SUCCESS_RESPONSE(response)),
271 expected_result));
272 },
273 &called);
274 EXPECT_TRUE(called);
275
276 fl_binary_messenger_shutdown(FL_BINARY_MESSENGER(messenger));
277 }
278
279 TEST(FlTextInputHandlerTest, PerformAction) {
280 g_autoptr(FlMockBinaryMessenger) messenger = fl_mock_binary_messenger_new();
281 ::testing::NiceMock<flutter::testing::MockIMContext> context;
282 ::testing::NiceMock<flutter::testing::MockTextInputViewDelegate> delegate;
283
284 g_autoptr(FlTextInputHandler) handler = fl_text_input_handler_new(
285 FL_BINARY_MESSENGER(messenger), context, delegate);
286 EXPECT_NE(handler, nullptr);
287
288 set_client(messenger, {
289 .client_id = 1,
290 .input_type = "TextInputType.multiline",
291 .input_action = "TextInputAction.newline",
292 });
293 set_editing_state(messenger, {
294 .text = "Flutter",
295 .selection_base = 7,
296 .selection_extent = 7,
297 });
298
299 // Client will update editing state and perform action
300 int call_count = 0;
301 fl_mock_binary_messenger_set_json_method_channel(
302 messenger, "flutter/textinput",
303 [](FlMockBinaryMessenger* messenger, GTask* task, const gchar* name,
304 FlValue* args, gpointer user_data) {
305 int* call_count = static_cast<int*>(user_data);
306
307 if (strcmp(name, "TextInputClient.updateEditingState") == 0) {
308 g_autoptr(FlValue) expected_args = build_list({
309 fl_value_new_int(1), // client_id
310 build_editing_state({
311 .text = "Flutter\n",
312 .selection_base = 8,
313 .selection_extent = 8,
314 }),
315 });
316 EXPECT_TRUE(fl_value_equal(args, expected_args));
317 EXPECT_EQ(*call_count, 0);
318 (*call_count)++;
319 } else if (strcmp(name, "TextInputClient.performAction") == 0) {
320 g_autoptr(FlValue) expected_args = build_list({
321 fl_value_new_int(1), // client_id
322 fl_value_new_string("TextInputAction.newline"),
323 });
324 EXPECT_TRUE(fl_value_equal(args, expected_args));
325 EXPECT_EQ(*call_count, 1);
326 (*call_count)++;
327 }
328
329 return FL_METHOD_RESPONSE(fl_method_success_response_new(nullptr));
330 },
331 &call_count);
332
333 send_key_event(handler, GDK_KEY_Return);
334 EXPECT_EQ(call_count, 2);
335
336 fl_binary_messenger_shutdown(FL_BINARY_MESSENGER(messenger));
337 }
338
339 // Regression test for https://github.com/flutter/flutter/issues/125879.
340 TEST(FlTextInputHandlerTest, MultilineWithSendAction) {
341 g_autoptr(FlMockBinaryMessenger) messenger = fl_mock_binary_messenger_new();
342 ::testing::NiceMock<flutter::testing::MockIMContext> context;
343 ::testing::NiceMock<flutter::testing::MockTextInputViewDelegate> delegate;
344
345 g_autoptr(FlTextInputHandler) handler = fl_text_input_handler_new(
346 FL_BINARY_MESSENGER(messenger), context, delegate);
347 EXPECT_NE(handler, nullptr);
348
349 set_client(messenger, {
350 .client_id = 1,
351 .input_type = "TextInputType.multiline",
352 .input_action = "TextInputAction.send",
353 });
354 set_editing_state(messenger, {
355 .text = "Flutter",
356 .selection_base = 7,
357 .selection_extent = 7,
358 });
359
360 // Because the input action is not set to TextInputAction.newline, the next
361 // expected call is "TextInputClient.performAction". If the input action was
362 // set to TextInputAction.newline the next call would be
363 // "TextInputClient.updateEditingState" (this case is tested in the test named
364 // 'PerformAction').
365 int call_count = 0;
366 fl_mock_binary_messenger_set_json_method_channel(
367 messenger, "flutter/textinput",
368 [](FlMockBinaryMessenger* messenger, GTask* task, const gchar* name,
369 FlValue* args, gpointer user_data) {
370 int* call_count = static_cast<int*>(user_data);
371
372 EXPECT_STREQ(name, "TextInputClient.performAction");
373 g_autoptr(FlValue) expected_args = nullptr;
374 switch (*call_count) {
375 case 0:
376 // Perform action.
377 expected_args = build_list({
378 fl_value_new_int(1), // client_id
379 fl_value_new_string("TextInputAction.send"),
380 });
381 break;
382 default:
383 g_assert_not_reached();
384 break;
385 }
386 EXPECT_TRUE(fl_value_equal(args, expected_args));
387 (*call_count)++;
388
389 return FL_METHOD_RESPONSE(fl_method_success_response_new(nullptr));
390 },
391 &call_count);
392
393 send_key_event(handler, GDK_KEY_Return);
394 EXPECT_EQ(call_count, 1);
395
396 fl_binary_messenger_shutdown(FL_BINARY_MESSENGER(messenger));
397 }
398
399 TEST(FlTextInputHandlerTest, MoveCursor) {
400 g_autoptr(FlMockBinaryMessenger) messenger = fl_mock_binary_messenger_new();
401 ::testing::NiceMock<flutter::testing::MockIMContext> context;
402 ::testing::NiceMock<flutter::testing::MockTextInputViewDelegate> delegate;
403
404 g_autoptr(FlTextInputHandler) handler = fl_text_input_handler_new(
405 FL_BINARY_MESSENGER(messenger), context, delegate);
406 EXPECT_NE(handler, nullptr);
407
408 set_client(messenger, {.client_id = 1});
409 set_editing_state(messenger, {
410 .text = "Flutter",
411 .selection_base = 4,
412 .selection_extent = 4,
413 });
414
415 int call_count = 0;
416 fl_mock_binary_messenger_set_json_method_channel(
417 messenger, "flutter/textinput",
418 [](FlMockBinaryMessenger* messenger, GTask* task, const gchar* name,
419 FlValue* args, gpointer user_data) {
420 int* call_count = static_cast<int*>(user_data);
421
422 EXPECT_STREQ(name, "TextInputClient.updateEditingState");
423 g_autoptr(FlValue) expected_args = nullptr;
424 switch (*call_count) {
425 case 0:
426 // move cursor to beginning
427 expected_args = build_list({
428 fl_value_new_int(1), // client_id
429 build_editing_state({
430 .text = "Flutter",
431 .selection_base = 0,
432 .selection_extent = 0,
433 }),
434 });
435 break;
436 case 1:
437 // move cursor to end
438 expected_args = build_list({
439 fl_value_new_int(1), // client_id
440 build_editing_state({
441 .text = "Flutter",
442 .selection_base = 7,
443 .selection_extent = 7,
444 }),
445 });
446 break;
447 default:
448 g_assert_not_reached();
449 break;
450 }
451 EXPECT_TRUE(fl_value_equal(args, expected_args));
452 (*call_count)++;
453
454 return FL_METHOD_RESPONSE(fl_method_success_response_new(nullptr));
455 },
456 &call_count);
457
458 send_key_event(handler, GDK_KEY_Home);
459 send_key_event(handler, GDK_KEY_End);
460 EXPECT_EQ(call_count, 2);
461
462 fl_binary_messenger_shutdown(FL_BINARY_MESSENGER(messenger));
463 }
464
465 TEST(FlTextInputHandlerTest, Select) {
466 g_autoptr(FlMockBinaryMessenger) messenger = fl_mock_binary_messenger_new();
467 ::testing::NiceMock<flutter::testing::MockIMContext> context;
468 ::testing::NiceMock<flutter::testing::MockTextInputViewDelegate> delegate;
469
470 g_autoptr(FlTextInputHandler) handler = fl_text_input_handler_new(
471 FL_BINARY_MESSENGER(messenger), context, delegate);
472 EXPECT_NE(handler, nullptr);
473
474 set_client(messenger, {.client_id = 1});
475 set_editing_state(messenger, {
476 .text = "Flutter",
477 .selection_base = 4,
478 .selection_extent = 4,
479 });
480
481 int call_count = 0;
482 fl_mock_binary_messenger_set_json_method_channel(
483 messenger, "flutter/textinput",
484 [](FlMockBinaryMessenger* messenger, GTask* task, const gchar* name,
485 FlValue* args, gpointer user_data) {
486 int* call_count = static_cast<int*>(user_data);
487
488 EXPECT_STREQ(name, "TextInputClient.updateEditingState");
489 g_autoptr(FlValue) expected_args = nullptr;
490 switch (*call_count) {
491 case 0:
492 // select to end
493 expected_args = build_list({
494 fl_value_new_int(1), // client_id
495 build_editing_state({
496 .text = "Flutter",
497 .selection_base = 4,
498 .selection_extent = 7,
499 }),
500 });
501 break;
502 case 1:
503 // select to beginning
504 expected_args = build_list({
505 fl_value_new_int(1), // client_id
506 build_editing_state({
507 .text = "Flutter",
508 .selection_base = 4,
509 .selection_extent = 0,
510 }),
511 });
512 break;
513 default:
514 g_assert_not_reached();
515 break;
516 }
517 EXPECT_TRUE(fl_value_equal(args, expected_args));
518 (*call_count)++;
519
520 return FL_METHOD_RESPONSE(fl_method_success_response_new(nullptr));
521 },
522 &call_count);
523
524 send_key_event(handler, GDK_KEY_End, GDK_SHIFT_MASK);
525 send_key_event(handler, GDK_KEY_Home, GDK_SHIFT_MASK);
526 EXPECT_EQ(call_count, 2);
527
528 fl_binary_messenger_shutdown(FL_BINARY_MESSENGER(messenger));
529 }
530
531 TEST(FlTextInputHandlerTest, Composing) {
532 g_autoptr(FlMockBinaryMessenger) messenger = fl_mock_binary_messenger_new();
533 ::testing::NiceMock<flutter::testing::MockIMContext> context;
534 ::testing::NiceMock<flutter::testing::MockTextInputViewDelegate> delegate;
535
536 g_autoptr(FlTextInputHandler) handler = fl_text_input_handler_new(
537 FL_BINARY_MESSENGER(messenger), context, delegate);
538 EXPECT_NE(handler, nullptr);
539
540 // update
541 EXPECT_CALL(context,
542 gtk_im_context_get_preedit_string(
543 ::testing::Eq<GtkIMContext*>(context),
544 ::testing::A<gchar**>(), ::testing::_, ::testing::A<gint*>()))
545 .WillOnce(
546 ::testing::DoAll(::testing::SetArgPointee<1>(g_strdup("Flutter")),
547 ::testing::SetArgPointee<3>(0)));
548
549 int call_count = 0;
550 fl_mock_binary_messenger_set_json_method_channel(
551 messenger, "flutter/textinput",
552 [](FlMockBinaryMessenger* messenger, GTask* task, const gchar* name,
553 FlValue* args, gpointer user_data) {
554 int* call_count = static_cast<int*>(user_data);
555
556 EXPECT_STREQ(name, "TextInputClient.updateEditingState");
557 g_autoptr(FlValue) expected_args = nullptr;
558 switch (*call_count) {
559 case 0:
560 expected_args = build_list({
561 fl_value_new_int(-1), // client_id
562 build_editing_state({
563 .text = "Flutter",
564 .selection_base = 0,
565 .selection_extent = 0,
566 .composing_base = 0,
567 .composing_extent = 7,
568 }),
569 });
570 break;
571 case 1:
572 // commit
573 expected_args = build_list({
574 fl_value_new_int(-1), // client_id
575 build_editing_state({
576 .text = "engine",
577 .selection_base = 6,
578 .selection_extent = 6,
579 }),
580 });
581 break;
582 case 2:
583 // end
584 expected_args = build_list({
585 fl_value_new_int(-1), // client_id
586 build_editing_state({
587 .text = "engine",
588 .selection_base = 6,
589 .selection_extent = 6,
590 }),
591 });
592 break;
593 default:
594 g_assert_not_reached();
595 break;
596 }
597 EXPECT_TRUE(fl_value_equal(args, expected_args));
598 (*call_count)++;
599
600 return FL_METHOD_RESPONSE(fl_method_success_response_new(nullptr));
601 },
602 &call_count);
603
604 g_signal_emit_by_name(context, "preedit-start", nullptr);
605 g_signal_emit_by_name(context, "preedit-changed", nullptr);
606 g_signal_emit_by_name(context, "commit", "engine", nullptr);
607 g_signal_emit_by_name(context, "preedit-end", nullptr);
608 EXPECT_EQ(call_count, 3);
609
610 fl_binary_messenger_shutdown(FL_BINARY_MESSENGER(messenger));
611 }
612
613 TEST(FlTextInputHandlerTest, SurroundingText) {
614 g_autoptr(FlMockBinaryMessenger) messenger = fl_mock_binary_messenger_new();
615 ::testing::NiceMock<flutter::testing::MockIMContext> context;
616 ::testing::NiceMock<flutter::testing::MockTextInputViewDelegate> delegate;
617
618 g_autoptr(FlTextInputHandler) handler = fl_text_input_handler_new(
619 FL_BINARY_MESSENGER(messenger), context, delegate);
620 EXPECT_NE(handler, nullptr);
621
622 set_client(messenger, {.client_id = 1});
623 set_editing_state(messenger, {
624 .text = "Flutter",
625 .selection_base = 3,
626 .selection_extent = 3,
627 });
628
629 // retrieve
630 EXPECT_CALL(context, gtk_im_context_set_surrounding(
631 ::testing::Eq<GtkIMContext*>(context),
632 ::testing::StrEq("Flutter"), 7, 3));
633
634 gboolean retrieved = false;
635 g_signal_emit_by_name(context, "retrieve-surrounding", &retrieved, nullptr);
636 EXPECT_TRUE(retrieved);
637
638 int call_count = 0;
639 fl_mock_binary_messenger_set_json_method_channel(
640 messenger, "flutter/textinput",
641 [](FlMockBinaryMessenger* messenger, GTask* task, const gchar* name,
642 FlValue* args, gpointer user_data) {
643 int* call_count = static_cast<int*>(user_data);
644
645 EXPECT_STREQ(name, "TextInputClient.updateEditingState");
646 g_autoptr(FlValue) expected_args = nullptr;
647 switch (*call_count) {
648 case 0:
649 // delete
650 expected_args = build_list({
651 fl_value_new_int(1), // client_id
652 build_editing_state({
653 .text = "Flutr",
654 .selection_base = 3,
655 .selection_extent = 3,
656 }),
657 });
658 break;
659 default:
660 g_assert_not_reached();
661 break;
662 }
663 EXPECT_TRUE(fl_value_equal(args, expected_args));
664 (*call_count)++;
665
666 return FL_METHOD_RESPONSE(fl_method_success_response_new(nullptr));
667 },
668 &call_count);
669
670 gboolean deleted = false;
671 g_signal_emit_by_name(context, "delete-surrounding", 1, 2, &deleted, nullptr);
672 EXPECT_TRUE(deleted);
673 EXPECT_EQ(call_count, 1);
674
675 fl_binary_messenger_shutdown(FL_BINARY_MESSENGER(messenger));
676 }
677
678 TEST(FlTextInputHandlerTest, SetMarkedTextRect) {
679 g_autoptr(FlMockBinaryMessenger) messenger = fl_mock_binary_messenger_new();
680 ::testing::NiceMock<flutter::testing::MockIMContext> context;
681 ::testing::NiceMock<flutter::testing::MockTextInputViewDelegate> delegate;
682
683 g_autoptr(FlTextInputHandler) handler = fl_text_input_handler_new(
684 FL_BINARY_MESSENGER(messenger), context, delegate);
685 EXPECT_NE(handler, nullptr);
686
687 g_signal_emit_by_name(context, "preedit-start", nullptr);
688
689 // set editable size and transform
690 g_autoptr(FlValue) size_and_transform = build_map({
691 {
692 "transform",
693 build_list({
694 fl_value_new_float(1),
695 fl_value_new_float(2),
696 fl_value_new_float(3),
697 fl_value_new_float(4),
698 fl_value_new_float(5),
699 fl_value_new_float(6),
700 fl_value_new_float(7),
701 fl_value_new_float(8),
702 fl_value_new_float(9),
703 fl_value_new_float(10),
704 fl_value_new_float(11),
705 fl_value_new_float(12),
706 fl_value_new_float(13),
707 fl_value_new_float(14),
708 fl_value_new_float(15),
709 fl_value_new_float(16),
710 }),
711 },
712 });
713 gboolean called = FALSE;
714 fl_mock_binary_messenger_invoke_json_method(
715 messenger, "flutter/textinput", "TextInput.setEditableSizeAndTransform",
716 size_and_transform,
717 [](FlMockBinaryMessenger* messenger, FlMethodResponse* response,
718 gpointer user_data) {
719 gboolean* called = static_cast<gboolean*>(user_data);
720 *called = TRUE;
721
722 EXPECT_TRUE(FL_IS_METHOD_SUCCESS_RESPONSE(response));
723
724 g_autoptr(FlValue) expected_result = fl_value_new_null();
725 EXPECT_TRUE(fl_value_equal(fl_method_success_response_get_result(
726 FL_METHOD_SUCCESS_RESPONSE(response)),
727 expected_result));
728 },
729 &called);
730 EXPECT_TRUE(called);
731
732 EXPECT_CALL(delegate, fl_text_input_view_delegate_translate_coordinates(
733 ::testing::Eq<FlTextInputViewDelegate*>(delegate),
734 ::testing::Eq(27), ::testing::Eq(32), ::testing::_,
735 ::testing::_))
736 .WillOnce(::testing::DoAll(::testing::SetArgPointee<3>(123),
737 ::testing::SetArgPointee<4>(456)));
738
739 EXPECT_CALL(context, gtk_im_context_set_cursor_location(
740 ::testing::Eq<GtkIMContext*>(context),
741 ::testing::Pointee(::testing::AllOf(
742 ::testing::Field(&GdkRectangle::x, 123),
743 ::testing::Field(&GdkRectangle::y, 456),
744 ::testing::Field(&GdkRectangle::width, 0),
745 ::testing::Field(&GdkRectangle::height, 0)))));
746
747 // set marked text rect
748 g_autoptr(FlValue) rect = build_map({
749 {"x", fl_value_new_float(1)},
750 {"y", fl_value_new_float(2)},
751 {"width", fl_value_new_float(3)},
752 {"height", fl_value_new_float(4)},
753 });
754 called = FALSE;
755 fl_mock_binary_messenger_invoke_json_method(
756 messenger, "flutter/textinput", "TextInput.setMarkedTextRect", rect,
757 [](FlMockBinaryMessenger* messenger, FlMethodResponse* response,
758 gpointer user_data) {
759 gboolean* called = static_cast<gboolean*>(user_data);
760 *called = TRUE;
761
762 EXPECT_TRUE(FL_IS_METHOD_SUCCESS_RESPONSE(response));
763
764 g_autoptr(FlValue) expected_result = fl_value_new_null();
765 EXPECT_TRUE(fl_value_equal(fl_method_success_response_get_result(
766 FL_METHOD_SUCCESS_RESPONSE(response)),
767 expected_result));
768 },
769 &called);
770 EXPECT_TRUE(called);
771
772 fl_binary_messenger_shutdown(FL_BINARY_MESSENGER(messenger));
773 }
774
775 TEST(FlTextInputHandlerTest, TextInputTypeNone) {
776 g_autoptr(FlMockBinaryMessenger) messenger = fl_mock_binary_messenger_new();
777 ::testing::NiceMock<flutter::testing::MockIMContext> context;
778 ::testing::NiceMock<flutter::testing::MockTextInputViewDelegate> delegate;
779
780 g_autoptr(FlTextInputHandler) handler = fl_text_input_handler_new(
781 FL_BINARY_MESSENGER(messenger), context, delegate);
782 EXPECT_NE(handler, nullptr);
783
784 set_client(messenger, {
785 .client_id = 1,
786 .input_type = "TextInputType.none",
787 });
788
789 EXPECT_CALL(context,
790 gtk_im_context_focus_in(::testing::Eq<GtkIMContext*>(context)))
791 .Times(0);
792 EXPECT_CALL(context,
793 gtk_im_context_focus_out(::testing::Eq<GtkIMContext*>(context)));
794
795 gboolean called = FALSE;
796 fl_mock_binary_messenger_invoke_json_method(
797 messenger, "flutter/textinput", "TextInput.show", nullptr,
798 [](FlMockBinaryMessenger* messenger, FlMethodResponse* response,
799 gpointer user_data) {
800 gboolean* called = static_cast<gboolean*>(user_data);
801 *called = TRUE;
802
803 EXPECT_TRUE(FL_IS_METHOD_SUCCESS_RESPONSE(response));
804
805 g_autoptr(FlValue) expected_result = fl_value_new_null();
806 EXPECT_TRUE(fl_value_equal(fl_method_success_response_get_result(
807 FL_METHOD_SUCCESS_RESPONSE(response)),
808 expected_result));
809 },
810 &called);
811 EXPECT_TRUE(called);
812
813 fl_binary_messenger_shutdown(FL_BINARY_MESSENGER(messenger));
814 }
815
816 TEST(FlTextInputHandlerTest, TextEditingDelta) {
817 g_autoptr(FlMockBinaryMessenger) messenger = fl_mock_binary_messenger_new();
818 ::testing::NiceMock<flutter::testing::MockIMContext> context;
819 ::testing::NiceMock<flutter::testing::MockTextInputViewDelegate> delegate;
820
821 g_autoptr(FlTextInputHandler) handler = fl_text_input_handler_new(
822 FL_BINARY_MESSENGER(messenger), context, delegate);
823 EXPECT_NE(handler, nullptr);
824
825 set_client(messenger, {
826 .client_id = 1,
827 .enable_delta_model = true,
828 });
829 set_editing_state(messenger, {
830 .text = "Flutter",
831 .selection_base = 7,
832 .selection_extent = 7,
833 });
834
835 // update editing state with deltas
836 int call_count = 0;
837 fl_mock_binary_messenger_set_json_method_channel(
838 messenger, "flutter/textinput",
839 [](FlMockBinaryMessenger* messenger, GTask* task, const gchar* name,
840 FlValue* args, gpointer user_data) {
841 int* call_count = static_cast<int*>(user_data);
842
843 EXPECT_STREQ(name, "TextInputClient.updateEditingStateWithDeltas");
844 g_autoptr(FlValue) expected_args = nullptr;
845 switch (*call_count) {
846 case 0:
847 expected_args = build_list({
848 fl_value_new_int(1), // client_id
849 build_map({{
850 "deltas",
851 build_list({
852 build_editing_delta({
853 .old_text = "Flutter",
854 .delta_text = "Flutter",
855 .delta_start = 7,
856 .delta_end = 7,
857 .selection_base = 0,
858 .selection_extent = 0,
859 }),
860 }),
861 }}),
862 });
863 break;
864 default:
865 g_assert_not_reached();
866 break;
867 }
868 EXPECT_TRUE(fl_value_equal(args, expected_args));
869 (*call_count)++;
870
871 return FL_METHOD_RESPONSE(fl_method_success_response_new(nullptr));
872 },
873 &call_count);
874
875 send_key_event(handler, GDK_KEY_Home);
876 EXPECT_EQ(call_count, 1);
877
878 fl_binary_messenger_shutdown(FL_BINARY_MESSENGER(messenger));
879 }
880
881 TEST(FlTextInputHandlerTest, ComposingDelta) {
882 g_autoptr(FlMockBinaryMessenger) messenger = fl_mock_binary_messenger_new();
883 ::testing::NiceMock<flutter::testing::MockIMContext> context;
884 ::testing::NiceMock<flutter::testing::MockTextInputViewDelegate> delegate;
885
886 g_autoptr(FlTextInputHandler) handler = fl_text_input_handler_new(
887 FL_BINARY_MESSENGER(messenger), context, delegate);
888 EXPECT_NE(handler, nullptr);
889
890 // set config
891 set_client(messenger, {
892 .client_id = 1,
893 .enable_delta_model = true,
894 });
895
896 g_signal_emit_by_name(context, "preedit-start", nullptr);
897
898 // update
899 EXPECT_CALL(context,
900 gtk_im_context_get_preedit_string(
901 ::testing::Eq<GtkIMContext*>(context),
902 ::testing::A<gchar**>(), ::testing::_, ::testing::A<gint*>()))
903 .WillOnce(
904 ::testing::DoAll(::testing::SetArgPointee<1>(g_strdup("Flutter ")),
905 ::testing::SetArgPointee<3>(8)));
906
907 int call_count = 0;
908 fl_mock_binary_messenger_set_json_method_channel(
909 messenger, "flutter/textinput",
910 [](FlMockBinaryMessenger* messenger, GTask* task, const gchar* name,
911 FlValue* args, gpointer user_data) {
912 int* call_count = static_cast<int*>(user_data);
913
914 EXPECT_STREQ(name, "TextInputClient.updateEditingStateWithDeltas");
915 g_autoptr(FlValue) expected_args = nullptr;
916 switch (*call_count) {
917 case 0:
918 expected_args = build_list({
919 fl_value_new_int(1), // client_id
920 build_map({{
921 "deltas",
922 build_list({
923 build_editing_delta({
924 .old_text = "",
925 .delta_text = "Flutter ",
926 .delta_start = 0,
927 .delta_end = 0,
928 .selection_base = 8,
929 .selection_extent = 8,
930 .composing_base = 0,
931 .composing_extent = 8,
932 }),
933 }),
934 }}),
935 });
936 break;
937 case 1:
938 // commit
939 expected_args = build_list({
940 fl_value_new_int(1), // client_id
941 build_map({{
942 "deltas",
943 build_list({
944 build_editing_delta({
945 .old_text = "Flutter ",
946 .delta_text = "Flutter engine",
947 .delta_start = 0,
948 .delta_end = 8,
949 .selection_base = 14,
950 .selection_extent = 14,
951 .composing_base = -1,
952 .composing_extent = -1,
953 }),
954 }),
955 }}),
956 });
957 break;
958 case 2:
959 // end
960 expected_args = build_list({
961 fl_value_new_int(1), // client_id
962 build_map({{
963 "deltas",
964 build_list({
965 build_editing_delta({
966 .old_text = "Flutter engine",
967 .selection_base = 14,
968 .selection_extent = 14,
969 }),
970 }),
971 }}),
972 });
973 break;
974 default:
975 g_assert_not_reached();
976 break;
977 }
978 EXPECT_TRUE(fl_value_equal(args, expected_args));
979 (*call_count)++;
980
981 return FL_METHOD_RESPONSE(fl_method_success_response_new(nullptr));
982 },
983 &call_count);
984
985 g_signal_emit_by_name(context, "preedit-changed", nullptr);
986 g_signal_emit_by_name(context, "commit", "Flutter engine", nullptr);
987 g_signal_emit_by_name(context, "preedit-end", nullptr);
988 EXPECT_EQ(call_count, 3);
989
990 fl_binary_messenger_shutdown(FL_BINARY_MESSENGER(messenger));
991 }
992
993 TEST(FlTextInputHandlerTest, NonComposingDelta) {
994 g_autoptr(FlMockBinaryMessenger) messenger = fl_mock_binary_messenger_new();
995 ::testing::NiceMock<flutter::testing::MockIMContext> context;
996 ::testing::NiceMock<flutter::testing::MockTextInputViewDelegate> delegate;
997
998 g_autoptr(FlTextInputHandler) handler = fl_text_input_handler_new(
999 FL_BINARY_MESSENGER(messenger), context, delegate);
1000 EXPECT_NE(handler, nullptr);
1001
1002 // set config
1003 set_client(messenger, {
1004 .client_id = 1,
1005 .enable_delta_model = true,
1006 });
1007
1008 int call_count = 0;
1009 fl_mock_binary_messenger_set_json_method_channel(
1010 messenger, "flutter/textinput",
1011 [](FlMockBinaryMessenger* messenger, GTask* task, const gchar* name,
1012 FlValue* args, gpointer user_data) {
1013 int* call_count = static_cast<int*>(user_data);
1014
1015 EXPECT_STREQ(name, "TextInputClient.updateEditingStateWithDeltas");
1016 g_autoptr(FlValue) expected_args = nullptr;
1017 switch (*call_count) {
1018 case 0:
1019 // commit F
1020 expected_args = build_list({
1021 fl_value_new_int(1), // client_id
1022 build_map({{
1023 "deltas",
1024 build_list({
1025 build_editing_delta({
1026 .old_text = "",
1027 .delta_text = "F",
1028 .delta_start = 0,
1029 .delta_end = 0,
1030 .selection_base = 1,
1031 .selection_extent = 1,
1032 .composing_base = -1,
1033 .composing_extent = -1,
1034 }),
1035 }),
1036 }}),
1037 });
1038 break;
1039 case 1:
1040 // commit l
1041 expected_args = build_list({
1042 fl_value_new_int(1), // client_id
1043 build_map({{
1044 "deltas",
1045 build_list({
1046 build_editing_delta({
1047 .old_text = "F",
1048 .delta_text = "l",
1049 .delta_start = 1,
1050 .delta_end = 1,
1051 .selection_base = 2,
1052 .selection_extent = 2,
1053 .composing_base = -1,
1054 .composing_extent = -1,
1055 }),
1056 }),
1057 }}),
1058 });
1059 break;
1060 case 2:
1061 // commit u
1062 expected_args = build_list({
1063 fl_value_new_int(1), // client_id
1064 build_map({{
1065 "deltas",
1066 build_list({
1067 build_editing_delta({
1068 .old_text = "Fl",
1069 .delta_text = "u",
1070 .delta_start = 2,
1071 .delta_end = 2,
1072 .selection_base = 3,
1073 .selection_extent = 3,
1074 .composing_base = -1,
1075 .composing_extent = -1,
1076 }),
1077 }),
1078 }}),
1079 });
1080 break;
1081 case 3:
1082 // commit t
1083 expected_args = build_list({
1084 fl_value_new_int(1), // client_id
1085 build_map({{
1086 "deltas",
1087 build_list({
1088 build_editing_delta({
1089 .old_text = "Flu",
1090 .delta_text = "t",
1091 .delta_start = 3,
1092 .delta_end = 3,
1093 .selection_base = 4,
1094 .selection_extent = 4,
1095 .composing_base = -1,
1096 .composing_extent = -1,
1097 }),
1098 }),
1099 }}),
1100 });
1101 break;
1102 case 4:
1103 // commit t again
1104 expected_args = build_list({
1105 fl_value_new_int(1), // client_id
1106 build_map({{
1107 "deltas",
1108 build_list({
1109 build_editing_delta({
1110 .old_text = "Flut",
1111 .delta_text = "t",
1112 .delta_start = 4,
1113 .delta_end = 4,
1114 .selection_base = 5,
1115 .selection_extent = 5,
1116 .composing_base = -1,
1117 .composing_extent = -1,
1118 }),
1119 }),
1120 }}),
1121 });
1122 break;
1123 case 5:
1124 // commit e
1125 expected_args = build_list({
1126 fl_value_new_int(1), // client_id
1127 build_map({{
1128 "deltas",
1129 build_list({
1130 build_editing_delta({
1131 .old_text = "Flutt",
1132 .delta_text = "e",
1133 .delta_start = 5,
1134 .delta_end = 5,
1135 .selection_base = 6,
1136 .selection_extent = 6,
1137 .composing_base = -1,
1138 .composing_extent = -1,
1139 }),
1140 }),
1141 }}),
1142 });
1143 break;
1144 case 6:
1145 // commit r
1146 expected_args = build_list({
1147 fl_value_new_int(1), // client_id
1148 build_map({{
1149 "deltas",
1150 build_list({
1151 build_editing_delta({
1152 .old_text = "Flutte",
1153 .delta_text = "r",
1154 .delta_start = 6,
1155 .delta_end = 6,
1156 .selection_base = 7,
1157 .selection_extent = 7,
1158 .composing_base = -1,
1159 .composing_extent = -1,
1160 }),
1161 }),
1162 }}),
1163 });
1164 break;
1165 default:
1166 g_assert_not_reached();
1167 break;
1168 }
1169 EXPECT_TRUE(fl_value_equal(args, expected_args));
1170 (*call_count)++;
1171
1172 return FL_METHOD_RESPONSE(fl_method_success_response_new(nullptr));
1173 },
1174 &call_count);
1175
1176 g_signal_emit_by_name(context, "commit", "F", nullptr);
1177 g_signal_emit_by_name(context, "commit", "l", nullptr);
1178 g_signal_emit_by_name(context, "commit", "u", nullptr);
1179 g_signal_emit_by_name(context, "commit", "t", nullptr);
1180 g_signal_emit_by_name(context, "commit", "t", nullptr);
1181 g_signal_emit_by_name(context, "commit", "e", nullptr);
1182 g_signal_emit_by_name(context, "commit", "r", nullptr);
1183 EXPECT_EQ(call_count, 7);
1184
1185 fl_binary_messenger_shutdown(FL_BINARY_MESSENGER(messenger));
1186 }
state
AtkStateType state
Definition: fl_accessible_node.cc:10
fl_binary_messenger_shutdown
void fl_binary_messenger_shutdown(FlBinaryMessenger *self)
Definition: fl_binary_messenger.cc:500
fl_binary_messenger_private.h
args
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
Definition: fl_event_channel.h:89
user_data
G_BEGIN_DECLS G_MODULE_EXPORT FlValue gpointer user_data
Definition: fl_event_channel.h:90
fl_key_event_new_from_gdk_event
FlKeyEvent * fl_key_event_new_from_gdk_event(GdkEvent *event)
Definition: fl_key_event.cc:53
fl_method_codec_private.h
fl_method_success_response_new
G_MODULE_EXPORT FlMethodSuccessResponse * fl_method_success_response_new(FlValue *result)
Definition: fl_method_response.cc:126
fl_method_success_response_get_result
G_MODULE_EXPORT FlValue * fl_method_success_response_get_result(FlMethodSuccessResponse *self)
Definition: fl_method_response.cc:138
height
const uint8_t uint32_t uint32_t * height
Definition: fl_pixel_buffer_texture_test.cc:39
width
const uint8_t uint32_t * width
Definition: fl_pixel_buffer_texture_test.cc:38
TRUE
return TRUE
Definition: fl_pixel_buffer_texture_test.cc:53
value
uint8_t value
Definition: fl_standard_message_codec.cc:36
fl_text_input_handler_filter_keypress
gboolean fl_text_input_handler_filter_keypress(FlTextInputHandler *self, FlKeyEvent *event)
Definition: fl_text_input_handler.cc:476
fl_text_input_handler_new
FlTextInputHandler * fl_text_input_handler_new(FlBinaryMessenger *messenger, GtkIMContext *im_context, FlTextInputViewDelegate *view_delegate)
Definition: fl_text_input_handler.cc:455
fl_text_input_handler.h
send_key_event
static void send_key_event(FlTextInputHandler *handler, gint keyval, gint state=0)
Definition: fl_text_input_handler_test.cc:144
build_list
static FlValue * build_list(std::vector< FlValue * > args)
Definition: fl_text_input_handler_test.cc:27
set_client
static void set_client(FlMockBinaryMessenger *messenger, InputConfig config)
Definition: fl_text_input_handler_test.cc:101
build_editing_delta
static FlValue * build_editing_delta(EditingDelta delta)
Definition: fl_text_input_handler_test.cc:86
build_editing_state
static FlValue * build_editing_state(EditingState state)
Definition: fl_text_input_handler_test.cc:63
build_map
static FlValue * build_map(std::map< const gchar *, FlValue * > args)
Definition: fl_text_input_handler_test.cc:19
TEST
TEST(FlTextInputHandlerTest, MessageHandler)
Definition: fl_text_input_handler_test.cc:154
build_input_config
static FlValue * build_input_config(InputConfig config)
Definition: fl_text_input_handler_test.cc:42
set_editing_state
static void set_editing_state(FlMockBinaryMessenger *messenger, EditingState state)
Definition: fl_text_input_handler_test.cc:122
fl_text_input_view_delegate_translate_coordinates
void fl_text_input_view_delegate_translate_coordinates(FlTextInputViewDelegate *self, gint view_x, gint view_y, gint *window_x, gint *window_y)
Definition: fl_text_input_view_delegate.cc:14
fl_value_new_float
G_MODULE_EXPORT FlValue * fl_value_new_float(double value)
Definition: fl_value.cc:269
fl_value_set_string_take
G_MODULE_EXPORT void fl_value_set_string_take(FlValue *self, const gchar *key, FlValue *value)
Definition: fl_value.cc:650
fl_value_new_string
G_MODULE_EXPORT FlValue * fl_value_new_string(const gchar *value)
Definition: fl_value.cc:276
fl_value_new_bool
G_MODULE_EXPORT FlValue * fl_value_new_bool(bool value)
Definition: fl_value.cc:255
fl_value_new_list
G_MODULE_EXPORT FlValue * fl_value_new_list()
Definition: fl_value.cc:349
fl_value_append_take
G_MODULE_EXPORT void fl_value_append_take(FlValue *self, FlValue *value)
Definition: fl_value.cc:600
fl_value_new_null
G_MODULE_EXPORT FlValue * fl_value_new_null()
Definition: fl_value.cc:251
fl_value_equal
G_MODULE_EXPORT bool fl_value_equal(FlValue *a, FlValue *b)
Definition: fl_value.cc:471
fl_value_new_int
G_MODULE_EXPORT FlValue * fl_value_new_int(int64_t value)
Definition: fl_value.cc:262
fl_value_new_map
G_MODULE_EXPORT FlValue * fl_value_new_map()
Definition: fl_value.cc:366
FlValue
typedefG_BEGIN_DECLS struct _FlValue FlValue
Definition: fl_value.h:42
flutter::MessageHandler
std::function< void(const T &message, const MessageReply< T > &reply)> MessageHandler
Definition: basic_message_channel.h:51
EditingDelta
Definition: fl_text_input_handler_test.cc:75
EditingDelta::selection_extent
int selection_extent
Definition: fl_text_input_handler_test.cc:81
EditingDelta::selection_base
int selection_base
Definition: fl_text_input_handler_test.cc:80
EditingDelta::delta_text
const gchar * delta_text
Definition: fl_text_input_handler_test.cc:77
EditingDelta::composing_base
int composing_base
Definition: fl_text_input_handler_test.cc:82
EditingDelta::composing_extent
int composing_extent
Definition: fl_text_input_handler_test.cc:83
EditingDelta::old_text
const gchar * old_text
Definition: fl_text_input_handler_test.cc:76
EditingDelta::delta_end
int delta_end
Definition: fl_text_input_handler_test.cc:79
EditingDelta::delta_start
int delta_start
Definition: fl_text_input_handler_test.cc:78
EditingState
Definition: fl_text_input_handler_test.cc:55
EditingState::selection_extent
int selection_extent
Definition: fl_text_input_handler_test.cc:58
EditingState::composing_base
int composing_base
Definition: fl_text_input_handler_test.cc:59
EditingState::text
const gchar * text
Definition: fl_text_input_handler_test.cc:56
EditingState::selection_base
int selection_base
Definition: fl_text_input_handler_test.cc:57
EditingState::composing_extent
int composing_extent
Definition: fl_text_input_handler_test.cc:60
InputConfig
Definition: fl_text_input_handler_test.cc:35
InputConfig::input_type
const gchar * input_type
Definition: fl_text_input_handler_test.cc:37
InputConfig::enable_delta_model
gboolean enable_delta_model
Definition: fl_text_input_handler_test.cc:39
InputConfig::input_action
const gchar * input_action
Definition: fl_text_input_handler_test.cc:38
InputConfig::client_id
int64_t client_id
Definition: fl_text_input_handler_test.cc:36