5#include "flutter/shell/platform/windows/text_input_plugin.h"
11#include "flutter/fml/string_conversion.h"
12#include "flutter/shell/platform/common/json_method_codec.h"
13#include "flutter/shell/platform/common/text_editing_delta.h"
14#include "flutter/shell/platform/windows/flutter_windows_engine.h"
15#include "flutter/shell/platform/windows/flutter_windows_view.h"
24 "TextInput.setEditableSizeAndTransform";
29 "TextInputClient.updateEditingState";
31 "TextInputClient.updateEditingStateWithDeltas";
51static constexpr char kXKey[] =
"x";
52static constexpr char kYKey[] =
"y";
61 "Internal Consistency Error";
68 if (active_model_ ==
nullptr) {
71 std::u16string text_before_change =
73 TextRange selection_before_change = active_model_->selection();
74 active_model_->AddText(
text);
76 if (enable_delta_model) {
79 SendStateUpdateWithDelta(*active_model_, &
delta);
81 SendStateUpdate(*active_model_);
91 if (active_model_ ==
nullptr) {
99 EnterPressed(active_model_.get());
114 active_model_(nullptr) {
115 channel_->SetMethodCallHandler(
126 if (active_model_ ==
nullptr) {
129 active_model_->BeginComposing();
130 if (enable_delta_model) {
131 std::string
text = active_model_->GetText();
132 TextRange selection = active_model_->selection();
134 SendStateUpdateWithDelta(*active_model_, &
delta);
136 SendStateUpdate(*active_model_);
141 if (active_model_ ==
nullptr) {
144 std::string text_before_change = active_model_->GetText();
145 TextRange selection_before_change = active_model_->selection();
146 TextRange composing_before_change = active_model_->composing_range();
147 std::string composing_text_before_change = text_before_change.substr(
148 composing_before_change.
start(), composing_before_change.
length());
149 active_model_->CommitComposing();
176 if (active_model_ ==
nullptr) {
179 std::string text_before_change = active_model_->GetText();
180 TextRange selection_before_change = active_model_->selection();
181 active_model_->CommitComposing();
182 active_model_->EndComposing();
183 if (enable_delta_model) {
184 std::string
text = active_model_->GetText();
186 SendStateUpdateWithDelta(*active_model_, &
delta);
188 SendStateUpdate(*active_model_);
194 if (active_model_ ==
nullptr) {
197 std::string text_before_change = active_model_->GetText();
198 TextRange composing_before_change = active_model_->composing_range();
199 active_model_->AddText(
text);
200 active_model_->UpdateComposingText(
text,
TextRange(cursor_pos, cursor_pos));
201 std::string text_after_change = active_model_->GetText();
202 if (enable_delta_model) {
205 SendStateUpdateWithDelta(*active_model_, &
delta);
207 SendStateUpdate(*active_model_);
211void TextInputPlugin::HandleMethodCall(
214 const std::string& method =
method_call.method_name();
222 if (view ==
nullptr) {
224 "Text input is not available in Windows headless mode");
227 if (active_model_ !=
nullptr && active_model_->composing()) {
228 active_model_->CommitComposing();
229 active_model_->EndComposing();
230 SendStateUpdate(*active_model_);
232 view->OnResetImeComposing();
233 active_model_ =
nullptr;
241 const rapidjson::Value& client_id_json =
args[0];
242 const rapidjson::Value& client_config =
args[1];
243 if (client_id_json.IsNull()) {
247 if (client_config.IsNull()) {
249 "Could not set client, missing arguments.");
252 client_id_ = client_id_json.GetInt();
254 if (enable_delta_model_json != client_config.MemberEnd() &&
255 enable_delta_model_json->value.IsBool()) {
256 enable_delta_model = enable_delta_model_json->value.GetBool();
260 if (input_action_json != client_config.MemberEnd() &&
261 input_action_json->value.IsString()) {
262 input_action_ = input_action_json->value.GetString();
265 auto input_type_info_json = client_config.FindMember(
kTextInputType);
266 if (input_type_info_json != client_config.MemberEnd() &&
267 input_type_info_json->value.IsObject()) {
268 auto input_type_json =
270 if (input_type_json != input_type_info_json->value.MemberEnd() &&
271 input_type_json->value.IsString()) {
272 input_type_ = input_type_json->value.GetString();
275 active_model_ = std::make_unique<TextInputModel>();
283 if (active_model_ ==
nullptr) {
286 "Set editing state has been invoked, but no client is set.");
292 "Set editing state has been invoked, but without text.");
298 extent ==
args.MemberEnd() || extent->value.IsNull()) {
300 "Selection base/extent values invalid.");
304 int selection_base =
base->value.GetInt();
305 int selection_extent = extent->value.GetInt();
306 if (selection_base == -1 && selection_extent == -1) {
307 selection_base = selection_extent = 0;
309 active_model_->SetText(
text->value.GetString());
310 active_model_->SetSelection(
TextRange(selection_base, selection_extent));
315 extent ==
args.MemberEnd() || extent->value.IsNull()) {
317 "Composing base/extent values invalid.");
320 int composing_base =
base->value.GetInt();
321 int composing_extent =
base->value.GetInt();
322 if (composing_base == -1 && composing_extent == -1) {
323 active_model_->EndComposing();
325 int composing_start =
std::min(composing_base, composing_extent);
326 int cursor_offset = selection_base - composing_start;
327 active_model_->SetComposingRange(
328 TextRange(composing_base, composing_extent), cursor_offset);
334 if (view ==
nullptr) {
336 "Text input is not available in Windows headless mode");
348 if (
x ==
args.MemberEnd() ||
x->value.IsNull() ||
349 y ==
args.MemberEnd() ||
y->value.IsNull() ||
353 "Composing rect values invalid.");
356 composing_rect_ = {{
x->value.GetDouble(),
y->value.GetDouble()},
357 {
width->value.GetDouble(),
height->value.GetDouble()}};
359 Rect transformed_rect = GetCursorRect();
360 view->OnCursorRectUpdated(transformed_rect);
365 if (view ==
nullptr) {
367 "Text input is not available in Windows headless mode");
379 "EditableText transform invalid.");
383 for (
auto& entry :
transform->value.GetArray()) {
384 if (entry.IsNull()) {
386 "EditableText transform contains null value.");
389 editabletext_transform_[
i / 4][
i % 4] = entry.GetDouble();
392 Rect transformed_rect = GetCursorRect();
393 view->OnCursorRectUpdated(transformed_rect);
403Rect TextInputPlugin::GetCursorRect()
const {
404 Point transformed_point = {
405 composing_rect_.
left() * editabletext_transform_[0][0] +
406 composing_rect_.
top() * editabletext_transform_[1][0] +
407 editabletext_transform_[3][0],
408 composing_rect_.
left() * editabletext_transform_[0][1] +
409 composing_rect_.
top() * editabletext_transform_[1][1] +
410 editabletext_transform_[3][1]};
411 return {transformed_point, composing_rect_.
size()};
414void TextInputPlugin::SendStateUpdate(
const TextInputModel& model) {
415 auto args = std::make_unique<rapidjson::Document>(rapidjson::kArrayType);
416 auto& allocator =
args->GetAllocator();
417 args->PushBack(client_id_, allocator);
420 rapidjson::Value editing_state(rapidjson::kObjectType);
427 int composing_base = model.composing() ? model.composing_range().base() : -1;
428 int composing_extent =
429 model.composing() ? model.composing_range().extent() : -1;
432 editing_state.AddMember(
433 kTextKey, rapidjson::Value(model.GetText(), allocator).Move(), allocator);
434 args->PushBack(editing_state, allocator);
439void TextInputPlugin::SendStateUpdateWithDelta(
const TextInputModel& model,
440 const TextEditingDelta*
delta) {
441 auto args = std::make_unique<rapidjson::Document>(rapidjson::kArrayType);
442 auto& allocator =
args->GetAllocator();
443 args->PushBack(client_id_, allocator);
445 rapidjson::Value object(rapidjson::kObjectType);
446 rapidjson::Value deltas(rapidjson::kArrayType);
447 rapidjson::Value deltaJson(rapidjson::kObjectType);
460 int composing_base = model.composing() ? model.composing_range().base() : -1;
461 int composing_extent =
462 model.composing() ? model.composing_range().extent() : -1;
466 deltas.PushBack(deltaJson, allocator);
467 object.AddMember(
kDeltasKey, deltas, allocator);
468 args->PushBack(
object, allocator);
473void TextInputPlugin::EnterPressed(TextInputModel* model) {
477 TextRange selection_before_change = model->selection();
478 model->AddText(u
"\n");
479 if (enable_delta_model) {
480 TextEditingDelta
delta(text_before_change, selection_before_change,
482 SendStateUpdateWithDelta(*model, &
delta);
484 SendStateUpdate(*model);
487 auto args = std::make_unique<rapidjson::Document>(rapidjson::kArrayType);
488 auto& allocator =
args->GetAllocator();
489 args->PushBack(client_id_, allocator);
490 args->PushBack(rapidjson::Value(input_action_, allocator).Move(), allocator);
FlutterWindowsView * view(FlutterViewId view_id) const
void KeyboardHook(GLFWwindow *window, int key, int scancode, int action, int mods) override
virtual void ComposeCommitHook()
TextInputPlugin(flutter::BinaryMessenger *messenger)
virtual void ComposeChangeHook(const std::u16string &text, int cursor_pos)
virtual void TextHook(const std::u16string &text)
virtual void ComposeEndHook()
virtual ~TextInputPlugin()
virtual void ComposeBeginHook()
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
G_BEGIN_DECLS G_MODULE_EXPORT FlMethodCall * method_call
static float min(float r, float g, float b)
constexpr FlutterViewId kImplicitViewId
std::u16string Utf8ToUtf16(const std::string_view string)
SkRange< size_t > TextRange
static SkColor4f transform(SkColor4f c, SkColorSpace *src, SkColorSpace *dst)
A change in the state of an input field.
static constexpr char kClearClientMethod[]
static constexpr char kSetEditableSizeAndTransform[]
static constexpr char kSetMarkedTextRect[]
static constexpr char kEnableDeltaModel[]
static constexpr char kSelectionIsDirectionalKey[]
static constexpr char kDeltaEndKey[]
static constexpr char kHideMethod[]
static constexpr char kMultilineInputType[]
static constexpr char kDeltaOldTextKey[]
static constexpr char kWidthKey[]
static constexpr char kSetEditingStateMethod[]
static constexpr char kSelectionExtentKey[]
static constexpr char kHeightKey[]
static constexpr char kDeltaTextKey[]
static constexpr char kDeltasKey[]
static constexpr char kTextInputType[]
static constexpr char kChannelName[]
static constexpr char kXKey[]
static constexpr char kInputActionNewline[]
static constexpr char kInternalConsistencyError[]
static constexpr char kBadArgumentError[]
static constexpr char kSetClientMethod[]
static constexpr char kUpdateEditingStateMethod[]
static constexpr char kPerformActionMethod[]
static constexpr char kYKey[]
static constexpr char kShowMethod[]
static constexpr char kComposingExtentKey[]
static constexpr char kTextInputAction[]
static constexpr char kTransformKey[]
static constexpr char kComposingBaseKey[]
static constexpr char kTextInputTypeName[]
static constexpr char kUpdateEditingStateWithDeltasMethod[]
static constexpr char kAffinityDownstream[]
static constexpr char kSelectionAffinityKey[]
static constexpr char kTextKey[]
static constexpr char kSelectionBaseKey[]
static constexpr char kDeltaStartKey[]