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 3 // found in the LICENSE file. 4 5 #include "chrome/browser/chromeos/preferences.h" 6 7 #include "base/i18n/time_formatting.h" 8 #include "base/metrics/histogram.h" 9 #include "base/string_split.h" 10 #include "base/string_util.h" 11 #include "base/utf_string_conversions.h" 12 #include "chrome/browser/chromeos/cros/cros_library.h" 13 #include "chrome/browser/chromeos/cros/input_method_library.h" 14 #include "chrome/browser/chromeos/cros/power_library.h" 15 #include "chrome/browser/chromeos/cros/touchpad_library.h" 16 #include "chrome/browser/chromeos/input_method/input_method_util.h" 17 #include "chrome/browser/chromeos/input_method/xkeyboard.h" 18 #include "chrome/browser/chromeos/login/login_utils.h" 19 #include "chrome/browser/prefs/pref_member.h" 20 #include "chrome/browser/prefs/pref_service.h" 21 #include "chrome/common/pref_names.h" 22 #include "content/common/notification_details.h" 23 #include "content/common/notification_source.h" 24 #include "content/common/notification_type.h" 25 #include "unicode/timezone.h" 26 27 namespace chromeos { 28 29 static const char kFallbackInputMethodLocale[] = "en-US"; 30 31 Preferences::Preferences() {} 32 33 Preferences::~Preferences() {} 34 35 // static 36 void Preferences::RegisterUserPrefs(PrefService* prefs) { 37 prefs->RegisterBooleanPref(prefs::kTapToClickEnabled, false); 38 prefs->RegisterBooleanPref(prefs::kLabsMediaplayerEnabled, false); 39 prefs->RegisterBooleanPref(prefs::kLabsAdvancedFilesystemEnabled, false); 40 // Check if the accessibility pref is already registered, which can happen 41 // in WizardController::RegisterPrefs. We still want to try to register 42 // the pref here in case of Chrome/Linux with ChromeOS=1. 43 if (prefs->FindPreference(prefs::kAccessibilityEnabled) == NULL) { 44 prefs->RegisterBooleanPref(prefs::kAccessibilityEnabled, false); 45 } 46 prefs->RegisterIntegerPref(prefs::kTouchpadSensitivity, 3); 47 // Set the default based on the hour clock type of the current locale. 48 prefs->RegisterBooleanPref(prefs::kUse24HourClock, 49 base::GetHourClockType() == base::k24HourClock); 50 prefs->RegisterStringPref(prefs::kLanguageCurrentInputMethod, ""); 51 prefs->RegisterStringPref(prefs::kLanguagePreviousInputMethod, ""); 52 prefs->RegisterStringPref(prefs::kLanguageHotkeyNextEngineInMenu, 53 language_prefs::kHotkeyNextEngineInMenu); 54 prefs->RegisterStringPref(prefs::kLanguageHotkeyPreviousEngine, 55 language_prefs::kHotkeyPreviousEngine); 56 prefs->RegisterStringPref(prefs::kLanguagePreferredLanguages, 57 kFallbackInputMethodLocale); 58 prefs->RegisterStringPref( 59 prefs::kLanguagePreloadEngines, 60 input_method::GetHardwareInputMethodId()); 61 for (size_t i = 0; i < language_prefs::kNumChewingBooleanPrefs; ++i) { 62 prefs->RegisterBooleanPref( 63 language_prefs::kChewingBooleanPrefs[i].pref_name, 64 language_prefs::kChewingBooleanPrefs[i].default_pref_value); 65 } 66 for (size_t i = 0; i < language_prefs::kNumChewingMultipleChoicePrefs; ++i) { 67 prefs->RegisterStringPref( 68 language_prefs::kChewingMultipleChoicePrefs[i].pref_name, 69 language_prefs::kChewingMultipleChoicePrefs[i].default_pref_value); 70 } 71 prefs->RegisterIntegerPref( 72 language_prefs::kChewingHsuSelKeyType.pref_name, 73 language_prefs::kChewingHsuSelKeyType.default_pref_value); 74 75 for (size_t i = 0; i < language_prefs::kNumChewingIntegerPrefs; ++i) { 76 prefs->RegisterIntegerPref( 77 language_prefs::kChewingIntegerPrefs[i].pref_name, 78 language_prefs::kChewingIntegerPrefs[i].default_pref_value); 79 } 80 prefs->RegisterStringPref( 81 prefs::kLanguageHangulKeyboard, 82 language_prefs::kHangulKeyboardNameIDPairs[0].keyboard_id); 83 prefs->RegisterStringPref(prefs::kLanguageHangulHanjaKeys, 84 language_prefs::kHangulHanjaKeys); 85 for (size_t i = 0; i < language_prefs::kNumPinyinBooleanPrefs; ++i) { 86 prefs->RegisterBooleanPref( 87 language_prefs::kPinyinBooleanPrefs[i].pref_name, 88 language_prefs::kPinyinBooleanPrefs[i].default_pref_value); 89 } 90 for (size_t i = 0; i < language_prefs::kNumPinyinIntegerPrefs; ++i) { 91 prefs->RegisterIntegerPref( 92 language_prefs::kPinyinIntegerPrefs[i].pref_name, 93 language_prefs::kPinyinIntegerPrefs[i].default_pref_value); 94 } 95 prefs->RegisterIntegerPref( 96 language_prefs::kPinyinDoublePinyinSchema.pref_name, 97 language_prefs::kPinyinDoublePinyinSchema.default_pref_value); 98 99 for (size_t i = 0; i < language_prefs::kNumMozcBooleanPrefs; ++i) { 100 prefs->RegisterBooleanPref( 101 language_prefs::kMozcBooleanPrefs[i].pref_name, 102 language_prefs::kMozcBooleanPrefs[i].default_pref_value); 103 } 104 for (size_t i = 0; i < language_prefs::kNumMozcMultipleChoicePrefs; ++i) { 105 prefs->RegisterStringPref( 106 language_prefs::kMozcMultipleChoicePrefs[i].pref_name, 107 language_prefs::kMozcMultipleChoicePrefs[i].default_pref_value); 108 } 109 for (size_t i = 0; i < language_prefs::kNumMozcIntegerPrefs; ++i) { 110 prefs->RegisterIntegerPref( 111 language_prefs::kMozcIntegerPrefs[i].pref_name, 112 language_prefs::kMozcIntegerPrefs[i].default_pref_value); 113 } 114 prefs->RegisterIntegerPref(prefs::kLanguageXkbRemapSearchKeyTo, 115 input_method::kSearchKey); 116 prefs->RegisterIntegerPref(prefs::kLanguageXkbRemapControlKeyTo, 117 input_method::kLeftControlKey); 118 prefs->RegisterIntegerPref(prefs::kLanguageXkbRemapAltKeyTo, 119 input_method::kLeftAltKey); 120 prefs->RegisterBooleanPref(prefs::kLanguageXkbAutoRepeatEnabled, true); 121 prefs->RegisterIntegerPref(prefs::kLanguageXkbAutoRepeatDelay, 122 language_prefs::kXkbAutoRepeatDelayInMs); 123 prefs->RegisterIntegerPref(prefs::kLanguageXkbAutoRepeatInterval, 124 language_prefs::kXkbAutoRepeatIntervalInMs); 125 126 // Screen lock default to off. 127 prefs->RegisterBooleanPref(prefs::kEnableScreenLock, false); 128 129 // Mobile plan notifications default to on. 130 prefs->RegisterBooleanPref(prefs::kShowPlanNotifications, true); 131 132 // 3G first-time usage promo will be shown at least once. 133 prefs->RegisterBooleanPref(prefs::kShow3gPromoNotification, true); 134 135 // Carrier deal notification shown count defaults to 0. 136 prefs->RegisterIntegerPref(prefs::kCarrierDealPromoShown, 0); 137 138 // The map of timestamps of the last used file browser handlers. 139 prefs->RegisterDictionaryPref(prefs::kLastUsedFileBrowserHandlers); 140 } 141 142 void Preferences::Init(PrefService* prefs) { 143 tap_to_click_enabled_.Init(prefs::kTapToClickEnabled, prefs, this); 144 accessibility_enabled_.Init(prefs::kAccessibilityEnabled, prefs, this); 145 sensitivity_.Init(prefs::kTouchpadSensitivity, prefs, this); 146 use_24hour_clock_.Init(prefs::kUse24HourClock, prefs, this); 147 language_hotkey_next_engine_in_menu_.Init( 148 prefs::kLanguageHotkeyNextEngineInMenu, prefs, this); 149 language_hotkey_previous_engine_.Init( 150 prefs::kLanguageHotkeyPreviousEngine, prefs, this); 151 language_preferred_languages_.Init(prefs::kLanguagePreferredLanguages, 152 prefs, this); 153 language_preload_engines_.Init(prefs::kLanguagePreloadEngines, prefs, this); 154 for (size_t i = 0; i < language_prefs::kNumChewingBooleanPrefs; ++i) { 155 language_chewing_boolean_prefs_[i].Init( 156 language_prefs::kChewingBooleanPrefs[i].pref_name, prefs, this); 157 } 158 for (size_t i = 0; i < language_prefs::kNumChewingMultipleChoicePrefs; ++i) { 159 language_chewing_multiple_choice_prefs_[i].Init( 160 language_prefs::kChewingMultipleChoicePrefs[i].pref_name, prefs, this); 161 } 162 language_chewing_hsu_sel_key_type_.Init( 163 language_prefs::kChewingHsuSelKeyType.pref_name, prefs, this); 164 for (size_t i = 0; i < language_prefs::kNumChewingIntegerPrefs; ++i) { 165 language_chewing_integer_prefs_[i].Init( 166 language_prefs::kChewingIntegerPrefs[i].pref_name, prefs, this); 167 } 168 language_hangul_keyboard_.Init(prefs::kLanguageHangulKeyboard, prefs, this); 169 language_hangul_hanja_keys_.Init( 170 prefs::kLanguageHangulHanjaKeys, prefs, this); 171 for (size_t i = 0; i < language_prefs::kNumPinyinBooleanPrefs; ++i) { 172 language_pinyin_boolean_prefs_[i].Init( 173 language_prefs::kPinyinBooleanPrefs[i].pref_name, prefs, this); 174 } 175 for (size_t i = 0; i < language_prefs::kNumPinyinIntegerPrefs; ++i) { 176 language_pinyin_int_prefs_[i].Init( 177 language_prefs::kPinyinIntegerPrefs[i].pref_name, prefs, this); 178 } 179 language_pinyin_double_pinyin_schema_.Init( 180 language_prefs::kPinyinDoublePinyinSchema.pref_name, prefs, this); 181 for (size_t i = 0; i < language_prefs::kNumMozcBooleanPrefs; ++i) { 182 language_mozc_boolean_prefs_[i].Init( 183 language_prefs::kMozcBooleanPrefs[i].pref_name, prefs, this); 184 } 185 for (size_t i = 0; i < language_prefs::kNumMozcMultipleChoicePrefs; ++i) { 186 language_mozc_multiple_choice_prefs_[i].Init( 187 language_prefs::kMozcMultipleChoicePrefs[i].pref_name, prefs, this); 188 } 189 for (size_t i = 0; i < language_prefs::kNumMozcIntegerPrefs; ++i) { 190 language_mozc_integer_prefs_[i].Init( 191 language_prefs::kMozcIntegerPrefs[i].pref_name, prefs, this); 192 } 193 language_xkb_remap_search_key_to_.Init( 194 prefs::kLanguageXkbRemapSearchKeyTo, prefs, this); 195 language_xkb_remap_control_key_to_.Init( 196 prefs::kLanguageXkbRemapControlKeyTo, prefs, this); 197 language_xkb_remap_alt_key_to_.Init( 198 prefs::kLanguageXkbRemapAltKeyTo, prefs, this); 199 language_xkb_auto_repeat_enabled_.Init( 200 prefs::kLanguageXkbAutoRepeatEnabled, prefs, this); 201 language_xkb_auto_repeat_delay_pref_.Init( 202 prefs::kLanguageXkbAutoRepeatDelay, prefs, this); 203 language_xkb_auto_repeat_interval_pref_.Init( 204 prefs::kLanguageXkbAutoRepeatInterval, prefs, this); 205 206 enable_screen_lock_.Init(prefs::kEnableScreenLock, prefs, this); 207 208 // Initialize preferences to currently saved state. 209 NotifyPrefChanged(NULL); 210 211 // If a guest is logged in, initialize the prefs as if this is the first 212 // login. 213 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kGuestSession)) { 214 LoginUtils::Get()->SetFirstLoginPrefs(prefs); 215 } 216 } 217 218 void Preferences::Observe(NotificationType type, 219 const NotificationSource& source, 220 const NotificationDetails& details) { 221 if (type == NotificationType::PREF_CHANGED) 222 NotifyPrefChanged(Details<std::string>(details).ptr()); 223 } 224 225 void Preferences::NotifyPrefChanged(const std::string* pref_name) { 226 if (!pref_name || *pref_name == prefs::kTapToClickEnabled) { 227 bool enabled = tap_to_click_enabled_.GetValue(); 228 CrosLibrary::Get()->GetTouchpadLibrary()->SetTapToClick(enabled); 229 if (pref_name) 230 UMA_HISTOGRAM_BOOLEAN("Touchpad.TapToClick.Changed", enabled); 231 else 232 UMA_HISTOGRAM_BOOLEAN("Touchpad.TapToClick.Started", enabled); 233 } 234 if (!pref_name || *pref_name == prefs::kTouchpadSensitivity) { 235 int sensitivity = sensitivity_.GetValue(); 236 CrosLibrary::Get()->GetTouchpadLibrary()->SetSensitivity(sensitivity); 237 if (pref_name) { 238 UMA_HISTOGRAM_CUSTOM_COUNTS( 239 "Touchpad.Sensitivity.Changed", sensitivity, 1, 5, 5); 240 } else { 241 UMA_HISTOGRAM_CUSTOM_COUNTS( 242 "Touchpad.Sensitivity.Started", sensitivity, 1, 5, 5); 243 } 244 } 245 246 // We don't handle prefs::kLanguageCurrentInputMethod and PreviousInputMethod 247 // here. 248 249 if (!pref_name || *pref_name == prefs::kLanguageHotkeyNextEngineInMenu) { 250 SetLanguageConfigStringListAsCSV( 251 language_prefs::kHotKeySectionName, 252 language_prefs::kNextEngineInMenuConfigName, 253 language_hotkey_next_engine_in_menu_.GetValue()); 254 } 255 if (!pref_name || *pref_name == prefs::kLanguageHotkeyPreviousEngine) { 256 SetLanguageConfigStringListAsCSV( 257 language_prefs::kHotKeySectionName, 258 language_prefs::kPreviousEngineConfigName, 259 language_hotkey_previous_engine_.GetValue()); 260 } 261 if (!pref_name || *pref_name == prefs::kLanguagePreferredLanguages) { 262 // Unlike kLanguagePreloadEngines and some other input method 263 // preferencs, we don't need to send this to ibus-daemon. 264 } 265 266 // Here, we set up the the modifier key mapping. This has to be done 267 // before changing the current keyboard layout, so that the modifier key 268 // preference is properly preserved. For this reason, we should do this 269 // before setting preload engines, that could change the current 270 // keyboard layout as needed. 271 if (!pref_name || (*pref_name == prefs::kLanguageXkbRemapSearchKeyTo || 272 *pref_name == prefs::kLanguageXkbRemapControlKeyTo || 273 *pref_name == prefs::kLanguageXkbRemapAltKeyTo)) { 274 UpdateModifierKeyMapping(); 275 } 276 if (!pref_name || *pref_name == prefs::kLanguageXkbAutoRepeatEnabled) { 277 const bool enabled = language_xkb_auto_repeat_enabled_.GetValue(); 278 input_method::SetAutoRepeatEnabled(enabled); 279 } 280 if (!pref_name || ((*pref_name == prefs::kLanguageXkbAutoRepeatDelay) || 281 (*pref_name == prefs::kLanguageXkbAutoRepeatInterval))) { 282 UpdateAutoRepeatRate(); 283 } 284 285 if (!pref_name || *pref_name == prefs::kLanguagePreloadEngines) { 286 SetLanguageConfigStringListAsCSV(language_prefs::kGeneralSectionName, 287 language_prefs::kPreloadEnginesConfigName, 288 language_preload_engines_.GetValue()); 289 } 290 for (size_t i = 0; i < language_prefs::kNumChewingBooleanPrefs; ++i) { 291 if (!pref_name || 292 *pref_name == language_prefs::kChewingBooleanPrefs[i].pref_name) { 293 SetLanguageConfigBoolean( 294 language_prefs::kChewingSectionName, 295 language_prefs::kChewingBooleanPrefs[i].ibus_config_name, 296 language_chewing_boolean_prefs_[i].GetValue()); 297 } 298 } 299 for (size_t i = 0; i < language_prefs::kNumChewingMultipleChoicePrefs; ++i) { 300 if (!pref_name || 301 *pref_name == 302 language_prefs::kChewingMultipleChoicePrefs[i].pref_name) { 303 SetLanguageConfigString( 304 language_prefs::kChewingSectionName, 305 language_prefs::kChewingMultipleChoicePrefs[i].ibus_config_name, 306 language_chewing_multiple_choice_prefs_[i].GetValue()); 307 } 308 } 309 if (!pref_name || 310 *pref_name == language_prefs::kChewingHsuSelKeyType.pref_name) { 311 SetLanguageConfigInteger( 312 language_prefs::kChewingSectionName, 313 language_prefs::kChewingHsuSelKeyType.ibus_config_name, 314 language_chewing_hsu_sel_key_type_.GetValue()); 315 } 316 for (size_t i = 0; i < language_prefs::kNumChewingIntegerPrefs; ++i) { 317 if (!pref_name || 318 *pref_name == language_prefs::kChewingIntegerPrefs[i].pref_name) { 319 SetLanguageConfigInteger( 320 language_prefs::kChewingSectionName, 321 language_prefs::kChewingIntegerPrefs[i].ibus_config_name, 322 language_chewing_integer_prefs_[i].GetValue()); 323 } 324 } 325 if (!pref_name || 326 *pref_name == prefs::kLanguageHangulKeyboard) { 327 SetLanguageConfigString(language_prefs::kHangulSectionName, 328 language_prefs::kHangulKeyboardConfigName, 329 language_hangul_keyboard_.GetValue()); 330 } 331 if (!pref_name || *pref_name == prefs::kLanguageHangulHanjaKeys) { 332 SetLanguageConfigString(language_prefs::kHangulSectionName, 333 language_prefs::kHangulHanjaKeysConfigName, 334 language_hangul_hanja_keys_.GetValue()); 335 } 336 for (size_t i = 0; i < language_prefs::kNumPinyinBooleanPrefs; ++i) { 337 if (!pref_name || 338 *pref_name == language_prefs::kPinyinBooleanPrefs[i].pref_name) { 339 SetLanguageConfigBoolean( 340 language_prefs::kPinyinSectionName, 341 language_prefs::kPinyinBooleanPrefs[i].ibus_config_name, 342 language_pinyin_boolean_prefs_[i].GetValue()); 343 } 344 } 345 for (size_t i = 0; i < language_prefs::kNumPinyinIntegerPrefs; ++i) { 346 if (!pref_name || 347 *pref_name == language_prefs::kPinyinIntegerPrefs[i].pref_name) { 348 SetLanguageConfigInteger( 349 language_prefs::kPinyinSectionName, 350 language_prefs::kPinyinIntegerPrefs[i].ibus_config_name, 351 language_pinyin_int_prefs_[i].GetValue()); 352 } 353 } 354 if (!pref_name || 355 *pref_name == language_prefs::kPinyinDoublePinyinSchema.pref_name) { 356 SetLanguageConfigInteger( 357 language_prefs::kPinyinSectionName, 358 language_prefs::kPinyinDoublePinyinSchema.ibus_config_name, 359 language_pinyin_double_pinyin_schema_.GetValue()); 360 } 361 for (size_t i = 0; i < language_prefs::kNumMozcBooleanPrefs; ++i) { 362 if (!pref_name || 363 *pref_name == language_prefs::kMozcBooleanPrefs[i].pref_name) { 364 SetLanguageConfigBoolean( 365 language_prefs::kMozcSectionName, 366 language_prefs::kMozcBooleanPrefs[i].ibus_config_name, 367 language_mozc_boolean_prefs_[i].GetValue()); 368 } 369 } 370 for (size_t i = 0; i < language_prefs::kNumMozcMultipleChoicePrefs; ++i) { 371 if (!pref_name || 372 *pref_name == language_prefs::kMozcMultipleChoicePrefs[i].pref_name) { 373 SetLanguageConfigString( 374 language_prefs::kMozcSectionName, 375 language_prefs::kMozcMultipleChoicePrefs[i].ibus_config_name, 376 language_mozc_multiple_choice_prefs_[i].GetValue()); 377 } 378 } 379 for (size_t i = 0; i < language_prefs::kNumMozcIntegerPrefs; ++i) { 380 if (!pref_name || 381 *pref_name == language_prefs::kMozcIntegerPrefs[i].pref_name) { 382 SetLanguageConfigInteger( 383 language_prefs::kMozcSectionName, 384 language_prefs::kMozcIntegerPrefs[i].ibus_config_name, 385 language_mozc_integer_prefs_[i].GetValue()); 386 } 387 } 388 389 // Init or update power manager config. 390 if (!pref_name || *pref_name == prefs::kEnableScreenLock) { 391 CrosLibrary::Get()->GetPowerLibrary()->EnableScreenLock( 392 enable_screen_lock_.GetValue()); 393 } 394 } 395 396 void Preferences::SetLanguageConfigBoolean(const char* section, 397 const char* name, 398 bool value) { 399 ImeConfigValue config; 400 config.type = ImeConfigValue::kValueTypeBool; 401 config.bool_value = value; 402 CrosLibrary::Get()->GetInputMethodLibrary()-> 403 SetImeConfig(section, name, config); 404 } 405 406 void Preferences::SetLanguageConfigInteger(const char* section, 407 const char* name, 408 int value) { 409 ImeConfigValue config; 410 config.type = ImeConfigValue::kValueTypeInt; 411 config.int_value = value; 412 CrosLibrary::Get()->GetInputMethodLibrary()-> 413 SetImeConfig(section, name, config); 414 } 415 416 void Preferences::SetLanguageConfigString(const char* section, 417 const char* name, 418 const std::string& value) { 419 ImeConfigValue config; 420 config.type = ImeConfigValue::kValueTypeString; 421 config.string_value = value; 422 CrosLibrary::Get()->GetInputMethodLibrary()-> 423 SetImeConfig(section, name, config); 424 } 425 426 void Preferences::SetLanguageConfigStringList( 427 const char* section, 428 const char* name, 429 const std::vector<std::string>& values) { 430 ImeConfigValue config; 431 config.type = ImeConfigValue::kValueTypeStringList; 432 for (size_t i = 0; i < values.size(); ++i) 433 config.string_list_value.push_back(values[i]); 434 435 CrosLibrary::Get()->GetInputMethodLibrary()-> 436 SetImeConfig(section, name, config); 437 } 438 439 void Preferences::SetLanguageConfigStringListAsCSV(const char* section, 440 const char* name, 441 const std::string& value) { 442 VLOG(1) << "Setting " << name << " to '" << value << "'"; 443 444 std::vector<std::string> split_values; 445 if (!value.empty()) 446 base::SplitString(value, ',', &split_values); 447 448 // We should call the cros API even when |value| is empty, to disable default 449 // config. 450 SetLanguageConfigStringList(section, name, split_values); 451 } 452 453 void Preferences::UpdateModifierKeyMapping() { 454 const int search_remap = language_xkb_remap_search_key_to_.GetValue(); 455 const int control_remap = language_xkb_remap_control_key_to_.GetValue(); 456 const int alt_remap = language_xkb_remap_alt_key_to_.GetValue(); 457 if ((search_remap < input_method::kNumModifierKeys) && (search_remap >= 0) && 458 (control_remap < input_method::kNumModifierKeys) && 459 (control_remap >= 0) && 460 (alt_remap < input_method::kNumModifierKeys) && (alt_remap >= 0)) { 461 input_method::ModifierMap modifier_map; 462 modifier_map.push_back( 463 input_method::ModifierKeyPair( 464 input_method::kSearchKey, 465 input_method::ModifierKey(search_remap))); 466 modifier_map.push_back( 467 input_method::ModifierKeyPair( 468 input_method::kLeftControlKey, 469 input_method::ModifierKey(control_remap))); 470 modifier_map.push_back( 471 input_method::ModifierKeyPair( 472 input_method::kLeftAltKey, 473 input_method::ModifierKey(alt_remap))); 474 input_method::RemapModifierKeys(modifier_map); 475 } else { 476 LOG(ERROR) << "Failed to remap modifier keys. Unexpected value(s): " 477 << search_remap << ", " << control_remap << ", " << alt_remap; 478 } 479 } 480 481 void Preferences::UpdateAutoRepeatRate() { 482 input_method::AutoRepeatRate rate; 483 rate.initial_delay_in_ms = language_xkb_auto_repeat_delay_pref_.GetValue(); 484 rate.repeat_interval_in_ms = 485 language_xkb_auto_repeat_interval_pref_.GetValue(); 486 DCHECK(rate.initial_delay_in_ms > 0); 487 DCHECK(rate.repeat_interval_in_ms > 0); 488 input_method::SetAutoRepeatRate(rate); 489 } 490 491 } // namespace chromeos 492