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
|
// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/ash/input_method/native_input_method_engine.h"
#include <utility>
#include "ash/constants/ash_features.h"
#include "ash/lobster/lobster_controller.h"
#include "base/feature_list.h"
#include "base/metrics/histogram_macros.h"
#include "chrome/browser/ash/input_method/assistive_suggester_client_filter.h"
#include "chrome/browser/ash/input_method/assistive_suggester_switch.h"
#include "chrome/browser/ash/input_method/autocorrect_manager.h"
#include "chrome/browser/ash/input_method/editor_mediator_factory.h"
#include "chrome/browser/ash/input_method/get_current_window_properties.h"
#include "chrome/browser/ash/input_method/grammar_service_client.h"
#include "chrome/browser/ash/input_method/native_input_method_engine_observer.h"
#include "chrome/browser/ash/input_method/suggestions_service_client.h"
#include "chrome/browser/ash/lobster/lobster_event_sink.h"
#include "chrome/browser/ash/lobster/lobster_service_provider.h"
#include "chrome/browser/ui/ash/input_method/input_method_menu_manager.h"
#include "chromeos/constants/chromeos_features.h"
#include "components/prefs/pref_service.h"
#include "ui/base/ime/ash/input_method_manager.h"
namespace ash {
namespace input_method {
namespace {
bool ShouldRouteToFirstPartyVietnameseInput(std::string_view engine_id) {
return base::FeatureList::IsEnabled(features::kFirstPartyVietnameseInput) &&
(engine_id == "vkd_vi_vni" || engine_id == "vkd_vi_telex");
}
} // namespace
NativeInputMethodEngine::NativeInputMethodEngine()
: NativeInputMethodEngine(/*use_ime_service=*/true) {}
NativeInputMethodEngine::NativeInputMethodEngine(bool use_ime_service)
: use_ime_service_(use_ime_service) {}
// static
std::unique_ptr<NativeInputMethodEngine>
NativeInputMethodEngine::CreateForTesting(bool use_ime_service) {
return base::WrapUnique<NativeInputMethodEngine>(
new NativeInputMethodEngine(use_ime_service));
}
NativeInputMethodEngine::~NativeInputMethodEngine() = default;
NativeInputMethodEngine::NativeInputMethodEngine(
std::unique_ptr<AssistiveSuggesterSwitch> suggester_switch)
: suggester_switch_(std::move(suggester_switch)) {}
void NativeInputMethodEngine::Initialize(
std::unique_ptr<InputMethodEngineObserver> observer,
const char* extension_id,
Profile* profile) {
// TODO(crbug.com/40154142): refactor the mix of unique and raw ptr here.
std::unique_ptr<AssistiveSuggester> assistive_suggester =
std::make_unique<AssistiveSuggester>(
this, profile,
suggester_switch_
? std::move(suggester_switch_)
: std::make_unique<AssistiveSuggesterClientFilter>(
base::BindRepeating(&GetFocusedTabUrl),
base::BindRepeating(&GetFocusedWindowProperties)));
assistive_suggester_ = assistive_suggester.get();
std::unique_ptr<AutocorrectManager> autocorrect_manager =
std::make_unique<AutocorrectManager>(this, profile);
autocorrect_manager_ = autocorrect_manager.get();
auto suggestions_service_client =
base::FeatureList::IsEnabled(features::kAssistMultiWord)
? std::make_unique<SuggestionsServiceClient>()
: nullptr;
auto suggestions_collector =
base::FeatureList::IsEnabled(features::kAssistMultiWord)
? std::make_unique<SuggestionsCollector>(
assistive_suggester_, std::move(suggestions_service_client))
: nullptr;
EditorMediator* editor_event_sink =
chromeos::features::IsOrcaEnabled()
? EditorMediatorFactory::GetInstance()->GetForProfile(profile)
: nullptr;
LobsterEventSink* lobster_event_sink =
ash::features::IsLobsterEnabled()
? LobsterServiceProvider::GetForProfile(profile)
: nullptr;
chrome_keyboard_controller_client_observer_.Observe(
ChromeKeyboardControllerClient::Get());
// Wrap the given observer in our observer that will decide whether to call
// Mojo directly or forward to the extension.
auto native_observer = std::make_unique<NativeInputMethodEngineObserver>(
profile->GetPrefs(), editor_event_sink, lobster_event_sink,
std::move(observer), std::move(assistive_suggester),
std::move(autocorrect_manager), std::move(suggestions_collector),
std::make_unique<GrammarManager>(
profile, std::make_unique<GrammarServiceClient>(), this),
use_ime_service_);
InputMethodEngine::Initialize(std::move(native_observer), extension_id,
profile);
}
bool NativeInputMethodEngine::ShouldRouteToNativeMojoEngine(
const std::string& engine_id) const {
return use_ime_service_ && CanRouteToNativeMojoEngine(engine_id);
}
void NativeInputMethodEngine::CandidateClicked(uint32_t index) {
// The parent implementation will try to convert `index` into a candidate ID.
// The native Mojo engine doesn't use candidate IDs, so we just treat `index`
// as the ID, without doing a mapping.
if (ShouldRouteToNativeMojoEngine(GetActiveComponentId())) {
GetNativeObserver()->OnCandidateClicked(GetActiveComponentId(), index,
MOUSE_BUTTON_LEFT);
} else {
InputMethodEngine::CandidateClicked(index);
}
}
bool NativeInputMethodEngine::IsReadyForTesting() {
if (ShouldRouteToNativeMojoEngine(GetActiveComponentId())) {
return GetNativeObserver()->IsReadyForTesting(); // IN-TEST
}
return InputMethodEngine::IsReadyForTesting();
}
void NativeInputMethodEngine::OnKeyboardEnabledChanged(bool enabled) {
// Re-activate the engine whenever the virtual keyboard is enabled or disabled
// so that the native or extension state is reset correctly.
Enable(GetActiveComponentId());
}
void NativeInputMethodEngine::OnProfileWillBeDestroyed(Profile* profile) {
InputMethodEngine::OnProfileWillBeDestroyed(profile);
GetNativeObserver()->OnProfileWillBeDestroyed();
}
void NativeInputMethodEngine::FlushForTesting() {
GetNativeObserver()->FlushForTesting();
}
bool NativeInputMethodEngine::IsConnectedForTesting() const {
return GetNativeObserver()->IsConnectedForTesting();
}
void NativeInputMethodEngine::OnAutocorrect(
const std::u16string& typed_word,
const std::u16string& corrected_word,
int start_index) {
autocorrect_manager_->HandleAutocorrect(
gfx::Range(start_index, start_index + corrected_word.length()),
typed_word, corrected_word);
}
NativeInputMethodEngineObserver* NativeInputMethodEngine::GetNativeObserver()
const {
return static_cast<NativeInputMethodEngineObserver*>(observer_.get());
}
bool NativeInputMethodEngine::UpdateMenuItems(
const std::vector<InputMethodManager::MenuItem>& items,
std::string* error) {
// Ignore calls to UpdateMenuItems when the native Mojo engine is active.
// The menu items are stored in a singleton that is shared between the native
// Mojo engine and the extension. This method is called when the extension
// wants to update the menu items.
// Ignore this if the native Mojo engine is active to prevent the extension
// from overriding the menu items set by the native Mojo engine.
if (ShouldRouteToNativeMojoEngine(GetActiveComponentId())) {
return true;
}
return InputMethodEngine::UpdateMenuItems(items, error);
}
void NativeInputMethodEngine::OnInputMethodOptionsChanged() {
if (ShouldRouteToNativeMojoEngine(GetActiveComponentId()) ||
ShouldRouteToFirstPartyVietnameseInput(GetActiveComponentId())) {
Enable(GetActiveComponentId());
} else {
InputMethodEngine::OnInputMethodOptionsChanged();
}
}
} // namespace input_method
} // namespace ash
|