chromium/ash/accelerators/accelerator_alias_converter_unittest.cc

// Copyright 2023 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/accelerators/accelerator_alias_converter.h"

#include <optional>
#include <vector>

#include "ash/constants/ash_features.h"
#include "ash/constants/ash_pref_names.h"
#include "ash/constants/ash_switches.h"
#include "ash/keyboard/keyboard_controller_impl.h"
#include "ash/public/mojom/input_device_settings.mojom.h"
#include "ash/session/session_controller_impl.h"
#include "ash/shell.h"
#include "ash/system/input_device_settings/input_device_settings_controller_impl.h"
#include "ash/test/ash_test_base.h"
#include "base/containers/flat_map.h"
#include "base/files/file_path.h"
#include "base/test/scoped_feature_list.h"
#include "device/udev_linux/fake_udev_loader.h"
#include "ui/base/accelerators/accelerator.h"
#include "ui/base/ui_base_features.h"
#include "ui/events/ash/keyboard_capability.h"
#include "ui/events/ash/mojom/six_pack_shortcut_modifier.mojom-shared.h"
#include "ui/events/devices/device_data_manager_test_api.h"
#include "ui/events/devices/keyboard_device.h"
#include "ui/events/event_constants.h"
#include "ui/events/keycodes/keyboard_codes_posix.h"

namespace ash {

namespace {

constexpr char kKbdTopRowPropertyName[] = "CROS_KEYBOARD_TOP_ROW_LAYOUT";

constexpr char kKbdTopRowLayoutUnspecified[] = "";
constexpr char kKbdTopRowLayout1Tag[] = "1";
constexpr char kKbdTopRowLayout2Tag[] = "2";
constexpr char kKbdTopRowLayoutWilcoTag[] = "3";
constexpr char kKbdTopRowLayoutDrallionTag[] = "4";

struct AcceleratorAliasConverterTestData {
  ui::Accelerator accelerator_;
  std::optional<ui::Accelerator> expected_accelerators_;
};

struct TopRowAcceleratorAliasConverterTestData {
  // All currently connected keyboards' connection type, e.g.
  // INPUT_DEVICE_INTERNAL.
  std::vector<ui::InputDeviceType> keyboard_connection_type_;
  // All currently connected keyboards' layout types.
  std::vector<std::string> keyboard_layout_types_;
  ui::Accelerator accelerator_;
  std::vector<ui::Accelerator> expected_accelerators_;
};

struct ActionKeyAliasConverterTestData {
  // All currently connected keyboards' connection type, e.g.
  // INPUT_DEVICE_INTERNAL.
  std::vector<ui::InputDeviceType> keyboard_connection_type_;
  // All currently connected keyboards' layout types.
  std::vector<std::string> keyboard_layout_types_;
  std::vector<bool> top_row_are_fkeys_;
  ui::Accelerator accelerator_;
  std::vector<ui::Accelerator> expected_accelerators_;
};

class FakeDeviceManager {
 public:
  FakeDeviceManager() = default;
  FakeDeviceManager(const FakeDeviceManager&) = delete;
  FakeDeviceManager& operator=(const FakeDeviceManager&) = delete;
  ~FakeDeviceManager() = default;

  // Add a fake keyboard to DeviceDataManagerTestApi and provide layout info to
  // fake udev.
  void AddFakeKeyboard(const ui::KeyboardDevice& fake_keyboard,
                       const std::string& layout) {
    fake_keyboard_devices_.push_back(fake_keyboard);

    ui::DeviceDataManagerTestApi().SetKeyboardDevices({});
    ui::DeviceDataManagerTestApi().SetKeyboardDevices(fake_keyboard_devices_);
    ui::DeviceDataManagerTestApi().OnDeviceListsComplete();

    std::map<std::string, std::string> sysfs_properties;
    std::map<std::string, std::string> sysfs_attributes;
    sysfs_properties[kKbdTopRowPropertyName] = layout;
    fake_udev_.AddFakeDevice(fake_keyboard.name, fake_keyboard.sys_path.value(),
                             /*subsystem=*/"input", /*devnode=*/std::nullopt,
                             /*devtype=*/std::nullopt,
                             std::move(sysfs_attributes),
                             std::move(sysfs_properties));
  }

  void RemoveAllDevices() {
    fake_udev_.Reset();
    fake_keyboard_devices_.clear();
  }

 private:
  testing::FakeUdevLoader fake_udev_;
  std::vector<ui::KeyboardDevice> fake_keyboard_devices_;
};

}  // namespace

class AcceleratorAliasConverterTest : public AshTestBase {
 public:
  void SetUp() override {
    scoped_feature_list_.InitAndEnableFeature(
        features::kInputDeviceSettingsSplit);
    AshTestBase::SetUp();
  }

  void TearDown() override {
    AshTestBase::TearDown();
    scoped_feature_list_.Reset();
  }

  void CheckFKeyAddToSixPackKeyAlias() {
    for (auto entry : ui::kSixPackKeyToFnKeyMap) {
      AcceleratorAliasConverter accelerator_alias_converter_;
      const ui::Accelerator accelerator{entry.first, ui::EF_ALT_DOWN};
      std::vector<ui::Accelerator> accelerator_aliases =
          accelerator_alias_converter_.CreateAcceleratorAlias(accelerator);

      EXPECT_EQ(1u, accelerator_aliases.size());
      const ui::Accelerator expected_accelerator{
          entry.second, ui::EF_ALT_DOWN | ui::EF_FUNCTION_DOWN,
          accelerator.key_state()};
      EXPECT_EQ(expected_accelerator, accelerator_aliases[0]);
    }

    AcceleratorAliasConverter accelerator_alias_converter_;
    const ui::Accelerator accelerator{ui::KeyboardCode::VKEY_INSERT,
                                      ui::EF_ALT_DOWN};
    std::vector<ui::Accelerator> accelerator_aliases =
        accelerator_alias_converter_.CreateAcceleratorAlias(accelerator);

    EXPECT_EQ(0u, accelerator_aliases.size());
  }

  std::optional<ui::KeyboardCode> GetActionVKey(
      ui::KeyboardDevice& keyboard,
      const ui::Accelerator accelerator) {
    std::optional<ui::TopRowActionKey> action_key =
        Shell::Get()->keyboard_capability()->GetCorrespondingActionKeyForFKey(
            keyboard, accelerator.key_code());

    // Convert the `ui::TopRowActionKey` to the corresponding `ui::KeyboardCode`
    std::optional<ui::KeyboardCode> action_vkey =
        ui::KeyboardCapability::ConvertToKeyboardCode(*action_key);
    return action_vkey;
  }

  void SetTopRowAsFKeysForKeyboard(const ui::InputDevice& keyboard,
                                   bool enabled) {
    if (!features::IsInputDeviceSettingsSplitEnabled()) {
      // Top row keys not fKeys prevents remapping.
      Shell::Get()->session_controller()->GetActivePrefService()->SetBoolean(
          prefs::kSendFunctionKeys, enabled);
      EXPECT_EQ(
          enabled,
          Shell::Get()->keyboard_controller()->AreTopRowKeysFunctionKeys());
      return;
    }

    auto settings = Shell::Get()
                        ->input_device_settings_controller()
                        ->GetKeyboardSettings(keyboard.id)
                        ->Clone();
    settings->top_row_are_fkeys = enabled;
    Shell::Get()->input_device_settings_controller()->SetKeyboardSettings(
        keyboard.id, std::move(settings));
  }

  void SetKeyboardInfo(
      const ui::KeyboardDevice& keyboard,
      ui::KeyboardCapability::DeviceType device_type,
      ui::KeyboardCapability::KeyboardTopRowLayout top_row_layout) {
    ui::KeyboardCapability::KeyboardInfo keyboard_info;
    keyboard_info.device_type = device_type;
    keyboard_info.top_row_layout = top_row_layout;
    keyboard_info.top_row_action_keys = std::vector<ui::TopRowActionKey>(
        std::begin(ui::kLayout1TopRowActionKeys),
        std::end(ui::kLayout1TopRowActionKeys));
    switch (top_row_layout) {
      case ui::KeyboardCapability::KeyboardTopRowLayout::kKbdTopRowLayout1:
        keyboard_info.top_row_action_keys = std::vector<ui::TopRowActionKey>(
            std::begin(ui::kLayout1TopRowActionKeys),
            std::end(ui::kLayout1TopRowActionKeys));
        break;

      case ui::KeyboardCapability::KeyboardTopRowLayout::kKbdTopRowLayout2:
        keyboard_info.top_row_action_keys = std::vector<ui::TopRowActionKey>(
            std::begin(ui::kLayout2TopRowActionKeys),
            std::end(ui::kLayout2TopRowActionKeys));
        break;

      case ui::KeyboardCapability::KeyboardTopRowLayout::kKbdTopRowLayoutWilco:
      case ui::KeyboardCapability::KeyboardTopRowLayout::
          kKbdTopRowLayoutDrallion:
        keyboard_info.top_row_action_keys = std::vector<ui::TopRowActionKey>(
            std::begin(ui::kLayoutWilcoDrallionTopRowActionKeys),
            std::end(ui::kLayoutWilcoDrallionTopRowActionKeys));
        break;
      case ui::KeyboardCapability::KeyboardTopRowLayout::kKbdTopRowLayoutCustom:
        break;
    }
    Shell::Get()->keyboard_capability()->SetKeyboardInfoForTesting(
        keyboard, std::move(keyboard_info));
  }

 protected:
  base::test::ScopedFeatureList scoped_feature_list_;
};

TEST_F(AcceleratorAliasConverterTest, UpdateSixPackKeyAliasWithFkey) {
  base::test::ScopedFeatureList feature_list;
  feature_list.InitAndEnableFeature(features::kModifierSplit);
  auto ignore_modifier_split_secret_key =
      ash::switches::SetIgnoreModifierSplitSecretKeyForTest();
  Shell::Get()
      ->keyboard_capability()
      ->ResetModifierSplitDogfoodControllerForTesting();

  std::unique_ptr<FakeDeviceManager> fake_keyboard_manager_ =
      std::make_unique<FakeDeviceManager>();
  ui::KeyboardDevice fake_keyboard(
      /*id=*/1, /*type=*/ui::InputDeviceType::INPUT_DEVICE_INTERNAL,
      /*name=*/kKbdTopRowLayout1Tag, /*has_assistant_key=*/true,
      /*has_function_key=*/true);
  fake_keyboard.sys_path = base::FilePath("path");
  fake_keyboard_manager_->AddFakeKeyboard(fake_keyboard, kKbdTopRowLayout1Tag);

  CheckFKeyAddToSixPackKeyAlias();
}

TEST_F(AcceleratorAliasConverterTest, UpdateTopRowKeysAliasWithFkey) {
  base::test::ScopedFeatureList feature_list;
  feature_list.InitAndEnableFeature(features::kModifierSplit);
  auto ignore_modifier_split_secret_key =
      ash::switches::SetIgnoreModifierSplitSecretKeyForTest();
  Shell::Get()
      ->keyboard_capability()
      ->ResetModifierSplitDogfoodControllerForTesting();

  std::unique_ptr<FakeDeviceManager> fake_keyboard_manager_ =
      std::make_unique<FakeDeviceManager>();
  ui::KeyboardDevice fake_keyboard(
      /*id=*/1, /*type=*/ui::InputDeviceType::INPUT_DEVICE_INTERNAL,
      /*name=*/kKbdTopRowLayout1Tag, /*has_assistant_key=*/true,
      /*has_function_key=*/true);
  fake_keyboard.sys_path = base::FilePath("path");
  fake_keyboard_manager_->AddFakeKeyboard(fake_keyboard, kKbdTopRowLayout1Tag);

  AcceleratorAliasConverter accelerator_alias_converter_;
  const ui::Accelerator accelerator{ui::VKEY_ZOOM, ui::EF_NONE};
  SetTopRowAsFKeysForKeyboard(fake_keyboard, /*enabled=*/true);
  std::vector<ui::Accelerator> accelerator_aliases =
      accelerator_alias_converter_.CreateAcceleratorAlias(accelerator);

  EXPECT_EQ(1u, accelerator_aliases.size());
  const ui::Accelerator expected_accelerator{
      ui::VKEY_ZOOM, ui::EF_FUNCTION_DOWN, accelerator.key_state()};
  EXPECT_EQ(expected_accelerator, accelerator_aliases[0]);

  SetTopRowAsFKeysForKeyboard(fake_keyboard, /*enabled=*/false);
  std::vector<ui::Accelerator> updated_accelerator_aliases =
      accelerator_alias_converter_.CreateAcceleratorAlias(accelerator);

  EXPECT_EQ(1u, updated_accelerator_aliases.size());
  const ui::Accelerator updated_expected_accelerator{ui::VKEY_ZOOM, ui::EF_NONE,
                                                     accelerator.key_state()};
  EXPECT_EQ(updated_expected_accelerator, updated_accelerator_aliases[0]);
}

TEST_F(AcceleratorAliasConverterTest, UpdateFunctionAlias) {
  base::test::ScopedFeatureList feature_list;
  feature_list.InitAndEnableFeature(features::kModifierSplit);
  auto ignore_modifier_split_secret_key =
      ash::switches::SetIgnoreModifierSplitSecretKeyForTest();
  Shell::Get()
      ->keyboard_capability()
      ->ResetModifierSplitDogfoodControllerForTesting();

  std::unique_ptr<FakeDeviceManager> fake_keyboard_manager_ =
      std::make_unique<FakeDeviceManager>();
  ui::KeyboardDevice fake_keyboard(
      /*id=*/1, /*type=*/ui::InputDeviceType::INPUT_DEVICE_INTERNAL,
      /*name=*/kKbdTopRowLayout1Tag, /*has_assistant_key=*/true,
      /*has_function_key=*/true);
  fake_keyboard.sys_path = base::FilePath("path");
  fake_keyboard_manager_->AddFakeKeyboard(fake_keyboard, kKbdTopRowLayout1Tag);

  AcceleratorAliasConverter accelerator_alias_converter_;
  const ui::Accelerator accelerator{ui::VKEY_F1, ui::EF_NONE};
  SetTopRowAsFKeysForKeyboard(fake_keyboard, /*enabled=*/false);
  std::vector<ui::Accelerator> accelerator_aliases =
      accelerator_alias_converter_.CreateAcceleratorAlias(accelerator);

  auto action_vkey_1 = GetActionVKey(fake_keyboard, accelerator);
  ASSERT_TRUE(action_vkey_1);
  EXPECT_EQ(1u, accelerator_aliases.size());
  const ui::Accelerator expected_accelerator{
      action_vkey_1.value(), ui::EF_FUNCTION_DOWN, accelerator.key_state()};
  EXPECT_EQ(expected_accelerator, accelerator_aliases[0]);

  SetTopRowAsFKeysForKeyboard(fake_keyboard, /*enabled=*/true);
  std::vector<ui::Accelerator> updated_accelerator_aliases =
      accelerator_alias_converter_.CreateAcceleratorAlias(accelerator);

  auto action_vkey_2 = GetActionVKey(fake_keyboard, accelerator);
  ASSERT_TRUE(action_vkey_2);
  EXPECT_EQ(1u, accelerator_aliases.size());
  EXPECT_EQ(1u, updated_accelerator_aliases.size());
  const ui::Accelerator updated_expected_accelerator{
      action_vkey_2.value(), ui::EF_NONE, accelerator.key_state()};
  EXPECT_EQ(updated_expected_accelerator, updated_accelerator_aliases[0]);
}

TEST_F(AcceleratorAliasConverterTest, CheckTopRowAliasNoAlias) {
  std::unique_ptr<FakeDeviceManager> fake_keyboard_manager_ =
      std::make_unique<FakeDeviceManager>();
  ui::KeyboardDevice fake_keyboard(
      /*id=*/1, /*type=*/ui::InputDeviceType::INPUT_DEVICE_BLUETOOTH,
      /*name=*/kKbdTopRowLayout1Tag);
  fake_keyboard.sys_path = base::FilePath("path");
  fake_keyboard_manager_->AddFakeKeyboard(fake_keyboard, kKbdTopRowLayout1Tag);

  AcceleratorAliasConverter accelerator_alias_converter_;

  SetTopRowAsFKeysForKeyboard(fake_keyboard, /*enabled=*/false);
  const ui::Accelerator accelerator{ui::VKEY_ZOOM, ui::EF_ALT_DOWN};
  std::vector<ui::Accelerator> accelerator_aliases =
      accelerator_alias_converter_.CreateAcceleratorAlias(accelerator);

  EXPECT_EQ(1u, accelerator_aliases.size());
  EXPECT_EQ(accelerator, accelerator_aliases[0]);
}

TEST_F(AcceleratorAliasConverterTest, CheckGlobeKeyAlias) {
  std::unique_ptr<FakeDeviceManager> fake_keyboard_manager_ =
      std::make_unique<FakeDeviceManager>();
  AcceleratorAliasConverter accelerator_alias_converter_;

  // Globe key is not available in non-wilco/drallion internal devices.
  ui::KeyboardDevice internal_keyboard(
      /*id=*/1, /*type=*/ui::InputDeviceType::INPUT_DEVICE_INTERNAL,
      /*name=*/kKbdTopRowLayout1Tag);
  internal_keyboard.sys_path = base::FilePath("internal_path");
  fake_keyboard_manager_->AddFakeKeyboard(internal_keyboard,
                                          kKbdTopRowLayout1Tag);

  const ui::Accelerator accelerator{ui::VKEY_MODECHANGE, ui::EF_NONE};
  std::vector<ui::Accelerator> accelerator_aliases =
      accelerator_alias_converter_.CreateAcceleratorAlias(accelerator);
  EXPECT_EQ(0u, accelerator_aliases.size());

  // Globe key is available in external keyboard.
  ui::KeyboardDevice fake_keyboard(
      /*id=*/1, /*type=*/ui::InputDeviceType::INPUT_DEVICE_BLUETOOTH,
      /*name=*/kKbdTopRowLayout1Tag);
  fake_keyboard.sys_path = base::FilePath("path");
  fake_keyboard_manager_->AddFakeKeyboard(fake_keyboard, kKbdTopRowLayout1Tag);

  accelerator_aliases =
      accelerator_alias_converter_.CreateAcceleratorAlias(accelerator);
  EXPECT_EQ(1u, accelerator_aliases.size());
  EXPECT_EQ(accelerator, accelerator_aliases[0]);

  // Globe key is available in wilco/drallion keyboards.
  ui::KeyboardDevice wilco_keyboard(
      /*id=*/2, /*type=*/ui::InputDeviceType::INPUT_DEVICE_INTERNAL,
      /*name=*/kKbdTopRowLayout1Tag);
  wilco_keyboard.sys_path = base::FilePath("path2");
  fake_keyboard_manager_->AddFakeKeyboard(wilco_keyboard,
                                          kKbdTopRowLayoutWilcoTag);
  accelerator_aliases =
      accelerator_alias_converter_.CreateAcceleratorAlias(accelerator);
  EXPECT_EQ(1u, accelerator_aliases.size());
  EXPECT_EQ(accelerator, accelerator_aliases[0]);
}

TEST_F(AcceleratorAliasConverterTest, CheckCalculatorKeyAlias) {
  std::unique_ptr<FakeDeviceManager> fake_keyboard_manager_ =
      std::make_unique<FakeDeviceManager>();
  ui::KeyboardDevice fake_keyboard(
      /*id=*/1, /*type=*/ui::InputDeviceType::INPUT_DEVICE_INTERNAL,
      /*name=*/kKbdTopRowLayout1Tag);
  fake_keyboard.sys_path = base::FilePath("path");
  fake_keyboard_manager_->AddFakeKeyboard(fake_keyboard, kKbdTopRowLayout1Tag);

  AcceleratorAliasConverter accelerator_alias_converter_;

  const ui::Accelerator accelerator{ui::VKEY_MEDIA_LAUNCH_APP2, ui::EF_NONE};
  std::vector<ui::Accelerator> accelerator_aliases =
      accelerator_alias_converter_.CreateAcceleratorAlias(accelerator);
  EXPECT_EQ(0u, accelerator_aliases.size());

  ui::KeyboardDevice wilco_keyboard(
      /*id=*/2, /*type=*/ui::InputDeviceType::INPUT_DEVICE_BLUETOOTH,
      /*name=*/kKbdTopRowLayout1Tag);
  wilco_keyboard.sys_path = base::FilePath("path2");
  fake_keyboard_manager_->AddFakeKeyboard(wilco_keyboard,
                                          kKbdTopRowLayoutWilcoTag);
  accelerator_aliases =
      accelerator_alias_converter_.CreateAcceleratorAlias(accelerator);
  EXPECT_EQ(1u, accelerator_aliases.size());
  EXPECT_EQ(accelerator, accelerator_aliases[0]);
}

TEST_F(AcceleratorAliasConverterTest, CheckBrowserSearchKeyAlias) {
  std::unique_ptr<FakeDeviceManager> fake_keyboard_manager_ =
      std::make_unique<FakeDeviceManager>();
  ui::KeyboardDevice fake_keyboard(
      /*id=*/1, /*type=*/ui::InputDeviceType::INPUT_DEVICE_INTERNAL,
      /*name=*/kKbdTopRowLayout1Tag);
  fake_keyboard.sys_path = base::FilePath("path");
  fake_keyboard_manager_->AddFakeKeyboard(fake_keyboard, kKbdTopRowLayout1Tag);

  AcceleratorAliasConverter accelerator_alias_converter_;

  const ui::Accelerator accelerator{ui::VKEY_BROWSER_SEARCH, ui::EF_NONE};
  std::vector<ui::Accelerator> accelerator_aliases =
      accelerator_alias_converter_.CreateAcceleratorAlias(accelerator);
  EXPECT_EQ(0u, accelerator_aliases.size());

  ui::KeyboardDevice wilco_keyboard(
      /*id=*/2, /*type=*/ui::InputDeviceType::INPUT_DEVICE_BLUETOOTH,
      /*name=*/kKbdTopRowLayoutWilcoTag);
  wilco_keyboard.sys_path = base::FilePath("path2");
  fake_keyboard_manager_->AddFakeKeyboard(wilco_keyboard,
                                          kKbdTopRowLayoutWilcoTag);
  accelerator_aliases =
      accelerator_alias_converter_.CreateAcceleratorAlias(accelerator);
  EXPECT_EQ(1u, accelerator_aliases.size());
  EXPECT_EQ(accelerator, accelerator_aliases[0]);
}

TEST_F(AcceleratorAliasConverterTest, CheckHelpKeyAlias) {
  std::unique_ptr<FakeDeviceManager> fake_keyboard_manager_ =
      std::make_unique<FakeDeviceManager>();
  ui::KeyboardDevice fake_keyboard(
      /*id=*/1, /*type=*/ui::InputDeviceType::INPUT_DEVICE_INTERNAL,
      /*name=*/kKbdTopRowLayout1Tag);
  fake_keyboard.sys_path = base::FilePath("path");
  fake_keyboard_manager_->AddFakeKeyboard(fake_keyboard, kKbdTopRowLayout1Tag);

  AcceleratorAliasConverter accelerator_alias_converter_;

  const ui::Accelerator accelerator{ui::VKEY_HELP, ui::EF_NONE};
  std::vector<ui::Accelerator> accelerator_aliases =
      accelerator_alias_converter_.CreateAcceleratorAlias(accelerator);
  EXPECT_EQ(0u, accelerator_aliases.size());

  ui::KeyboardDevice wilco_keyboard(
      /*id=*/2, /*type=*/ui::InputDeviceType::INPUT_DEVICE_BLUETOOTH,
      /*name=*/kKbdTopRowLayoutWilcoTag);
  wilco_keyboard.sys_path = base::FilePath("path2");
  fake_keyboard_manager_->AddFakeKeyboard(wilco_keyboard,
                                          kKbdTopRowLayoutWilcoTag);
  accelerator_aliases =
      accelerator_alias_converter_.CreateAcceleratorAlias(accelerator);
  EXPECT_EQ(1u, accelerator_aliases.size());
  EXPECT_EQ(accelerator, accelerator_aliases[0]);
}

TEST_F(AcceleratorAliasConverterTest, CheckSettingsKeyAlias) {
  std::unique_ptr<FakeDeviceManager> fake_keyboard_manager_ =
      std::make_unique<FakeDeviceManager>();
  ui::KeyboardDevice fake_keyboard(
      /*id=*/1, /*type=*/ui::InputDeviceType::INPUT_DEVICE_INTERNAL,
      /*name=*/kKbdTopRowLayout1Tag);
  fake_keyboard.sys_path = base::FilePath("path");
  fake_keyboard_manager_->AddFakeKeyboard(fake_keyboard, kKbdTopRowLayout1Tag);

  AcceleratorAliasConverter accelerator_alias_converter_;

  const ui::Accelerator accelerator{ui::VKEY_SETTINGS, ui::EF_NONE};
  std::vector<ui::Accelerator> accelerator_aliases =
      accelerator_alias_converter_.CreateAcceleratorAlias(accelerator);
  EXPECT_EQ(0u, accelerator_aliases.size());

  ui::KeyboardDevice wilco_keyboard(
      /*id=*/2, /*type=*/ui::InputDeviceType::INPUT_DEVICE_BLUETOOTH,
      /*name=*/kKbdTopRowLayoutWilcoTag);
  wilco_keyboard.sys_path = base::FilePath("path2");
  fake_keyboard_manager_->AddFakeKeyboard(wilco_keyboard,
                                          kKbdTopRowLayoutWilcoTag);
  accelerator_aliases =
      accelerator_alias_converter_.CreateAcceleratorAlias(accelerator);
  EXPECT_EQ(1u, accelerator_aliases.size());
  EXPECT_EQ(accelerator, accelerator_aliases[0]);
}

TEST_F(AcceleratorAliasConverterTest, SplitModifierKeyboardCapsLockAlias) {
  base::test::ScopedFeatureList feature_list;
  feature_list.InitAndEnableFeature(features::kModifierSplit);
  auto ignore_modifier_split_secret_key =
      ash::switches::SetIgnoreModifierSplitSecretKeyForTest();
  Shell::Get()
      ->keyboard_capability()
      ->ResetModifierSplitDogfoodControllerForTesting();

  std::unique_ptr<FakeDeviceManager> fake_keyboard_manager_ =
      std::make_unique<FakeDeviceManager>();
  ui::KeyboardDevice split_modifier_keyboard(
      /*id=*/1, /*type=*/ui::InputDeviceType::INPUT_DEVICE_INTERNAL,
      /*name=*/kKbdTopRowLayout1Tag, /*has_assistant_key=*/true,
      /*has_function_key=*/true);
  split_modifier_keyboard.sys_path = base::FilePath("path");
  fake_keyboard_manager_->AddFakeKeyboard(split_modifier_keyboard,
                                          kKbdTopRowLayout1Tag);

  AcceleratorAliasConverter accelerator_alias_converter_;
  const ui::Accelerator capslock_accelerator{ui::VKEY_CAPITAL, ui::EF_NONE};
  std::vector<ui::Accelerator> accelerator_aliases =
      accelerator_alias_converter_.CreateAcceleratorAlias(capslock_accelerator);
  EXPECT_EQ(1u, accelerator_aliases.size());
  EXPECT_EQ(ui::Accelerator(ui::VKEY_RIGHT_ALT, ui::EF_FUNCTION_DOWN),
            accelerator_aliases[0]);
  const ui::Accelerator capslock_accelerator_2{ui::VKEY_LWIN, ui::EF_ALT_DOWN};
  std::vector<ui::Accelerator> new_accelerator_aliases =
      accelerator_alias_converter_.CreateAcceleratorAlias(
          capslock_accelerator_2);
  EXPECT_EQ(0u, new_accelerator_aliases.size());
}

TEST_F(AcceleratorAliasConverterTest, ExternalKeyboardCapsLockAlias) {
  std::unique_ptr<FakeDeviceManager> fake_keyboard_manager_ =
      std::make_unique<FakeDeviceManager>();

  ui::KeyboardDevice external_keyboard(
      /*id=*/1, /*type=*/ui::InputDeviceType::INPUT_DEVICE_BLUETOOTH,
      /*name=*/kKbdTopRowLayout1Tag);
  SetKeyboardInfo(
      external_keyboard,
      ui::KeyboardCapability::DeviceType::kDeviceExternalUnknown,
      ui::KeyboardCapability::KeyboardTopRowLayout::kKbdTopRowLayout1);
  external_keyboard.sys_path = base::FilePath("path");
  fake_keyboard_manager_->AddFakeKeyboard(external_keyboard,
                                          kKbdTopRowLayout1Tag);

  AcceleratorAliasConverter accelerator_alias_converter_;
  const ui::Accelerator capslock_accelerator{ui::VKEY_CAPITAL, ui::EF_NONE};
  std::vector<ui::Accelerator> accelerator_aliases =
      accelerator_alias_converter_.CreateAcceleratorAlias(capslock_accelerator);
  EXPECT_EQ(1u, accelerator_aliases.size());
  EXPECT_EQ(capslock_accelerator, accelerator_aliases[0]);
  const ui::Accelerator capslock_accelerator_2{ui::VKEY_LWIN, ui::EF_ALT_DOWN};
  std::vector<ui::Accelerator> new_accelerator_aliases =
      accelerator_alias_converter_.CreateAcceleratorAlias(
          capslock_accelerator_2);
  EXPECT_EQ(1u, new_accelerator_aliases.size());
  EXPECT_EQ(capslock_accelerator_2, new_accelerator_aliases[0]);
}

TEST_F(AcceleratorAliasConverterTest, CheckCapsLockAlias) {
  std::unique_ptr<FakeDeviceManager> fake_keyboard_manager_ =
      std::make_unique<FakeDeviceManager>();
  ui::KeyboardDevice fake_keyboard(
      /*id=*/1, /*type=*/ui::InputDeviceType::INPUT_DEVICE_INTERNAL,
      /*name=*/kKbdTopRowLayout1Tag);
  fake_keyboard.sys_path = base::FilePath("path");
  fake_keyboard_manager_->AddFakeKeyboard(fake_keyboard, kKbdTopRowLayout1Tag);

  AcceleratorAliasConverter accelerator_alias_converter_;

  const ui::Accelerator good_accelerator{ui::VKEY_LWIN, ui::EF_ALT_DOWN};
  const ui::Accelerator bad_accelerator{ui::VKEY_MENU, ui::EF_COMMAND_DOWN};
  std::vector<ui::Accelerator> accelerator_aliases =
      accelerator_alias_converter_.CreateAcceleratorAlias(good_accelerator);
  EXPECT_EQ(1u, accelerator_aliases.size());
  EXPECT_EQ(good_accelerator, accelerator_aliases[0]);

  accelerator_aliases =
      accelerator_alias_converter_.CreateAcceleratorAlias(bad_accelerator);
  EXPECT_EQ(0u, accelerator_aliases.size());
}

TEST_F(AcceleratorAliasConverterTest, CheckRightAltInList) {
  base::test::ScopedFeatureList feature_list;
  feature_list.InitAndEnableFeature(features::kModifierSplit);
  auto ignore_modifier_split_secret_key =
      ash::switches::SetIgnoreModifierSplitSecretKeyForTest();
  Shell::Get()
      ->keyboard_capability()
      ->ResetModifierSplitDogfoodControllerForTesting();

  std::unique_ptr<FakeDeviceManager> fake_keyboard_manager_ =
      std::make_unique<FakeDeviceManager>();
  ui::KeyboardDevice fake_keyboard(
      /*id=*/1, /*type=*/ui::InputDeviceType::INPUT_DEVICE_INTERNAL,
      /*name=*/kKbdTopRowLayout1Tag, /*has_assistant_key=*/true,
      /*has_function_key=*/true);
  fake_keyboard.sys_path = base::FilePath("path");
  fake_keyboard_manager_->AddFakeKeyboard(fake_keyboard, kKbdTopRowLayout1Tag);

  const ui::Accelerator right_alt_accelerator{ui::VKEY_RIGHT_ALT, ui::EF_NONE};

  AcceleratorAliasConverter accelerator_alias_converter;

  EXPECT_EQ(std::vector<ui::Accelerator>{right_alt_accelerator},
            accelerator_alias_converter.CreateAcceleratorAlias(
                right_alt_accelerator));
}

TEST_F(AcceleratorAliasConverterTest, CheckRightAltNotInList) {
  base::test::ScopedFeatureList feature_list;
  feature_list.InitAndEnableFeature(features::kModifierSplit);
  auto ignore_modifier_split_secret_key =
      ash::switches::SetIgnoreModifierSplitSecretKeyForTest();
  Shell::Get()
      ->keyboard_capability()
      ->ResetModifierSplitDogfoodControllerForTesting();

  std::unique_ptr<FakeDeviceManager> fake_keyboard_manager_ =
      std::make_unique<FakeDeviceManager>();
  ui::KeyboardDevice fake_keyboard(
      /*id=*/1, /*type=*/ui::InputDeviceType::INPUT_DEVICE_INTERNAL,
      /*name=*/kKbdTopRowLayout1Tag);
  fake_keyboard.sys_path = base::FilePath("path");
  fake_keyboard_manager_->AddFakeKeyboard(fake_keyboard, kKbdTopRowLayout1Tag);

  const ui::Accelerator right_alt_accelerator{ui::VKEY_RIGHT_ALT, ui::EF_NONE};

  AcceleratorAliasConverter accelerator_alias_converter;
  EXPECT_TRUE(
      accelerator_alias_converter.CreateAcceleratorAlias(right_alt_accelerator)
          .empty());
}

TEST_F(AcceleratorAliasConverterTest, MetaFKeyRewritesSuppressed) {
  // Needs to be in user session to edit input device settings.
  SimulateGuestLogin();

  std::unique_ptr<FakeDeviceManager> fake_keyboard_manager_ =
      std::make_unique<FakeDeviceManager>();
  ui::KeyboardDevice fake_keyboard(
      /*id=*/1, /*type=*/ui::InputDeviceType::INPUT_DEVICE_BLUETOOTH,
      /*name=*/kKbdTopRowLayoutUnspecified, /*phys=*/"",
      /*sys_path=*/base::FilePath(),
      /*vendor=*/0x2222, /*product=*/0x2222, /*version=*/0x0);
  fake_keyboard.sys_path = base::FilePath("path");
  fake_keyboard_manager_->AddFakeKeyboard(fake_keyboard,
                                          kKbdTopRowLayoutUnspecified);

  mojom::KeyboardSettings settings;
  settings.six_pack_key_remappings = mojom::SixPackKeyInfo::New();
  settings.top_row_are_fkeys = true;
  settings.suppress_meta_fkey_rewrites = false;
  Shell::Get()->input_device_settings_controller()->SetKeyboardSettings(
      fake_keyboard.id, settings.Clone());

  AcceleratorAliasConverter accelerator_alias_converter_;

  const ui::Accelerator refresh_accelerator{ui::VKEY_BROWSER_REFRESH,
                                            ui::EF_NONE};
  std::vector<ui::Accelerator> accelerator_aliases =
      accelerator_alias_converter_.CreateAcceleratorAlias(refresh_accelerator);
  ASSERT_EQ(2u, accelerator_aliases.size());
  EXPECT_EQ(ui::Accelerator(ui::VKEY_F3, ui::EF_COMMAND_DOWN),
            accelerator_aliases[0]);
  EXPECT_EQ(refresh_accelerator, accelerator_aliases[1]);

  settings.suppress_meta_fkey_rewrites = true;
  Shell::Get()->input_device_settings_controller()->SetKeyboardSettings(
      fake_keyboard.id, settings.Clone());

  accelerator_aliases =
      accelerator_alias_converter_.CreateAcceleratorAlias(refresh_accelerator);
  ASSERT_EQ(1u, accelerator_aliases.size());
  EXPECT_EQ(refresh_accelerator, accelerator_aliases[0]);

  ui::KeyboardDevice fake_internal_keyboard(
      /*id=*/2, /*type=*/ui::InputDeviceType::INPUT_DEVICE_INTERNAL,
      /*name=*/kKbdTopRowLayout2Tag, /*phys=*/"", /*sys_path=*/base::FilePath(),
      /*vendor=*/0x1111, /*product=*/0x1111, /*version=*/0x0);
  fake_internal_keyboard.sys_path = base::FilePath("path2");
  fake_keyboard_manager_->AddFakeKeyboard(fake_internal_keyboard,
                                          kKbdTopRowLayout2Tag);

  settings.top_row_are_fkeys = true;
  settings.suppress_meta_fkey_rewrites = false;
  Shell::Get()->input_device_settings_controller()->SetKeyboardSettings(
      fake_internal_keyboard.id, settings.Clone());

  accelerator_aliases =
      accelerator_alias_converter_.CreateAcceleratorAlias(refresh_accelerator);
  ASSERT_EQ(2u, accelerator_aliases.size());
  EXPECT_EQ(refresh_accelerator, accelerator_aliases[0]);
  EXPECT_EQ(ui::Accelerator(ui::VKEY_BROWSER_REFRESH, ui::EF_COMMAND_DOWN),
            accelerator_aliases[1]);
}

class TopRowAliasTest : public AcceleratorAliasConverterTest,
                        public testing::WithParamInterface<
                            TopRowAcceleratorAliasConverterTestData> {
 public:
  void SetUp() override {
    AcceleratorAliasConverterTest::SetUp();
    TopRowAcceleratorAliasConverterTestData test_data = GetParam();
    keyboard_connection_type_ = test_data.keyboard_connection_type_;
    keyboard_layout_types_ = test_data.keyboard_layout_types_;
    accelerator_ = test_data.accelerator_;
    expected_accelerators_ = test_data.expected_accelerators_;
    fake_keyboard_manager_ = std::make_unique<FakeDeviceManager>();
  }

 protected:
  std::vector<ui::InputDeviceType> keyboard_connection_type_;
  std::vector<std::string> keyboard_layout_types_;
  ui::Accelerator accelerator_;
  std::vector<ui::Accelerator> expected_accelerators_;
  std::unique_ptr<FakeDeviceManager> fake_keyboard_manager_;
};

INSTANTIATE_TEST_SUITE_P(
    // Empty to simplify gtest output
    ,
    TopRowAliasTest,
    testing::ValuesIn(std::vector<TopRowAcceleratorAliasConverterTestData>{
        // [Search] as original modifier prevents remapping, regardless of
        // keyboard connection type.
        {{ui::InputDeviceType::INPUT_DEVICE_INTERNAL},
         {kKbdTopRowLayout1Tag},
         ui::Accelerator{ui::VKEY_ZOOM, ui::EF_COMMAND_DOWN},
         {ui::Accelerator{ui::VKEY_ZOOM, ui::EF_COMMAND_DOWN}}},

        // key_code not as a top row key prevents remapping, regardless of
        // keyboard connection type.
        {{ui::InputDeviceType::INPUT_DEVICE_INTERNAL,
          ui::InputDeviceType::INPUT_DEVICE_USB},
         {kKbdTopRowLayout1Tag, kKbdTopRowLayout2Tag},
         ui::Accelerator{ui::VKEY_TAB, ui::EF_ALT_DOWN},
         {ui::Accelerator{ui::VKEY_TAB, ui::EF_ALT_DOWN}}},

        // Below are testing each layout type.

        // For TopRowLayout1: [Alt] + [Back] -> [Alt] + [Search] + [F1].
        // TopRowKeysAreFKeys() remains true. This statement applies to all
        // tests in TopRowAliasTest class.
        {{ui::InputDeviceType::INPUT_DEVICE_USB},
         {kKbdTopRowLayoutUnspecified},
         ui::Accelerator{ui::VKEY_BROWSER_BACK, ui::EF_ALT_DOWN},
         {ui::Accelerator{ui::VKEY_F1, ui::EF_COMMAND_DOWN | ui::EF_ALT_DOWN},
          ui::Accelerator{ui::VKEY_BROWSER_BACK, ui::EF_ALT_DOWN}}},

        // For internal keyboard only, we shows icon + meta.
        {{ui::InputDeviceType::INPUT_DEVICE_INTERNAL},
         {kKbdTopRowLayout1Tag},
         ui::Accelerator{ui::VKEY_BROWSER_BACK, ui::EF_ALT_DOWN},
         {ui::Accelerator{ui::VKEY_BROWSER_BACK,
                          ui::EF_COMMAND_DOWN | ui::EF_ALT_DOWN}}},

        // For layout 1, remap F1 to back key.
        {{ui::InputDeviceType::INPUT_DEVICE_INTERNAL},
         {kKbdTopRowLayout1Tag},
         ui::Accelerator{ui::VKEY_F1, ui::EF_ALT_DOWN},
         {ui::Accelerator{ui::VKEY_BROWSER_BACK, ui::EF_ALT_DOWN}}},

        // For internal keyboard only, layout1 doesn't have
        // VKEY_MEDIA_PLAY_PAUSE key.
        {{ui::InputDeviceType::INPUT_DEVICE_INTERNAL},
         {kKbdTopRowLayout1Tag},
         ui::Accelerator{ui::VKEY_MEDIA_PLAY_PAUSE, ui::EF_ALT_DOWN},
         {}},

        // For internal keyboard only, layout2 doesn't have
        // VKEY_BROWSER_FORWARD key.
        {{ui::InputDeviceType::INPUT_DEVICE_INTERNAL},
         {kKbdTopRowLayout2Tag},
         ui::Accelerator{ui::VKEY_BROWSER_FORWARD, ui::EF_ALT_DOWN},
         {}},

        // For layout2, remap F2 to refresh key.
        {{ui::InputDeviceType::INPUT_DEVICE_INTERNAL},
         {kKbdTopRowLayout2Tag},
         ui::Accelerator{ui::VKEY_F2, ui::EF_ALT_DOWN},
         {ui::Accelerator{ui::VKEY_BROWSER_REFRESH, ui::EF_ALT_DOWN}}},

        // Layout2 doesn't have VKEY_ALL_APPLICATIONS key.
        {{ui::InputDeviceType::INPUT_DEVICE_INTERNAL},
         {kKbdTopRowLayout2Tag},
         ui::Accelerator{ui::VKEY_ALL_APPLICATIONS, ui::EF_ALT_DOWN},
         {}},

        // Layout1 doesn't have VKEY_SNAPSHOT key.
        {{ui::InputDeviceType::INPUT_DEVICE_INTERNAL},
         {kKbdTopRowLayout1Tag},
         ui::Accelerator{ui::VKEY_SNAPSHOT, ui::EF_ALT_DOWN},
         {}},

        // Layout1 doesn't have VKEY_SNAPSHOT key, but since its external, it
        // should always be shown.
        {{ui::InputDeviceType::INPUT_DEVICE_BLUETOOTH},
         {kKbdTopRowLayout1Tag},
         ui::Accelerator{ui::VKEY_SNAPSHOT, ui::EF_ALT_DOWN},
         {ui::Accelerator{ui::VKEY_SNAPSHOT, ui::EF_ALT_DOWN}}},

        // LayoutWilco doesn't have VKEY_MICROPHONE_MUTE_TOGGLE key.
        {{ui::InputDeviceType::INPUT_DEVICE_INTERNAL},
         {kKbdTopRowLayoutWilcoTag},
         ui::Accelerator{ui::VKEY_MICROPHONE_MUTE_TOGGLE, ui::EF_ALT_DOWN},
         {}},

        // LayoutWilco doesn't have VKEY_MICROPHONE_MUTE_TOGGLE key, but since
        // it is external, it should always be shown.
        {{ui::InputDeviceType::INPUT_DEVICE_USB},
         {kKbdTopRowLayoutWilcoTag},
         ui::Accelerator{ui::VKEY_MICROPHONE_MUTE_TOGGLE, ui::EF_ALT_DOWN},
         {ui::Accelerator{ui::VKEY_MICROPHONE_MUTE_TOGGLE, ui::EF_ALT_DOWN}}},

        // For TopRowLayout1: [Alt] + [Forward] -> [Alt] + [Search] + [F2].
        {{ui::InputDeviceType::INPUT_DEVICE_BLUETOOTH},
         {kKbdTopRowLayoutUnspecified},
         ui::Accelerator{ui::VKEY_BROWSER_FORWARD, ui::EF_ALT_DOWN},
         {ui::Accelerator{ui::VKEY_F2, ui::EF_COMMAND_DOWN | ui::EF_ALT_DOWN},
          ui::Accelerator{ui::VKEY_BROWSER_FORWARD, ui::EF_ALT_DOWN}}},

        // For TopRowLayout1: [Alt] + [Zoom] -> [Alt] + [Search] + [F4].
        {{ui::InputDeviceType::INPUT_DEVICE_USB},
         {kKbdTopRowLayoutUnspecified},
         ui::Accelerator{ui::VKEY_ZOOM, ui::EF_ALT_DOWN},
         {ui::Accelerator{ui::VKEY_F4, ui::EF_COMMAND_DOWN | ui::EF_ALT_DOWN},
          {ui::Accelerator{ui::VKEY_ZOOM, ui::EF_ALT_DOWN}}}},

        // For TopRowLayout2: [Alt] + [Shift] + [Back] -> [Alt] + [Shift] +
        // [Search] + [Back].
        {{ui::InputDeviceType::INPUT_DEVICE_INTERNAL},
         {kKbdTopRowLayout2Tag},
         ui::Accelerator{ui::VKEY_BROWSER_BACK,
                         ui::EF_ALT_DOWN | ui::EF_SHIFT_DOWN},
         {ui::Accelerator{ui::VKEY_BROWSER_BACK, ui::EF_COMMAND_DOWN |
                                                     ui::EF_ALT_DOWN |
                                                     ui::EF_SHIFT_DOWN}}},

        // For TopRowLayout2: [Alt] + [Zoom] -> [Alt] + [Search] + [F3].
        {{ui::InputDeviceType::INPUT_DEVICE_INTERNAL},
         {kKbdTopRowLayout2Tag},
         ui::Accelerator{ui::VKEY_ZOOM, ui::EF_ALT_DOWN},
         {ui::Accelerator{ui::VKEY_ZOOM,
                          ui::EF_COMMAND_DOWN | ui::EF_ALT_DOWN}}},

        // For TopRowLayout2: [Alt] + [Pause] -> [Alt] + [Search] + [F7].
        {{ui::InputDeviceType::INPUT_DEVICE_INTERNAL},
         {kKbdTopRowLayout2Tag},
         ui::Accelerator{ui::VKEY_MEDIA_PLAY_PAUSE, ui::EF_ALT_DOWN},
         {ui::Accelerator{ui::VKEY_MEDIA_PLAY_PAUSE,
                          ui::EF_COMMAND_DOWN | ui::EF_ALT_DOWN}}},

        // For TopRowLayoutWilco: [Alt] + [Zoom] -> [Alt] + [Search] + [F3].
        {{ui::InputDeviceType::INPUT_DEVICE_INTERNAL},
         {kKbdTopRowLayoutWilcoTag},
         ui::Accelerator{ui::VKEY_ZOOM, ui::EF_ALT_DOWN},
         {ui::Accelerator{ui::VKEY_ZOOM,
                          ui::EF_COMMAND_DOWN | ui::EF_ALT_DOWN}}},

        // For TopRowLayoutWilco: [Alt] + [VolumeUp] -> [Alt] + [Search] + [F9].
        {{ui::InputDeviceType::INPUT_DEVICE_INTERNAL},
         {kKbdTopRowLayoutWilcoTag},
         ui::Accelerator{ui::VKEY_VOLUME_UP, ui::EF_ALT_DOWN},
         {ui::Accelerator{ui::VKEY_VOLUME_UP,
                          ui::EF_COMMAND_DOWN | ui::EF_ALT_DOWN}}},

        // For kKbdTopRowLayoutDrallionTag: [Alt] + [Mute] -> [Alt] + [Search] +
        // [F7].
        {{ui::InputDeviceType::INPUT_DEVICE_INTERNAL},
         {kKbdTopRowLayoutDrallionTag},
         ui::Accelerator{ui::VKEY_VOLUME_MUTE, ui::EF_ALT_DOWN},
         {ui::Accelerator{ui::VKEY_VOLUME_MUTE,
                          ui::EF_COMMAND_DOWN | ui::EF_ALT_DOWN}}},

        // Aliasing should be for the most recently connected external keyboard
        // (last item in the list).
        // In this case, the most recently connected external keyboard does not
        // have a browser forward key.
        // As the most recently connected keyboard and the internal keyboards
        // are both ChromeOS keyboards, no alias is generated.
        {{ui::InputDeviceType::INPUT_DEVICE_INTERNAL,
          ui::InputDeviceType::INPUT_DEVICE_BLUETOOTH,
          ui::InputDeviceType::INPUT_DEVICE_USB},
         {kKbdTopRowLayout1Tag, kKbdTopRowLayoutUnspecified,
          kKbdTopRowLayout2Tag},
         ui::Accelerator{ui::VKEY_BROWSER_FORWARD, ui::EF_NONE},
         {}},

        // Since the external keyboard uses Layout1 by default, it should map to
        // F2.
        {{ui::InputDeviceType::INPUT_DEVICE_INTERNAL,
          ui::InputDeviceType::INPUT_DEVICE_USB},
         {kKbdTopRowLayout1Tag, kKbdTopRowLayoutUnspecified},
         ui::Accelerator{ui::VKEY_BROWSER_FORWARD, ui::EF_NONE},
         {ui::Accelerator{ui::VKEY_F2, ui::EF_COMMAND_DOWN},
          ui::Accelerator{ui::VKEY_BROWSER_FORWARD, ui::EF_COMMAND_DOWN},
          ui::Accelerator{ui::VKEY_BROWSER_FORWARD, ui::EF_NONE}}},

        // Since the external keyboard uses Layout1 by default, it should map to
        // F2, even if the most recently connected keyboard (which is internal)
        // does not have the key.
        {{ui::InputDeviceType::INPUT_DEVICE_USB,
          ui::InputDeviceType::INPUT_DEVICE_INTERNAL},
         {kKbdTopRowLayoutUnspecified, kKbdTopRowLayout2Tag},
         ui::Accelerator{ui::VKEY_BROWSER_FORWARD, ui::EF_NONE},
         {ui::Accelerator{ui::VKEY_F2, ui::EF_COMMAND_DOWN},
          ui::Accelerator{ui::VKEY_BROWSER_FORWARD, ui::EF_NONE}}},
    }));

TEST_P(TopRowAliasTest, CheckTopRowAlias) {
  // Add fake keyboards based on layout type.
  fake_keyboard_manager_->RemoveAllDevices();
  for (int i = 0; const std::string& layout : keyboard_layout_types_) {
    ui::KeyboardDevice fake_keyboard(
        /*id=*/i, /*type=*/keyboard_connection_type_[i],
        /*name=*/layout);
    fake_keyboard.sys_path = base::FilePath("path" + layout);
    fake_keyboard_manager_->AddFakeKeyboard(fake_keyboard, layout);
    SetTopRowAsFKeysForKeyboard(fake_keyboard, /*enabled=*/true);
    i++;
  }

  AcceleratorAliasConverter accelerator_alias_converter_;

  std::vector<ui::Accelerator> accelerator_alias =
      accelerator_alias_converter_.CreateAcceleratorAlias(accelerator_);
  base::ranges::sort(accelerator_alias);
  base::ranges::sort(expected_accelerators_);

  ASSERT_EQ(expected_accelerators_.size(), accelerator_alias.size());
  for (size_t i = 0; i < expected_accelerators_.size(); i++) {
    EXPECT_EQ(expected_accelerators_[i], accelerator_alias[i]);
  }
}

class SixPackAliasTestWithExternalKeyboard
    : public AcceleratorAliasConverterTest,
      public testing::WithParamInterface<AcceleratorAliasConverterTestData> {
  void SetUp() override {
    AcceleratorAliasConverterTest::SetUp();
    AcceleratorAliasConverterTestData test_data = GetParam();
    accelerator_ = test_data.accelerator_;
    expected_accelerators_ = test_data.expected_accelerators_;
    fake_keyboard_manager_ = std::make_unique<FakeDeviceManager>();
  }

 protected:
  ui::Accelerator accelerator_;
  std::optional<ui::Accelerator> expected_accelerators_;
  std::unique_ptr<FakeDeviceManager> fake_keyboard_manager_;
};

INSTANTIATE_TEST_SUITE_P(
    // Empty to simplify gtest output
    ,
    SixPackAliasTestWithExternalKeyboard,
    testing::ValuesIn(std::vector<AcceleratorAliasConverterTestData>{
        // [Search] as original modifier prevents remapping.
        {ui::Accelerator{ui::VKEY_ZOOM, ui::EF_COMMAND_DOWN}, std::nullopt},
        // key_code not as six pack key prevents remapping.
        {ui::Accelerator{ui::VKEY_TAB, ui::EF_ALT_DOWN}, std::nullopt},
        // [Shift] + [Delete] should not be remapped.
        {ui::Accelerator{ui::VKEY_DELETE, ui::EF_SHIFT_DOWN}, std::nullopt},
        // [Shift] + [Insert] should not be remapped.
        {ui::Accelerator{ui::VKEY_INSERT, ui::EF_SHIFT_DOWN}, std::nullopt},
        // For Insert: [modifiers] -> [Search] + [Shift] + [original_modifiers].
        {ui::Accelerator{ui::VKEY_INSERT, ui::EF_ALT_DOWN},
         ui::Accelerator{ui::VKEY_BACK, ui::EF_COMMAND_DOWN |
                                            ui::EF_SHIFT_DOWN |
                                            ui::EF_ALT_DOWN}},
        // For other six-pack-keys: [modifiers] -> [Search] +
        // [original_modifiers].
        {ui::Accelerator{ui::VKEY_DELETE, ui::EF_ALT_DOWN},
         ui::Accelerator{ui::VKEY_BACK, ui::EF_COMMAND_DOWN | ui::EF_ALT_DOWN}},
    }));

TEST_P(SixPackAliasTestWithExternalKeyboard, CheckSixPackAlias) {
  fake_keyboard_manager_->RemoveAllDevices();
  ui::KeyboardDevice fake_keyboard(
      /*id=*/1, /*type=*/ui::InputDeviceType::INPUT_DEVICE_BLUETOOTH,
      /*name=*/kKbdTopRowLayout1Tag);
  fake_keyboard.sys_path = base::FilePath("path");
  fake_keyboard_manager_->AddFakeKeyboard(fake_keyboard, kKbdTopRowLayout1Tag);

  AcceleratorAliasConverter accelerator_alias_converter_;

  std::vector<ui::Accelerator> accelerator_alias =
      accelerator_alias_converter_.CreateAcceleratorAlias(accelerator_);

  if (expected_accelerators_.has_value()) {
    // Accelerator has valid a remapping.
    EXPECT_EQ(2u, accelerator_alias.size());
    EXPECT_EQ(expected_accelerators_, accelerator_alias[0]);
    EXPECT_EQ(accelerator_, accelerator_alias[1]);
  } else {
    // Accelerator doesn't have a valid remapping.
    EXPECT_EQ(1u, accelerator_alias.size());
    ASSERT_EQ(accelerator_, accelerator_alias[0]);
  }
}

class SixPackAliasTestWithInternalKeyboard
    : public AcceleratorAliasConverterTest,
      public testing::WithParamInterface<AcceleratorAliasConverterTestData> {
  void SetUp() override {
    AcceleratorAliasConverterTest::SetUp();
    AcceleratorAliasConverterTestData test_data = GetParam();
    accelerator_ = test_data.accelerator_;
    expected_accelerators_ = test_data.expected_accelerators_;
    fake_keyboard_manager_ = std::make_unique<FakeDeviceManager>();
  }

 protected:
  ui::Accelerator accelerator_;
  std::optional<ui::Accelerator> expected_accelerators_;
  std::unique_ptr<FakeDeviceManager> fake_keyboard_manager_;
};

INSTANTIATE_TEST_SUITE_P(
    // Empty to simplify gtest output
    ,
    SixPackAliasTestWithInternalKeyboard,
    testing::ValuesIn(std::vector<AcceleratorAliasConverterTestData>{
        // A keyboard without six pack keys should not affect the aliasing of
        // six pack key.

        // [Search] as original modifier prevents remapping.
        {ui::Accelerator{ui::VKEY_ZOOM, ui::EF_COMMAND_DOWN}, std::nullopt},
        // key_code not as six pack key prevents remapping.
        {ui::Accelerator{ui::VKEY_TAB, ui::EF_ALT_DOWN}, std::nullopt},
        // [Shift] + [Delete] should not be remapped.
        {ui::Accelerator{ui::VKEY_DELETE, ui::EF_SHIFT_DOWN}, std::nullopt},
        // [Shift] + [Insert] should not be remapped.
        {ui::Accelerator{ui::VKEY_INSERT, ui::EF_SHIFT_DOWN}, std::nullopt},
        // For Insert: [modifiers] -> [Search] + [Shift] + [original_modifiers].
        {ui::Accelerator{ui::VKEY_INSERT, ui::EF_ALT_DOWN},
         ui::Accelerator{ui::VKEY_BACK, ui::EF_COMMAND_DOWN |
                                            ui::EF_SHIFT_DOWN |
                                            ui::EF_ALT_DOWN}},
        // For other six-pack-keys: [modifiers] -> [Search] +
        // [original_modifiers].
        {ui::Accelerator{ui::VKEY_DELETE, ui::EF_ALT_DOWN},
         ui::Accelerator{ui::VKEY_BACK, ui::EF_COMMAND_DOWN | ui::EF_ALT_DOWN}},
    }));

TEST_P(SixPackAliasTestWithInternalKeyboard, CheckSixPackAlias) {
  fake_keyboard_manager_->RemoveAllDevices();
  ui::KeyboardDevice fake_keyboard(
      /*id=*/1, /*type=*/ui::InputDeviceType::INPUT_DEVICE_INTERNAL,
      /*name=*/kKbdTopRowLayout1Tag);
  fake_keyboard.sys_path = base::FilePath("path");
  fake_keyboard_manager_->AddFakeKeyboard(fake_keyboard, kKbdTopRowLayout2Tag);

  AcceleratorAliasConverter accelerator_alias_converter_;

  std::vector<ui::Accelerator> accelerator_alias =
      accelerator_alias_converter_.CreateAcceleratorAlias(accelerator_);

  if (expected_accelerators_.has_value()) {
    // Accelerator has valid a remapping.
    EXPECT_EQ(1u, accelerator_alias.size());
    EXPECT_EQ(expected_accelerators_, accelerator_alias[0]);
  } else if (ui::KeyboardCapability::IsSixPackKey(accelerator_.key_code())) {
    // Original accelerator has six pack key, which is not supported by internal
    // keyboard.
    EXPECT_EQ(0u, accelerator_alias.size());
  } else {
    EXPECT_EQ(1u, accelerator_alias.size());
    EXPECT_EQ(accelerator_, accelerator_alias[0]);
  }
}

class SixPackAliasAltTest
    : public AcceleratorAliasConverterTest,
      public testing::WithParamInterface<AcceleratorAliasConverterTestData> {
  void SetUp() override {
    scoped_feature_list_.InitWithFeatures(
        {ash::features::kInputDeviceSettingsSplit,
         ash::features::kAltClickAndSixPackCustomization},
        /*disabled_features=*/{});
    AcceleratorAliasConverterTest::SetUp();
    AcceleratorAliasConverterTestData test_data = GetParam();
    accelerator_ = test_data.accelerator_;
    expected_accelerators_ = test_data.expected_accelerators_;
    fake_keyboard_manager_ = std::make_unique<FakeDeviceManager>();
  }

 protected:
  base::test::ScopedFeatureList scoped_feature_list_;
  ui::Accelerator accelerator_;
  std::optional<ui::Accelerator> expected_accelerators_;
  std::unique_ptr<FakeDeviceManager> fake_keyboard_manager_;
};

INSTANTIATE_TEST_SUITE_P(
    // Empty to simplify gtest output
    ,
    SixPackAliasAltTest,
    testing::ValuesIn(std::vector<AcceleratorAliasConverterTestData>{
        {ui::Accelerator{ui::VKEY_DELETE, ui::EF_NONE},
         ui::Accelerator{ui::VKEY_BACK, ui::EF_ALT_DOWN}},

        {ui::Accelerator{ui::VKEY_HOME, ui::EF_NONE},
         ui::Accelerator{ui::VKEY_UP, ui::EF_ALT_DOWN | ui::EF_CONTROL_DOWN}},

        {ui::Accelerator{ui::VKEY_PRIOR, ui::EF_NONE},
         ui::Accelerator{ui::VKEY_UP, ui::EF_ALT_DOWN}},

        {ui::Accelerator{ui::VKEY_END, ui::EF_NONE},
         ui::Accelerator{ui::VKEY_DOWN, ui::EF_ALT_DOWN | ui::EF_CONTROL_DOWN}},

        {ui::Accelerator{ui::VKEY_NEXT, ui::EF_NONE},
         ui::Accelerator{ui::VKEY_DOWN, ui::EF_ALT_DOWN}},

        // The following should not perform an alias since Alt is part of the
        // original accelerator.
        {ui::Accelerator{ui::VKEY_DELETE, ui::EF_ALT_DOWN}, std::nullopt},

        {ui::Accelerator{ui::VKEY_HOME, ui::EF_ALT_DOWN}, std::nullopt},

        {ui::Accelerator{ui::VKEY_PRIOR, ui::EF_ALT_DOWN}, std::nullopt},

        {ui::Accelerator{ui::VKEY_END, ui::EF_ALT_DOWN}, std::nullopt},

        {ui::Accelerator{ui::VKEY_NEXT, ui::EF_ALT_DOWN}, std::nullopt},

        {ui::Accelerator{ui::VKEY_HOME, ui::EF_CONTROL_DOWN}, std::nullopt},

        {ui::Accelerator{ui::VKEY_END, ui::EF_CONTROL_DOWN}, std::nullopt},

        {ui::Accelerator{ui::VKEY_HOME, ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN},
         std::nullopt},

        {ui::Accelerator{ui::VKEY_END, ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN},
         std::nullopt},
    }));

TEST_P(SixPackAliasAltTest, CheckSixPackAliasAlt) {
  fake_keyboard_manager_->RemoveAllDevices();
  ui::KeyboardDevice fake_keyboard(
      /*id=*/1, /*type=*/ui::InputDeviceType::INPUT_DEVICE_INTERNAL,
      /*name=*/kKbdTopRowLayout1Tag);
  fake_keyboard.sys_path = base::FilePath("path");
  fake_keyboard_manager_->AddFakeKeyboard(fake_keyboard, kKbdTopRowLayout2Tag);
  auto settings = Shell::Get()
                      ->input_device_settings_controller()
                      ->GetKeyboardSettings(fake_keyboard.id)
                      ->Clone();

  mojom::SixPackKeyInfoPtr six_pack_key_info = mojom::SixPackKeyInfo::New();
  six_pack_key_info->del = ui::mojom::SixPackShortcutModifier::kAlt;
  six_pack_key_info->home = ui::mojom::SixPackShortcutModifier::kAlt;
  six_pack_key_info->end = ui::mojom::SixPackShortcutModifier::kAlt;
  six_pack_key_info->page_down = ui::mojom::SixPackShortcutModifier::kAlt;
  six_pack_key_info->page_up = ui::mojom::SixPackShortcutModifier::kAlt;

  settings->six_pack_key_remappings = six_pack_key_info.Clone();
  Shell::Get()->input_device_settings_controller()->SetKeyboardSettings(
      fake_keyboard.id, std::move(settings));
  AcceleratorAliasConverter accelerator_alias_converter_;

  std::vector<ui::Accelerator> accelerator_alias =
      accelerator_alias_converter_.CreateAcceleratorAlias(accelerator_);

  if (expected_accelerators_.has_value()) {
    // Accelerator has valid a remapping.
    EXPECT_EQ(1u, accelerator_alias.size());
    EXPECT_EQ(expected_accelerators_, accelerator_alias[0]);
  } else {
    EXPECT_EQ(0u, accelerator_alias.size());
  }
}

class SixPackAliasSearchTest
    : public AcceleratorAliasConverterTest,
      public testing::WithParamInterface<AcceleratorAliasConverterTestData> {
  void SetUp() override {
    scoped_feature_list_.InitWithFeatures(
        {ash::features::kInputDeviceSettingsSplit,
         ash::features::kAltClickAndSixPackCustomization},
        /*disabled_features=*/{});
    AcceleratorAliasConverterTest::SetUp();
    AcceleratorAliasConverterTestData test_data = GetParam();
    accelerator_ = test_data.accelerator_;
    expected_accelerators_ = test_data.expected_accelerators_;
    fake_keyboard_manager_ = std::make_unique<FakeDeviceManager>();
  }

 protected:
  base::test::ScopedFeatureList scoped_feature_list_;
  ui::Accelerator accelerator_;
  std::optional<ui::Accelerator> expected_accelerators_;
  std::unique_ptr<FakeDeviceManager> fake_keyboard_manager_;
};

INSTANTIATE_TEST_SUITE_P(
    // Empty to simplify gtest output
    ,
    SixPackAliasSearchTest,
    testing::ValuesIn(std::vector<AcceleratorAliasConverterTestData>{

        {ui::Accelerator{ui::VKEY_INSERT, ui::EF_NONE},
         ui::Accelerator{ui::VKEY_BACK,
                         ui::EF_COMMAND_DOWN | ui::EF_SHIFT_DOWN}},

        {ui::Accelerator{ui::VKEY_DELETE, ui::EF_NONE},
         ui::Accelerator{ui::VKEY_BACK, ui::EF_COMMAND_DOWN}},

        {ui::Accelerator{ui::VKEY_HOME, ui::EF_NONE},
         ui::Accelerator{ui::VKEY_LEFT, ui::EF_COMMAND_DOWN}},

        {ui::Accelerator{ui::VKEY_PRIOR, ui::EF_NONE},
         ui::Accelerator{ui::VKEY_UP, ui::EF_COMMAND_DOWN}},

        {ui::Accelerator{ui::VKEY_END, ui::EF_NONE},
         ui::Accelerator{ui::VKEY_RIGHT, ui::EF_COMMAND_DOWN}},

        {ui::Accelerator{ui::VKEY_NEXT, ui::EF_NONE},
         ui::Accelerator{ui::VKEY_DOWN, ui::EF_COMMAND_DOWN}},
    }));

TEST_P(SixPackAliasSearchTest, CheckSixPackAliasSearch) {
  fake_keyboard_manager_->RemoveAllDevices();
  ui::KeyboardDevice fake_keyboard(
      /*id=*/1, /*type=*/ui::InputDeviceType::INPUT_DEVICE_INTERNAL,
      /*name=*/kKbdTopRowLayout1Tag);
  fake_keyboard.sys_path = base::FilePath("path");
  fake_keyboard_manager_->AddFakeKeyboard(fake_keyboard, kKbdTopRowLayout2Tag);
  auto settings = Shell::Get()
                      ->input_device_settings_controller()
                      ->GetKeyboardSettings(fake_keyboard.id)
                      ->Clone();

  mojom::SixPackKeyInfoPtr six_pack_key_info = mojom::SixPackKeyInfo::New();
  settings->six_pack_key_remappings = six_pack_key_info.Clone();
  Shell::Get()->input_device_settings_controller()->SetKeyboardSettings(
      fake_keyboard.id, std::move(settings));
  AcceleratorAliasConverter accelerator_alias_converter_;

  std::vector<ui::Accelerator> accelerator_alias =
      accelerator_alias_converter_.CreateAcceleratorAlias(accelerator_);

  EXPECT_EQ(1u, accelerator_alias.size());
  EXPECT_EQ(expected_accelerators_, accelerator_alias[0]);
}

TEST_P(SixPackAliasSearchTest, CheckSixPackAliasNone) {
  fake_keyboard_manager_->RemoveAllDevices();
  ui::KeyboardDevice fake_keyboard(
      /*id=*/1, /*type=*/ui::InputDeviceType::INPUT_DEVICE_INTERNAL,
      /*name=*/kKbdTopRowLayout1Tag);
  fake_keyboard.sys_path = base::FilePath("path");
  fake_keyboard_manager_->AddFakeKeyboard(fake_keyboard, kKbdTopRowLayout2Tag);
  auto settings = Shell::Get()
                      ->input_device_settings_controller()
                      ->GetKeyboardSettings(fake_keyboard.id)
                      ->Clone();

  mojom::SixPackKeyInfoPtr six_pack_key_info = mojom::SixPackKeyInfo::New();
  six_pack_key_info->del = ui::mojom::SixPackShortcutModifier::kNone;
  six_pack_key_info->home = ui::mojom::SixPackShortcutModifier::kNone;
  six_pack_key_info->insert = ui::mojom::SixPackShortcutModifier::kNone;
  six_pack_key_info->end = ui::mojom::SixPackShortcutModifier::kNone;
  six_pack_key_info->page_down = ui::mojom::SixPackShortcutModifier::kNone;
  six_pack_key_info->page_up = ui::mojom::SixPackShortcutModifier::kNone;
  settings->six_pack_key_remappings = six_pack_key_info.Clone();
  Shell::Get()->input_device_settings_controller()->SetKeyboardSettings(
      fake_keyboard.id, std::move(settings));
  AcceleratorAliasConverter accelerator_alias_converter_;

  std::vector<ui::Accelerator> accelerator_alias =
      accelerator_alias_converter_.CreateAcceleratorAlias(accelerator_);

  EXPECT_EQ(0u, accelerator_alias.size());
}

class MediaKeyAliasTest : public AcceleratorAliasConverterTest,
                          public testing::WithParamInterface<ui::KeyboardCode> {
};

INSTANTIATE_TEST_SUITE_P(
    All,
    MediaKeyAliasTest,
    testing::Values(ui::VKEY_OEM_103,  // Media Rewind
                    ui::VKEY_OEM_104,  // Media Fast Forward
                    ui::VKEY_MEDIA_STOP));

TEST_P(MediaKeyAliasTest, CheckMediaKeyAlias) {
  std::unique_ptr<FakeDeviceManager> fake_keyboard_manager_ =
      std::make_unique<FakeDeviceManager>();
  ui::KeyboardDevice fake_keyboard(
      /*id=*/1, /*type=*/ui::InputDeviceType::INPUT_DEVICE_INTERNAL,
      /*name=*/kKbdTopRowLayout1Tag);
  fake_keyboard.sys_path = base::FilePath("path");
  fake_keyboard_manager_->AddFakeKeyboard(fake_keyboard, kKbdTopRowLayout1Tag);

  AcceleratorAliasConverter accelerator_alias_converter_;

  const ui::Accelerator accelerator{GetParam(), ui::EF_NONE};
  std::vector<ui::Accelerator> accelerator_aliases =
      accelerator_alias_converter_.CreateAcceleratorAlias(accelerator);
  EXPECT_EQ(0u, accelerator_aliases.size());

  ui::KeyboardDevice wilco_keyboard(
      /*id=*/2, /*type=*/ui::InputDeviceType::INPUT_DEVICE_BLUETOOTH,
      /*name=*/kKbdTopRowLayoutWilcoTag);
  wilco_keyboard.sys_path = base::FilePath("path2");
  fake_keyboard_manager_->AddFakeKeyboard(wilco_keyboard,
                                          kKbdTopRowLayoutWilcoTag);
  accelerator_aliases =
      accelerator_alias_converter_.CreateAcceleratorAlias(accelerator);
  EXPECT_EQ(1u, accelerator_aliases.size());
  EXPECT_EQ(accelerator, accelerator_aliases[0]);
}

class ExtendedFKeysAliasAltTest
    : public AcceleratorAliasConverterTest,
      public testing::WithParamInterface<AcceleratorAliasConverterTestData> {
 public:
  void SetUp() override {
    scoped_feature_list_.InitWithFeatures(
        {ash::features::kInputDeviceSettingsSplit,
         ash::features::kAltClickAndSixPackCustomization,
         ::features::kSupportF11AndF12KeyShortcuts},
        /*disabled_features=*/{});
    AcceleratorAliasConverterTest::SetUp();
    AcceleratorAliasConverterTestData test_data = GetParam();
    accelerator_ = test_data.accelerator_;
    expected_accelerators_ = test_data.expected_accelerators_;
  }

 protected:
  base::test::ScopedFeatureList scoped_feature_list_;
  ui::Accelerator accelerator_;
  std::optional<ui::Accelerator> expected_accelerators_;
  std::unique_ptr<FakeDeviceManager> fake_keyboard_manager_;
};

INSTANTIATE_TEST_SUITE_P(
    // Empty to simplify gtest output
    ,
    ExtendedFKeysAliasAltTest,
    testing::ValuesIn(std::vector<AcceleratorAliasConverterTestData>{
        // The following test cases all have `top_row_are_fkeys` enabled
        // and use an internal ChromeOS keyboard. The F11/F12 accelerators
        // will be aliased due to ChromeOS keyboards having fewer than 12 keys
        // in the top row. The `top_row_are_fkeys` setting determines whether
        // or not `ui::EF_COMMAND_DOWN` should be present in the aliased
        // accelerator.
        {ui::Accelerator{ui::VKEY_F11, ui::EF_CONTROL_DOWN},
         ui::Accelerator{ui::VKEY_BROWSER_BACK,
                         ui::EF_ALT_DOWN | ui::EF_CONTROL_DOWN}},

        {ui::Accelerator{ui::VKEY_F12, ui::EF_CONTROL_DOWN},
         ui::Accelerator{ui::VKEY_BROWSER_FORWARD,
                         ui::EF_ALT_DOWN | ui::EF_CONTROL_DOWN}},

        {ui::Accelerator{ui::VKEY_F11, ui::EF_NONE},
         ui::Accelerator{ui::VKEY_BROWSER_BACK, ui::EF_ALT_DOWN}},

        {ui::Accelerator{ui::VKEY_F12, ui::EF_NONE},
         ui::Accelerator{ui::VKEY_BROWSER_FORWARD, ui::EF_ALT_DOWN}},

        // The following should not perform an alias since Alt is part of the
        // original accelerator.
        {ui::Accelerator{ui::VKEY_F11, ui::EF_ALT_DOWN}, std::nullopt},
    }));

TEST_P(ExtendedFKeysAliasAltTest, CheckExtendedFKeysAliasAlt) {
  std::unique_ptr<FakeDeviceManager> fake_keyboard_manager_ =
      std::make_unique<FakeDeviceManager>();
  ui::KeyboardDevice fake_keyboard(
      /*id=*/1, /*type=*/ui::InputDeviceType::INPUT_DEVICE_INTERNAL,
      /*name=*/kKbdTopRowLayout1Tag);
  fake_keyboard.sys_path = base::FilePath("path");
  SetKeyboardInfo(
      fake_keyboard,
      ui::KeyboardCapability::DeviceType::kDeviceInternalKeyboard,
      ui::KeyboardCapability::KeyboardTopRowLayout::kKbdTopRowLayout1);
  fake_keyboard_manager_->AddFakeKeyboard(fake_keyboard, kKbdTopRowLayout1Tag);
  auto settings = Shell::Get()
                      ->input_device_settings_controller()
                      ->GetKeyboardSettings(fake_keyboard.id)
                      ->Clone();

  settings->f11 = ui::mojom::ExtendedFkeysModifier::kAlt;
  settings->f12 = ui::mojom::ExtendedFkeysModifier::kAlt;
  Shell::Get()->input_device_settings_controller()->SetKeyboardSettings(
      fake_keyboard.id, mojo::Clone(settings));
  AcceleratorAliasConverter accelerator_alias_converter_;
  SetTopRowAsFKeysForKeyboard(fake_keyboard, /*enabled=*/true);
  std::vector<ui::Accelerator> accelerator_alias =
      accelerator_alias_converter_.CreateAcceleratorAlias(accelerator_);
  if (expected_accelerators_.has_value()) {
    // Accelerator has valid a remapping.
    EXPECT_EQ(1u, accelerator_alias.size());
    EXPECT_EQ(expected_accelerators_, accelerator_alias[0]);
  } else {
    // Expect base accelerator.
    EXPECT_EQ(accelerator_, accelerator_alias[0]);
  }
}

class ExtendedFKeysAliasShiftTest
    : public AcceleratorAliasConverterTest,
      public testing::WithParamInterface<AcceleratorAliasConverterTestData> {
 public:
  void SetUp() override {
    scoped_feature_list_.InitWithFeatures(
        {ash::features::kInputDeviceSettingsSplit,
         ash::features::kAltClickAndSixPackCustomization,
         ::features::kSupportF11AndF12KeyShortcuts},
        /*disabled_features=*/{});
    AcceleratorAliasConverterTest::SetUp();
    AcceleratorAliasConverterTestData test_data = GetParam();
    accelerator_ = test_data.accelerator_;
    expected_accelerators_ = test_data.expected_accelerators_;
  }

 protected:
  base::test::ScopedFeatureList scoped_feature_list_;
  ui::Accelerator accelerator_;
  std::optional<ui::Accelerator> expected_accelerators_;
  std::unique_ptr<FakeDeviceManager> fake_keyboard_manager_;
};

INSTANTIATE_TEST_SUITE_P(
    // Empty to simplify gtest output
    ,
    ExtendedFKeysAliasShiftTest,
    testing::ValuesIn(std::vector<AcceleratorAliasConverterTestData>{

        {ui::Accelerator{ui::VKEY_F11, ui::EF_CONTROL_DOWN},
         ui::Accelerator{ui::VKEY_BROWSER_BACK,
                         ui::EF_SHIFT_DOWN | ui::EF_CONTROL_DOWN}},

        {ui::Accelerator{ui::VKEY_F12, ui::EF_CONTROL_DOWN},
         ui::Accelerator{ui::VKEY_BROWSER_FORWARD,
                         ui::EF_SHIFT_DOWN | ui::EF_CONTROL_DOWN}},

        {ui::Accelerator{ui::VKEY_F11, ui::EF_NONE},
         ui::Accelerator{ui::VKEY_BROWSER_BACK, ui::EF_SHIFT_DOWN}},

        {ui::Accelerator{ui::VKEY_F12, ui::EF_NONE},
         ui::Accelerator{ui::VKEY_BROWSER_FORWARD, ui::EF_SHIFT_DOWN}},

        // The following should not perform an alias since Shift is part of
        // the original accelerator.
        {ui::Accelerator{ui::VKEY_F11, ui::EF_SHIFT_DOWN}, std::nullopt},
    }));

TEST_P(ExtendedFKeysAliasShiftTest, CheckExtendedFKeysAliasShift) {
  std::unique_ptr<FakeDeviceManager> fake_keyboard_manager_ =
      std::make_unique<FakeDeviceManager>();
  ui::KeyboardDevice fake_keyboard(
      /*id=*/1, /*type=*/ui::InputDeviceType::INPUT_DEVICE_INTERNAL,
      /*name=*/kKbdTopRowLayout1Tag);
  fake_keyboard.sys_path = base::FilePath("path");
  SetKeyboardInfo(
      fake_keyboard,
      ui::KeyboardCapability::DeviceType::kDeviceInternalKeyboard,
      ui::KeyboardCapability::KeyboardTopRowLayout::kKbdTopRowLayout1);
  fake_keyboard_manager_->AddFakeKeyboard(fake_keyboard, kKbdTopRowLayout1Tag);
  auto settings = Shell::Get()
                      ->input_device_settings_controller()
                      ->GetKeyboardSettings(fake_keyboard.id)
                      ->Clone();

  settings->f11 = ui::mojom::ExtendedFkeysModifier::kShift;
  settings->f12 = ui::mojom::ExtendedFkeysModifier::kShift;
  Shell::Get()->input_device_settings_controller()->SetKeyboardSettings(
      fake_keyboard.id, mojo::Clone(settings));
  AcceleratorAliasConverter accelerator_alias_converter_;
  SetTopRowAsFKeysForKeyboard(fake_keyboard, /*enabled=*/true);
  std::vector<ui::Accelerator> accelerator_alias =
      accelerator_alias_converter_.CreateAcceleratorAlias(accelerator_);
  if (expected_accelerators_.has_value()) {
    // Accelerator has valid a remapping.
    EXPECT_EQ(1u, accelerator_alias.size());
    EXPECT_EQ(expected_accelerators_, accelerator_alias[0]);
  } else {
    // Expect base accelerator.
    EXPECT_EQ(accelerator_, accelerator_alias[0]);
  }
}

class ExtendedFKeysAliasCtrlShiftTest
    : public AcceleratorAliasConverterTest,
      public testing::WithParamInterface<AcceleratorAliasConverterTestData> {
 public:
  void SetUp() override {
    scoped_feature_list_.InitWithFeatures(
        {ash::features::kInputDeviceSettingsSplit,
         ash::features::kAltClickAndSixPackCustomization,
         ::features::kSupportF11AndF12KeyShortcuts},
        /*disabled_features=*/{});
    AcceleratorAliasConverterTest::SetUp();
    AcceleratorAliasConverterTestData test_data = GetParam();
    accelerator_ = test_data.accelerator_;
    expected_accelerators_ = test_data.expected_accelerators_;
  }

 protected:
  base::test::ScopedFeatureList scoped_feature_list_;
  ui::Accelerator accelerator_;
  std::optional<ui::Accelerator> expected_accelerators_;
  std::unique_ptr<FakeDeviceManager> fake_keyboard_manager_;
};

INSTANTIATE_TEST_SUITE_P(
    // Empty to simplify gtest output
    ,
    ExtendedFKeysAliasCtrlShiftTest,
    testing::ValuesIn(std::vector<AcceleratorAliasConverterTestData>{

        {ui::Accelerator{ui::VKEY_F11, ui::EF_ALT_DOWN},
         ui::Accelerator{ui::VKEY_BROWSER_BACK, ui::EF_SHIFT_DOWN |
                                                    ui::EF_CONTROL_DOWN |
                                                    ui::EF_ALT_DOWN}},

        {ui::Accelerator{ui::VKEY_F12, ui::EF_ALT_DOWN},
         ui::Accelerator{ui::VKEY_BROWSER_FORWARD, ui::EF_SHIFT_DOWN |
                                                       ui::EF_CONTROL_DOWN |
                                                       ui::EF_ALT_DOWN}},

        {ui::Accelerator{ui::VKEY_F11, ui::EF_NONE},
         ui::Accelerator{ui::VKEY_BROWSER_BACK,
                         ui::EF_SHIFT_DOWN | ui::EF_CONTROL_DOWN}},

        {ui::Accelerator{ui::VKEY_F12, ui::EF_NONE},
         ui::Accelerator{ui::VKEY_BROWSER_FORWARD,
                         ui::EF_SHIFT_DOWN | ui::EF_CONTROL_DOWN}},

        // The following should not perform an alias since Ctrl and Shift
        // are part of the original accelerator.
        {ui::Accelerator{ui::VKEY_F11, ui::EF_SHIFT_DOWN | ui::EF_CONTROL_DOWN},
         std::nullopt},

        // The following should not perform an alias since Ctrl is part of the
        // original accelerator.
        {ui::Accelerator{ui::VKEY_F11, ui::EF_CONTROL_DOWN}, std::nullopt},

        // The following should not perform an alias since Shift is part of the
        // original accelerator.
        {ui::Accelerator{ui::VKEY_F11, ui::EF_SHIFT_DOWN}, std::nullopt},
    }));

TEST_P(ExtendedFKeysAliasCtrlShiftTest, CheckExtendedFKeysAliasCtrlShift) {
  std::unique_ptr<FakeDeviceManager> fake_keyboard_manager_ =
      std::make_unique<FakeDeviceManager>();
  ui::KeyboardDevice fake_keyboard(
      /*id=*/1, /*type=*/ui::InputDeviceType::INPUT_DEVICE_INTERNAL,
      /*name=*/kKbdTopRowLayout1Tag);
  fake_keyboard.sys_path = base::FilePath("path");
  SetKeyboardInfo(
      fake_keyboard,
      ui::KeyboardCapability::DeviceType::kDeviceInternalKeyboard,
      ui::KeyboardCapability::KeyboardTopRowLayout::kKbdTopRowLayout1);
  fake_keyboard_manager_->AddFakeKeyboard(fake_keyboard, kKbdTopRowLayout1Tag);
  auto settings = Shell::Get()
                      ->input_device_settings_controller()
                      ->GetKeyboardSettings(fake_keyboard.id)
                      ->Clone();

  settings->f11 = ui::mojom::ExtendedFkeysModifier::kCtrlShift;
  settings->f12 = ui::mojom::ExtendedFkeysModifier::kCtrlShift;
  Shell::Get()->input_device_settings_controller()->SetKeyboardSettings(
      fake_keyboard.id, mojo::Clone(settings));
  AcceleratorAliasConverter accelerator_alias_converter_;
  SetTopRowAsFKeysForKeyboard(fake_keyboard, /*enabled=*/true);
  std::vector<ui::Accelerator> accelerator_alias =
      accelerator_alias_converter_.CreateAcceleratorAlias(accelerator_);
  if (expected_accelerators_.has_value()) {
    // Accelerator has valid a remapping.
    EXPECT_EQ(1u, accelerator_alias.size());
    EXPECT_EQ(expected_accelerators_, accelerator_alias[0]);
  } else {
    // Expect base accelerator.
    EXPECT_EQ(accelerator_, accelerator_alias[0]);
  }
}

class ExtendedFKeysAliasTest : public AcceleratorAliasConverterTest {
 public:
  void SetUp() override {
    scoped_feature_list_.InitWithFeatures(
        {ash::features::kInputDeviceSettingsSplit,
         ash::features::kAltClickAndSixPackCustomization,
         ::features::kSupportF11AndF12KeyShortcuts},
        /*disabled_features=*/{});
    AcceleratorAliasConverterTest::SetUp();
  }

 protected:
  base::test::ScopedFeatureList scoped_feature_list_;
  std::unique_ptr<FakeDeviceManager> fake_keyboard_manager_;
};

TEST_F(ExtendedFKeysAliasTest, ExtendedFKeysAliasAltTopRowAreFKeys) {
  std::unique_ptr<FakeDeviceManager> fake_keyboard_manager_ =
      std::make_unique<FakeDeviceManager>();
  ui::KeyboardDevice fake_keyboard(
      /*id=*/1, /*type=*/ui::InputDeviceType::INPUT_DEVICE_INTERNAL,
      /*name=*/kKbdTopRowLayout1Tag);
  fake_keyboard.sys_path = base::FilePath("path");
  SetKeyboardInfo(
      fake_keyboard,
      ui::KeyboardCapability::DeviceType::kDeviceInternalKeyboard,
      ui::KeyboardCapability::KeyboardTopRowLayout::kKbdTopRowLayout1);
  fake_keyboard_manager_->AddFakeKeyboard(fake_keyboard, kKbdTopRowLayout1Tag);
  auto settings = Shell::Get()
                      ->input_device_settings_controller()
                      ->GetKeyboardSettings(fake_keyboard.id)
                      ->Clone();

  settings->f11 = ui::mojom::ExtendedFkeysModifier::kAlt;
  settings->f12 = ui::mojom::ExtendedFkeysModifier::kAlt;
  Shell::Get()->input_device_settings_controller()->SetKeyboardSettings(
      fake_keyboard.id, mojo::Clone(settings));
  AcceleratorAliasConverter accelerator_alias_converter_;
  SetTopRowAsFKeysForKeyboard(fake_keyboard, /*enabled=*/false);

  const ui::Accelerator accelerator{ui::VKEY_F11, ui::EF_CONTROL_DOWN};
  ui::Accelerator expected_accelerator{
      ui::VKEY_BROWSER_BACK,
      ui::EF_ALT_DOWN | ui::EF_CONTROL_DOWN | ui::EF_COMMAND_DOWN};
  std::vector<ui::Accelerator> accelerator_alias =
      accelerator_alias_converter_.CreateAcceleratorAlias(accelerator);
  EXPECT_EQ(1u, accelerator_alias.size());
  EXPECT_EQ(expected_accelerator, accelerator_alias[0]);

  SetTopRowAsFKeysForKeyboard(fake_keyboard, /*enabled=*/true);
  expected_accelerator = {ui::VKEY_BROWSER_BACK,
                          ui::EF_ALT_DOWN | ui::EF_CONTROL_DOWN};
  accelerator_alias =
      accelerator_alias_converter_.CreateAcceleratorAlias(accelerator);
  EXPECT_EQ(1u, accelerator_alias.size());
  EXPECT_EQ(expected_accelerator, accelerator_alias[0]);
}

TEST_F(ExtendedFKeysAliasTest, ExtendedFKeysAliasInternalAndExternalKb) {
  std::unique_ptr<FakeDeviceManager> fake_keyboard_manager_ =
      std::make_unique<FakeDeviceManager>();
  ui::KeyboardDevice fake_keyboard1(
      /*id=*/1, /*type=*/ui::InputDeviceType::INPUT_DEVICE_INTERNAL,
      /*name=*/kKbdTopRowLayout1Tag);
  fake_keyboard1.sys_path = base::FilePath("path");
  SetKeyboardInfo(
      fake_keyboard1,
      ui::KeyboardCapability::DeviceType::kDeviceInternalKeyboard,
      ui::KeyboardCapability::KeyboardTopRowLayout::kKbdTopRowLayout1);
  fake_keyboard_manager_->AddFakeKeyboard(fake_keyboard1, kKbdTopRowLayout1Tag);
  ui::KeyboardDevice fake_keyboard2(
      /*id=*/2, /*type=*/ui::InputDeviceType::INPUT_DEVICE_USB,
      /*name=*/kKbdTopRowLayoutUnspecified);
  fake_keyboard2.sys_path = base::FilePath("path2");
  fake_keyboard_manager_->AddFakeKeyboard(fake_keyboard2, kKbdTopRowLayout2Tag);
  SetKeyboardInfo(
      fake_keyboard2,
      ui::KeyboardCapability::DeviceType::kDeviceExternalAppleKeyboard,
      ui::KeyboardCapability::KeyboardTopRowLayout::kKbdTopRowLayout2);

  auto settings = Shell::Get()
                      ->input_device_settings_controller()
                      ->GetKeyboardSettings(fake_keyboard1.id)
                      ->Clone();

  settings->f11 = ui::mojom::ExtendedFkeysModifier::kAlt;
  settings->f12 = ui::mojom::ExtendedFkeysModifier::kAlt;
  Shell::Get()->input_device_settings_controller()->SetKeyboardSettings(
      fake_keyboard1.id, mojo::Clone(settings));
  AcceleratorAliasConverter accelerator_alias_converter_;
  SetTopRowAsFKeysForKeyboard(fake_keyboard1, /*enabled=*/true);
  const ui::Accelerator accelerator{ui::VKEY_F11, ui::EF_CONTROL_DOWN};
  ui::Accelerator expected_accelerator{ui::VKEY_BROWSER_BACK,
                                       ui::EF_ALT_DOWN | ui::EF_CONTROL_DOWN};
  std::vector<ui::Accelerator> accelerator_alias =
      accelerator_alias_converter_.CreateAcceleratorAlias(accelerator);
  EXPECT_EQ(2u, accelerator_alias.size());
  EXPECT_EQ(accelerator, accelerator_alias[0]);
  EXPECT_EQ(expected_accelerator, accelerator_alias[1]);
}

class ActionKeyboardVariantsTest
    : public AcceleratorAliasConverterTest,
      public testing::WithParamInterface<ActionKeyAliasConverterTestData> {
 public:
  void SetUp() override {
    AcceleratorAliasConverterTest::SetUp();
    ActionKeyAliasConverterTestData test_data = GetParam();
    keyboard_connection_type_ = test_data.keyboard_connection_type_;
    keyboard_layout_types_ = test_data.keyboard_layout_types_;
    top_row_are_fkeys_ = test_data.top_row_are_fkeys_;
    accelerator_ = test_data.accelerator_;
    expected_accelerators_ = test_data.expected_accelerators_;
    fake_keyboard_manager_ = std::make_unique<FakeDeviceManager>();
  }

 protected:
  std::vector<ui::InputDeviceType> keyboard_connection_type_;
  std::vector<std::string> keyboard_layout_types_;
  std::vector<bool> top_row_are_fkeys_;
  ui::Accelerator accelerator_;
  std::vector<ui::Accelerator> expected_accelerators_;
  std::unique_ptr<FakeDeviceManager> fake_keyboard_manager_;
};

INSTANTIATE_TEST_SUITE_P(
    // Empty to simplify gtest output
    ,
    ActionKeyboardVariantsTest,
    testing::ValuesIn(std::vector<ActionKeyAliasConverterTestData>{
        {{ui::InputDeviceType::INPUT_DEVICE_INTERNAL},
         {kKbdTopRowLayout1Tag},
         {/*treat_top_row_as_fkeys=*/false},
         ui::Accelerator{ui::VKEY_BROWSER_REFRESH, ui::EF_NONE},
         {ui::Accelerator{ui::VKEY_BROWSER_REFRESH, ui::EF_NONE}}},
        {{ui::InputDeviceType::INPUT_DEVICE_INTERNAL},
         {kKbdTopRowLayout1Tag},
         {/*treat_top_row_as_fkeys=*/true},
         ui::Accelerator{ui::VKEY_BROWSER_REFRESH, ui::EF_NONE},
         {ui::Accelerator{ui::VKEY_BROWSER_REFRESH, ui::EF_COMMAND_DOWN}}},
        {{ui::InputDeviceType::INPUT_DEVICE_USB},
         {kKbdTopRowLayoutUnspecified},
         {/*treat_top_row_as_fkeys=*/false},
         ui::Accelerator{ui::VKEY_BROWSER_REFRESH, ui::EF_NONE},
         {ui::Accelerator{ui::VKEY_BROWSER_REFRESH, ui::EF_NONE},
          ui::Accelerator{ui::VKEY_F3, ui::EF_NONE}}},
        {{ui::InputDeviceType::INPUT_DEVICE_USB},
         {kKbdTopRowLayoutUnspecified},
         {/*treat_top_row_as_fkeys=*/true},
         ui::Accelerator{ui::VKEY_BROWSER_REFRESH, ui::EF_NONE},
         {ui::Accelerator{ui::VKEY_BROWSER_REFRESH, ui::EF_NONE},
          ui::Accelerator{ui::VKEY_F3, ui::EF_COMMAND_DOWN}}},
        {{ui::InputDeviceType::INPUT_DEVICE_INTERNAL, ui::INPUT_DEVICE_USB},
         {kKbdTopRowLayout1Tag, kKbdTopRowLayoutUnspecified},
         {/*treat_top_row_as_fkeys=*/false, /*treat_top_row_as_fkeys=*/false},
         ui::Accelerator{ui::VKEY_BROWSER_REFRESH, ui::EF_NONE},
         {ui::Accelerator{ui::VKEY_BROWSER_REFRESH, ui::EF_NONE},
          ui::Accelerator{ui::VKEY_F3, ui::EF_NONE}}},
        {{ui::InputDeviceType::INPUT_DEVICE_INTERNAL, ui::INPUT_DEVICE_USB},
         {kKbdTopRowLayout1Tag, kKbdTopRowLayoutUnspecified},
         {/*treat_top_row_as_fkeys=*/false, /*treat_top_row_as_fkeys=*/true},
         ui::Accelerator{ui::VKEY_BROWSER_REFRESH, ui::EF_NONE},
         {ui::Accelerator{ui::VKEY_BROWSER_REFRESH, ui::EF_NONE},
          ui::Accelerator{ui::VKEY_F3, ui::EF_COMMAND_DOWN}}},
        {{ui::InputDeviceType::INPUT_DEVICE_INTERNAL, ui::INPUT_DEVICE_USB},
         {kKbdTopRowLayout1Tag, kKbdTopRowLayoutUnspecified},
         {/*treat_top_row_as_fkeys=*/true, /*treat_top_row_as_fkeys=*/false},
         ui::Accelerator{ui::VKEY_BROWSER_REFRESH, ui::EF_NONE},
         {ui::Accelerator{ui::VKEY_F3, ui::EF_NONE},
          ui::Accelerator{ui::VKEY_BROWSER_REFRESH, ui::EF_NONE},
          ui::Accelerator{ui::VKEY_BROWSER_REFRESH, ui::EF_COMMAND_DOWN}}},
        {{ui::InputDeviceType::INPUT_DEVICE_INTERNAL, ui::INPUT_DEVICE_USB},
         {kKbdTopRowLayout1Tag, kKbdTopRowLayoutUnspecified},
         {/*treat_top_row_as_fkeys=*/true, /*treat_top_row_as_fkeys=*/true},
         ui::Accelerator{ui::VKEY_BROWSER_REFRESH, ui::EF_NONE},
         {ui::Accelerator{ui::VKEY_BROWSER_REFRESH, ui::EF_NONE},
          ui::Accelerator{ui::VKEY_BROWSER_REFRESH, ui::EF_COMMAND_DOWN},
          ui::Accelerator{ui::VKEY_F3, ui::EF_COMMAND_DOWN}}},
    }));

TEST_P(ActionKeyboardVariantsTest, CheckTopRowAlias) {
  // Add fake keyboards based on layout type.
  fake_keyboard_manager_->RemoveAllDevices();
  for (int i = 0; const std::string& layout : keyboard_layout_types_) {
    ui::KeyboardDevice fake_keyboard(
        /*id=*/i, /*type=*/keyboard_connection_type_[i],
        /*name=*/layout);
    fake_keyboard.sys_path = base::FilePath("path" + layout);
    fake_keyboard.vendor_id = i;
    fake_keyboard.product_id = i;
    fake_keyboard_manager_->AddFakeKeyboard(fake_keyboard, layout);
    SetTopRowAsFKeysForKeyboard(fake_keyboard, top_row_are_fkeys_[i]);
    i++;
  }

  AcceleratorAliasConverter accelerator_alias_converter_;

  std::vector<ui::Accelerator> accelerator_alias =
      accelerator_alias_converter_.CreateAcceleratorAlias(accelerator_);
  base::ranges::sort(accelerator_alias);
  base::ranges::sort(expected_accelerators_);

  ASSERT_EQ(expected_accelerators_.size(), accelerator_alias.size());
  for (size_t i = 0; i < expected_accelerators_.size(); i++) {
    EXPECT_EQ(expected_accelerators_[i], accelerator_alias[i]);
  }
}

}  // namespace ash