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