diff --git a/shell/platform/windows/text_input_plugin.cc b/shell/platform/windows/text_input_plugin.cc index ebfe004292644..4d3cac7add4d2 100644 --- a/shell/platform/windows/text_input_plugin.cc +++ b/shell/platform/windows/text_input_plugin.cc @@ -16,6 +16,9 @@ static constexpr char kClearClientMethod[] = "TextInput.clearClient"; static constexpr char kSetClientMethod[] = "TextInput.setClient"; static constexpr char kShowMethod[] = "TextInput.show"; static constexpr char kHideMethod[] = "TextInput.hide"; +static constexpr char kSetMarkedTextRect[] = "TextInput.setMarkedTextRect"; +static constexpr char kSetEditableSizeAndTransform[] = + "TextInput.setEditableSizeAndTransform"; static constexpr char kMultilineInputType[] = "TextInputType.multiline"; @@ -34,6 +37,11 @@ static constexpr char kSelectionBaseKey[] = "selectionBase"; static constexpr char kSelectionExtentKey[] = "selectionExtent"; static constexpr char kSelectionIsDirectionalKey[] = "selectionIsDirectional"; static constexpr char kTextKey[] = "text"; +static constexpr char kXKey[] = "x"; +static constexpr char kYKey[] = "y"; +static constexpr char kWidthKey[] = "width"; +static constexpr char kHeightKey[] = "height"; +static constexpr char kTransformKey[] = "transform"; static constexpr char kChannelName[] = "flutter/textinput"; @@ -171,6 +179,49 @@ void TextInputPlugin::HandleMethodCall( } active_model_->SetText(text->value.GetString()); active_model_->SetSelection(TextRange(base, extent)); + } else if (method.compare(kSetMarkedTextRect) == 0) { + if (!method_call.arguments() || method_call.arguments()->IsNull()) { + result->Error(kBadArgumentError, "Method invoked without args"); + return; + } + const rapidjson::Document& args = *method_call.arguments(); + auto x = args.FindMember(kXKey); + auto y = args.FindMember(kYKey); + auto width = args.FindMember(kWidthKey); + auto height = args.FindMember(kHeightKey); + if (x == args.MemberEnd() || x->value.IsNull() || + y == args.MemberEnd() || y->value.IsNull() || + width == args.MemberEnd() || width->value.IsNull() || + height == args.MemberEnd() || height->value.IsNull()) { + result->Error(kInternalConsistencyError, "Composing rect values invalid."); + return; + } + compose_rect_.x = x->value.GetDouble(); + compose_rect_.y = y->value.GetDouble(); + compose_rect_.width = width->value.GetDouble(); + compose_rect_.height = height->value.GetDouble(); + } else if (method.compare(kSetEditableSizeAndTransform) == 0) { + if (!method_call.arguments() || method_call.arguments()->IsNull()) { + result->Error(kBadArgumentError, "Method invoked without args"); + return; + } + const rapidjson::Document& args = *method_call.arguments(); + auto transform = args.FindMember(kTransformKey); + if (transform == args.MemberEnd() || transform->value.IsNull() || + !transform->value.IsArray() || transform->value.Size() != 16) { + result->Error(kInternalConsistencyError, "EditableText transform invalid."); + return; + } + size_t i = 0; + for (auto& entry : transform->value.GetArray()) { + if (entry.IsNull()) { + result->Error(kInternalConsistencyError, + "EditableText transform contains null value."); + return; + } + editabletext_transform_[i / 4][i % 4] = entry.GetDouble(); + ++i; + } } else { result->NotImplemented(); return; diff --git a/shell/platform/windows/text_input_plugin.h b/shell/platform/windows/text_input_plugin.h index d74b2516afcf3..837549996d3ff 100644 --- a/shell/platform/windows/text_input_plugin.h +++ b/shell/platform/windows/text_input_plugin.h @@ -19,6 +19,21 @@ namespace flutter { class FlutterWindowsView; +// A rectangle with a position and extent. +// +// Used to store the current composing rectangle when using multi-step (IME) +// text input. +struct Rect { + Rect() = default; + Rect(const Rect& rect) = default; + Rect& operator=(const Rect& other) = default; + + double x; + double y; + double width; + double height; +}; + // Implements a text input plugin. // // Specifically handles window events within windows. @@ -50,6 +65,10 @@ class TextInputPlugin : public KeyboardHookHandler { const flutter::MethodCall& method_call, std::unique_ptr> result); + void SetMarkedTextRect( + const flutter::MethodCall& method_call, + std::unique_ptr> result); + // The MethodChannel used for communication with the Flutter engine. std::unique_ptr> channel_; @@ -66,6 +85,16 @@ class TextInputPlugin : public KeyboardHookHandler { // An action requested by the user on the input client. See available options: // https://api.flutter.dev/flutter/services/TextInputAction-class.html std::string input_action_; + + // The smallest rect, in local coordinates, of the text in the composing + // range, or of the caret in the case where there is no current composing + // range. This value is updated via `TextInput.setMarkedTextRect` messages + // over the text input channel. + Rect compose_rect_; + + // A 4x4 matrix that maps from `EditableText` local coordinates to the + // coordinate system of `PipelineOwner.rootNode`. + double editabletext_transform_[4][4]; }; } // namespace flutter