| // 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/webui/common/backend/shortcut_input_provider.h" |
| |
| #include <memory> |
| |
| #include "ash/accelerators/accelerator_controller_impl.h" |
| #include "ash/constants/ash_features.h" |
| #include "ash/public/cpp/accelerators.h" |
| #include "ash/public/mojom/input_device_settings.mojom.h" |
| #include "ash/shell.h" |
| #include "ash/test/ash_test_base.h" |
| #include "ash/webui/common/mojom/shortcut_input_provider.mojom.h" |
| #include "base/test/scoped_feature_list.h" |
| #include "chromeos/ash/components/test/ash_test_suite.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "ui/base/resource/resource_bundle.h" |
| #include "ui/events/event.h" |
| #include "ui/events/event_constants.h" |
| #include "ui/events/keycodes/keyboard_codes_posix.h" |
| #include "ui/events/types/event_type.h" |
| #include "ui/views/widget/widget.h" |
| |
| namespace ash { |
| |
| namespace { |
| |
| class FakeShortcutInputObserver : public common::mojom::ShortcutInputObserver { |
| public: |
| void OnShortcutInputEventPressed(ash::mojom::KeyEventPtr key_event) override { |
| ++num_input_events_pressed_; |
| } |
| void OnShortcutInputEventReleased( |
| ash::mojom::KeyEventPtr key_event) override { |
| ++num_input_events_released_; |
| } |
| |
| int num_input_events_pressed() { return num_input_events_pressed_; } |
| int num_input_events_released() { return num_input_events_released_; } |
| |
| mojo::Receiver<common::mojom::ShortcutInputObserver> receiver{this}; |
| |
| private: |
| int num_input_events_pressed_ = 0; |
| int num_input_events_released_ = 0; |
| }; |
| |
| ui::KeyEvent CreateKeyEvent(bool pressed) { |
| return ui::KeyEvent(pressed ? ui::ET_KEY_PRESSED : ui::ET_KEY_RELEASED, |
| ui::VKEY_A, ui::EF_NONE); |
| } |
| |
| } // namespace |
| |
| class ShortcutInputProviderTest : public AshTestBase { |
| public: |
| ShortcutInputProviderTest() { |
| scoped_feature_list_.InitWithFeatures({features::kPeripheralCustomization, |
| features::kInputDeviceSettingsSplit}, |
| {}); |
| } |
| |
| void SetUp() override { |
| ui::ResourceBundle::CleanupSharedInstance(); |
| AshTestSuite::LoadTestResources(); |
| AshTestBase::SetUp(); |
| |
| shortcut_input_handler_ = Shell::Get()->shortcut_input_handler(); |
| shortcut_input_provider_ = std::make_unique<ShortcutInputProvider>(); |
| observer_ = std::make_unique<FakeShortcutInputObserver>(); |
| shortcut_input_provider_->StartObservingShortcutInput( |
| observer_->receiver.BindNewPipeAndPassRemote()); |
| |
| widget_ = CreateTestWidget(); |
| widget_->Show(); |
| widget_->Activate(); |
| } |
| |
| void TearDown() override { |
| shortcut_input_provider_.reset(); |
| shortcut_input_handler_ = nullptr; |
| AshTestBase::TearDown(); |
| } |
| |
| protected: |
| std::unique_ptr<ShortcutInputProvider> shortcut_input_provider_ = nullptr; |
| raw_ptr<ShortcutInputHandler> shortcut_input_handler_; |
| std::unique_ptr<FakeShortcutInputObserver> observer_; |
| std::unique_ptr<views::Widget> widget_; |
| base::test::ScopedFeatureList scoped_feature_list_; |
| }; |
| |
| TEST_F(ShortcutInputProviderTest, NoWidget) { |
| ui::KeyEvent pressed_event = CreateKeyEvent(/*pressed=*/true); |
| ui::KeyEvent released_event = CreateKeyEvent(/*pressed=*/false); |
| shortcut_input_handler_->OnKeyEvent(&pressed_event); |
| shortcut_input_handler_->OnKeyEvent(&released_event); |
| shortcut_input_provider_->FlushMojoForTesting(); |
| |
| EXPECT_EQ(0, observer_->num_input_events_pressed()); |
| EXPECT_EQ(0, observer_->num_input_events_released()); |
| EXPECT_FALSE(Shell::Get() |
| ->accelerator_controller() |
| ->ShouldPreventProcessingAccelerators()); |
| } |
| |
| TEST_F(ShortcutInputProviderTest, SimpleEvent) { |
| ui::KeyEvent pressed_event = CreateKeyEvent(/*pressed=*/true); |
| ui::KeyEvent released_event = CreateKeyEvent(/*pressed=*/false); |
| shortcut_input_provider_->TieProviderToWidget(widget_.get()); |
| |
| shortcut_input_handler_->OnKeyEvent(&pressed_event); |
| shortcut_input_handler_->OnKeyEvent(&released_event); |
| shortcut_input_provider_->FlushMojoForTesting(); |
| |
| EXPECT_EQ(1, observer_->num_input_events_pressed()); |
| EXPECT_EQ(1, observer_->num_input_events_released()); |
| EXPECT_TRUE(Shell::Get() |
| ->accelerator_controller() |
| ->ShouldPreventProcessingAccelerators()); |
| } |
| |
| TEST_F(ShortcutInputProviderTest, SimpleEventNoFocus) { |
| ui::KeyEvent pressed_event = CreateKeyEvent(/*pressed=*/true); |
| ui::KeyEvent released_event = CreateKeyEvent(/*pressed=*/false); |
| shortcut_input_provider_->TieProviderToWidget(widget_.get()); |
| |
| widget_->Hide(); |
| |
| shortcut_input_handler_->OnKeyEvent(&pressed_event); |
| shortcut_input_handler_->OnKeyEvent(&released_event); |
| shortcut_input_provider_->FlushMojoForTesting(); |
| |
| EXPECT_EQ(0, observer_->num_input_events_pressed()); |
| EXPECT_EQ(0, observer_->num_input_events_released()); |
| EXPECT_FALSE(Shell::Get() |
| ->accelerator_controller() |
| ->ShouldPreventProcessingAccelerators()); |
| |
| widget_->Show(); |
| |
| shortcut_input_handler_->OnKeyEvent(&pressed_event); |
| shortcut_input_handler_->OnKeyEvent(&released_event); |
| shortcut_input_provider_->FlushMojoForTesting(); |
| |
| EXPECT_EQ(1, observer_->num_input_events_pressed()); |
| EXPECT_EQ(1, observer_->num_input_events_released()); |
| EXPECT_TRUE(Shell::Get() |
| ->accelerator_controller() |
| ->ShouldPreventProcessingAccelerators()); |
| } |
| |
| TEST_F(ShortcutInputProviderTest, StopObservingTest) { |
| ui::KeyEvent pressed_event = CreateKeyEvent(/*pressed=*/true); |
| ui::KeyEvent released_event = CreateKeyEvent(/*pressed=*/false); |
| shortcut_input_provider_->TieProviderToWidget(widget_.get()); |
| |
| shortcut_input_handler_->OnKeyEvent(&pressed_event); |
| shortcut_input_handler_->OnKeyEvent(&released_event); |
| shortcut_input_provider_->FlushMojoForTesting(); |
| |
| EXPECT_EQ(1, observer_->num_input_events_pressed()); |
| EXPECT_EQ(1, observer_->num_input_events_released()); |
| EXPECT_TRUE(Shell::Get() |
| ->accelerator_controller() |
| ->ShouldPreventProcessingAccelerators()); |
| |
| shortcut_input_provider_->StopObservingShortcutInput(); |
| shortcut_input_handler_->OnKeyEvent(&pressed_event); |
| shortcut_input_handler_->OnKeyEvent(&released_event); |
| shortcut_input_provider_->FlushMojoForTesting(); |
| |
| EXPECT_EQ(1, observer_->num_input_events_pressed()); |
| EXPECT_EQ(1, observer_->num_input_events_released()); |
| EXPECT_FALSE(Shell::Get() |
| ->accelerator_controller() |
| ->ShouldPreventProcessingAccelerators()); |
| } |
| |
| TEST_F(ShortcutInputProviderTest, WidgetDestroyedTest) { |
| ui::KeyEvent pressed_event = CreateKeyEvent(/*pressed=*/true); |
| ui::KeyEvent released_event = CreateKeyEvent(/*pressed=*/false); |
| shortcut_input_provider_->TieProviderToWidget(widget_.get()); |
| |
| shortcut_input_handler_->OnKeyEvent(&pressed_event); |
| shortcut_input_handler_->OnKeyEvent(&released_event); |
| shortcut_input_provider_->FlushMojoForTesting(); |
| |
| EXPECT_EQ(1, observer_->num_input_events_pressed()); |
| EXPECT_EQ(1, observer_->num_input_events_released()); |
| |
| // Destroy the widget, key events should not be communicated over mojo. |
| widget_.reset(); |
| shortcut_input_handler_->OnKeyEvent(&pressed_event); |
| shortcut_input_handler_->OnKeyEvent(&released_event); |
| shortcut_input_provider_->FlushMojoForTesting(); |
| |
| EXPECT_EQ(1, observer_->num_input_events_pressed()); |
| EXPECT_EQ(1, observer_->num_input_events_released()); |
| } |
| |
| } // namespace ash |