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 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460
|
// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef UI_BASE_IME_TEXT_INPUT_CLIENT_H_
#define UI_BASE_IME_TEXT_INPUT_CLIENT_H_
#include <stddef.h>
#include <stdint.h>
#include <optional>
#include <ostream>
#include <string>
#include <string_view>
#include <vector>
#include "base/component_export.h"
#include "base/i18n/rtl.h"
#include "base/memory/weak_ptr.h"
#include "build/build_config.h"
#include "services/metrics/public/cpp/ukm_source_id.h"
#include "ui/base/ime/composition_text.h"
#include "ui/base/ime/grammar_fragment.h"
#include "ui/base/ime/ime_key_event_dispatcher.h"
#include "ui/base/ime/text_input_mode.h"
#include "ui/base/ime/text_input_type.h"
#include "ui/gfx/native_widget_types.h"
#include "ui/gfx/range/range.h"
#include "url/gurl.h"
namespace gfx {
class Point;
class Rect;
}
namespace ui {
class KeyEvent;
enum class TextEditCommand;
#if BUILDFLAG(IS_WIN)
// Mirrors `dwFlags` for ITextStoreACP::GetACPFromPoint:
// https://learn.microsoft.com/en-us/windows/win32/api/textstor/nf-textstor-itextstoreacp-getacpfrompoint
enum class IndexFromPointFlags : uint8_t {
kNone = 0,
// Mirror of: GXFPF_ROUND_NEAREST
// Overrides the default behavior of `GetACPFromPoint` if and only if a
// character bounds contains `point`. Finds the index of the character which
// has the closest origin to `point`.
kNearestToContainedPoint = 0x01,
// Mirror of: GXFPF_NEAREST
// Overrides the default behavior of `GetACPFromPoint` if and only if no
// character bounds contain `point`. Finds the index of the character which
// has the closest origin to `point`.
kNearestToUncontainedPoint = 0x02,
// Alias for having both flags set. Always overrides the default behavior.
// Finds the index of the character which has the closest origin to `point`.
kNearestToPoint = kNearestToContainedPoint | kNearestToUncontainedPoint,
};
#endif // BUILDFLAG(IS_WIN)
// An interface implemented by a View that needs text input support.
// All strings related to IME operations should be UTF-16 encoded and all
// indices/ranges relative to those strings should be UTF-16 code units.
class COMPONENT_EXPORT(UI_BASE_IME) TextInputClient {
public:
// The reason the control was focused, used by the virtual keyboard to detect
// pen input.
enum FocusReason {
// Not focused.
FOCUS_REASON_NONE,
// User initiated with mouse.
FOCUS_REASON_MOUSE,
// User initiated with touch.
FOCUS_REASON_TOUCH,
// User initiated with pen.
FOCUS_REASON_PEN,
// All other reasons (e.g. system initiated, mouse)
FOCUS_REASON_OTHER,
};
#if BUILDFLAG(IS_CHROMEOS)
enum SubClass {
kRenderWidgetHostViewAura = 0,
kArcImeService = 1,
kTextField = 2,
kMaxValue = kTextField,
};
#endif
virtual ~TextInputClient();
// This should be implemented by the most concrete class.
virtual base::WeakPtr<TextInputClient> AsWeakPtr() = 0;
// Input method result -------------------------------------------------------
// Sets composition text and attributes. If there is composition text already,
// it'll be replaced by the new one. Otherwise, current selection will be
// replaced. If there is no selection, the composition text will be inserted
// at the insertion point.
virtual void SetCompositionText(const ui::CompositionText& composition) = 0;
// Converts current composition text into final content.
// If keep_selection is true, keep the selected range unchanged
// otherwise, set it to be after the newly committed text.
// If text was committed, return the number of characters committed.
// If we do not know what the number of characters committed is, return
// std::numeric_limits<size_t>::max().
virtual size_t ConfirmCompositionText(bool keep_selection) = 0;
// Removes current composition text.
virtual void ClearCompositionText() = 0;
enum class InsertTextCursorBehavior {
// Move cursor to the position after the last character in the text.
// e.g. for "hello", the cursor will be right after "o".
kMoveCursorAfterText,
// Move cursor to the position before the first character in the text.
// e.g. for "hello", the cursor will be right before "h".
kMoveCursorBeforeText,
};
// Inserts a given text at the insertion point. Current composition text or
// selection will be removed. This method should never be called when the
// current text input type is TEXT_INPUT_TYPE_NONE.
virtual void InsertText(const std::u16string& text,
InsertTextCursorBehavior cursor_behavior) = 0;
// Inserts a single char at the insertion point. Unlike above InsertText()
// method, this method takes an |event| parameter indicating
// the event that was unprocessed. This method should only be
// called when a key press is not handled by the input method but still
// generates a character (eg. by the keyboard driver). In another word, the
// preceding key press event should not be a VKEY_PROCESSKEY.
// This method will be called whenever a char is generated by the keyboard,
// even if the current text input type is TEXT_INPUT_TYPE_NONE.
virtual void InsertChar(const ui::KeyEvent& event) = 0;
// Returns whether the current insertion point supports images.
virtual bool CanInsertImage();
// Inserts a given image at the insertion point. It should be only called when
// CanInsertImage returns true.
virtual void InsertImage(const GURL& src) {}
// Input context information -------------------------------------------------
// Returns current text input type. It could be changed and even becomes
// TEXT_INPUT_TYPE_NONE at runtime.
virtual ui::TextInputType GetTextInputType() const = 0;
// Returns current text input mode. It could be changed and even becomes
// TEXT_INPUT_MODE_DEFAULT at runtime.
virtual ui::TextInputMode GetTextInputMode() const = 0;
// Returns the current text direction.
virtual base::i18n::TextDirection GetTextDirection() const = 0;
// Returns the current text input flags, which is a bit map of
// WebTextInputType defined in blink. This is valid only for web input fileds;
// it will return TEXT_INPUT_FLAG_NONE for native input fields.
virtual int GetTextInputFlags() const = 0;
// Returns if the client supports inline composition currently.
virtual bool CanComposeInline() const = 0;
// Returns current caret (insertion point) bounds in the universal screen
// coordinates in DIP (Density Independent Pixel).
// If there is selection, then the selection bounds will be returned.
virtual gfx::Rect GetCaretBounds() const = 0;
// Returns the bounds of the rectangle which encloses the selection region.
// Bounds are in the screen coordinates. An empty value should be returned if
// there is not any selection or this function is not implemented.
virtual gfx::Rect GetSelectionBoundingBox() const = 0;
#if BUILDFLAG(IS_WIN)
// For StylusHandwritingWin gesture support, this method mirrors the
// expectations of ITextStoreACP::GetTextExt. Returns the smallest
// axis-aligned bounding box which contains all of the axis-aligned character
// bounding boxes specified by the character offset `range` [start, end).
// The result is in DIP screen coordinates.
//
// For renderer content, "ProximateCharacterBounds" uses a cached subset of
// the actual character bounding boxes, so requests for valid character
// indices may fall outside of the cached rage. If `range` extends outside the
// cached range, regardless of whether the character offset is valid for the
// actual text, std::nullopt is returned.
//
// For views content, it's possible to retrieve accurate results for
// "ProximateCharacterBounds" since the data is readily available. The caching
// mechanism is to mitigate performance costs (CPU and memory) when processing
// very large documents.
virtual std::optional<gfx::Rect> GetProximateCharacterBounds(
const gfx::Range& range) const = 0;
// For StylusHandwritingWin gesture support, this method mirrors the
// expectations of ITextStoreACP::GetACPFromPoint. Depending on which `flags`
// are provided, returns an appropriate character offset relative to
// `screen_point_in_dips`. See comments around IndexFromPointFlags and its
// values for details.
//
// For renderer content, "ProximateCharacterBounds" uses a cached subset of
// the actual character bounding boxes, so requests for `screen_point_in_dips`
// contained by a character bounding box may not be considered "hit" by this
// method if that character falls outside the cached range, or what's
// considered "nearest" may be technically incorrect based on this fact. If
// no `flags` are provided and `screen_point_in_dips` isn't contained by any
// cached character bounds, regardless of whether `screen_point_in_dips` is
// technically valid for the content, std::nullopt is returned. If either or
// both `flags` are provided, this is guaranteed to return *some* character
// offset, even if it's not the most appropriate offset based on the actual
// content.
//
// For views content, it's possible to retrieve accurate results for
// "ProximateCharacterBounds" since the data is readily available. The caching
// mechanism is to mitigate performance costs (CPU and memory) when processing
// very large documents.
virtual std::optional<size_t> GetProximateCharacterIndexFromPoint(
const gfx::Point& screen_point_in_dips,
IndexFromPointFlags flags) const = 0;
#endif // BUILDFLAG(IS_WIN)
// Retrieves the composition character boundary rectangle in the universal
// screen coordinates in DIP (Density Independent Pixel).
// The |index| is zero-based index of character position in composition text.
// Returns false if there is no composition text or |index| is out of range.
// The |rect| is not touched in the case of failure.
virtual bool GetCompositionCharacterBounds(size_t index,
gfx::Rect* rect) const = 0;
// Returns true if there is composition text.
virtual bool HasCompositionText() const = 0;
// Returns how the text input client was focused.
virtual FocusReason GetFocusReason() const = 0;
// Document content operations ----------------------------------------------
// Retrieves the UTF-16 code unit range containing accessible text in
// the View. It must cover the composition and selection range.
// Returns false if the information cannot be retrieved right now.
virtual bool GetTextRange(gfx::Range* range) const = 0;
// Retrieves the UTF-16 code unit range of current composition text.
// Returns false if the information cannot be retrieved right now.
virtual bool GetCompositionTextRange(gfx::Range* range) const = 0;
// Retrieves the UTF-16 code unit range of current selection in the text
// input. Returns false if the information cannot be retrieved right now.
// Returns false if the selected text is outside of the text input (== the
// text input is not focused)
virtual bool GetEditableSelectionRange(gfx::Range* range) const = 0;
// Selects the given UTF-16 code unit range. Current composition text
// will be confirmed before selecting the range.
// Returns false if the operation is not supported.
virtual bool SetEditableSelectionRange(const gfx::Range& range) = 0;
#if BUILDFLAG(IS_MAC)
// Deletes contents in the given UTF-16 code unit range. Current
// composition text will be confirmed before deleting the range.
// The input caret will be moved to the place where the range gets deleted.
// ExtendSelectionAndDelete should be used instead as far as you are deleting
// characters around current caret. This function with the range based on
// GetEditableSelectionRange has a race condition due to asynchronous IPCs
// between browser and renderer. Returns false if the operation is not
// supported.
virtual bool DeleteRange(const gfx::Range& range) = 0;
#endif
// Retrieves the text content in a given UTF-16 code unit range.
// The result will be stored into |*text|.
// Returns false if the operation is not supported or the specified range
// is out of the text range returned by GetTextRange().
virtual bool GetTextFromRange(const gfx::Range& range,
std::u16string* text) const = 0;
// Miscellaneous ------------------------------------------------------------
// Called whenever current keyboard layout or input method is changed,
// especially the change of input locale and text direction.
virtual void OnInputMethodChanged() = 0;
// Called whenever the user requests to change the text direction and layout
// alignment of the current text box. It's for supporting ctrl-shift on
// Windows.
// Returns false if the operation is not supported.
virtual bool ChangeTextDirectionAndLayoutAlignment(
base::i18n::TextDirection direction) = 0;
// Deletes the current selection plus the specified number of char16 values
// before and after the selection or caret. This function should be used
// instead of calling DeleteRange with GetEditableSelectionRange, because
// GetEditableSelectionRange may not be the latest value due to asynchronous
// of IPC between browser and renderer.
virtual void ExtendSelectionAndDelete(size_t before, size_t after) = 0;
#if BUILDFLAG(IS_CHROMEOS)
// Deletes any active composition, and the current selection plus the
// specified number of char16 values before and after the selection, and
// replaces it with |replacement_string|.
// Places the cursor at the end of |replacement_string|.
//
// Clients should try to implement this with an atomic operation to ensure
// that input method features like autocorrection works well. However, it's
// also okay for clients to fall back to ExtendSelectionAndDelete followed by
// InsertText for a degraded experience.
virtual void ExtendSelectionAndReplace(
size_t length_before_selection,
size_t length_after_selection,
std::u16string_view replacement_string);
#endif
// Ensure the caret is not in |rect|. |rect| is in screen coordinates in
// DIP (Density Independent Pixel) and may extend beyond the bounds of this
// TextInputClient.
virtual void EnsureCaretNotInRect(const gfx::Rect& rect) = 0;
// Returns true if |command| is currently allowed to be executed.
virtual bool IsTextEditCommandEnabled(TextEditCommand command) const = 0;
// Execute |command| on the next key event. This allows a TextInputClient to
// be informed of a platform-independent edit command that has been derived
// from the key event currently being dispatched (but not yet sent to the
// TextInputClient). The edit command will take into account any OS-specific,
// or user-specified, keybindings that may be set up.
virtual void SetTextEditCommandForNextKeyEvent(TextEditCommand command) = 0;
// Returns a UKM source for identifying the input client (e.g. for web input
// clients, the source represents the URL of the page).
virtual ukm::SourceId GetClientSourceForMetrics() const = 0;
// Returns whether text entered into this text client should be used to
// improve typing suggestions for the user. This should return false for text
// fields that are considered 'private' (e.g. in incognito tabs).
virtual bool ShouldDoLearning() = 0;
#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
// Start composition over a given UTF-16 code range from existing text. This
// should only be used for composition scenario when IME wants to start
// composition on existing text. Returns whether the operation was successful.
// Must not be called with an invalid range.
virtual bool SetCompositionFromExistingText(
const gfx::Range& range,
const std::vector<ui::ImeTextSpan>& ui_ime_text_spans) = 0;
#endif
#if BUILDFLAG(IS_CHROMEOS)
// Return the start and end index of the autocorrect range. If non-existent,
// return an empty Range.
virtual gfx::Range GetAutocorrectRange() const = 0;
// Return the location of the autocorrect range as a gfx::Rect object.
// If gfx::Rect is empty, then the autocorrect character bounds have not been
// set.
// These bounds are in screen coordinates.
virtual gfx::Rect GetAutocorrectCharacterBounds() const = 0;
// Sets the autocorrect range to |range|. Clients should show some visual
// indication of the range, such as flashing or underlining. If |range| is
// empty, then the autocorrect range is cleared.
// Returns true if the operation was successful. If |range| is invalid, then
// no modifications are made and this function returns false.
virtual bool SetAutocorrectRange(const gfx::Range& range) = 0;
// Returns the grammar fragment which contains the current cursor. If
// non-existent, returns nullopt.
virtual std::optional<GrammarFragment> GetGrammarFragmentAtCursor() const;
// Clears all the grammar fragments in |range|, returns whether the operation
// is successful. Should return true if the there is no fragment in the range.
virtual bool ClearGrammarFragments(const gfx::Range& range);
// Adds new grammar markers according to |fragments|. Clients should show
// some visual indications such as underlining. Returns whether the operation
// is successful.
virtual bool AddGrammarFragments(
const std::vector<GrammarFragment>& fragments);
// Does the current text client support always confirming a composition, even
// if there isn't a composition currently set?
virtual bool SupportsAlwaysConfirmComposition();
#endif
#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_CHROMEOS)
// Returns false if either the focused editable element or the EditContext
// bounds is not available, else it returns true with the control and
// selection bounds for the EditContext or control bounds of the active
// editable element. This is used to report the layout bounds of the text
// input control to TSF on Windows and to the Virtual Keyboard extension on
// ChromeOS.
virtual void GetActiveTextInputControlLayoutBounds(
std::optional<gfx::Rect>* control_bounds,
std::optional<gfx::Rect>* selection_bounds) = 0;
#endif
#if BUILDFLAG(IS_WIN)
// Notifies accessibility about active composition. This API is currently
// only defined for TSF which is available only on Windows
// https://docs.microsoft.com/en-us/windows/desktop/api/UIAutomationCore/
// nf-uiautomationcore-itexteditprovider-getactivecomposition
// It notifies the composition range, composition text and whether the
// composition has been committed or not.
virtual void SetActiveCompositionForAccessibility(
const gfx::Range& range,
const std::u16string& active_composition_text,
bool is_composition_committed) = 0;
#endif
#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_CHROMEOS)
struct EditingContext {
// Contains the active web content's URL.
GURL page_url;
};
virtual ui::TextInputClient::EditingContext GetTextEditingContext();
// Notifies TSF when a frame with a committed Url receives focus.
virtual void NotifyOnFrameFocusChanged() {}
#endif
// Called before ui::InputMethod dispatches a not-consumed event to PostIME
// phase. This method gives TextInputClient a chance to intercept event
// dispatching.
virtual void OnDispatchingKeyEventPostIME(ui::KeyEvent* event) {}
};
#if BUILDFLAG(IS_WIN)
COMPONENT_EXPORT(UI_BASE_IME)
extern std::ostream& operator<<(std::ostream& os, IndexFromPointFlags flags);
#endif // BUILDFLAG(IS_WIN)
} // namespace ui
#if BUILDFLAG(IS_WIN)
inline constexpr ui::IndexFromPointFlags operator&(ui::IndexFromPointFlags a,
ui::IndexFromPointFlags b) {
using T = std::underlying_type_t<ui::IndexFromPointFlags>;
return static_cast<ui::IndexFromPointFlags>(static_cast<T>(a) &
static_cast<T>(b));
}
inline constexpr ui::IndexFromPointFlags operator|(ui::IndexFromPointFlags a,
ui::IndexFromPointFlags b) {
using T = std::underlying_type_t<ui::IndexFromPointFlags>;
return static_cast<ui::IndexFromPointFlags>(static_cast<T>(a) |
static_cast<T>(b));
}
inline constexpr ui::IndexFromPointFlags& operator|=(
ui::IndexFromPointFlags& a,
ui::IndexFromPointFlags b) {
a = a | b;
return a;
}
#endif // BUILDFLAG(IS_WIN)
#endif // UI_BASE_IME_TEXT_INPUT_CLIENT_H_
|