Win32: Fix Korean text input (#30805)

Fixes an issue with Korean IMEs wherein a text input state update may be
sent to the framework that misleads the framework into assuming that IME
composing has ended.

When inputting Korean text, characters are built up keystroke by
keystroke until the point that either:
* the user presses space/enter to terminate composing and commit the
  character, or;
* the user presses a key such that the character currently being
  composed cannot be modified further, and the IME determines that the
  user has begun composing the next character.

The following is an example sequence of events for the latter case:

1. User presses ㅂ. GCS_COMPSTR event received with ㅂ. Embedder sends
   state update to framework.
2. User presses ㅏ. GCS_COMPSTR event received with 바. Embedder sends
   state update to framework.
3. User presses ㄴ. GCS_COMPSTR event received with 반. Embedder sends
   state update to framework.
4. User presses ㅏ. At this point, the current character being composed
   (반) cannot be modified in a meaningful way, and the IME determines
   that the user is typing 바 followed by 나. GCS_RESULTSTR event
   received with 바, immediately followed by GCS_COMPSTR event with 나.

In step 4, we previously sent two events to the framework, one
immediately after the other:
* GCS_RESULTSTR triggers the text input model to commit the current
  composing region to the string under edit. This causes the composing
  region to collapse to an empty range.
* GCS_COMPSTR triggers the text input model to insert the new composing
  character and set the composing region to that character.

Conceptually, this is an atomic operation. The fourth keystroke causes
the 반 character to be broken into two (바 and ㄴ) and the latter to be
modified to 나. From the user's point of view, as well as from the IME's
point of view, the user has NOT stopped composing, and the composing
region has simply moved on to the next character.

Flutter has no concept of whether the user is composing or not other
that whether a non-empty composing region exists. As such, sending a
state update after the GCS_RESULTSTR event misleads the framework into
believing that composing has ended. This triggers a serious bug:

Text fields with input formatters applied do not perform input
formatting updates while composing is active; instead they wait until
composing has ended to apply any formatting. The previous behaviour
would thus trigger input formatters to be applied each time the user
input caused a new character to be input. This has the add-on negative
effect that once formatting has been applied, it sends an update back to
the embedder so that the native OS text input state can be updated.
However, since the GCS_RESULTSTR event is _immediately_ followed by a
GCS_COMPSTR, the state has changed in the meantime, and the embedder is
left processing an update (the intermediate state sent after the
GCS_RESULTSTR) which is now out of date (i.e. missing the new state from
the GCS_COMPSTR event).

Since GCS_RESULTR events are always immediately followed by a subsequent
GCS_COMPSTR (in the case where composing continues) or a
WM_IME_ENDCOMPOSITION (in the case where composing is finished), and
because the event handlers for both of those send updated state to the
framework, this change eliminates sending the (intermediate) state in
response to GCS_COMPSTR events.

Issue: https://github.com/flutter/flutter/issues/96209 (full fix)
Issue: https://github.com/flutter/flutter/issues/88645 (partial fix)
2 files changed
tree: 5852a3871cfcab381a2070796a41cd69cc7b3869
  1. .github/
  2. assets/
  3. benchmarking/
  4. build/
  5. ci/
  6. common/
  7. display_list/
  8. docs/
  9. examples/
  10. flow/
  11. flutter_frontend_server/
  12. fml/
  13. lib/
  14. runtime/
  15. shell/
  16. sky/
  17. testing/
  18. third_party/
  19. tools/
  20. vulkan/
  21. web_sdk/
  22. .ci.yaml
  23. .cirrus.yml
  24. .clang-format
  25. .clang-tidy
  26. .gitattributes
  27. .gitignore
  28. analysis_options.yaml
  29. AUTHORS
  30. BUILD.gn
  31. CONTRIBUTING.md
  32. DEPS
  33. Doxyfile
  34. LICENSE
  35. README.md
README.md

Flutter Engine

Build Status - Cirrus

Flutter is Google's SDK for crafting beautiful, fast user experiences for mobile, web, and desktop from a single codebase. Flutter works with existing code, is used by developers and organizations around the world, and is free and open source.

The Flutter Engine is a portable runtime for hosting Flutter applications. It implements Flutter's core libraries, including animation and graphics, file and network I/O, accessibility support, plugin architecture, and a Dart runtime and compile toolchain. Most developers will interact with Flutter via the Flutter Framework, which provides a modern, reactive framework, and a rich set of platform, layout and foundation widgets.

If you want to run/contribute to Flutter Web engine, more tooling can be found at felt. This is a tool written to make web engine development experience easy.

If you are new to Flutter, then you will find more general information on the Flutter project, including tutorials and samples, on our Web site at Flutter.dev. For specific information about Flutter's APIs, consider our API reference which can be found at the docs.flutter.dev.

Flutter is a fully open source project, and we welcome contributions. Information on how to get started can be found at our contributor guide.