blob: 666e4f3afa24e2c63a848583dfb7403b898a2f60 [file] [log] [blame]
// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/ui/views/accelerator_table.h"
#include <stddef.h>
#include "base/containers/contains.h"
#include "base/containers/flat_set.h"
#include "base/containers/span.h"
#include "build/build_config.h"
#include "chrome/app/chrome_command_ids.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/events/event_constants.h"
#if BUILDFLAG(IS_CHROMEOS)
#include "ash/accelerators/accelerator_table.h"
#include "ash/public/cpp/accelerators.h"
#endif
namespace chrome {
namespace {
struct Cmp {
bool operator()(const AcceleratorMapping& lhs,
const AcceleratorMapping& rhs) const {
if (lhs.keycode != rhs.keycode) {
return lhs.keycode < rhs.keycode;
}
return lhs.modifiers < rhs.modifiers;
// Do not check |command_id|.
}
};
} // namespace
TEST(AcceleratorTableTest, CheckDuplicatedAccelerators) {
base::flat_set<AcceleratorMapping, Cmp> accelerators;
for (const auto& entry : GetAcceleratorList()) {
EXPECT_TRUE(accelerators.insert(entry).second)
<< "Duplicated accelerator: " << entry.keycode << ", "
<< (entry.modifiers & ui::EF_SHIFT_DOWN) << ", "
<< (entry.modifiers & ui::EF_CONTROL_DOWN) << ", "
<< (entry.modifiers & ui::EF_ALT_DOWN) << ", "
<< (entry.modifiers & ui::EF_ALTGR_DOWN);
}
}
TEST(AcceleratorTableTest, PrintKeySupport) {
int command_id = -1;
for (const auto& entry : GetAcceleratorList()) {
if (entry.keycode == ui::VKEY_PRINT) {
command_id = entry.command_id;
}
}
// KEY_PRINT->DomCode::PRINT->VKEY_PRINT are only mapped to IDC_PRINT on
// Chrome OS. On Linux KEY_PRINT is treated as print screen which isn't
// handled by the browser.
#if BUILDFLAG(IS_CHROMEOS)
EXPECT_EQ(IDC_PRINT, command_id);
#else // !BUILDFLAG(IS_CHROMEOS)
EXPECT_EQ(-1, command_id);
#endif // BUILDFLAG(IS_CHROMEOS)
}
TEST(AcceleratorTableTest, OpenFeedbackWithSearchBasedAccelerator) {
int command_id = -1;
for (const auto& entry : GetAcceleratorList()) {
if (entry.keycode == ui::VKEY_I &&
entry.modifiers == (ui::EF_CONTROL_DOWN | ui::EF_COMMAND_DOWN)) {
command_id = entry.command_id;
}
}
#if BUILDFLAG(IS_CHROMEOS) && BUILDFLAG(GOOGLE_CHROME_BRANDING)
EXPECT_EQ(IDC_FEEDBACK, command_id);
#else // !BUILDFLAG(IS_CHROMEOS) || !BUILDFLAG(GOOGLE_CHROME_BRANDING)
EXPECT_EQ(-1, command_id);
#endif // BUILDFLAG(IS_CHROMEOS) && BUILDFLAG(GOOGLE_CHROME_BRANDING)
}
#if BUILDFLAG(IS_CHROMEOS)
TEST(AcceleratorTableTest, CheckDuplicatedAcceleratorsAsh) {
base::flat_set<AcceleratorMapping, Cmp> accelerators(GetAcceleratorList());
for (const ash::AcceleratorData& ash_entry : ash::kAcceleratorData) {
if (!ash_entry.trigger_on_press) {
continue; // kAcceleratorMap does not have any release accelerators.
}
// A few shortcuts are defined in the browser as well as in ash so that web
// contents can consume them. http://crbug.com/309915, 370019, 412435,
// 321568.
if (base::Contains(ash::kActionsInterceptableByBrowser, ash_entry.action)) {
continue;
}
// The following actions are duplicated in both ash and browser accelerator
// list to ensure BrowserView can retrieve browser command id from the
// accelerator without needing to know ash.
// See http://crbug.com/737307 for details.
if (base::Contains(ash::kActionsDuplicatedWithBrowser, ash_entry.action)) {
AcceleratorMapping entry;
entry.keycode = ash_entry.keycode;
entry.modifiers = ash_entry.modifiers;
entry.command_id = 0; // dummy
// These accelerators should use the same shortcuts in browser accelerator
// table and ash accelerator table.
EXPECT_FALSE(accelerators.insert(entry).second)
<< "Action " << ash_entry.action;
continue;
}
AcceleratorMapping entry;
entry.keycode = ash_entry.keycode;
entry.modifiers = ash_entry.modifiers;
entry.command_id = 0; // dummy
EXPECT_TRUE(accelerators.insert(entry).second)
<< "Duplicated accelerator: " << entry.keycode << ", "
<< (entry.modifiers & ui::EF_SHIFT_DOWN) << ", "
<< (entry.modifiers & ui::EF_CONTROL_DOWN) << ", "
<< (entry.modifiers & ui::EF_ALT_DOWN) << ", "
<< (entry.modifiers & ui::EF_ALTGR_DOWN) << ", action "
<< (ash_entry.action);
}
}
TEST(AcceleratorTableTest, DontUseKeysWithUnstablePositions) {
// Some punctuation keys are problematic on international keyboard
// layouts and should not be used as shortcuts. Two existing shortcuts
// do use these keys and are excluded (Page Zoom In/Out), and help also
// uses this key, however it is overridden on Chrome OS in ash.
// See crbug.com/1174326 for more information.
for (const auto& entry : GetAcceleratorList()) {
if (entry.command_id == IDC_ZOOM_MINUS ||
entry.command_id == IDC_ZOOM_PLUS ||
entry.command_id == IDC_HELP_PAGE_VIA_KEYBOARD) {
continue;
}
switch (entry.keycode) {
case ui::VKEY_OEM_PLUS:
case ui::VKEY_OEM_MINUS:
case ui::VKEY_OEM_1:
case ui::VKEY_OEM_2:
case ui::VKEY_OEM_3:
case ui::VKEY_OEM_4:
case ui::VKEY_OEM_5:
case ui::VKEY_OEM_6:
case ui::VKEY_OEM_7:
case ui::VKEY_OEM_8:
case ui::VKEY_OEM_COMMA:
case ui::VKEY_OEM_PERIOD:
FAIL() << "Accelerator command " << entry.command_id
<< " is using a disallowed punctuation key " << entry.keycode
<< ". Prefer to use alphanumeric keys for new shortcuts.";
default:
break;
}
}
}
#else
// A test fixture for testing GetAcceleratorList().
class GetAcceleratorListTest : public ::testing::Test {
protected:
void SetUp() override {
// Make sure that previous tests don't affect this test.
ClearAcceleratorListForTesting();
}
void TearDown() override {
// Make sure that this test doesn't affect following tests.
ClearAcceleratorListForTesting();
}
};
// Verify that the shortcuts for DevTools are enabled.
TEST_F(GetAcceleratorListTest, DevToolsAreEnabled) {
// Verify there is a mapping that is associated to IDC_DEV_TOOLS_TOGGLE.
std::vector<AcceleratorMapping> list = GetAcceleratorList();
auto iter = std::find_if(list.begin(), list.end(), [](auto mapping) {
return mapping.command_id == IDC_DEV_TOOLS_TOGGLE;
});
EXPECT_NE(iter, list.end());
}
#endif // BUILDFLAG(IS_CHROMEOS)
} // namespace chrome