Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(853)

Side by Side Diff: ui/base/ime/input_method_chromeos.cc

Issue 2957173004: Make DispatchKeyEventPostIME() asynchronous.
Patch Set: cleanup. Created 3 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698