// Copyright 2021 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_MULTI_WORD_SUGGESTER_H_
#define CHROME_BROWSER_ASH_INPUT_METHOD_MULTI_WORD_SUGGESTER_H_
#include <optional>
#include "base/memory/raw_ptr.h"
#include "base/time/time.h"
#include "chrome/browser/ash/input_method/suggester.h"
#include "chrome/browser/ash/input_method/suggestion_enums.h"
#include "chrome/browser/ash/input_method/suggestion_handler_interface.h"
#include "chromeos/ash/services/ime/public/cpp/assistive_suggestions.h"
namespace ash {
namespace input_method {
// Integrates multi word suggestions produced by the system with the assistive
// framework. Handles showing / accepting / dismissing any multi word
// suggestions generated by the system.
class MultiWordSuggester : public Suggester {
public:
// `suggestion_handler` and `profile` need to exist longer than the lifetime
// of this object.
MultiWordSuggester(SuggestionHandlerInterface* suggestion_handler,
Profile* profile);
~MultiWordSuggester() override;
// Suggester overrides:
void OnFocus(int context_id) override;
void OnBlur() override;
void OnExternalSuggestionsUpdated(
const std::vector<ime::AssistiveSuggestion>& suggestions,
const std::optional<ime::SuggestionsTextContext>& context) override;
SuggestionStatus HandleKeyEvent(const ui::KeyEvent& event) override;
bool TrySuggestWithSurroundingText(const std::u16string& text,
gfx::Range selection_range) override;
bool AcceptSuggestion(size_t index = 0) override;
void DismissSuggestion() override;
AssistiveType GetProposeActionType() override;
bool HasSuggestions() override;
std::vector<ime::AssistiveSuggestion> GetSuggestions() override;
// Used to capture any changes to the current input text.
void OnSurroundingTextChanged(const std::u16string& text,
gfx::Range selection_range);
private:
// Used to capture any internal state around the previously or currently
// shown suggestions.
class SuggestionState {
public:
enum State {
kNoSuggestionShown,
kPredictionSuggestionShown,
kCompletionSuggestionShown,
kTrackingLastSuggestionShown,
kSuggestionDismissed,
kSuggestionAccepted,
};
struct Suggestion {
ime::AssistiveSuggestionMode mode;
std::u16string text;
size_t confirmed_length;
size_t initial_confirmed_length;
base::TimeTicks time_first_shown;
bool highlighted = false;
size_t original_surrounding_text_length;
};
struct SurroundingText {
std::u16string text;
size_t cursor_pos;
size_t prev_cursor_pos;
bool cursor_at_end_of_text;
};
explicit SuggestionState(MultiWordSuggester* suggester);
~SuggestionState();
// As the name suggests, used to update the current state and perform
// any actions required during a transition.
void UpdateState(const State& state);
// Captures surrounding text context.
void UpdateSurroundingText(const SurroundingText& surrounding_text);
// Captures new suggestion context.
void UpdateSuggestion(const Suggestion& suggestion,
bool new_tracking_behavior);
// Validates the given suggestion text context with the current surrounding
// text, and returns the state of the given suggestion context.
MultiWordSuggestionState ValidateSuggestion(
const Suggestion& suggestion,
const ime::SuggestionsTextContext& context);
// Takes the current suggestion and surrounding text state, and ensures the
// confirmed length or any other suggestion details are correct.
void ReconcileSuggestionWithText();
// Toggles the highlight state of the current suggeston.
void ToggleSuggestionHighlight();
// As the name suggests, is there a suggestion currently shown to the user?
bool IsSuggestionShowing();
// Is the user's cursor located at the end of the text they are currently
// editing?
bool IsCursorAtEndOfText();
// Has the user highlighted the current suggestion showing?
bool IsSuggestionHighlighted();
// Returns the current suggestion state if there is any available.
std::optional<Suggestion> GetSuggestion();
// Returns the last suggestion type shown to the user. This suggestion may,
// or may not, be currently showing to the user.
AssistiveType GetLastSuggestionType();
// Resets the current suggestion context, and any other related state.
void ResetSuggestion();
private:
// Not owned by this class
raw_ptr<MultiWordSuggester> suggester_;
// The current state of the suggester (eg is a suggestion shown or not).
State state_ = State::kNoSuggestionShown;
// Last known surrounding text context captured by the suggester.
std::optional<SurroundingText> surrounding_text_;
// The current suggestion shown to the user by the suggester.
std::optional<Suggestion> suggestion_;
// The last suggestion type shown to the user.
AssistiveType last_suggestion_type_ = AssistiveType::kGenericAction;
};
void DisplaySuggestionIfAvailable();
void DisplaySuggestion(const SuggestionState::Suggestion& suggestion);
void ResetSuggestionState();
void ResetTextState();
// Visibly highlight the suggestion in the ui shown to the user.
void SetSuggestionHighlight(bool highlighted);
// Announce the given message to the user.
void Announce(const std::u16string& message);
// The currently focused input (nullopt if none are focused)
std::optional<int> focused_context_id_;
// Not owned by this class
raw_ptr<SuggestionHandlerInterface, DanglingUntriaged> suggestion_handler_;
// Current suggestion state
SuggestionState state_;
ui::ime::AssistiveWindowButton suggestion_button_;
// The current user's Chrome user profile.
const raw_ptr<Profile> profile_;
};
} // namespace input_method
} // namespace ash
#endif // CHROME_BROWSER_ASH_INPUT_METHOD_MULTI_WORD_SUGGESTER_H_