Commit 8b5855bc authored by Darren Shen's avatar Darren Shen Committed by Commit Bot

rule-based: Connect to IME service natively when using rule-based.

To migrate rule-based to Chromium C++, we need to have a separate code
path for the official XKB keyboard. The new code path needs to use Mojo
directly instead of sending extension messages.

Currently, IMF communicates to the extension via an "IME observer" which
takes native events like OnActivate and converts them to extension API
events.

To start off this migration, we create a new IME observer that basically
intercepts events from IMF and forwards them to the existing
extension-based IME observer. This allows us to migrate event-by-event
by routing a certain event directly to the IME service instead of
through the extension system.

In this CL, we hook into the OnActivate event to create a connection
to the IME service. All events are still forwarded to the old extension
system, so nothing should change.

In a followup CL, we will route OnReset directly to the IME service
as our first migration.

Bug: 1009903
Change-Id: Id4df50c8688474c76a498f5f2746f9ad2cbadabb
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1847701
Auto-Submit: Darren Shen <shend@chromium.org>
Reviewed-by: default avatarOksana Zhuravlova <oksamyt@chromium.org>
Reviewed-by: default avatarShu Chen <shuchen@chromium.org>
Commit-Queue: Darren Shen <shend@chromium.org>
Cr-Commit-Position: refs/heads/master@{#710192}
parent e107d751
...@@ -1164,6 +1164,8 @@ source_set("chromeos") { ...@@ -1164,6 +1164,8 @@ source_set("chromeos") {
"input_method/input_method_persistence.h", "input_method/input_method_persistence.h",
"input_method/input_method_syncer.cc", "input_method/input_method_syncer.cc",
"input_method/input_method_syncer.h", "input_method/input_method_syncer.h",
"input_method/native_input_method_engine.cc",
"input_method/native_input_method_engine.h",
"kerberos/kerberos_credentials_manager.cc", "kerberos/kerberos_credentials_manager.cc",
"kerberos/kerberos_credentials_manager.h", "kerberos/kerberos_credentials_manager.h",
"kerberos/kerberos_ticket_expiry_notification.cc", "kerberos/kerberos_ticket_expiry_notification.cc",
......
...@@ -37,6 +37,7 @@ specific_include_rules = { ...@@ -37,6 +37,7 @@ specific_include_rules = {
"+chrome/browser", "+chrome/browser",
"+chrome/test", "+chrome/test",
"+content/public", "+content/public",
"+mojo/core/embedder/embedder.h",
], ],
"xkeyboard_unittest\.cc": [ "xkeyboard_unittest\.cc": [
"!content/public/test/test_browser_thread.h", "!content/public/test/test_browser_thread.h",
......
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/chromeos/input_method/native_input_method_engine.h"
#include "base/strings/string_util.h"
#include "ui/base/ime/chromeos/input_method_manager.h"
namespace chromeos {
namespace {
bool ShouldEngineUseMojo(const std::string& engine_id) {
return base::StartsWith(engine_id, "vkd_", base::CompareCase::SENSITIVE);
}
} // namespace
NativeInputMethodEngine::NativeInputMethodEngine() = default;
NativeInputMethodEngine::~NativeInputMethodEngine() = default;
void NativeInputMethodEngine::Initialize(
std::unique_ptr<InputMethodEngineBase::Observer> observer,
const char* extension_id,
Profile* profile) {
// 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<chromeos::NativeInputMethodEngine::ImeObserver>(
std::move(observer));
InputMethodEngine::Initialize(std::move(native_observer), extension_id,
profile);
}
void NativeInputMethodEngine::FlushForTesting() {
GetNativeObserver()->FlushForTesting();
}
bool NativeInputMethodEngine::IsConnectedForTesting() const {
return GetNativeObserver()->IsConnectedForTesting();
}
NativeInputMethodEngine::ImeObserver*
NativeInputMethodEngine::GetNativeObserver() const {
return static_cast<ImeObserver*>(observer_.get());
}
NativeInputMethodEngine::ImeObserver::ImeObserver(
std::unique_ptr<InputMethodEngineBase::Observer> base_observer)
: base_observer_(std::move(base_observer)), receiver_from_engine_(this) {
input_method::InputMethodManager::Get()->ConnectInputEngineManager(
remote_manager_.BindNewPipeAndPassReceiver());
}
NativeInputMethodEngine::ImeObserver::~ImeObserver() = default;
void NativeInputMethodEngine::ImeObserver::OnActivate(
const std::string& engine_id) {
if (ShouldEngineUseMojo(engine_id)) {
// For legacy reasons, |engine_id| starts with "vkd_" in the input method
// manifest, but the InputEngineManager expects the prefix "m17n:".
// TODO(https://crbug.com/1012490): Migrate to m17n prefix and remove this.
const auto new_engine_id = "m17n:" + engine_id.substr(4);
remote_manager_->ConnectToImeEngine(
new_engine_id, remote_to_engine_.BindNewPipeAndPassReceiver(),
receiver_from_engine_.BindNewPipeAndPassRemote(), {},
base::BindOnce(&ImeObserver::OnConnected, base::Unretained(this)));
}
base_observer_->OnActivate(engine_id);
}
void NativeInputMethodEngine::ImeObserver::OnFocus(
const IMEEngineHandlerInterface::InputContext& context) {
base_observer_->OnFocus(context);
}
void NativeInputMethodEngine::ImeObserver::OnBlur(int context_id) {
base_observer_->OnBlur(context_id);
}
void NativeInputMethodEngine::ImeObserver::OnKeyEvent(
const std::string& engine_id,
const InputMethodEngineBase::KeyboardEvent& event,
ui::IMEEngineHandlerInterface::KeyEventDoneCallback callback) {
base_observer_->OnKeyEvent(engine_id, event, std::move(callback));
}
void NativeInputMethodEngine::ImeObserver::OnReset(
const std::string& engine_id) {
base_observer_->OnReset(engine_id);
}
void NativeInputMethodEngine::ImeObserver::OnDeactivated(
const std::string& engine_id) {
base_observer_->OnDeactivated(engine_id);
}
void NativeInputMethodEngine::ImeObserver::OnCompositionBoundsChanged(
const std::vector<gfx::Rect>& bounds) {
base_observer_->OnCompositionBoundsChanged(bounds);
}
void NativeInputMethodEngine::ImeObserver::OnSurroundingTextChanged(
const std::string& engine_id,
const std::string& text,
int cursor_pos,
int anchor_pos,
int offset_pos) {
base_observer_->OnSurroundingTextChanged(engine_id, text, cursor_pos,
anchor_pos, offset_pos);
}
void NativeInputMethodEngine::ImeObserver::OnInputContextUpdate(
const IMEEngineHandlerInterface::InputContext& context) {
base_observer_->OnInputContextUpdate(context);
}
void NativeInputMethodEngine::ImeObserver::OnCandidateClicked(
const std::string& component_id,
int candidate_id,
InputMethodEngineBase::MouseButtonEvent button) {
base_observer_->OnCandidateClicked(component_id, candidate_id, button);
}
void NativeInputMethodEngine::ImeObserver::OnMenuItemActivated(
const std::string& component_id,
const std::string& menu_id) {
base_observer_->OnMenuItemActivated(component_id, menu_id);
}
void NativeInputMethodEngine::ImeObserver::OnScreenProjectionChanged(
bool is_projected) {
base_observer_->OnScreenProjectionChanged(is_projected);
}
void NativeInputMethodEngine::ImeObserver::FlushForTesting() {
remote_manager_.FlushForTesting();
receiver_from_engine_.FlushForTesting();
remote_to_engine_.FlushForTesting();
}
void NativeInputMethodEngine::ImeObserver::OnConnected(bool bound) {
connected_to_engine_ = bound;
}
} // namespace chromeos
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_CHROMEOS_INPUT_METHOD_NATIVE_INPUT_METHOD_ENGINE_H_
#define CHROME_BROWSER_CHROMEOS_INPUT_METHOD_NATIVE_INPUT_METHOD_ENGINE_H_
#include "chrome/browser/chromeos/input_method/input_method_engine.h"
#include "chromeos/services/ime/public/mojom/input_engine.mojom.h"
#include "mojo/public/cpp/bindings/remote.h"
namespace chromeos {
// An InputMethodEngine used for the official Chrome OS build. It's a bridge
// between the Chrome OS input framework and the IME service. Although it
// currently depends on the Chrome extension system, it will not need to in
// the future after all the extensions code are migrated to the IME service.
// The design of this class is not good, mainly because we are inheriting
// from InputMethodEngineBase, which was designed for extension-based engines.
//
// In the final design, there should be some common interface between
// NativeInputMethodEngine and "ExtensionInputMethodEngine" (which is
// InputMethodEngineBase in the current design). All extensions-related logic
// will reside in the ExtensionInputMethodEngine inheritance tree. There will
// be no "ImeObserver" for the native engine either, as it is only used as
// a way for ExtensionInputMethodEngine to delegate to the extensions code,
// which is not required for the native engine.
class NativeInputMethodEngine : public InputMethodEngine {
public:
NativeInputMethodEngine();
~NativeInputMethodEngine() override;
// InputMethodEngine:
void Initialize(std::unique_ptr<InputMethodEngineBase::Observer> observer,
const char* extension_id,
Profile* profile) override;
// Flush all relevant Mojo pipes.
void FlushForTesting();
// Returns whether this is connected to the input engine.
bool IsConnectedForTesting() const;
private:
class ImeObserver : public InputMethodEngineBase::Observer,
public ime::mojom::InputChannel {
public:
// |base_observer| is to forward events to extension during this migration.
// It will be removed when the official extension is completely migrated.
explicit ImeObserver(
std::unique_ptr<InputMethodEngineBase::Observer> base_observer);
~ImeObserver() override;
// InputMethodEngineBase::Observer:
void OnActivate(const std::string& engine_id) override;
void OnFocus(
const IMEEngineHandlerInterface::InputContext& context) override;
void OnBlur(int context_id) override;
void OnKeyEvent(
const std::string& engine_id,
const InputMethodEngineBase::KeyboardEvent& event,
ui::IMEEngineHandlerInterface::KeyEventDoneCallback callback) override;
void OnReset(const std::string& engine_id) override;
void OnDeactivated(const std::string& engine_id) override;
void OnCompositionBoundsChanged(
const std::vector<gfx::Rect>& bounds) override;
void OnSurroundingTextChanged(const std::string& engine_id,
const std::string& text,
int cursor_pos,
int anchor_pos,
int offset_pos) override;
void OnInputContextUpdate(
const IMEEngineHandlerInterface::InputContext& context) override;
void OnCandidateClicked(
const std::string& component_id,
int candidate_id,
InputMethodEngineBase::MouseButtonEvent button) override;
void OnMenuItemActivated(const std::string& component_id,
const std::string& menu_id) override;
void OnScreenProjectionChanged(bool is_projected) override;
// mojom::InputChannel:
void ProcessMessage(const std::vector<uint8_t>& message,
ProcessMessageCallback callback) override {}
void ProcessKeypressForRulebased(
ime::mojom::KeypressInfoForRulebasedPtr message,
ProcessKeypressForRulebasedCallback callback) override {}
void ResetForRulebased() override {}
void GetRulebasedKeypressCountForTesting(
GetRulebasedKeypressCountForTestingCallback callback) override {}
// Flush all relevant Mojo pipes.
void FlushForTesting();
// Returns whether this is connected to the input engine.
bool IsConnectedForTesting() const { return connected_to_engine_; }
private:
// Called when this is connected to the input engine. |bound| indicates
// the success of the connection.
void OnConnected(bool bound);
std::unique_ptr<InputMethodEngineBase::Observer> base_observer_;
mojo::Remote<ime::mojom::InputEngineManager> remote_manager_;
mojo::Receiver<ime::mojom::InputChannel> receiver_from_engine_;
mojo::Remote<ime::mojom::InputChannel> remote_to_engine_;
bool connected_to_engine_ = false;
};
ImeObserver* GetNativeObserver() const;
};
} // namespace chromeos
#endif // CHROME_BROWSER_CHROMEOS_INPUT_METHOD_NATIVE_INPUT_METHOD_ENGINE_H_
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/chromeos/input_method/native_input_method_engine.h"
#include "base/test/task_environment.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "content/public/test/test_utils.h"
#include "mojo/core/embedder/embedder.h"
namespace {
using input_method::InputMethodEngineBase;
class TestObserver : public InputMethodEngineBase::Observer {
public:
TestObserver() = default;
~TestObserver() override = default;
void OnActivate(const std::string& engine_id) override {}
void OnDeactivated(const std::string& engine_id) override {}
void OnFocus(
const ui::IMEEngineHandlerInterface::InputContext& context) override {}
void OnBlur(int context_id) override {}
void OnKeyEvent(
const std::string& engine_id,
const InputMethodEngineBase::KeyboardEvent& event,
ui::IMEEngineHandlerInterface::KeyEventDoneCallback key_data) override {}
void OnInputContextUpdate(
const ui::IMEEngineHandlerInterface::InputContext& context) override {}
void OnCandidateClicked(
const std::string& engine_id,
int candidate_id,
InputMethodEngineBase::MouseButtonEvent button) override {}
void OnMenuItemActivated(const std::string& engine_id,
const std::string& menu_id) override {}
void OnSurroundingTextChanged(const std::string& engine_id,
const std::string& text,
int cursor_pos,
int anchor_pos,
int offset) override {}
void OnCompositionBoundsChanged(
const std::vector<gfx::Rect>& bounds) override {}
void OnScreenProjectionChanged(bool is_projected) override {}
void OnReset(const std::string& engine_id) override {}
private:
DISALLOW_COPY_AND_ASSIGN(TestObserver);
};
class NativeInputMethodEngineTest : public InProcessBrowserTest {
protected:
void SetUp() override {
mojo::core::Init();
InProcessBrowserTest::SetUp();
}
void SetUpOnMainThread() override {
auto observer = std::make_unique<TestObserver>();
engine_.Initialize(std::move(observer), "", nullptr);
InProcessBrowserTest::SetUpOnMainThread();
}
chromeos::NativeInputMethodEngine engine_;
};
} // namespace
IN_PROC_BROWSER_TEST_F(NativeInputMethodEngineTest, CanConnectToInputEngine) {
// ID for Arabic is specified in google_xkb_manifest.json.
engine_.Enable("vkd_ar");
engine_.FlushForTesting();
EXPECT_TRUE(engine_.IsConnectedForTesting());
}
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include "base/feature_list.h" #include "base/feature_list.h"
#include "base/macros.h" #include "base/macros.h"
#include "chrome/browser/chromeos/input_method/input_method_engine.h" #include "chrome/browser/chromeos/input_method/input_method_engine.h"
#include "chrome/browser/chromeos/input_method/native_input_method_engine.h"
#include "chrome/browser/chromeos/login/lock/screen_locker.h" #include "chrome/browser/chromeos/login/lock/screen_locker.h"
#include "chrome/browser/chromeos/login/session/user_session_manager.h" #include "chrome/browser/chromeos/login/session/user_session_manager.h"
#include "chrome/browser/chromeos/profiles/profile_helper.h" #include "chrome/browser/chromeos/profiles/profile_helper.h"
...@@ -444,11 +445,13 @@ bool InputImeEventRouter::RegisterImeExtension( ...@@ -444,11 +445,13 @@ bool InputImeEventRouter::RegisterImeExtension(
profile = profile->GetOffTheRecordProfile(); profile = profile->GetOffTheRecordProfile();
} }
std::unique_ptr<InputMethodEngineBase::Observer> observer( auto observer = std::make_unique<ImeObserverChromeOS>(extension_id, profile);
new ImeObserverChromeOS(extension_id, profile)); auto engine = (extension_id == "jkghodnilhceideoidjikpgommlajknk")
auto engine = std::make_unique<chromeos::InputMethodEngine>(); ? std::make_unique<chromeos::NativeInputMethodEngine>()
: std::make_unique<chromeos::InputMethodEngine>();
engine->Initialize(std::move(observer), extension_id.c_str(), profile); engine->Initialize(std::move(observer), extension_id.c_str(), profile);
engine_map_[extension_id] = std::move(engine); engine_map_[extension_id] = std::move(engine);
chromeos::UserSessionManager::GetInstance() chromeos::UserSessionManager::GetInstance()
->GetDefaultIMEState(profile) ->GetDefaultIMEState(profile)
->AddInputMethodExtension(extension_id, descriptors, ->AddInputMethodExtension(extension_id, descriptors,
......
...@@ -129,7 +129,8 @@ class InputMethodEngineBase : virtual public ui::IMEEngineHandlerInterface { ...@@ -129,7 +129,8 @@ class InputMethodEngineBase : virtual public ui::IMEEngineHandlerInterface {
~InputMethodEngineBase() override; ~InputMethodEngineBase() override;
void Initialize(std::unique_ptr<InputMethodEngineBase::Observer> observer, virtual void Initialize(
std::unique_ptr<InputMethodEngineBase::Observer> observer,
const char* extension_id, const char* extension_id,
Profile* profile); Profile* profile);
......
...@@ -2096,6 +2096,7 @@ if (!is_android) { ...@@ -2096,6 +2096,7 @@ if (!is_android) {
"../browser/chromeos/first_run/drive_first_run_browsertest.cc", "../browser/chromeos/first_run/drive_first_run_browsertest.cc",
"../browser/chromeos/first_run/goodies_displayer_browsertest.cc", "../browser/chromeos/first_run/goodies_displayer_browsertest.cc",
"../browser/chromeos/input_method/input_method_engine_browsertests.cc", "../browser/chromeos/input_method/input_method_engine_browsertests.cc",
"../browser/chromeos/input_method/native_input_method_engine_browsertest.cc",
"../browser/chromeos/input_method/textinput_browsertest.cc", "../browser/chromeos/input_method/textinput_browsertest.cc",
"../browser/chromeos/input_method/textinput_surroundingtext_browsertest.cc", "../browser/chromeos/input_method/textinput_surroundingtext_browsertest.cc",
"../browser/chromeos/input_method/textinput_test_helper.cc", "../browser/chromeos/input_method/textinput_test_helper.cc",
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment