1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353
|
// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef COMPONENTS_EXO_TEXT_INPUT_H_
#define COMPONENTS_EXO_TEXT_INPUT_H_
#include <optional>
#include <string>
#include <string_view>
#include "base/i18n/rtl.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/scoped_observation.h"
#include "components/exo/seat_observer.h"
#include "ui/base/ime/ash/input_method_manager.h"
#include "ui/base/ime/autocorrect_info.h"
#include "ui/base/ime/composition_text.h"
#include "ui/base/ime/surrounding_text_tracker.h"
#include "ui/base/ime/text_input_client.h"
#include "ui/base/ime/text_input_flags.h"
#include "ui/base/ime/text_input_mode.h"
#include "ui/base/ime/text_input_type.h"
#include "ui/base/ime/virtual_keyboard_controller.h"
#include "ui/base/ime/virtual_keyboard_controller_observer.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/range/range.h"
namespace ui {
class InputMethod;
} // namespace ui
namespace exo {
class Surface;
class Seat;
// This class bridges the ChromeOS input method and a text-input context.
// It can be inactive, active, or in a pending state where Activate() was
// called but the associated window is not focused.
class TextInput : public ui::TextInputClient,
public ui::VirtualKeyboardControllerObserver,
public ash::input_method::InputMethodManager::Observer,
public SeatObserver {
public:
class Delegate {
public:
virtual ~Delegate() = default;
// Called when the text input session is activated.
virtual void Activated() = 0;
// Called when the text input session is deactivated. TextInput does not
// refer to the delegate anymore.
virtual void Deactivated() = 0;
// Called when the virtual keyboard visibility state has changed.
virtual void OnVirtualKeyboardVisibilityChanged(bool is_visible) = 0;
// Called when the virtual keyboard's occluded bounds has changed.
// The bounds are in screen DIP.
virtual void OnVirtualKeyboardOccludedBoundsChanged(
const gfx::Rect& screen_bounds) = 0;
// Returns true if the server can expect a finalize_virtual_keyboard_changes
// request from the client.
virtual bool SupportsFinalizeVirtualKeyboardChanges() = 0;
// Set the 'composition text' of the current text input.
virtual void SetCompositionText(const ui::CompositionText& composition) = 0;
// Commit |text| to the current text input session.
virtual void Commit(std::u16string_view text) = 0;
// Set the cursor position.
// |surrounding_text| is the current surrounding text.
// The |selection| range is in UTF-16 offsets of the current surrounding
// text. |selection| must be a valid range, i.e.
// selection.IsValid() && selection.GetMax() <= surrounding_text.length().
virtual void SetCursor(std::u16string_view surrounding_text,
const gfx::Range& selection) = 0;
// Delete the surrounding text of the current text input.
// |surrounding_text| is the current surrounding text.
// The delete |range| is in UTF-16 offsets of the current surrounding text.
// |range| must be a valid range, i.e.
// range.IsValid() && range.GetMax() <= surrounding_text.length().
virtual void DeleteSurroundingText(std::u16string_view surrounding_text,
const gfx::Range& range) = 0;
// Sends a key event.
virtual void SendKey(const ui::KeyEvent& event) = 0;
// Called when the text direction has changed.
virtual void OnTextDirectionChanged(
base::i18n::TextDirection direction) = 0;
// Sets composition from the current surrounding text offsets.
// Offsets in |cursor| and |range| is relative to the beginning of
// |surrounding_text|. Offsets in |ui_ime_text_spans| is relative to the new
// composition, i.e. relative to |range|'s start. All offsets are in UTF16,
// and must be valid.
virtual void SetCompositionFromExistingText(
std::u16string_view surrounding_text,
const gfx::Range& cursor,
const gfx::Range& range,
const std::vector<ui::ImeTextSpan>& ui_ime_text_spans) = 0;
// Clears all the grammar fragments in |range|.
// |surrounding_text| is the current surrounding text, used for utf16 to
// utf8 conversion.
virtual void ClearGrammarFragments(std::u16string_view surrounding_text,
const gfx::Range& range) = 0;
// Adds a new grammar marker according to |fragments|. Clients should show
// some visual indications such as underlining.
// |surrounding_text| is the current surrounding text, used for utf16 to
// utf8 conversion.
virtual void AddGrammarFragment(std::u16string_view surrounding_text,
const ui::GrammarFragment& fragment) = 0;
// Sets the autocorrect range from the current surrounding text offsets.
// Offsets in |range| is relative to the beginning of
// |surrounding_text|. All offsets are in UTF16, and must be valid.
virtual void SetAutocorrectRange(std::u16string_view surrounding_text,
const gfx::Range& range) = 0;
// Commits the current composition text.
// If `keep_selection` is true, keep the selection range unchanged.
// Otherwise, set the selection range to be after the committed text.
// Returns whether the operation is supported by the client.
virtual bool ConfirmComposition(bool keep_selection) = 0;
// Does the current delegate support the new ConfirmComposition wayland
// method name confirm_preedit?
virtual bool SupportsConfirmPreedit() = 0;
// Checks if InsertImage() is supported via wayland.
virtual bool HasImageInsertSupport() = 0;
// Inserts image.
virtual void InsertImage(const GURL& src) = 0;
};
explicit TextInput(std::unique_ptr<Delegate> delegate);
TextInput(const TextInput&) = delete;
TextInput& operator=(const TextInput&) = delete;
~TextInput() override;
// Request to activate the text input context on the surface. Activation will
// occur immediately if the associated window is already focused, or
// otherwise when the window gains focus.
void Activate(Seat* seat,
Surface* surface,
ui::TextInputClient::FocusReason reason);
// Deactivates the text input context.
void Deactivate();
// Shows the virtual keyboard if needed.
void ShowVirtualKeyboardIfEnabled();
// Hides the virtual keyboard.
void HideVirtualKeyboard();
// Re-synchronize the current status when the surrounding text has changed
// during the text input session.
void Resync();
// Resets the current input method composition state.
void Reset();
// Sets the surrounding text in the app.
// Ranges of |cursor_pos|, |grammar_fragment| and |autocorrect_info| are
// relative to |text|.
// |grammar_fragment| is the grammar fragment at the cursor position,
// if given.
// |autocorrect_info->bounds| is the bounding rect around the autocorrected
// text and is relative to the window origin.
void SetSurroundingText(
std::u16string_view text,
uint32_t offset,
const gfx::Range& cursor_pos,
const std::optional<ui::GrammarFragment>& grammar_fragment,
const std::optional<ui::AutocorrectInfo>& autocorrect_info);
// Sets the text input type, mode, flags, |should_do_learning|,
// |can_compose_inline| and |surrounding_text_supported|.
void SetTypeModeFlags(ui::TextInputType type,
ui::TextInputMode mode,
int flags,
bool should_do_learning,
bool can_compose_inline,
bool surrounding_text_supported);
// Sets the bounds of the text caret, relative to the window origin.
void SetCaretBounds(const gfx::Rect& bounds);
// Finalizes pending virtual keyboard requested changes.
void FinalizeVirtualKeyboardChanges();
Delegate* delegate() { return delegate_.get(); }
// ui::TextInputClient:
base::WeakPtr<ui::TextInputClient> AsWeakPtr() override;
void SetCompositionText(const ui::CompositionText& composition) override;
size_t ConfirmCompositionText(bool keep_selection) override;
void ClearCompositionText() override;
void InsertText(const std::u16string& text,
InsertTextCursorBehavior cursor_behavior) override;
void InsertChar(const ui::KeyEvent& event) override;
bool CanInsertImage() override;
void InsertImage(const GURL& src) override;
ui::TextInputType GetTextInputType() const override;
ui::TextInputMode GetTextInputMode() const override;
base::i18n::TextDirection GetTextDirection() const override;
int GetTextInputFlags() const override;
bool CanComposeInline() const override;
gfx::Rect GetCaretBounds() const override;
gfx::Rect GetSelectionBoundingBox() const override;
bool GetCompositionCharacterBounds(size_t index,
gfx::Rect* rect) const override;
bool HasCompositionText() const override;
ui::TextInputClient::FocusReason GetFocusReason() const override;
bool GetTextRange(gfx::Range* range) const override;
bool GetCompositionTextRange(gfx::Range* range) const override;
bool GetEditableSelectionRange(gfx::Range* range) const override;
bool SetEditableSelectionRange(const gfx::Range& range) override;
bool GetTextFromRange(const gfx::Range& range,
std::u16string* text) const override;
void OnInputMethodChanged() override;
bool ChangeTextDirectionAndLayoutAlignment(
base::i18n::TextDirection direction) override;
void ExtendSelectionAndDelete(size_t before, size_t after) override;
void ExtendSelectionAndReplace(size_t before,
size_t after,
std::u16string_view replacement_text) override;
void EnsureCaretNotInRect(const gfx::Rect& rect) override;
bool IsTextEditCommandEnabled(ui::TextEditCommand command) const override;
void SetTextEditCommandForNextKeyEvent(ui::TextEditCommand command) override;
ukm::SourceId GetClientSourceForMetrics() const override;
bool ShouldDoLearning() override;
bool SetCompositionFromExistingText(
const gfx::Range& range,
const std::vector<ui::ImeTextSpan>& ui_ime_text_spans) override;
gfx::Range GetAutocorrectRange() const override;
gfx::Rect GetAutocorrectCharacterBounds() const override;
bool SetAutocorrectRange(const gfx::Range& range) override;
std::optional<ui::GrammarFragment> GetGrammarFragmentAtCursor()
const override;
bool ClearGrammarFragments(const gfx::Range& range) override;
bool AddGrammarFragments(
const std::vector<ui::GrammarFragment>& fragments) override;
bool SupportsAlwaysConfirmComposition() override;
void GetActiveTextInputControlLayoutBounds(
std::optional<gfx::Rect>* control_bounds,
std::optional<gfx::Rect>* selection_bounds) override {}
// ui::VirtualKeyboardControllerObserver:
void OnKeyboardVisible(const gfx::Rect& keyboard_rect) override;
void OnKeyboardHidden() override;
// ash::input_method::InputMethodManager::Observer:
void InputMethodChanged(ash::input_method::InputMethodManager* manager,
Profile* profile,
bool show_message) override;
// SeatObserver:
void OnSurfaceFocused(Surface* gained_focus,
Surface* lost_focus,
bool has_focused_surface) override;
private:
void AttachInputMethod();
void DetachInputMethod();
void ResetCompositionTextCache();
bool ShouldStageVKState();
void SendStagedVKVisibility();
void SendStagedVKOccludedBounds();
// Delegate to talk to actual its client.
std::unique_ptr<Delegate> delegate_;
// On requesting to show Virtual Keyboard, InputMethod may not be connected.
// So, remember the request temporarily, and then on InputMethod connection
// show the Virtual Keyboard.
bool pending_vk_visible_ = false;
// |surface_| and |seat_| are non-null if and only if the TextInput is in a
// pending or active state, in which case the TextInput will be observing the
// Seat.
raw_ptr<Surface, DanglingUntriaged> surface_ = nullptr;
raw_ptr<Seat, DanglingUntriaged> seat_ = nullptr;
// If the TextInput is active (associated window has focus) and the
// InputMethod is available, this is set and the TextInput will be its
// focused client. Otherwise, it is null and the TextInput is not attached
// to any InputMethod, so the TextInputClient overrides will not be called.
raw_ptr<ui::InputMethod, DanglingUntriaged> input_method_ = nullptr;
base::ScopedObservation<ash::input_method::InputMethodManager,
ash::input_method::InputMethodManager::Observer>
input_method_manager_observation_{this};
base::ScopedObservation<ui::VirtualKeyboardController,
ui::VirtualKeyboardControllerObserver>
virtual_keyboard_observation_{this};
// Cache of the current caret bounding box, sent from the client.
gfx::Rect caret_bounds_;
// Cache of the current input field attributes sent from the client.
ui::TextInputType input_type_ = ui::TEXT_INPUT_TYPE_NONE;
ui::TextInputMode input_mode_ = ui::TEXT_INPUT_MODE_DEFAULT;
int flags_ = ui::TEXT_INPUT_FLAG_NONE;
bool should_do_learning_ = true;
bool can_compose_inline_ = true;
ui::TextInputClient::FocusReason focus_reason_ =
ui::TextInputClient::FOCUS_REASON_NONE;
// Whether the client supports surrounding text.
bool surrounding_text_supported_ = true;
// If surrounding text is not supported and the active IME needs it, we force
// using TEXT_INPUT_TYPE_NULL.
bool use_null_input_type_ = false;
// Tracks the surrounding text.
ui::SurroundingTextTracker surrounding_text_tracker_;
// Cache of the current text input direction, update from the Chrome OS IME.
base::i18n::TextDirection direction_ = base::i18n::UNKNOWN_DIRECTION;
// Cache of the grammar fragment at cursor position, send from Lacros side.
std::optional<ui::GrammarFragment> grammar_fragment_at_cursor_;
// Latest autocorrect information that was sent from the Wayland client.
// along with the last surrounding text change.
ui::AutocorrectInfo autocorrect_info_;
// True when client has made virtual keyboard related requests but haven't
// sent the virtual keyboard finalize request.
bool pending_vk_finalize_ = false;
// Holds the vk visibility to send to the client.
std::optional<bool> staged_vk_visible_;
// Holds the vk occluded bounds to send to the client.
std::optional<gfx::Rect> staged_vk_occluded_bounds_;
base::WeakPtrFactory<TextInput> weak_ptr_factory_{this};
};
} // namespace exo
#endif // COMPONENTS_EXO_TEXT_INPUT_H_
|