OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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_ibus.h" | 5 #include "ui/base/ime/input_method_ibus.h" |
6 | 6 |
7 #include <X11/X.h> | 7 #include <X11/X.h> |
8 #include <X11/Xlib.h> | 8 #include <X11/Xlib.h> |
9 #include <X11/Xutil.h> | 9 #include <X11/Xutil.h> |
10 #undef FocusIn | 10 #undef FocusIn |
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
84 namespace ui { | 84 namespace ui { |
85 | 85 |
86 // InputMethodIBus implementation ----------------------------------------- | 86 // InputMethodIBus implementation ----------------------------------------- |
87 InputMethodIBus::InputMethodIBus( | 87 InputMethodIBus::InputMethodIBus( |
88 internal::InputMethodDelegate* delegate) | 88 internal::InputMethodDelegate* delegate) |
89 : input_context_state_(INPUT_CONTEXT_STOP), | 89 : input_context_state_(INPUT_CONTEXT_STOP), |
90 create_input_context_fail_count_(0), | 90 create_input_context_fail_count_(0), |
91 context_focused_(false), | 91 context_focused_(false), |
92 composing_text_(false), | 92 composing_text_(false), |
93 composition_changed_(false), | 93 composition_changed_(false), |
94 suppress_next_result_(false), | |
95 current_keyevent_id_(0), | 94 current_keyevent_id_(0), |
96 weak_ptr_factory_(this) { | 95 weak_ptr_factory_(this) { |
97 SetDelegate(delegate); | 96 SetDelegate(delegate); |
98 | 97 |
99 // chromeos::IBusDaemonController is not available in case of some testing, | 98 // chromeos::IBusDaemonController is not available in case of some testing, |
100 // e.g. content_browser test can't initialize IBusDaemonController. | 99 // e.g. content_browser test can't initialize IBusDaemonController. |
101 DCHECK(!base::chromeos::IsRunningOnChromeOS() || | 100 DCHECK(!base::chromeos::IsRunningOnChromeOS() || |
102 chromeos::IBusDaemonController::GetInstance()); | 101 chromeos::IBusDaemonController::GetInstance()); |
103 | 102 |
104 if (chromeos::IBusDaemonController::GetInstance()) | 103 if (chromeos::IBusDaemonController::GetInstance()) |
(...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
226 ibus_keyval, | 225 ibus_keyval, |
227 ibus_keycode, | 226 ibus_keycode, |
228 ibus_state); | 227 ibus_state); |
229 | 228 |
230 GetInputContextClient()->ProcessKeyEvent(ibus_keyval, | 229 GetInputContextClient()->ProcessKeyEvent(ibus_keyval, |
231 ibus_keycode, | 230 ibus_keycode, |
232 ibus_state, | 231 ibus_state, |
233 callback, | 232 callback, |
234 base::Bind(callback, false)); | 233 base::Bind(callback, false)); |
235 ++current_keyevent_id_; | 234 ++current_keyevent_id_; |
236 | |
237 // We don't want to suppress the result generated by this key event, but it | |
238 // may cause problem. See comment in ResetContext() method. | |
239 suppress_next_result_ = false; | |
240 return true; | 235 return true; |
241 } | 236 } |
242 | 237 |
243 bool InputMethodIBus::DispatchFabricatedKeyEvent(const ui::KeyEvent& event) { | 238 bool InputMethodIBus::DispatchFabricatedKeyEvent(const ui::KeyEvent& event) { |
244 // TODO(bryeung): The fabricated events should also pass through IME. | 239 // TODO(bryeung): The fabricated events should also pass through IME. |
245 if (event.type() == ET_KEY_PRESSED) { | 240 if (event.type() == ET_KEY_PRESSED) { |
246 ProcessUnfilteredFabricatedKeyPressEvent( | 241 ProcessUnfilteredFabricatedKeyPressEvent( |
247 ET_KEY_PRESSED, event.key_code(), event.flags()); | 242 ET_KEY_PRESSED, event.key_code(), event.flags()); |
248 } else { | 243 } else { |
249 DispatchFabricatedKeyEventPostIME( | 244 DispatchFabricatedKeyEventPostIME( |
(...skipping 172 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
422 | 417 |
423 ResetContext(); | 418 ResetContext(); |
424 } | 419 } |
425 | 420 |
426 void InputMethodIBus::ResetContext() { | 421 void InputMethodIBus::ResetContext() { |
427 if (!context_focused_ || !GetTextInputClient()) | 422 if (!context_focused_ || !GetTextInputClient()) |
428 return; | 423 return; |
429 | 424 |
430 DCHECK(system_toplevel_window_focused()); | 425 DCHECK(system_toplevel_window_focused()); |
431 | 426 |
432 // Because ibus runs in asynchronous mode, the input method may still send us | |
433 // results after sending out the reset request, so we use a flag to discard | |
434 // all results generated by previous key events. But because ibus does not | |
435 // have a mechanism to identify each key event and corresponding results, this | |
436 // approach will not work for some corner cases. For example if the user types | |
437 // very fast, then the next key event may come in before the |context_| is | |
438 // really reset. Then we actually cannot know whether or not the next | |
439 // result should be discard. | |
440 suppress_next_result_ = true; | |
441 | |
442 composition_.Clear(); | 427 composition_.Clear(); |
443 result_text_.clear(); | 428 result_text_.clear(); |
444 composing_text_ = false; | 429 composing_text_ = false; |
445 composition_changed_ = false; | 430 composition_changed_ = false; |
446 | 431 |
447 // We need to abandon all pending key events, but as above comment says, there | 432 // We need to abandon all pending key events, but as above comment says, there |
448 // is no reliable way to abandon all results generated by these abandoned key | 433 // is no reliable way to abandon all results generated by these abandoned key |
449 // events. | 434 // events. |
450 AbandonAllPendingKeyEvents(); | 435 AbandonAllPendingKeyEvents(); |
451 | 436 |
(...skipping 208 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
660 DispatchFabricatedKeyEventPostIME(pressed ? ET_KEY_PRESSED : ET_KEY_RELEASED, | 645 DispatchFabricatedKeyEventPostIME(pressed ? ET_KEY_PRESSED : ET_KEY_RELEASED, |
661 VKEY_PROCESSKEY, | 646 VKEY_PROCESSKEY, |
662 0); | 647 0); |
663 } | 648 } |
664 | 649 |
665 void InputMethodIBus::AbandonAllPendingKeyEvents() { | 650 void InputMethodIBus::AbandonAllPendingKeyEvents() { |
666 pending_key_events_.clear(); | 651 pending_key_events_.clear(); |
667 } | 652 } |
668 | 653 |
669 void InputMethodIBus::CommitText(const chromeos::IBusText& text) { | 654 void InputMethodIBus::CommitText(const chromeos::IBusText& text) { |
670 if (suppress_next_result_ || text.text().empty()) | 655 if (text.text().empty()) |
671 return; | 656 return; |
672 | 657 |
673 // We need to receive input method result even if the text input type is | 658 // We need to receive input method result even if the text input type is |
674 // TEXT_INPUT_TYPE_NONE, to make sure we can always send correct | 659 // TEXT_INPUT_TYPE_NONE, to make sure we can always send correct |
675 // character for each key event to the focused text input client. | 660 // character for each key event to the focused text input client. |
676 if (!GetTextInputClient()) | 661 if (!GetTextInputClient()) |
677 return; | 662 return; |
678 | 663 |
679 const string16 utf16_text = UTF8ToUTF16(text.text()); | 664 const string16 utf16_text = UTF8ToUTF16(text.text()); |
680 if (utf16_text.empty()) | 665 if (utf16_text.empty()) |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
712 // results. | 697 // results. |
713 if (event_type == ET_KEY_PRESSED) { | 698 if (event_type == ET_KEY_PRESSED) { |
714 ProcessUnfilteredFabricatedKeyPressEvent(event_type, ui_key_code, | 699 ProcessUnfilteredFabricatedKeyPressEvent(event_type, ui_key_code, |
715 event_flags); | 700 event_flags); |
716 } else { | 701 } else { |
717 DispatchFabricatedKeyEventPostIME(event_type, ui_key_code, event_flags); | 702 DispatchFabricatedKeyEventPostIME(event_type, ui_key_code, event_flags); |
718 } | 703 } |
719 } | 704 } |
720 | 705 |
721 void InputMethodIBus::ShowPreeditText() { | 706 void InputMethodIBus::ShowPreeditText() { |
722 if (suppress_next_result_ || IsTextInputTypeNone()) | 707 if (IsTextInputTypeNone()) |
723 return; | 708 return; |
724 | 709 |
725 composing_text_ = true; | 710 composing_text_ = true; |
726 } | 711 } |
727 | 712 |
728 void InputMethodIBus::UpdatePreeditText(const chromeos::IBusText& text, | 713 void InputMethodIBus::UpdatePreeditText(const chromeos::IBusText& text, |
729 uint32 cursor_pos, | 714 uint32 cursor_pos, |
730 bool visible) { | 715 bool visible) { |
731 if (suppress_next_result_ || IsTextInputTypeNone()) | 716 if (IsTextInputTypeNone()) |
732 return; | 717 return; |
733 | 718 |
734 // |visible| argument is very confusing. For example, what's the correct | 719 // |visible| argument is very confusing. For example, what's the correct |
735 // behavior when: | 720 // behavior when: |
736 // 1. OnUpdatePreeditText() is called with a text and visible == false, then | 721 // 1. OnUpdatePreeditText() is called with a text and visible == false, then |
737 // 2. OnShowPreeditText() is called afterwards. | 722 // 2. OnShowPreeditText() is called afterwards. |
738 // | 723 // |
739 // If it's only for clearing the current preedit text, then why not just use | 724 // If it's only for clearing the current preedit text, then why not just use |
740 // OnHidePreeditText()? | 725 // OnHidePreeditText()? |
741 if (!visible) { | 726 if (!visible) { |
(...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
853 } | 838 } |
854 | 839 |
855 bool InputMethodIBus::ExecuteCharacterComposer(uint32 ibus_keyval, | 840 bool InputMethodIBus::ExecuteCharacterComposer(uint32 ibus_keyval, |
856 uint32 ibus_keycode, | 841 uint32 ibus_keycode, |
857 uint32 ibus_state) { | 842 uint32 ibus_state) { |
858 bool consumed = character_composer_.FilterKeyPress( | 843 bool consumed = character_composer_.FilterKeyPress( |
859 ibus_keyval, | 844 ibus_keyval, |
860 ibus_keycode, | 845 ibus_keycode, |
861 EventFlagsFromXState(ibus_state)); | 846 EventFlagsFromXState(ibus_state)); |
862 | 847 |
863 suppress_next_result_ = false; | |
864 chromeos::IBusText preedit; | 848 chromeos::IBusText preedit; |
865 preedit.set_text( | 849 preedit.set_text( |
866 UTF16ToUTF8(character_composer_.preedit_string())); | 850 UTF16ToUTF8(character_composer_.preedit_string())); |
867 UpdatePreeditText(preedit, preedit.text().size(), | 851 UpdatePreeditText(preedit, preedit.text().size(), |
868 !preedit.text().empty()); | 852 !preedit.text().empty()); |
869 std::string commit_text = | 853 std::string commit_text = |
870 UTF16ToUTF8(character_composer_.composed_character()); | 854 UTF16ToUTF8(character_composer_.composed_character()); |
871 if (!commit_text.empty()) { | 855 if (!commit_text.empty()) { |
872 chromeos::IBusText ibus_text; | 856 chromeos::IBusText ibus_text; |
873 ibus_text.set_text(commit_text); | 857 ibus_text.set_text(commit_text); |
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
969 } | 953 } |
970 | 954 |
971 // Use a black thin underline by default. | 955 // Use a black thin underline by default. |
972 if (out_composition->underlines.empty()) { | 956 if (out_composition->underlines.empty()) { |
973 out_composition->underlines.push_back(CompositionUnderline( | 957 out_composition->underlines.push_back(CompositionUnderline( |
974 0, length, SK_ColorBLACK, false /* thick */)); | 958 0, length, SK_ColorBLACK, false /* thick */)); |
975 } | 959 } |
976 } | 960 } |
977 | 961 |
978 } // namespace ui | 962 } // namespace ui |
OLD | NEW |