Commit 9c8e3f4a authored by Yuichiro Hanada's avatar Yuichiro Hanada Committed by Commit Bot

Send control characters as a KeyEvent.

Android IMEs can call CommitText() with control characters, but
InputMethodEngine::CommitText expects only text characters.
This CL adds IsControlChar() and SendControlKeyEvent() to send those
control characters as a KeyEvent.

Bug: 845079
Test: Omnibox works with Gboard.
Change-Id: I6d3dadb3879ada22993b9b5a330e08c634521380
Reviewed-on: https://chromium-review.googlesource.com/c/1275465
Commit-Queue: Yuichiro Hanada <yhanada@chromium.org>
Reviewed-by: default avatarYusuke Sato <yusukes@chromium.org>
Cr-Commit-Position: refs/heads/master@{#598704}
parent 625d9984
......@@ -159,9 +159,23 @@ class TestIMEInputContextHandler : public ui::MockIMEInputContextHandler {
ui::InputMethod* GetInputMethod() override { return input_method_; }
void SendKeyEvent(ui::KeyEvent* event) override {
ui::MockIMEInputContextHandler::SendKeyEvent(event);
++send_key_event_call_count_;
}
void Reset() {
ui::MockIMEInputContextHandler::Reset();
send_key_event_call_count_ = 0;
}
int send_key_event_call_count() const { return send_key_event_call_count_; }
private:
ui::InputMethod* const input_method_;
int send_key_event_call_count_ = 0;
DISALLOW_COPY_AND_ASSIGN(TestIMEInputContextHandler);
};
......@@ -757,6 +771,13 @@ TEST_F(ArcInputMethodManagerServiceTest, IMEOperations) {
EXPECT_EQ(1, bridge()->update_text_input_state_calls_count_);
EXPECT_TRUE(bridge()->last_text_input_state->first_update_after_operation);
// Calling CommitText() with '\n' doesn't invoke
// InputMethodEngine::CommitText.
EXPECT_EQ(0, test_context_handler.send_key_event_call_count());
connection->CommitText(base::ASCIIToUTF16("\n"), 0);
EXPECT_EQ(1, test_context_handler.commit_text_call_count());
EXPECT_EQ(2, test_context_handler.send_key_event_call_count());
test_context_handler.Reset();
connection->DeleteSurroundingText(1, 1);
EXPECT_EQ(1, test_context_handler.delete_surrounding_text_call_count());
......
......@@ -4,9 +4,12 @@
#include "chrome/browser/chromeos/arc/input_method_manager/input_connection_impl.h"
#include <tuple>
#include "base/strings/utf_string_conversions.h"
#include "base/threading/thread_task_runner_handle.h"
#include "ui/base/ime/ime_bridge.h"
#include "ui/events/keycodes/keyboard_codes.h"
namespace arc {
......@@ -20,6 +23,22 @@ namespace {
// send the current text input state right after the IME operation completion.
constexpr base::TimeDelta kStateUpdateTimeout = base::TimeDelta::FromSeconds(1);
// Characters which should be sent as a KeyEvent and attributes of generated
// KeyEvent.
constexpr std::tuple<char, ui::KeyboardCode, const char*>
kControlCharToKeyEvent[] = {{'\n', ui::VKEY_RETURN, "Enter"}};
bool IsControlChar(const base::string16& text) {
const std::string str = base::UTF16ToUTF8(text);
if (str.length() != 1)
return false;
for (const auto& t : kControlCharToKeyEvent) {
if (str[0] == std::get<0>(t))
return true;
}
return false;
}
} // namespace
InputConnectionImpl::InputConnectionImpl(
......@@ -80,6 +99,12 @@ void InputConnectionImpl::CommitText(const base::string16& text,
// Clear the current composing text at first.
if (!ime_engine_->ClearComposition(input_context_id_, &error))
LOG(ERROR) << "ClearComposition failed: error=\"" << error << "\"";
if (IsControlChar(text)) {
SendControlKeyEvent(text);
return;
}
if (!ime_engine_->CommitText(input_context_id_,
base::UTF16ToUTF8(text).c_str(), &error))
LOG(ERROR) << "CommitText failed: error=\"" << error << "\"";
......@@ -164,4 +189,25 @@ void InputConnectionImpl::StartStateUpdateTimer() {
true /* is_input_state_update_requested */));
}
void InputConnectionImpl::SendControlKeyEvent(const base::string16& text) {
DCHECK(IsControlChar(text));
const std::string str = base::UTF16ToUTF8(text);
DCHECK_EQ(1u, str.length());
for (const auto& t : kControlCharToKeyEvent) {
if (std::get<0>(t) == str[0]) {
chromeos::InputMethodEngine::KeyboardEvent press;
press.type = "keydown";
press.key_code = std::get<1>(t);
press.key = press.code = std::get<2>(t);
chromeos::InputMethodEngine::KeyboardEvent release(press);
release.type = "keyup";
ime_engine_->SendKeyEvents(input_context_id_, {press, release});
break;
}
}
return;
}
} // namespace arc
......@@ -55,6 +55,8 @@ class InputConnectionImpl : public mojom::InputConnection {
// starting timer is after API call, the timer won't be cancelled.
void StartStateUpdateTimer();
void SendControlKeyEvent(const base::string16& text);
chromeos::InputMethodEngine* const ime_engine_; // Not owned
ArcInputMethodManagerBridge* const imm_bridge_; // Not owned
const int input_context_id_;
......
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