Commit db550526 authored by azurewei's avatar azurewei Committed by Commit bot

Implement chrome.input.ime.setComposition and chrome.input.ime.commitText APIs...

Implement chrome.input.ime.setComposition and chrome.input.ime.commitText APIs on Linux and Windows platform.

This cl makes ui::InputMethodBase inherits from ui::IMEInputContextHandlerInterface, thus we can implement functions CommitText() and UpdateCompositionText() once for Linux and Windows.

Make InputImeKeyEventHandledFunction::Run() calls the new added InputMethodBase::KeyEventHandler() in  to set |handling_key_event_|, which indicates whether the IME extension is handling key event. And when |handling_key_event_| == true, we should not setComposition and commitText until it's done to run the callback.

Add helper function UpdateCommitText() and CommitTextToInputContext() in InputMethodEngineBase, which will be override in chromeos::InputMehtodEngine and input_method::InputMethodEngine to implement the API on different platforms.

BUG=517773
TEST=None

Review URL: https://codereview.chromium.org/1657593007

Cr-Commit-Position: refs/heads/master@{#376095}
parent 660aa300
...@@ -344,4 +344,28 @@ void InputMethodEngine::MenuItemToProperty( ...@@ -344,4 +344,28 @@ void InputMethodEngine::MenuItemToProperty(
// TODO(nona): Support item.children. // TODO(nona): Support item.children.
} }
void InputMethodEngine::UpdateComposition(
const ui::CompositionText& composition_text,
uint32_t cursor_pos,
bool is_visible) {
ui::IMEInputContextHandlerInterface* input_context =
ui::IMEBridge::Get()->GetInputContextHandler();
if (input_context)
input_context->UpdateCompositionText(composition_text, cursor_pos,
is_visible);
}
void InputMethodEngine::CommitTextToInputContext(int context_id,
const std::string& text) {
ui::IMEBridge::Get()->GetInputContextHandler()->CommitText(text);
// Records histograms for committed characters.
if (!composition_text_->text.empty()) {
base::string16 wtext = base::UTF8ToUTF16(text);
UMA_HISTOGRAM_CUSTOM_COUNTS("InputMethod.CommitLength", wtext.length(), 1,
25, 25);
composition_text_.reset(new ui::CompositionText());
}
}
} // namespace chromeos } // namespace chromeos
...@@ -151,6 +151,13 @@ class InputMethodEngine : public ::input_method::InputMethodEngineBase { ...@@ -151,6 +151,13 @@ class InputMethodEngine : public ::input_method::InputMethodEngineBase {
// Enables overriding input view page to Virtual Keyboard window. // Enables overriding input view page to Virtual Keyboard window.
void EnableInputView(); void EnableInputView();
// input_method::InputMethodEngineBase:
void UpdateComposition(const ui::CompositionText& composition_text,
uint32_t cursor_pos,
bool is_visible) override;
void CommitTextToInputContext(int context_id,
const std::string& text) override;
// The current candidate window. // The current candidate window.
scoped_ptr<ui::CandidateWindow> candidate_window_; scoped_ptr<ui::CandidateWindow> candidate_window_;
......
...@@ -10,6 +10,8 @@ ...@@ -10,6 +10,8 @@
namespace input_ime = extensions::api::input_ime; namespace input_ime = extensions::api::input_ime;
namespace KeyEventHandled = extensions::api::input_ime::KeyEventHandled; namespace KeyEventHandled = extensions::api::input_ime::KeyEventHandled;
namespace SetComposition = extensions::api::input_ime::SetComposition;
namespace CommitText = extensions::api::input_ime::CommitText;
using ui::IMEEngineHandlerInterface; using ui::IMEEngineHandlerInterface;
using input_method::InputMethodEngineBase; using input_method::InputMethodEngineBase;
...@@ -263,6 +265,70 @@ ExtensionFunction::ResponseAction InputImeKeyEventHandledFunction::Run() { ...@@ -263,6 +265,70 @@ ExtensionFunction::ResponseAction InputImeKeyEventHandledFunction::Run() {
return RespondNow(NoArguments()); return RespondNow(NoArguments());
} }
ExtensionFunction::ResponseAction InputImeSetCompositionFunction::Run() {
bool success = false;
InputImeEventRouter* event_router =
GetInputImeEventRouter(Profile::FromBrowserContext(browser_context()));
InputMethodEngineBase* engine =
event_router ? event_router->GetActiveEngine(extension_id()) : nullptr;
if (engine) {
scoped_ptr<SetComposition::Params> parent_params(
SetComposition::Params::Create(*args_));
const SetComposition::Params::Parameters& params =
parent_params->parameters;
std::vector<InputMethodEngineBase::SegmentInfo> segments;
if (params.segments) {
const std::vector<
linked_ptr<SetComposition::Params::Parameters::SegmentsType>>&
segments_args = *params.segments;
for (const auto& segments_arg : segments_args) {
EXTENSION_FUNCTION_VALIDATE(segments_arg->style !=
input_ime::UNDERLINE_STYLE_NONE);
InputMethodEngineBase::SegmentInfo segment_info;
segment_info.start = segments_arg->start;
segment_info.end = segments_arg->end;
if (segments_arg->style == input_ime::UNDERLINE_STYLE_UNDERLINE) {
segment_info.style = InputMethodEngineBase::SEGMENT_STYLE_UNDERLINE;
} else if (segments_arg->style ==
input_ime::UNDERLINE_STYLE_DOUBLEUNDERLINE) {
segment_info.style =
InputMethodEngineBase::SEGMENT_STYLE_DOUBLE_UNDERLINE;
} else {
segment_info.style =
InputMethodEngineBase::SEGMENT_STYLE_NO_UNDERLINE;
}
segments.push_back(segment_info);
}
}
int selection_start =
params.selection_start ? *params.selection_start : params.cursor;
int selection_end =
params.selection_end ? *params.selection_end : params.cursor;
success = engine->SetComposition(params.context_id, params.text.c_str(),
selection_start, selection_end,
params.cursor, segments, &error_);
}
scoped_ptr<base::ListValue> output = SetComposition::Results::Create(success);
return RespondNow(ArgumentList(std::move(output)));
}
ExtensionFunction::ResponseAction InputImeCommitTextFunction::Run() {
bool success = false;
InputImeEventRouter* event_router =
GetInputImeEventRouter(Profile::FromBrowserContext(browser_context()));
InputMethodEngineBase* engine =
event_router ? event_router->GetActiveEngine(extension_id()) : nullptr;
if (engine) {
scoped_ptr<CommitText::Params> parent_params(
CommitText::Params::Create(*args_));
const CommitText::Params::Parameters& params = parent_params->parameters;
success =
engine->CommitText(params.context_id, params.text.c_str(), &error_);
}
scoped_ptr<base::ListValue> output = CommitText::Results::Create(success);
return RespondNow(ArgumentList(std::move(output)));
}
InputImeAPI::InputImeAPI(content::BrowserContext* context) InputImeAPI::InputImeAPI(content::BrowserContext* context)
: browser_context_(context), extension_registry_observer_(this) { : browser_context_(context), extension_registry_observer_(this) {
extension_registry_observer_.Add(ExtensionRegistry::Get(browser_context_)); extension_registry_observer_.Add(ExtensionRegistry::Get(browser_context_));
......
...@@ -128,6 +128,29 @@ class InputImeKeyEventHandledFunction : public UIThreadExtensionFunction { ...@@ -128,6 +128,29 @@ class InputImeKeyEventHandledFunction : public UIThreadExtensionFunction {
ResponseAction Run() override; ResponseAction Run() override;
}; };
class InputImeSetCompositionFunction : public UIThreadExtensionFunction {
public:
DECLARE_EXTENSION_FUNCTION("input.ime.setComposition",
INPUT_IME_SETCOMPOSITION)
protected:
~InputImeSetCompositionFunction() override {}
// UIThreadExtensionFunction:
ResponseAction Run() override;
};
class InputImeCommitTextFunction : public UIThreadExtensionFunction {
public:
DECLARE_EXTENSION_FUNCTION("input.ime.commitText", INPUT_IME_COMMITTEXT)
protected:
~InputImeCommitTextFunction() override {}
// UIThreadExtensionFunction:
ResponseAction Run() override;
};
class InputImeAPI : public BrowserContextKeyedAPI, class InputImeAPI : public BrowserContextKeyedAPI,
public ExtensionRegistryObserver, public ExtensionRegistryObserver,
public EventRouter::Observer { public EventRouter::Observer {
......
...@@ -35,9 +35,7 @@ namespace SetCursorPosition = extensions::api::input_ime::SetCursorPosition; ...@@ -35,9 +35,7 @@ namespace SetCursorPosition = extensions::api::input_ime::SetCursorPosition;
namespace SetCandidates = extensions::api::input_ime::SetCandidates; namespace SetCandidates = extensions::api::input_ime::SetCandidates;
namespace SetCandidateWindowProperties = namespace SetCandidateWindowProperties =
extensions::api::input_ime::SetCandidateWindowProperties; extensions::api::input_ime::SetCandidateWindowProperties;
namespace CommitText = extensions::api::input_ime::CommitText;
namespace ClearComposition = extensions::api::input_ime::ClearComposition; namespace ClearComposition = extensions::api::input_ime::ClearComposition;
namespace SetComposition = extensions::api::input_ime::SetComposition;
namespace OnCompositionBoundsChanged = namespace OnCompositionBoundsChanged =
extensions::api::input_method_private::OnCompositionBoundsChanged; extensions::api::input_method_private::OnCompositionBoundsChanged;
using ui::IMEEngineHandlerInterface; using ui::IMEEngineHandlerInterface;
...@@ -346,55 +344,6 @@ InputMethodEngineBase* InputImeEventRouter::GetActiveEngine( ...@@ -346,55 +344,6 @@ InputMethodEngineBase* InputImeEventRouter::GetActiveEngine(
: nullptr; : nullptr;
} }
bool InputImeSetCompositionFunction::RunSync() {
InputMethodEngine* engine = GetActiveEngine(
Profile::FromBrowserContext(browser_context()), extension_id());
if (!engine) {
SetResult(new base::FundamentalValue(false));
return true;
}
scoped_ptr<SetComposition::Params> parent_params(
SetComposition::Params::Create(*args_));
const SetComposition::Params::Parameters& params = parent_params->parameters;
std::vector<InputMethodEngineBase::SegmentInfo> segments;
if (params.segments) {
const std::vector<linked_ptr<
SetComposition::Params::Parameters::SegmentsType> >&
segments_args = *params.segments;
for (size_t i = 0; i < segments_args.size(); ++i) {
EXTENSION_FUNCTION_VALIDATE(
segments_args[i]->style !=
input_ime::UNDERLINE_STYLE_NONE);
segments.push_back(InputMethodEngineBase::SegmentInfo());
segments.back().start = segments_args[i]->start;
segments.back().end = segments_args[i]->end;
if (segments_args[i]->style ==
input_ime::UNDERLINE_STYLE_UNDERLINE) {
segments.back().style = InputMethodEngineBase::SEGMENT_STYLE_UNDERLINE;
} else if (segments_args[i]->style ==
input_ime::UNDERLINE_STYLE_DOUBLEUNDERLINE) {
segments.back().style =
InputMethodEngineBase::SEGMENT_STYLE_DOUBLE_UNDERLINE;
} else {
segments.back().style =
InputMethodEngineBase::SEGMENT_STYLE_NO_UNDERLINE;
}
}
}
int selection_start =
params.selection_start ? *params.selection_start : params.cursor;
int selection_end =
params.selection_end ? *params.selection_end : params.cursor;
SetResult(new base::FundamentalValue(
engine->SetComposition(params.context_id, params.text.c_str(),
selection_start, selection_end, params.cursor,
segments, &error_)));
return true;
}
bool InputImeClearCompositionFunction::RunSync() { bool InputImeClearCompositionFunction::RunSync() {
InputMethodEngine* engine = GetActiveEngine( InputMethodEngine* engine = GetActiveEngine(
Profile::FromBrowserContext(browser_context()), extension_id()); Profile::FromBrowserContext(browser_context()), extension_id());
...@@ -413,24 +362,6 @@ bool InputImeClearCompositionFunction::RunSync() { ...@@ -413,24 +362,6 @@ bool InputImeClearCompositionFunction::RunSync() {
return true; return true;
} }
bool InputImeCommitTextFunction::RunSync() {
InputMethodEngine* engine = GetActiveEngine(
Profile::FromBrowserContext(browser_context()), extension_id());
if (!engine) {
SetResult(new base::FundamentalValue(false));
return true;
}
scoped_ptr<CommitText::Params> parent_params(
CommitText::Params::Create(*args_));
const CommitText::Params::Parameters& params =
parent_params->parameters;
SetResult(new base::FundamentalValue(
engine->CommitText(params.context_id, params.text.c_str(), &error_)));
return true;
}
bool InputImeHideInputViewFunction::RunAsync() { bool InputImeHideInputViewFunction::RunAsync() {
InputMethodEngine* engine = GetActiveEngine( InputMethodEngine* engine = GetActiveEngine(
Profile::FromBrowserContext(browser_context()), extension_id()); Profile::FromBrowserContext(browser_context()), extension_id());
......
...@@ -21,18 +21,6 @@ class InputMethodEngine; ...@@ -21,18 +21,6 @@ class InputMethodEngine;
namespace extensions { namespace extensions {
class InputImeSetCompositionFunction : public SyncExtensionFunction {
public:
DECLARE_EXTENSION_FUNCTION("input.ime.setComposition",
INPUT_IME_SETCOMPOSITION)
protected:
~InputImeSetCompositionFunction() override {}
// ExtensionFunction:
bool RunSync() override;
};
class InputImeClearCompositionFunction : public SyncExtensionFunction { class InputImeClearCompositionFunction : public SyncExtensionFunction {
public: public:
DECLARE_EXTENSION_FUNCTION("input.ime.clearComposition", DECLARE_EXTENSION_FUNCTION("input.ime.clearComposition",
...@@ -45,17 +33,6 @@ class InputImeClearCompositionFunction : public SyncExtensionFunction { ...@@ -45,17 +33,6 @@ class InputImeClearCompositionFunction : public SyncExtensionFunction {
bool RunSync() override; bool RunSync() override;
}; };
class InputImeCommitTextFunction : public SyncExtensionFunction {
public:
DECLARE_EXTENSION_FUNCTION("input.ime.commitText", INPUT_IME_COMMITTEXT)
protected:
~InputImeCommitTextFunction() override {}
// ExtensionFunction:
bool RunSync() override;
};
class InputImeSetCandidateWindowPropertiesFunction class InputImeSetCandidateWindowPropertiesFunction
: public SyncExtensionFunction { : public SyncExtensionFunction {
public: public:
......
...@@ -4,6 +4,10 @@ ...@@ -4,6 +4,10 @@
#include "chrome/browser/ui/input_method/input_method_engine.h" #include "chrome/browser/ui/input_method/input_method_engine.h"
#include "ui/base/ime/composition_text.h"
#include "ui/base/ime/ime_bridge.h"
#include "ui/base/ime/ime_input_context_handler_interface.h"
namespace input_method { namespace input_method {
InputMethodEngine::InputMethodEngine() {} InputMethodEngine::InputMethodEngine() {}
...@@ -25,4 +29,44 @@ std::string InputMethodEngine::GetExtensionId() const { ...@@ -25,4 +29,44 @@ std::string InputMethodEngine::GetExtensionId() const {
return extension_id_; return extension_id_;
} }
void InputMethodEngine::UpdateComposition(
const ui::CompositionText& composition_text,
uint32_t cursor_pos,
bool is_visible) {
composition_.CopyFrom(composition_text);
// Use a black thin underline by default.
if (composition_.underlines.empty()) {
composition_.underlines.push_back(
ui::CompositionUnderline(0, composition_.text.length(), SK_ColorBLACK,
false /* thick */, SK_ColorTRANSPARENT));
}
ui::IMEInputContextHandlerInterface* input_context =
ui::IMEBridge::Get()->GetInputContextHandler();
// If the IME extension is handling key event, hold the composition text
// until the key event is handled.
if (input_context && !handling_key_event_) {
input_context->UpdateCompositionText(composition_text, cursor_pos,
is_visible);
composition_.Clear();
}
}
void InputMethodEngine::CommitTextToInputContext(int context_id,
const std::string& text) {
// Append the text to the buffer, as it allows committing text multiple times
// when processing a key event.
text_ += text;
ui::IMEInputContextHandlerInterface* input_context =
ui::IMEBridge::Get()->GetInputContextHandler();
// If the IME extension is handling key event, hold the text until the key
// event is handled.
if (input_context && !handling_key_event_) {
input_context->CommitText(text_);
text_ = "";
}
}
} // namespace input_method } // namespace input_method
...@@ -24,6 +24,13 @@ class InputMethodEngine : public InputMethodEngineBase { ...@@ -24,6 +24,13 @@ class InputMethodEngine : public InputMethodEngineBase {
std::string GetExtensionId() const override; std::string GetExtensionId() const override;
private: private:
// input_method::InputMethodEngineBase:
void UpdateComposition(const ui::CompositionText& composition_text,
uint32_t cursor_pos,
bool is_visible) override;
void CommitTextToInputContext(int context_id,
const std::string& text) override;
DISALLOW_COPY_AND_ASSIGN(InputMethodEngine); DISALLOW_COPY_AND_ASSIGN(InputMethodEngine);
}; };
......
...@@ -47,30 +47,6 @@ namespace { ...@@ -47,30 +47,6 @@ namespace {
const char kErrorNotActive[] = "IME is not active"; const char kErrorNotActive[] = "IME is not active";
const char kErrorWrongContext[] = "Context is not active"; const char kErrorWrongContext[] = "Context is not active";
// Notifies InputContextHandler that the composition is changed.
void UpdateComposition(const ui::CompositionText& composition_text,
uint32_t cursor_pos,
bool is_visible) {
ui::IMEInputContextHandlerInterface* input_context =
ui::IMEBridge::Get()->GetInputContextHandler();
if (input_context)
input_context->UpdateCompositionText(composition_text, cursor_pos,
is_visible);
}
// Returns the length of characters of a UTF-8 string with unknown string
// length. Cannot apply faster algorithm to count characters in an utf-8
// string without knowing the string length, so just does a full scan.
size_t GetUtf8StringLength(const char* s) {
size_t ret = 0;
while (*s) {
if ((*s & 0xC0) != 0x80)
ret++;
++s;
}
return ret;
}
#if defined(OS_CHROMEOS) #if defined(OS_CHROMEOS)
std::string GetKeyFromEvent(const ui::KeyEvent& event) { std::string GetKeyFromEvent(const ui::KeyEvent& event) {
const std::string code = event.GetCodeString(); const std::string code = event.GetCodeString();
...@@ -181,7 +157,9 @@ InputMethodEngineBase::InputMethodEngineBase() ...@@ -181,7 +157,9 @@ InputMethodEngineBase::InputMethodEngineBase()
composition_cursor_(0), composition_cursor_(0),
sent_key_event_(nullptr), sent_key_event_(nullptr),
profile_(nullptr), profile_(nullptr),
next_request_id_(1) {} next_request_id_(1),
text_(""),
handling_key_event_(false) {}
InputMethodEngineBase::~InputMethodEngineBase() {} InputMethodEngineBase::~InputMethodEngineBase() {}
...@@ -285,14 +263,7 @@ bool InputMethodEngineBase::CommitText(int context_id, ...@@ -285,14 +263,7 @@ bool InputMethodEngineBase::CommitText(int context_id,
return false; return false;
} }
ui::IMEBridge::Get()->GetInputContextHandler()->CommitText(text); CommitTextToInputContext(context_id, std::string(text));
// Records histograms for committed characters.
if (!composition_text_->text.empty()) {
size_t len = GetUtf8StringLength(text);
UMA_HISTOGRAM_CUSTOM_COUNTS("InputMethod.CommitLength", len, 1, 25, 25);
composition_text_.reset(new ui::CompositionText());
}
return true; return true;
} }
...@@ -380,6 +351,10 @@ bool InputMethodEngineBase::IsInterestedInKeyEvent() const { ...@@ -380,6 +351,10 @@ bool InputMethodEngineBase::IsInterestedInKeyEvent() const {
void InputMethodEngineBase::ProcessKeyEvent(const ui::KeyEvent& key_event, void InputMethodEngineBase::ProcessKeyEvent(const ui::KeyEvent& key_event,
KeyEventDoneCallback& callback) { KeyEventDoneCallback& callback) {
// Make true that we don't handle IME API calling of setComposition and
// commitText while the extension is handling key event.
handling_key_event_ = true;
KeyboardEvent ext_event; KeyboardEvent ext_event;
GetExtensionKeyboardEventFromKeyEvent(key_event, &ext_event); GetExtensionKeyboardEventFromKeyEvent(key_event, &ext_event);
...@@ -405,6 +380,25 @@ void InputMethodEngineBase::SetSurroundingText(const std::string& text, ...@@ -405,6 +380,25 @@ void InputMethodEngineBase::SetSurroundingText(const std::string& text,
void InputMethodEngineBase::KeyEventHandled(const std::string& extension_id, void InputMethodEngineBase::KeyEventHandled(const std::string& extension_id,
const std::string& request_id, const std::string& request_id,
bool handled) { bool handled) {
handling_key_event_ = false;
// When finish handling key event, take care of the unprocessed setComposition
// and commitText calls.
ui::IMEInputContextHandlerInterface* input_context =
ui::IMEBridge::Get()->GetInputContextHandler();
if (!composition_.text.empty()) {
if (input_context) {
input_context->UpdateCompositionText(
composition_, composition_.selection.start(), true);
}
composition_.Clear();
}
if (!text_.empty()) {
if (input_context) {
input_context->CommitText(text_);
}
text_ = "";
}
RequestMap::iterator request = request_map_.find(request_id); RequestMap::iterator request = request_map_.find(request_id);
if (request == request_map_.end()) { if (request == request_map_.end()) {
LOG(ERROR) << "Request ID not found: " << request_id; LOG(ERROR) << "Request ID not found: " << request_id;
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include <vector> #include <vector>
#include "base/time/time.h" #include "base/time/time.h"
#include "ui/base/ime/chromeos/input_method_descriptor.h" #include "ui/base/ime/chromeos/input_method_descriptor.h"
#include "ui/base/ime/composition_text.h"
#include "ui/base/ime/ime_engine_handler_interface.h" #include "ui/base/ime/ime_engine_handler_interface.h"
#include "url/gurl.h" #include "url/gurl.h"
...@@ -174,7 +175,18 @@ class InputMethodEngineBase : virtual public ui::IMEEngineHandlerInterface { ...@@ -174,7 +175,18 @@ class InputMethodEngineBase : virtual public ui::IMEEngineHandlerInterface {
const std::string& component_id, const std::string& component_id,
ui::IMEEngineHandlerInterface::KeyEventDoneCallback& key_data); ui::IMEEngineHandlerInterface::KeyEventDoneCallback& key_data);
// Called when a key event is handled.
void KeyEventHandled();
protected: protected:
// Notifies InputContextHandler that the composition is changed.
virtual void UpdateComposition(const ui::CompositionText& composition_text,
uint32_t cursor_pos,
bool is_visible) = 0;
// Notifies InputContextHanlder to commit |text|.
virtual void CommitTextToInputContext(int context_id,
const std::string& text) = 0;
ui::TextInputType current_input_type_; ui::TextInputType current_input_type_;
// ID that is used for the current input context. False if there is no focus. // ID that is used for the current input context. False if there is no focus.
...@@ -209,6 +221,16 @@ class InputMethodEngineBase : virtual public ui::IMEEngineHandlerInterface { ...@@ -209,6 +221,16 @@ class InputMethodEngineBase : virtual public ui::IMEEngineHandlerInterface {
unsigned int next_request_id_; unsigned int next_request_id_;
RequestMap request_map_; RequestMap request_map_;
// The composition text to be set from calling input.ime.setComposition API.
ui::CompositionText composition_;
// The text to be committed from calling input.ime.commitText API.
std::string text_;
// Indicates whether the IME extension is currently handling a physical key
// event. This is used in CommitText/UpdateCompositionText/etc.
bool handling_key_event_;
}; };
} // namespace input_method } // namespace input_method
......
...@@ -135,7 +135,7 @@ ...@@ -135,7 +135,7 @@
"name": "setComposition", "name": "setComposition",
"type": "function", "type": "function",
"description": "Set the current composition. If this extension does not own the active IME, this fails.", "description": "Set the current composition. If this extension does not own the active IME, this fails.",
"platforms": ["chromeos"], "platforms": ["chromeos", "win", "linux"],
"parameters": [ "parameters": [
{ {
"name": "parameters", "name": "parameters",
...@@ -235,7 +235,7 @@ ...@@ -235,7 +235,7 @@
"name": "commitText", "name": "commitText",
"type": "function", "type": "function",
"description": "Commits the provided text to the current input.", "description": "Commits the provided text to the current input.",
"platforms": ["chromeos"], "platforms": ["chromeos", "win", "linux"],
"parameters": [ "parameters": [
{ {
"name": "parameters", "name": "parameters",
......
...@@ -7,6 +7,8 @@ ...@@ -7,6 +7,8 @@
#include "base/bind.h" #include "base/bind.h"
#include "base/logging.h" #include "base/logging.h"
#include "base/message_loop/message_loop.h" #include "base/message_loop/message_loop.h"
#include "base/strings/utf_string_conversions.h"
#include "ui/base/ime/ime_bridge.h"
#include "ui/base/ime/input_method_delegate.h" #include "ui/base/ime/input_method_delegate.h"
#include "ui/base/ime/input_method_observer.h" #include "ui/base/ime/input_method_observer.h"
#include "ui/base/ime/text_input_client.h" #include "ui/base/ime/text_input_client.h"
...@@ -15,14 +17,15 @@ ...@@ -15,14 +17,15 @@
namespace ui { namespace ui {
InputMethodBase::InputMethodBase() InputMethodBase::InputMethodBase()
: delegate_(NULL), : delegate_(NULL), text_input_client_(NULL) {}
text_input_client_(NULL) {
}
InputMethodBase::~InputMethodBase() { InputMethodBase::~InputMethodBase() {
FOR_EACH_OBSERVER(InputMethodObserver, FOR_EACH_OBSERVER(InputMethodObserver,
observer_list_, observer_list_,
OnInputMethodDestroyed(this)); OnInputMethodDestroyed(this));
if (ui::IMEBridge::Get() &&
ui::IMEBridge::Get()->GetInputContextHandler() == this)
ui::IMEBridge::Get()->SetInputContextHandler(nullptr);
} }
void InputMethodBase::SetDelegate(internal::InputMethodDelegate* delegate) { void InputMethodBase::SetDelegate(internal::InputMethodDelegate* delegate) {
...@@ -35,6 +38,8 @@ void InputMethodBase::OnBlur() {} ...@@ -35,6 +38,8 @@ void InputMethodBase::OnBlur() {}
void InputMethodBase::SetFocusedTextInputClient(TextInputClient* client) { void InputMethodBase::SetFocusedTextInputClient(TextInputClient* client) {
SetFocusedTextInputClientInternal(client); SetFocusedTextInputClientInternal(client);
if (ui::IMEBridge::Get())
ui::IMEBridge::Get()->SetInputContextHandler(this);
} }
void InputMethodBase::DetachTextInputClient(TextInputClient* client) { void InputMethodBase::DetachTextInputClient(TextInputClient* client) {
...@@ -148,4 +153,41 @@ std::vector<gfx::Rect> InputMethodBase::GetCompositionBounds( ...@@ -148,4 +153,41 @@ std::vector<gfx::Rect> InputMethodBase::GetCompositionBounds(
return bounds; return bounds;
} }
bool InputMethodBase::SendFakeProcessKeyEvent(bool pressed) const {
KeyEvent evt(pressed ? ET_KEY_PRESSED : ET_KEY_RELEASED,
pressed ? VKEY_PROCESSKEY : VKEY_UNKNOWN, EF_IME_FABRICATED_KEY);
ignore_result(DispatchKeyEventPostIME(&evt));
return evt.stopped_propagation();
}
void InputMethodBase::CommitText(const std::string& text) {
if (text.empty() || !GetTextInputClient() || IsTextInputTypeNone())
return;
const base::string16 utf16_text = base::UTF8ToUTF16(text);
if (utf16_text.empty())
return;
if (!SendFakeProcessKeyEvent(true))
GetTextInputClient()->InsertText(utf16_text);
SendFakeProcessKeyEvent(false);
}
void InputMethodBase::UpdateCompositionText(const CompositionText& composition_,
uint32_t cursor_pos,
bool visible) {
if (IsTextInputTypeNone() || composition_.text.empty())
return;
if (!SendFakeProcessKeyEvent(true)) {
if (visible)
GetTextInputClient()->SetCompositionText(composition_);
else
GetTextInputClient()->ClearCompositionText();
}
SendFakeProcessKeyEvent(false);
}
void InputMethodBase::DeleteSurroundingText(int32_t offset, uint32_t length) {}
} // namespace ui } // namespace ui
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include "base/macros.h" #include "base/macros.h"
#include "base/memory/weak_ptr.h" #include "base/memory/weak_ptr.h"
#include "base/observer_list.h" #include "base/observer_list.h"
#include "ui/base/ime/ime_input_context_handler_interface.h"
#include "ui/base/ime/input_method.h" #include "ui/base/ime/input_method.h"
#include "ui/base/ime/ui_base_ime_export.h" #include "ui/base/ime/ui_base_ime_export.h"
#include "ui/events/event_dispatcher.h" #include "ui/events/event_dispatcher.h"
...@@ -29,7 +30,8 @@ class TextInputClient; ...@@ -29,7 +30,8 @@ class TextInputClient;
// implementations. // implementations.
class UI_BASE_IME_EXPORT InputMethodBase class UI_BASE_IME_EXPORT InputMethodBase
: NON_EXPORTED_BASE(public InputMethod), : NON_EXPORTED_BASE(public InputMethod),
public base::SupportsWeakPtr<InputMethodBase> { public base::SupportsWeakPtr<InputMethodBase>,
public IMEInputContextHandlerInterface {
public: public:
InputMethodBase(); InputMethodBase();
~InputMethodBase() override; ~InputMethodBase() override;
...@@ -61,6 +63,17 @@ class UI_BASE_IME_EXPORT InputMethodBase ...@@ -61,6 +63,17 @@ class UI_BASE_IME_EXPORT InputMethodBase
virtual void OnDidChangeFocusedClient(TextInputClient* focused_before, virtual void OnDidChangeFocusedClient(TextInputClient* focused_before,
TextInputClient* focused) {} TextInputClient* focused) {}
// IMEInputContextHandlerInterface:
void CommitText(const std::string& text) override;
void UpdateCompositionText(const CompositionText& text,
uint32_t cursor_pos,
bool visible) override;
void DeleteSurroundingText(int32_t offset, uint32_t length) override;
// Sends a fake key event for IME composing without physical key events.
// Returns true if the faked key event is stopped propagation.
bool SendFakeProcessKeyEvent(bool pressed) const;
// Returns true if |client| is currently focused. // Returns true if |client| is currently focused.
bool IsTextInputClientFocused(const TextInputClient* client); bool IsTextInputClientFocused(const TextInputClient* client);
......
...@@ -439,14 +439,6 @@ bool InputMethodChromeOS::HasInputMethodResult() const { ...@@ -439,14 +439,6 @@ bool InputMethodChromeOS::HasInputMethodResult() const {
return result_text_.length() || composition_changed_; return result_text_.length() || composition_changed_;
} }
bool InputMethodChromeOS::SendFakeProcessKeyEvent(bool pressed) const {
KeyEvent evt(pressed ? ET_KEY_PRESSED : ET_KEY_RELEASED,
pressed ? VKEY_PROCESSKEY : VKEY_UNKNOWN,
EF_IME_FABRICATED_KEY);
ignore_result(DispatchKeyEventPostIME(&evt));
return evt.stopped_propagation();
}
void InputMethodChromeOS::CommitText(const std::string& text) { void InputMethodChromeOS::CommitText(const std::string& text) {
if (text.empty()) if (text.empty())
return; return;
......
...@@ -22,9 +22,7 @@ ...@@ -22,9 +22,7 @@
namespace ui { namespace ui {
// A ui::InputMethod implementation based on IBus. // A ui::InputMethod implementation based on IBus.
class UI_BASE_IME_EXPORT InputMethodChromeOS class UI_BASE_IME_EXPORT InputMethodChromeOS : public InputMethodBase {
: public InputMethodBase,
public ui::IMEInputContextHandlerInterface {
public: public:
explicit InputMethodChromeOS(internal::InputMethodDelegate* delegate); explicit InputMethodChromeOS(internal::InputMethodDelegate* delegate);
~InputMethodChromeOS() override; ~InputMethodChromeOS() override;
...@@ -89,10 +87,6 @@ class UI_BASE_IME_EXPORT InputMethodChromeOS ...@@ -89,10 +87,6 @@ class UI_BASE_IME_EXPORT InputMethodChromeOS
// Checks if there is pending input method result. // Checks if there is pending input method result.
bool HasInputMethodResult() const; bool HasInputMethodResult() const;
// Sends a fake key event for IME composing without physical key events.
// Returns true if the faked key event is stopped propagation.
bool SendFakeProcessKeyEvent(bool pressed) const;
// Passes keyevent and executes character composition if necessary. Returns // Passes keyevent and executes character composition if necessary. Returns
// true if character composer comsumes key event. // true if character composer comsumes key event.
bool ExecuteCharacterComposer(const ui::KeyEvent& event); bool ExecuteCharacterComposer(const ui::KeyEvent& event);
......
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