| // Copyright 2013 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef CHROME_BROWSER_ASH_INPUT_METHOD_INPUT_METHOD_ENGINE_H_ |
| #define CHROME_BROWSER_ASH_INPUT_METHOD_INPUT_METHOD_ENGINE_H_ |
| |
| #include <stddef.h> |
| #include <stdint.h> |
| |
| #include <map> |
| #include <string> |
| #include <string_view> |
| #include <vector> |
| |
| #include "base/containers/span.h" |
| #include "base/memory/raw_ptr.h" |
| #include "base/scoped_observation.h" |
| #include "base/types/expected.h" |
| #include "base/values.h" |
| #include "chrome/browser/ash/input_method/assistive_window_properties.h" |
| #include "chrome/browser/ash/input_method/input_method_engine_observer.h" |
| #include "chrome/browser/ash/input_method/screen_projection_change_monitor.h" |
| #include "chrome/browser/ash/input_method/suggestion_handler_interface.h" |
| #include "chrome/browser/profiles/profile.h" |
| #include "chrome/browser/profiles/profile_observer.h" |
| #include "components/prefs/pref_change_registrar.h" |
| #include "extensions/common/extension_id.h" |
| #include "ui/base/ime/ash/input_method_descriptor.h" |
| #include "ui/base/ime/ash/input_method_manager.h" |
| #include "ui/base/ime/ash/text_input_method.h" |
| #include "ui/base/ime/candidate_window.h" |
| #include "ui/base/ime/composition_text.h" |
| #include "ui/events/event.h" |
| |
| static_assert(BUILDFLAG(IS_CHROMEOS), "For ChromeOS only"); |
| |
| namespace ui { |
| struct CompositionText; |
| class KeyEvent; |
| |
| namespace ime { |
| struct AssistiveWindowButton; |
| struct InputMethodMenuItem; |
| struct SuggestionDetails; |
| } // namespace ime |
| } // namespace ui |
| |
| namespace ash { |
| |
| namespace ime { |
| struct AssistiveWindow; |
| } // namespace ime |
| |
| namespace input_method { |
| |
| struct AssistiveWindowProperties; |
| |
| class InputMethodEngine : virtual public TextInputMethod, |
| public ProfileObserver, |
| public SuggestionHandlerInterface { |
| public: |
| enum { |
| MENU_ITEM_MODIFIED_LABEL = 0x0001, |
| MENU_ITEM_MODIFIED_CHECKED = 0x0010, |
| }; |
| |
| enum SegmentStyle { |
| SEGMENT_STYLE_UNDERLINE, |
| SEGMENT_STYLE_DOUBLE_UNDERLINE, |
| SEGMENT_STYLE_NO_UNDERLINE, |
| }; |
| |
| struct SegmentInfo { |
| int start; |
| int end; |
| SegmentStyle style; |
| }; |
| |
| struct UsageEntry { |
| std::string title; |
| std::string body; |
| }; |
| |
| struct Candidate { |
| Candidate(); |
| Candidate(const Candidate& other); |
| virtual ~Candidate(); |
| |
| std::string value; |
| int id; |
| std::string label; |
| std::string annotation; |
| UsageEntry usage; |
| std::vector<Candidate> candidates; |
| }; |
| |
| struct CandidateWindowProperty { |
| CandidateWindowProperty(); |
| virtual ~CandidateWindowProperty(); |
| CandidateWindowProperty(const CandidateWindowProperty& other); |
| int page_size; |
| bool is_cursor_visible; |
| bool is_vertical; |
| bool show_window_at_composition; |
| |
| // Auxiliary text is typically displayed in the footer of the candidate |
| // window. |
| std::string auxiliary_text; |
| bool is_auxiliary_text_visible; |
| |
| // The index of the current chosen candidate out of total candidates. |
| // value is -1 if there is no current chosen candidate. |
| int current_candidate_index = -1; |
| int total_candidates = 0; |
| }; |
| |
| enum class Error { |
| kInputMethodNotActive, |
| kIncorrectContextId, |
| }; |
| |
| InputMethodEngine(); |
| InputMethodEngine(const InputMethodEngine&) = delete; |
| InputMethodEngine& operator=(const InputMethodEngine&) = delete; |
| ~InputMethodEngine() override; |
| |
| virtual void Initialize(std::unique_ptr<InputMethodEngineObserver> observer, |
| const char* extension_id, |
| Profile* profile); |
| |
| // Returns true if this IME is active, false if not. |
| bool IsActive() const; |
| |
| // Returns the current active input_component id. |
| const std::string& GetActiveComponentId() const; |
| |
| // Clear the current composition. |
| bool ClearComposition(int context_id, std::string* error); |
| |
| // Commit the specified text to the specified context. Fails if the context |
| // is not focused. |
| bool CommitText(int context_id, |
| const std::u16string& text, |
| std::string* error); |
| |
| // Notifies InputContextHandler to commit any composition text. |
| // Set |reset_engine| to false if the event was from the extension. |
| void ConfirmComposition(bool reset_engine); |
| |
| // Deletes |number_of_chars| unicode characters as the basis of |offset| from |
| // the surrounding text. The |offset| is relative position based on current |
| // caret. |
| // NOTE: Currently we are falling back to backspace forwarding workaround, |
| // because delete_surrounding_text is not supported in Chrome. So this |
| // function is restricted for only preceding text. |
| // TODO(nona): Support full spec delete surrounding text. |
| bool DeleteSurroundingText(int context_id, |
| int offset, |
| size_t number_of_chars, |
| std::string* error); |
| |
| // 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|. |
| base::expected<void, Error> ReplaceSurroundingText( |
| int context_id, |
| int length_before_selection, |
| int length_after_selection, |
| std::u16string_view replacement_text); |
| |
| // Commit the text currently being composed to the composition. |
| // Fails if the context is not focused. |
| bool FinishComposingText(int context_id, std::string* error); |
| |
| // Send the sequence of key events. |
| bool SendKeyEvents(int context_id, |
| const std::vector<ui::KeyEvent>& events, |
| std::string* error); |
| |
| // Set the current composition and associated properties. |
| // Note: The cursor is used to index into a UTF16 version |
| // of the input text. Ideally, we should check the |
| // UTF16 version of the input text and make sure the |
| // selection start and end falls within that range. |
| bool SetComposition(int context_id, |
| const char* text, |
| int selection_start, |
| int selection_end, |
| int cursor, |
| const std::vector<SegmentInfo>& segments, |
| std::string* error); |
| |
| // Set the current composition range around the current cursor. |
| // This function is deprecated. Use |SetComposingRange| instead. |
| bool SetCompositionRange(int context_id, |
| int selection_before, |
| int selection_after, |
| const std::vector<SegmentInfo>& segments, |
| std::string* error); |
| |
| // Set the current composition range. |
| bool SetComposingRange(int context_id, |
| int start, |
| int end, |
| const std::vector<SegmentInfo>& segments, |
| std::string* error); |
| |
| gfx::Rect GetTextFieldBounds(int context_id, std::string* error); |
| |
| bool SetAutocorrectRange(int context_id, |
| const gfx::Range& range, |
| std::string* error); |
| |
| // Called when a key event is handled. |
| void KeyEventHandled(const std::string& extension_id, |
| const std::string& request_id, |
| bool handled); |
| |
| // Returns the request ID for this key event. |
| std::string AddPendingKeyEvent( |
| const std::string& component_id, |
| TextInputMethod::KeyEventDoneCallback callback); |
| |
| // Resolves all the pending key event callbacks as not handled. |
| void CancelPendingKeyEvents(); |
| |
| int GetContextIdForTesting() const { return context_id_; } |
| |
| PrefChangeRegistrar* GetPrefChangeRegistrarForTesting() const { |
| return pref_change_registrar_.get(); |
| } |
| |
| // TextInputMethod overrides. |
| void Focus(const TextInputMethod::InputContext& input_context) override; |
| void Blur() override; |
| void Enable(const std::string& component_id) override; |
| void Disable() override; |
| void Reset() override; |
| void ProcessKeyEvent(const ui::KeyEvent& key_event, |
| KeyEventDoneCallback callback) override; |
| void SetSurroundingText(const std::u16string& text, |
| gfx::Range selection_range, |
| uint32_t offset_pos) override; |
| void SetCaretBounds(const gfx::Rect& caret_bounds) override; |
| void PropertyActivate(const std::string& property_name) override; |
| void CandidateClicked(uint32_t index) override; |
| void AssistiveWindowButtonClicked( |
| const ui::ime::AssistiveWindowButton& button) override; |
| void AssistiveWindowChanged(const ash::ime::AssistiveWindow& window) override; |
| ui::VirtualKeyboardController* GetVirtualKeyboardController() const override; |
| bool IsReadyForTesting() override; |
| |
| // SuggestionHandlerInterface overrides. |
| bool DismissSuggestion(int context_id, std::string* error) override; |
| bool SetSuggestion(int context_id, |
| const ui::ime::SuggestionDetails& details, |
| std::string* error) override; |
| bool AcceptSuggestion(int context_id, std::string* error) override; |
| void OnSuggestionsChanged( |
| const std::vector<std::string>& suggestions) override; |
| bool SetButtonHighlighted(int context_id, |
| const ui::ime::AssistiveWindowButton& button, |
| bool highlighted, |
| std::string* error) override; |
| void ClickButton(const ui::ime::AssistiveWindowButton& button) override; |
| bool AcceptSuggestionCandidate(int context_id, |
| const std::u16string& candidate, |
| size_t delete_previous_utf16_len, |
| std::string* error) override; |
| bool SetAssistiveWindowProperties( |
| int context_id, |
| const AssistiveWindowProperties& assistive_window, |
| std::string* error) override; |
| void Announce(const std::u16string& message) override; |
| |
| // ProfileObserver overrides. |
| void OnProfileWillBeDestroyed(Profile* profile) override; |
| |
| // This function returns the current property of the candidate window of the |
| // corresponding engine_id. If the CandidateWindowProperty is not set for the |
| // engine_id, a default value is set. The caller can use the returned value as |
| // the default property and modify some of specified items. |
| const CandidateWindowProperty& GetCandidateWindowProperty( |
| const std::string& engine_id); |
| |
| // Changes the property of the candidate window of the given engine_id and |
| // repaints the candidate window widget. |
| void SetCandidateWindowProperty(const std::string& engine_id, |
| const CandidateWindowProperty& property); |
| |
| // Show or hide the candidate window. |
| bool SetCandidateWindowVisible(bool visible, std::string* error); |
| |
| // Set the list of entries displayed in the candidate window. |
| bool SetCandidates(int context_id, |
| const std::vector<Candidate>& candidates, |
| std::string* error); |
| |
| // Set the position of the cursor in the candidate window. |
| bool SetCursorPosition(int context_id, int candidate_id, std::string* error); |
| |
| // Update the state of the menu items. |
| virtual bool UpdateMenuItems( |
| const std::vector<InputMethodManager::MenuItem>& items, |
| std::string* error); |
| |
| // Hides the input view window (from API call). |
| void HideInputView(); |
| |
| void NotifyInputMethodExtensionReadyForTesting(); |
| |
| protected: |
| virtual void OnInputMethodOptionsChanged(); |
| |
| // The observer object receiving events for this IME. |
| std::unique_ptr<InputMethodEngineObserver> observer_; |
| |
| private: |
| struct PendingKeyEvent { |
| PendingKeyEvent(const std::string& component_id, |
| TextInputMethod::KeyEventDoneCallback callback); |
| PendingKeyEvent(PendingKeyEvent&& other); |
| |
| PendingKeyEvent(const PendingKeyEvent&) = delete; |
| PendingKeyEvent& operator=(const PendingKeyEvent&) = delete; |
| |
| ~PendingKeyEvent(); |
| |
| std::string component_id; |
| TextInputMethod::KeyEventDoneCallback callback; |
| }; |
| |
| // Called when Diacritics setting changed for metrics. |
| void DiacriticsSettingsChanged(); |
| |
| // Notifies InputContextHandler that the composition is changed. |
| void UpdateComposition(const ui::CompositionText& composition_text, |
| uint32_t cursor_pos, |
| bool is_visible); |
| |
| // Notifies InputContextHandler to commit |text|. |
| void CommitTextToInputContext(int context_id, const std::u16string& text); |
| |
| // Converts MenuItem to InputMethodMenuItem. |
| void MenuItemToProperty(const InputMethodManager::MenuItem& item, |
| ui::ime::InputMethodMenuItem* property); |
| |
| void OnScreenProjectionChanged(bool is_projected); |
| |
| // Infers if the user is choosing from a candidate from the window. |
| // TODO(b/300576550): get this information from IME. |
| bool InferIsUserSelecting(base::span<const Candidate> candidates); |
| |
| // The current candidate window. |
| ui::CandidateWindow candidate_window_; |
| |
| // The candidate window property of the current engine_id. |
| std::pair<std::string, CandidateWindowProperty> candidate_window_property_; |
| |
| // Indicates whether the candidate window is visible. |
| bool window_visible_ = false; |
| |
| // Mapping of candidate index to candidate id. |
| std::vector<int> candidate_ids_; |
| |
| // Mapping of candidate id to index. |
| std::map<int, int> candidate_indexes_; |
| |
| ui::TextInputType current_input_type_; |
| |
| // ID that is used for the current input context. False if there is no focus. |
| int context_id_; |
| |
| // Next id that will be assigned to a context. |
| int next_context_id_; |
| |
| // The input_component ID in IME extension's manifest. |
| std::string active_component_id_; |
| |
| // The IME extension ID. |
| extensions::ExtensionId extension_id_; |
| |
| raw_ptr<Profile> profile_; |
| |
| unsigned int next_request_id_ = 1; |
| |
| std::map<std::string, PendingKeyEvent> pending_key_events_; |
| |
| // The composition text to be set from calling input.ime.setComposition API. |
| ui::CompositionText composition_; |
| |
| bool composition_changed_; |
| |
| // The text to be committed from calling input.ime.commitText API. |
| std::u16string text_; |
| |
| bool commit_text_changed_; |
| |
| std::unique_ptr<PrefChangeRegistrar> pref_change_registrar_; |
| |
| base::Value::Dict input_method_settings_snapshot_; |
| |
| ScreenProjectionChangeMonitor screen_projection_change_monitor_; |
| |
| bool is_ready_for_testing_ = false; |
| |
| base::ScopedObservation<Profile, ProfileObserver> profile_observation_{this}; |
| }; |
| |
| } // namespace input_method |
| } // namespace ash |
| |
| #endif // CHROME_BROWSER_ASH_INPUT_METHOD_INPUT_METHOD_ENGINE_H_ |