| Flutter Windows Embedder |

text_input_plugin.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/windows/text_input_plugin.h"
6 #include "flutter/fml/string_conversion.h"
7 #include "flutter/shell/platform/common/text_editing_delta.h"
8 #include "flutter/shell/platform/windows/text_input_plugin_delegate.h"
9
10 #include <windows.h>
11
12 #include <cstdint>
13
14 #include "flutter/shell/platform/common/json_method_codec.h"
15
16 static constexpr char kSetEditingStateMethod[] = "TextInput.setEditingState";
17 static constexpr char kClearClientMethod[] = "TextInput.clearClient";
18 static constexpr char kSetClientMethod[] = "TextInput.setClient";
19 static constexpr char kShowMethod[] = "TextInput.show";
20 static constexpr char kHideMethod[] = "TextInput.hide";
21 static constexpr char kSetMarkedTextRect[] = "TextInput.setMarkedTextRect";
22 static constexpr char kSetEditableSizeAndTransform[] =
23 "TextInput.setEditableSizeAndTransform";
24
25 static constexpr char kMultilineInputType[] = "TextInputType.multiline";
26
27 static constexpr char kUpdateEditingStateMethod[] =
28 "TextInputClient.updateEditingState";
29 static constexpr char kUpdateEditingStateWithDeltasMethod[] =
30 "TextInputClient.updateEditingStateWithDeltas";
31 static constexpr char kPerformActionMethod[] = "TextInputClient.performAction";
32
33 static constexpr char kDeltaOldTextKey[] = "oldText";
34 static constexpr char kDeltaTextKey[] = "deltaText";
35 static constexpr char kDeltaStartKey[] = "deltaStart";
36 static constexpr char kDeltaEndKey[] = "deltaEnd";
37 static constexpr char kDeltasKey[] = "deltas";
38 static constexpr char kEnableDeltaModel[] = "enableDeltaModel";
39 static constexpr char kTextInputAction[] = "inputAction";
40 static constexpr char kTextInputType[] = "inputType";
41 static constexpr char kTextInputTypeName[] = "name";
42 static constexpr char kComposingBaseKey[] = "composingBase";
43 static constexpr char kComposingExtentKey[] = "composingExtent";
44 static constexpr char kSelectionAffinityKey[] = "selectionAffinity";
45 static constexpr char kAffinityDownstream[] = "TextAffinity.downstream";
46 static constexpr char kSelectionBaseKey[] = "selectionBase";
47 static constexpr char kSelectionExtentKey[] = "selectionExtent";
48 static constexpr char kSelectionIsDirectionalKey[] = "selectionIsDirectional";
49 static constexpr char kTextKey[] = "text";
50 static constexpr char kXKey[] = "x";
51 static constexpr char kYKey[] = "y";
52 static constexpr char kWidthKey[] = "width";
53 static constexpr char kHeightKey[] = "height";
54 static constexpr char kTransformKey[] = "transform";
55
56 static constexpr char kChannelName[] = "flutter/textinput";
57
58 static constexpr char kBadArgumentError[] = "Bad Arguments";
59 static constexpr char kInternalConsistencyError[] =
60 "Internal Consistency Error";
61
62 static constexpr char kInputActionNewline[] = "TextInputAction.newline";
63
64 namespace flutter {
65
66 void TextInputPlugin::TextHook(const std::u16string& text) {
67 if (active_model_ == nullptr) {
68 return;
69 }
70 std::u16string text_before_change =
71 fml::Utf8ToUtf16(active_model_->GetText());
72 TextRange selection_before_change = active_model_->selection();
73 active_model_->AddText(text);
74
75 if (enable_delta_model) {
76 TextEditingDelta delta =
77 TextEditingDelta(text_before_change, selection_before_change, text);
78 SendStateUpdateWithDelta(*active_model_, &delta);
79 } else {
80 SendStateUpdate(*active_model_);
81 }
82 }
83
84 void TextInputPlugin::KeyboardHook(int key,
85 int scancode,
86 int action,
87 char32_t character,
88 bool extended,
89 bool was_down) {
90 if (active_model_ == nullptr) {
91 return;
92 }
93 if (action == WM_KEYDOWN || action == WM_SYSKEYDOWN) {
94 // Most editing keys (arrow keys, backspace, delete, etc.) are handled in
95 // the framework, so don't need to be handled at this layer.
96 switch (key) {
97 case VK_RETURN:
98 EnterPressed(active_model_.get());
99 break;
100 default:
101 break;
102 }
103 }
104 }
105
106 TextInputPlugin::TextInputPlugin(flutter::BinaryMessenger* messenger,
107 TextInputPluginDelegate* delegate)
108 : channel_(std::make_unique<flutter::MethodChannel<rapidjson::Document>>(
109 messenger,
110 kChannelName,
111 &flutter::JsonMethodCodec::GetInstance())),
112 delegate_(delegate),
113 active_model_(nullptr) {
114 channel_->SetMethodCallHandler(
115 [this](
116 const flutter::MethodCall<rapidjson::Document>& call,
117 std::unique_ptr<flutter::MethodResult<rapidjson::Document>> result) {
118 HandleMethodCall(call, std::move(result));
119 });
120 }
121
122 TextInputPlugin::~TextInputPlugin() = default;
123
124 void TextInputPlugin::ComposeBeginHook() {
125 if (active_model_ == nullptr) {
126 return;
127 }
128 active_model_->BeginComposing();
129 if (enable_delta_model) {
130 std::string text = active_model_->GetText();
131 TextRange selection = active_model_->selection();
132 TextEditingDelta delta = TextEditingDelta(text);
133 SendStateUpdateWithDelta(*active_model_, &delta);
134 } else {
135 SendStateUpdate(*active_model_);
136 }
137 }
138
139 void TextInputPlugin::ComposeCommitHook() {
140 if (active_model_ == nullptr) {
141 return;
142 }
143 std::string text_before_change = active_model_->GetText();
144 TextRange selection_before_change = active_model_->selection();
145 TextRange composing_before_change = active_model_->composing_range();
146 std::string composing_text_before_change = text_before_change.substr(
147 composing_before_change.start(), composing_before_change.length());
148 active_model_->CommitComposing();
149
150 // We do not trigger SendStateUpdate here.
151 //
152 // Until a WM_IME_ENDCOMPOSING event, the user is still composing from the OS
153 // point of view. Commit events are always immediately followed by another
154 // composing event or an end composing event. However, in the brief window
155 // between the commit event and the following event, the composing region is
156 // collapsed. Notifying the framework of this intermediate state will trigger
157 // any framework code designed to execute at the end of composing, such as
158 // input formatters, which may try to update the text and send a message back
159 // to the engine with changes.
160 //
161 // This is a particular problem with Korean IMEs, which build up one
162 // character at a time in their composing region until a keypress that makes
163 // no sense for the in-progress character. At that point, the result
164 // character is committed and a compose event is immedidately received with
165 // the new composing region.
166 //
167 // In the case where this event is immediately followed by a composing event,
168 // the state will be sent in ComposeChangeHook.
169 //
170 // In the case where this event is immediately followed by an end composing
171 // event, the state will be sent in ComposeEndHook.
172 }
173
174 void TextInputPlugin::ComposeEndHook() {
175 if (active_model_ == nullptr) {
176 return;
177 }
178 std::string text_before_change = active_model_->GetText();
179 TextRange selection_before_change = active_model_->selection();
180 active_model_->CommitComposing();
181 active_model_->EndComposing();
182 if (enable_delta_model) {
183 std::string text = active_model_->GetText();
184 TextEditingDelta delta = TextEditingDelta(text);
185 SendStateUpdateWithDelta(*active_model_, &delta);
186 } else {
187 SendStateUpdate(*active_model_);
188 }
189 }
190
191 void TextInputPlugin::ComposeChangeHook(const std::u16string& text,
192 int cursor_pos) {
193 if (active_model_ == nullptr) {
194 return;
195 }
196 std::string text_before_change = active_model_->GetText();
197 TextRange composing_before_change = active_model_->composing_range();
198 active_model_->AddText(text);
199 cursor_pos += active_model_->composing_range().start();
200 active_model_->UpdateComposingText(text);
201 active_model_->SetSelection(TextRange(cursor_pos, cursor_pos));
202 std::string text_after_change = active_model_->GetText();
203 if (enable_delta_model) {
204 TextEditingDelta delta = TextEditingDelta(
205 fml::Utf8ToUtf16(text_before_change), composing_before_change, text);
206 SendStateUpdateWithDelta(*active_model_, &delta);
207 } else {
208 SendStateUpdate(*active_model_);
209 }
210 }
211
212 void TextInputPlugin::HandleMethodCall(
213 const flutter::MethodCall<rapidjson::Document>& method_call,
214 std::unique_ptr<flutter::MethodResult<rapidjson::Document>> result) {
215 const std::string& method = method_call.method_name();
216
217 if (method.compare(kShowMethod) == 0 || method.compare(kHideMethod) == 0) {
218 // These methods are no-ops.
219 } else if (method.compare(kClearClientMethod) == 0) {
220 if (active_model_ != nullptr && active_model_->composing()) {
221 active_model_->CommitComposing();
222 active_model_->EndComposing();
223 SendStateUpdate(*active_model_);
224 }
225 delegate_->OnResetImeComposing();
226 active_model_ = nullptr;
227 } else if (method.compare(kSetClientMethod) == 0) {
228 if (!method_call.arguments() || method_call.arguments()->IsNull()) {
229 result->Error(kBadArgumentError, "Method invoked without args");
230 return;
231 }
232 const rapidjson::Document& args = *method_call.arguments();
233
234 const rapidjson::Value& client_id_json = args[0];
235 const rapidjson::Value& client_config = args[1];
236 if (client_id_json.IsNull()) {
237 result->Error(kBadArgumentError, "Could not set client, ID is null.");
238 return;
239 }
240 if (client_config.IsNull()) {
241 result->Error(kBadArgumentError,
242 "Could not set client, missing arguments.");
243 return;
244 }
245 client_id_ = client_id_json.GetInt();
246 auto enable_delta_model_json = client_config.FindMember(kEnableDeltaModel);
247 if (enable_delta_model_json != client_config.MemberEnd() &&
248 enable_delta_model_json->value.IsBool()) {
249 enable_delta_model = enable_delta_model_json->value.GetBool();
250 }
251 input_action_ = "";
252 auto input_action_json = client_config.FindMember(kTextInputAction);
253 if (input_action_json != client_config.MemberEnd() &&
254 input_action_json->value.IsString()) {
255 input_action_ = input_action_json->value.GetString();
256 }
257 input_type_ = "";
258 auto input_type_info_json = client_config.FindMember(kTextInputType);
259 if (input_type_info_json != client_config.MemberEnd() &&
260 input_type_info_json->value.IsObject()) {
261 auto input_type_json =
262 input_type_info_json->value.FindMember(kTextInputTypeName);
263 if (input_type_json != input_type_info_json->value.MemberEnd() &&
264 input_type_json->value.IsString()) {
265 input_type_ = input_type_json->value.GetString();
266 }
267 }
268 active_model_ = std::make_unique<TextInputModel>();
269 } else if (method.compare(kSetEditingStateMethod) == 0) {
270 if (!method_call.arguments() || method_call.arguments()->IsNull()) {
271 result->Error(kBadArgumentError, "Method invoked without args");
272 return;
273 }
274 const rapidjson::Document& args = *method_call.arguments();
275
276 if (active_model_ == nullptr) {
277 result->Error(
278 kInternalConsistencyError,
279 "Set editing state has been invoked, but no client is set.");
280 return;
281 }
282 auto text = args.FindMember(kTextKey);
283 if (text == args.MemberEnd() || text->value.IsNull()) {
284 result->Error(kBadArgumentError,
285 "Set editing state has been invoked, but without text.");
286 return;
287 }
288 auto base = args.FindMember(kSelectionBaseKey);
289 auto extent = args.FindMember(kSelectionExtentKey);
290 if (base == args.MemberEnd() || base->value.IsNull() ||
291 extent == args.MemberEnd() || extent->value.IsNull()) {
292 result->Error(kInternalConsistencyError,
293 "Selection base/extent values invalid.");
294 return;
295 }
296 // Flutter uses -1/-1 for invalid; translate that to 0/0 for the model.
297 int selection_base = base->value.GetInt();
298 int selection_extent = extent->value.GetInt();
299 if (selection_base == -1 && selection_extent == -1) {
300 selection_base = selection_extent = 0;
301 }
302 active_model_->SetText(text->value.GetString());
303 active_model_->SetSelection(TextRange(selection_base, selection_extent));
304
305 base = args.FindMember(kComposingBaseKey);
306 extent = args.FindMember(kComposingExtentKey);
307 if (base == args.MemberEnd() || base->value.IsNull() ||
308 extent == args.MemberEnd() || extent->value.IsNull()) {
309 result->Error(kInternalConsistencyError,
310 "Composing base/extent values invalid.");
311 return;
312 }
313 int composing_base = base->value.GetInt();
314 int composing_extent = base->value.GetInt();
315 if (composing_base == -1 && composing_extent == -1) {
316 active_model_->EndComposing();
317 } else {
318 int composing_start = std::min(composing_base, composing_extent);
319 int cursor_offset = selection_base - composing_start;
320 active_model_->SetComposingRange(
321 TextRange(composing_base, composing_extent), cursor_offset);
322 }
323 } else if (method.compare(kSetMarkedTextRect) == 0) {
324 if (!method_call.arguments() || method_call.arguments()->IsNull()) {
325 result->Error(kBadArgumentError, "Method invoked without args");
326 return;
327 }
328 const rapidjson::Document& args = *method_call.arguments();
329 auto x = args.FindMember(kXKey);
330 auto y = args.FindMember(kYKey);
331 auto width = args.FindMember(kWidthKey);
332 auto height = args.FindMember(kHeightKey);
333 if (x == args.MemberEnd() || x->value.IsNull() || //
334 y == args.MemberEnd() || y->value.IsNull() || //
335 width == args.MemberEnd() || width->value.IsNull() || //
336 height == args.MemberEnd() || height->value.IsNull()) {
337 result->Error(kInternalConsistencyError,
338 "Composing rect values invalid.");
339 return;
340 }
341 composing_rect_ = {{x->value.GetDouble(), y->value.GetDouble()},
342 {width->value.GetDouble(), height->value.GetDouble()}};
343
344 Rect transformed_rect = GetCursorRect();
345 delegate_->OnCursorRectUpdated(transformed_rect);
346 } else if (method.compare(kSetEditableSizeAndTransform) == 0) {
347 if (!method_call.arguments() || method_call.arguments()->IsNull()) {
348 result->Error(kBadArgumentError, "Method invoked without args");
349 return;
350 }
351 const rapidjson::Document& args = *method_call.arguments();
352 auto transform = args.FindMember(kTransformKey);
353 if (transform == args.MemberEnd() || transform->value.IsNull() ||
354 !transform->value.IsArray() || transform->value.Size() != 16) {
355 result->Error(kInternalConsistencyError,
356 "EditableText transform invalid.");
357 return;
358 }
359 size_t i = 0;
360 for (auto& entry : transform->value.GetArray()) {
361 if (entry.IsNull()) {
362 result->Error(kInternalConsistencyError,
363 "EditableText transform contains null value.");
364 return;
365 }
366 editabletext_transform_[i / 4][i % 4] = entry.GetDouble();
367 ++i;
368 }
369 Rect transformed_rect = GetCursorRect();
370 delegate_->OnCursorRectUpdated(transformed_rect);
371 } else {
372 result->NotImplemented();
373 return;
374 }
375 // All error conditions return early, so if nothing has gone wrong indicate
376 // success.
377 result->Success();
378 }
379
380 Rect TextInputPlugin::GetCursorRect() const {
381 Point transformed_point = {
382 composing_rect_.left() * editabletext_transform_[0][0] +
383 composing_rect_.top() * editabletext_transform_[1][0] +
384 editabletext_transform_[3][0],
385 composing_rect_.left() * editabletext_transform_[0][1] +
386 composing_rect_.top() * editabletext_transform_[1][1] +
387 editabletext_transform_[3][1]};
388 return {transformed_point, composing_rect_.size()};
389 }
390
391 void TextInputPlugin::SendStateUpdate(const TextInputModel& model) {
392 auto args = std::make_unique<rapidjson::Document>(rapidjson::kArrayType);
393 auto& allocator = args->GetAllocator();
394 args->PushBack(client_id_, allocator);
395
396 TextRange selection = model.selection();
397 rapidjson::Value editing_state(rapidjson::kObjectType);
398 editing_state.AddMember(kSelectionAffinityKey, kAffinityDownstream,
399 allocator);
400 editing_state.AddMember(kSelectionBaseKey, selection.base(), allocator);
401 editing_state.AddMember(kSelectionExtentKey, selection.extent(), allocator);
402 editing_state.AddMember(kSelectionIsDirectionalKey, false, allocator);
403
404 int composing_base = model.composing() ? model.composing_range().base() : -1;
405 int composing_extent =
406 model.composing() ? model.composing_range().extent() : -1;
407 editing_state.AddMember(kComposingBaseKey, composing_base, allocator);
408 editing_state.AddMember(kComposingExtentKey, composing_extent, allocator);
409 editing_state.AddMember(
410 kTextKey, rapidjson::Value(model.GetText(), allocator).Move(), allocator);
411 args->PushBack(editing_state, allocator);
412
413 channel_->InvokeMethod(kUpdateEditingStateMethod, std::move(args));
414 }
415
416 void TextInputPlugin::SendStateUpdateWithDelta(const TextInputModel& model,
417 const TextEditingDelta* delta) {
418 auto args = std::make_unique<rapidjson::Document>(rapidjson::kArrayType);
419 auto& allocator = args->GetAllocator();
420 args->PushBack(client_id_, allocator);
421
422 rapidjson::Value object(rapidjson::kObjectType);
423 rapidjson::Value deltas(rapidjson::kArrayType);
424 rapidjson::Value deltaJson(rapidjson::kObjectType);
425
426 deltaJson.AddMember(kDeltaOldTextKey, delta->old_text(), allocator);
427 deltaJson.AddMember(kDeltaTextKey, delta->delta_text(), allocator);
428 deltaJson.AddMember(kDeltaStartKey, delta->delta_start(), allocator);
429 deltaJson.AddMember(kDeltaEndKey, delta->delta_end(), allocator);
430
431 TextRange selection = model.selection();
432 deltaJson.AddMember(kSelectionAffinityKey, kAffinityDownstream, allocator);
433 deltaJson.AddMember(kSelectionBaseKey, selection.base(), allocator);
434 deltaJson.AddMember(kSelectionExtentKey, selection.extent(), allocator);
435 deltaJson.AddMember(kSelectionIsDirectionalKey, false, allocator);
436
437 int composing_base = model.composing() ? model.composing_range().base() : -1;
438 int composing_extent =
439 model.composing() ? model.composing_range().extent() : -1;
440 deltaJson.AddMember(kComposingBaseKey, composing_base, allocator);
441 deltaJson.AddMember(kComposingExtentKey, composing_extent, allocator);
442
443 deltas.PushBack(deltaJson, allocator);
444 object.AddMember(kDeltasKey, deltas, allocator);
445 args->PushBack(object, allocator);
446
447 channel_->InvokeMethod(kUpdateEditingStateWithDeltasMethod, std::move(args));
448 }
449
450 void TextInputPlugin::EnterPressed(TextInputModel* model) {
451 if (input_type_ == kMultilineInputType &&
452 input_action_ == kInputActionNewline) {
453 std::u16string text_before_change = fml::Utf8ToUtf16(model->GetText());
454 TextRange selection_before_change = model->selection();
455 model->AddText(u"\n");
456 if (enable_delta_model) {
457 TextEditingDelta delta(text_before_change, selection_before_change,
458 u"\n");
459 SendStateUpdateWithDelta(*model, &delta);
460 } else {
461 SendStateUpdate(*model);
462 }
463 }
464 auto args = std::make_unique<rapidjson::Document>(rapidjson::kArrayType);
465 auto& allocator = args->GetAllocator();
466 args->PushBack(client_id_, allocator);
467 args->PushBack(rapidjson::Value(input_action_, allocator).Move(), allocator);
468
469 channel_->InvokeMethod(kPerformActionMethod, std::move(args));
470 }
471
472 } // namespace flutter
kTextInputTypeName
static constexpr char kTextInputTypeName[]
Definition: text_input_plugin.cc:41
flutter::TextInputPlugin::ComposeBeginHook
virtual void ComposeBeginHook()
Definition: text_input_plugin.cc:124
flutter::TextInputPlugin::ComposeChangeHook
virtual void ComposeChangeHook(const std::u16string &text, int cursor_pos)
Definition: text_input_plugin.cc:191
flutter::TextInputPlugin::TextInputPlugin
TextInputPlugin(flutter::BinaryMessenger *messenger, TextInputPluginDelegate *delegate)
Definition: text_input_plugin.cc:106
kTextInputType
static constexpr char kTextInputType[]
Definition: text_input_plugin.cc:40
kXKey
static constexpr char kXKey[]
Definition: text_input_plugin.cc:50
kDeltaOldTextKey
static constexpr char kDeltaOldTextKey[]
Definition: text_input_plugin.cc:33
kAffinityDownstream
static constexpr char kAffinityDownstream[]
Definition: text_input_plugin.cc:45
scancode
int scancode
Definition: keyboard_key_handler_unittests.cc:115
was_down
bool was_down
Definition: keyboard_key_handler_unittests.cc:119
text_input_plugin.h
flutter::JsonMethodCodec
Definition: json_method_codec.h:16
extended
bool extended
Definition: keyboard_key_handler_unittests.cc:118
flutter::MethodChannel
Definition: method_channel.h:33
kBadArgumentError
static constexpr char kBadArgumentError[]
Definition: text_input_plugin.cc:58
kDeltasKey
static constexpr char kDeltasKey[]
Definition: text_input_plugin.cc:37
character
char32_t character
Definition: keyboard_key_handler_unittests.cc:117
kUpdateEditingStateMethod
static constexpr char kUpdateEditingStateMethod[]
Definition: text_input_plugin.cc:27
kTransformKey
static constexpr char kTransformKey[]
Definition: text_input_plugin.cc:54
flutter::TextInputPlugin::ComposeEndHook
virtual void ComposeEndHook()
Definition: text_input_plugin.cc:174
json_method_codec.h
kComposingExtentKey
static constexpr char kComposingExtentKey[]
Definition: text_input_plugin.cc:43
flutter::TextInputPlugin::~TextInputPlugin
virtual ~TextInputPlugin()
flutter::TextInputPluginDelegate::OnResetImeComposing
virtual void OnResetImeComposing()=0
kHeightKey
static constexpr char kHeightKey[]
Definition: text_input_plugin.cc:53
flutter::TextInputPlugin::ComposeCommitHook
virtual void ComposeCommitHook()
Definition: text_input_plugin.cc:139
kTextKey
static constexpr char kTextKey[]
Definition: text_input_plugin.cc:49
flutter::TextInputPluginDelegate
Definition: text_input_plugin_delegate.h:13
kChannelName
static constexpr char kChannelName[]
Definition: text_input_plugin.cc:56
kTextInputAction
static constexpr char kTextInputAction[]
Definition: text_input_plugin.cc:39
kEnableDeltaModel
static constexpr char kEnableDeltaModel[]
Definition: text_input_plugin.cc:38
kSelectionIsDirectionalKey
static constexpr char kSelectionIsDirectionalKey[]
Definition: text_input_plugin.cc:48
kSetEditableSizeAndTransform
static constexpr char kSetEditableSizeAndTransform[]
Definition: text_input_plugin.cc:22
kSelectionExtentKey
static constexpr char kSelectionExtentKey[]
Definition: text_input_plugin.cc:47
flutter::Rect::left
double left() const
Definition: geometry.h:63
flutter::BinaryMessenger
Definition: binary_messenger.h:28
flutter::TextRange
Definition: text_range.h:19
text
std::u16string text
Definition: keyboard_unittests.cc:332
flutter::TextInputPlugin::TextHook
virtual void TextHook(const std::u16string &text)
Definition: text_input_plugin.cc:66
kSetEditingStateMethod
static constexpr char kSetEditingStateMethod[]
Definition: text_input_plugin.cc:16
kDeltaStartKey
static constexpr char kDeltaStartKey[]
Definition: text_input_plugin.cc:35
kDeltaEndKey
static constexpr char kDeltaEndKey[]
Definition: text_input_plugin.cc:36
flutter::MethodCall
Definition: method_call.h:18
kInternalConsistencyError
static constexpr char kInternalConsistencyError[]
Definition: text_input_plugin.cc:59
kSelectionBaseKey
static constexpr char kSelectionBaseKey[]
Definition: text_input_plugin.cc:46
flutter
Definition: accessibility_bridge_windows.cc:11
kYKey
static constexpr char kYKey[]
Definition: text_input_plugin.cc:51
kWidthKey
static constexpr char kWidthKey[]
Definition: text_input_plugin.cc:52
flutter::Rect::top
double top() const
Definition: geometry.h:64
kSetClientMethod
static constexpr char kSetClientMethod[]
Definition: text_input_plugin.cc:18
kClearClientMethod
static constexpr char kClearClientMethod[]
Definition: text_input_plugin.cc:17
flutter::Rect::size
Size size() const
Definition: geometry.h:70
flutter::MethodCall::method_name
const std::string & method_name() const
Definition: method_call.h:31
flutter::MethodResult
Definition: method_result.h:17
kSelectionAffinityKey
static constexpr char kSelectionAffinityKey[]
Definition: text_input_plugin.cc:44
flutter::TextInputPlugin::KeyboardHook
virtual void KeyboardHook(int key, int scancode, int action, char32_t character, bool extended, bool was_down)
Definition: text_input_plugin.cc:84
kPerformActionMethod
static constexpr char kPerformActionMethod[]
Definition: text_input_plugin.cc:31
flutter::TextRange::start
size_t start() const
Definition: text_range.h:42
kSetMarkedTextRect
static constexpr char kSetMarkedTextRect[]
Definition: text_input_plugin.cc:21
action
int action
Definition: keyboard_key_handler_unittests.cc:116
text_editing_delta.h
kComposingBaseKey
static constexpr char kComposingBaseKey[]
Definition: text_input_plugin.cc:42
flutter::TextRange::length
size_t length() const
Definition: text_range.h:74
text_input_plugin_delegate.h
flutter::TextInputPluginDelegate::OnCursorRectUpdated
virtual void OnCursorRectUpdated(const Rect &rect)=0
key
int key
Definition: keyboard_key_handler_unittests.cc:114
flutter::TextEditingDelta
A change in the state of an input field.
Definition: text_editing_delta.h:16
flutter::MethodCall::arguments
const T * arguments() const
Definition: method_call.h:34
kShowMethod
static constexpr char kShowMethod[]
Definition: text_input_plugin.cc:19
kUpdateEditingStateWithDeltasMethod
static constexpr char kUpdateEditingStateWithDeltasMethod[]
Definition: text_input_plugin.cc:29
kHideMethod
static constexpr char kHideMethod[]
Definition: text_input_plugin.cc:20
kMultilineInputType
static constexpr char kMultilineInputType[]
Definition: text_input_plugin.cc:25
kDeltaTextKey
static constexpr char kDeltaTextKey[]
Definition: text_input_plugin.cc:34
kInputActionNewline
static constexpr char kInputActionNewline[]
Definition: text_input_plugin.cc:62