Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit 6c751e5

Browse files
committed
Add FlTextInputChannel
1 parent b6fd490 commit 6c751e5

5 files changed

Lines changed: 535 additions & 2 deletions

File tree

ci/licenses_golden/licenses_flutter

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1216,6 +1216,8 @@ FILE: ../../../flutter/shell/platform/linux/fl_standard_method_codec.cc
12161216
FILE: ../../../flutter/shell/platform/linux/fl_standard_method_codec_test.cc
12171217
FILE: ../../../flutter/shell/platform/linux/fl_string_codec.cc
12181218
FILE: ../../../flutter/shell/platform/linux/fl_string_codec_test.cc
1219+
FILE: ../../../flutter/shell/platform/linux/fl_text_input_channel.cc
1220+
FILE: ../../../flutter/shell/platform/linux/fl_text_input_channel.h
12191221
FILE: ../../../flutter/shell/platform/linux/fl_value.cc
12201222
FILE: ../../../flutter/shell/platform/linux/fl_value_test.cc
12211223
FILE: ../../../flutter/shell/platform/linux/fl_view.cc

shell/platform/linux/BUILD.gn

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ source_set("flutter_linux") {
8585
"fl_standard_message_codec.cc",
8686
"fl_standard_method_codec.cc",
8787
"fl_string_codec.cc",
88+
"fl_text_input_channel.cc",
8889
"fl_value.cc",
8990
"fl_view.cc",
9091
]
Lines changed: 275 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,275 @@
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_text_input_channel.h"
6+
#include "flutter/shell/platform/linux/public/flutter_linux/fl_json_method_codec.h"
7+
8+
struct _FlTextInputChannel {
9+
FlMethodChannel parent_instance;
10+
11+
FlTextInputChannelSetClientHandler set_client_handler;
12+
FlTextInputChannelShowHandler show_handler;
13+
FlTextInputChannelSetEditingStateHandler set_editing_state_handler;
14+
FlTextInputChannelClearClientHandler clear_client_handler;
15+
FlTextInputChannelHideHandler hide_handler;
16+
gpointer handler_data;
17+
};
18+
19+
G_DEFINE_TYPE(FlTextInputChannel,
20+
fl_text_input_channel,
21+
fl_method_channel_get_type())
22+
23+
static void method_call_cb(FlMethodChannel* channel,
24+
const gchar* method,
25+
FlValue* args,
26+
FlMethodChannelResponseHandle* response_handle,
27+
gpointer user_data) {
28+
FlTextInputChannel* self = FL_TEXT_INPUT_CHANNEL(user_data);
29+
30+
if (strcmp(method, "TextInput.setClient") == 0) {
31+
if (self->set_client_handler != nullptr)
32+
self->set_client_handler(self, 0, "", self->handler_data);
33+
fl_method_channel_respond(channel, response_handle, nullptr, nullptr);
34+
} else if (strcmp(method, "TextInput.show") == 0) {
35+
if (self->show_handler != nullptr)
36+
self->show_handler(self, self->handler_data);
37+
fl_method_channel_respond(channel, response_handle, nullptr, nullptr);
38+
} else if (strcmp(method, "TextInput.setEditableSizeAndTransform") == 0) {
39+
fl_method_channel_respond_not_implemented(channel, response_handle,
40+
nullptr);
41+
} else if (strcmp(method, "TextInput.requestAutofill") == 0) {
42+
fl_method_channel_respond_not_implemented(channel, response_handle,
43+
nullptr);
44+
} else if (strcmp(method, "TextInput.setStyle") == 0) {
45+
fl_method_channel_respond_not_implemented(channel, response_handle,
46+
nullptr);
47+
} else if (strcmp(method, "TextInput.setEditingState") == 0) {
48+
const gchar* text =
49+
fl_value_get_string(fl_value_lookup_string(args, "text"));
50+
int64_t selection_base =
51+
fl_value_get_int(fl_value_lookup_string(args, "selectionBase"));
52+
int64_t selection_extent =
53+
fl_value_get_int(fl_value_lookup_string(args, "selectionExtent"));
54+
const gchar* selection_affinity_name =
55+
fl_value_get_string(fl_value_lookup_string(args, "selectionAffinity"));
56+
FlTextAffinity selection_affinity;
57+
if (g_strcmp0(selection_affinity_name, "TextAffinity.downstream") == 0)
58+
selection_affinity = FL_TEXT_AFFINITY_DOWNSTREAM;
59+
else if (g_strcmp0(selection_affinity_name, "TextAffinity.upstream") == 0)
60+
selection_affinity = FL_TEXT_AFFINITY_UPSTREAM;
61+
gboolean selection_is_directional = fl_value_get_bool(
62+
fl_value_lookup_string(args, "selectionIsDirectional"));
63+
int64_t composing_base =
64+
fl_value_get_int(fl_value_lookup_string(args, "composingBase"));
65+
int64_t composing_extent =
66+
fl_value_get_int(fl_value_lookup_string(args, "composingExtent"));
67+
68+
if (self->set_editing_state_handler != nullptr)
69+
self->set_editing_state_handler(self, text, selection_base,
70+
selection_extent, selection_affinity,
71+
selection_is_directional, composing_base,
72+
composing_extent, self->handler_data);
73+
74+
fl_method_channel_respond(channel, response_handle, nullptr, nullptr);
75+
} else if (strcmp(method, "TextInput.clearClient") == 0) {
76+
if (self->clear_client_handler != nullptr)
77+
self->clear_client_handler(self, self->handler_data);
78+
fl_method_channel_respond(channel, response_handle, nullptr, nullptr);
79+
} else if (strcmp(method, "TextInput.hide") == 0) {
80+
if (self->hide_handler != nullptr)
81+
self->hide_handler(self, self->handler_data);
82+
fl_method_channel_respond(channel, response_handle, nullptr, nullptr);
83+
} else
84+
fl_method_channel_respond_not_implemented(channel, response_handle,
85+
nullptr);
86+
}
87+
88+
// Helper function to just check if a method returned an error
89+
static gboolean finish_method(GObject* object,
90+
GAsyncResult* result,
91+
GError** error) {
92+
g_autoptr(FlMethodResponse) response = fl_method_channel_invoke_method_finish(
93+
FL_METHOD_CHANNEL(object), result, error);
94+
if (response == nullptr)
95+
return FALSE;
96+
return fl_method_response_get_result(response, error) != nullptr;
97+
}
98+
99+
static void update_editing_state_response_cb(GObject* object,
100+
GAsyncResult* result,
101+
gpointer user_data) {
102+
g_autoptr(GError) error = nullptr;
103+
if (!finish_method(object, result, &error))
104+
g_warning("Failed to call TextInputClient.updateEditingState: %s",
105+
error->message);
106+
}
107+
108+
static void perform_action_response_cb(GObject* object,
109+
GAsyncResult* result,
110+
gpointer user_data) {
111+
g_autoptr(GError) error = nullptr;
112+
if (!finish_method(object, result, &error))
113+
g_warning("Failed to call TextInputClient.performAction: %s",
114+
error->message);
115+
}
116+
117+
static void fl_text_input_channel_class_init(FlTextInputChannelClass* klass) {}
118+
119+
static void fl_text_input_channel_init(FlTextInputChannel* self) {}
120+
121+
FlTextInputChannel* fl_text_input_channel_new(
122+
FlBinaryMessenger* messenger,
123+
FlTextInputChannelSetClientHandler set_client_handler,
124+
FlTextInputChannelShowHandler show_handler,
125+
FlTextInputChannelSetEditingStateHandler set_editing_state_handler,
126+
FlTextInputChannelClearClientHandler clear_client_handler,
127+
FlTextInputChannelHideHandler hide_handler,
128+
gpointer user_data) {
129+
g_return_val_if_fail(FL_IS_BINARY_MESSENGER(messenger), nullptr);
130+
131+
g_autoptr(FlJsonMethodCodec) codec = fl_json_method_codec_new();
132+
FlTextInputChannel* self = FL_TEXT_INPUT_CHANNEL(
133+
g_object_new(fl_text_input_channel_get_type(), "messenger", messenger,
134+
"name", "flutter/textinput", "codec", codec, nullptr));
135+
fl_method_channel_set_method_call_handler(FL_METHOD_CHANNEL(self),
136+
method_call_cb, self);
137+
138+
self->set_client_handler = set_client_handler;
139+
self->show_handler = show_handler;
140+
self->set_editing_state_handler = set_editing_state_handler;
141+
self->clear_client_handler = clear_client_handler;
142+
self->hide_handler = hide_handler;
143+
self->handler_data = user_data;
144+
145+
return self;
146+
}
147+
148+
void text_input_channel_request_existing_input_state(
149+
FlTextInputChannel* self,
150+
GCancellable* cancellable,
151+
GAsyncReadyCallback callback,
152+
gpointer user_data) {
153+
fl_method_channel_invoke_method(FL_METHOD_CHANNEL(self),
154+
"TextInputClient.requestExistingInputState",
155+
nullptr, cancellable, callback, user_data);
156+
}
157+
158+
FlValue* text_input_channel_request_existing_input_state_finish(
159+
FlTextInputChannel* self,
160+
GAsyncResult* result,
161+
GError** error) {
162+
g_autoptr(FlMethodResponse) response = fl_method_channel_invoke_method_finish(
163+
FL_METHOD_CHANNEL(self), result, error);
164+
if (response == nullptr)
165+
return nullptr;
166+
return fl_method_response_get_result(response, error);
167+
}
168+
169+
void text_input_channel_update_editing_state(FlTextInputChannel* self,
170+
int64_t client_id,
171+
const gchar* text,
172+
int64_t selection_base,
173+
int64_t selection_extent,
174+
FlTextAffinity selection_affinity,
175+
gboolean selection_is_directional,
176+
int64_t composing_base,
177+
int64_t composing_extent) {
178+
g_printerr("TextInput.updateEditingState(%" G_GINT64_FORMAT
179+
", \"%s\", %" G_GINT64_FORMAT ", %" G_GINT64_FORMAT
180+
", %d, %s, %" G_GINT64_FORMAT ", %" G_GINT64_FORMAT ")\n",
181+
client_id, text, selection_base, selection_extent,
182+
selection_affinity, selection_is_directional ? "true" : "false",
183+
composing_base, composing_extent);
184+
185+
g_autoptr(FlValue) args = fl_value_new_list();
186+
fl_value_append_take(args, fl_value_new_int(client_id));
187+
g_autoptr(FlValue) value = fl_value_new_map();
188+
fl_value_set_string_take(value, "text", fl_value_new_string(text));
189+
fl_value_set_string_take(value, "selectionBase",
190+
fl_value_new_int(selection_base));
191+
fl_value_set_string_take(value, "selectionExtent",
192+
fl_value_new_int(selection_extent));
193+
const gchar* selection_affinity_name = "";
194+
switch (selection_affinity) {
195+
case FL_TEXT_AFFINITY_DOWNSTREAM:
196+
selection_affinity_name = "TextAffinity.downstream";
197+
break;
198+
case FL_TEXT_AFFINITY_UPSTREAM:
199+
selection_affinity_name = "TextAffinity.upstream";
200+
break;
201+
}
202+
fl_value_set_string_take(value, "selectionAffinity",
203+
fl_value_new_string(selection_affinity_name));
204+
fl_value_set_string_take(value, "selectionIsDirectional",
205+
fl_value_new_bool(selection_is_directional));
206+
fl_value_set_string_take(value, "composingBase",
207+
fl_value_new_int(composing_base));
208+
fl_value_set_string_take(value, "composingExtent",
209+
fl_value_new_int(composing_extent));
210+
fl_value_append(args, value);
211+
212+
fl_method_channel_invoke_method(
213+
FL_METHOD_CHANNEL(self), "TextInputClient.updateEditingState", args,
214+
nullptr, update_editing_state_response_cb, self);
215+
}
216+
217+
void text_input_channel_perform_action(FlTextInputChannel* self,
218+
int64_t client_id,
219+
FlTextInputAction action) {
220+
g_autoptr(FlValue) args = fl_value_new_list();
221+
fl_value_append_take(args, fl_value_new_int(client_id));
222+
const gchar* action_name = "";
223+
switch (action) {
224+
case FL_TEXT_INPUT_ACTION_CONTINUE:
225+
action_name = "TextInputAction.continueAction";
226+
break;
227+
case FL_TEXT_INPUT_ACTION_DONE:
228+
action_name = "TextInputAction.done";
229+
break;
230+
case FL_TEXT_INPUT_ACTION_EMERGENCY_CALL:
231+
action_name = "TextInputAction.emergencyCall";
232+
break;
233+
case FL_TEXT_INPUT_ACTION_GO:
234+
action_name = "TextInputAction.go";
235+
break;
236+
case FL_TEXT_INPUT_ACTION_JOIN:
237+
action_name = "TextInputAction.join";
238+
break;
239+
case FL_TEXT_INPUT_ACTION_NEWLINE:
240+
action_name = "TextInputAction.newline";
241+
break;
242+
case FL_TEXT_INPUT_ACTION_NEXT:
243+
action_name = "TextInputAction.next";
244+
break;
245+
case FL_TEXT_INPUT_ACTION_PREVIOUS:
246+
action_name = "TextInputAction.previous";
247+
break;
248+
case FL_TEXT_INPUT_ACTION_ROUTE:
249+
action_name = "TextInputAction.route";
250+
break;
251+
case FL_TEXT_INPUT_ACTION_SEARCH:
252+
action_name = "TextInputAction.search";
253+
break;
254+
case FL_TEXT_INPUT_ACTION_SEND:
255+
action_name = "TextInputAction.send";
256+
break;
257+
case FL_TEXT_INPUT_ACTION_UNSPECIFIED:
258+
action_name = "TextInputAction.unspecified";
259+
break;
260+
}
261+
fl_value_append_take(args, fl_value_new_string(action_name));
262+
263+
fl_method_channel_invoke_method(FL_METHOD_CHANNEL(self),
264+
"TextInputClient.performAction", args,
265+
nullptr, perform_action_response_cb, self);
266+
}
267+
268+
void text_input_channel_on_connection_closed(FlTextInputChannel* self,
269+
int64_t client_id) {
270+
g_autoptr(FlValue) args = fl_value_new_list();
271+
fl_value_append_take(args, fl_value_new_int(client_id));
272+
fl_method_channel_invoke_method(FL_METHOD_CHANNEL(self),
273+
"TextInputClient.onConnectionClosed", args,
274+
nullptr, nullptr, nullptr);
275+
}

0 commit comments

Comments
 (0)