mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
The C++ text input model used by Windows and Linux currently uses UTF-32. The intention was to facilitate handling of arrow keys, backspace/delete, etc., however since part of what is synchronized with the engine is cursor+selection offsets, and those offsets are defined in terms of UTF-16 code units, this causes very bad interactions with the framework-side model. This converts to using UTF-16, rather than UTF-32, so that the offsets align with the framework. It also adds surrogate pair handling to the operations that adjust indexes, to avoid breaking surrogate pairs. (Arbitrary grapheme cluster handling is out of scope for this PR; while definitely desirable in the long term, surrogate pair handling is much more critical since improper handling yields invalid UTF-16, which breaks the text field). This partially fixes https://github.com/flutter/flutter/issues/55014. A framework-side fix is also necessary (since currently both the engine and the framework attempt to handle arrow keys, which is another out-of-scope-for-this-PR issue), but even without the framework fix this dramatically improves the cursor behavior on Windows when there are surrogate pairs somewhere in the string since at least the two sides agree on what indexes mean. Includes minor plumbing changes to the text input plumbing on Windows so that we're not pointlessly converting from UTF-16 to UTF-32 and then back to UTF-16.
109 lines
3.4 KiB
C++
109 lines
3.4 KiB
C++
// Copyright 2013 The Flutter Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
#ifndef FLUTTER_SHELL_PLATFORM_CPP_TEXT_INPUT_MODEL_H_
|
|
#define FLUTTER_SHELL_PLATFORM_CPP_TEXT_INPUT_MODEL_H_
|
|
|
|
#include <memory>
|
|
#include <string>
|
|
|
|
#include "rapidjson/document.h"
|
|
|
|
namespace flutter {
|
|
// Handles underlying text input state, using a simple ASCII model.
|
|
//
|
|
// Ignores special states like "insert mode" for now.
|
|
class TextInputModel {
|
|
public:
|
|
TextInputModel(int client_id, const rapidjson::Value& config);
|
|
virtual ~TextInputModel();
|
|
|
|
// Attempts to set the text state.
|
|
//
|
|
// Returns false if the state is not valid (base or extent are out of
|
|
// bounds, or base is less than extent).
|
|
bool SetEditingState(size_t selection_base,
|
|
size_t selection_extent,
|
|
const std::string& text);
|
|
|
|
// Adds a Unicode code point.
|
|
//
|
|
// Either appends after the cursor (when selection base and extent are the
|
|
// same), or deletes the selected text, replacing it with the given
|
|
// code point.
|
|
void AddCodePoint(char32_t c);
|
|
|
|
// Adds a UTF-16 text.
|
|
//
|
|
// Either appends after the cursor (when selection base and extent are the
|
|
// same), or deletes the selected text, replacing it with the given text.
|
|
void AddText(const std::u16string& text);
|
|
|
|
// Deletes either the selection, or one character ahead of the cursor.
|
|
//
|
|
// Deleting one character ahead of the cursor occurs when the selection base
|
|
// and extent are the same.
|
|
//
|
|
// Returns true if any deletion actually occurred.
|
|
bool Delete();
|
|
|
|
// Deletes either the selection, or one character behind the cursor.
|
|
//
|
|
// Deleting one character behind the cursor occurs when the selection base
|
|
// and extent are the same.
|
|
//
|
|
// Returns true if any deletion actually occurred.
|
|
bool Backspace();
|
|
|
|
// Attempts to move the cursor backward.
|
|
//
|
|
// Returns true if the cursor could be moved. Changes base and extent to be
|
|
// equal to either the extent (if extent is at the end of the string), or
|
|
// for extent to be equal to
|
|
bool MoveCursorBack();
|
|
|
|
// Attempts to move the cursor forward.
|
|
//
|
|
// Returns true if the cursor could be moved.
|
|
bool MoveCursorForward();
|
|
|
|
// Attempts to move the cursor to the beginning.
|
|
//
|
|
// Returns true if the cursor could be moved.
|
|
void MoveCursorToBeginning();
|
|
|
|
// Attempts to move the cursor to the back.
|
|
//
|
|
// Returns true if the cursor could be moved.
|
|
void MoveCursorToEnd();
|
|
|
|
// Returns the state in the form of a platform message.
|
|
std::unique_ptr<rapidjson::Document> GetState() const;
|
|
|
|
// Id of the text input client.
|
|
int client_id() const { return client_id_; }
|
|
|
|
// Keyboard type of the client. See available options:
|
|
// https://docs.flutter.io/flutter/services/TextInputType-class.html
|
|
std::string input_type() const { return input_type_; }
|
|
|
|
// An action requested by the user on the input client. See available options:
|
|
// https://docs.flutter.io/flutter/services/TextInputAction-class.html
|
|
std::string input_action() const { return input_action_; }
|
|
|
|
private:
|
|
void DeleteSelected();
|
|
|
|
std::u16string text_;
|
|
int client_id_;
|
|
std::string input_type_;
|
|
std::string input_action_;
|
|
std::u16string::iterator selection_base_;
|
|
std::u16string::iterator selection_extent_;
|
|
};
|
|
|
|
} // namespace flutter
|
|
|
|
#endif // FLUTTER_SHELL_PLATFORM_CPP_TEXT_INPUT_MODEL_H_
|