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 |