Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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/chromeos/input_method/input_method_manager.h" | 5 #include "chrome/browser/chromeos/input_method/input_method_manager.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 | 8 |
| 9 #include <glib.h> | 9 #include <glib.h> |
| 10 | 10 |
| (...skipping 24 matching lines...) Expand all Loading... | |
| 35 #endif | 35 #endif |
| 36 | 36 |
| 37 #include <X11/X.h> // ShiftMask, ControlMask, etc. | 37 #include <X11/X.h> // ShiftMask, ControlMask, etc. |
| 38 #include <X11/Xutil.h> // for XK_* macros. | 38 #include <X11/Xutil.h> // for XK_* macros. |
| 39 | 39 |
| 40 namespace { | 40 namespace { |
| 41 | 41 |
| 42 const char kIBusDaemonPath[] = "/usr/bin/ibus-daemon"; | 42 const char kIBusDaemonPath[] = "/usr/bin/ibus-daemon"; |
| 43 | 43 |
| 44 // For hotkey handling. | 44 // For hotkey handling. |
| 45 enum HotkeyEvents { | 45 enum HotkeyEvent { |
| 46 kPreviousInputMethod = 0, | 46 kPreviousInputMethod = 0, |
| 47 kNextInputMethod, | 47 kNextInputMethod, |
| 48 kJapaneseInputMethod, | |
| 49 kJapaneseLayout, | |
| 50 kJapaneseInputMethodOrLayout, | |
| 51 kKoreanInputMethodOrLayout, | |
| 52 }; | |
| 53 | |
| 54 // Engine specific hotkeys. | |
| 55 const struct EngineSpecificHotkeySetting { | |
| 56 const char* input_method_ids[2]; | |
| 57 int event_id; | |
| 58 KeySym keysym; | |
| 59 uint32 modifiers; | |
| 60 bool trigger_on_press; | |
|
mazda
2011/09/12 10:02:54
What happens if trigger_on_press is false?
Yusuke Sato
2011/09/12 11:46:05
IME or layout is changed on key release. The Shift
mazda
2011/09/12 11:57:31
Thanks.
Probably it's better to add comment since
Yusuke Sato
2011/09/12 12:02:14
Done.
| |
| 61 } kEngineSpecificHotkeySettings[] = { | |
| 62 { | |
| 63 { "mozc-jp" }, | |
| 64 kJapaneseInputMethod, | |
| 65 XK_Henkan, | |
| 66 0x0, | |
| 67 true, | |
| 68 }, | |
| 69 { | |
| 70 { "xkb:jp::jpn" }, | |
| 71 kJapaneseLayout, | |
| 72 XK_Muhenkan, | |
| 73 0x0, | |
| 74 true, | |
| 75 }, | |
| 76 { | |
| 77 { "mozc-jp", "xkb:jp::jpn" }, | |
| 78 kJapaneseInputMethodOrLayout, | |
| 79 XK_Zenkaku_Hankaku, | |
| 80 0x0, | |
| 81 true, | |
| 82 }, | |
| 83 { | |
| 84 { "mozc-hangul", "xkb:kr:kr104:kor" }, | |
| 85 kKoreanInputMethodOrLayout, | |
| 86 XK_Hangul, | |
| 87 0x0, | |
| 88 true, | |
| 89 }, | |
| 90 { | |
| 91 { "mozc-hangul", "xkb:kr:kr104:kor" }, | |
| 92 kKoreanInputMethodOrLayout, | |
| 93 XK_space, | |
| 94 ShiftMask, | |
| 95 true, | |
| 96 }, | |
| 48 }; | 97 }; |
| 49 | 98 |
| 50 // Finds a property which has |new_prop.key| from |prop_list|, and replaces the | 99 // Finds a property which has |new_prop.key| from |prop_list|, and replaces the |
| 51 // property with |new_prop|. Returns true if such a property is found. | 100 // property with |new_prop|. Returns true if such a property is found. |
| 52 bool FindAndUpdateProperty( | 101 bool FindAndUpdateProperty( |
| 53 const chromeos::input_method::ImeProperty& new_prop, | 102 const chromeos::input_method::ImeProperty& new_prop, |
| 54 chromeos::input_method::ImePropertyList* prop_list) { | 103 chromeos::input_method::ImePropertyList* prop_list) { |
| 55 for (size_t i = 0; i < prop_list->size(); ++i) { | 104 for (size_t i = 0; i < prop_list->size(); ++i) { |
| 56 chromeos::input_method::ImeProperty& prop = prop_list->at(i); | 105 chromeos::input_method::ImeProperty& prop = prop_list->at(i); |
| 57 if (prop.key == new_prop.key) { | 106 if (prop.key == new_prop.key) { |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 97 // details. | 146 // details. |
| 98 notification_registrar_.Add(this, content::NOTIFICATION_APP_TERMINATING, | 147 notification_registrar_.Add(this, content::NOTIFICATION_APP_TERMINATING, |
| 99 NotificationService::AllSources()); | 148 NotificationService::AllSources()); |
| 100 | 149 |
| 101 ibus_controller_ = IBusController::Create(); | 150 ibus_controller_ = IBusController::Create(); |
| 102 // The observer should be added before Connect() so we can capture the | 151 // The observer should be added before Connect() so we can capture the |
| 103 // initial connection change. | 152 // initial connection change. |
| 104 ibus_controller_->AddObserver(this); | 153 ibus_controller_->AddObserver(this); |
| 105 ibus_controller_->Connect(); | 154 ibus_controller_->Connect(); |
| 106 | 155 |
| 156 // Initialize engine_hotkeys_. | |
| 157 for (size_t i = 0; i < arraysize(kEngineSpecificHotkeySettings); ++i) { | |
| 158 const char* const* input_method_ids = | |
| 159 kEngineSpecificHotkeySettings[i].input_method_ids; | |
| 160 const size_t input_method_ids_len = | |
| 161 arraysize(kEngineSpecificHotkeySettings[i].input_method_ids); | |
| 162 for (size_t j = 0; j < input_method_ids_len && input_method_ids[j]; ++j) { | |
| 163 engine_hotkeys_.insert(std::make_pair( | |
| 164 input_method_ids[j], &kEngineSpecificHotkeySettings[i])); | |
| 165 } | |
| 166 } | |
| 167 | |
| 168 // Register global input method hotkeys: Control+space and Shift+Alt. | |
| 107 InitHotkeyManager(); | 169 InitHotkeyManager(); |
| 108 } | 170 } |
| 109 | 171 |
| 110 virtual ~InputMethodManagerImpl() { | 172 virtual ~InputMethodManagerImpl() { |
| 111 hotkey_manager_.RemoveObserver(this); | 173 hotkey_manager_.RemoveObserver(this); |
| 112 ibus_controller_->RemoveObserver(this); | 174 ibus_controller_->RemoveObserver(this); |
| 113 } | 175 } |
| 114 | 176 |
| 115 virtual void AddObserver(InputMethodManager::Observer* observer) { | 177 virtual void AddObserver(InputMethodManager::Observer* observer) { |
| 116 if (!observers_.size()) { | 178 if (!observers_.size()) { |
| (...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 216 // input methods cache |active_input_method_ids_| here. We need to | 278 // input methods cache |active_input_method_ids_| here. We need to |
| 217 // update the cache before actually flushing the config. since we need | 279 // update the cache before actually flushing the config. since we need |
| 218 // to return active input methods from GetActiveInputMethods() before | 280 // to return active input methods from GetActiveInputMethods() before |
| 219 // the input method daemon starts. For instance, we need to show the | 281 // the input method daemon starts. For instance, we need to show the |
| 220 // list of available input methods (keyboard layouts) on the login | 282 // list of available input methods (keyboard layouts) on the login |
| 221 // screen before the input method starts. | 283 // screen before the input method starts. |
| 222 if (section == language_prefs::kGeneralSectionName && | 284 if (section == language_prefs::kGeneralSectionName && |
| 223 config_name == language_prefs::kPreloadEnginesConfigName && | 285 config_name == language_prefs::kPreloadEnginesConfigName && |
| 224 value.type == ImeConfigValue::kValueTypeStringList) { | 286 value.type == ImeConfigValue::kValueTypeStringList) { |
| 225 active_input_method_ids_ = value.string_list_value; | 287 active_input_method_ids_ = value.string_list_value; |
| 288 UpdateEngineSpecificHotkeys(); | |
|
mazda
2011/09/12 10:02:54
Is it OK that UpdateEngineSpecificHotkeys is calle
Yusuke Sato
2011/09/12 11:46:05
For now it's okay since hotkey information for an
| |
| 226 | 289 |
| 227 std::map<std::string, InputMethodDescriptor>::const_iterator ix; | 290 std::map<std::string, InputMethodDescriptor>::const_iterator ix; |
| 228 for (ix = extra_input_method_ids_.begin(); | 291 for (ix = extra_input_method_ids_.begin(); |
| 229 ix != extra_input_method_ids_.end(); ++ix) { | 292 ix != extra_input_method_ids_.end(); ++ix) { |
| 230 active_input_method_ids_.push_back(ix->first); | 293 active_input_method_ids_.push_back(ix->first); |
| 231 } | 294 } |
| 232 } | 295 } |
| 233 | 296 |
| 234 // Before calling FlushImeConfig(), start input method process if necessary. | 297 // Before calling FlushImeConfig(), start input method process if necessary. |
| 235 MaybeStartInputMethodDaemon(section, config_name, value); | 298 MaybeStartInputMethodDaemon(section, config_name, value); |
| (...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 342 virtual void ClearAllVirtualKeyboardPreferences() { | 405 virtual void ClearAllVirtualKeyboardPreferences() { |
| 343 virtual_keyboard_selector_.ClearAllUserPreferences(); | 406 virtual_keyboard_selector_.ClearAllUserPreferences(); |
| 344 UpdateVirtualKeyboardUI(); | 407 UpdateVirtualKeyboardUI(); |
| 345 } | 408 } |
| 346 | 409 |
| 347 virtual HotkeyManager* GetHotkeyManager() { | 410 virtual HotkeyManager* GetHotkeyManager() { |
| 348 return &hotkey_manager_; | 411 return &hotkey_manager_; |
| 349 } | 412 } |
| 350 | 413 |
| 351 virtual void HotkeyPressed(HotkeyManager* manager, int event_id) { | 414 virtual void HotkeyPressed(HotkeyManager* manager, int event_id) { |
| 352 switch (HotkeyEvents(event_id)) { | 415 const HotkeyEvent event = HotkeyEvent(event_id); |
| 416 switch (event) { | |
| 353 case kPreviousInputMethod: | 417 case kPreviousInputMethod: |
| 354 SwitchToPreviousInputMethod(); | 418 SwitchToPreviousInputMethod(); |
| 355 break; | 419 break; |
| 356 case kNextInputMethod: | 420 case kNextInputMethod: |
| 357 SwitchToNextInputMethod(); | 421 SwitchToNextInputMethod(); |
| 358 break; | 422 break; |
| 423 case kJapaneseInputMethod: | |
| 424 case kJapaneseLayout: | |
| 425 case kJapaneseInputMethodOrLayout: | |
| 426 case kKoreanInputMethodOrLayout: | |
| 427 SwitchToInputMethod(event); | |
|
mazda
2011/09/12 10:02:54
default case.
Yusuke Sato
2011/09/12 11:46:05
Since HotkeyEvent is an enum, adding default: is n
| |
| 428 break; | |
| 359 } | 429 } |
| 360 // TODO(yusukes): handle engine specific hotkeys like Henkan, Muhenkan, and | |
| 361 // Hangul. | |
| 362 } | 430 } |
| 363 | 431 |
| 364 static InputMethodManagerImpl* GetInstance() { | 432 static InputMethodManagerImpl* GetInstance() { |
| 365 return Singleton<InputMethodManagerImpl, | 433 return Singleton<InputMethodManagerImpl, |
| 366 DefaultSingletonTraits<InputMethodManagerImpl> >::get(); | 434 DefaultSingletonTraits<InputMethodManagerImpl> >::get(); |
| 367 } | 435 } |
| 368 | 436 |
| 369 private: | 437 private: |
| 370 friend struct DefaultSingletonTraits<InputMethodManagerImpl>; | 438 friend struct DefaultSingletonTraits<InputMethodManagerImpl>; |
| 371 | 439 |
| (...skipping 582 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 954 ShiftMask | Mod1Mask, | 1022 ShiftMask | Mod1Mask, |
| 955 false); | 1023 false); |
| 956 hotkey_manager_.AddHotkey(kNextInputMethod, | 1024 hotkey_manager_.AddHotkey(kNextInputMethod, |
| 957 XK_Meta_L, | 1025 XK_Meta_L, |
| 958 ShiftMask | Mod1Mask, | 1026 ShiftMask | Mod1Mask, |
| 959 false); | 1027 false); |
| 960 hotkey_manager_.AddHotkey(kNextInputMethod, | 1028 hotkey_manager_.AddHotkey(kNextInputMethod, |
| 961 XK_Meta_R, | 1029 XK_Meta_R, |
| 962 ShiftMask | Mod1Mask, | 1030 ShiftMask | Mod1Mask, |
| 963 false); | 1031 false); |
| 1032 // Engine specific hotkeys will be added in SetImeConfig(). | |
| 964 | 1033 |
| 965 // TODO(yusukes): Support engine specific hotkeys like XK_Henkan, Muhenkan, | |
| 966 // and Hangul. | |
| 967 hotkey_manager_.AddObserver(this); | 1034 hotkey_manager_.AddObserver(this); |
| 968 } | 1035 } |
| 969 | 1036 |
| 1037 void UpdateEngineSpecificHotkeys() { | |
| 1038 // Remove all engine specific hotkeys first. | |
| 1039 for (size_t i = 0; i < arraysize(kEngineSpecificHotkeySettings); ++i) { | |
| 1040 hotkey_manager_.RemoveHotkey(kEngineSpecificHotkeySettings[i].event_id); | |
| 1041 } | |
| 1042 for (size_t i = 0; i < active_input_method_ids_.size(); ++i) { | |
| 1043 typedef std::map<std::string, | |
| 1044 const EngineSpecificHotkeySetting*>::const_iterator Iter; | |
| 1045 std::pair<Iter, Iter> result = engine_hotkeys_.equal_range( | |
| 1046 active_input_method_ids_[i]); | |
| 1047 for (Iter iter = result.first; iter != result.second; ++iter) { | |
| 1048 hotkey_manager_.AddHotkey(iter->second->event_id, | |
| 1049 iter->second->keysym, | |
| 1050 iter->second->modifiers, | |
| 1051 iter->second->trigger_on_press); | |
| 1052 } | |
| 1053 } | |
| 1054 } | |
| 1055 | |
| 970 // Handles "Shift+Alt" hotkey. | 1056 // Handles "Shift+Alt" hotkey. |
| 971 void SwitchToNextInputMethod() { | 1057 void SwitchToNextInputMethod() { |
| 972 // Sanity checks. | 1058 // Sanity checks. |
| 973 if (active_input_method_ids_.empty()) { | 1059 if (active_input_method_ids_.empty()) { |
| 974 LOG(ERROR) << "active input method is empty"; | 1060 LOG(ERROR) << "active input method is empty"; |
| 975 return; | 1061 return; |
| 976 } | 1062 } |
| 977 if (current_input_method_.id().empty()) { | 1063 if (current_input_method_.id().empty()) { |
| 978 LOG(ERROR) << "current_input_method_ is unknown"; | 1064 LOG(ERROR) << "current_input_method_ is unknown"; |
| 979 return; | 1065 return; |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1012 active_input_method_ids_.end(), | 1098 active_input_method_ids_.end(), |
| 1013 previous_input_method_.id()); | 1099 previous_input_method_.id()); |
| 1014 if (iter == active_input_method_ids_.end()) { | 1100 if (iter == active_input_method_ids_.end()) { |
| 1015 // previous_input_method_ is not supported. | 1101 // previous_input_method_ is not supported. |
| 1016 SwitchToNextInputMethod(); | 1102 SwitchToNextInputMethod(); |
| 1017 } else { | 1103 } else { |
| 1018 ChangeInputMethod(*iter); | 1104 ChangeInputMethod(*iter); |
| 1019 } | 1105 } |
| 1020 } | 1106 } |
| 1021 | 1107 |
| 1108 // Handles engine specific hotkeys like XK_Henkan. | |
| 1109 void SwitchToInputMethod(HotkeyEvent event) { | |
| 1110 // Sanity check. | |
| 1111 if (active_input_method_ids_.empty()) { | |
| 1112 LOG(ERROR) << "active input method is empty"; | |
| 1113 return; | |
| 1114 } | |
| 1115 | |
| 1116 const char* const* input_method_ids_to_switch = NULL; | |
| 1117 size_t input_method_ids_to_switch_len = 0; | |
| 1118 | |
| 1119 // Get the list of input method ids for |event_id|. For example, get | |
| 1120 // { "mozc-hangul", "xkb:kr:kr104:kor" } for kKoreanInputMethodOrLayout. | |
| 1121 switch (event) { | |
| 1122 case kPreviousInputMethod: | |
| 1123 case kNextInputMethod: { | |
| 1124 break; | |
|
mazda
2011/09/12 10:02:54
Are these two error case?
Yusuke Sato
2011/09/12 11:46:05
added a comment.
| |
| 1125 } | |
| 1126 case kJapaneseInputMethod: | |
| 1127 case kJapaneseLayout: | |
| 1128 case kJapaneseInputMethodOrLayout: | |
| 1129 case kKoreanInputMethodOrLayout: { | |
| 1130 const size_t index = static_cast<size_t>(event) - 2; | |
|
Zachary Kuznia
2011/09/12 09:48:07
This line looks scary. Please give it a reassurin
Yusuke Sato
2011/09/12 11:46:05
Probably this was too error-prone. I've written th
| |
| 1131 DCHECK(event == kEngineSpecificHotkeySettings[index].event_id); | |
| 1132 input_method_ids_to_switch = | |
| 1133 kEngineSpecificHotkeySettings[index].input_method_ids; | |
| 1134 input_method_ids_to_switch_len = | |
| 1135 arraysize(kEngineSpecificHotkeySettings[index].input_method_ids); | |
| 1136 break; | |
| 1137 } | |
| 1138 } | |
| 1139 if (!input_method_ids_to_switch) { | |
|
mazda
2011/09/12 10:02:54
How about moving this to the default case of the s
Yusuke Sato
2011/09/12 11:46:05
ditto. I prefer not to use default: in order to ke
| |
| 1140 LOG(ERROR) << "Unknown event: " << event; | |
| 1141 return; | |
| 1142 } | |
| 1143 | |
| 1144 // Obtain the intersection of input_method_ids_to_switch and | |
| 1145 // active_input_method_ids_. The order of IDs in active_input_method_ids_ is | |
| 1146 // preserved. | |
| 1147 std::vector<std::string> ids; | |
| 1148 for (size_t i = 0; i < input_method_ids_to_switch_len; ++i) { | |
| 1149 const char* id = input_method_ids_to_switch[i]; | |
| 1150 if (id && std::find(active_input_method_ids_.begin(), | |
| 1151 active_input_method_ids_.end(), | |
| 1152 id) != active_input_method_ids_.end()) { | |
| 1153 ids.push_back(id); | |
| 1154 } | |
| 1155 } | |
| 1156 if (ids.empty()) { | |
| 1157 LOG(ERROR) << "No input method for " << event << " is active"; | |
| 1158 return; | |
| 1159 } | |
| 1160 | |
| 1161 // If current_input_method_ is not in ids, switch to ids[0]. If | |
| 1162 // current_input_method_ is ids[N], switch to ids[N+1]. | |
| 1163 std::vector<std::string>::const_iterator iter = | |
| 1164 std::find(ids.begin(), ids.end(), current_input_method_.id()); | |
| 1165 if (iter != ids.end()) { | |
| 1166 ++iter; | |
| 1167 } | |
| 1168 if (iter == ids.end()) { | |
| 1169 iter = ids.begin(); | |
| 1170 } | |
| 1171 ChangeInputMethod(*iter); | |
| 1172 } | |
| 1173 | |
| 1022 // A reference to the language api, to allow callbacks when the input method | 1174 // A reference to the language api, to allow callbacks when the input method |
| 1023 // status changes. | 1175 // status changes. |
| 1024 IBusController* ibus_controller_; | 1176 IBusController* ibus_controller_; |
| 1025 ObserverList<InputMethodManager::Observer> observers_; | 1177 ObserverList<InputMethodManager::Observer> observers_; |
| 1026 ObserverList<VirtualKeyboardObserver> virtual_keyboard_observers_; | 1178 ObserverList<VirtualKeyboardObserver> virtual_keyboard_observers_; |
| 1027 | 1179 |
| 1028 // The input method which was/is selected. | 1180 // The input method which was/is selected. |
| 1029 InputMethodDescriptor previous_input_method_; | 1181 InputMethodDescriptor previous_input_method_; |
| 1030 InputMethodDescriptor current_input_method_; | 1182 InputMethodDescriptor current_input_method_; |
| 1031 | 1183 |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1081 // An object which keeps a list of available virtual keyboards. | 1233 // An object which keeps a list of available virtual keyboards. |
| 1082 VirtualKeyboardSelector virtual_keyboard_selector_; | 1234 VirtualKeyboardSelector virtual_keyboard_selector_; |
| 1083 | 1235 |
| 1084 // The active input method ids cache. | 1236 // The active input method ids cache. |
| 1085 std::vector<std::string> active_input_method_ids_; | 1237 std::vector<std::string> active_input_method_ids_; |
| 1086 | 1238 |
| 1087 // Extra input methods that have been explicitly added to the menu, such as | 1239 // Extra input methods that have been explicitly added to the menu, such as |
| 1088 // those created by extension. | 1240 // those created by extension. |
| 1089 std::map<std::string, InputMethodDescriptor> extra_input_method_ids_; | 1241 std::map<std::string, InputMethodDescriptor> extra_input_method_ids_; |
| 1090 | 1242 |
| 1243 // A muitlmap from input method id to engine specific hotkey information. | |
| 1244 // e.g. "mozc-jp" to XK_ZenkakuHankaku, "mozc-jp" to XK_Henkan. | |
| 1245 std::multimap<std::string, | |
| 1246 const EngineSpecificHotkeySetting*> engine_hotkeys_; | |
| 1091 // An object which detects Control+space and Shift+Alt key presses. | 1247 // An object which detects Control+space and Shift+Alt key presses. |
| 1092 HotkeyManager hotkey_manager_; | 1248 HotkeyManager hotkey_manager_; |
| 1093 | 1249 |
| 1094 DISALLOW_COPY_AND_ASSIGN(InputMethodManagerImpl); | 1250 DISALLOW_COPY_AND_ASSIGN(InputMethodManagerImpl); |
| 1095 }; | 1251 }; |
| 1096 | 1252 |
| 1097 // static | 1253 // static |
| 1098 InputMethodManager* InputMethodManager::GetInstance() { | 1254 InputMethodManager* InputMethodManager::GetInstance() { |
| 1099 return InputMethodManagerImpl::GetInstance(); | 1255 return InputMethodManagerImpl::GetInstance(); |
| 1100 } | 1256 } |
| 1101 | 1257 |
| 1102 } // namespace input_method | 1258 } // namespace input_method |
| 1103 } // namespace chromeos | 1259 } // namespace chromeos |
| 1104 | 1260 |
| 1105 // Allows InvokeLater without adding refcounting. This class is a Singleton and | 1261 // Allows InvokeLater without adding refcounting. This class is a Singleton and |
| 1106 // won't be deleted until it's last InvokeLater is run. | 1262 // won't be deleted until it's last InvokeLater is run. |
| 1107 DISABLE_RUNNABLE_METHOD_REFCOUNT( | 1263 DISABLE_RUNNABLE_METHOD_REFCOUNT( |
| 1108 chromeos::input_method::InputMethodManagerImpl); | 1264 chromeos::input_method::InputMethodManagerImpl); |
| OLD | NEW |