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 "chrome/browser/chromeos/input_method/input_method_util.h" | 5 #include "chrome/browser/chromeos/input_method/input_method_util.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 #include <functional> | 8 #include <functional> |
9 #include <map> | 9 #include <map> |
10 #include <utility> | 10 #include <utility> |
11 | 11 |
12 #include "base/basictypes.h" | 12 #include "base/basictypes.h" |
13 #include "base/memory/scoped_ptr.h" | 13 #include "base/memory/scoped_ptr.h" |
14 #include "base/prefs/pref_service.h" | 14 #include "base/prefs/pref_service.h" |
15 #include "base/strings/string_split.h" | 15 #include "base/strings/string_split.h" |
16 #include "base/strings/string_util.h" | 16 #include "base/strings/string_util.h" |
17 #include "base/strings/utf_string_conversions.h" | 17 #include "base/strings/utf_string_conversions.h" |
18 #include "chromeos/ime/component_extension_ime_manager.h" | 18 #include "chromeos/ime/component_extension_ime_manager.h" |
19 #include "chromeos/ime/extension_ime_util.h" | 19 #include "chromeos/ime/extension_ime_util.h" |
20 // For SetHardwareKeyboardLayoutForTesting. | 20 // For SetHardwareKeyboardLayoutForTesting. |
21 #include "chromeos/ime/fake_input_method_delegate.h" | 21 #include "chromeos/ime/fake_input_method_delegate.h" |
22 #include "chromeos/ime/input_method_delegate.h" | 22 #include "chromeos/ime/input_method_delegate.h" |
| 23 #include "chromeos/ime/input_method_whitelist.h" |
23 // TODO(nona): move this header from this file. | 24 // TODO(nona): move this header from this file. |
24 #include "grit/generated_resources.h" | 25 #include "grit/generated_resources.h" |
25 | 26 |
26 namespace { | 27 namespace { |
27 | 28 |
28 // A mapping from an input method id to a string for the language indicator. The | 29 // A mapping from an input method id to a string for the language indicator. The |
29 // mapping is necessary since some input methods belong to the same language. | 30 // mapping is necessary since some input methods belong to the same language. |
30 // For example, both "xkb:us::eng" and "xkb:us:dvorak:eng" are for US English. | 31 // For example, both "xkb:us::eng" and "xkb:us:dvorak:eng" are for US English. |
31 const struct { | 32 const struct { |
32 const char* input_method_id; | 33 const char* input_method_id; |
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
119 { "ja", "us", "_comp_ime_fpfbhcjppmaeaijcidgiibchfbnhbeljnacl_mozc_us" }, | 120 { "ja", "us", "_comp_ime_fpfbhcjppmaeaijcidgiibchfbnhbeljnacl_mozc_us" }, |
120 { "ja", "jp", "_comp_ime_fpfbhcjppmaeaijcidgiibchfbnhbeljnacl_mozc_jp" }, | 121 { "ja", "jp", "_comp_ime_fpfbhcjppmaeaijcidgiibchfbnhbeljnacl_mozc_jp" }, |
121 { "zh-CN", "us", "_comp_ime_nmblnjkfdkabgdofidlkienfnnbjhnabzh-t-i0-pinyin" }, | 122 { "zh-CN", "us", "_comp_ime_nmblnjkfdkabgdofidlkienfnnbjhnabzh-t-i0-pinyin" }, |
122 { "zh-TW", "us", | 123 { "zh-TW", "us", |
123 "_comp_ime_goedamlknlnjaengojinmfgpmdjmkooozh-hant-t-i0-und" }, | 124 "_comp_ime_goedamlknlnjaengojinmfgpmdjmkooozh-hant-t-i0-und" }, |
124 { "th", "us", "_comp_ime_jhffeifommiaekmbkkjlpmilogcfdohpvkd_th" }, | 125 { "th", "us", "_comp_ime_jhffeifommiaekmbkkjlpmilogcfdohpvkd_th" }, |
125 { "vi", "us", "_comp_ime_jhffeifommiaekmbkkjlpmilogcfdohpvkd_vi_tcvn" }, | 126 { "vi", "us", "_comp_ime_jhffeifommiaekmbkkjlpmilogcfdohpvkd_vi_tcvn" }, |
126 { "vi", "us", "_comp_ime_jhffeifommiaekmbkkjlpmilogcfdohpvkd_vi_tcvn" }, | 127 { "vi", "us", "_comp_ime_jhffeifommiaekmbkkjlpmilogcfdohpvkd_vi_tcvn" }, |
127 }; | 128 }; |
128 | 129 |
| 130 // The map from xkb layout to the indicator text. |
| 131 // Refer to crbug.com/349829. |
| 132 const char* const kXkbIndicators[][2] = {{"am", "AM"}, |
| 133 {"be", "BE"}, |
| 134 {"bg", "BG"}, |
| 135 {"bg(phonetic)", "BG"}, |
| 136 {"br", "BR"}, |
| 137 {"by", "BY"}, |
| 138 {"ca", "CA"}, |
| 139 {"ca(eng)", "CA"}, |
| 140 {"ca(multix)", "CA"}, |
| 141 {"ch", "CH"}, |
| 142 {"ch(fr)", "CH"}, |
| 143 {"cz", "CZ"}, |
| 144 {"cz(qwerty)", "CS"}, |
| 145 {"de", "DE"}, |
| 146 {"de(neo)", "NEO"}, |
| 147 {"dk", "DK"}, |
| 148 {"ee", "EE"}, |
| 149 {"es", "ES"}, |
| 150 {"es(cat)", "CAS"}, |
| 151 {"fi", "FI"}, |
| 152 {"fr", "FR"}, |
| 153 {"gb(dvorak)", "DV"}, |
| 154 {"gb(extd)", "GB"}, |
| 155 {"ge", "GE"}, |
| 156 {"gr", "GR"}, |
| 157 {"hr", "HR"}, |
| 158 {"hu", "HU"}, |
| 159 {"il", "IL"}, |
| 160 {"is", "IS"}, |
| 161 {"it", "IT"}, |
| 162 {"jp", "JA"}, |
| 163 {"latam", "LA"}, |
| 164 {"lt", "LT"}, |
| 165 {"lv(apostrophe)", "LV"}, |
| 166 {"mn", "MN"}, |
| 167 {"no", "NO"}, |
| 168 {"pl", "PL"}, |
| 169 {"pt", "PT"}, |
| 170 {"ro", "RO"}, |
| 171 {"rs", "RS"}, |
| 172 {"ru", "RU"}, |
| 173 {"ru(phonetic)", "RU"}, |
| 174 {"se", "SE"}, |
| 175 {"si", "SI"}, |
| 176 {"sk", "SK"}, |
| 177 {"tr", "TR"}, |
| 178 {"ua", "UA"}, |
| 179 {"us", "US"}, |
| 180 {"us(altgr-intl)", "EXTD"}, |
| 181 {"us(colemak)", "CO"}, |
| 182 {"us(dvorak)", "DV"}, |
| 183 {"us(intl)", "INTL"}, }; |
| 184 |
129 } // namespace | 185 } // namespace |
130 | 186 |
131 namespace chromeos { | 187 namespace chromeos { |
132 | 188 |
133 extern const char* kExtensionImePrefix; | 189 extern const char* kExtensionImePrefix; |
134 | 190 |
135 namespace input_method { | 191 namespace input_method { |
136 | 192 |
137 namespace { | 193 namespace { |
138 | 194 |
(...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
284 const size_t kEnglishToResourceIdArraySize = | 340 const size_t kEnglishToResourceIdArraySize = |
285 arraysize(kEnglishToResourceIdArray); | 341 arraysize(kEnglishToResourceIdArray); |
286 | 342 |
287 } // namespace | 343 } // namespace |
288 | 344 |
289 InputMethodUtil::InputMethodUtil( | 345 InputMethodUtil::InputMethodUtil( |
290 InputMethodDelegate* delegate, | 346 InputMethodDelegate* delegate, |
291 scoped_ptr<InputMethodDescriptors> supported_input_methods) | 347 scoped_ptr<InputMethodDescriptors> supported_input_methods) |
292 : supported_input_methods_(supported_input_methods.Pass()), | 348 : supported_input_methods_(supported_input_methods.Pass()), |
293 delegate_(delegate) { | 349 delegate_(delegate) { |
| 350 // Makes sure the supported input methods at least have the fallback ime. |
| 351 // So that it won't cause massive test failures. |
| 352 if (supported_input_methods_->empty()) |
| 353 supported_input_methods_->push_back(GetFallbackInputMethodDescriptor()); |
| 354 |
294 ReloadInternalMaps(); | 355 ReloadInternalMaps(); |
295 | 356 |
296 // Initialize a map from English string to Chrome string resource ID as well. | 357 // Initialize a map from English string to Chrome string resource ID as well. |
297 for (size_t i = 0; i < kEnglishToResourceIdArraySize; ++i) { | 358 for (size_t i = 0; i < kEnglishToResourceIdArraySize; ++i) { |
298 const EnglishToResouceId& map_entry = kEnglishToResourceIdArray[i]; | 359 const EnglishToResouceId& map_entry = kEnglishToResourceIdArray[i]; |
299 const bool result = english_to_resource_id_.insert(std::make_pair( | 360 const bool result = english_to_resource_id_.insert(std::make_pair( |
300 map_entry.english_string_from_ibus, map_entry.resource_id)).second; | 361 map_entry.english_string_from_ibus, map_entry.resource_id)).second; |
301 DCHECK(result) << "Duplicated string is found: " | 362 DCHECK(result) << "Duplicated string is found: " |
302 << map_entry.english_string_from_ibus; | 363 << map_entry.english_string_from_ibus; |
303 } | 364 } |
| 365 |
| 366 // Initialize the map from xkb layout to indicator text. |
| 367 for (size_t i = 0; i < arraysize(kXkbIndicators); ++i) { |
| 368 xkb_layout_to_indicator_[kXkbIndicators[i][0]] = kXkbIndicators[i][1]; |
| 369 } |
304 } | 370 } |
305 | 371 |
306 InputMethodUtil::~InputMethodUtil() { | 372 InputMethodUtil::~InputMethodUtil() { |
307 } | 373 } |
308 | 374 |
309 bool InputMethodUtil::TranslateStringInternal( | 375 bool InputMethodUtil::TranslateStringInternal( |
310 const std::string& english_string, base::string16 *out_string) const { | 376 const std::string& english_string, base::string16 *out_string) const { |
311 DCHECK(out_string); | 377 DCHECK(out_string); |
312 HashType::const_iterator iter = english_to_resource_id_.find(english_string); | 378 HashType::const_iterator iter = english_to_resource_id_.find(english_string); |
313 if (iter == english_to_resource_id_.end()) { | 379 if (iter == english_to_resource_id_.end()) { |
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
391 // Check special cases first. | 457 // Check special cases first. |
392 for (size_t i = 0; i < kMappingFromIdToIndicatorTextLen; ++i) { | 458 for (size_t i = 0; i < kMappingFromIdToIndicatorTextLen; ++i) { |
393 if (kMappingFromIdToIndicatorText[i].input_method_id == | 459 if (kMappingFromIdToIndicatorText[i].input_method_id == |
394 input_method.id()) { | 460 input_method.id()) { |
395 text = base::UTF8ToUTF16(kMappingFromIdToIndicatorText[i].indicator_text); | 461 text = base::UTF8ToUTF16(kMappingFromIdToIndicatorText[i].indicator_text); |
396 break; | 462 break; |
397 } | 463 } |
398 } | 464 } |
399 | 465 |
400 // Display the keyboard layout name when using a keyboard layout. | 466 // Display the keyboard layout name when using a keyboard layout. |
401 if (text.empty() && | 467 if (text.empty() && IsKeyboardLayout(input_method.id())) { |
402 IsKeyboardLayout(input_method.id())) { | 468 std::map<std::string, std::string>::const_iterator it = |
403 const size_t kMaxKeyboardLayoutNameLen = 2; | 469 xkb_layout_to_indicator_.find(GetKeyboardLayoutName(input_method.id())); |
404 const base::string16 keyboard_layout = | 470 if (it != xkb_layout_to_indicator_.end()) |
405 base::UTF8ToUTF16(GetKeyboardLayoutName(input_method.id())); | 471 text = base::UTF8ToUTF16(it->second); |
406 text = StringToUpperASCII(keyboard_layout).substr( | |
407 0, kMaxKeyboardLayoutNameLen); | |
408 } | 472 } |
409 | 473 |
410 // TODO(yusukes): Some languages have two or more input methods. For example, | 474 // TODO(yusukes): Some languages have two or more input methods. For example, |
411 // Thai has 3, Vietnamese has 4. If these input methods could be activated at | 475 // Thai has 3, Vietnamese has 4. If these input methods could be activated at |
412 // the same time, we should do either of the following: | 476 // the same time, we should do either of the following: |
413 // (1) Add mappings to |kMappingFromIdToIndicatorText| | 477 // (1) Add mappings to |kMappingFromIdToIndicatorText| |
414 // (2) Add suffix (1, 2, ...) to |text| when ambiguous. | 478 // (2) Add suffix (1, 2, ...) to |text| when ambiguous. |
415 | 479 |
416 if (text.empty()) { | 480 if (text.empty()) { |
417 const size_t kMaxLanguageNameLen = 2; | 481 const size_t kMaxLanguageNameLen = 2; |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
474 | 538 |
475 text = language_name + base::UTF8ToUTF16(" - ") + text; | 539 text = language_name + base::UTF8ToUTF16(" - ") + text; |
476 } | 540 } |
477 | 541 |
478 DCHECK(!text.empty()); | 542 DCHECK(!text.empty()); |
479 return text; | 543 return text; |
480 } | 544 } |
481 | 545 |
482 const InputMethodDescriptor* InputMethodUtil::GetInputMethodDescriptorFromId( | 546 const InputMethodDescriptor* InputMethodUtil::GetInputMethodDescriptorFromId( |
483 const std::string& input_method_id) const { | 547 const std::string& input_method_id) const { |
484 InputMethodIdToDescriptorMap::const_iterator iter | 548 InputMethodIdToDescriptorMap::const_iterator iter = |
485 = id_to_descriptor_.find(input_method_id); | 549 id_to_descriptor_.find(input_method_id); |
486 if (iter == id_to_descriptor_.end()) { | 550 if (iter == id_to_descriptor_.end()) |
487 // If failed to find the descriptor for given id, it may because of the id | 551 return NULL; |
488 // is a component extension xkb id (_comp_ime_...xkb:...). | |
489 // So try to convert it to legacy xkb id and find again. | |
490 // This hack is mainly for OOBE session, which requires a sync call to get | |
491 // the input method descriptor for extension xkb id. | |
492 // TODO(shuchen): need to support async wait for component extension | |
493 // loading in OOBE session. This hack won't be needed when it's been done. | |
494 iter = id_to_descriptor_.find( | |
495 extension_ime_util::MaybeGetLegacyXkbId(input_method_id)); | |
496 if (iter == id_to_descriptor_.end()) | |
497 return NULL; | |
498 } | |
499 return &(iter->second); | 552 return &(iter->second); |
500 } | 553 } |
501 | 554 |
502 bool InputMethodUtil::GetInputMethodIdsFromLanguageCode( | 555 bool InputMethodUtil::GetInputMethodIdsFromLanguageCode( |
503 const std::string& normalized_language_code, | 556 const std::string& normalized_language_code, |
504 InputMethodType type, | 557 InputMethodType type, |
505 std::vector<std::string>* out_input_method_ids) const { | 558 std::vector<std::string>* out_input_method_ids) const { |
506 return GetInputMethodIdsFromLanguageCodeInternal( | 559 return GetInputMethodIdsFromLanguageCodeInternal( |
507 language_code_to_ids_, | 560 language_code_to_ids_, |
508 normalized_language_code, type, out_input_method_ids); | 561 normalized_language_code, type, out_input_method_ids); |
(...skipping 192 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
701 | 754 |
702 bool InputMethodUtil::IsLoginKeyboard(const std::string& input_method_id) | 755 bool InputMethodUtil::IsLoginKeyboard(const std::string& input_method_id) |
703 const { | 756 const { |
704 const InputMethodDescriptor* ime = | 757 const InputMethodDescriptor* ime = |
705 GetInputMethodDescriptorFromId(input_method_id); | 758 GetInputMethodDescriptorFromId(input_method_id); |
706 return ime ? ime->is_login_keyboard() : false; | 759 return ime ? ime->is_login_keyboard() : false; |
707 } | 760 } |
708 | 761 |
709 void InputMethodUtil::SetComponentExtensions( | 762 void InputMethodUtil::SetComponentExtensions( |
710 const InputMethodDescriptors& imes) { | 763 const InputMethodDescriptors& imes) { |
711 component_extension_ime_id_to_descriptor_.clear(); | |
712 for (size_t i = 0; i < imes.size(); ++i) { | 764 for (size_t i = 0; i < imes.size(); ++i) { |
713 const InputMethodDescriptor& input_method = imes.at(i); | 765 const InputMethodDescriptor& input_method = imes[i]; |
714 DCHECK(!input_method.language_codes().empty()); | 766 DCHECK(!input_method.language_codes().empty()); |
715 const std::string language_code = input_method.language_codes().at(0); | 767 const std::vector<std::string>& language_codes = |
716 id_to_language_code_.insert( | 768 input_method.language_codes(); |
717 std::make_pair(input_method.id(), language_code)); | 769 id_to_language_code_[input_method.id()] = language_codes[0]; |
718 id_to_descriptor_.insert( | 770 id_to_descriptor_[input_method.id()] = input_method; |
719 std::make_pair(input_method.id(), input_method)); | 771 |
| 772 typedef LanguageCodeToIdsMap::const_iterator It; |
| 773 for (size_t j = 0; j < language_codes.size(); ++j) { |
| 774 std::pair<It, It> range = |
| 775 language_code_to_ids_.equal_range(language_codes[j]); |
| 776 It it = range.first; |
| 777 for (; it != range.second; ++it) { |
| 778 if (it->second == input_method.id()) |
| 779 break; |
| 780 } |
| 781 if (it == range.second) |
| 782 language_code_to_ids_.insert( |
| 783 std::make_pair(language_codes[j], input_method.id())); |
| 784 } |
720 } | 785 } |
721 } | 786 } |
722 | 787 |
| 788 void InputMethodUtil::InitXkbInputMethodsForTesting() { |
| 789 if (!extension_ime_util::UseWrappedExtensionKeyboardLayouts()) |
| 790 return; |
| 791 scoped_ptr<InputMethodDescriptors> original_imes = |
| 792 InputMethodWhitelist().GetSupportedInputMethods(); |
| 793 InputMethodDescriptors whitelist_imes; |
| 794 for (size_t i = 0; i < original_imes->size(); ++i) { |
| 795 const InputMethodDescriptor& ime = (*original_imes)[i]; |
| 796 whitelist_imes.push_back(InputMethodDescriptor( |
| 797 extension_ime_util::GetInputMethodIDByKeyboardLayout(ime.id()), |
| 798 "", |
| 799 ime.indicator(), |
| 800 ime.keyboard_layouts(), |
| 801 ime.language_codes(), |
| 802 ime.is_login_keyboard(), |
| 803 ime.options_page_url(), |
| 804 ime.input_view_url())); |
| 805 } |
| 806 SetComponentExtensions(whitelist_imes); |
| 807 } |
| 808 |
723 InputMethodDescriptor InputMethodUtil::GetFallbackInputMethodDescriptor() { | 809 InputMethodDescriptor InputMethodUtil::GetFallbackInputMethodDescriptor() { |
724 std::vector<std::string> layouts; | 810 std::vector<std::string> layouts; |
725 layouts.push_back("us"); | 811 layouts.push_back("us"); |
726 std::vector<std::string> languages; | 812 std::vector<std::string> languages; |
727 languages.push_back("en-US"); | 813 languages.push_back("en-US"); |
728 return InputMethodDescriptor( | 814 return InputMethodDescriptor( |
729 extension_ime_util::GetInputMethodIDByKeyboardLayout("xkb:us::eng"), | 815 extension_ime_util::GetInputMethodIDByKeyboardLayout("xkb:us::eng"), |
730 "", | 816 "", |
731 "US", | 817 "US", |
732 layouts, | 818 layouts, |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
765 if (IsKeyboardLayout(input_method.id())) { | 851 if (IsKeyboardLayout(input_method.id())) { |
766 xkb_id_to_descriptor_.insert( | 852 xkb_id_to_descriptor_.insert( |
767 std::make_pair(input_method.GetPreferredKeyboardLayout(), | 853 std::make_pair(input_method.GetPreferredKeyboardLayout(), |
768 input_method)); | 854 input_method)); |
769 } | 855 } |
770 } | 856 } |
771 } | 857 } |
772 | 858 |
773 } // namespace input_method | 859 } // namespace input_method |
774 } // namespace chromeos | 860 } // namespace chromeos |
OLD | NEW |