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
|
// 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 <string>
#include "base/i18n/rtl.h"
#include "base/scoped_observation.h"
#include "base/strings/string_piece.h"
#include "components/exo/seat_observer.h"
#include "third_party/abseil-cpp/absl/types/optional.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 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(base::StringPiece16 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(base::StringPiece16 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(base::StringPiece16 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(
base::StringPiece16 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(base::StringPiece16 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(base::StringPiece16 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(base::StringPiece16 surrounding_text,
const gfx::Range& range) = 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);
// 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.
// |cursor_pos| is the range of |text|.
void SetSurroundingText(const std::u16string& text,
const gfx::Range& cursor_pos);
// Sets the text input type, mode, flags, and |should_do_learning|.
void SetTypeModeFlags(ui::TextInputType type,
ui::TextInputMode mode,
int flags,
bool should_do_learning);
// Sets the bounds of the text caret, relative to the window origin.
void SetCaretBounds(const gfx::Rect& bounds);
// Sets grammar fragment at the cursor position.
void SetGrammarFragmentAtCursor(
const absl::optional<ui::GrammarFragment>& fragment);
// Sets the autocorrect range and bounds. `autocorrect_bounds` is the
// bounding rect around the autocorreced text, and are relative to
// to the window origin.
void SetAutocorrectInfo(const gfx::Range& autocorrect_range,
const gfx::Rect& autocorrect_bounds);
// Finalizes pending virtual keyboard requested changes.
void FinalizeVirtualKeyboardChanges();
Delegate* delegate() { return delegate_.get(); }
// ui::TextInputClient:
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;
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 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;
absl::optional<ui::GrammarFragment> GetGrammarFragmentAtCursor()
const override;
bool ClearGrammarFragments(const gfx::Range& range) override;
bool AddGrammarFragments(
const std::vector<ui::GrammarFragment>& fragments) override;
void GetActiveTextInputControlLayoutBounds(
absl::optional<gfx::Rect>* control_bounds,
absl::optional<gfx::Rect>* selection_bounds) override {}
// ui::VirtualKeyboardControllerObserver:
void OnKeyboardVisible(const gfx::Rect& keyboard_rect) override;
void OnKeyboardHidden() 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.
Surface* surface_ = nullptr;
Seat* 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.
ui::InputMethod* input_method_ = nullptr;
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;
// 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.
// Wayland API sends the fragment range in utf8 and what IME needs is utf16.
// To correctly convert the utf8 range to utf16, we need the updated
// surrounding text, which is not available when we receive the grammar
// fragment. It is guaranteed that on Lacros side, it always updates grammar
// fragment before updating surrounding text. So we store the utf8 fragment in
// |grammar_fragment_at_cursor_utf8_| when we receive it and when we receive
// the surrounding text update next time, we convert the utf8 fragment to
// utf16 fragment and store it in |grammar_fragment_at_cursor_utf16_|. When
// IME requests current grammar fragment, we always return the utf16 version.
absl::optional<ui::GrammarFragment> grammar_fragment_at_cursor_utf8_;
absl::optional<ui::GrammarFragment> grammar_fragment_at_cursor_utf16_;
struct AutocorrectInfo {
gfx::Range range;
gfx::Rect bounds;
};
// Latest autocorrect information that was sent from the Wayland client.
// along with the last surrounding text change.
AutocorrectInfo autocorrect_info_;
// Latest autocorrect information that was received without a receiving a
// corresponding surrounding text. Once this class receives a surrounding text
// update, `autocorrect_info_` will take on this pending value, if it exists.
absl::optional<AutocorrectInfo> pending_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.
absl::optional<bool> staged_vk_visible_;
// Holds the vk occluded bounds to send to the client.
absl::optional<gfx::Rect> staged_vk_occluded_bounds_;
};
} // namespace exo
#endif // COMPONENTS_EXO_TEXT_INPUT_H_
|