| OLD | NEW |
| (Empty) |
| 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 | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "chrome/browser/chromeos/input_method/input_method_util.h" | |
| 6 | |
| 7 #include <stddef.h> | |
| 8 | |
| 9 #include <algorithm> | |
| 10 #include <functional> | |
| 11 #include <map> | |
| 12 #include <memory> | |
| 13 #include <unordered_set> | |
| 14 #include <utility> | |
| 15 | |
| 16 #include "base/macros.h" | |
| 17 #include "base/strings/string_split.h" | |
| 18 #include "base/strings/string_util.h" | |
| 19 #include "base/strings/utf_string_conversions.h" | |
| 20 #include "chrome/common/extensions/extension_constants.h" | |
| 21 // TODO(nona): move this header from this file. | |
| 22 #include "chrome/grit/generated_resources.h" | |
| 23 #include "components/prefs/pref_service.h" | |
| 24 #include "ui/base/ime/chromeos/component_extension_ime_manager.h" | |
| 25 #include "ui/base/ime/chromeos/extension_ime_util.h" | |
| 26 // For SetHardwareKeyboardLayoutForTesting. | |
| 27 #include "ui/base/ime/chromeos/fake_input_method_delegate.h" | |
| 28 #include "ui/base/ime/chromeos/input_method_delegate.h" | |
| 29 #include "ui/base/l10n/l10n_util.h" | |
| 30 | |
| 31 namespace { | |
| 32 | |
| 33 // A mapping from an input method id to a resource id for a | |
| 34 // medium length language indicator. | |
| 35 // For those languages that want to display a slightly longer text in the | |
| 36 // "Your input method has changed to..." bubble than in the status tray. | |
| 37 // If an entry is not found in this table the short name is used. | |
| 38 const struct { | |
| 39 const char* engine_id; | |
| 40 const int resource_id; | |
| 41 } kMappingImeIdToMediumLenNameResourceId[] = { | |
| 42 { "hangul_2set", IDS_LANGUAGES_MEDIUM_LEN_NAME_KOREAN }, | |
| 43 { "hangul_3set390", IDS_LANGUAGES_MEDIUM_LEN_NAME_KOREAN }, | |
| 44 { "hangul_3setfinal", IDS_LANGUAGES_MEDIUM_LEN_NAME_KOREAN }, | |
| 45 { "hangul_3setnoshift", IDS_LANGUAGES_MEDIUM_LEN_NAME_KOREAN }, | |
| 46 { "hangul_3setromaja", IDS_LANGUAGES_MEDIUM_LEN_NAME_KOREAN }, | |
| 47 { "zh-t-i0-pinyin", IDS_LANGUAGES_MEDIUM_LEN_NAME_CHINESE_SIMPLIFIED}, | |
| 48 { "zh-t-i0-wubi-1986", IDS_LANGUAGES_MEDIUM_LEN_NAME_CHINESE_SIMPLIFIED }, | |
| 49 { "zh-hant-t-i0-und", IDS_LANGUAGES_MEDIUM_LEN_NAME_CHINESE_TRADITIONAL }, | |
| 50 { "zh-hant-t-i0-cangjie-1987", | |
| 51 IDS_LANGUAGES_MEDIUM_LEN_NAME_CHINESE_TRADITIONAL }, | |
| 52 { "zh-hant-t-i0-cangjie-1987-x-m0-simplified", | |
| 53 IDS_LANGUAGES_MEDIUM_LEN_NAME_CHINESE_TRADITIONAL }, | |
| 54 { extension_misc::kBrailleImeEngineId, | |
| 55 IDS_LANGUAGES_MEDIUM_LEN_NAME_BRAILLE }, | |
| 56 }; | |
| 57 const size_t kMappingImeIdToMediumLenNameResourceIdLen = | |
| 58 arraysize(kMappingImeIdToMediumLenNameResourceId); | |
| 59 | |
| 60 // Due to asynchronous initialization of component extension manager, | |
| 61 // GetFirstLoginInputMethodIds may miss component extension IMEs. To enable | |
| 62 // component extension IME as the first loging input method, we have to prepare | |
| 63 // component extension IME IDs. | |
| 64 // Note: empty layout means the rule applies for all layouts. | |
| 65 const struct { | |
| 66 const char* locale; | |
| 67 const char* layout; | |
| 68 const char* engine_id; | |
| 69 } kDefaultInputMethodRecommendation[] = { | |
| 70 { "ja", "jp", "nacl_mozc_jp" }, | |
| 71 { "ja", "", "nacl_mozc_us" }, | |
| 72 { "zh-CN", "", "zh-t-i0-pinyin" }, | |
| 73 { "zh-TW", "", "zh-hant-t-i0-und" }, | |
| 74 { "th", "", "vkd_th" }, | |
| 75 { "vi", "", "vkd_vi_tcvn" }, | |
| 76 { "ru", "", "xkb:ru::rus" }, | |
| 77 }; | |
| 78 | |
| 79 // The engine ID map for migration. This migration is for input method IDs from | |
| 80 // VPD so it's NOT a temporary migration. | |
| 81 const char* const kEngineIdMigrationMap[][2] = { | |
| 82 // Workaround for invalid keyboard layout in kefka board vpd. | |
| 83 // See https://crbug.com/700625 | |
| 84 {"ANSI", "xkb:us::eng"}, | |
| 85 {"ime:jp:mozc_jp", "nacl_mozc_jp"}, | |
| 86 {"ime:jp:mozc_us", "nacl_mozc_us"}, | |
| 87 {"ime:ko:hangul_2set", "ko-t-i0-und"}, | |
| 88 {"ime:ko:hangul", "ko-t-i0-und"}, | |
| 89 {"ime:zh-t:array", "zh-hant-t-i0-array-1992"}, | |
| 90 {"ime:zh-t:cangjie", "zh-hant-t-i0-cangjie-1987"}, | |
| 91 {"ime:zh-t:dayi", "zh-hant-t-i0-dayi-1988"}, | |
| 92 {"ime:zh-t:pinyin", "zh-hant-t-i0-pinyin"}, | |
| 93 {"ime:zh-t:quick", "zh-hant-t-i0-cangjie-1987-x-m0-simplified"}, | |
| 94 {"ime:zh-t:zhuyin", "zh-hant-t-i0-und"}, | |
| 95 {"ime:zh:pinyin", "zh-t-i0-pinyin"}, | |
| 96 {"ime:zh:wubi", "zh-t-i0-wubi-1986"}, | |
| 97 {"m17n:", "vkd_"}, | |
| 98 {"t13n:am", "am-t-i0-und"}, | |
| 99 {"t13n:ar", "ar-t-i0-und"}, | |
| 100 {"t13n:bn", "bn-t-i0-und"}, | |
| 101 {"t13n:el", "el-t-i0-und"}, | |
| 102 {"t13n:fa", "fa-t-i0-und"}, | |
| 103 {"t13n:gu", "gu-t-i0-und"}, | |
| 104 {"t13n:he", "he-t-i0-und"}, | |
| 105 {"t13n:hi", "hi-t-i0-und"}, | |
| 106 {"t13n:kn", "kn-t-i0-und"}, | |
| 107 {"t13n:ml", "ml-t-i0-und"}, | |
| 108 {"t13n:mr", "mr-t-i0-und"}, | |
| 109 {"t13n:ne", "ne-t-i0-und"}, | |
| 110 {"t13n:or", "or-t-i0-und"}, | |
| 111 {"t13n:pa", "pa-t-i0-und"}, | |
| 112 {"t13n:sa", "sa-t-i0-und"}, | |
| 113 {"t13n:sr", "sr-t-i0-und"}, | |
| 114 {"t13n:ta", "ta-t-i0-und"}, | |
| 115 {"t13n:te", "te-t-i0-und"}, | |
| 116 {"t13n:ti", "ti-t-i0-und"}, | |
| 117 {"t13n:ur", "ur-t-i0-und"}, | |
| 118 }; | |
| 119 | |
| 120 const struct EnglishToResouceId { | |
| 121 const char* english_string_from_ibus; | |
| 122 int resource_id; | |
| 123 } kEnglishToResourceIdArray[] = { | |
| 124 // For xkb-layouts. | |
| 125 {"xkb:am:phonetic:arm", IDS_STATUSBAR_LAYOUT_ARMENIAN_PHONETIC}, | |
| 126 {"xkb:be::fra", IDS_STATUSBAR_LAYOUT_BELGIUM}, | |
| 127 {"xkb:be::ger", IDS_STATUSBAR_LAYOUT_BELGIUM}, | |
| 128 {"xkb:be::nld", IDS_STATUSBAR_LAYOUT_BELGIUM}, | |
| 129 {"xkb:bg::bul", IDS_STATUSBAR_LAYOUT_BULGARIA}, | |
| 130 {"xkb:bg:phonetic:bul", IDS_STATUSBAR_LAYOUT_BULGARIA_PHONETIC}, | |
| 131 {"xkb:br::por", IDS_STATUSBAR_LAYOUT_BRAZIL}, | |
| 132 {"xkb:by::bel", IDS_STATUSBAR_LAYOUT_BELARUSIAN}, | |
| 133 {"xkb:ca::fra", IDS_STATUSBAR_LAYOUT_CANADA}, | |
| 134 {"xkb:ca:eng:eng", IDS_STATUSBAR_LAYOUT_CANADA_ENGLISH}, | |
| 135 {"xkb:ca:multix:fra", IDS_STATUSBAR_LAYOUT_CANADIAN_MULTILINGUAL}, | |
| 136 {"xkb:ch::ger", IDS_STATUSBAR_LAYOUT_SWITZERLAND}, | |
| 137 {"xkb:ch:fr:fra", IDS_STATUSBAR_LAYOUT_SWITZERLAND_FRENCH}, | |
| 138 {"xkb:cz::cze", IDS_STATUSBAR_LAYOUT_CZECHIA}, | |
| 139 {"xkb:cz:qwerty:cze", IDS_STATUSBAR_LAYOUT_CZECHIA_QWERTY}, | |
| 140 {"xkb:de::ger", IDS_STATUSBAR_LAYOUT_GERMANY}, | |
| 141 {"xkb:de:neo:ger", IDS_STATUSBAR_LAYOUT_GERMANY_NEO2}, | |
| 142 {"xkb:dk::dan", IDS_STATUSBAR_LAYOUT_DENMARK}, | |
| 143 {"xkb:ee::est", IDS_STATUSBAR_LAYOUT_ESTONIA}, | |
| 144 {"xkb:es::spa", IDS_STATUSBAR_LAYOUT_SPAIN}, | |
| 145 {"xkb:es:cat:cat", IDS_STATUSBAR_LAYOUT_SPAIN_CATALAN}, | |
| 146 {"xkb:fo::fao", IDS_STATUSBAR_LAYOUT_FAROESE}, | |
| 147 {"xkb:fi::fin", IDS_STATUSBAR_LAYOUT_FINLAND}, | |
| 148 {"xkb:fr:bepo:fra", IDS_STATUSBAR_LAYOUT_FRANCE_BEPO}, | |
| 149 {"xkb:fr::fra", IDS_STATUSBAR_LAYOUT_FRANCE}, | |
| 150 {"xkb:gb:dvorak:eng", IDS_STATUSBAR_LAYOUT_UNITED_KINGDOM_DVORAK}, | |
| 151 {"xkb:gb:extd:eng", IDS_STATUSBAR_LAYOUT_UNITED_KINGDOM}, | |
| 152 {"xkb:ge::geo", IDS_STATUSBAR_LAYOUT_GEORGIAN}, | |
| 153 {"xkb:gr::gre", IDS_STATUSBAR_LAYOUT_GREECE}, | |
| 154 {"xkb:hr::scr", IDS_STATUSBAR_LAYOUT_CROATIA}, | |
| 155 {"xkb:hu:qwerty:hun", IDS_STATUSBAR_LAYOUT_HUNGARY_QWERTY}, | |
| 156 {"xkb:hu::hun", IDS_STATUSBAR_LAYOUT_HUNGARY}, | |
| 157 {"xkb:ie::ga", IDS_STATUSBAR_LAYOUT_IRISH}, | |
| 158 {"xkb:il::heb", IDS_STATUSBAR_LAYOUT_ISRAEL}, | |
| 159 {"xkb:is::ice", IDS_STATUSBAR_LAYOUT_ICELANDIC}, | |
| 160 {"xkb:it::ita", IDS_STATUSBAR_LAYOUT_ITALY}, | |
| 161 {"xkb:jp::jpn", IDS_STATUSBAR_LAYOUT_JAPAN}, | |
| 162 {"xkb:kz::kaz", IDS_STATUSBAR_LAYOUT_KAZAKH}, | |
| 163 {"xkb:latam::spa", IDS_STATUSBAR_LAYOUT_LATIN_AMERICAN}, | |
| 164 {"xkb:lt::lit", IDS_STATUSBAR_LAYOUT_LITHUANIA}, | |
| 165 {"xkb:lv:apostrophe:lav", IDS_STATUSBAR_LAYOUT_LATVIA}, | |
| 166 {"xkb:mk::mkd", IDS_STATUSBAR_LAYOUT_MACEDONIAN}, | |
| 167 {"xkb:mn::mon", IDS_STATUSBAR_LAYOUT_MONGOLIAN}, | |
| 168 {"xkb:nl::nld", IDS_STATUSBAR_LAYOUT_NETHERLANDS}, | |
| 169 {"xkb:no::nob", IDS_STATUSBAR_LAYOUT_NORWAY}, | |
| 170 {"xkb:pl::pol", IDS_STATUSBAR_LAYOUT_POLAND}, | |
| 171 {"xkb:pt::por", IDS_STATUSBAR_LAYOUT_PORTUGAL}, | |
| 172 {"xkb:ro::rum", IDS_STATUSBAR_LAYOUT_ROMANIA}, | |
| 173 {"xkb:rs::srp", IDS_STATUSBAR_LAYOUT_SERBIA}, | |
| 174 {"xkb:ru::rus", IDS_STATUSBAR_LAYOUT_RUSSIA}, | |
| 175 {"xkb:ru:phonetic:rus", IDS_STATUSBAR_LAYOUT_RUSSIA_PHONETIC}, | |
| 176 {"xkb:se::swe", IDS_STATUSBAR_LAYOUT_SWEDEN}, | |
| 177 {"xkb:si::slv", IDS_STATUSBAR_LAYOUT_SLOVENIA}, | |
| 178 {"xkb:sk::slo", IDS_STATUSBAR_LAYOUT_SLOVAKIA}, | |
| 179 {"xkb:tr::tur", IDS_STATUSBAR_LAYOUT_TURKEY}, | |
| 180 {"xkb:tr:f:tur", IDS_STATUSBAR_LAYOUT_TURKEY_F}, | |
| 181 {"xkb:ua::ukr", IDS_STATUSBAR_LAYOUT_UKRAINE}, | |
| 182 {"xkb:us::eng", IDS_STATUSBAR_LAYOUT_USA}, | |
| 183 {"xkb:us::fil", IDS_STATUSBAR_LAYOUT_USA}, | |
| 184 {"xkb:us::ind", IDS_STATUSBAR_LAYOUT_USA}, | |
| 185 {"xkb:us::msa", IDS_STATUSBAR_LAYOUT_USA}, | |
| 186 {"xkb:us:altgr-intl:eng", IDS_STATUSBAR_LAYOUT_USA_EXTENDED}, | |
| 187 {"xkb:us:colemak:eng", IDS_STATUSBAR_LAYOUT_USA_COLEMAK}, | |
| 188 {"xkb:us:dvorak:eng", IDS_STATUSBAR_LAYOUT_USA_DVORAK}, | |
| 189 {"xkb:us:dvp:eng", IDS_STATUSBAR_LAYOUT_USA_DVP}, | |
| 190 {"xkb:us:intl:eng", IDS_STATUSBAR_LAYOUT_USA_INTERNATIONAL}, | |
| 191 {"xkb:us:intl:nld", IDS_STATUSBAR_LAYOUT_USA_INTERNATIONAL}, | |
| 192 {"xkb:us:intl:por", IDS_STATUSBAR_LAYOUT_USA_INTERNATIONAL}, | |
| 193 {"xkb:us:workman-intl:eng", IDS_STATUSBAR_LAYOUT_USA_WORKMAN_INTERNATIONAL}, | |
| 194 {"xkb:us:workman:eng", IDS_STATUSBAR_LAYOUT_USA_WORKMAN}, | |
| 195 }; | |
| 196 const size_t kEnglishToResourceIdArraySize = | |
| 197 arraysize(kEnglishToResourceIdArray); | |
| 198 | |
| 199 const struct InputMethodNameMap { | |
| 200 const char* message_name; | |
| 201 int resource_id; | |
| 202 bool operator<(const InputMethodNameMap& other) const { | |
| 203 return strcmp(message_name, other.message_name) < 0; | |
| 204 } | |
| 205 } kInputMethodNameMap[] = { | |
| 206 {"__MSG_INPUTMETHOD_ARRAY__", IDS_IME_NAME_INPUTMETHOD_ARRAY}, | |
| 207 {"__MSG_INPUTMETHOD_CANGJIE__", IDS_IME_NAME_INPUTMETHOD_CANGJIE}, | |
| 208 {"__MSG_INPUTMETHOD_CANTONESE__", IDS_IME_NAME_INPUTMETHOD_CANTONESE}, | |
| 209 {"__MSG_INPUTMETHOD_DAYI__", IDS_IME_NAME_INPUTMETHOD_DAYI}, | |
| 210 {"__MSG_INPUTMETHOD_HANGUL_2_SET__", IDS_IME_NAME_INPUTMETHOD_HANGUL_2_SET}, | |
| 211 {"__MSG_INPUTMETHOD_HANGUL_3_SET_390__", | |
| 212 IDS_IME_NAME_INPUTMETHOD_HANGUL_3_SET_390}, | |
| 213 {"__MSG_INPUTMETHOD_HANGUL_3_SET_FINAL__", | |
| 214 IDS_IME_NAME_INPUTMETHOD_HANGUL_3_SET_FINAL}, | |
| 215 {"__MSG_INPUTMETHOD_HANGUL_3_SET_NO_SHIFT__", | |
| 216 IDS_IME_NAME_INPUTMETHOD_HANGUL_3_SET_NO_SHIFT}, | |
| 217 {"__MSG_INPUTMETHOD_HANGUL_AHNMATAE__", | |
| 218 IDS_IME_NAME_INPUTMETHOD_HANGUL_AHNMATAE}, | |
| 219 {"__MSG_INPUTMETHOD_HANGUL_ROMAJA__", | |
| 220 IDS_IME_NAME_INPUTMETHOD_HANGUL_ROMAJA}, | |
| 221 {"__MSG_INPUTMETHOD_HANGUL__", IDS_IME_NAME_INPUTMETHOD_HANGUL}, | |
| 222 {"__MSG_INPUTMETHOD_MOZC_JP__", IDS_IME_NAME_INPUTMETHOD_MOZC_JP}, | |
| 223 {"__MSG_INPUTMETHOD_MOZC_US__", IDS_IME_NAME_INPUTMETHOD_MOZC_US}, | |
| 224 {"__MSG_INPUTMETHOD_PINYIN__", IDS_IME_NAME_INPUTMETHOD_PINYIN}, | |
| 225 {"__MSG_INPUTMETHOD_QUICK__", IDS_IME_NAME_INPUTMETHOD_QUICK}, | |
| 226 {"__MSG_INPUTMETHOD_TRADITIONAL_PINYIN__", | |
| 227 IDS_IME_NAME_INPUTMETHOD_TRADITIONAL_PINYIN}, | |
| 228 {"__MSG_INPUTMETHOD_WUBI__", IDS_IME_NAME_INPUTMETHOD_WUBI}, | |
| 229 {"__MSG_INPUTMETHOD_ZHUYIN__", IDS_IME_NAME_INPUTMETHOD_ZHUYIN}, | |
| 230 {"__MSG_KEYBOARD_ARABIC__", IDS_IME_NAME_KEYBOARD_ARABIC}, | |
| 231 {"__MSG_KEYBOARD_ARMENIAN_PHONETIC__", | |
| 232 IDS_IME_NAME_KEYBOARD_ARMENIAN_PHONETIC}, | |
| 233 {"__MSG_KEYBOARD_BELARUSIAN__", IDS_IME_NAME_KEYBOARD_BELARUSIAN}, | |
| 234 {"__MSG_KEYBOARD_BELGIAN__", IDS_IME_NAME_KEYBOARD_BELGIAN}, | |
| 235 {"__MSG_KEYBOARD_BENGALI_PHONETIC__", | |
| 236 IDS_IME_NAME_KEYBOARD_BENGALI_PHONETIC}, | |
| 237 {"__MSG_KEYBOARD_BRAZILIAN__", IDS_IME_NAME_KEYBOARD_BRAZILIAN}, | |
| 238 {"__MSG_KEYBOARD_BULGARIAN_PHONETIC__", | |
| 239 IDS_IME_NAME_KEYBOARD_BULGARIAN_PHONETIC}, | |
| 240 {"__MSG_KEYBOARD_BULGARIAN__", IDS_IME_NAME_KEYBOARD_BULGARIAN}, | |
| 241 {"__MSG_KEYBOARD_CANADIAN_ENGLISH__", | |
| 242 IDS_IME_NAME_KEYBOARD_CANADIAN_ENGLISH}, | |
| 243 {"__MSG_KEYBOARD_CANADIAN_FRENCH__", IDS_IME_NAME_KEYBOARD_CANADIAN_FRENCH}, | |
| 244 {"__MSG_KEYBOARD_CANADIAN_MULTILINGUAL__", | |
| 245 IDS_IME_NAME_KEYBOARD_CANADIAN_MULTILINGUAL}, | |
| 246 {"__MSG_KEYBOARD_CATALAN__", IDS_IME_NAME_KEYBOARD_CATALAN}, | |
| 247 {"__MSG_KEYBOARD_CROATIAN__", IDS_IME_NAME_KEYBOARD_CROATIAN}, | |
| 248 {"__MSG_KEYBOARD_CZECH_QWERTY__", IDS_IME_NAME_KEYBOARD_CZECH_QWERTY}, | |
| 249 {"__MSG_KEYBOARD_CZECH__", IDS_IME_NAME_KEYBOARD_CZECH}, | |
| 250 {"__MSG_KEYBOARD_DANISH__", IDS_IME_NAME_KEYBOARD_DANISH}, | |
| 251 {"__MSG_KEYBOARD_DEVANAGARI_PHONETIC__", | |
| 252 IDS_IME_NAME_KEYBOARD_DEVANAGARI_PHONETIC}, | |
| 253 {"__MSG_KEYBOARD_ESTONIAN__", IDS_IME_NAME_KEYBOARD_ESTONIAN}, | |
| 254 {"__MSG_KEYBOARD_ETHIOPIC__", IDS_IME_NAME_KEYBOARD_ETHIOPIC}, | |
| 255 {"__MSG_KEYBOARD_FAROESE__", IDS_IME_NAME_KEYBOARD_FAROESE}, | |
| 256 {"__MSG_KEYBOARD_FINNISH__", IDS_IME_NAME_KEYBOARD_FINNISH}, | |
| 257 {"__MSG_KEYBOARD_FRENCH_BEPO__", IDS_IME_NAME_KEYBOARD_FRENCH_BEPO}, | |
| 258 {"__MSG_KEYBOARD_FRENCH__", IDS_IME_NAME_KEYBOARD_FRENCH}, | |
| 259 {"__MSG_KEYBOARD_GEORGIAN__", IDS_IME_NAME_KEYBOARD_GEORGIAN}, | |
| 260 {"__MSG_KEYBOARD_GERMAN_NEO_2__", IDS_IME_NAME_KEYBOARD_GERMAN_NEO_2}, | |
| 261 {"__MSG_KEYBOARD_GERMAN__", IDS_IME_NAME_KEYBOARD_GERMAN}, | |
| 262 {"__MSG_KEYBOARD_GREEK__", IDS_IME_NAME_KEYBOARD_GREEK}, | |
| 263 {"__MSG_KEYBOARD_GUJARATI_PHONETIC__", | |
| 264 IDS_IME_NAME_KEYBOARD_GUJARATI_PHONETIC}, | |
| 265 {"__MSG_KEYBOARD_HEBREW__", IDS_IME_NAME_KEYBOARD_HEBREW}, | |
| 266 {"__MSG_KEYBOARD_HUNGARIAN_QWERTY__", | |
| 267 IDS_IME_NAME_KEYBOARD_HUNGARIAN_QWERTY}, | |
| 268 {"__MSG_KEYBOARD_HUNGARIAN__", IDS_IME_NAME_KEYBOARD_HUNGARIAN}, | |
| 269 {"__MSG_KEYBOARD_ICELANDIC__", IDS_IME_NAME_KEYBOARD_ICELANDIC}, | |
| 270 {"__MSG_KEYBOARD_IRISH__", IDS_IME_NAME_KEYBOARD_IRISH}, | |
| 271 {"__MSG_KEYBOARD_ITALIAN__", IDS_IME_NAME_KEYBOARD_ITALIAN}, | |
| 272 {"__MSG_KEYBOARD_JAPANESE__", IDS_IME_NAME_KEYBOARD_JAPANESE}, | |
| 273 {"__MSG_KEYBOARD_KANNADA_PHONETIC__", | |
| 274 IDS_IME_NAME_KEYBOARD_KANNADA_PHONETIC}, | |
| 275 {"__MSG_KEYBOARD_KAZAKH__", IDS_IME_NAME_KEYBOARD_KAZAKH}, | |
| 276 {"__MSG_KEYBOARD_KHMER__", IDS_IME_NAME_KEYBOARD_KHMER}, | |
| 277 {"__MSG_KEYBOARD_LAO__", IDS_IME_NAME_KEYBOARD_LAO}, | |
| 278 {"__MSG_KEYBOARD_LATIN_AMERICAN__", IDS_IME_NAME_KEYBOARD_LATIN_AMERICAN}, | |
| 279 {"__MSG_KEYBOARD_LATVIAN__", IDS_IME_NAME_KEYBOARD_LATVIAN}, | |
| 280 {"__MSG_KEYBOARD_LITHUANIAN__", IDS_IME_NAME_KEYBOARD_LITHUANIAN}, | |
| 281 {"__MSG_KEYBOARD_MACEDONIAN__", IDS_IME_NAME_KEYBOARD_MACEDONIAN}, | |
| 282 {"__MSG_KEYBOARD_MALAYALAM_PHONETIC__", | |
| 283 IDS_IME_NAME_KEYBOARD_MALAYALAM_PHONETIC}, | |
| 284 {"__MSG_KEYBOARD_MALTESE__", IDS_IME_NAME_KEYBOARD_MALTESE}, | |
| 285 {"__MSG_KEYBOARD_MONGOLIAN__", IDS_IME_NAME_KEYBOARD_MONGOLIAN}, | |
| 286 {"__MSG_KEYBOARD_MYANMAR_MYANSAN__", IDS_IME_NAME_KEYBOARD_MYANMAR_MYANSAN}, | |
| 287 {"__MSG_KEYBOARD_MYANMAR__", IDS_IME_NAME_KEYBOARD_MYANMAR}, | |
| 288 {"__MSG_KEYBOARD_NEPALI_INSCRIPT__", IDS_IME_NAME_KEYBOARD_NEPALI_INSCRIPT}, | |
| 289 {"__MSG_KEYBOARD_NEPALI_PHONETIC__", IDS_IME_NAME_KEYBOARD_NEPALI_PHONETIC}, | |
| 290 {"__MSG_KEYBOARD_NETHERLANDS__", IDS_IME_NAME_KEYBOARD_NETHERLANDS}, | |
| 291 {"__MSG_KEYBOARD_NORWEGIAN__", IDS_IME_NAME_KEYBOARD_NORWEGIAN}, | |
| 292 {"__MSG_KEYBOARD_PERSIAN__", IDS_IME_NAME_KEYBOARD_PERSIAN}, | |
| 293 {"__MSG_KEYBOARD_POLISH__", IDS_IME_NAME_KEYBOARD_POLISH}, | |
| 294 {"__MSG_KEYBOARD_PORTUGUESE__", IDS_IME_NAME_KEYBOARD_PORTUGUESE}, | |
| 295 {"__MSG_KEYBOARD_ROMANIAN_STANDARD__", | |
| 296 IDS_IME_NAME_KEYBOARD_ROMANIAN_STANDARD}, | |
| 297 {"__MSG_KEYBOARD_ROMANIAN__", IDS_IME_NAME_KEYBOARD_ROMANIAN}, | |
| 298 {"__MSG_KEYBOARD_RUSSIAN_PHONETIC_AATSEEL__", | |
| 299 IDS_IME_NAME_KEYBOARD_RUSSIAN_PHONETIC_AATSEEL}, | |
| 300 {"__MSG_KEYBOARD_RUSSIAN_PHONETIC_YAZHERT__", | |
| 301 IDS_IME_NAME_KEYBOARD_RUSSIAN_PHONETIC_YAZHERT}, | |
| 302 {"__MSG_KEYBOARD_RUSSIAN_PHONETIC__", | |
| 303 IDS_IME_NAME_KEYBOARD_RUSSIAN_PHONETIC}, | |
| 304 {"__MSG_KEYBOARD_RUSSIAN__", IDS_IME_NAME_KEYBOARD_RUSSIAN}, | |
| 305 {"__MSG_KEYBOARD_SERBIAN__", IDS_IME_NAME_KEYBOARD_SERBIAN}, | |
| 306 {"__MSG_KEYBOARD_SINHALA__", IDS_IME_NAME_KEYBOARD_SINHALA}, | |
| 307 {"__MSG_KEYBOARD_SLOVAK__", IDS_IME_NAME_KEYBOARD_SLOVAK}, | |
| 308 {"__MSG_KEYBOARD_SLOVENIAN__", IDS_IME_NAME_KEYBOARD_SLOVENIAN}, | |
| 309 {"__MSG_KEYBOARD_SORANIKURDISH_AR__", | |
| 310 IDS_IME_NAME_KEYBOARD_SORANIKURDISH_AR}, | |
| 311 {"__MSG_KEYBOARD_SORANIKURDISH_EN__", | |
| 312 IDS_IME_NAME_KEYBOARD_SORANIKURDISH_EN}, | |
| 313 {"__MSG_KEYBOARD_SPANISH__", IDS_IME_NAME_KEYBOARD_SPANISH}, | |
| 314 {"__MSG_KEYBOARD_SWEDISH__", IDS_IME_NAME_KEYBOARD_SWEDISH}, | |
| 315 {"__MSG_KEYBOARD_SWISS_FRENCH__", IDS_IME_NAME_KEYBOARD_SWISS_FRENCH}, | |
| 316 {"__MSG_KEYBOARD_SWISS__", IDS_IME_NAME_KEYBOARD_SWISS}, | |
| 317 {"__MSG_KEYBOARD_TAMIL_INSCRIPT__", IDS_IME_NAME_KEYBOARD_TAMIL_INSCRIPT}, | |
| 318 {"__MSG_KEYBOARD_TAMIL_ITRANS__", IDS_IME_NAME_KEYBOARD_TAMIL_ITRANS}, | |
| 319 {"__MSG_KEYBOARD_TAMIL_PHONETIC__", IDS_IME_NAME_KEYBOARD_TAMIL_PHONETIC}, | |
| 320 {"__MSG_KEYBOARD_TAMIL_TAMIL99__", IDS_IME_NAME_KEYBOARD_TAMIL_TAMIL99}, | |
| 321 {"__MSG_KEYBOARD_TAMIL_TYPEWRITER__", | |
| 322 IDS_IME_NAME_KEYBOARD_TAMIL_TYPEWRITER}, | |
| 323 {"__MSG_KEYBOARD_TELUGU_PHONETIC__", IDS_IME_NAME_KEYBOARD_TELUGU_PHONETIC}, | |
| 324 {"__MSG_KEYBOARD_THAI_KEDMANEE__", IDS_IME_NAME_KEYBOARD_THAI_KEDMANEE}, | |
| 325 {"__MSG_KEYBOARD_THAI_PATTACHOTE__", IDS_IME_NAME_KEYBOARD_THAI_PATTACHOTE}, | |
| 326 {"__MSG_KEYBOARD_THAI_TIS__", IDS_IME_NAME_KEYBOARD_THAI_TIS}, | |
| 327 {"__MSG_KEYBOARD_TURKISH_F__", IDS_IME_NAME_KEYBOARD_TURKISH_F}, | |
| 328 {"__MSG_KEYBOARD_TURKISH__", IDS_IME_NAME_KEYBOARD_TURKISH}, | |
| 329 {"__MSG_KEYBOARD_UKRAINIAN__", IDS_IME_NAME_KEYBOARD_UKRAINIAN}, | |
| 330 {"__MSG_KEYBOARD_UK_DVORAK__", IDS_IME_NAME_KEYBOARD_UK_DVORAK}, | |
| 331 {"__MSG_KEYBOARD_UK__", IDS_IME_NAME_KEYBOARD_UK}, | |
| 332 {"__MSG_KEYBOARD_US_COLEMAK__", IDS_IME_NAME_KEYBOARD_US_COLEMAK}, | |
| 333 {"__MSG_KEYBOARD_US_DVORAK__", IDS_IME_NAME_KEYBOARD_US_DVORAK}, | |
| 334 {"__MSG_KEYBOARD_US_DVP__", IDS_IME_NAME_KEYBOARD_US_DVP}, | |
| 335 {"__MSG_KEYBOARD_US_EXTENDED__", IDS_IME_NAME_KEYBOARD_US_EXTENDED}, | |
| 336 {"__MSG_KEYBOARD_US_INTERNATIONAL__", | |
| 337 IDS_IME_NAME_KEYBOARD_US_INTERNATIONAL}, | |
| 338 {"__MSG_KEYBOARD_US_WORKMAN_INTERNATIONAL__", | |
| 339 IDS_IME_NAME_KEYBOARD_US_WORKMAN_INTERNATIONAL}, | |
| 340 {"__MSG_KEYBOARD_US_WORKMAN__", IDS_IME_NAME_KEYBOARD_US_WORKMAN}, | |
| 341 {"__MSG_KEYBOARD_US__", IDS_IME_NAME_KEYBOARD_US}, | |
| 342 {"__MSG_KEYBOARD_VIETNAMESE_TCVN__", IDS_IME_NAME_KEYBOARD_VIETNAMESE_TCVN}, | |
| 343 {"__MSG_KEYBOARD_VIETNAMESE_TELEX__", | |
| 344 IDS_IME_NAME_KEYBOARD_VIETNAMESE_TELEX}, | |
| 345 {"__MSG_KEYBOARD_VIETNAMESE_VIQR__", IDS_IME_NAME_KEYBOARD_VIETNAMESE_VIQR}, | |
| 346 {"__MSG_KEYBOARD_VIETNAMESE_VNI__", IDS_IME_NAME_KEYBOARD_VIETNAMESE_VNI}, | |
| 347 {"__MSG_TRANSLITERATION_AM__", IDS_IME_NAME_TRANSLITERATION_AM}, | |
| 348 {"__MSG_TRANSLITERATION_AR__", IDS_IME_NAME_TRANSLITERATION_AR}, | |
| 349 {"__MSG_TRANSLITERATION_BN__", IDS_IME_NAME_TRANSLITERATION_BN}, | |
| 350 {"__MSG_TRANSLITERATION_EL__", IDS_IME_NAME_TRANSLITERATION_EL}, | |
| 351 {"__MSG_TRANSLITERATION_FA__", IDS_IME_NAME_TRANSLITERATION_FA}, | |
| 352 {"__MSG_TRANSLITERATION_GU__", IDS_IME_NAME_TRANSLITERATION_GU}, | |
| 353 {"__MSG_TRANSLITERATION_HE__", IDS_IME_NAME_TRANSLITERATION_HE}, | |
| 354 {"__MSG_TRANSLITERATION_HI__", IDS_IME_NAME_TRANSLITERATION_HI}, | |
| 355 {"__MSG_TRANSLITERATION_KN__", IDS_IME_NAME_TRANSLITERATION_KN}, | |
| 356 {"__MSG_TRANSLITERATION_ML__", IDS_IME_NAME_TRANSLITERATION_ML}, | |
| 357 {"__MSG_TRANSLITERATION_MR__", IDS_IME_NAME_TRANSLITERATION_MR}, | |
| 358 {"__MSG_TRANSLITERATION_NE__", IDS_IME_NAME_TRANSLITERATION_NE}, | |
| 359 {"__MSG_TRANSLITERATION_OR__", IDS_IME_NAME_TRANSLITERATION_OR}, | |
| 360 {"__MSG_TRANSLITERATION_PA__", IDS_IME_NAME_TRANSLITERATION_PA}, | |
| 361 {"__MSG_TRANSLITERATION_SA__", IDS_IME_NAME_TRANSLITERATION_SA}, | |
| 362 {"__MSG_TRANSLITERATION_SR__", IDS_IME_NAME_TRANSLITERATION_SR}, | |
| 363 {"__MSG_TRANSLITERATION_TA__", IDS_IME_NAME_TRANSLITERATION_TA}, | |
| 364 {"__MSG_TRANSLITERATION_TE__", IDS_IME_NAME_TRANSLITERATION_TE}, | |
| 365 {"__MSG_TRANSLITERATION_TI__", IDS_IME_NAME_TRANSLITERATION_TI}, | |
| 366 {"__MSG_TRANSLITERATION_UR__", IDS_IME_NAME_TRANSLITERATION_UR}, | |
| 367 }; | |
| 368 | |
| 369 } // namespace | |
| 370 | |
| 371 namespace chromeos { | |
| 372 | |
| 373 namespace input_method { | |
| 374 | |
| 375 InputMethodUtil::InputMethodUtil(InputMethodDelegate* delegate) | |
| 376 : delegate_(delegate) { | |
| 377 InputMethodDescriptors default_input_methods; | |
| 378 default_input_methods.push_back(GetFallbackInputMethodDescriptor()); | |
| 379 ResetInputMethods(default_input_methods); | |
| 380 | |
| 381 // Initialize a map from English string to Chrome string resource ID as well. | |
| 382 for (size_t i = 0; i < kEnglishToResourceIdArraySize; ++i) { | |
| 383 const EnglishToResouceId& map_entry = kEnglishToResourceIdArray[i]; | |
| 384 const bool result = english_to_resource_id_.insert(std::make_pair( | |
| 385 map_entry.english_string_from_ibus, map_entry.resource_id)).second; | |
| 386 DCHECK(result) << "Duplicated string is found: " | |
| 387 << map_entry.english_string_from_ibus; | |
| 388 } | |
| 389 } | |
| 390 | |
| 391 InputMethodUtil::~InputMethodUtil() { | |
| 392 } | |
| 393 | |
| 394 std::string InputMethodUtil::GetLocalizedDisplayName( | |
| 395 const InputMethodDescriptor& descriptor) const { | |
| 396 // Localizes the input method name. | |
| 397 const std::string& disp = descriptor.name(); | |
| 398 if (base::StartsWith(disp, "__MSG_", base::CompareCase::SENSITIVE)) { | |
| 399 const InputMethodNameMap* map = kInputMethodNameMap; | |
| 400 size_t map_size = arraysize(kInputMethodNameMap); | |
| 401 std::string name = base::ToUpperASCII(disp); | |
| 402 const InputMethodNameMap map_key = {name.c_str(), 0}; | |
| 403 const InputMethodNameMap* p = | |
| 404 std::lower_bound(map, map + map_size, map_key); | |
| 405 if (p != map + map_size && name == p->message_name) | |
| 406 return l10n_util::GetStringUTF8(p->resource_id); | |
| 407 } | |
| 408 return disp; | |
| 409 } | |
| 410 | |
| 411 bool InputMethodUtil::TranslateStringInternal( | |
| 412 const std::string& english_string, base::string16 *out_string) const { | |
| 413 DCHECK(out_string); | |
| 414 // |english_string| could be an input method id. So legacy xkb id is required | |
| 415 // to get the translated string. | |
| 416 std::string key_string = extension_ime_util::MaybeGetLegacyXkbId( | |
| 417 english_string); | |
| 418 HashType::const_iterator iter = english_to_resource_id_.find(key_string); | |
| 419 | |
| 420 if (iter == english_to_resource_id_.end()) { | |
| 421 // TODO(yusukes): Write Autotest which checks if all display names and all | |
| 422 // property names for supported input methods are listed in the resource | |
| 423 // ID array (crosbug.com/4572). | |
| 424 LOG(ERROR) << "Resource ID is not found for: " << english_string | |
| 425 << ", " << key_string; | |
| 426 return false; | |
| 427 } | |
| 428 | |
| 429 *out_string = delegate_->GetLocalizedString(iter->second); | |
| 430 return true; | |
| 431 } | |
| 432 | |
| 433 base::string16 InputMethodUtil::TranslateString( | |
| 434 const std::string& english_string) const { | |
| 435 base::string16 localized_string; | |
| 436 if (TranslateStringInternal(english_string, &localized_string)) { | |
| 437 return localized_string; | |
| 438 } | |
| 439 return base::UTF8ToUTF16(english_string); | |
| 440 } | |
| 441 | |
| 442 bool InputMethodUtil::IsValidInputMethodId( | |
| 443 const std::string& input_method_id) const { | |
| 444 // We can't check the component extension is whilelisted or not here because | |
| 445 // it might not be initialized. | |
| 446 return GetInputMethodDescriptorFromId(input_method_id) != NULL || | |
| 447 extension_ime_util::IsComponentExtensionIME(input_method_id); | |
| 448 } | |
| 449 | |
| 450 // static | |
| 451 bool InputMethodUtil::IsKeyboardLayout(const std::string& input_method_id) { | |
| 452 return base::StartsWith(input_method_id, "xkb:", | |
| 453 base::CompareCase::INSENSITIVE_ASCII) || | |
| 454 extension_ime_util::IsKeyboardLayoutExtension(input_method_id); | |
| 455 } | |
| 456 | |
| 457 std::string InputMethodUtil::GetKeyboardLayoutName( | |
| 458 const std::string& input_method_id) const { | |
| 459 InputMethodIdToDescriptorMap::const_iterator iter | |
| 460 = id_to_descriptor_.find(input_method_id); | |
| 461 return (iter == id_to_descriptor_.end()) ? | |
| 462 "" : iter->second.GetPreferredKeyboardLayout(); | |
| 463 } | |
| 464 | |
| 465 std::string InputMethodUtil::GetInputMethodDisplayNameFromId( | |
| 466 const std::string& input_method_id) const { | |
| 467 base::string16 display_name; | |
| 468 if (!extension_ime_util::IsExtensionIME(input_method_id) && | |
| 469 TranslateStringInternal(input_method_id, &display_name)) { | |
| 470 return base::UTF16ToUTF8(display_name); | |
| 471 } | |
| 472 const InputMethodDescriptor* descriptor = | |
| 473 GetInputMethodDescriptorFromId(input_method_id); | |
| 474 if (descriptor) | |
| 475 return GetLocalizedDisplayName(*descriptor); | |
| 476 // Return an empty string if the input method is not found. | |
| 477 return ""; | |
| 478 } | |
| 479 | |
| 480 base::string16 InputMethodUtil::GetInputMethodShortName( | |
| 481 const InputMethodDescriptor& input_method) const { | |
| 482 // TODO(shuchen): remove this method, as the client can directly use | |
| 483 // input_method.GetIndicator(). | |
| 484 return base::UTF8ToUTF16(input_method.GetIndicator()); | |
| 485 } | |
| 486 | |
| 487 base::string16 InputMethodUtil::GetInputMethodMediumName( | |
| 488 const InputMethodDescriptor& input_method) const { | |
| 489 // For the "Your input method has changed to..." bubble. In most cases | |
| 490 // it uses the same name as the short name, unless found in a table | |
| 491 // for medium length names. | |
| 492 for (size_t i = 0; i < kMappingImeIdToMediumLenNameResourceIdLen; ++i) { | |
| 493 if (extension_ime_util::GetInputMethodIDByEngineID( | |
| 494 kMappingImeIdToMediumLenNameResourceId[i].engine_id) == | |
| 495 input_method.id()) { | |
| 496 return delegate_->GetLocalizedString( | |
| 497 kMappingImeIdToMediumLenNameResourceId[i].resource_id); | |
| 498 } | |
| 499 } | |
| 500 return GetInputMethodShortName(input_method); | |
| 501 } | |
| 502 | |
| 503 base::string16 InputMethodUtil::GetInputMethodLongNameInternal( | |
| 504 const InputMethodDescriptor& input_method, bool short_name) const { | |
| 505 std::string localized_display_name = GetLocalizedDisplayName(input_method); | |
| 506 if (!localized_display_name.empty() && !IsKeyboardLayout(input_method.id())) { | |
| 507 // If the descriptor has a name, use it. | |
| 508 return base::UTF8ToUTF16(localized_display_name); | |
| 509 } | |
| 510 | |
| 511 // We don't show language here. Name of keyboard layout or input method | |
| 512 // usually imply (or explicitly include) its language. | |
| 513 // Special case for German, French and Dutch: these languages have multiple | |
| 514 // keyboard layouts and share the same layout of keyboard (Belgian). We need | |
| 515 // to show explicitly the language for the layout. | |
| 516 DCHECK(!input_method.language_codes().empty()); | |
| 517 const std::string language_code = input_method.language_codes().at(0); | |
| 518 | |
| 519 base::string16 text = (short_name || localized_display_name.empty()) | |
| 520 ? TranslateString(input_method.id()) | |
| 521 : base::UTF8ToUTF16(localized_display_name); | |
| 522 if (language_code == "de" || language_code == "fr" || language_code == "nl") { | |
| 523 const base::string16 language_name = delegate_->GetDisplayLanguageName( | |
| 524 language_code); | |
| 525 text = language_name + base::UTF8ToUTF16(" - ") + text; | |
| 526 } | |
| 527 | |
| 528 DCHECK(!text.empty()); | |
| 529 return text; | |
| 530 } | |
| 531 | |
| 532 | |
| 533 base::string16 InputMethodUtil::GetInputMethodLongNameStripped( | |
| 534 const InputMethodDescriptor& input_method) const { | |
| 535 return GetInputMethodLongNameInternal(input_method, true /* short_name */); | |
| 536 } | |
| 537 | |
| 538 base::string16 InputMethodUtil::GetInputMethodLongName( | |
| 539 const InputMethodDescriptor& input_method) const { | |
| 540 return GetInputMethodLongNameInternal(input_method, false /* short_name */); | |
| 541 } | |
| 542 | |
| 543 const InputMethodDescriptor* InputMethodUtil::GetInputMethodDescriptorFromId( | |
| 544 const std::string& input_method_id) const { | |
| 545 InputMethodIdToDescriptorMap::const_iterator iter = | |
| 546 id_to_descriptor_.find(input_method_id); | |
| 547 if (iter == id_to_descriptor_.end()) | |
| 548 return NULL; | |
| 549 return &(iter->second); | |
| 550 } | |
| 551 | |
| 552 bool InputMethodUtil::GetInputMethodIdsFromLanguageCode( | |
| 553 const std::string& normalized_language_code, | |
| 554 InputMethodType type, | |
| 555 std::vector<std::string>* out_input_method_ids) const { | |
| 556 return GetInputMethodIdsFromLanguageCodeInternal( | |
| 557 language_code_to_ids_, | |
| 558 normalized_language_code, type, out_input_method_ids); | |
| 559 } | |
| 560 | |
| 561 bool InputMethodUtil::GetInputMethodIdsFromLanguageCodeInternal( | |
| 562 const std::multimap<std::string, std::string>& language_code_to_ids, | |
| 563 const std::string& normalized_language_code, | |
| 564 InputMethodType type, | |
| 565 std::vector<std::string>* out_input_method_ids) const { | |
| 566 DCHECK(out_input_method_ids); | |
| 567 out_input_method_ids->clear(); | |
| 568 | |
| 569 bool result = false; | |
| 570 std::pair<LanguageCodeToIdsMap::const_iterator, | |
| 571 LanguageCodeToIdsMap::const_iterator> range = | |
| 572 language_code_to_ids.equal_range(normalized_language_code); | |
| 573 for (LanguageCodeToIdsMap::const_iterator iter = range.first; | |
| 574 iter != range.second; ++iter) { | |
| 575 const std::string& input_method_id = iter->second; | |
| 576 if ((type == kAllInputMethods) || IsKeyboardLayout(input_method_id)) { | |
| 577 out_input_method_ids->push_back(input_method_id); | |
| 578 result = true; | |
| 579 } | |
| 580 } | |
| 581 if ((type == kAllInputMethods) && !result) { | |
| 582 DVLOG(1) << "Unknown language code: " << normalized_language_code; | |
| 583 } | |
| 584 return result; | |
| 585 } | |
| 586 | |
| 587 void InputMethodUtil::GetFirstLoginInputMethodIds( | |
| 588 const std::string& language_code, | |
| 589 const InputMethodDescriptor& preferred_input_method, | |
| 590 std::vector<std::string>* out_input_method_ids) const { | |
| 591 out_input_method_ids->clear(); | |
| 592 | |
| 593 // First, add the preferred keyboard layout (e.g. one used on the login | |
| 594 // screen or set in UserContext when starting a public session). | |
| 595 out_input_method_ids->push_back(preferred_input_method.id()); | |
| 596 | |
| 597 const std::string current_layout | |
| 598 = preferred_input_method.GetPreferredKeyboardLayout(); | |
| 599 for (size_t i = 0; i < arraysize(kDefaultInputMethodRecommendation); | |
| 600 ++i) { | |
| 601 if (kDefaultInputMethodRecommendation[i].locale == language_code && ( | |
| 602 !kDefaultInputMethodRecommendation[i].layout[0] || | |
| 603 kDefaultInputMethodRecommendation[i].layout == current_layout)) { | |
| 604 out_input_method_ids->push_back( | |
| 605 extension_ime_util::GetInputMethodIDByEngineID( | |
| 606 kDefaultInputMethodRecommendation[i].engine_id)); | |
| 607 return; | |
| 608 } | |
| 609 } | |
| 610 | |
| 611 std::vector<std::string> input_method_ids; | |
| 612 GetInputMethodIdsFromLanguageCode( | |
| 613 language_code, kAllInputMethods, &input_method_ids); | |
| 614 // Uses the first input method as the most popular one. | |
| 615 if (input_method_ids.size() > 0 && | |
| 616 preferred_input_method.id() != input_method_ids[0]) { | |
| 617 out_input_method_ids->push_back(input_method_ids[0]); | |
| 618 } | |
| 619 } | |
| 620 | |
| 621 void InputMethodUtil::GetLanguageCodesFromInputMethodIds( | |
| 622 const std::vector<std::string>& input_method_ids, | |
| 623 std::vector<std::string>* out_language_codes) const { | |
| 624 out_language_codes->clear(); | |
| 625 | |
| 626 for (size_t i = 0; i < input_method_ids.size(); ++i) { | |
| 627 const std::string& input_method_id = input_method_ids[i]; | |
| 628 const InputMethodDescriptor* input_method = | |
| 629 GetInputMethodDescriptorFromId(input_method_id); | |
| 630 if (!input_method) { | |
| 631 DVLOG(1) << "Unknown input method ID: " << input_method_ids[i]; | |
| 632 continue; | |
| 633 } | |
| 634 DCHECK(!input_method->language_codes().empty()); | |
| 635 const std::string language_code = input_method->language_codes().at(0); | |
| 636 // Add it if it's not already present. | |
| 637 if (std::count(out_language_codes->begin(), out_language_codes->end(), | |
| 638 language_code) == 0) { | |
| 639 out_language_codes->push_back(language_code); | |
| 640 } | |
| 641 } | |
| 642 } | |
| 643 | |
| 644 std::string InputMethodUtil::GetLanguageDefaultInputMethodId( | |
| 645 const std::string& language_code) { | |
| 646 std::vector<std::string> candidates; | |
| 647 GetInputMethodIdsFromLanguageCode( | |
| 648 language_code, input_method::kKeyboardLayoutsOnly, &candidates); | |
| 649 if (candidates.size()) | |
| 650 return candidates.front(); | |
| 651 | |
| 652 return std::string(); | |
| 653 } | |
| 654 | |
| 655 std::string InputMethodUtil::MigrateInputMethod( | |
| 656 const std::string& input_method_id) { | |
| 657 std::string engine_id = input_method_id; | |
| 658 // Migrates some Engine IDs from VPD. | |
| 659 for (size_t j = 0; j < arraysize(kEngineIdMigrationMap); ++j) { | |
| 660 size_t pos = engine_id.find(kEngineIdMigrationMap[j][0]); | |
| 661 if (pos == 0) { | |
| 662 engine_id.replace(0, | |
| 663 strlen(kEngineIdMigrationMap[j][0]), | |
| 664 kEngineIdMigrationMap[j][1]); | |
| 665 break; | |
| 666 } | |
| 667 } | |
| 668 // Migrates the extension IDs. | |
| 669 std::string id = | |
| 670 extension_ime_util::GetInputMethodIDByEngineID(engine_id); | |
| 671 if (extension_ime_util::IsComponentExtensionIME(id)) { | |
| 672 std::string id_new = extension_ime_util::GetInputMethodIDByEngineID( | |
| 673 extension_ime_util::GetComponentIDByInputMethodID(id)); | |
| 674 if (extension_ime_util::IsComponentExtensionIME(id_new)) | |
| 675 id = id_new; | |
| 676 } | |
| 677 return id; | |
| 678 } | |
| 679 | |
| 680 bool InputMethodUtil::MigrateInputMethods( | |
| 681 std::vector<std::string>* input_method_ids) { | |
| 682 bool rewritten = false; | |
| 683 std::vector<std::string>& ids = *input_method_ids; | |
| 684 for (size_t i = 0; i < ids.size(); ++i) { | |
| 685 std::string id = MigrateInputMethod(ids[i]); | |
| 686 if (id != ids[i]) { | |
| 687 ids[i] = id; | |
| 688 rewritten = true; | |
| 689 } | |
| 690 } | |
| 691 if (rewritten) { | |
| 692 // Removes the duplicates. | |
| 693 std::vector<std::string> new_ids; | |
| 694 std::unordered_set<std::string> ids_set; | |
| 695 for (size_t i = 0; i < ids.size(); ++i) { | |
| 696 if (ids_set.find(ids[i]) == ids_set.end()) | |
| 697 new_ids.push_back(ids[i]); | |
| 698 ids_set.insert(ids[i]); | |
| 699 } | |
| 700 ids.swap(new_ids); | |
| 701 } | |
| 702 return rewritten; | |
| 703 } | |
| 704 | |
| 705 void InputMethodUtil::UpdateHardwareLayoutCache() { | |
| 706 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 707 hardware_layouts_.clear(); | |
| 708 hardware_login_layouts_.clear(); | |
| 709 if (cached_hardware_layouts_.empty()) { | |
| 710 cached_hardware_layouts_ = | |
| 711 base::SplitString(delegate_->GetHardwareKeyboardLayouts(), ",", | |
| 712 base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY); | |
| 713 } | |
| 714 hardware_layouts_ = cached_hardware_layouts_; | |
| 715 MigrateInputMethods(&hardware_layouts_); | |
| 716 | |
| 717 bool has_xkb = false; | |
| 718 for (size_t i = 0; i < hardware_layouts_.size(); ++i) { | |
| 719 if (IsLoginKeyboard(hardware_layouts_[i])) | |
| 720 hardware_login_layouts_.push_back(hardware_layouts_[i]); | |
| 721 if (extension_ime_util::IsKeyboardLayoutExtension(hardware_layouts_[i])) | |
| 722 has_xkb = true; | |
| 723 } | |
| 724 | |
| 725 if (hardware_login_layouts_.empty()) { | |
| 726 // This is totally fine if |hardware_layouts_| is empty. The hardware | |
| 727 // keyboard layout is not stored if startup_manifest.json | |
| 728 // (OEM customization data) is not present (ex. Cr48 doen't have that file). | |
| 729 // So need to make sure |hardware_login_layouts_| is not empty, and | |
| 730 // |hardware_layouts_| contains at least one login layout. | |
| 731 std::string fallback_id = GetFallbackInputMethodDescriptor().id(); | |
| 732 hardware_login_layouts_.push_back(fallback_id); | |
| 733 // If has XKB input method, it means the XKB input method is | |
| 734 // non-login-able. Therefore, add the fallback to the hardware layouts. | |
| 735 // If has no XKB input method, then it is up to the VPD to set the correct | |
| 736 // hardware input methods. | |
| 737 // Examples: | |
| 738 // 1) Arabic transliteration input method cannot be used to input Latin | |
| 739 // characters. So the VPD should be "xkb:us::eng,t13n:ar". | |
| 740 // 2) Korean input method can be used to input Latin characters. So the | |
| 741 // VPD should be "ime:ko:hangul". See chrome-os-partner:48623. | |
| 742 // 3) Russian keyboard cannot be used to input Latin characters, but it is | |
| 743 // XKB input method. So the VPD can be "xkb:ru::rus". | |
| 744 if (hardware_layouts_.empty() || has_xkb) | |
| 745 hardware_layouts_.insert(hardware_layouts_.begin(), fallback_id); | |
| 746 } | |
| 747 } | |
| 748 | |
| 749 void InputMethodUtil::SetHardwareKeyboardLayoutForTesting( | |
| 750 const std::string& layout) { | |
| 751 delegate_->SetHardwareKeyboardLayoutForTesting(layout); | |
| 752 cached_hardware_layouts_.clear(); | |
| 753 UpdateHardwareLayoutCache(); | |
| 754 } | |
| 755 | |
| 756 const std::vector<std::string>& | |
| 757 InputMethodUtil::GetHardwareInputMethodIds() { | |
| 758 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 759 UpdateHardwareLayoutCache(); | |
| 760 return hardware_layouts_; | |
| 761 } | |
| 762 | |
| 763 const std::vector<std::string>& | |
| 764 InputMethodUtil::GetHardwareLoginInputMethodIds() { | |
| 765 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 766 UpdateHardwareLayoutCache(); | |
| 767 return hardware_login_layouts_; | |
| 768 } | |
| 769 | |
| 770 bool InputMethodUtil::IsLoginKeyboard(const std::string& input_method_id) | |
| 771 const { | |
| 772 const InputMethodDescriptor* ime = | |
| 773 GetInputMethodDescriptorFromId(input_method_id); | |
| 774 return ime ? ime->is_login_keyboard() : false; | |
| 775 } | |
| 776 | |
| 777 void InputMethodUtil::AppendInputMethods(const InputMethodDescriptors& imes) { | |
| 778 for (size_t i = 0; i < imes.size(); ++i) { | |
| 779 const InputMethodDescriptor& input_method = imes[i]; | |
| 780 DCHECK(!input_method.language_codes().empty()); | |
| 781 const std::vector<std::string>& language_codes = | |
| 782 input_method.language_codes(); | |
| 783 id_to_descriptor_[input_method.id()] = input_method; | |
| 784 | |
| 785 typedef LanguageCodeToIdsMap::const_iterator It; | |
| 786 for (size_t j = 0; j < language_codes.size(); ++j) { | |
| 787 std::pair<It, It> range = | |
| 788 language_code_to_ids_.equal_range(language_codes[j]); | |
| 789 It it = range.first; | |
| 790 for (; it != range.second; ++it) { | |
| 791 if (it->second == input_method.id()) | |
| 792 break; | |
| 793 } | |
| 794 if (it == range.second) | |
| 795 language_code_to_ids_.insert( | |
| 796 std::make_pair(language_codes[j], input_method.id())); | |
| 797 } | |
| 798 } | |
| 799 } | |
| 800 | |
| 801 void InputMethodUtil::ResetInputMethods(const InputMethodDescriptors& imes) { | |
| 802 // Clear the existing maps. | |
| 803 language_code_to_ids_.clear(); | |
| 804 id_to_descriptor_.clear(); | |
| 805 | |
| 806 AppendInputMethods(imes); | |
| 807 } | |
| 808 | |
| 809 void InputMethodUtil::InitXkbInputMethodsForTesting( | |
| 810 const InputMethodDescriptors& imes) { | |
| 811 cached_hardware_layouts_.clear(); | |
| 812 ResetInputMethods(imes); | |
| 813 } | |
| 814 | |
| 815 const InputMethodUtil::InputMethodIdToDescriptorMap& | |
| 816 InputMethodUtil::GetIdToDesciptorMapForTesting() { | |
| 817 return id_to_descriptor_; | |
| 818 } | |
| 819 | |
| 820 InputMethodDescriptor InputMethodUtil::GetFallbackInputMethodDescriptor() { | |
| 821 std::vector<std::string> layouts; | |
| 822 layouts.push_back("us"); | |
| 823 std::vector<std::string> languages; | |
| 824 languages.push_back("en-US"); | |
| 825 return InputMethodDescriptor( | |
| 826 extension_ime_util::GetInputMethodIDByEngineID("xkb:us::eng"), | |
| 827 "", | |
| 828 "US", | |
| 829 layouts, | |
| 830 languages, | |
| 831 true, // login keyboard. | |
| 832 GURL(), // options page, not available. | |
| 833 GURL()); // input view page, not available. | |
| 834 } | |
| 835 | |
| 836 } // namespace input_method | |
| 837 } // namespace chromeos | |
| OLD | NEW |