blob: f475413add418b83fa9f866398b22add7df0f1d0 [file] [log] [blame]
// 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/accelerators/ash_accelerator_configuration.h"
#include <memory>
#include <string>
#include "ash/accelerators/ash_accelerator_configuration.h"
#include "ash/public/cpp/accelerator_configuration.h"
#include "ash/public/cpp/accelerators.h"
#include "ash/public/cpp/accelerators_util.h"
#include "ash/public/mojom/accelerator_configuration.mojom.h"
#include "base/containers/contains.h"
#include "base/ranges/algorithm.h"
#include "base/test/scoped_feature_list.h"
#include "ui/base/accelerators/accelerator.h"
#include "ui/base/ui_base_features.h"
#include "ui/events/event_constants.h"
#include "ui/events/keycodes/dom/dom_codes_array.h"
#include "ui/events/keycodes/dom/dom_key.h"
#include "ui/events/keycodes/keyboard_codes_posix.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace {
using ::ash::mojom::AcceleratorConfigResult;
class UpdatedAcceleratorsObserver
: public ash::AshAcceleratorConfiguration::Observer {
public:
UpdatedAcceleratorsObserver() = default;
UpdatedAcceleratorsObserver(const UpdatedAcceleratorsObserver&) = delete;
UpdatedAcceleratorsObserver& operator=(const UpdatedAcceleratorsObserver&) =
delete;
~UpdatedAcceleratorsObserver() override = default;
// ash::AshAcceleratorConfiguration::Observer:
void OnAcceleratorsUpdated() override {
++num_times_accelerator_updated_called_;
}
int num_times_accelerator_updated_called() {
return num_times_accelerator_updated_called_;
}
private:
int num_times_accelerator_updated_called_ = 0;
};
bool CompareAccelerators(const ash::AcceleratorData& expected_data,
const ui::Accelerator& actual_accelerator) {
ui::Accelerator expected_accel(expected_data.keycode,
expected_data.modifiers);
return expected_accel.key_code() == actual_accelerator.key_code() &&
expected_accel.modifiers() == actual_accelerator.modifiers();
}
void ExpectAllAcceleratorsEqual(
const base::span<const ash::AcceleratorData> expected,
const std::vector<ui::Accelerator>& actual) {
EXPECT_EQ(std::size(expected), actual.size());
for (const auto& actual_accelerator : actual) {
bool found_match = false;
for (const auto& expected_data : expected) {
found_match = CompareAccelerators(expected_data, actual_accelerator);
if (found_match) {
break;
}
}
EXPECT_TRUE(found_match);
}
}
} // namespace
namespace ash {
class AshAcceleratorConfigurationTest : public testing::Test {
public:
AshAcceleratorConfigurationTest() {
scoped_feature_list_.InitAndEnableFeature(
::features::kShortcutCustomization);
config_ = std::make_unique<AshAcceleratorConfiguration>();
config_->AddObserver(&observer_);
}
~AshAcceleratorConfigurationTest() override {
config_->RemoveObserver(&observer_);
}
protected:
base::test::ScopedFeatureList scoped_feature_list_;
UpdatedAcceleratorsObserver observer_;
std::unique_ptr<AshAcceleratorConfiguration> config_;
};
TEST_F(AshAcceleratorConfigurationTest, VerifyAcceleratorMappingPopulated) {
const AcceleratorData test_data[] = {
{/*trigger_on_press=*/true, ui::VKEY_SPACE, ui::EF_CONTROL_DOWN,
SWITCH_TO_LAST_USED_IME},
{/*trigger_on_press=*/true, ui::VKEY_SPACE,
ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN, SWITCH_TO_LAST_USED_IME},
{/*trigger_on_press=*/true, ui::VKEY_TAB, ui::EF_ALT_DOWN,
CYCLE_FORWARD_MRU},
{/*trigger_on_press=*/true, ui::VKEY_TAB,
ui::EF_SHIFT_DOWN | ui::EF_ALT_DOWN, CYCLE_BACKWARD_MRU},
};
config_->Initialize(test_data);
const std::vector<ui::Accelerator>& accelerators =
config_->GetAllAccelerators();
ExpectAllAcceleratorsEqual(test_data, accelerators);
}
TEST_F(AshAcceleratorConfigurationTest, DeprecatedAccelerators) {
// Test deprecated accelerators, in this case `SHOW_TASK_MANAGER` has two
// associated accelerators: (deprecated) ESCAPE + SHIFT and
// (active) ESCAPE + COMMAND.
const AcceleratorData initial_test_data[] = {
{/*trigger_on_press=*/true, ui::VKEY_TAB, ui::EF_ALT_DOWN,
CYCLE_FORWARD_MRU},
{/*trigger_on_press=*/true, ui::VKEY_TAB,
ui::EF_SHIFT_DOWN | ui::EF_ALT_DOWN, CYCLE_BACKWARD_MRU},
{/*trigger_on_press=*/true, ui::VKEY_ESCAPE, ui::EF_COMMAND_DOWN,
SHOW_TASK_MANAGER},
};
const AcceleratorData expected_test_data[] = {
{/*trigger_on_press=*/true, ui::VKEY_TAB, ui::EF_ALT_DOWN,
CYCLE_FORWARD_MRU},
{/*trigger_on_press=*/true, ui::VKEY_TAB,
ui::EF_SHIFT_DOWN | ui::EF_ALT_DOWN, CYCLE_BACKWARD_MRU},
{/*trigger_on_press=*/true, ui::VKEY_ESCAPE, ui::EF_COMMAND_DOWN,
SHOW_TASK_MANAGER},
{/*trigger_on_press=*/true, ui::VKEY_ESCAPE, ui::EF_SHIFT_DOWN,
SHOW_TASK_MANAGER},
};
const DeprecatedAcceleratorData deprecated_data[] = {
{SHOW_TASK_MANAGER, /*uma_histogram_name=*/"deprecated.showTaskManager",
/*notification_message_id=*/1, /*old_shortcut_id=*/1,
/*new_shortcut_id=*/2, /*deprecated_enabled=*/true},
};
const AcceleratorData test_deprecated_accelerators[] = {
{/*trigger_on_press=*/true, ui::VKEY_ESCAPE, ui::EF_SHIFT_DOWN,
SHOW_TASK_MANAGER},
};
config_->Initialize(initial_test_data);
config_->InitializeDeprecatedAccelerators(deprecated_data,
test_deprecated_accelerators);
const std::vector<ui::Accelerator>& accelerators =
config_->GetAllAccelerators();
// When initializing deprecated accelerators, expect them to be added to the
// overall accelerators list too.
ExpectAllAcceleratorsEqual(expected_test_data, accelerators);
// Verify that the fetched deprecated accelerators are correct.
std::vector<ui::Accelerator> deprecated_accelerators;
for (const auto& accel : accelerators) {
if (config_->IsDeprecated(accel)) {
deprecated_accelerators.push_back(accel);
}
}
ExpectAllAcceleratorsEqual(test_deprecated_accelerators,
deprecated_accelerators);
// Verify ESCAPE + SHIFT is deprecated.
const ui::Accelerator deprecated_accelerator(ui::VKEY_ESCAPE,
ui::EF_SHIFT_DOWN);
EXPECT_TRUE(config_->IsDeprecated(deprecated_accelerator));
// Verify fetching a deprecated accelerator works.
EXPECT_EQ(deprecated_data,
config_->GetDeprecatedAcceleratorData(SHOW_TASK_MANAGER));
// CYCLE_BACKWARD_MRU is not a deprecated action, expect nullptr.
EXPECT_EQ(nullptr, config_->GetDeprecatedAcceleratorData(CYCLE_BACKWARD_MRU));
// Verify that ESCAPE + COMMAND is not deprecated.
const ui::Accelerator active_accelerator(ui::VKEY_ESCAPE,
ui::EF_COMMAND_DOWN);
EXPECT_FALSE(config_->IsDeprecated(active_accelerator));
}
TEST_F(AshAcceleratorConfigurationTest,
RemoveAndRestoreDeprecatedAccelerators) {
// Test deprecated accelerators, in this case `SHOW_TASK_MANAGER` has two
// associated accelerators: (deprecated) ESCAPE + SHIFT and
// (active) ESCAPE + COMMAND.
const AcceleratorData initial_test_data[] = {
{/*trigger_on_press=*/true, ui::VKEY_TAB, ui::EF_ALT_DOWN,
CYCLE_FORWARD_MRU},
{/*trigger_on_press=*/true, ui::VKEY_TAB,
ui::EF_SHIFT_DOWN | ui::EF_ALT_DOWN, CYCLE_BACKWARD_MRU},
{/*trigger_on_press=*/true, ui::VKEY_ESCAPE, ui::EF_COMMAND_DOWN,
SHOW_TASK_MANAGER},
};
const AcceleratorData expected_test_data[] = {
{/*trigger_on_press=*/true, ui::VKEY_TAB, ui::EF_ALT_DOWN,
CYCLE_FORWARD_MRU},
{/*trigger_on_press=*/true, ui::VKEY_TAB,
ui::EF_SHIFT_DOWN | ui::EF_ALT_DOWN, CYCLE_BACKWARD_MRU},
{/*trigger_on_press=*/true, ui::VKEY_ESCAPE, ui::EF_COMMAND_DOWN,
SHOW_TASK_MANAGER},
{/*trigger_on_press=*/true, ui::VKEY_ESCAPE, ui::EF_SHIFT_DOWN,
SHOW_TASK_MANAGER},
};
const DeprecatedAcceleratorData deprecated_data[] = {
{SHOW_TASK_MANAGER, /*uma_histogram_name=*/"deprecated.showTaskManager",
/*notification_message_id=*/1, /*old_shortcut_id=*/1,
/*new_shortcut_id=*/2, /*deprecated_enabled=*/true},
};
const AcceleratorData test_deprecated_accelerators[] = {
{/*trigger_on_press=*/true, ui::VKEY_ESCAPE, ui::EF_SHIFT_DOWN,
SHOW_TASK_MANAGER},
};
config_->Initialize(initial_test_data);
config_->InitializeDeprecatedAccelerators(deprecated_data,
test_deprecated_accelerators);
const ui::Accelerator deprecated_accelerator(ui::VKEY_ESCAPE,
ui::EF_SHIFT_DOWN);
// Remove the deprecated accelerator ESCAPE + SHIFT.
const AcceleratorData updated_expected_test_data[] = {
{/*trigger_on_press=*/true, ui::VKEY_TAB, ui::EF_ALT_DOWN,
CYCLE_FORWARD_MRU},
{/*trigger_on_press=*/true, ui::VKEY_TAB,
ui::EF_SHIFT_DOWN | ui::EF_ALT_DOWN, CYCLE_BACKWARD_MRU},
{/*trigger_on_press=*/true, ui::VKEY_ESCAPE, ui::EF_COMMAND_DOWN,
SHOW_TASK_MANAGER},
};
AcceleratorConfigResult result =
config_->RemoveAccelerator(SHOW_TASK_MANAGER, deprecated_accelerator);
EXPECT_EQ(AcceleratorConfigResult::kSuccess, result);
// Verify that the accelerator is no longer deprecated.
EXPECT_FALSE(config_->IsDeprecated(deprecated_accelerator));
EXPECT_FALSE(config_->GetDeprecatedAcceleratorData(SHOW_TASK_MANAGER));
ExpectAllAcceleratorsEqual(updated_expected_test_data,
config_->GetAllAccelerators());
// Attempt to restore SHOW_TASK_MANAGER, expect deprecated accelerator to NOT
// be re-added.
result = config_->RestoreDefault(SHOW_TASK_MANAGER);
EXPECT_EQ(AcceleratorConfigResult::kSuccess, result);
EXPECT_FALSE(config_->IsDeprecated(deprecated_accelerator));
EXPECT_FALSE(config_->GetDeprecatedAcceleratorData(SHOW_TASK_MANAGER));
ExpectAllAcceleratorsEqual(updated_expected_test_data,
config_->GetAllAccelerators());
// Now restore all accelerators, this time deprecated accelerators should be
// restored.
result = config_->RestoreAllDefaults();
EXPECT_EQ(AcceleratorConfigResult::kSuccess, result);
EXPECT_TRUE(config_->IsDeprecated(deprecated_accelerator));
EXPECT_EQ(deprecated_data,
config_->GetDeprecatedAcceleratorData(SHOW_TASK_MANAGER));
ExpectAllAcceleratorsEqual(expected_test_data, config_->GetAllAccelerators());
}
TEST_F(AshAcceleratorConfigurationTest, IsDefaultAccelerator) {
const AcceleratorData test_data[] = {
{/*trigger_on_press=*/true, ui::VKEY_ZOOM, ui::EF_CONTROL_DOWN,
TOGGLE_MIRROR_MODE},
{/*trigger_on_press=*/true, ui::VKEY_ZOOM, ui::EF_ALT_DOWN,
SWAP_PRIMARY_DISPLAY},
{/*trigger_on_press=*/true, ui::VKEY_MEDIA_LAUNCH_APP1,
ui::EF_CONTROL_DOWN, TAKE_SCREENSHOT},
{/*trigger_on_press=*/true, ui::VKEY_KBD_BRIGHTNESS_UP, ui::EF_NONE,
KEYBOARD_BRIGHTNESS_UP},
{/*trigger_on_press=*/true, ui::VKEY_BRIGHTNESS_UP, ui::EF_ALT_DOWN,
KEYBOARD_BRIGHTNESS_UP},
};
// `Initialize()` sets up the default accelerators.
config_->Initialize(test_data);
ExpectAllAcceleratorsEqual(test_data, config_->GetAllAccelerators());
// Verify that Control + Zoom is the default for TOGGLE_MIRROR_MODE.
ui::Accelerator expected_default =
ui::Accelerator(ui::VKEY_ZOOM, ui::EF_CONTROL_DOWN);
absl::optional<AcceleratorAction> accelerator_id =
config_->GetIdForDefaultAccelerator(expected_default);
EXPECT_TRUE(accelerator_id.has_value());
EXPECT_EQ(TOGGLE_MIRROR_MODE, accelerator_id.value());
std::vector<ui::Accelerator> default_accelerators =
config_->GetDefaultAcceleratorsForId(TOGGLE_MIRROR_MODE);
EXPECT_EQ(1u, default_accelerators.size());
EXPECT_EQ(expected_default, default_accelerators[0]);
}
TEST_F(AshAcceleratorConfigurationTest, MultipleDefaultAccelerators) {
const AcceleratorData test_data[] = {
{/*trigger_on_press=*/true, ui::VKEY_ZOOM, ui::EF_CONTROL_DOWN,
TOGGLE_MIRROR_MODE},
{/*trigger_on_press=*/true, ui::VKEY_ZOOM, ui::EF_ALT_DOWN,
TOGGLE_MIRROR_MODE},
{/*trigger_on_press=*/true, ui::VKEY_MEDIA_LAUNCH_APP1,
ui::EF_CONTROL_DOWN, TAKE_SCREENSHOT},
{/*trigger_on_press=*/true, ui::VKEY_KBD_BRIGHTNESS_UP, ui::EF_NONE,
KEYBOARD_BRIGHTNESS_UP},
{/*trigger_on_press=*/true, ui::VKEY_BRIGHTNESS_UP, ui::EF_ALT_DOWN,
KEYBOARD_BRIGHTNESS_UP},
};
// `Initialize()` sets up the default accelerators.
config_->Initialize(test_data);
ExpectAllAcceleratorsEqual(test_data, config_->GetAllAccelerators());
// Verify that Control + Zoom and Alt + Zoom are defaults for
// TOGGLE_MIRROR_MODE.
ui::Accelerator expected_default =
ui::Accelerator(ui::VKEY_ZOOM, ui::EF_CONTROL_DOWN);
ui::Accelerator expected_default_2 =
ui::Accelerator(ui::VKEY_ZOOM, ui::EF_ALT_DOWN);
absl::optional<AcceleratorAction> accelerator_id =
config_->GetIdForDefaultAccelerator(expected_default);
EXPECT_TRUE(accelerator_id.has_value());
EXPECT_EQ(TOGGLE_MIRROR_MODE, accelerator_id.value());
accelerator_id = config_->GetIdForDefaultAccelerator(expected_default_2);
EXPECT_TRUE(accelerator_id.has_value());
EXPECT_EQ(TOGGLE_MIRROR_MODE, accelerator_id.value());
std::vector<ui::Accelerator> default_accelerators =
config_->GetDefaultAcceleratorsForId(TOGGLE_MIRROR_MODE);
EXPECT_EQ(2u, default_accelerators.size());
EXPECT_TRUE(base::Contains(default_accelerators, expected_default));
EXPECT_TRUE(base::Contains(default_accelerators, expected_default_2));
}
TEST_F(AshAcceleratorConfigurationTest, DefaultNotFound) {
const AcceleratorData test_data[] = {
{/*trigger_on_press=*/true, ui::VKEY_ZOOM, ui::EF_CONTROL_DOWN,
TOGGLE_MIRROR_MODE},
{/*trigger_on_press=*/true, ui::VKEY_ZOOM, ui::EF_ALT_DOWN,
SWAP_PRIMARY_DISPLAY},
{/*trigger_on_press=*/true, ui::VKEY_MEDIA_LAUNCH_APP1,
ui::EF_CONTROL_DOWN, TAKE_SCREENSHOT},
{/*trigger_on_press=*/true, ui::VKEY_KBD_BRIGHTNESS_UP, ui::EF_NONE,
KEYBOARD_BRIGHTNESS_UP},
{/*trigger_on_press=*/true, ui::VKEY_BRIGHTNESS_UP, ui::EF_ALT_DOWN,
KEYBOARD_BRIGHTNESS_UP},
};
// `Initialize()` sets up the default accelerators.
config_->Initialize(test_data);
ExpectAllAcceleratorsEqual(test_data, config_->GetAllAccelerators());
// Verify that Ctrl + U is not a default accelerator in this test set.
ui::Accelerator fake_default =
ui::Accelerator(ui::VKEY_U, ui::EF_CONTROL_DOWN);
absl::optional<AcceleratorAction> accelerator_id =
config_->GetIdForDefaultAccelerator(fake_default);
EXPECT_FALSE(accelerator_id.has_value());
}
TEST_F(AshAcceleratorConfigurationTest, GetAcceleratorsFromActionId) {
const AcceleratorData test_data[] = {
{/*trigger_on_press=*/true, ui::VKEY_ZOOM, ui::EF_CONTROL_DOWN,
TOGGLE_MIRROR_MODE},
{/*trigger_on_press=*/true, ui::VKEY_ZOOM, ui::EF_ALT_DOWN,
SWAP_PRIMARY_DISPLAY},
{/*trigger_on_press=*/true, ui::VKEY_MEDIA_LAUNCH_APP1,
ui::EF_CONTROL_DOWN, TAKE_SCREENSHOT},
{/*trigger_on_press=*/true, ui::VKEY_KBD_BRIGHTNESS_UP, ui::EF_NONE,
KEYBOARD_BRIGHTNESS_UP},
{/*trigger_on_press=*/true, ui::VKEY_BRIGHTNESS_UP, ui::EF_ALT_DOWN,
KEYBOARD_BRIGHTNESS_UP},
};
config_->Initialize(test_data);
// Create expected id_to_accelerator_data map.
std::map<AcceleratorActionId, std::vector<AcceleratorData>>
id_to_accelerator_data;
for (const auto& data : test_data) {
id_to_accelerator_data[static_cast<uint32_t>(data.action)].push_back(data);
}
// Verify that expected and actual are equal.
for (const auto& data : test_data) {
std::vector<AcceleratorData> expected =
id_to_accelerator_data.at(data.action);
std::vector<ui::Accelerator> actual =
config_->GetAcceleratorsForAction(data.action);
ExpectAllAcceleratorsEqual(expected, actual);
}
}
TEST_F(AshAcceleratorConfigurationTest, VerifyObserversAreNotified) {
EXPECT_EQ(0, observer_.num_times_accelerator_updated_called());
const AcceleratorData test_data[] = {
{/*trigger_on_press=*/true, ui::VKEY_SPACE, ui::EF_CONTROL_DOWN,
SWITCH_TO_LAST_USED_IME},
{/*trigger_on_press=*/true, ui::VKEY_SPACE,
ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN, SWITCH_TO_LAST_USED_IME},
{/*trigger_on_press=*/true, ui::VKEY_TAB, ui::EF_ALT_DOWN,
CYCLE_FORWARD_MRU},
{/*trigger_on_press=*/true, ui::VKEY_TAB,
ui::EF_SHIFT_DOWN | ui::EF_ALT_DOWN, CYCLE_BACKWARD_MRU},
};
config_->Initialize(test_data);
const std::vector<ui::Accelerator>& accelerators =
config_->GetAllAccelerators();
ExpectAllAcceleratorsEqual(test_data, accelerators);
EXPECT_EQ(1, observer_.num_times_accelerator_updated_called());
// Now update accelerators with a different set of accelerators.
const AcceleratorData test_data_updated[] = {
{/*trigger_on_press=*/true, ui::VKEY_J, ui::EF_CONTROL_DOWN,
TOGGLE_FULLSCREEN},
};
config_->Initialize(test_data_updated);
const std::vector<ui::Accelerator>& accelerators_updated =
config_->GetAllAccelerators();
ExpectAllAcceleratorsEqual(test_data_updated, accelerators_updated);
EXPECT_EQ(2, observer_.num_times_accelerator_updated_called());
}
TEST_F(AshAcceleratorConfigurationTest, RemoveAccelerator) {
EXPECT_EQ(0, observer_.num_times_accelerator_updated_called());
const AcceleratorData test_data[] = {
{/*trigger_on_press=*/true, ui::VKEY_SPACE, ui::EF_CONTROL_DOWN,
SWITCH_TO_LAST_USED_IME},
{/*trigger_on_press=*/true, ui::VKEY_SPACE,
ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN, SWITCH_TO_LAST_USED_IME},
{/*trigger_on_press=*/true, ui::VKEY_TAB, ui::EF_ALT_DOWN,
CYCLE_FORWARD_MRU},
{/*trigger_on_press=*/true, ui::VKEY_TAB,
ui::EF_SHIFT_DOWN | ui::EF_ALT_DOWN, CYCLE_BACKWARD_MRU},
};
config_->Initialize(test_data);
ExpectAllAcceleratorsEqual(test_data, config_->GetAllAccelerators());
EXPECT_EQ(1, observer_.num_times_accelerator_updated_called());
// Remove `SWITCH_TO_LAST_USE_IME`.
const AcceleratorData updated_test_data[] = {
{/*trigger_on_press=*/true, ui::VKEY_SPACE,
ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN, SWITCH_TO_LAST_USED_IME},
{/*trigger_on_press=*/true, ui::VKEY_TAB, ui::EF_ALT_DOWN,
CYCLE_FORWARD_MRU},
{/*trigger_on_press=*/true, ui::VKEY_TAB,
ui::EF_SHIFT_DOWN | ui::EF_ALT_DOWN, CYCLE_BACKWARD_MRU},
};
AcceleratorConfigResult result = config_->RemoveAccelerator(
SWITCH_TO_LAST_USED_IME,
ui::Accelerator(ui::VKEY_SPACE, ui::EF_CONTROL_DOWN));
EXPECT_EQ(AcceleratorConfigResult::kSuccess, result);
// Compare expected accelerators and that the observer was fired after
// removing an accelerator.
ExpectAllAcceleratorsEqual(updated_test_data, config_->GetAllAccelerators());
EXPECT_EQ(2, observer_.num_times_accelerator_updated_called());
// Attempt to remove the accelerator again, expect to return error.
AcceleratorConfigResult re_remove_result = config_->RemoveAccelerator(
SWITCH_TO_LAST_USED_IME,
ui::Accelerator(ui::VKEY_SPACE, ui::EF_CONTROL_DOWN));
EXPECT_EQ(AcceleratorConfigResult::kNotFound, re_remove_result);
// Expect no changes to be made.
ExpectAllAcceleratorsEqual(updated_test_data, config_->GetAllAccelerators());
EXPECT_EQ(2, observer_.num_times_accelerator_updated_called());
}
TEST_F(AshAcceleratorConfigurationTest, RemoveAcceleratorIDThatDoesntExist) {
EXPECT_EQ(0, observer_.num_times_accelerator_updated_called());
const AcceleratorData test_data[] = {
{/*trigger_on_press=*/true, ui::VKEY_SPACE, ui::EF_CONTROL_DOWN,
SWITCH_TO_LAST_USED_IME},
};
config_->Initialize(test_data);
ExpectAllAcceleratorsEqual(test_data, config_->GetAllAccelerators());
EXPECT_EQ(1, observer_.num_times_accelerator_updated_called());
// Attempt to remove an accelerator with an action ID that doesn't exist.
AcceleratorConfigResult result = config_->RemoveAccelerator(
CYCLE_BACKWARD_MRU, ui::Accelerator(ui::VKEY_SPACE, ui::EF_CONTROL_DOWN));
EXPECT_EQ(AcceleratorConfigResult::kNotFound, result);
// Nothing should change.
ExpectAllAcceleratorsEqual(test_data, config_->GetAllAccelerators());
EXPECT_EQ(1, observer_.num_times_accelerator_updated_called());
}
TEST_F(AshAcceleratorConfigurationTest, RemoveAcceleratorThatDoesntExist) {
EXPECT_EQ(0, observer_.num_times_accelerator_updated_called());
const AcceleratorData test_data[] = {
{/*trigger_on_press=*/true, ui::VKEY_SPACE, ui::EF_CONTROL_DOWN,
SWITCH_TO_LAST_USED_IME},
};
config_->Initialize(test_data);
ExpectAllAcceleratorsEqual(test_data, config_->GetAllAccelerators());
EXPECT_EQ(1, observer_.num_times_accelerator_updated_called());
// Remove an accelerator that doesn't exist, but with an
// existing action ID. Expect no change.
AcceleratorConfigResult updated_result = config_->RemoveAccelerator(
SWITCH_TO_LAST_USED_IME,
ui::Accelerator(ui::VKEY_M, ui::EF_CONTROL_DOWN));
EXPECT_EQ(AcceleratorConfigResult::kNotFound, updated_result);
// Nothing should change.
ExpectAllAcceleratorsEqual(test_data, config_->GetAllAccelerators());
EXPECT_EQ(1, observer_.num_times_accelerator_updated_called());
}
TEST_F(AshAcceleratorConfigurationTest, RemoveDefaultAccelerator) {
EXPECT_EQ(0, observer_.num_times_accelerator_updated_called());
const AcceleratorData test_data[] = {
{/*trigger_on_press=*/true, ui::VKEY_SPACE, ui::EF_CONTROL_DOWN,
SWITCH_TO_LAST_USED_IME},
{/*trigger_on_press=*/true, ui::VKEY_SPACE,
ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN, BRIGHTNESS_DOWN},
{/*trigger_on_press=*/true, ui::VKEY_TAB, ui::EF_ALT_DOWN,
CYCLE_FORWARD_MRU},
{/*trigger_on_press=*/true, ui::VKEY_TAB,
ui::EF_SHIFT_DOWN | ui::EF_ALT_DOWN, CYCLE_BACKWARD_MRU},
};
config_->Initialize(test_data);
ExpectAllAcceleratorsEqual(test_data, config_->GetAllAccelerators());
EXPECT_EQ(1, observer_.num_times_accelerator_updated_called());
// Remove `SWITCH_TO_LAST_USE_IME`.
const AcceleratorData updated_test_data[] = {
{/*trigger_on_press=*/true, ui::VKEY_SPACE,
ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN, SWITCH_TO_LAST_USED_IME},
{/*trigger_on_press=*/true, ui::VKEY_TAB, ui::EF_ALT_DOWN,
CYCLE_FORWARD_MRU},
{/*trigger_on_press=*/true, ui::VKEY_TAB,
ui::EF_SHIFT_DOWN | ui::EF_ALT_DOWN, CYCLE_BACKWARD_MRU},
};
ui::Accelerator removed_accelerator =
ui::Accelerator(ui::VKEY_SPACE, ui::EF_CONTROL_DOWN);
AcceleratorConfigResult result =
config_->RemoveAccelerator(SWITCH_TO_LAST_USED_IME, removed_accelerator);
EXPECT_EQ(AcceleratorConfigResult::kSuccess, result);
// We removed a default accelerator, it should still be cached as a default.
EXPECT_EQ(SWITCH_TO_LAST_USED_IME,
config_->GetIdForDefaultAccelerator(removed_accelerator));
std::vector<ui::Accelerator> default_accelerators =
config_->GetDefaultAcceleratorsForId(SWITCH_TO_LAST_USED_IME);
EXPECT_EQ(1u, default_accelerators.size());
EXPECT_EQ(removed_accelerator, default_accelerators[0]);
// Compare expected accelerators and that the observer was fired after
// removing an accelerator.
ExpectAllAcceleratorsEqual(updated_test_data, config_->GetAllAccelerators());
EXPECT_EQ(2, observer_.num_times_accelerator_updated_called());
}
TEST_F(AshAcceleratorConfigurationTest, RemoveAndRestoreDefault) {
EXPECT_EQ(0, observer_.num_times_accelerator_updated_called());
const AcceleratorData test_data[] = {
{/*trigger_on_press=*/true, ui::VKEY_SPACE, ui::EF_CONTROL_DOWN,
SWITCH_TO_LAST_USED_IME},
{/*trigger_on_press=*/true, ui::VKEY_SPACE,
ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN, SWITCH_TO_LAST_USED_IME},
{/*trigger_on_press=*/true, ui::VKEY_TAB, ui::EF_ALT_DOWN,
CYCLE_FORWARD_MRU},
{/*trigger_on_press=*/true, ui::VKEY_TAB,
ui::EF_SHIFT_DOWN | ui::EF_ALT_DOWN, CYCLE_BACKWARD_MRU},
};
config_->Initialize(test_data);
ExpectAllAcceleratorsEqual(test_data, config_->GetAllAccelerators());
EXPECT_EQ(1, observer_.num_times_accelerator_updated_called());
// Remove `SWITCH_TO_LAST_USE_IME`.
const AcceleratorData updated_test_data[] = {
{/*trigger_on_press=*/true, ui::VKEY_SPACE,
ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN, SWITCH_TO_LAST_USED_IME},
{/*trigger_on_press=*/true, ui::VKEY_TAB, ui::EF_ALT_DOWN,
CYCLE_FORWARD_MRU},
{/*trigger_on_press=*/true, ui::VKEY_TAB,
ui::EF_SHIFT_DOWN | ui::EF_ALT_DOWN, CYCLE_BACKWARD_MRU},
};
AcceleratorConfigResult result = config_->RemoveAccelerator(
SWITCH_TO_LAST_USED_IME,
ui::Accelerator(ui::VKEY_SPACE, ui::EF_CONTROL_DOWN));
EXPECT_EQ(AcceleratorConfigResult::kSuccess, result);
// Compare expected accelerators and that the observer was fired after
// removing an accelerator.
ExpectAllAcceleratorsEqual(updated_test_data, config_->GetAllAccelerators());
EXPECT_EQ(2, observer_.num_times_accelerator_updated_called());
// Restore all defaults.
result = config_->RestoreAllDefaults();
EXPECT_EQ(AcceleratorConfigResult::kSuccess, result);
// Expect accelerators to revert back to the default state and observer
// is called.
ExpectAllAcceleratorsEqual(test_data, config_->GetAllAccelerators());
EXPECT_EQ(3, observer_.num_times_accelerator_updated_called());
}
TEST_F(AshAcceleratorConfigurationTest, RestoreAllConsecutively) {
EXPECT_EQ(0, observer_.num_times_accelerator_updated_called());
const AcceleratorData test_data[] = {
{/*trigger_on_press=*/true, ui::VKEY_SPACE, ui::EF_CONTROL_DOWN,
SWITCH_TO_LAST_USED_IME},
{/*trigger_on_press=*/true, ui::VKEY_SPACE,
ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN, SWITCH_TO_LAST_USED_IME},
{/*trigger_on_press=*/true, ui::VKEY_TAB, ui::EF_ALT_DOWN,
CYCLE_FORWARD_MRU},
{/*trigger_on_press=*/true, ui::VKEY_TAB,
ui::EF_SHIFT_DOWN | ui::EF_ALT_DOWN, CYCLE_BACKWARD_MRU},
};
config_->Initialize(test_data);
ExpectAllAcceleratorsEqual(test_data, config_->GetAllAccelerators());
EXPECT_EQ(1, observer_.num_times_accelerator_updated_called());
// Restore all defaults, even though no change was made.
AcceleratorConfigResult reset_result = config_->RestoreAllDefaults();
EXPECT_EQ(AcceleratorConfigResult::kSuccess, reset_result);
// Nothing should have changed, but the observer is called.
ExpectAllAcceleratorsEqual(test_data, config_->GetAllAccelerators());
EXPECT_EQ(2, observer_.num_times_accelerator_updated_called());
// Restore all defaults again, even though no change was made.
reset_result = config_->RestoreAllDefaults();
EXPECT_EQ(AcceleratorConfigResult::kSuccess, reset_result);
// Nothing should have changed, but the observer is called.
ExpectAllAcceleratorsEqual(test_data, config_->GetAllAccelerators());
EXPECT_EQ(3, observer_.num_times_accelerator_updated_called());
}
TEST_F(AshAcceleratorConfigurationTest, RemoveAndRestoreOneAction) {
EXPECT_EQ(0, observer_.num_times_accelerator_updated_called());
const AcceleratorData test_data[] = {
{/*trigger_on_press=*/true, ui::VKEY_SPACE, ui::EF_CONTROL_DOWN,
SWITCH_TO_LAST_USED_IME},
{/*trigger_on_press=*/true, ui::VKEY_SPACE,
ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN, SWITCH_TO_LAST_USED_IME},
{/*trigger_on_press=*/true, ui::VKEY_TAB, ui::EF_ALT_DOWN,
CYCLE_FORWARD_MRU},
{/*trigger_on_press=*/true, ui::VKEY_TAB,
ui::EF_SHIFT_DOWN | ui::EF_ALT_DOWN, CYCLE_BACKWARD_MRU},
};
config_->Initialize(test_data);
ExpectAllAcceleratorsEqual(test_data, config_->GetAllAccelerators());
EXPECT_EQ(1, observer_.num_times_accelerator_updated_called());
// Remove `SWITCH_TO_LAST_USE_IME`.
const AcceleratorData updated_test_data[] = {
{/*trigger_on_press=*/true, ui::VKEY_SPACE,
ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN, SWITCH_TO_LAST_USED_IME},
{/*trigger_on_press=*/true, ui::VKEY_TAB, ui::EF_ALT_DOWN,
CYCLE_FORWARD_MRU},
{/*trigger_on_press=*/true, ui::VKEY_TAB,
ui::EF_SHIFT_DOWN | ui::EF_ALT_DOWN, CYCLE_BACKWARD_MRU},
};
AcceleratorConfigResult result = config_->RemoveAccelerator(
SWITCH_TO_LAST_USED_IME,
ui::Accelerator(ui::VKEY_SPACE, ui::EF_CONTROL_DOWN));
EXPECT_EQ(AcceleratorConfigResult::kSuccess, result);
// Compare expected accelerators and that the observer was fired after
// removing an accelerator.
ExpectAllAcceleratorsEqual(updated_test_data, config_->GetAllAccelerators());
EXPECT_EQ(2, observer_.num_times_accelerator_updated_called());
// Reset the `SWITCH_TO_LAST_USED_IME` action..
result = config_->RestoreDefault(SWITCH_TO_LAST_USED_IME);
EXPECT_EQ(AcceleratorConfigResult::kSuccess, result);
// Expect accelerators to revert back to the default state and observer
// is called.
ExpectAllAcceleratorsEqual(test_data, config_->GetAllAccelerators());
EXPECT_EQ(3, observer_.num_times_accelerator_updated_called());
// Reset one more time, no changes should be made.
result = config_->RestoreDefault(SWITCH_TO_LAST_USED_IME);
EXPECT_EQ(AcceleratorConfigResult::kSuccess, result);
// No changes to be made, but observer should be called.
ExpectAllAcceleratorsEqual(test_data, config_->GetAllAccelerators());
EXPECT_EQ(4, observer_.num_times_accelerator_updated_called());
}
TEST_F(AshAcceleratorConfigurationTest, RestoreInvalidAction) {
EXPECT_EQ(0, observer_.num_times_accelerator_updated_called());
const AcceleratorData test_data[] = {
{/*trigger_on_press=*/true, ui::VKEY_SPACE, ui::EF_CONTROL_DOWN,
SWITCH_TO_LAST_USED_IME},
{/*trigger_on_press=*/true, ui::VKEY_SPACE,
ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN, SWITCH_TO_LAST_USED_IME},
{/*trigger_on_press=*/true, ui::VKEY_TAB, ui::EF_ALT_DOWN,
CYCLE_FORWARD_MRU},
{/*trigger_on_press=*/true, ui::VKEY_TAB,
ui::EF_SHIFT_DOWN | ui::EF_ALT_DOWN, CYCLE_BACKWARD_MRU},
};
config_->Initialize(test_data);
ExpectAllAcceleratorsEqual(test_data, config_->GetAllAccelerators());
EXPECT_EQ(1, observer_.num_times_accelerator_updated_called());
// `BRIGHTNESS_DOWN` is not a valid accelerator, so this should return an
// error.
const AcceleratorConfigResult result =
config_->RestoreDefault(BRIGHTNESS_DOWN);
EXPECT_EQ(AcceleratorConfigResult::kNotFound, result);
// Expect nothing to change.
ExpectAllAcceleratorsEqual(test_data, config_->GetAllAccelerators());
EXPECT_EQ(1, observer_.num_times_accelerator_updated_called());
}
// Add accelerator with no conflict.
TEST_F(AshAcceleratorConfigurationTest, AddAccelerator) {
EXPECT_EQ(0, observer_.num_times_accelerator_updated_called());
const AcceleratorData test_data[] = {
{/*trigger_on_press=*/true, ui::VKEY_SPACE,
ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN, SWITCH_TO_LAST_USED_IME},
{/*trigger_on_press=*/true, ui::VKEY_TAB, ui::EF_ALT_DOWN,
CYCLE_FORWARD_MRU},
{/*trigger_on_press=*/true, ui::VKEY_TAB,
ui::EF_SHIFT_DOWN | ui::EF_ALT_DOWN, CYCLE_BACKWARD_MRU},
};
config_->Initialize(test_data);
ExpectAllAcceleratorsEqual(test_data, config_->GetAllAccelerators());
EXPECT_EQ(1, observer_.num_times_accelerator_updated_called());
// Add CTRL + SPACE to SWITCH_TO_LAST_USED_IME.
const AcceleratorData updated_test_data[] = {
{/*trigger_on_press=*/true, ui::VKEY_SPACE, ui::EF_CONTROL_DOWN,
SWITCH_TO_LAST_USED_IME},
{/*trigger_on_press=*/true, ui::VKEY_SPACE,
ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN, SWITCH_TO_LAST_USED_IME},
{/*trigger_on_press=*/true, ui::VKEY_TAB, ui::EF_ALT_DOWN,
CYCLE_FORWARD_MRU},
{/*trigger_on_press=*/true, ui::VKEY_TAB,
ui::EF_SHIFT_DOWN | ui::EF_ALT_DOWN, CYCLE_BACKWARD_MRU},
};
const ui::Accelerator new_accelerator(ui::VKEY_SPACE, ui::EF_CONTROL_DOWN);
AcceleratorConfigResult result =
config_->AddUserAccelerator(SWITCH_TO_LAST_USED_IME, new_accelerator);
EXPECT_EQ(AcceleratorConfigResult::kSuccess, result);
// Compare expected accelerators and that the observer was fired after
// adding an accelerator.
EXPECT_EQ(2, observer_.num_times_accelerator_updated_called());
ExpectAllAcceleratorsEqual(updated_test_data, config_->GetAllAccelerators());
const AcceleratorAction* found_action =
config_->FindAcceleratorAction(new_accelerator);
EXPECT_TRUE(found_action);
EXPECT_EQ(SWITCH_TO_LAST_USED_IME, *found_action);
}
// Add accelerator that conflict with default accelerator.
TEST_F(AshAcceleratorConfigurationTest, AddAcceleratorDefaultConflict) {
EXPECT_EQ(0, observer_.num_times_accelerator_updated_called());
const AcceleratorData test_data[] = {
{/*trigger_on_press=*/true, ui::VKEY_SPACE,
ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN, SWITCH_TO_LAST_USED_IME},
{/*trigger_on_press=*/true, ui::VKEY_TAB, ui::EF_ALT_DOWN,
CYCLE_FORWARD_MRU},
{/*trigger_on_press=*/true, ui::VKEY_TAB,
ui::EF_SHIFT_DOWN | ui::EF_ALT_DOWN, CYCLE_BACKWARD_MRU},
};
config_->Initialize(test_data);
ExpectAllAcceleratorsEqual(test_data, config_->GetAllAccelerators());
EXPECT_EQ(1, observer_.num_times_accelerator_updated_called());
// Add ALT + SHIFT + TAB to SWITCH_TO_LAST_USED_IME, which conflicts with
// CYCLE_BACKWARD_MRU.
const AcceleratorData updated_test_data[] = {
{/*trigger_on_press=*/true, ui::VKEY_TAB,
ui::EF_SHIFT_DOWN | ui::EF_ALT_DOWN, SWITCH_TO_LAST_USED_IME},
{/*trigger_on_press=*/true, ui::VKEY_SPACE,
ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN, SWITCH_TO_LAST_USED_IME},
{/*trigger_on_press=*/true, ui::VKEY_TAB, ui::EF_ALT_DOWN,
CYCLE_FORWARD_MRU},
};
const ui::Accelerator new_accelerator(ui::VKEY_TAB,
ui::EF_SHIFT_DOWN | ui::EF_ALT_DOWN);
AcceleratorConfigResult result =
config_->AddUserAccelerator(SWITCH_TO_LAST_USED_IME, new_accelerator);
EXPECT_EQ(AcceleratorConfigResult::kSuccess, result);
// Compare expected accelerators and that the observer was fired after
// removing an accelerator.
EXPECT_EQ(2, observer_.num_times_accelerator_updated_called());
ExpectAllAcceleratorsEqual(updated_test_data, config_->GetAllAccelerators());
const AcceleratorAction* found_action =
config_->FindAcceleratorAction(new_accelerator);
EXPECT_TRUE(found_action);
EXPECT_EQ(SWITCH_TO_LAST_USED_IME, *found_action);
// Confirm that conflicting accelerator was removed.
const std::vector<ui::Accelerator>& backward_mru_accelerators =
config_->GetAcceleratorsForAction(CYCLE_BACKWARD_MRU);
EXPECT_TRUE(backward_mru_accelerators.empty());
}
// Add accelerator that conflicts with a deprecated accelerator.
TEST_F(AshAcceleratorConfigurationTest, AddAcceleratorDeprecatedConflict) {
EXPECT_EQ(0, observer_.num_times_accelerator_updated_called());
const AcceleratorData test_data[] = {
{/*trigger_on_press=*/true, ui::VKEY_SPACE,
ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN, SWITCH_TO_LAST_USED_IME},
{/*trigger_on_press=*/true, ui::VKEY_TAB, ui::EF_ALT_DOWN,
CYCLE_FORWARD_MRU},
{/*trigger_on_press=*/true, ui::VKEY_TAB,
ui::EF_SHIFT_DOWN | ui::EF_ALT_DOWN, CYCLE_BACKWARD_MRU},
};
const DeprecatedAcceleratorData deprecated_data[] = {
{SHOW_TASK_MANAGER, /*uma_histogram_name=*/"deprecated.showTaskManager",
/*notification_message_id=*/1, /*old_shortcut_id=*/1,
/*new_shortcut_id=*/2, /*deprecated_enabled=*/true},
};
const AcceleratorData test_deprecated_accelerators[] = {
{/*trigger_on_press=*/true, ui::VKEY_ESCAPE, ui::EF_SHIFT_DOWN,
SHOW_TASK_MANAGER},
};
const AcceleratorData initial_expected_data[] = {
{/*trigger_on_press=*/true, ui::VKEY_SPACE,
ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN, SWITCH_TO_LAST_USED_IME},
{/*trigger_on_press=*/true, ui::VKEY_TAB, ui::EF_ALT_DOWN,
CYCLE_FORWARD_MRU},
{/*trigger_on_press=*/true, ui::VKEY_TAB,
ui::EF_SHIFT_DOWN | ui::EF_ALT_DOWN, CYCLE_BACKWARD_MRU},
{/*trigger_on_press=*/true, ui::VKEY_ESCAPE, ui::EF_SHIFT_DOWN,
SHOW_TASK_MANAGER},
};
config_->Initialize(test_data);
config_->InitializeDeprecatedAccelerators(deprecated_data,
test_deprecated_accelerators);
ExpectAllAcceleratorsEqual(initial_expected_data,
config_->GetAllAccelerators());
// Initializing deprecated accelerators will also trigger the observer.
EXPECT_EQ(2, observer_.num_times_accelerator_updated_called());
const ui::Accelerator deprecated_accelerator(ui::VKEY_ESCAPE,
ui::EF_SHIFT_DOWN);
EXPECT_TRUE(config_->IsDeprecated(deprecated_accelerator));
// Add SHIFT + ESCAPE to SWITCH_TO_LAST_USED_IME, which conflicts with
// a deprecated accelerator.
const AcceleratorData updated_test_data[] = {
{/*trigger_on_press=*/true, ui::VKEY_SPACE,
ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN, SWITCH_TO_LAST_USED_IME},
{/*trigger_on_press=*/true, ui::VKEY_ESCAPE, ui::EF_SHIFT_DOWN,
SWITCH_TO_LAST_USED_IME},
{/*trigger_on_press=*/true, ui::VKEY_TAB, ui::EF_ALT_DOWN,
CYCLE_FORWARD_MRU},
{/*trigger_on_press=*/true, ui::VKEY_TAB,
ui::EF_SHIFT_DOWN | ui::EF_ALT_DOWN, CYCLE_BACKWARD_MRU},
};
AcceleratorConfigResult result = config_->AddUserAccelerator(
SWITCH_TO_LAST_USED_IME, deprecated_accelerator);
EXPECT_EQ(AcceleratorConfigResult::kSuccess, result);
// Compare expected accelerators and that the observer was fired after
// removing an accelerator.
EXPECT_EQ(3, observer_.num_times_accelerator_updated_called());
ExpectAllAcceleratorsEqual(updated_test_data, config_->GetAllAccelerators());
const AcceleratorAction* found_action =
config_->FindAcceleratorAction(deprecated_accelerator);
EXPECT_TRUE(found_action);
EXPECT_EQ(SWITCH_TO_LAST_USED_IME, *found_action);
// Confirm that the deprecated accelerator was removed.
EXPECT_FALSE(config_->IsDeprecated(deprecated_accelerator));
}
// Add and then remove an accelerator.
TEST_F(AshAcceleratorConfigurationTest, AddRemoveAccelerator) {
EXPECT_EQ(0, observer_.num_times_accelerator_updated_called());
const AcceleratorData test_data[] = {
{/*trigger_on_press=*/true, ui::VKEY_SPACE,
ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN, SWITCH_TO_LAST_USED_IME},
{/*trigger_on_press=*/true, ui::VKEY_TAB, ui::EF_ALT_DOWN,
CYCLE_FORWARD_MRU},
{/*trigger_on_press=*/true, ui::VKEY_TAB,
ui::EF_SHIFT_DOWN | ui::EF_ALT_DOWN, CYCLE_BACKWARD_MRU},
};
config_->Initialize(test_data);
ExpectAllAcceleratorsEqual(test_data, config_->GetAllAccelerators());
EXPECT_EQ(1, observer_.num_times_accelerator_updated_called());
// Add CTRL + SPACE to SWITCH_TO_LAST_USED_IME.
const AcceleratorData added_updated_test_data[] = {
{/*trigger_on_press=*/true, ui::VKEY_SPACE, ui::EF_CONTROL_DOWN,
SWITCH_TO_LAST_USED_IME},
{/*trigger_on_press=*/true, ui::VKEY_SPACE,
ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN, SWITCH_TO_LAST_USED_IME},
{/*trigger_on_press=*/true, ui::VKEY_TAB, ui::EF_ALT_DOWN,
CYCLE_FORWARD_MRU},
{/*trigger_on_press=*/true, ui::VKEY_TAB,
ui::EF_SHIFT_DOWN | ui::EF_ALT_DOWN, CYCLE_BACKWARD_MRU},
};
const ui::Accelerator new_accelerator(ui::VKEY_SPACE, ui::EF_CONTROL_DOWN);
AcceleratorConfigResult result =
config_->AddUserAccelerator(SWITCH_TO_LAST_USED_IME, new_accelerator);
EXPECT_EQ(AcceleratorConfigResult::kSuccess, result);
// Compare expected accelerators and that the observer was fired after
// adding an accelerator.
EXPECT_EQ(2, observer_.num_times_accelerator_updated_called());
ExpectAllAcceleratorsEqual(added_updated_test_data,
config_->GetAllAccelerators());
const AcceleratorAction* found_action =
config_->FindAcceleratorAction(new_accelerator);
EXPECT_TRUE(found_action);
EXPECT_EQ(SWITCH_TO_LAST_USED_IME, *found_action);
// Remove CTRL + SPACE from SWITCH_TO_LAST_USED_IME.
const AcceleratorData removed_updated_test_data[] = {
{/*trigger_on_press=*/true, ui::VKEY_SPACE,
ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN, SWITCH_TO_LAST_USED_IME},
{/*trigger_on_press=*/true, ui::VKEY_TAB, ui::EF_ALT_DOWN,
CYCLE_FORWARD_MRU},
{/*trigger_on_press=*/true, ui::VKEY_TAB,
ui::EF_SHIFT_DOWN | ui::EF_ALT_DOWN, CYCLE_BACKWARD_MRU},
};
// Remove the accelerator now.
result = config_->RemoveAccelerator(SWITCH_TO_LAST_USED_IME, new_accelerator);
EXPECT_EQ(AcceleratorConfigResult::kSuccess, result);
EXPECT_EQ(3, observer_.num_times_accelerator_updated_called());
ExpectAllAcceleratorsEqual(removed_updated_test_data,
config_->GetAllAccelerators());
EXPECT_FALSE(config_->FindAcceleratorAction(new_accelerator));
}
// Add accelerator and restore its default.
TEST_F(AshAcceleratorConfigurationTest, AddRestoreAccelerator) {
EXPECT_EQ(0, observer_.num_times_accelerator_updated_called());
const AcceleratorData test_data[] = {
{/*trigger_on_press=*/true, ui::VKEY_SPACE,
ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN, SWITCH_TO_LAST_USED_IME},
{/*trigger_on_press=*/true, ui::VKEY_TAB, ui::EF_ALT_DOWN,
CYCLE_FORWARD_MRU},
{/*trigger_on_press=*/true, ui::VKEY_TAB,
ui::EF_SHIFT_DOWN | ui::EF_ALT_DOWN, CYCLE_BACKWARD_MRU},
};
config_->Initialize(test_data);
ExpectAllAcceleratorsEqual(test_data, config_->GetAllAccelerators());
EXPECT_EQ(1, observer_.num_times_accelerator_updated_called());
// Add CTRL + SPACE to SWITCH_TO_LAST_USED_IME.
const AcceleratorData updated_test_data[] = {
{/*trigger_on_press=*/true, ui::VKEY_SPACE, ui::EF_CONTROL_DOWN,
SWITCH_TO_LAST_USED_IME},
{/*trigger_on_press=*/true, ui::VKEY_SPACE,
ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN, SWITCH_TO_LAST_USED_IME},
{/*trigger_on_press=*/true, ui::VKEY_TAB, ui::EF_ALT_DOWN,
CYCLE_FORWARD_MRU},
{/*trigger_on_press=*/true, ui::VKEY_TAB,
ui::EF_SHIFT_DOWN | ui::EF_ALT_DOWN, CYCLE_BACKWARD_MRU},
};
const ui::Accelerator new_accelerator(ui::VKEY_SPACE, ui::EF_CONTROL_DOWN);
AcceleratorConfigResult result =
config_->AddUserAccelerator(SWITCH_TO_LAST_USED_IME, new_accelerator);
EXPECT_EQ(AcceleratorConfigResult::kSuccess, result);
// Compare expected accelerators and that the observer was fired after
// adding an accelerator.
EXPECT_EQ(2, observer_.num_times_accelerator_updated_called());
ExpectAllAcceleratorsEqual(updated_test_data, config_->GetAllAccelerators());
const AcceleratorAction* found_action =
config_->FindAcceleratorAction(new_accelerator);
EXPECT_TRUE(found_action);
EXPECT_EQ(SWITCH_TO_LAST_USED_IME, *found_action);
// Restore default, expect to be back to default state.
result = config_->RestoreDefault(SWITCH_TO_LAST_USED_IME);
EXPECT_EQ(3, observer_.num_times_accelerator_updated_called());
EXPECT_EQ(AcceleratorConfigResult::kSuccess, result);
EXPECT_FALSE(config_->FindAcceleratorAction(new_accelerator));
ExpectAllAcceleratorsEqual(test_data, config_->GetAllAccelerators());
}
// Add an accelerator, then add the same accelerator to another action.
TEST_F(AshAcceleratorConfigurationTest, ReAddAcceleratorToAnotherAction) {
EXPECT_EQ(0, observer_.num_times_accelerator_updated_called());
const AcceleratorData test_data[] = {
{/*trigger_on_press=*/true, ui::VKEY_SPACE,
ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN, SWITCH_TO_LAST_USED_IME},
{/*trigger_on_press=*/true, ui::VKEY_TAB, ui::EF_ALT_DOWN,
CYCLE_FORWARD_MRU},
{/*trigger_on_press=*/true, ui::VKEY_TAB,
ui::EF_SHIFT_DOWN | ui::EF_ALT_DOWN, CYCLE_BACKWARD_MRU},
};
config_->Initialize(test_data);
ExpectAllAcceleratorsEqual(test_data, config_->GetAllAccelerators());
EXPECT_EQ(1, observer_.num_times_accelerator_updated_called());
// Add CTRL + SPACE to SWITCH_TO_LAST_USED_IME.
const AcceleratorData updated_test_data[] = {
{/*trigger_on_press=*/true, ui::VKEY_SPACE, ui::EF_CONTROL_DOWN,
SWITCH_TO_LAST_USED_IME},
{/*trigger_on_press=*/true, ui::VKEY_SPACE,
ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN, SWITCH_TO_LAST_USED_IME},
{/*trigger_on_press=*/true, ui::VKEY_TAB, ui::EF_ALT_DOWN,
CYCLE_FORWARD_MRU},
{/*trigger_on_press=*/true, ui::VKEY_TAB,
ui::EF_SHIFT_DOWN | ui::EF_ALT_DOWN, CYCLE_BACKWARD_MRU},
};
const ui::Accelerator new_accelerator(ui::VKEY_SPACE, ui::EF_CONTROL_DOWN);
AcceleratorConfigResult result =
config_->AddUserAccelerator(SWITCH_TO_LAST_USED_IME, new_accelerator);
EXPECT_EQ(AcceleratorConfigResult::kSuccess, result);
// Compare expected accelerators and that the observer was fired after
// adding an accelerator.
EXPECT_EQ(2, observer_.num_times_accelerator_updated_called());
ExpectAllAcceleratorsEqual(updated_test_data, config_->GetAllAccelerators());
const AcceleratorAction* found_action =
config_->FindAcceleratorAction(new_accelerator);
EXPECT_TRUE(found_action);
EXPECT_EQ(SWITCH_TO_LAST_USED_IME, *found_action);
// Add CTRL + SPACE to CYCLE_BACKWARD_MRU.
const AcceleratorData reupdated_test_data[] = {
{/*trigger_on_press=*/true, ui::VKEY_SPACE,
ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN, SWITCH_TO_LAST_USED_IME},
{/*trigger_on_press=*/true, ui::VKEY_TAB, ui::EF_ALT_DOWN,
CYCLE_FORWARD_MRU},
{/*trigger_on_press=*/true, ui::VKEY_TAB,
ui::EF_SHIFT_DOWN | ui::EF_ALT_DOWN, CYCLE_BACKWARD_MRU},
{/*trigger_on_press=*/true, ui::VKEY_SPACE, ui::EF_CONTROL_DOWN,
CYCLE_BACKWARD_MRU},
};
result = config_->AddUserAccelerator(CYCLE_BACKWARD_MRU, new_accelerator);
EXPECT_EQ(AcceleratorConfigResult::kSuccess, result);
ExpectAllAcceleratorsEqual(reupdated_test_data,
config_->GetAllAccelerators());
const AcceleratorAction* found_action2 =
config_->FindAcceleratorAction(new_accelerator);
EXPECT_TRUE(found_action2);
EXPECT_EQ(CYCLE_BACKWARD_MRU, *found_action2);
}
} // namespace ash