| OLD | NEW |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/ui/input_method/input_method_engine_base.h" | 5 #include "chrome/browser/ui/input_method/input_method_engine_base.h" |
| 6 | 6 |
| 7 #undef FocusIn | 7 #undef FocusIn |
| 8 #undef FocusOut | 8 #undef FocusOut |
| 9 #undef RootWindow | 9 #undef RootWindow |
| 10 #include <algorithm> | 10 #include <algorithm> |
| (...skipping 29 matching lines...) Expand all Loading... |
| 40 #include "ui/events/keycodes/keyboard_codes_posix.h" | 40 #include "ui/events/keycodes/keyboard_codes_posix.h" |
| 41 #endif | 41 #endif |
| 42 | 42 |
| 43 namespace input_method { | 43 namespace input_method { |
| 44 | 44 |
| 45 namespace { | 45 namespace { |
| 46 | 46 |
| 47 const char kErrorNotActive[] = "IME is not active"; | 47 const char kErrorNotActive[] = "IME is not active"; |
| 48 const char kErrorWrongContext[] = "Context is not active"; | 48 const char kErrorWrongContext[] = "Context is not active"; |
| 49 | 49 |
| 50 // Notifies InputContextHandler that the composition is changed. | |
| 51 void UpdateComposition(const ui::CompositionText& composition_text, | |
| 52 uint32_t cursor_pos, | |
| 53 bool is_visible) { | |
| 54 ui::IMEInputContextHandlerInterface* input_context = | |
| 55 ui::IMEBridge::Get()->GetInputContextHandler(); | |
| 56 if (input_context) | |
| 57 input_context->UpdateCompositionText(composition_text, cursor_pos, | |
| 58 is_visible); | |
| 59 } | |
| 60 | |
| 61 // Returns the length of characters of a UTF-8 string with unknown string | |
| 62 // length. Cannot apply faster algorithm to count characters in an utf-8 | |
| 63 // string without knowing the string length, so just does a full scan. | |
| 64 size_t GetUtf8StringLength(const char* s) { | |
| 65 size_t ret = 0; | |
| 66 while (*s) { | |
| 67 if ((*s & 0xC0) != 0x80) | |
| 68 ret++; | |
| 69 ++s; | |
| 70 } | |
| 71 return ret; | |
| 72 } | |
| 73 | |
| 74 #if defined(OS_CHROMEOS) | 50 #if defined(OS_CHROMEOS) |
| 75 std::string GetKeyFromEvent(const ui::KeyEvent& event) { | 51 std::string GetKeyFromEvent(const ui::KeyEvent& event) { |
| 76 const std::string code = event.GetCodeString(); | 52 const std::string code = event.GetCodeString(); |
| 77 if (base::StartsWith(code, "Control", base::CompareCase::SENSITIVE)) | 53 if (base::StartsWith(code, "Control", base::CompareCase::SENSITIVE)) |
| 78 return "Ctrl"; | 54 return "Ctrl"; |
| 79 if (base::StartsWith(code, "Shift", base::CompareCase::SENSITIVE)) | 55 if (base::StartsWith(code, "Shift", base::CompareCase::SENSITIVE)) |
| 80 return "Shift"; | 56 return "Shift"; |
| 81 if (base::StartsWith(code, "Alt", base::CompareCase::SENSITIVE)) | 57 if (base::StartsWith(code, "Alt", base::CompareCase::SENSITIVE)) |
| 82 return "Alt"; | 58 return "Alt"; |
| 83 if (base::StartsWith(code, "Arrow", base::CompareCase::SENSITIVE)) | 59 if (base::StartsWith(code, "Arrow", base::CompareCase::SENSITIVE)) |
| (...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 174 InputMethodEngineBase::KeyboardEvent::~KeyboardEvent() {} | 150 InputMethodEngineBase::KeyboardEvent::~KeyboardEvent() {} |
| 175 | 151 |
| 176 InputMethodEngineBase::InputMethodEngineBase() | 152 InputMethodEngineBase::InputMethodEngineBase() |
| 177 : current_input_type_(ui::TEXT_INPUT_TYPE_NONE), | 153 : current_input_type_(ui::TEXT_INPUT_TYPE_NONE), |
| 178 context_id_(0), | 154 context_id_(0), |
| 179 next_context_id_(1), | 155 next_context_id_(1), |
| 180 composition_text_(new ui::CompositionText()), | 156 composition_text_(new ui::CompositionText()), |
| 181 composition_cursor_(0), | 157 composition_cursor_(0), |
| 182 sent_key_event_(nullptr), | 158 sent_key_event_(nullptr), |
| 183 profile_(nullptr), | 159 profile_(nullptr), |
| 184 next_request_id_(1) {} | 160 next_request_id_(1), |
| 161 text_(""), |
| 162 handling_key_event_(false) {} |
| 185 | 163 |
| 186 InputMethodEngineBase::~InputMethodEngineBase() {} | 164 InputMethodEngineBase::~InputMethodEngineBase() {} |
| 187 | 165 |
| 188 void InputMethodEngineBase::Initialize( | 166 void InputMethodEngineBase::Initialize( |
| 189 scoped_ptr<InputMethodEngineBase::Observer> observer, | 167 scoped_ptr<InputMethodEngineBase::Observer> observer, |
| 190 const char* extension_id, | 168 const char* extension_id, |
| 191 Profile* profile) { | 169 Profile* profile) { |
| 192 DCHECK(observer) << "Observer must not be null."; | 170 DCHECK(observer) << "Observer must not be null."; |
| 193 | 171 |
| 194 // TODO(komatsu): It is probably better to set observer out of Initialize. | 172 // TODO(komatsu): It is probably better to set observer out of Initialize. |
| (...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 278 if (!IsActive()) { | 256 if (!IsActive()) { |
| 279 // TODO: Commit the text anyways. | 257 // TODO: Commit the text anyways. |
| 280 *error = kErrorNotActive; | 258 *error = kErrorNotActive; |
| 281 return false; | 259 return false; |
| 282 } | 260 } |
| 283 if (context_id != context_id_ || context_id_ == -1) { | 261 if (context_id != context_id_ || context_id_ == -1) { |
| 284 *error = kErrorWrongContext; | 262 *error = kErrorWrongContext; |
| 285 return false; | 263 return false; |
| 286 } | 264 } |
| 287 | 265 |
| 288 ui::IMEBridge::Get()->GetInputContextHandler()->CommitText(text); | 266 CommitTextToInputContext(context_id, std::string(text)); |
| 289 | |
| 290 // Records histograms for committed characters. | |
| 291 if (!composition_text_->text.empty()) { | |
| 292 size_t len = GetUtf8StringLength(text); | |
| 293 UMA_HISTOGRAM_CUSTOM_COUNTS("InputMethod.CommitLength", len, 1, 25, 25); | |
| 294 composition_text_.reset(new ui::CompositionText()); | |
| 295 } | |
| 296 return true; | 267 return true; |
| 297 } | 268 } |
| 298 | 269 |
| 299 bool InputMethodEngineBase::DeleteSurroundingText(int context_id, | 270 bool InputMethodEngineBase::DeleteSurroundingText(int context_id, |
| 300 int offset, | 271 int offset, |
| 301 size_t number_of_chars, | 272 size_t number_of_chars, |
| 302 std::string* error) { | 273 std::string* error) { |
| 303 if (!IsActive()) { | 274 if (!IsActive()) { |
| 304 *error = kErrorNotActive; | 275 *error = kErrorNotActive; |
| 305 return false; | 276 return false; |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 373 composition_text_.reset(new ui::CompositionText()); | 344 composition_text_.reset(new ui::CompositionText()); |
| 374 observer_->OnReset(active_component_id_); | 345 observer_->OnReset(active_component_id_); |
| 375 } | 346 } |
| 376 | 347 |
| 377 bool InputMethodEngineBase::IsInterestedInKeyEvent() const { | 348 bool InputMethodEngineBase::IsInterestedInKeyEvent() const { |
| 378 return observer_->IsInterestedInKeyEvent(); | 349 return observer_->IsInterestedInKeyEvent(); |
| 379 } | 350 } |
| 380 | 351 |
| 381 void InputMethodEngineBase::ProcessKeyEvent(const ui::KeyEvent& key_event, | 352 void InputMethodEngineBase::ProcessKeyEvent(const ui::KeyEvent& key_event, |
| 382 KeyEventDoneCallback& callback) { | 353 KeyEventDoneCallback& callback) { |
| 354 // Make true that we don't handle IME API calling of setComposition and |
| 355 // commitText while the extension is handling key event. |
| 356 handling_key_event_ = true; |
| 357 |
| 383 KeyboardEvent ext_event; | 358 KeyboardEvent ext_event; |
| 384 GetExtensionKeyboardEventFromKeyEvent(key_event, &ext_event); | 359 GetExtensionKeyboardEventFromKeyEvent(key_event, &ext_event); |
| 385 | 360 |
| 386 // If the given key event is equal to the key event sent by | 361 // If the given key event is equal to the key event sent by |
| 387 // SendKeyEvents, this engine ID is propagated to the extension IME. | 362 // SendKeyEvents, this engine ID is propagated to the extension IME. |
| 388 // Note, this check relies on that ui::KeyEvent is propagated as | 363 // Note, this check relies on that ui::KeyEvent is propagated as |
| 389 // reference without copying. | 364 // reference without copying. |
| 390 if (&key_event == sent_key_event_) | 365 if (&key_event == sent_key_event_) |
| 391 ext_event.extension_id = extension_id_; | 366 ext_event.extension_id = extension_id_; |
| 392 | 367 |
| 393 observer_->OnKeyEvent(active_component_id_, ext_event, callback); | 368 observer_->OnKeyEvent(active_component_id_, ext_event, callback); |
| 394 } | 369 } |
| 395 | 370 |
| 396 void InputMethodEngineBase::SetSurroundingText(const std::string& text, | 371 void InputMethodEngineBase::SetSurroundingText(const std::string& text, |
| 397 uint32_t cursor_pos, | 372 uint32_t cursor_pos, |
| 398 uint32_t anchor_pos, | 373 uint32_t anchor_pos, |
| 399 uint32_t offset_pos) { | 374 uint32_t offset_pos) { |
| 400 observer_->OnSurroundingTextChanged( | 375 observer_->OnSurroundingTextChanged( |
| 401 active_component_id_, text, static_cast<int>(cursor_pos), | 376 active_component_id_, text, static_cast<int>(cursor_pos), |
| 402 static_cast<int>(anchor_pos), static_cast<int>(offset_pos)); | 377 static_cast<int>(anchor_pos), static_cast<int>(offset_pos)); |
| 403 } | 378 } |
| 404 | 379 |
| 405 void InputMethodEngineBase::KeyEventHandled(const std::string& extension_id, | 380 void InputMethodEngineBase::KeyEventHandled(const std::string& extension_id, |
| 406 const std::string& request_id, | 381 const std::string& request_id, |
| 407 bool handled) { | 382 bool handled) { |
| 383 handling_key_event_ = false; |
| 384 // When finish handling key event, take care of the unprocessed setComposition |
| 385 // and commitText calls. |
| 386 ui::IMEInputContextHandlerInterface* input_context = |
| 387 ui::IMEBridge::Get()->GetInputContextHandler(); |
| 388 if (!composition_.text.empty()) { |
| 389 if (input_context) { |
| 390 input_context->UpdateCompositionText( |
| 391 composition_, composition_.selection.start(), true); |
| 392 } |
| 393 composition_.Clear(); |
| 394 } |
| 395 if (!text_.empty()) { |
| 396 if (input_context) { |
| 397 input_context->CommitText(text_); |
| 398 } |
| 399 text_ = ""; |
| 400 } |
| 401 |
| 408 RequestMap::iterator request = request_map_.find(request_id); | 402 RequestMap::iterator request = request_map_.find(request_id); |
| 409 if (request == request_map_.end()) { | 403 if (request == request_map_.end()) { |
| 410 LOG(ERROR) << "Request ID not found: " << request_id; | 404 LOG(ERROR) << "Request ID not found: " << request_id; |
| 411 return; | 405 return; |
| 412 } | 406 } |
| 413 | 407 |
| 414 request->second.second.Run(handled); | 408 request->second.second.Run(handled); |
| 415 request_map_.erase(request); | 409 request_map_.erase(request); |
| 416 } | 410 } |
| 417 | 411 |
| 418 std::string InputMethodEngineBase::AddRequest( | 412 std::string InputMethodEngineBase::AddRequest( |
| 419 const std::string& component_id, | 413 const std::string& component_id, |
| 420 ui::IMEEngineHandlerInterface::KeyEventDoneCallback& key_data) { | 414 ui::IMEEngineHandlerInterface::KeyEventDoneCallback& key_data) { |
| 421 std::string request_id = base::IntToString(next_request_id_); | 415 std::string request_id = base::IntToString(next_request_id_); |
| 422 ++next_request_id_; | 416 ++next_request_id_; |
| 423 | 417 |
| 424 request_map_[request_id] = std::make_pair(component_id, key_data); | 418 request_map_[request_id] = std::make_pair(component_id, key_data); |
| 425 | 419 |
| 426 return request_id; | 420 return request_id; |
| 427 } | 421 } |
| 428 | 422 |
| 429 } // namespace input_method | 423 } // namespace input_method |
| OLD | NEW |