Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 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 "ui/base/ime/input_method_chromeos.h" | 5 #include "ui/base/ime/input_method_chromeos.h" |
| 6 | 6 |
| 7 #include <stddef.h> | 7 #include <stddef.h> |
| 8 | 8 |
| 9 #include <algorithm> | 9 #include <algorithm> |
| 10 #include <cstring> | 10 #include <cstring> |
| 11 #include <set> | 11 #include <set> |
| 12 #include <vector> | 12 #include <vector> |
| 13 | 13 |
| 14 #include "base/bind.h" | 14 #include "base/bind.h" |
| 15 #include "base/i18n/char_iterator.h" | 15 #include "base/i18n/char_iterator.h" |
| 16 #include "base/logging.h" | 16 #include "base/logging.h" |
| 17 #include "base/memory/ptr_util.h" | |
| 17 #include "base/strings/string_util.h" | 18 #include "base/strings/string_util.h" |
| 18 #include "base/strings/utf_string_conversions.h" | 19 #include "base/strings/utf_string_conversions.h" |
| 19 #include "base/third_party/icu/icu_utf.h" | 20 #include "base/third_party/icu/icu_utf.h" |
| 20 #include "chromeos/system/devicemode.h" | 21 #include "chromeos/system/devicemode.h" |
| 21 #include "ui/base/ime/chromeos/ime_keyboard.h" | 22 #include "ui/base/ime/chromeos/ime_keyboard.h" |
| 22 #include "ui/base/ime/chromeos/input_method_manager.h" | 23 #include "ui/base/ime/chromeos/input_method_manager.h" |
| 23 #include "ui/base/ime/composition_text.h" | 24 #include "ui/base/ime/composition_text.h" |
| 24 #include "ui/base/ime/ime_bridge.h" | 25 #include "ui/base/ime/ime_bridge.h" |
| 25 #include "ui/base/ime/ime_engine_handler_interface.h" | 26 #include "ui/base/ime/ime_engine_handler_interface.h" |
| 27 #include "ui/base/ime/input_method_delegate.h" | |
| 26 #include "ui/base/ime/text_input_client.h" | 28 #include "ui/base/ime/text_input_client.h" |
| 27 #include "ui/events/event.h" | 29 #include "ui/events/event.h" |
| 28 #include "ui/gfx/geometry/rect.h" | 30 #include "ui/gfx/geometry/rect.h" |
| 29 | 31 |
| 30 namespace { | 32 namespace { |
| 31 ui::IMEEngineHandlerInterface* GetEngine() { | 33 ui::IMEEngineHandlerInterface* GetEngine() { |
| 32 return ui::IMEBridge::Get()->GetCurrentEngineHandler(); | 34 return ui::IMEBridge::Get()->GetCurrentEngineHandler(); |
| 33 } | 35 } |
| 34 } // namespace | 36 } // namespace |
| 35 | 37 |
| (...skipping 30 matching lines...) Expand all Loading... | |
| 66 // The Caps Lock toggling has been removed from here, because now it is | 68 // The Caps Lock toggling has been removed from here, because now it is |
| 67 // handled in accelerator controller. | 69 // handled in accelerator controller. |
| 68 // (see https://bugs.chromium.org/p/chromium/issues/detail?id=700705). | 70 // (see https://bugs.chromium.org/p/chromium/issues/detail?id=700705). |
| 69 | 71 |
| 70 // If |context_| is not usable, then we can only dispatch the key event as is. | 72 // If |context_| is not usable, then we can only dispatch the key event as is. |
| 71 // We only dispatch the key event to input method when the |context_| is an | 73 // We only dispatch the key event to input method when the |context_| is an |
| 72 // normal input field (not a password field). | 74 // normal input field (not a password field). |
| 73 // Note: We need to send the key event to ibus even if the |context_| is not | 75 // Note: We need to send the key event to ibus even if the |context_| is not |
| 74 // enabled, so that ibus can have a chance to enable the |context_|. | 76 // enabled, so that ibus can have a chance to enable the |context_|. |
| 75 if (!IsNonPasswordInputFieldFocused() || !GetEngine()) { | 77 if (!IsNonPasswordInputFieldFocused() || !GetEngine()) { |
| 76 ui::EventDispatchDetails dispatch_details; | |
| 77 if (event->type() == ET_KEY_PRESSED) { | 78 if (event->type() == ET_KEY_PRESSED) { |
| 78 if (ExecuteCharacterComposer(*event)) { | 79 if (ExecuteCharacterComposer(*event)) { |
| 79 // Treating as PostIME event if character composer handles key event and | 80 // Treating as PostIME event if character composer handles key event and |
| 80 // generates some IME event, | 81 // generates some IME event, |
| 81 dispatch_details = ProcessKeyEventPostIME(event, true); | 82 return ProcessKeyEventPostIME(event, std::move(ack_callback), false, |
| 82 if (ack_callback) | 83 true); |
| 83 ack_callback->Run(true); | |
| 84 return dispatch_details; | |
| 85 } | 84 } |
| 86 dispatch_details = ProcessUnfilteredKeyPressEvent(event); | 85 return ProcessUnfilteredKeyPressEvent(event, std::move(ack_callback)); |
| 87 } else { | |
| 88 dispatch_details = DispatchKeyEventPostIME(event); | |
| 89 } | 86 } |
| 90 if (ack_callback) | 87 return DispatchKeyEventPostIME(event, std::move(ack_callback)); |
| 91 ack_callback->Run(false); | |
| 92 return dispatch_details; | |
| 93 } | 88 } |
| 94 | 89 |
| 95 handling_key_event_ = true; | 90 handling_key_event_ = true; |
| 96 if (GetEngine()->IsInterestedInKeyEvent()) { | 91 if (GetEngine()->IsInterestedInKeyEvent()) { |
| 97 ui::IMEEngineHandlerInterface::KeyEventDoneCallback callback = base::Bind( | 92 ui::IMEEngineHandlerInterface::KeyEventDoneCallback callback = base::Bind( |
| 98 &InputMethodChromeOS::KeyEventDoneCallback, | 93 &InputMethodChromeOS::KeyEventDoneCallback, |
| 99 weak_ptr_factory_.GetWeakPtr(), | 94 weak_ptr_factory_.GetWeakPtr(), |
| 100 // Pass the ownership of the new copied event. | 95 // Pass the ownership of the new copied event. |
| 101 base::Owned(new ui::KeyEvent(*event)), Passed(&ack_callback)); | 96 base::Owned(new ui::KeyEvent(*event)), Passed(&ack_callback)); |
| 102 GetEngine()->ProcessKeyEvent(*event, callback); | 97 GetEngine()->ProcessKeyEvent(*event, callback); |
| (...skipping 27 matching lines...) Expand all Loading... | |
| 130 // IME event has a priority to be handled, so that character composer | 125 // IME event has a priority to be handled, so that character composer |
| 131 // should be reset. | 126 // should be reset. |
| 132 character_composer_.Reset(); | 127 character_composer_.Reset(); |
| 133 } else { | 128 } else { |
| 134 // If IME does not handle key event, passes keyevent to character composer | 129 // If IME does not handle key event, passes keyevent to character composer |
| 135 // to be able to compose complex characters. | 130 // to be able to compose complex characters. |
| 136 is_handled = ExecuteCharacterComposer(*event); | 131 is_handled = ExecuteCharacterComposer(*event); |
| 137 } | 132 } |
| 138 } | 133 } |
| 139 | 134 |
| 140 if (ack_callback) | 135 ui::EventDispatchDetails details = |
| 141 ack_callback->Run(is_handled); | 136 ProcessKeyEventPostIME(event, std::move(ack_callback), false, is_handled); |
|
Shu Chen
2017/07/07 01:01:11
Here removes the original checks:
if (event->typ
| |
| 142 | |
| 143 ui::EventDispatchDetails details; | |
| 144 if (event->type() == ET_KEY_PRESSED || event->type() == ET_KEY_RELEASED) | |
| 145 details = ProcessKeyEventPostIME(event, is_handled); | |
| 146 | |
| 147 handling_key_event_ = false; | 137 handling_key_event_ = false; |
| 148 return details; | 138 return details; |
| 149 } | 139 } |
| 150 | 140 |
| 151 ui::EventDispatchDetails InputMethodChromeOS::DispatchKeyEvent( | 141 ui::EventDispatchDetails InputMethodChromeOS::DispatchKeyEvent( |
| 152 ui::KeyEvent* event) { | 142 ui::KeyEvent* event) { |
| 153 return DispatchKeyEvent(event, nullptr); | 143 return DispatchKeyEvent(event, nullptr); |
| 154 } | 144 } |
| 155 | 145 |
| 156 void InputMethodChromeOS::OnTextInputTypeChanged( | 146 void InputMethodChromeOS::OnTextInputTypeChanged( |
| (...skipping 161 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 318 ui::IMEEngineHandlerInterface::InputContext context( | 308 ui::IMEEngineHandlerInterface::InputContext context( |
| 319 GetTextInputType(), GetTextInputMode(), GetTextInputFlags()); | 309 GetTextInputType(), GetTextInputMode(), GetTextInputFlags()); |
| 320 ui::IMEBridge::Get()->SetCurrentInputContext(context); | 310 ui::IMEBridge::Get()->SetCurrentInputContext(context); |
| 321 | 311 |
| 322 if (!IsTextInputTypeNone()) | 312 if (!IsTextInputTypeNone()) |
| 323 OnCaretBoundsChanged(GetTextInputClient()); | 313 OnCaretBoundsChanged(GetTextInputClient()); |
| 324 } | 314 } |
| 325 | 315 |
| 326 ui::EventDispatchDetails InputMethodChromeOS::ProcessKeyEventPostIME( | 316 ui::EventDispatchDetails InputMethodChromeOS::ProcessKeyEventPostIME( |
| 327 ui::KeyEvent* event, | 317 ui::KeyEvent* event, |
| 318 std::unique_ptr<AckCallback> ack_callback, | |
| 319 bool skip_process_filtered, | |
| 328 bool handled) { | 320 bool handled) { |
| 329 TextInputClient* client = GetTextInputClient(); | 321 TextInputClient* client = GetTextInputClient(); |
| 330 if (!client) { | 322 if (!client) { |
| 331 // As ibus works asynchronously, there is a chance that the focused client | 323 // As ibus works asynchronously, there is a chance that the focused client |
| 332 // loses focus before this method gets called. | 324 // loses focus before this method gets called. |
| 333 return DispatchKeyEventPostIME(event); | 325 return DispatchKeyEventPostIME(event, std::move(ack_callback)); |
| 334 } | 326 } |
| 335 | 327 |
| 336 ui::EventDispatchDetails dispatch_details; | 328 ui::EventDispatchDetails dispatch_details; |
| 337 if (event->type() == ET_KEY_PRESSED && handled) { | 329 if (event->type() == ET_KEY_PRESSED && handled && !skip_process_filtered) |
| 338 dispatch_details = ProcessFilteredKeyPressEvent(event); | 330 return ProcessFilteredKeyPressEvent(event, std::move(ack_callback)); |
|
Shu Chen
2017/07/07 01:24:26
Is this a potential dead loop?
ProcessFilteredKey
| |
| 339 if (event->stopped_propagation()) { | |
| 340 ResetContext(); | |
| 341 return dispatch_details; | |
| 342 } | |
| 343 if (dispatch_details.dispatcher_destroyed || | |
| 344 dispatch_details.target_destroyed) | |
| 345 return dispatch_details; | |
| 346 } | |
| 347 | 331 |
| 348 // In case the focus was changed by the key event. The |context_| should have | 332 // In case the focus was changed by the key event. The |context_| should have |
| 349 // been reset when the focused window changed. | 333 // been reset when the focused window changed. |
| 350 if (client != GetTextInputClient()) | 334 if (client != GetTextInputClient()) { |
| 351 return dispatch_details; | 335 if (ack_callback) |
| 336 ack_callback->Run(false); | |
| 337 return ui::EventDispatchDetails(); | |
| 338 } | |
| 352 | 339 |
| 353 if (HasInputMethodResult()) | 340 if (HasInputMethodResult()) |
| 354 ProcessInputMethodResult(event, handled); | 341 ProcessInputMethodResult(event, handled); |
| 355 | 342 |
| 356 // In case the focus was changed when sending input method results to the | 343 // In case the focus was changed when sending input method results to the |
| 357 // focused window. | 344 // focused window. |
| 358 if (client != GetTextInputClient()) | 345 if (client != GetTextInputClient()) { |
| 359 return dispatch_details; | 346 if (ack_callback) |
| 347 ack_callback->Run(false); | |
| 348 return ui::EventDispatchDetails(); | |
| 349 } | |
| 360 | 350 |
| 361 if (handled) | 351 if (handled) { |
| 362 return dispatch_details; // IME handled the key event. do not forward. | 352 if (ack_callback) |
| 353 ack_callback->Run(true); | |
| 354 return ui::EventDispatchDetails(); // IME handled the key event. do not | |
| 355 // forward. | |
| 356 } | |
| 363 | 357 |
| 364 if (event->type() == ET_KEY_PRESSED) | 358 if (event->type() == ET_KEY_PRESSED) |
| 365 return ProcessUnfilteredKeyPressEvent(event); | 359 return ProcessUnfilteredKeyPressEvent(event, std::move(ack_callback)); |
| 366 | 360 |
| 367 if (event->type() == ET_KEY_RELEASED) | 361 return DispatchKeyEventPostIME(event, std::move(ack_callback)); |
| 368 return DispatchKeyEventPostIME(event); | 362 } |
| 369 | 363 |
| 370 return dispatch_details; | 364 ui::EventDispatchDetails InputMethodChromeOS::DispatchKeyEventPostIME( |
| 365 ui::KeyEvent* event, | |
| 366 std::unique_ptr<AckCallback> ack_callback) const { | |
| 367 if (delegate_) | |
| 368 return delegate_->DispatchKeyEventPostIME(event, std::move(ack_callback)); | |
| 369 if (ack_callback) | |
| 370 ack_callback->Run(false); | |
| 371 return ui::EventDispatchDetails(); | |
| 371 } | 372 } |
| 372 | 373 |
| 373 ui::EventDispatchDetails InputMethodChromeOS::ProcessFilteredKeyPressEvent( | 374 ui::EventDispatchDetails InputMethodChromeOS::ProcessFilteredKeyPressEvent( |
| 374 ui::KeyEvent* event) { | 375 ui::KeyEvent* event, |
| 376 std::unique_ptr<AckCallback> ack_callback) { | |
| 377 auto callback = base::MakeUnique<AckCallback>(base::Bind( | |
| 378 &InputMethodChromeOS::PostProcessFilteredKeyPressEvent, | |
| 379 weak_ptr_factory_.GetWeakPtr(), base::Owned(new ui::KeyEvent(*event)), | |
| 380 GetTextInputClient(), Passed(&ack_callback))); | |
| 381 | |
| 375 if (NeedInsertChar()) | 382 if (NeedInsertChar()) |
| 376 return DispatchKeyEventPostIME(event); | 383 return DispatchKeyEventPostIME(event, std::move(callback)); |
| 377 | 384 |
| 378 ui::KeyEvent fabricated_event(ET_KEY_PRESSED, | 385 ui::KeyEvent fabricated_event(ET_KEY_PRESSED, |
| 379 VKEY_PROCESSKEY, | 386 VKEY_PROCESSKEY, |
| 380 event->code(), | 387 event->code(), |
| 381 event->flags(), | 388 event->flags(), |
| 382 event->GetDomKey(), | 389 event->GetDomKey(), |
| 383 event->time_stamp()); | 390 event->time_stamp()); |
| 384 ui::EventDispatchDetails dispatch_details = | 391 return DispatchKeyEventPostIME(&fabricated_event, std::move(callback)); |
|
Shu Chen
2017/07/07 01:01:11
Here skip the call to event->StopPropagation(), is
| |
| 385 DispatchKeyEventPostIME(&fabricated_event); | 392 } |
| 386 if (fabricated_event.stopped_propagation()) | 393 |
| 387 event->StopPropagation(); | 394 void InputMethodChromeOS::PostProcessFilteredKeyPressEvent( |
| 388 return dispatch_details; | 395 ui::KeyEvent* event, |
| 396 TextInputClient* prev_client, | |
| 397 std::unique_ptr<AckCallback> ack_callback, | |
| 398 bool stopped_propagation) { | |
| 399 // In case the focus was changed by the key event. | |
| 400 if (GetTextInputClient() != prev_client) | |
| 401 return; | |
| 402 | |
| 403 if (stopped_propagation) { | |
| 404 ResetContext(); | |
| 405 if (ack_callback) | |
| 406 ack_callback->Run(true); | |
| 407 return; | |
| 408 } | |
| 409 ignore_result( | |
| 410 ProcessKeyEventPostIME(event, std::move(ack_callback), true, true)); | |
| 389 } | 411 } |
| 390 | 412 |
| 391 ui::EventDispatchDetails InputMethodChromeOS::ProcessUnfilteredKeyPressEvent( | 413 ui::EventDispatchDetails InputMethodChromeOS::ProcessUnfilteredKeyPressEvent( |
| 392 ui::KeyEvent* event) { | 414 ui::KeyEvent* event, |
| 393 const TextInputClient* prev_client = GetTextInputClient(); | 415 std::unique_ptr<AckCallback> ack_callback) { |
| 394 ui::EventDispatchDetails dispatch_details = DispatchKeyEventPostIME(event); | 416 return DispatchKeyEventPostIME( |
| 395 if (event->stopped_propagation()) { | 417 event, |
| 418 base::MakeUnique<AckCallback>(base::Bind( | |
| 419 &InputMethodChromeOS::PostProcessUnfilteredKeyPressEvent, | |
| 420 weak_ptr_factory_.GetWeakPtr(), base::Owned(new ui::KeyEvent(*event)), | |
| 421 GetTextInputClient(), Passed(&ack_callback)))); | |
| 422 } | |
| 423 | |
| 424 void InputMethodChromeOS::PostProcessUnfilteredKeyPressEvent( | |
| 425 ui::KeyEvent* event, | |
| 426 TextInputClient* prev_client, | |
| 427 std::unique_ptr<AckCallback> ack_callback, | |
| 428 bool stopped_propagation) { | |
| 429 if (stopped_propagation) { | |
| 396 ResetContext(); | 430 ResetContext(); |
| 397 return dispatch_details; | 431 if (ack_callback) |
| 432 ack_callback->Run(false); | |
| 433 return; | |
| 398 } | 434 } |
| 399 | 435 |
| 400 // We shouldn't dispatch the character anymore if the key event dispatch | 436 // We shouldn't dispatch the character anymore if the key event dispatch |
| 401 // caused focus change. For example, in the following scenario, | 437 // caused focus change. For example, in the following scenario, |
| 402 // 1. visit a web page which has a <textarea>. | 438 // 1. visit a web page which has a <textarea>. |
| 403 // 2. click Omnibox. | 439 // 2. click Omnibox. |
| 404 // 3. enable Korean IME, press A, then press Tab to move the focus to the web | 440 // 3. enable Korean IME, press A, then press Tab to move the focus to the web |
| 405 // page. | 441 // page. |
| 406 // We should return here not to send the Tab key event to RWHV. | 442 // We should return here not to send the Tab key event to RWHV. |
| 407 TextInputClient* client = GetTextInputClient(); | 443 TextInputClient* client = GetTextInputClient(); |
| 408 if (!client || client != prev_client) | 444 if (!client || client != prev_client) { |
| 409 return dispatch_details; | 445 if (ack_callback) |
| 446 ack_callback->Run(false); | |
| 447 return; | |
| 448 } | |
| 410 | 449 |
| 411 // If a key event was not filtered by |context_| and |character_composer_|, | 450 // If a key event was not filtered by |context_| and |character_composer_|, |
| 412 // then it means the key event didn't generate any result text. So we need | 451 // then it means the key event didn't generate any result text. So we need |
| 413 // to send corresponding character to the focused text input client. | 452 // to send corresponding character to the focused text input client. |
| 414 uint16_t ch = event->GetCharacter(); | 453 uint16_t ch = event->GetCharacter(); |
| 415 if (ch) | 454 if (ch) |
| 416 client->InsertChar(*event); | 455 client->InsertChar(*event); |
| 417 return dispatch_details; | 456 |
| 457 if (ack_callback) | |
| 458 ack_callback->Run(false); | |
| 418 } | 459 } |
| 419 | 460 |
| 420 void InputMethodChromeOS::ProcessInputMethodResult(ui::KeyEvent* event, | 461 void InputMethodChromeOS::ProcessInputMethodResult(ui::KeyEvent* event, |
| 421 bool handled) { | 462 bool handled) { |
| 422 TextInputClient* client = GetTextInputClient(); | 463 TextInputClient* client = GetTextInputClient(); |
| 423 DCHECK(client); | 464 DCHECK(client); |
| 424 | 465 |
| 425 if (result_text_.length()) { | 466 if (result_text_.length()) { |
| 426 if (handled && NeedInsertChar()) { | 467 if (handled && NeedInsertChar()) { |
| 427 for (base::string16::const_iterator i = result_text_.begin(); | 468 for (base::string16::const_iterator i = result_text_.begin(); |
| (...skipping 232 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 660 bool InputMethodChromeOS::IsNonPasswordInputFieldFocused() { | 701 bool InputMethodChromeOS::IsNonPasswordInputFieldFocused() { |
| 661 TextInputType type = GetTextInputType(); | 702 TextInputType type = GetTextInputType(); |
| 662 return (type != TEXT_INPUT_TYPE_NONE) && (type != TEXT_INPUT_TYPE_PASSWORD); | 703 return (type != TEXT_INPUT_TYPE_NONE) && (type != TEXT_INPUT_TYPE_PASSWORD); |
| 663 } | 704 } |
| 664 | 705 |
| 665 bool InputMethodChromeOS::IsInputFieldFocused() { | 706 bool InputMethodChromeOS::IsInputFieldFocused() { |
| 666 return GetTextInputType() != TEXT_INPUT_TYPE_NONE; | 707 return GetTextInputType() != TEXT_INPUT_TYPE_NONE; |
| 667 } | 708 } |
| 668 | 709 |
| 669 } // namespace ui | 710 } // namespace ui |
| OLD | NEW |