| // Copyright 2022 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "ash/system/input_device_settings/input_device_settings_controller_impl.h" |
| |
| #include <iterator> |
| #include <memory> |
| #include <vector> |
| |
| #include "ash/constants/ash_features.h" |
| #include "ash/constants/ash_pref_names.h" |
| #include "ash/events/event_rewriter_controller_impl.h" |
| #include "ash/events/peripheral_customization_event_rewriter.h" |
| #include "ash/public/cpp/accelerators_util.h" |
| #include "ash/public/mojom/input_device_settings.mojom-forward.h" |
| #include "ash/public/mojom/input_device_settings.mojom-shared.h" |
| #include "ash/public/mojom/input_device_settings.mojom.h" |
| #include "ash/session/session_controller_impl.h" |
| #include "ash/shell.h" |
| #include "ash/strings/grit/ash_strings.h" |
| #include "ash/system/input_device_settings/input_device_duplicate_id_finder.h" |
| #include "ash/system/input_device_settings/input_device_key_alias_manager.h" |
| #include "ash/system/input_device_settings/input_device_notifier.h" |
| #include "ash/system/input_device_settings/input_device_settings_defaults.h" |
| #include "ash/system/input_device_settings/input_device_settings_metadata.h" |
| #include "ash/system/input_device_settings/input_device_settings_notification_controller.h" |
| #include "ash/system/input_device_settings/input_device_settings_policy_handler.h" |
| #include "ash/system/input_device_settings/input_device_settings_pref_names.h" |
| #include "ash/system/input_device_settings/input_device_settings_utils.h" |
| #include "ash/system/input_device_settings/pref_handlers/graphics_tablet_pref_handler_impl.h" |
| #include "ash/system/input_device_settings/pref_handlers/keyboard_pref_handler_impl.h" |
| #include "ash/system/input_device_settings/pref_handlers/mouse_pref_handler_impl.h" |
| #include "ash/system/input_device_settings/pref_handlers/pointing_stick_pref_handler_impl.h" |
| #include "ash/system/input_device_settings/pref_handlers/touchpad_pref_handler_impl.h" |
| #include "base/containers/contains.h" |
| #include "base/containers/flat_map.h" |
| #include "base/functional/bind.h" |
| #include "base/functional/callback_forward.h" |
| #include "base/metrics/histogram_functions.h" |
| #include "base/strings/strcat.h" |
| #include "base/strings/string_number_conversions.h" |
| #include "base/strings/to_string.h" |
| #include "base/strings/utf_string_conversions.h" |
| #include "base/task/sequenced_task_runner.h" |
| #include "base/values.h" |
| #include "components/account_id/account_id.h" |
| #include "components/pref_registry/pref_registry_syncable.h" |
| #include "components/prefs/pref_change_registrar.h" |
| #include "components/prefs/pref_registry_simple.h" |
| #include "components/prefs/pref_service.h" |
| #include "components/user_manager/known_user.h" |
| #include "mojo/public/cpp/bindings/struct_ptr.h" |
| #include "ui/base/l10n/l10n_util.h" |
| #include "ui/base/ui_base_features.h" |
| #include "ui/events/ash/keyboard_capability.h" |
| #include "ui/events/devices/input_device.h" |
| #include "ui/events/devices/keyboard_device.h" |
| #include "ui/events/devices/touchpad_device.h" |
| #include "ui/events/keycodes/dom/dom_key.h" |
| #include "ui/events/keycodes/dom/keycode_converter.h" |
| #include "ui/events/keycodes/keyboard_codes_posix.h" |
| #include "ui/events/ozone/layout/keyboard_layout_engine.h" |
| #include "ui/events/ozone/layout/keyboard_layout_engine_manager.h" |
| #include "ui/message_center/message_center.h" |
| |
| namespace ash { |
| |
| namespace { |
| |
| const int kMaxButtonNameLength = 32; |
| constexpr char kGraphicsTabletDeviceType[] = "GraphicsTablet"; |
| constexpr char kGraphicsTabletPenDeviceType[] = "GraphicsTabletPen"; |
| constexpr char kMouseDeviceType[] = "Mouse"; |
| |
| mojom::MetaKey GetMetaKeyForKeyboard(const ui::KeyboardDevice& keyboard) { |
| const auto device_type = |
| Shell::Get()->keyboard_capability()->GetDeviceType(keyboard); |
| switch (device_type) { |
| case ui::KeyboardCapability::DeviceType::kDeviceInternalKeyboard: |
| case ui::KeyboardCapability::DeviceType::kDeviceExternalChromeOsKeyboard: |
| case ui::KeyboardCapability::DeviceType::kDeviceHotrodRemote: |
| case ui::KeyboardCapability::DeviceType::kDeviceVirtualCoreKeyboard: |
| return Shell::Get()->keyboard_capability()->HasLauncherButton(keyboard) |
| ? mojom::MetaKey::kLauncher |
| : mojom::MetaKey::kSearch; |
| case ui::KeyboardCapability::DeviceType::kDeviceExternalAppleKeyboard: |
| return mojom::MetaKey::kCommand; |
| case ui::KeyboardCapability::DeviceType::kDeviceUnknown: |
| case ui::KeyboardCapability::DeviceType::kDeviceExternalGenericKeyboard: |
| case ui::KeyboardCapability::DeviceType::kDeviceExternalUnknown: |
| case ui::KeyboardCapability::DeviceType::kDeviceInternalRevenKeyboard: |
| case ui::KeyboardCapability::DeviceType:: |
| kDeviceExternalNullTopRowChromeOsKeyboard: |
| return mojom::MetaKey::kExternalMeta; |
| }; |
| } |
| |
| constexpr mojom::TopRowActionKey ConvertTopRowActionKey( |
| ui::TopRowActionKey action_key) { |
| switch (action_key) { |
| case ui::TopRowActionKey::kBack: |
| return mojom::TopRowActionKey::kBack; |
| case ui::TopRowActionKey::kForward: |
| return mojom::TopRowActionKey::kForward; |
| case ui::TopRowActionKey::kRefresh: |
| return mojom::TopRowActionKey::kRefresh; |
| case ui::TopRowActionKey::kFullscreen: |
| return mojom::TopRowActionKey::kFullscreen; |
| case ui::TopRowActionKey::kOverview: |
| return mojom::TopRowActionKey::kOverview; |
| case ui::TopRowActionKey::kScreenshot: |
| return mojom::TopRowActionKey::kScreenshot; |
| case ui::TopRowActionKey::kScreenBrightnessDown: |
| return mojom::TopRowActionKey::kScreenBrightnessDown; |
| case ui::TopRowActionKey::kScreenBrightnessUp: |
| return mojom::TopRowActionKey::kScreenBrightnessUp; |
| case ui::TopRowActionKey::kMicrophoneMute: |
| return mojom::TopRowActionKey::kMicrophoneMute; |
| case ui::TopRowActionKey::kVolumeMute: |
| return mojom::TopRowActionKey::kVolumeMute; |
| case ui::TopRowActionKey::kVolumeDown: |
| return mojom::TopRowActionKey::kVolumeDown; |
| case ui::TopRowActionKey::kVolumeUp: |
| return mojom::TopRowActionKey::kVolumeUp; |
| case ui::TopRowActionKey::kKeyboardBacklightToggle: |
| return mojom::TopRowActionKey::kKeyboardBacklightToggle; |
| case ui::TopRowActionKey::kKeyboardBacklightDown: |
| return mojom::TopRowActionKey::kKeyboardBacklightDown; |
| case ui::TopRowActionKey::kKeyboardBacklightUp: |
| return mojom::TopRowActionKey::kKeyboardBacklightUp; |
| case ui::TopRowActionKey::kNextTrack: |
| return mojom::TopRowActionKey::kNextTrack; |
| case ui::TopRowActionKey::kPreviousTrack: |
| return mojom::TopRowActionKey::kPreviousTrack; |
| case ui::TopRowActionKey::kPlayPause: |
| return mojom::TopRowActionKey::kPlayPause; |
| case ui::TopRowActionKey::kPrivacyScreenToggle: |
| return mojom::TopRowActionKey::kPrivacyScreenToggle; |
| case ui::TopRowActionKey::kAllApplications: |
| return mojom::TopRowActionKey::kAllApplications; |
| case ui::TopRowActionKey::kEmojiPicker: |
| return mojom::TopRowActionKey::kEmojiPicker; |
| case ui::TopRowActionKey::kDictation: |
| return mojom::TopRowActionKey::kDictation; |
| case ui::TopRowActionKey::kUnknown: |
| case ui::TopRowActionKey::kNone: |
| return mojom::TopRowActionKey::kNone; |
| } |
| } |
| |
| std::vector<mojom::TopRowActionKey> GetTopRowActionKeys( |
| const ui::KeyboardDevice& keyboard) { |
| const auto* action_keys = |
| Shell::Get()->keyboard_capability()->GetTopRowActionKeys(keyboard); |
| if (!action_keys) { |
| return std::vector<mojom::TopRowActionKey>(); |
| } |
| |
| std::vector<mojom::TopRowActionKey> top_row_keys; |
| for (const auto& key : *action_keys) { |
| top_row_keys.push_back(ConvertTopRowActionKey(key)); |
| } |
| return top_row_keys; |
| } |
| |
| mojom::KeyboardPtr BuildMojomKeyboard(const ui::KeyboardDevice& keyboard) { |
| mojom::KeyboardPtr mojom_keyboard = mojom::Keyboard::New(); |
| mojom_keyboard->id = keyboard.id; |
| mojom_keyboard->name = keyboard.name; |
| mojom_keyboard->device_key = |
| Shell::Get()->input_device_key_alias_manager()->GetAliasedDeviceKey( |
| keyboard); |
| mojom_keyboard->is_external = |
| keyboard.type != ui::InputDeviceType::INPUT_DEVICE_INTERNAL; |
| // Enable only when flag is enabled to avoid crashing while problem is |
| // addressed. See b/272960076 |
| if (features::IsInputDeviceSettingsSplitEnabled()) { |
| mojom_keyboard->modifier_keys = |
| Shell::Get()->keyboard_capability()->GetModifierKeys(keyboard); |
| mojom_keyboard->meta_key = GetMetaKeyForKeyboard(keyboard); |
| } |
| if (::features::AreF11AndF12ShortcutsEnabled()) { |
| mojom_keyboard->top_row_action_keys = GetTopRowActionKeys(keyboard); |
| } |
| return mojom_keyboard; |
| } |
| |
| mojom::MousePtr BuildMojomMouse( |
| const ui::InputDevice& mouse, |
| mojom::CustomizationRestriction customization_restriction, |
| mojom::MouseButtonConfig mouse_button_config) { |
| mojom::MousePtr mojom_mouse = mojom::Mouse::New(); |
| mojom_mouse->id = mouse.id; |
| mojom_mouse->name = mouse.name; |
| mojom_mouse->customization_restriction = customization_restriction; |
| mojom_mouse->mouse_button_config = mouse_button_config; |
| mojom_mouse->device_key = |
| Shell::Get()->input_device_key_alias_manager()->GetAliasedDeviceKey( |
| mouse); |
| mojom_mouse->is_external = |
| mouse.type != ui::InputDeviceType::INPUT_DEVICE_INTERNAL; |
| return mojom_mouse; |
| } |
| |
| mojom::TouchpadPtr BuildMojomTouchpad(const ui::TouchpadDevice& touchpad) { |
| mojom::TouchpadPtr mojom_touchpad = mojom::Touchpad::New(); |
| mojom_touchpad->id = touchpad.id; |
| mojom_touchpad->name = touchpad.name; |
| mojom_touchpad->device_key = |
| Shell::Get()->input_device_key_alias_manager()->GetAliasedDeviceKey( |
| touchpad); |
| mojom_touchpad->is_external = |
| touchpad.type != ui::InputDeviceType::INPUT_DEVICE_INTERNAL; |
| mojom_touchpad->is_haptic = touchpad.is_haptic; |
| return mojom_touchpad; |
| } |
| |
| mojom::PointingStickPtr BuildMojomPointingStick( |
| const ui::InputDevice& touchpad) { |
| mojom::PointingStickPtr mojom_pointing_stick = mojom::PointingStick::New(); |
| mojom_pointing_stick->id = touchpad.id; |
| mojom_pointing_stick->name = touchpad.name; |
| mojom_pointing_stick->device_key = |
| Shell::Get()->input_device_key_alias_manager()->GetAliasedDeviceKey( |
| touchpad); |
| mojom_pointing_stick->is_external = |
| touchpad.type != ui::InputDeviceType::INPUT_DEVICE_INTERNAL; |
| return mojom_pointing_stick; |
| } |
| |
| mojom::GraphicsTabletPtr BuildMojomGraphicsTablet( |
| const ui::InputDevice& graphics_tablet, |
| mojom::CustomizationRestriction customization_restriction, |
| mojom::GraphicsTabletButtonConfig graphics_tablet_button_config) { |
| mojom::GraphicsTabletPtr mojom_graphics_tablet = mojom::GraphicsTablet::New(); |
| mojom_graphics_tablet->name = graphics_tablet.name; |
| mojom_graphics_tablet->id = graphics_tablet.id; |
| mojom_graphics_tablet->customization_restriction = customization_restriction; |
| mojom_graphics_tablet->graphics_tablet_button_config = |
| graphics_tablet_button_config; |
| mojom_graphics_tablet->device_key = |
| Shell::Get()->input_device_key_alias_manager()->GetAliasedDeviceKey( |
| graphics_tablet); |
| return mojom_graphics_tablet; |
| } |
| |
| bool IsGraphicsTabletPenButton(const mojom::Button& button) { |
| return button.is_customizable_button(); |
| } |
| |
| void AddButtonToButtonRemappingList( |
| const mojom::Button& button, |
| std::vector<mojom::ButtonRemappingPtr>& button_remappings, |
| bool is_mouse_button_remapping) { |
| std::string button_name; |
| // If its a middle click, give it the default middle button name. |
| if (is_mouse_button_remapping && button.is_customizable_button() && |
| button.get_customizable_button() == mojom::CustomizableButton::kMiddle) { |
| button_name = l10n_util::GetStringUTF8( |
| IDS_SETTINGS_CUSTOMIZATION_MIDDLE_BUTTON_DEFAULT_NAME); |
| } else { |
| // Otherwise, give it the default button name indexed at the number of |
| // non-middle click buttons in `button_remappings` + 1. |
| auto iter = |
| base::ranges::find(button_remappings, |
| *mojom::Button::NewCustomizableButton( |
| mojom::CustomizableButton::kMiddle), |
| [](const mojom::ButtonRemappingPtr& remapping) { |
| return *remapping->button; |
| }); |
| |
| int button_number = button_remappings.size() + 1; |
| if (is_mouse_button_remapping && iter != button_remappings.end()) { |
| --button_number; |
| } |
| button_name = l10n_util::GetStringFUTF8( |
| IDS_SETTINGS_CUSTOMIZATION_OTHER_BUTTON_DEFAULT_NAME, |
| base::NumberToString16(button_number)); |
| } |
| |
| button_remappings.push_back(mojom::ButtonRemapping::New( |
| std::move(button_name), button.Clone(), /*remapping_action=*/nullptr)); |
| } |
| |
| // suppress_meta_fkey_rewrites must never be non-default for internal |
| // keyboards, otherwise the keyboard settings are not valid. |
| // Modifier remappings must only contain valid modifiers within the |
| // modifier_keys array. Settings are invalid if top_row_are_fkeys_policy exists |
| // and policy status is kManaged and the top_row_are_fkeys_policy's value is |
| // different from the settings top_row_are_fkeys value. F11/F12 settings |
| // should only be included for ChromeOS keyboards. |
| bool KeyboardSettingsAreValid( |
| const mojom::Keyboard& keyboard, |
| const mojom::KeyboardSettings& settings, |
| const mojom::KeyboardPolicies& keyboard_policies) { |
| for (const auto& remapping : settings.modifier_remappings) { |
| auto it = base::ranges::find(keyboard.modifier_keys, remapping.first); |
| if (it == keyboard.modifier_keys.end()) { |
| return false; |
| } |
| } |
| if (keyboard_policies.top_row_are_fkeys_policy && |
| keyboard_policies.top_row_are_fkeys_policy->policy_status == |
| mojom::PolicyStatus::kManaged && |
| keyboard_policies.top_row_are_fkeys_policy->value != |
| settings.top_row_are_fkeys) { |
| return false; |
| } |
| |
| const bool is_non_chromeos_keyboard = |
| (keyboard.meta_key != mojom::MetaKey::kLauncher && |
| keyboard.meta_key != mojom::MetaKey::kSearch); |
| if (is_non_chromeos_keyboard && ::features::AreF11AndF12ShortcutsEnabled() && |
| (settings.f11.has_value() || settings.f12.has_value())) { |
| return false; |
| } |
| |
| const bool is_meta_suppressed_setting_default = |
| settings.suppress_meta_fkey_rewrites == kDefaultSuppressMetaFKeyRewrites; |
| |
| // The suppress_meta_fkey_rewrites setting can only be changed if the device |
| // is a non-chromeos keyboard. |
| return is_non_chromeos_keyboard || is_meta_suppressed_setting_default; |
| } |
| |
| // The haptic_enabled and haptic_sensitivity are allowed to change only if the |
| // touchpad is haptic. |
| bool TouchpadSettingsAreValid(const mojom::Touchpad& touchpad, |
| const mojom::TouchpadSettings& settings) { |
| return touchpad.is_haptic || |
| (touchpad.settings->haptic_enabled == settings.haptic_enabled && |
| touchpad.settings->haptic_sensitivity == settings.haptic_sensitivity); |
| } |
| |
| // ValidateButtonRemappingList verifies if the new button remapping list has |
| // the same buttons as these in the original button remapping list and all the |
| // button remapping names should be fewer than 32 characters. |
| bool ValidateButtonRemappingList( |
| const std::vector<mojom::ButtonRemappingPtr>& original_remapping_list, |
| const std::vector<mojom::ButtonRemappingPtr>& new_remapping_list) { |
| if (original_remapping_list.size() != new_remapping_list.size()) { |
| return false; |
| } |
| |
| for (const auto& new_remapping : new_remapping_list) { |
| bool found = false; |
| for (const auto& original_remapping : original_remapping_list) { |
| if (*original_remapping->button == *new_remapping->button) { |
| found = true; |
| break; |
| } |
| } |
| if (!found || new_remapping->name.size() > kMaxButtonNameLength) { |
| return false; |
| } |
| } |
| |
| return true; |
| } |
| |
| // Valid graphics tablet settings should have the same tablet and pen buttons |
| // as these in the graphics tablet and all the button remapping names should be |
| // fewer than 32 characters. |
| bool GraphicsTabletSettingsAreValid( |
| const mojom::GraphicsTablet& graphics_tablet, |
| const mojom::GraphicsTabletSettings& settings) { |
| return ValidateButtonRemappingList( |
| graphics_tablet.settings->tablet_button_remappings, |
| settings.tablet_button_remappings) && |
| ValidateButtonRemappingList( |
| graphics_tablet.settings->pen_button_remappings, |
| settings.pen_button_remappings); |
| } |
| |
| // Valid mouse settings should have the same buttons as those |
| // in the mouse and all the button remapping names should be |
| // fewer than 32 characters. |
| bool MouseSettingsAreValid(const mojom::Mouse& mouse, |
| const mojom::MouseSettings& settings) { |
| if (!features::IsPeripheralCustomizationEnabled()) { |
| return true; |
| } |
| return ValidateButtonRemappingList(mouse.settings->button_remappings, |
| settings.button_remappings); |
| } |
| |
| void RecordSetKeyboardSettingsValidMetric(bool is_valid) { |
| base::UmaHistogramBoolean( |
| "ChromeOS.Settings.Device.Keyboard.SetSettingsSucceeded", is_valid); |
| } |
| |
| void RecordSetTouchpadSettingsValidMetric(bool is_valid) { |
| base::UmaHistogramBoolean( |
| "ChromeOS.Settings.Device.Touchpad.SetSettingsSucceeded", is_valid); |
| } |
| |
| void RecordSetPointingStickSettingsValidMetric(bool is_valid) { |
| base::UmaHistogramBoolean( |
| "ChromeOS.Settings.Device.PointingStick.SetSettingsSucceeded", is_valid); |
| } |
| |
| void RecordSetMouseSettingsValidMetric(bool is_valid) { |
| base::UmaHistogramBoolean( |
| "ChromeOS.Settings.Device.Mouse.SetSettingsSucceeded", is_valid); |
| } |
| |
| // Check the list of keyboards to see if any have the same |device_key|. |
| // If so, their settings need to also be updated. |
| template <typename T> |
| void UpdateDuplicateDeviceSettings( |
| const T& updated_device, |
| base::flat_map<InputDeviceSettingsControllerImpl::DeviceId, |
| mojo::StructPtr<T>>& devices, |
| base::RepeatingCallback<void(InputDeviceSettingsControllerImpl::DeviceId)> |
| settings_updated_callback) { |
| for (const auto& [device_id, device] : devices) { |
| if (device_id != updated_device.id && |
| device->device_key == updated_device.device_key) { |
| device->settings = updated_device.settings->Clone(); |
| settings_updated_callback.Run(device_id); |
| } |
| } |
| } |
| |
| template <typename T> |
| T* FindDevice(InputDeviceSettingsControllerImpl::DeviceId id, |
| const InputDeviceDuplicateIdFinder* deduper, |
| base::flat_map<InputDeviceSettingsControllerImpl::DeviceId, |
| mojo::StructPtr<T>>& devices_) { |
| auto iter = devices_.find(id); |
| if (iter != devices_.end()) { |
| return iter->second.get(); |
| } |
| |
| if (!deduper) { |
| return nullptr; |
| } |
| |
| const auto* duplicate_device_ids = deduper->GetDuplicateDeviceIds(id); |
| if (!duplicate_device_ids) { |
| return nullptr; |
| } |
| |
| for (const auto& duplicate_id : *duplicate_device_ids) { |
| iter = devices_.find(duplicate_id); |
| if (iter != devices_.end()) { |
| return iter->second.get(); |
| } |
| } |
| |
| return nullptr; |
| } |
| |
| void DeleteLoginScreenSettingsPrefWhenInputDeviceSettingsSplitDisabled( |
| PrefService* local_state) { |
| // local_state could be null in tests. |
| if (!local_state) { |
| return; |
| } |
| user_manager::KnownUser known_user(local_state); |
| AccountId account_id = |
| Shell::Get()->session_controller()->GetActiveAccountId(); |
| |
| known_user.SetPath(account_id, prefs::kMouseLoginScreenInternalSettingsPref, |
| std::nullopt); |
| known_user.SetPath(account_id, prefs::kMouseLoginScreenExternalSettingsPref, |
| std::nullopt); |
| known_user.SetPath(account_id, |
| prefs::kKeyboardLoginScreenInternalSettingsPref, |
| std::nullopt); |
| known_user.SetPath(account_id, |
| prefs::kKeyboardLoginScreenExternalSettingsPref, |
| std::nullopt); |
| known_user.SetPath(account_id, |
| prefs::kPointingStickLoginScreenInternalSettingsPref, |
| std::nullopt); |
| known_user.SetPath(account_id, |
| prefs::kPointingStickLoginScreenExternalSettingsPref, |
| std::nullopt); |
| known_user.SetPath(account_id, |
| prefs::kTouchpadLoginScreenInternalSettingsPref, |
| std::nullopt); |
| known_user.SetPath(account_id, |
| prefs::kTouchpadLoginScreenExternalSettingsPref, |
| std::nullopt); |
| } |
| |
| void DeleteLoginScreenButtonRemappingListPrefWhenPeripheralCustomizationDisabled( |
| PrefService* local_state) { |
| // local_state could be null in tests. |
| if (!local_state) { |
| return; |
| } |
| user_manager::KnownUser known_user(local_state); |
| AccountId account_id = |
| Shell::Get()->session_controller()->GetActiveAccountId(); |
| |
| known_user.SetPath( |
| account_id, |
| prefs::kGraphicsTabletLoginScreenTabletButtonRemappingListPref, |
| std::nullopt); |
| known_user.SetPath( |
| account_id, prefs::kGraphicsTabletLoginScreenPenButtonRemappingListPref, |
| std::nullopt); |
| known_user.SetPath(account_id, |
| prefs::kMouseLoginScreenButtonRemappingListPref, |
| std::nullopt); |
| } |
| |
| void RefreshKeyDisplayInRemappingList( |
| std::vector<mojom::ButtonRemappingPtr>& remappings) { |
| for (const auto& remapping : remappings) { |
| if (!remapping->remapping_action || |
| !remapping->remapping_action->is_key_event()) { |
| continue; |
| } |
| mojom::KeyEvent& key_event = *remapping->remapping_action->get_key_event(); |
| key_event.key_display = base::UTF16ToUTF8(GetKeyDisplay(key_event.vkey)); |
| } |
| } |
| |
| void RefreshKeyDisplayMouse(mojom::Mouse& mouse) { |
| RefreshKeyDisplayInRemappingList(mouse.settings->button_remappings); |
| } |
| |
| void RefreshKeyDisplayGraphicsTablet(mojom::GraphicsTablet& graphics_tablet) { |
| RefreshKeyDisplayInRemappingList( |
| graphics_tablet.settings->tablet_button_remappings); |
| RefreshKeyDisplayInRemappingList( |
| graphics_tablet.settings->pen_button_remappings); |
| } |
| |
| } // namespace |
| |
| InputDeviceSettingsControllerImpl::InputDeviceSettingsControllerImpl( |
| PrefService* local_state) |
| : local_state_(local_state), |
| keyboard_pref_handler_(std::make_unique<KeyboardPrefHandlerImpl>()), |
| touchpad_pref_handler_(std::make_unique<TouchpadPrefHandlerImpl>()), |
| mouse_pref_handler_(std::make_unique<MousePrefHandlerImpl>()), |
| pointing_stick_pref_handler_( |
| std::make_unique<PointingStickPrefHandlerImpl>()), |
| graphics_tablet_pref_handler_( |
| std::make_unique<GraphicsTabletPrefHandlerImpl>()), |
| sequenced_task_runner_(base::SequencedTaskRunner::GetCurrentDefault()) { |
| Init(); |
| } |
| |
| InputDeviceSettingsControllerImpl::InputDeviceSettingsControllerImpl( |
| PrefService* local_state, |
| std::unique_ptr<KeyboardPrefHandler> keyboard_pref_handler, |
| std::unique_ptr<TouchpadPrefHandler> touchpad_pref_handler, |
| std::unique_ptr<MousePrefHandler> mouse_pref_handler, |
| std::unique_ptr<PointingStickPrefHandler> pointing_stick_pref_handler, |
| std::unique_ptr<GraphicsTabletPrefHandler> graphics_tablet_pref_handler, |
| scoped_refptr<base::SequencedTaskRunner> task_runner) |
| : local_state_(local_state), |
| keyboard_pref_handler_(std::move(keyboard_pref_handler)), |
| touchpad_pref_handler_(std::move(touchpad_pref_handler)), |
| mouse_pref_handler_(std::move(mouse_pref_handler)), |
| pointing_stick_pref_handler_(std::move(pointing_stick_pref_handler)), |
| graphics_tablet_pref_handler_(std::move(graphics_tablet_pref_handler)), |
| sequenced_task_runner_(std::move(task_runner)) { |
| Init(); |
| } |
| |
| void InputDeviceSettingsControllerImpl::Init() { |
| Shell::Get()->session_controller()->AddObserver(this); |
| CHECK(input_method::InputMethodManager::Get()); |
| input_method::InputMethodManager::Get()->AddObserver(this); |
| |
| InitializePolicyHandler(); |
| // Initialize the duplicate id finder first then the notifiers to make sure |
| // duplicate ids are up to date before the controller gets updates about |
| // connected devices. |
| if (features::IsPeripheralCustomizationEnabled()) { |
| duplicate_id_finder_ = std::make_unique<InputDeviceDuplicateIdFinder>(); |
| } |
| |
| if (features::IsPeripheralNotificationEnabled()) { |
| notification_controller_ = |
| std::make_unique<InputDeviceSettingsNotificationController>( |
| message_center::MessageCenter::Get()); |
| } |
| |
| keyboard_notifier_ = std::make_unique< |
| InputDeviceNotifier<mojom::KeyboardPtr, ui::KeyboardDevice>>( |
| &keyboards_, |
| base::BindRepeating( |
| &InputDeviceSettingsControllerImpl::OnKeyboardListUpdated, |
| base::Unretained(this))); |
| mouse_notifier_ = |
| std::make_unique<InputDeviceNotifier<mojom::MousePtr, ui::InputDevice>>( |
| &mice_, base::BindRepeating( |
| &InputDeviceSettingsControllerImpl::OnMouseListUpdated, |
| base::Unretained(this))); |
| touchpad_notifier_ = std::make_unique< |
| InputDeviceNotifier<mojom::TouchpadPtr, ui::TouchpadDevice>>( |
| &touchpads_, |
| base::BindRepeating( |
| &InputDeviceSettingsControllerImpl::OnTouchpadListUpdated, |
| base::Unretained(this))); |
| pointing_stick_notifier_ = std::make_unique< |
| InputDeviceNotifier<mojom::PointingStickPtr, ui::InputDevice>>( |
| &pointing_sticks_, |
| base::BindRepeating( |
| &InputDeviceSettingsControllerImpl::OnPointingStickListUpdated, |
| base::Unretained(this))); |
| if (features::IsPeripheralCustomizationEnabled()) { |
| graphics_tablet_notifier_ = std::make_unique< |
| InputDeviceNotifier<mojom::GraphicsTabletPtr, ui::InputDevice>>( |
| &graphics_tablets_, |
| base::BindRepeating( |
| &InputDeviceSettingsControllerImpl::OnGraphicsTabletListUpdated, |
| base::Unretained(this))); |
| } |
| metrics_manager_ = std::make_unique<InputDeviceSettingsMetricsManager>(); |
| } |
| |
| void InputDeviceSettingsControllerImpl::InitializePolicyHandler() { |
| policy_handler_ = std::make_unique<InputDeviceSettingsPolicyHandler>( |
| base::BindRepeating( |
| &InputDeviceSettingsControllerImpl::OnKeyboardPoliciesChanged, |
| base::Unretained(this)), |
| base::BindRepeating( |
| &InputDeviceSettingsControllerImpl::OnMousePoliciesChanged, |
| base::Unretained(this))); |
| // Only initialize if we have either local state or pref service. |
| // `local_state` can be null in tests. |
| if (local_state_ || active_pref_service_) { |
| policy_handler_->Initialize(local_state_, active_pref_service_); |
| } |
| } |
| |
| InputDeviceSettingsControllerImpl::~InputDeviceSettingsControllerImpl() { |
| Shell::Get()->session_controller()->RemoveObserver(this); |
| CHECK(input_method::InputMethodManager::Get()); |
| input_method::InputMethodManager::Get()->RemoveObserver(this); |
| // Clear all dangling observers. Known dependency issue: |
| // `InputDeviceSettingsControllerImpl` destructs before `ShortcutAppManager`. |
| observers_.Clear(); |
| } |
| |
| void InputDeviceSettingsControllerImpl::RegisterProfilePrefs( |
| PrefRegistrySimple* pref_registry) { |
| pref_registry->RegisterDictionaryPref(prefs::kKeyboardDeviceSettingsDictPref); |
| pref_registry->RegisterDictionaryPref(prefs::kMouseDeviceSettingsDictPref); |
| pref_registry->RegisterDictionaryPref( |
| prefs::kPointingStickDeviceSettingsDictPref); |
| pref_registry->RegisterDictionaryPref(prefs::kTouchpadDeviceSettingsDictPref); |
| pref_registry->RegisterDictionaryPref(prefs::kKeyboardInternalSettings); |
| |
| pref_registry->RegisterDictionaryPref( |
| prefs::kTouchpadInternalSettings, |
| user_prefs::PrefRegistrySyncable::SYNCABLE_OS_PREF); |
| pref_registry->RegisterDictionaryPref( |
| prefs::kTouchpadDefaultSettings, |
| user_prefs::PrefRegistrySyncable::SYNCABLE_OS_PREF); |
| pref_registry->RegisterDictionaryPref( |
| prefs::kPointingStickInternalSettings, |
| user_prefs::PrefRegistrySyncable::SYNCABLE_OS_PREF); |
| pref_registry->RegisterDictionaryPref( |
| prefs::kMouseDefaultSettings, |
| user_prefs::PrefRegistrySyncable::SYNCABLE_OS_PREF); |
| pref_registry->RegisterDictionaryPref( |
| prefs::kKeyboardDefaultChromeOSSettings, |
| user_prefs::PrefRegistrySyncable::SYNCABLE_OS_PREF); |
| pref_registry->RegisterDictionaryPref( |
| prefs::kKeyboardDefaultNonChromeOSSettings, |
| user_prefs::PrefRegistrySyncable::SYNCABLE_OS_PREF); |
| |
| pref_registry->RegisterDictionaryPref( |
| prefs::kKeyboardUpdateSettingsMetricInfo); |
| pref_registry->RegisterDictionaryPref(prefs::kMouseUpdateSettingsMetricInfo); |
| pref_registry->RegisterDictionaryPref( |
| prefs::kTouchpadUpdateSettingsMetricInfo); |
| pref_registry->RegisterDictionaryPref( |
| prefs::kPointingStickUpdateSettingsMetricInfo); |
| |
| pref_registry->RegisterListPref(prefs::kKeyboardDeviceImpostersListPref); |
| pref_registry->RegisterDictionaryPref(prefs::kMouseButtonRemappingsDictPref); |
| pref_registry->RegisterDictionaryPref( |
| prefs::kGraphicsTabletTabletButtonRemappingsDictPref); |
| pref_registry->RegisterDictionaryPref( |
| prefs::kGraphicsTabletPenButtonRemappingsDictPref); |
| pref_registry->RegisterIntegerPref( |
| prefs::kF11KeyModifier, |
| static_cast<int>(ui::mojom::ExtendedFkeysModifier::kDisabled)); |
| pref_registry->RegisterIntegerPref( |
| prefs::kF12KeyModifier, |
| static_cast<int>(ui::mojom::ExtendedFkeysModifier::kDisabled)); |
| pref_registry->RegisterIntegerPref( |
| prefs::kHomeAndEndKeysModifier, |
| static_cast<int>(ui::mojom::SixPackShortcutModifier::kNone)); |
| pref_registry->RegisterIntegerPref( |
| prefs::kPageUpAndPageDownKeysModifier, |
| static_cast<int>(ui::mojom::SixPackShortcutModifier::kNone)); |
| pref_registry->RegisterIntegerPref( |
| prefs::kDeleteKeyModifier, |
| static_cast<int>(ui::mojom::SixPackShortcutModifier::kNone)); |
| pref_registry->RegisterIntegerPref( |
| prefs::kInsertKeyModifier, |
| static_cast<int>(ui::mojom::SixPackShortcutModifier::kNone)); |
| } |
| |
| void InputDeviceSettingsControllerImpl::OnActiveUserPrefServiceChanged( |
| PrefService* pref_service) { |
| // If the flag is disabled, clear the button remapping dictionaries. |
| if (!features::IsPeripheralCustomizationEnabled()) { |
| pref_service->ClearPref( |
| prefs::kGraphicsTabletTabletButtonRemappingsDictPref); |
| pref_service->ClearPref(prefs::kGraphicsTabletPenButtonRemappingsDictPref); |
| pref_service->ClearPref(prefs::kMouseButtonRemappingsDictPref); |
| DeleteLoginScreenButtonRemappingListPrefWhenPeripheralCustomizationDisabled( |
| local_state_); |
| } |
| |
| if (!features::IsPeripheralNotificationEnabled()) { |
| pref_service->ClearPref(prefs::kPeripheralNotificationMiceSeen); |
| pref_service->ClearPref(prefs::kPeripheralNotificationGraphicsTabletsSeen); |
| } |
| |
| // If the flag is disabled, clear all the settings dictionaries. |
| if (!features::IsInputDeviceSettingsSplitEnabled()) { |
| active_pref_service_ = nullptr; |
| pref_service->SetDict(prefs::kKeyboardDeviceSettingsDictPref, {}); |
| pref_service->SetDict(prefs::kMouseDeviceSettingsDictPref, {}); |
| pref_service->SetDict(prefs::kPointingStickDeviceSettingsDictPref, {}); |
| pref_service->SetDict(prefs::kTouchpadDeviceSettingsDictPref, {}); |
| pref_service->SetList(prefs::kKeyboardDeviceImpostersListPref, {}); |
| |
| pref_service->ClearPref(prefs::kKeyboardInternalSettings); |
| pref_service->ClearPref(prefs::kKeyboardUpdateSettingsMetricInfo); |
| pref_service->ClearPref(prefs::kMouseUpdateSettingsMetricInfo); |
| pref_service->ClearPref(prefs::kTouchpadUpdateSettingsMetricInfo); |
| pref_service->ClearPref(prefs::kPointingStickUpdateSettingsMetricInfo); |
| |
| DeleteLoginScreenSettingsPrefWhenInputDeviceSettingsSplitDisabled( |
| local_state_); |
| return; |
| } |
| |
| // If the flag is disabled, clear the new touchpad and keyboard settings from |
| // all settings dictionaries and reset the notification prefs. |
| if (!features::IsAltClickAndSixPackCustomizationEnabled() && pref_service) { |
| base::Value::Dict updated_touchpad_dict = |
| pref_service->GetDict(prefs::kTouchpadDeviceSettingsDictPref).Clone(); |
| for (auto [key, dict] : updated_touchpad_dict) { |
| CHECK(dict.is_dict()); |
| dict.GetDict().Remove(prefs::kTouchpadSettingSimulateRightClick); |
| } |
| |
| base::Value::Dict updated_keyboard_dict = |
| pref_service->GetDict(prefs::kKeyboardDeviceSettingsDictPref).Clone(); |
| |
| for (auto [key, dict] : updated_keyboard_dict) { |
| CHECK(dict.is_dict()); |
| dict.GetDict().Remove(prefs::kKeyboardSettingSixPackKeyRemappings); |
| } |
| pref_service->SetDict(prefs::kTouchpadDeviceSettingsDictPref, |
| std::move(updated_touchpad_dict)); |
| pref_service->SetDict(prefs::kKeyboardDeviceSettingsDictPref, |
| std::move(updated_keyboard_dict)); |
| |
| // Remove six pack remappings from internal keyboard as well. |
| base::Value::Dict updated_internal_keyboard_dict = |
| pref_service->GetDict(prefs::kKeyboardInternalSettings).Clone(); |
| updated_internal_keyboard_dict.Remove( |
| prefs::kKeyboardSettingSixPackKeyRemappings); |
| pref_service->SetDict(prefs::kKeyboardInternalSettings, |
| std::move(updated_internal_keyboard_dict)); |
| |
| pref_service->ClearPref(prefs::kRemapToRightClickNotificationsRemaining); |
| pref_service->ClearPref(prefs::kSixPackKeyDeleteNotificationsRemaining); |
| pref_service->ClearPref(prefs::kSixPackKeyHomeNotificationsRemaining); |
| pref_service->ClearPref(prefs::kSixPackKeyEndNotificationsRemaining); |
| pref_service->ClearPref(prefs::kSixPackKeyPageUpNotificationsRemaining); |
| pref_service->ClearPref(prefs::kSixPackKeyPageDownNotificationsRemaining); |
| pref_service->ClearPref(prefs::kSixPackKeyInsertNotificationsRemaining); |
| } |
| active_pref_service_ = pref_service; |
| active_account_id_ = Shell::Get()->session_controller()->GetActiveAccountId(); |
| InitializePolicyHandler(); |
| |
| // Observe changes to synced prefs to ensure updates made on other devices are |
| // properly reflected. |
| pref_change_registrar_ = std::make_unique<PrefChangeRegistrar>(); |
| if (active_pref_service_) { |
| pref_change_registrar_->Init(active_pref_service_); |
| pref_change_registrar_->Add( |
| prefs::kPointingStickInternalSettings, |
| base::BindRepeating(&InputDeviceSettingsControllerImpl:: |
| RefreshInternalPointingStickSettings, |
| weak_ptr_factory_.GetWeakPtr())); |
| pref_change_registrar_->Add( |
| prefs::kTouchpadInternalSettings, |
| base::BindRepeating( |
| &InputDeviceSettingsControllerImpl::RefreshInternalTouchpadSettings, |
| weak_ptr_factory_.GetWeakPtr())); |
| } |
| |
| // Device settings must be refreshed when the user pref service is updated, |
| // but all dependencies of `InputDeviceSettingsControllerImpl` must be |
| // updated due to the active pref service change first. Therefore, schedule |
| // a task so other dependencies are updated first. |
| ScheduleDeviceSettingsRefresh(); |
| } |
| |
| void InputDeviceSettingsControllerImpl::ScheduleDeviceSettingsRefresh() { |
| if (!settings_refresh_pending_) { |
| settings_refresh_pending_ = true; |
| sequenced_task_runner_->PostTask( |
| FROM_HERE, |
| base::BindOnce( |
| &InputDeviceSettingsControllerImpl::RefreshAllDeviceSettings, |
| weak_ptr_factory_.GetWeakPtr())); |
| } |
| } |
| |
| void InputDeviceSettingsControllerImpl::RefreshAllDeviceSettings() { |
| settings_refresh_pending_ = false; |
| for (const auto& [id, keyboard] : keyboards_) { |
| InitializeKeyboardSettings(keyboard.get()); |
| DispatchKeyboardSettingsChanged(id); |
| } |
| for (const auto& [id, touchpad] : touchpads_) { |
| InitializeTouchpadSettings(touchpad.get()); |
| DispatchTouchpadSettingsChanged(id); |
| } |
| for (const auto& [id, mouse] : mice_) { |
| InitializeMouseSettings(mouse.get()); |
| DispatchMouseSettingsChanged(id); |
| } |
| for (const auto& [id, pointing_stick] : pointing_sticks_) { |
| InitializePointingStickSettings(pointing_stick.get()); |
| DispatchPointingStickSettingsChanged(id); |
| } |
| |
| RefreshCachedKeyboardSettings(); |
| RefreshCachedMouseSettings(); |
| RefreshCachedTouchpadSettings(); |
| RefreshStoredLoginScreenPointingStickSettings(); |
| |
| if (features::IsPeripheralCustomizationEnabled()) { |
| for (const auto& [id, graphics_tablet] : graphics_tablets_) { |
| InitializeGraphicsTabletSettings(graphics_tablet.get()); |
| DispatchGraphicsTabletSettingsChanged(id); |
| } |
| RefreshStoredLoginScreenGraphicsTabletSettings(); |
| } |
| } |
| |
| void InputDeviceSettingsControllerImpl:: |
| RefreshStoredLoginScreenKeyboardSettings() { |
| if (!local_state_ || !active_account_id_.has_value()) { |
| return; |
| } |
| |
| // Our map of keyboards is sorted so iterating in reverse order guarantees |
| // that we'll select the most recently connected device. |
| auto external_iter = base::ranges::find( |
| keyboards_.rbegin(), keyboards_.rend(), /*value=*/true, |
| [](const auto& keyboard) { return keyboard.second->is_external; }); |
| auto internal_iter = base::ranges::find( |
| keyboards_.rbegin(), keyboards_.rend(), /*value=*/false, |
| [](const auto& keyboard) { return keyboard.second->is_external; }); |
| |
| if (external_iter != keyboards_.rend()) { |
| auto& external_keyboard = *external_iter->second; |
| keyboard_pref_handler_->UpdateLoginScreenKeyboardSettings( |
| local_state_, active_account_id_.value(), |
| policy_handler_->keyboard_policies(), external_keyboard); |
| } |
| |
| if (internal_iter != keyboards_.rend()) { |
| auto& internal_keyboard = *internal_iter->second; |
| keyboard_pref_handler_->UpdateLoginScreenKeyboardSettings( |
| local_state_, active_account_id_.value(), |
| policy_handler_->keyboard_policies(), internal_keyboard); |
| } |
| } |
| |
| void InputDeviceSettingsControllerImpl:: |
| RefreshStoredLoginScreenMouseSettings() { |
| if (!local_state_ || !active_account_id_.has_value()) { |
| return; |
| } |
| |
| // Our map of mice is sorted so iterating in reverse order guarantees |
| // that we'll select the most recently connected device. |
| auto external_iter = base::ranges::find( |
| mice_.rbegin(), mice_.rend(), /*value=*/true, |
| [](const auto& mouse) { return mouse.second->is_external; }); |
| auto internal_iter = base::ranges::find( |
| mice_.rbegin(), mice_.rend(), /*value=*/false, |
| [](const auto& mouse) { return mouse.second->is_external; }); |
| |
| if (external_iter != mice_.rend()) { |
| auto& external_mouse = *external_iter->second; |
| mouse_pref_handler_->UpdateLoginScreenMouseSettings( |
| local_state_, active_account_id_.value(), |
| policy_handler_->mouse_policies(), external_mouse); |
| } |
| |
| if (internal_iter != mice_.rend()) { |
| auto& internal_mouse = *internal_iter->second; |
| mouse_pref_handler_->UpdateLoginScreenMouseSettings( |
| local_state_, active_account_id_.value(), |
| policy_handler_->mouse_policies(), internal_mouse); |
| } |
| } |
| |
| void InputDeviceSettingsControllerImpl:: |
| RefreshStoredLoginScreenPointingStickSettings() { |
| if (!local_state_ || !active_account_id_.has_value()) { |
| return; |
| } |
| |
| // Our map of pointing sticks is sorted so iterating in reverse order |
| // guarantees that we'll select the most recently connected device. |
| auto external_iter = |
| base::ranges::find(pointing_sticks_.rbegin(), pointing_sticks_.rend(), |
| /*value=*/true, [](const auto& pointing_stick) { |
| return pointing_stick.second->is_external; |
| }); |
| auto internal_iter = |
| base::ranges::find(pointing_sticks_.rbegin(), pointing_sticks_.rend(), |
| /*value=*/false, [](const auto& pointing_stick) { |
| return pointing_stick.second->is_external; |
| }); |
| |
| if (external_iter != pointing_sticks_.rend()) { |
| auto& external_pointing_stick = *external_iter->second; |
| pointing_stick_pref_handler_->UpdateLoginScreenPointingStickSettings( |
| local_state_, active_account_id_.value(), external_pointing_stick); |
| } |
| |
| if (internal_iter != pointing_sticks_.rend()) { |
| auto& internal_pointing_stick = *internal_iter->second; |
| pointing_stick_pref_handler_->UpdateLoginScreenPointingStickSettings( |
| local_state_, active_account_id_.value(), internal_pointing_stick); |
| } |
| } |
| |
| void InputDeviceSettingsControllerImpl:: |
| RefreshStoredLoginScreenTouchpadSettings() { |
| if (!local_state_ || !active_account_id_.has_value()) { |
| return; |
| } |
| |
| // Our map of touchpads is sorted so iterating in reverse order guarantees |
| // that we'll select the most recently connected device. |
| auto external_iter = base::ranges::find( |
| touchpads_.rbegin(), touchpads_.rend(), /*value=*/true, |
| [](const auto& touchpad) { return touchpad.second->is_external; }); |
| auto internal_iter = base::ranges::find( |
| touchpads_.rbegin(), touchpads_.rend(), /*value=*/false, |
| [](const auto& touchpad) { return touchpad.second->is_external; }); |
| |
| if (external_iter != touchpads_.rend()) { |
| auto& external_touchpad = *external_iter->second; |
| touchpad_pref_handler_->UpdateLoginScreenTouchpadSettings( |
| local_state_, active_account_id_.value(), external_touchpad); |
| } |
| |
| if (internal_iter != touchpads_.rend()) { |
| auto& internal_touchpad = *internal_iter->second; |
| touchpad_pref_handler_->UpdateLoginScreenTouchpadSettings( |
| local_state_, active_account_id_.value(), internal_touchpad); |
| } |
| } |
| |
| void InputDeviceSettingsControllerImpl:: |
| RefreshStoredLoginScreenGraphicsTabletSettings() { |
| if (!local_state_ || !active_account_id_.has_value()) { |
| return; |
| } |
| if (graphics_tablets_.size() == 0) { |
| return; |
| } |
| graphics_tablet_pref_handler_->UpdateLoginScreenGraphicsTabletSettings( |
| local_state_, active_account_id_.value(), |
| *graphics_tablets_.rbegin()->second); |
| } |
| |
| void InputDeviceSettingsControllerImpl::OnLoginScreenFocusedPodChanged( |
| const AccountId& account_id) { |
| active_account_id_ = account_id; |
| |
| for (const auto& [id, keyboard] : keyboards_) { |
| keyboard_pref_handler_->InitializeLoginScreenKeyboardSettings( |
| local_state_, account_id, policy_handler_->keyboard_policies(), |
| keyboard.get()); |
| DispatchKeyboardSettingsChanged(id); |
| } |
| |
| for (const auto& [id, mouse] : mice_) { |
| mouse_pref_handler_->InitializeLoginScreenMouseSettings( |
| local_state_, account_id, policy_handler_->mouse_policies(), |
| mouse.get()); |
| DispatchMouseSettingsChanged(id); |
| } |
| |
| for (const auto& [id, pointing_stick] : pointing_sticks_) { |
| pointing_stick_pref_handler_->InitializeLoginScreenPointingStickSettings( |
| local_state_, account_id, pointing_stick.get()); |
| DispatchPointingStickSettingsChanged(id); |
| } |
| |
| for (const auto& [id, touchpad] : touchpads_) { |
| touchpad_pref_handler_->InitializeLoginScreenTouchpadSettings( |
| local_state_, account_id, touchpad.get()); |
| DispatchTouchpadSettingsChanged(id); |
| } |
| |
| if (features::IsPeripheralCustomizationEnabled()) { |
| for (const auto& [id, graphics_tablet] : graphics_tablets_) { |
| graphics_tablet_pref_handler_ |
| ->InitializeLoginScreenGraphicsTabletSettings( |
| local_state_, account_id, graphics_tablet.get()); |
| DispatchGraphicsTabletSettingsChanged(id); |
| } |
| } |
| } |
| |
| void InputDeviceSettingsControllerImpl::OnKeyboardPoliciesChanged() { |
| for (auto& observer : observers_) { |
| observer.OnKeyboardPoliciesUpdated(policy_handler_->keyboard_policies()); |
| } |
| ScheduleDeviceSettingsRefresh(); |
| } |
| |
| void InputDeviceSettingsControllerImpl::OnMousePoliciesChanged() { |
| for (const auto& [id, mouse] : mice_) { |
| InitializeMouseSettings(mouse.get()); |
| DispatchMouseSettingsChanged(id); |
| } |
| |
| for (auto& observer : observers_) { |
| observer.OnMousePoliciesUpdated(policy_handler_->mouse_policies()); |
| } |
| } |
| |
| const mojom::KeyboardPolicies& |
| InputDeviceSettingsControllerImpl::GetKeyboardPolicies() { |
| CHECK(policy_handler_); |
| return policy_handler_->keyboard_policies(); |
| } |
| |
| const mojom::MousePolicies& |
| InputDeviceSettingsControllerImpl::GetMousePolicies() { |
| CHECK(policy_handler_); |
| return policy_handler_->mouse_policies(); |
| } |
| |
| const mojom::KeyboardSettings* |
| InputDeviceSettingsControllerImpl::GetKeyboardSettings(DeviceId id) { |
| const auto* keyboard = FindKeyboard(id); |
| return keyboard ? keyboard->settings.get() : nullptr; |
| } |
| |
| const mojom::MouseSettings* InputDeviceSettingsControllerImpl::GetMouseSettings( |
| DeviceId id) { |
| const auto* mouse = FindMouse(id); |
| return mouse ? mouse->settings.get() : nullptr; |
| } |
| |
| const mojom::TouchpadSettings* |
| InputDeviceSettingsControllerImpl::GetTouchpadSettings(DeviceId id) { |
| const auto* touchpad = FindTouchpad(id); |
| return touchpad ? touchpad->settings.get() : nullptr; |
| } |
| |
| const mojom::PointingStickSettings* |
| InputDeviceSettingsControllerImpl::GetPointingStickSettings(DeviceId id) { |
| const auto* pointing_stick = FindPointingStick(id); |
| return pointing_stick ? pointing_stick->settings.get() : nullptr; |
| } |
| |
| const mojom::GraphicsTabletSettings* |
| InputDeviceSettingsControllerImpl::GetGraphicsTabletSettings(DeviceId id) { |
| const auto* graphics_tablet = FindGraphicsTablet(id); |
| return graphics_tablet ? graphics_tablet->settings.get() : nullptr; |
| } |
| |
| std::vector<mojom::KeyboardPtr> |
| InputDeviceSettingsControllerImpl::GetConnectedKeyboards() { |
| std::vector<mojom::KeyboardPtr> keyboard_vector; |
| keyboard_vector.reserve(keyboards_.size()); |
| |
| for (const auto& [_, keyboard] : keyboards_) { |
| keyboard_vector.push_back(keyboard->Clone()); |
| } |
| |
| return keyboard_vector; |
| } |
| |
| std::vector<mojom::TouchpadPtr> |
| InputDeviceSettingsControllerImpl::GetConnectedTouchpads() { |
| std::vector<mojom::TouchpadPtr> mouse_vector; |
| mouse_vector.reserve(touchpads_.size()); |
| |
| for (const auto& [_, touchpad] : touchpads_) { |
| mouse_vector.push_back(touchpad->Clone()); |
| } |
| |
| return mouse_vector; |
| } |
| |
| std::vector<mojom::MousePtr> |
| InputDeviceSettingsControllerImpl::GetConnectedMice() { |
| std::vector<mojom::MousePtr> mouse_vector; |
| mouse_vector.reserve(mice_.size()); |
| |
| for (const auto& [_, mouse] : mice_) { |
| mouse_vector.push_back(mouse->Clone()); |
| } |
| |
| return mouse_vector; |
| } |
| |
| std::vector<mojom::PointingStickPtr> |
| InputDeviceSettingsControllerImpl::GetConnectedPointingSticks() { |
| std::vector<mojom::PointingStickPtr> pointing_stick_vector; |
| pointing_stick_vector.reserve(pointing_sticks_.size()); |
| |
| for (const auto& [_, pointing_stick] : pointing_sticks_) { |
| pointing_stick_vector.push_back(pointing_stick->Clone()); |
| } |
| |
| return pointing_stick_vector; |
| } |
| |
| std::vector<mojom::GraphicsTabletPtr> |
| InputDeviceSettingsControllerImpl::GetConnectedGraphicsTablets() { |
| std::vector<mojom::GraphicsTabletPtr> graphics_tablet_vector; |
| graphics_tablet_vector.reserve(graphics_tablets_.size()); |
| |
| for (const auto& [_, graphics_tablet] : graphics_tablets_) { |
| graphics_tablet_vector.push_back(graphics_tablet->Clone()); |
| } |
| |
| return graphics_tablet_vector; |
| } |
| |
| bool InputDeviceSettingsControllerImpl::SetKeyboardSettings( |
| DeviceId id, |
| mojom::KeyboardSettingsPtr settings) { |
| DCHECK(active_pref_service_); |
| |
| // If a device with the given id does not exist, do nothing. |
| auto found_keyboard_iter = keyboards_.find(id); |
| if (found_keyboard_iter == keyboards_.end()) { |
| RecordSetKeyboardSettingsValidMetric(/*is_valid=*/false); |
| return false; |
| } |
| auto& found_keyboard = *found_keyboard_iter->second; |
| |
| if (!KeyboardSettingsAreValid(found_keyboard, *settings, |
| policy_handler_->keyboard_policies())) { |
| RecordSetKeyboardSettingsValidMetric(/*is_valid=*/false); |
| return false; |
| } |
| RecordSetKeyboardSettingsValidMetric(/*is_valid=*/true); |
| |
| const auto old_settings = std::move(found_keyboard.settings); |
| found_keyboard.settings = settings.Clone(); |
| keyboard_pref_handler_->UpdateKeyboardSettings( |
| active_pref_service_, policy_handler_->keyboard_policies(), |
| found_keyboard); |
| metrics_manager_->RecordKeyboardChangedMetrics(found_keyboard, *old_settings); |
| DispatchKeyboardSettingsChanged(id); |
| |
| UpdateDuplicateDeviceSettings( |
| found_keyboard, keyboards_, |
| base::BindRepeating( |
| &InputDeviceSettingsControllerImpl::DispatchKeyboardSettingsChanged, |
| base::Unretained(this))); |
| RefreshCachedKeyboardSettings(); |
| return true; |
| } |
| |
| bool InputDeviceSettingsControllerImpl::SetTouchpadSettings( |
| DeviceId id, |
| mojom::TouchpadSettingsPtr settings) { |
| DCHECK(active_pref_service_); |
| |
| // If a device with the given id does not exist, do nothing. |
| auto found_touchpad_iter = touchpads_.find(id); |
| if (found_touchpad_iter == touchpads_.end()) { |
| RecordSetTouchpadSettingsValidMetric(/*is_valid=*/false); |
| return false; |
| } |
| |
| auto& found_touchpad = *found_touchpad_iter->second; |
| if (!TouchpadSettingsAreValid(found_touchpad, *settings)) { |
| RecordSetTouchpadSettingsValidMetric(/*is_valid=*/false); |
| return false; |
| } |
| RecordSetTouchpadSettingsValidMetric(/*is_valid=*/true); |
| |
| const auto old_settings = std::move(found_touchpad.settings); |
| found_touchpad.settings = settings.Clone(); |
| touchpad_pref_handler_->UpdateTouchpadSettings(active_pref_service_, |
| found_touchpad); |
| metrics_manager_->RecordTouchpadChangedMetrics(found_touchpad, *old_settings); |
| DispatchTouchpadSettingsChanged(id); |
| |
| UpdateDuplicateDeviceSettings( |
| found_touchpad, touchpads_, |
| base::BindRepeating( |
| &InputDeviceSettingsControllerImpl::DispatchTouchpadSettingsChanged, |
| base::Unretained(this))); |
| RefreshCachedTouchpadSettings(); |
| return true; |
| } |
| |
| bool InputDeviceSettingsControllerImpl::SetMouseSettings( |
| DeviceId id, |
| mojom::MouseSettingsPtr settings) { |
| DCHECK(active_pref_service_); |
| |
| // If a device with the given id does not exist, do nothing. |
| auto found_mouse_iter = mice_.find(id); |
| if (found_mouse_iter == mice_.end()) { |
| RecordSetMouseSettingsValidMetric(/*is_valid=*/false); |
| return false; |
| } |
| |
| auto& found_mouse = *found_mouse_iter->second; |
| if (!MouseSettingsAreValid(found_mouse, *settings)) { |
| RecordSetMouseSettingsValidMetric(/*is_valid=*/false); |
| return false; |
| } |
| RecordSetMouseSettingsValidMetric(/*is_valid=*/true); |
| |
| const auto old_settings = std::move(found_mouse.settings); |
| found_mouse.settings = settings.Clone(); |
| mouse_pref_handler_->UpdateMouseSettings( |
| active_pref_service_, policy_handler_->mouse_policies(), found_mouse); |
| metrics_manager_->RecordMouseChangedMetrics(found_mouse, *old_settings); |
| DispatchMouseSettingsChanged(id); |
| |
| UpdateDuplicateDeviceSettings( |
| found_mouse, mice_, |
| base::BindRepeating( |
| &InputDeviceSettingsControllerImpl::DispatchMouseSettingsChanged, |
| base::Unretained(this))); |
| RefreshCachedMouseSettings(); |
| return true; |
| } |
| |
| bool InputDeviceSettingsControllerImpl::SetPointingStickSettings( |
| DeviceId id, |
| mojom::PointingStickSettingsPtr settings) { |
| DCHECK(active_pref_service_); |
| |
| // If a device with the given id does not exist, do nothing. |
| auto found_pointing_stick_iter = pointing_sticks_.find(id); |
| if (found_pointing_stick_iter == pointing_sticks_.end()) { |
| RecordSetPointingStickSettingsValidMetric(/*is_valid=*/false); |
| return false; |
| } |
| RecordSetPointingStickSettingsValidMetric(/*is_valid=*/true); |
| |
| auto& found_pointing_stick = *found_pointing_stick_iter->second; |
| const auto old_settings = std::move(found_pointing_stick.settings); |
| found_pointing_stick.settings = settings.Clone(); |
| pointing_stick_pref_handler_->UpdatePointingStickSettings( |
| active_pref_service_, found_pointing_stick); |
| metrics_manager_->RecordPointingStickChangedMetrics(found_pointing_stick, |
| *old_settings); |
| DispatchPointingStickSettingsChanged(id); |
| // Check the list of pointing sticks to see if any have the same |
| // |device_key|. If so, their settings need to also be updated. |
| for (const auto& [device_id, pointing_stick] : pointing_sticks_) { |
| if (device_id != found_pointing_stick.id && |
| pointing_stick->device_key == found_pointing_stick.device_key) { |
| pointing_stick->settings = settings->Clone(); |
| DispatchPointingStickSettingsChanged(device_id); |
| } |
| } |
| |
| RefreshStoredLoginScreenPointingStickSettings(); |
| return true; |
| } |
| |
| bool InputDeviceSettingsControllerImpl::SetGraphicsTabletSettings( |
| DeviceId id, |
| mojom::GraphicsTabletSettingsPtr settings) { |
| DCHECK(active_pref_service_); |
| |
| // If a device with the given id does not exist, do nothing. |
| auto found_graphics_tablet_iter = graphics_tablets_.find(id); |
| if (found_graphics_tablet_iter == graphics_tablets_.end()) { |
| return false; |
| } |
| |
| auto& found_graphics_tablet = *found_graphics_tablet_iter->second; |
| if (!GraphicsTabletSettingsAreValid(found_graphics_tablet, *settings)) { |
| return false; |
| } |
| |
| const auto old_settings = std::move(found_graphics_tablet.settings); |
| found_graphics_tablet.settings = settings.Clone(); |
| graphics_tablet_pref_handler_->UpdateGraphicsTabletSettings( |
| active_pref_service_, found_graphics_tablet); |
| metrics_manager_->RecordGraphicsTabletChangedMetrics(found_graphics_tablet, |
| *old_settings); |
| DispatchGraphicsTabletSettingsChanged(id); |
| |
| UpdateDuplicateDeviceSettings( |
| found_graphics_tablet, graphics_tablets_, |
| base::BindRepeating(&InputDeviceSettingsControllerImpl:: |
| DispatchGraphicsTabletSettingsChanged, |
| base::Unretained(this))); |
| RefreshStoredLoginScreenGraphicsTabletSettings(); |
| return true; |
| } |
| |
| void InputDeviceSettingsControllerImpl::AddObserver( |
| InputDeviceSettingsController::Observer* observer) { |
| observers_.AddObserver(observer); |
| } |
| |
| void InputDeviceSettingsControllerImpl::RemoveObserver( |
| InputDeviceSettingsController::Observer* observer) { |
| observers_.RemoveObserver(observer); |
| } |
| |
| void InputDeviceSettingsControllerImpl::RecordComboDeviceMetric( |
| const mojom::Keyboard& keyboard) { |
| for (const auto& [_, mouse] : mice_) { |
| if (mouse->device_key == keyboard.device_key) { |
| metrics_manager_->RecordKeyboardMouseComboDeviceMetric(keyboard, *mouse); |
| } |
| } |
| } |
| |
| void InputDeviceSettingsControllerImpl::RecordComboDeviceMetric( |
| const mojom::Mouse& mouse) { |
| for (const auto& [_, keyboard] : keyboards_) { |
| if (keyboard->device_key == mouse.device_key) { |
| metrics_manager_->RecordKeyboardMouseComboDeviceMetric(*keyboard, mouse); |
| } |
| } |
| } |
| |
| void InputDeviceSettingsControllerImpl::DispatchKeyboardConnected(DeviceId id) { |
| DCHECK(base::Contains(keyboards_, id)); |
| const auto& keyboard = *keyboards_.at(id); |
| for (auto& observer : observers_) { |
| observer.OnKeyboardConnected(keyboard); |
| } |
| RecordComboDeviceMetric(keyboard); |
| } |
| |
| void InputDeviceSettingsControllerImpl:: |
| DispatchKeyboardDisconnectedAndEraseFromList(DeviceId id) { |
| DCHECK(base::Contains(keyboards_, id)); |
| auto keyboard_iter = keyboards_.find(id); |
| auto keyboard = std::move(keyboard_iter->second); |
| keyboards_.erase(keyboard_iter); |
| for (auto& observer : observers_) { |
| observer.OnKeyboardDisconnected(*keyboard); |
| } |
| } |
| |
| void InputDeviceSettingsControllerImpl::DispatchKeyboardSettingsChanged( |
| DeviceId id) { |
| DCHECK(base::Contains(keyboards_, id)); |
| const auto& keyboard = *keyboards_.at(id); |
| for (auto& observer : observers_) { |
| observer.OnKeyboardSettingsUpdated(keyboard); |
| } |
| } |
| |
| void InputDeviceSettingsControllerImpl::DispatchTouchpadConnected(DeviceId id) { |
| DCHECK(base::Contains(touchpads_, id)); |
| const auto& touchpad = *touchpads_.at(id); |
| for (auto& observer : observers_) { |
| observer.OnTouchpadConnected(touchpad); |
| } |
| } |
| |
| void InputDeviceSettingsControllerImpl:: |
| DispatchTouchpadDisconnectedAndEraseFromList(DeviceId id) { |
| DCHECK(base::Contains(touchpads_, id)); |
| auto touchpad_iter = touchpads_.find(id); |
| auto touchpad = std::move(touchpad_iter->second); |
| touchpads_.erase(touchpad_iter); |
| for (auto& observer : observers_) { |
| observer.OnTouchpadDisconnected(*touchpad); |
| } |
| } |
| |
| void InputDeviceSettingsControllerImpl::DispatchTouchpadSettingsChanged( |
| DeviceId id) { |
| DCHECK(base::Contains(touchpads_, id)); |
| const auto& touchpad = *touchpads_.at(id); |
| for (auto& observer : observers_) { |
| observer.OnTouchpadSettingsUpdated(touchpad); |
| } |
| } |
| |
| void InputDeviceSettingsControllerImpl::DispatchMouseConnected(DeviceId id) { |
| DCHECK(base::Contains(mice_, id)); |
| const auto& mouse = *mice_.at(id); |
| for (auto& observer : observers_) { |
| observer.OnMouseConnected(mouse); |
| } |
| RecordComboDeviceMetric(mouse); |
| } |
| |
| void InputDeviceSettingsControllerImpl:: |
| DispatchMouseDisconnectedAndEraseFromList(DeviceId id) { |
| DCHECK(base::Contains(mice_, id)); |
| auto mouse_iter = mice_.find(id); |
| auto mouse = std::move(mouse_iter->second); |
| mice_.erase(mouse_iter); |
| for (auto& observer : observers_) { |
| observer.OnMouseDisconnected(*mouse); |
| } |
| } |
| |
| void InputDeviceSettingsControllerImpl::DispatchMouseSettingsChanged( |
| DeviceId id) { |
| DCHECK(base::Contains(mice_, id)); |
| const auto& mouse = *mice_.at(id); |
| for (auto& observer : observers_) { |
| observer.OnMouseSettingsUpdated(mouse); |
| } |
| } |
| |
| void InputDeviceSettingsControllerImpl::DispatchPointingStickConnected( |
| DeviceId id) { |
| DCHECK(base::Contains(pointing_sticks_, id)); |
| const auto& pointing_stick = *pointing_sticks_.at(id); |
| for (auto& observer : observers_) { |
| observer.OnPointingStickConnected(pointing_stick); |
| } |
| } |
| |
| void InputDeviceSettingsControllerImpl:: |
| DispatchPointingStickDisconnectedAndEraseFromList(DeviceId id) { |
| DCHECK(base::Contains(pointing_sticks_, id)); |
| auto pointing_stick_iter = pointing_sticks_.find(id); |
| auto pointing_stick = std::move(pointing_stick_iter->second); |
| pointing_sticks_.erase(pointing_stick_iter); |
| for (auto& observer : observers_) { |
| observer.OnPointingStickDisconnected(*pointing_stick); |
| } |
| } |
| |
| void InputDeviceSettingsControllerImpl::DispatchPointingStickSettingsChanged( |
| DeviceId id) { |
| DCHECK(base::Contains(pointing_sticks_, id)); |
| const auto& pointing_stick = *pointing_sticks_.at(id); |
| for (auto& observer : observers_) { |
| observer.OnPointingStickSettingsUpdated(pointing_stick); |
| } |
| } |
| |
| void InputDeviceSettingsControllerImpl::DispatchGraphicsTabletConnected( |
| DeviceId id) { |
| DCHECK(base::Contains(graphics_tablets_, id)); |
| const auto& graphics_tablet = *graphics_tablets_.at(id); |
| for (auto& observer : observers_) { |
| observer.OnGraphicsTabletConnected(graphics_tablet); |
| } |
| } |
| |
| void InputDeviceSettingsControllerImpl:: |
| DispatchGraphicsTabletDisconnectedAndEraseFromList(DeviceId id) { |
| DCHECK(base::Contains(graphics_tablets_, id)); |
| auto graphics_tablet_iter = graphics_tablets_.find(id); |
| auto graphics_tablet = std::move(graphics_tablet_iter->second); |
| graphics_tablets_.erase(graphics_tablet_iter); |
| for (auto& observer : observers_) { |
| observer.OnGraphicsTabletDisconnected(*graphics_tablet); |
| } |
| } |
| |
| void InputDeviceSettingsControllerImpl::DispatchGraphicsTabletSettingsChanged( |
| DeviceId id) { |
| DCHECK(base::Contains(graphics_tablets_, id)); |
| const auto& graphics_tablet = *graphics_tablets_.at(id); |
| for (auto& observer : observers_) { |
| observer.OnGraphicsTabletSettingsUpdated(graphics_tablet); |
| } |
| } |
| |
| mojom::CustomizationRestriction |
| InputDeviceSettingsControllerImpl::GetMouseCustomizationRestriction( |
| const ui::InputDevice& mouse) { |
| const auto* mouse_metadata = GetMouseMetadata(mouse); |
| if (mouse_metadata) { |
| return mouse_metadata->customization_restriction; |
| } |
| const auto* keyboard_mouse_combo_metadata = |
| GetKeyboardMouseComboMetadata(mouse); |
| if (keyboard_mouse_combo_metadata) { |
| return keyboard_mouse_combo_metadata->customization_restriction; |
| } |
| |
| return mojom::CustomizationRestriction::kDisableKeyEventRewrites; |
| } |
| |
| mojom::CustomizationRestriction |
| InputDeviceSettingsControllerImpl::GetGraphicsTabletCustomizationRestriction( |
| const ui::InputDevice& graphics_tablet) { |
| const auto* graphics_tablet_metadata = |
| GetGraphicsTabletMetadata(graphics_tablet); |
| if (graphics_tablet_metadata) { |
| return graphics_tablet_metadata->customization_restriction; |
| } |
| |
| return mojom::CustomizationRestriction::kAllowCustomizations; |
| } |
| |
| mojom::MouseButtonConfig |
| InputDeviceSettingsControllerImpl::GetMouseButtonConfig( |
| const ui::InputDevice& mouse) { |
| const auto* mouse_metadata = GetMouseMetadata(mouse); |
| if (mouse_metadata) { |
| return mouse_metadata->mouse_button_config; |
| } |
| |
| return mojom::MouseButtonConfig::kNoConfig; |
| } |
| |
| mojom::GraphicsTabletButtonConfig |
| InputDeviceSettingsControllerImpl::GetGraphicsTabletButtonConfig( |
| const ui::InputDevice& graphics_tablet) { |
| const auto* graphics_tablet_metadata = |
| GetGraphicsTabletMetadata(graphics_tablet); |
| if (graphics_tablet_metadata) { |
| return graphics_tablet_metadata->graphics_tablet_button_config; |
| } |
| |
| return mojom::GraphicsTabletButtonConfig::kNoConfig; |
| } |
| |
| void InputDeviceSettingsControllerImpl::OnKeyboardListUpdated( |
| std::vector<ui::KeyboardDevice> keyboards_to_add, |
| std::vector<DeviceId> keyboard_ids_to_remove) { |
| for (const auto& keyboard : keyboards_to_add) { |
| // Get initial settings from the pref manager and generate our local |
| // storage of the device. |
| auto mojom_keyboard = BuildMojomKeyboard(keyboard); |
| InitializeKeyboardSettings(mojom_keyboard.get()); |
| keyboards_.insert_or_assign(keyboard.id, std::move(mojom_keyboard)); |
| DispatchKeyboardConnected(keyboard.id); |
| } |
| |
| for (const auto id : keyboard_ids_to_remove) { |
| DispatchKeyboardDisconnectedAndEraseFromList(id); |
| } |
| |
| RefreshCachedKeyboardSettings(); |
| } |
| |
| void InputDeviceSettingsControllerImpl::OnTouchpadListUpdated( |
| std::vector<ui::TouchpadDevice> touchpads_to_add, |
| std::vector<DeviceId> touchpad_ids_to_remove) { |
| for (const auto& touchpad : touchpads_to_add) { |
| auto mojom_touchpad = BuildMojomTouchpad(touchpad); |
| InitializeTouchpadSettings(mojom_touchpad.get()); |
| touchpads_.insert_or_assign(touchpad.id, std::move(mojom_touchpad)); |
| DispatchTouchpadConnected(touchpad.id); |
| } |
| |
| for (const auto id : touchpad_ids_to_remove) { |
| DispatchTouchpadDisconnectedAndEraseFromList(id); |
| } |
| |
| RefreshCachedTouchpadSettings(); |
| } |
| |
| void InputDeviceSettingsControllerImpl::OnMouseListUpdated( |
| std::vector<ui::InputDevice> mice_to_add, |
| std::vector<DeviceId> mouse_ids_to_remove) { |
| for (const auto& mouse : mice_to_add) { |
| auto mojom_mouse = |
| BuildMojomMouse(mouse, GetMouseCustomizationRestriction(mouse), |
| GetMouseButtonConfig(mouse)); |
| if (features::IsPeripheralNotificationEnabled()) { |
| notification_controller_->NotifyMouseFirstTimeConnected(*mojom_mouse); |
| } |
| |
| InitializeMouseSettings(mojom_mouse.get()); |
| mice_.insert_or_assign(mouse.id, std::move(mojom_mouse)); |
| DispatchMouseConnected(mouse.id); |
| } |
| |
| for (const auto id : mouse_ids_to_remove) { |
| DispatchMouseDisconnectedAndEraseFromList(id); |
| } |
| |
| RefreshCachedMouseSettings(); |
| } |
| |
| void InputDeviceSettingsControllerImpl::OnPointingStickListUpdated( |
| std::vector<ui::InputDevice> pointing_sticks_to_add, |
| std::vector<DeviceId> pointing_stick_ids_to_remove) { |
| for (const auto& pointing_stick : pointing_sticks_to_add) { |
| auto mojom_pointing_stick = BuildMojomPointingStick(pointing_stick); |
| InitializePointingStickSettings(mojom_pointing_stick.get()); |
| pointing_sticks_.insert_or_assign(pointing_stick.id, |
| std::move(mojom_pointing_stick)); |
| DispatchPointingStickConnected(pointing_stick.id); |
| } |
| |
| for (const auto id : pointing_stick_ids_to_remove) { |
| DispatchPointingStickDisconnectedAndEraseFromList(id); |
| } |
| |
| RefreshStoredLoginScreenPointingStickSettings(); |
| } |
| |
| void InputDeviceSettingsControllerImpl::OnGraphicsTabletListUpdated( |
| std::vector<ui::InputDevice> graphics_tablets_to_add, |
| std::vector<DeviceId> graphics_tablet_ids_to_remove) { |
| for (const auto& graphics_tablet : graphics_tablets_to_add) { |
| auto mojom_graphics_tablet = BuildMojomGraphicsTablet( |
| graphics_tablet, |
| GetGraphicsTabletCustomizationRestriction(graphics_tablet), |
| GetGraphicsTabletButtonConfig(graphics_tablet)); |
| InitializeGraphicsTabletSettings(mojom_graphics_tablet.get()); |
| if (features::IsPeripheralNotificationEnabled()) { |
| notification_controller_->NotifyGraphicsTabletFirstTimeConnected( |
| mojom_graphics_tablet.get()); |
| } |
| |
| graphics_tablets_.insert_or_assign(graphics_tablet.id, |
| std::move(mojom_graphics_tablet)); |
| DispatchGraphicsTabletConnected(graphics_tablet.id); |
| } |
| |
| for (const auto id : graphics_tablet_ids_to_remove) { |
| DispatchGraphicsTabletDisconnectedAndEraseFromList(id); |
| } |
| RefreshStoredLoginScreenGraphicsTabletSettings(); |
| } |
| |
| void InputDeviceSettingsControllerImpl::RestoreDefaultKeyboardRemappings( |
| DeviceId id) { |
| DCHECK(base::Contains(keyboards_, id)); |
| auto& keyboard = *keyboards_.at(id); |
| mojom::KeyboardSettingsPtr new_settings = keyboard.settings->Clone(); |
| new_settings->modifier_remappings = {}; |
| new_settings->six_pack_key_remappings = mojom::SixPackKeyInfo::New(); |
| if (keyboard.meta_key == mojom::MetaKey::kCommand) { |
| new_settings->modifier_remappings[ui::mojom::ModifierKey::kControl] = |
| ui::mojom::ModifierKey::kMeta; |
| new_settings->modifier_remappings[ui::mojom::ModifierKey::kMeta] = |
| ui::mojom::ModifierKey::kControl; |
| } |
| metrics_manager_->RecordKeyboardNumberOfKeysReset(keyboard, *new_settings); |
| SetKeyboardSettings(id, std::move(new_settings)); |
| } |
| |
| void InputDeviceSettingsControllerImpl::InitializeKeyboardSettings( |
| mojom::Keyboard* keyboard) { |
| if (active_pref_service_) { |
| keyboard_pref_handler_->InitializeKeyboardSettings( |
| active_pref_service_, policy_handler_->keyboard_policies(), keyboard); |
| metrics_manager_->RecordKeyboardInitialMetrics(*keyboard); |
| return; |
| } |
| |
| // Ensure `keyboard.settings` is left in a valid state. This state occurs |
| // during OOBE setup and when signing in a new user. |
| if (!active_account_id_.has_value() || !local_state_) { |
| keyboard_pref_handler_->InitializeWithDefaultKeyboardSettings( |
| policy_handler_->keyboard_policies(), keyboard); |
| return; |
| } |
| |
| keyboard_pref_handler_->InitializeLoginScreenKeyboardSettings( |
| local_state_, active_account_id_.value(), |
| policy_handler_->keyboard_policies(), keyboard); |
| } |
| |
| // GetGeneralizedTopRowAreFKeys returns false if there is no keyboard. If there |
| // is only internal keyboard, GetGeneralizedTopRowAreFKeys returns the |
| // top_row_are_fkeys of it. If there are multiple keyboards, |
| // GetGeneralizedTopRowAreFKeys returns the top_row_are_fkeys of latest external |
| // keyboard which has the largest device id. |
| bool InputDeviceSettingsControllerImpl::GetGeneralizedTopRowAreFKeys() { |
| auto external_iter = base::ranges::find( |
| keyboards_.rbegin(), keyboards_.rend(), /*value=*/true, |
| [](const auto& keyboard) { return keyboard.second->is_external; }); |
| auto internal_iter = base::ranges::find( |
| keyboards_.rbegin(), keyboards_.rend(), /*value=*/false, |
| [](const auto& keyboard) { return keyboard.second->is_external; }); |
| if (external_iter != keyboards_.rend()) { |
| return external_iter->second->settings->top_row_are_fkeys; |
| } |
| if (internal_iter != keyboards_.rend()) { |
| return internal_iter->second->settings->top_row_are_fkeys; |
| } |
| return false; |
| } |
| |
| void InputDeviceSettingsControllerImpl::InitializeMouseSettings( |
| mojom::Mouse* mouse) { |
| if (active_pref_service_) { |
| mouse_pref_handler_->InitializeMouseSettings( |
| active_pref_service_, policy_handler_->mouse_policies(), mouse); |
| metrics_manager_->RecordMouseInitialMetrics(*mouse); |
| return; |
| } |
| |
| // Ensure `mouse.settings` is left in a valid state. This state occurs |
| // during OOBE setup and when signing in a new user. |
| if (!active_account_id_.has_value() || !local_state_) { |
| mouse_pref_handler_->InitializeWithDefaultMouseSettings( |
| policy_handler_->mouse_policies(), mouse); |
| return; |
| } |
| |
| mouse_pref_handler_->InitializeLoginScreenMouseSettings( |
| local_state_, active_account_id_.value(), |
| policy_handler_->mouse_policies(), mouse); |
| } |
| |
| void InputDeviceSettingsControllerImpl::InitializePointingStickSettings( |
| mojom::PointingStick* pointing_stick) { |
| if (active_pref_service_) { |
| pointing_stick_pref_handler_->InitializePointingStickSettings( |
| active_pref_service_, pointing_stick); |
| metrics_manager_->RecordPointingStickInitialMetrics(*pointing_stick); |
| return; |
| } |
| |
| // Ensure `pointing_stick.settings` is left in a valid state. This state |
| // occurs during OOBE setup and when signing in a new user. |
| if (!active_account_id_.has_value() || !local_state_) { |
| pointing_stick_pref_handler_->InitializeWithDefaultPointingStickSettings( |
| pointing_stick); |
| return; |
| } |
| |
| pointing_stick_pref_handler_->InitializeLoginScreenPointingStickSettings( |
| local_state_, active_account_id_.value(), pointing_stick); |
| } |
| |
| void InputDeviceSettingsControllerImpl::InitializeGraphicsTabletSettings( |
| mojom::GraphicsTablet* graphics_tablet) { |
| if (active_pref_service_) { |
| graphics_tablet_pref_handler_->InitializeGraphicsTabletSettings( |
| active_pref_service_, graphics_tablet); |
| metrics_manager_->RecordGraphicsTabletInitialMetrics(*graphics_tablet); |
| return; |
| } |
| |
| // If there is no active account id or local state isn't initialized, use |
| // default graphics tablet settings. This can happen as an uncommon race |
| // condition when first signing in on the login screen. |
| if (!active_account_id_ || !local_state_) { |
| graphics_tablet->settings = mojom::GraphicsTabletSettings::New(); |
| return; |
| } |
| |
| graphics_tablet_pref_handler_->InitializeLoginScreenGraphicsTabletSettings( |
| local_state_, active_account_id_.value(), graphics_tablet); |
| } |
| |
| void InputDeviceSettingsControllerImpl::InitializeTouchpadSettings( |
| mojom::Touchpad* touchpad) { |
| if (active_pref_service_) { |
| touchpad_pref_handler_->InitializeTouchpadSettings(active_pref_service_, |
| touchpad); |
| metrics_manager_->RecordTouchpadInitialMetrics(*touchpad); |
| return; |
| } |
| |
| // Ensure `touchpad.settings` is left in a valid state. This state occurs |
| // during OOBE setup and when signing in a new user. |
| if (!active_account_id_.has_value() || !local_state_) { |
| touchpad_pref_handler_->InitializeWithDefaultTouchpadSettings(touchpad); |
| return; |
| } |
| |
| touchpad_pref_handler_->InitializeLoginScreenTouchpadSettings( |
| local_state_, active_account_id_.value(), touchpad); |
| } |
| |
| const mojom::Mouse* InputDeviceSettingsControllerImpl::GetMouse(DeviceId id) { |
| return FindMouse(id); |
| } |
| |
| const mojom::Touchpad* InputDeviceSettingsControllerImpl::GetTouchpad( |
| DeviceId id) { |
| return FindTouchpad(id); |
| } |
| |
| const mojom::Keyboard* InputDeviceSettingsControllerImpl::GetKeyboard( |
| DeviceId id) { |
| return FindKeyboard(id); |
| } |
| |
| const mojom::GraphicsTablet* |
| InputDeviceSettingsControllerImpl::GetGraphicsTablet(DeviceId id) { |
| return FindGraphicsTablet(id); |
| } |
| |
| const mojom::PointingStick* InputDeviceSettingsControllerImpl::GetPointingStick( |
| DeviceId id) { |
| return FindPointingStick(id); |
| } |
| |
| mojom::Mouse* InputDeviceSettingsControllerImpl::FindMouse(DeviceId id) { |
| return FindDevice(id, duplicate_id_finder_.get(), mice_); |
| } |
| |
| mojom::Touchpad* InputDeviceSettingsControllerImpl::FindTouchpad(DeviceId id) { |
| return FindDevice(id, duplicate_id_finder_.get(), touchpads_); |
| } |
| |
| mojom::Keyboard* InputDeviceSettingsControllerImpl::FindKeyboard(DeviceId id) { |
| return FindDevice(id, duplicate_id_finder_.get(), keyboards_); |
| } |
| |
| mojom::GraphicsTablet* InputDeviceSettingsControllerImpl::FindGraphicsTablet( |
| DeviceId id) { |
| return FindDevice(id, duplicate_id_finder_.get(), graphics_tablets_); |
| } |
| |
| mojom::PointingStick* InputDeviceSettingsControllerImpl::FindPointingStick( |
| DeviceId id) { |
| return FindDevice(id, duplicate_id_finder_.get(), pointing_sticks_); |
| } |
| |
| void InputDeviceSettingsControllerImpl::StartObservingButtons(DeviceId id) { |
| DCHECK(features::IsPeripheralCustomizationEnabled()); |
| PeripheralCustomizationEventRewriter* rewriter = |
| Shell::Get() |
| ->event_rewriter_controller() |
| ->peripheral_customization_event_rewriter(); |
| CHECK(rewriter); |
| auto* mouse = FindMouse(id); |
| if (mouse && |
| mouse->customization_restriction != |
| ash::mojom::CustomizationRestriction::kDisallowCustomizations) { |
| const auto* duplicate_ids = |
| duplicate_id_finder_->GetDuplicateDeviceIds(mouse->id); |
| CHECK(duplicate_ids); |
| for (const auto& duplicate_id : *duplicate_ids) { |
| rewriter->StartObservingMouse(duplicate_id, |
| mouse->customization_restriction); |
| } |
| for (auto& observer : observers_) { |
| observer.OnCustomizableMouseObservingStarted(*mouse); |
| } |
| return; |
| } |
| |
| auto* graphics_tablet = FindGraphicsTablet(id); |
| if (graphics_tablet && |
| graphics_tablet->customization_restriction != |
| ash::mojom::CustomizationRestriction::kDisallowCustomizations) { |
| const auto* duplicate_ids = |
| duplicate_id_finder_->GetDuplicateDeviceIds(graphics_tablet->id); |
| CHECK(duplicate_ids); |
| for (const auto& duplicate_id : *duplicate_ids) { |
| rewriter->StartObservingGraphicsTablet( |
| duplicate_id, graphics_tablet->customization_restriction); |
| } |
| return; |
| } |
| } |
| |
| void InputDeviceSettingsControllerImpl::StopObservingButtons() { |
| DCHECK(features::IsPeripheralCustomizationEnabled()); |
| PeripheralCustomizationEventRewriter* rewriter = |
| Shell::Get() |
| ->event_rewriter_controller() |
| ->peripheral_customization_event_rewriter(); |
| CHECK(rewriter); |
| rewriter->StopObserving(); |
| |
| for (auto& observer : observers_) { |
| observer.OnCustomizableMouseObservingStopped(); |
| } |
| } |
| |
| void InputDeviceSettingsControllerImpl::OnMouseButtonPressed( |
| DeviceId device_id, |
| const mojom::Button& button) { |
| DCHECK(features::IsPeripheralCustomizationEnabled()); |
| auto* mouse_ptr = FindMouse(device_id); |
| if (!mouse_ptr) { |
| return; |
| } |
| |
| auto& mouse = *mouse_ptr; |
| auto& button_remappings = mouse.settings->button_remappings; |
| auto remapping_iter = |
| base::ranges::find(button_remappings, button, |
| [](const mojom::ButtonRemappingPtr& remapping) { |
| return *remapping->button; |
| }); |
| if (remapping_iter != button_remappings.end()) { |
| DispatchCustomizableMouseButtonPressed(mouse, button); |
| return; |
| } |
| |
| AddButtonToButtonRemappingList(button, button_remappings, |
| /*is_mouse_button_remapping=*/true); |
| mouse_pref_handler_->UpdateMouseSettings( |
| active_pref_service_, policy_handler_->mouse_policies(), mouse); |
| DispatchCustomizableMouseButtonPressed(mouse, button); |
| metrics_manager_->RecordNewButtonRegisteredMetrics(button, kMouseDeviceType); |
| DispatchMouseSettingsChanged(mouse_ptr->id); |
| |
| UpdateDuplicateDeviceSettings( |
| mouse, mice_, |
| base::BindRepeating( |
| &InputDeviceSettingsControllerImpl::DispatchMouseSettingsChanged, |
| base::Unretained(this))); |
| } |
| |
| void InputDeviceSettingsControllerImpl::OnGraphicsTabletButtonPressed( |
| DeviceId device_id, |
| const mojom::Button& button) { |
| DCHECK(features::IsPeripheralCustomizationEnabled()); |
| auto* graphics_tablet_ptr = FindGraphicsTablet(device_id); |
| if (!graphics_tablet_ptr) { |
| return; |
| } |
| |
| auto& graphics_tablet = *graphics_tablet_ptr; |
| auto& tablet_button_remappings = |
| graphics_tablet.settings->tablet_button_remappings; |
| auto tablet_remapping_iter = |
| base::ranges::find(tablet_button_remappings, button, |
| [](const mojom::ButtonRemappingPtr& remapping) { |
| return *remapping->button; |
| }); |
| if (tablet_remapping_iter != tablet_button_remappings.end()) { |
| DispatchCustomizableTabletButtonPressed(graphics_tablet, button); |
| return; |
| } |
| |
| auto& pen_button_remappings = graphics_tablet.settings->pen_button_remappings; |
| auto pen_remapping_iter = |
| base::ranges::find(pen_button_remappings, button, |
| [](const mojom::ButtonRemappingPtr& remapping) { |
| return *remapping->button; |
| }); |
| if (pen_remapping_iter != pen_button_remappings.end()) { |
| DispatchCustomizablePenButtonPressed(graphics_tablet, button); |
| return; |
| } |
| |
| if (IsGraphicsTabletPenButton(button)) { |
| AddButtonToButtonRemappingList(button, pen_button_remappings, |
| /*is_mouse_button_remapping=*/false); |
| DispatchCustomizablePenButtonPressed(graphics_tablet, button); |
| metrics_manager_->RecordNewButtonRegisteredMetrics( |
| button, kGraphicsTabletPenDeviceType); |
| } else { |
| AddButtonToButtonRemappingList(button, tablet_button_remappings, |
| /*is_mouse_button_remapping=*/false); |
| DispatchCustomizableTabletButtonPressed(graphics_tablet, button); |
| metrics_manager_->RecordNewButtonRegisteredMetrics( |
| button, kGraphicsTabletDeviceType); |
| } |
| graphics_tablet_pref_handler_->UpdateGraphicsTabletSettings( |
| active_pref_service_, graphics_tablet); |
| DispatchGraphicsTabletSettingsChanged(graphics_tablet_ptr->id); |
| |
| UpdateDuplicateDeviceSettings( |
| graphics_tablet, graphics_tablets_, |
| base::BindRepeating(&InputDeviceSettingsControllerImpl:: |
| DispatchGraphicsTabletSettingsChanged, |
| base::Unretained(this))); |
| } |
| |
| void InputDeviceSettingsControllerImpl::DispatchCustomizableMouseButtonPressed( |
| const mojom::Mouse& mouse, |
| const mojom::Button& button) { |
| for (auto& observer : observers_) { |
| observer.OnCustomizableMouseButtonPressed(mouse, button); |
| } |
| } |
| |
| void InputDeviceSettingsControllerImpl::DispatchCustomizableTabletButtonPressed( |
| const mojom::GraphicsTablet& graphics_tablet, |
| const mojom::Button& button) { |
| for (auto& observer : observers_) { |
| observer.OnCustomizableTabletButtonPressed(graphics_tablet, button); |
| } |
| } |
| |
| void InputDeviceSettingsControllerImpl::DispatchCustomizablePenButtonPressed( |
| const mojom::GraphicsTablet& graphics_tablet, |
| const mojom::Button& button) { |
| for (auto& observer : observers_) { |
| observer.OnCustomizablePenButtonPressed(graphics_tablet, button); |
| } |
| } |
| |
| void InputDeviceSettingsControllerImpl::RefreshInternalPointingStickSettings() { |
| for (auto& [id, pointing_stick] : pointing_sticks_) { |
| if (pointing_stick->is_external) { |
| continue; |
| } |
| |
| InitializePointingStickSettings(pointing_stick.get()); |
| DispatchPointingStickSettingsChanged(id); |
| } |
| } |
| |
| void InputDeviceSettingsControllerImpl::RefreshInternalTouchpadSettings() { |
| for (auto& [id, touchpad] : touchpads_) { |
| if (touchpad->is_external) { |
| continue; |
| } |
| |
| InitializeTouchpadSettings(touchpad.get()); |
| DispatchTouchpadSettingsChanged(id); |
| } |
| } |
| |
| void InputDeviceSettingsControllerImpl::RefreshCachedMouseSettings() { |
| RefreshStoredLoginScreenMouseSettings(); |
| RefreshMouseDefaultSettings(); |
| } |
| |
| void InputDeviceSettingsControllerImpl::RefreshCachedKeyboardSettings() { |
| RefreshStoredLoginScreenKeyboardSettings(); |
| RefreshKeyboardDefaultSettings(); |
| } |
| |
| void InputDeviceSettingsControllerImpl::RefreshCachedTouchpadSettings() { |
| RefreshStoredLoginScreenTouchpadSettings(); |
| RefreshTouchpadDefaultSettings(); |
| } |
| |
| void InputDeviceSettingsControllerImpl::RefreshMouseDefaultSettings() { |
| if (!active_pref_service_ || mice_.empty()) { |
| return; |
| } |
| |
| mouse_pref_handler_->UpdateDefaultMouseSettings( |
| active_pref_service_, policy_handler_->mouse_policies(), |
| *mice_.rbegin()->second); |
| } |
| |
| void InputDeviceSettingsControllerImpl::RefreshKeyboardDefaultSettings() { |
| if (!active_pref_service_) { |
| return; |
| } |
| |
| auto chromeos_iter = |
| base::ranges::find(keyboards_.rbegin(), keyboards_.rend(), /*value=*/true, |
| [](const auto& keyboard) { |
| return IsChromeOSKeyboard(*keyboard.second); |
| }); |
| auto non_chromeos_iter = |
| base::ranges::find(keyboards_.rbegin(), keyboards_.rend(), |
| /*value=*/false, [](const auto& keyboard) { |
| return IsChromeOSKeyboard(*keyboard.second); |
| ; |
| }); |
| |
| if (chromeos_iter != keyboards_.rend()) { |
| keyboard_pref_handler_->UpdateDefaultChromeOSKeyboardSettings( |
| active_pref_service_, policy_handler_->keyboard_policies(), |
| *chromeos_iter->second); |
| } |
| |
| if (non_chromeos_iter != keyboards_.rend()) { |
| keyboard_pref_handler_->UpdateDefaultNonChromeOSKeyboardSettings( |
| active_pref_service_, policy_handler_->keyboard_policies(), |
| *non_chromeos_iter->second); |
| } |
| } |
| |
| void InputDeviceSettingsControllerImpl::RefreshTouchpadDefaultSettings() { |
| if (!active_pref_service_ || touchpads_.empty()) { |
| return; |
| } |
| |
| touchpad_pref_handler_->UpdateDefaultTouchpadSettings( |
| active_pref_service_, *touchpads_.rbegin()->second); |
| } |
| |
| void InputDeviceSettingsControllerImpl::RefreshKeyDisplay() { |
| for (auto& [_, mouse] : mice_) { |
| RefreshKeyDisplayMouse(*mouse); |
| DispatchMouseSettingsChanged(mouse->id); |
| } |
| |
| for (auto& [_, graphics_tablet] : graphics_tablets_) { |
| RefreshKeyDisplayGraphicsTablet(*graphics_tablet); |
| DispatchGraphicsTabletSettingsChanged(graphics_tablet->id); |
| } |
| } |
| |
| void InputDeviceSettingsControllerImpl::InputMethodChanged( |
| input_method::InputMethodManager* manager, |
| Profile* profile, |
| bool show_message) { |
| if (!features::IsPeripheralCustomizationEnabled()) { |
| return; |
| } |
| |
| // Must be posted as a task because the data source for key display values is |
| // not yet updated right when this is called. |
| sequenced_task_runner_->PostTask( |
| FROM_HERE, |
| base::BindOnce(&InputDeviceSettingsControllerImpl::RefreshKeyDisplay, |
| weak_ptr_factory_.GetWeakPtr())); |
| } |
| |
| } // namespace ash |