blob: 827f8a00598a9fbebb2cbad3f00f3e7f00023883 [file] [log] [blame]
// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <fidl/fuchsia.input.virtualkeyboard/cpp/wire_messaging.h>
#include <fidl/fuchsia.ui.input3/cpp/fidl.h>
#include <lib/async/default.h>
#include <memory>
#include <string_view>
#include "base/fuchsia/scoped_service_binding.h"
#include "base/fuchsia/test_component_context_for_process.h"
#include "base/strings/string_number_conversions.h"
#include "base/test/scoped_feature_list.h"
#include "content/public/test/browser_test.h"
#include "content/public/test/browser_test_utils.h"
#include "fuchsia_web/common/test/frame_for_test.h"
#include "fuchsia_web/common/test/frame_test_util.h"
#include "fuchsia_web/common/test/test_navigation_listener.h"
#include "fuchsia_web/webengine/browser/context_impl.h"
#include "fuchsia_web/webengine/features.h"
#include "fuchsia_web/webengine/test/scenic_test_helper.h"
#include "fuchsia_web/webengine/test/scoped_connection_checker.h"
#include "fuchsia_web/webengine/test/test_data.h"
#include "fuchsia_web/webengine/test/web_engine_browser_test.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/ozone/public/ozone_platform.h"
using fuchsia_input::Key;
using fuchsia_ui_input3::KeyEvent;
using fuchsia_ui_input3::KeyEventType;
namespace {
const char kKeyDown[] = "keydown";
const char kKeyPress[] = "keypress";
const char kKeyUp[] = "keyup";
const char kKeyDicts[] = "keyDicts";
// Returns a KeyEvent with |key_meaning| set based on the supplied codepoint,
// the |key| field left not set.
KeyEvent CreateCharacterKeyEvent(uint32_t codepoint, KeyEventType event_type) {
return {{
.timestamp = base::TimeTicks::Now().ToZxTime(),
.type = event_type,
.key_meaning = fuchsia_ui_input3::KeyMeaning::WithCodepoint(codepoint),
}};
}
struct KeyEventOptions {
bool repeat;
std::vector<fuchsia_ui_input3::Modifiers> modifiers;
};
// Returns a KeyEvent with both |key| and |key_meaning| set.
KeyEvent CreateKeyEvent(Key key,
fuchsia_ui_input3::KeyMeaning key_meaning,
KeyEventType event_type,
KeyEventOptions options = {}) {
KeyEvent key_event{{
.timestamp = base::TimeTicks::Now().ToZxTime(),
.type = event_type,
.key = key,
.key_meaning = std::move(key_meaning),
}};
if (options.repeat) {
// Chromium doesn't look at the value of this, it just check if the field is
// present.
key_event.repeat_sequence(1);
}
if (!options.modifiers.empty()) {
fuchsia_ui_input3::Modifiers modifiers;
for (const auto modifier : options.modifiers) {
modifiers |= modifier;
}
key_event.modifiers(modifiers);
}
return key_event;
}
KeyEvent CreateKeyEvent(Key key,
uint32_t codepoint,
KeyEventType event_type,
KeyEventOptions options = {}) {
return CreateKeyEvent(
key, fuchsia_ui_input3::KeyMeaning::WithCodepoint(std::move(codepoint)),
event_type, options);
}
KeyEvent CreateKeyEvent(Key key,
fuchsia_ui_input3::NonPrintableKey non_printable_key,
KeyEventType event_type,
KeyEventOptions options = {}) {
return CreateKeyEvent(key,
fuchsia_ui_input3::KeyMeaning::WithNonPrintableKey(
std::move(non_printable_key)),
event_type, options);
}
base::Value::List FuchsiaModifiersToWebModifiers(
const std::vector<fuchsia_ui_input3::Modifiers> fuchsia_modifiers) {
base::Value::List web_modifiers;
for (const auto modifier : fuchsia_modifiers) {
if (modifier == fuchsia_ui_input3::Modifiers::kAlt) {
web_modifiers.Append("Alt");
} else if (modifier == fuchsia_ui_input3::Modifiers::kAltGraph) {
web_modifiers.Append("AltGraph");
} else if (modifier == fuchsia_ui_input3::Modifiers::kCapsLock) {
web_modifiers.Append("CapsLock");
} else if (modifier == fuchsia_ui_input3::Modifiers::kCtrl) {
web_modifiers.Append("Control");
} else if (modifier == fuchsia_ui_input3::Modifiers::kMeta) {
web_modifiers.Append("Meta");
} else if (modifier == fuchsia_ui_input3::Modifiers::kNumLock) {
web_modifiers.Append("NumLock");
} else if (modifier == fuchsia_ui_input3::Modifiers::kScrollLock) {
web_modifiers.Append("ScrollLock");
} else if (modifier == fuchsia_ui_input3::Modifiers::kShift) {
web_modifiers.Append("Shift");
} else {
NOTREACHED() << static_cast<uint64_t>(modifier) << " has no web mapping";
}
}
return web_modifiers;
}
base::Value ExpectedKeyValue(std::string_view code,
std::string_view key,
std::string_view type,
KeyEventOptions options = {}) {
base::Value::Dict expected;
expected.Set("code", code);
expected.Set("key", key);
expected.Set("type", type);
expected.Set("repeat", options.repeat);
expected.Set("modifiers", FuchsiaModifiersToWebModifiers(options.modifiers));
return base::Value(std::move(expected));
}
class FakeKeyboard : public fidl::Server<fuchsia_ui_input3::Keyboard> {
public:
explicit FakeKeyboard(sys::OutgoingDirectory* additional_services)
: binding_(additional_services, this) {}
~FakeKeyboard() override = default;
FakeKeyboard(const FakeKeyboard&) = delete;
FakeKeyboard& operator=(const FakeKeyboard&) = delete;
base::ScopedNaturalServiceBinding<fuchsia_ui_input3::Keyboard>* binding() {
return &binding_;
}
// Sends |key_event| to |listener_|;
void SendKeyEvent(KeyEvent key_event) {
listener_->OnKeyEvent(std::move(key_event))
.Then([num_sent_events = num_sent_events_,
this](const fidl::Result<
fuchsia_ui_input3::KeyboardListener::OnKeyEvent>& result) {
ASSERT_EQ(num_acked_events_, num_sent_events)
<< "Key events are acked out of order";
num_acked_events_++;
});
num_sent_events_++;
}
// fuchsia_ui_input3::Keyboard implementation.
void AddListener(AddListenerRequest& request,
AddListenerCompleter::Sync& completer) final {
// This implementation is only set up to have up to one listener.
EXPECT_FALSE(listener_);
listener_.Bind(std::move(request.listener()),
async_get_default_dispatcher());
completer.Reply();
}
private:
fidl::Client<fuchsia_ui_input3::KeyboardListener> listener_;
base::ScopedNaturalServiceBinding<fuchsia_ui_input3::Keyboard> binding_;
// Counters to make sure key events are acked in order.
int num_sent_events_ = 0;
int num_acked_events_ = 0;
};
class KeyboardInputTest : public WebEngineBrowserTest {
public:
KeyboardInputTest() { set_test_server_root(base::FilePath(kTestServerRoot)); }
~KeyboardInputTest() override = default;
KeyboardInputTest(const KeyboardInputTest&) = delete;
KeyboardInputTest& operator=(const KeyboardInputTest&) = delete;
protected:
virtual void SetUpService() {
keyboard_service_.emplace(component_context_->additional_services());
}
void SetUp() override {
if (ui::OzonePlatform::GetPlatformNameForTest() == "headless") {
GTEST_SKIP() << "Keyboard inputs are ignored in headless mode.";
}
scoped_feature_list_.InitWithFeatures({features::kKeyboardInput}, {});
WebEngineBrowserTest::SetUp();
}
void SetUpOnMainThread() override {
WebEngineBrowserTest::SetUpOnMainThread();
ASSERT_TRUE(embedded_test_server()->Start());
fuchsia::web::CreateFrameParams params;
frame_for_test_ = FrameForTest::Create(context(), std::move(params));
// Set up services needed for the test. The keyboard service is included in
// the allowed services by default. The real service needs to be removed so
// it can be replaced by this fake implementation.
component_context_.emplace(
base::TestComponentContextForProcess::InitialState::kCloneAll);
component_context_->additional_services()
->RemovePublicService<fuchsia_ui_input3::Keyboard>(
fidl::DiscoverableProtocolName<fuchsia_ui_input3::Keyboard>);
SetUpService();
virtual_keyboard_checker_.emplace(
component_context_->additional_services());
fuchsia::web::NavigationControllerPtr controller;
frame_for_test_.ptr()->GetNavigationController(controller.NewRequest());
const GURL test_url(embedded_test_server()->GetURL("/keyevents.html"));
EXPECT_TRUE(LoadUrlAndExpectResponse(
controller.get(), fuchsia::web::LoadUrlParams(), test_url.spec()));
frame_for_test_.navigation_listener().RunUntilUrlEquals(test_url);
fuchsia::web::FramePtr* frame_ptr = &(frame_for_test_.ptr());
scenic_test_helper_.CreateScenicView(
context_impl()->GetFrameImplForTest(frame_ptr), frame_for_test_.ptr());
scenic_test_helper_.SetUpViewForInteraction(
context_impl()->GetFrameImplForTest(frame_ptr)->web_contents());
}
void TearDownOnMainThread() override {
frame_for_test_ = {};
WebEngineBrowserTest::TearDownOnMainThread();
}
// The tests expect to have input processed immediately, even if the
// content has not been displayed yet. That's fine for the test, but
// we need to explicitly allow it.
void SetUpCommandLine(base::CommandLine* command_line) override {
command_line->AppendSwitch("allow-pre-commit-input");
}
void ExpectKeyEventsEqual(base::Value::List expected) {
frame_for_test_.navigation_listener().RunUntilTitleEquals(
base::NumberToString(expected.size()));
std::optional<base::Value> actual =
ExecuteJavaScript(frame_for_test_.ptr().get(), kKeyDicts);
EXPECT_EQ(*actual, base::Value(std::move(expected)));
}
template <typename... Args>
void ExpectKeyEventsEqual(Args... events) {
base::Value::List expected =
content::ListValueOf(std::forward<Args>(events)...).TakeList();
ExpectKeyEventsEqual(std::move(expected));
}
// Used to publish fake services.
std::optional<base::TestComponentContextForProcess> component_context_;
FrameForTest frame_for_test_;
ScenicTestHelper scenic_test_helper_;
std::optional<FakeKeyboard> keyboard_service_;
base::test::ScopedFeatureList scoped_feature_list_;
std::optional<
NeverConnectedChecker<fuchsia_input_virtualkeyboard::ControllerCreator>>
virtual_keyboard_checker_;
};
// Check that printable keys are sent and received correctly.
IN_PROC_BROWSER_TEST_F(KeyboardInputTest, PrintableKeys) {
// Send key press events from the Fuchsia keyboard service.
// Pressing character keys will generate a JavaScript keydown event followed
// by a keypress event. Releasing any key generates a keyup event.
keyboard_service_->SendKeyEvent(
CreateKeyEvent(Key::kA, 'a', KeyEventType::kPressed));
keyboard_service_->SendKeyEvent(
CreateKeyEvent(Key::kKey8, '8', KeyEventType::kPressed));
keyboard_service_->SendKeyEvent(
CreateKeyEvent(Key::kKey8, '8', KeyEventType::kReleased));
keyboard_service_->SendKeyEvent(
CreateKeyEvent(Key::kA, 'a', KeyEventType::kReleased));
ExpectKeyEventsEqual(ExpectedKeyValue("KeyA", "a", kKeyDown),
ExpectedKeyValue("KeyA", "a", kKeyPress),
ExpectedKeyValue("Digit8", "8", kKeyDown),
ExpectedKeyValue("Digit8", "8", kKeyPress),
ExpectedKeyValue("Digit8", "8", kKeyUp),
ExpectedKeyValue("KeyA", "a", kKeyUp));
}
// Check that character virtual keys are sent and received correctly.
IN_PROC_BROWSER_TEST_F(KeyboardInputTest, Characters) {
// Send key press events from the Fuchsia keyboard service.
// Pressing character keys will generate a JavaScript keydown event followed
// by a keypress event. Releasing any key generates a keyup event.
keyboard_service_->SendKeyEvent(
CreateCharacterKeyEvent('A', KeyEventType::kPressed));
keyboard_service_->SendKeyEvent(
CreateCharacterKeyEvent('A', KeyEventType::kReleased));
keyboard_service_->SendKeyEvent(
CreateCharacterKeyEvent('b', KeyEventType::kPressed));
ExpectKeyEventsEqual(
ExpectedKeyValue("", "A", kKeyDown), ExpectedKeyValue("", "A", kKeyPress),
ExpectedKeyValue("", "A", kKeyUp), ExpectedKeyValue("", "b", kKeyDown),
ExpectedKeyValue("", "b", kKeyPress));
}
// Verify that character events are not affected by active modifiers.
IN_PROC_BROWSER_TEST_F(KeyboardInputTest, ShiftCharacter) {
// TODO(fxbug.dev/106600): Update the WithCodepoint(0)s when the platform is
// fixed to provide valid KeyMeanings for these keys.
keyboard_service_->SendKeyEvent(
CreateKeyEvent(Key::kLeftShift, 0, KeyEventType::kPressed));
keyboard_service_->SendKeyEvent(
CreateCharacterKeyEvent('a', KeyEventType::kPressed));
keyboard_service_->SendKeyEvent(
CreateCharacterKeyEvent('a', KeyEventType::kReleased));
keyboard_service_->SendKeyEvent(
CreateKeyEvent(Key::kLeftShift, 0, KeyEventType::kReleased));
ExpectKeyEventsEqual(
ExpectedKeyValue("ShiftLeft", "Shift", kKeyDown),
ExpectedKeyValue("", "a", kKeyDown), // Remains lowercase.
ExpectedKeyValue("", "a", kKeyPress), // You guessed it! Still lowercase.
ExpectedKeyValue("", "a", kKeyUp), // Wow, lowercase just won't quit.
ExpectedKeyValue("ShiftLeft", "Shift", kKeyUp));
}
// Verifies that codepoints outside the 16-bit Unicode BMP are rejected.
IN_PROC_BROWSER_TEST_F(KeyboardInputTest, CharacterInBmp) {
const wchar_t kSigma = 0x03C3;
keyboard_service_->SendKeyEvent(
CreateCharacterKeyEvent(kSigma, KeyEventType::kPressed));
keyboard_service_->SendKeyEvent(
CreateCharacterKeyEvent(kSigma, KeyEventType::kReleased));
std::string expected_utf8;
ASSERT_TRUE(base::WideToUTF8(&kSigma, 1, &expected_utf8));
ExpectKeyEventsEqual(ExpectedKeyValue("", expected_utf8, kKeyDown),
ExpectedKeyValue("", expected_utf8, kKeyPress),
ExpectedKeyValue("", expected_utf8, kKeyUp));
}
// Verifies that codepoints beyond the range of allowable UCS-2 values
// are rejected.
IN_PROC_BROWSER_TEST_F(KeyboardInputTest, CharacterBeyondBmp) {
const uint32_t kRamenEmoji = 0x1F35C;
keyboard_service_->SendKeyEvent(
CreateCharacterKeyEvent(kRamenEmoji, KeyEventType::kPressed));
keyboard_service_->SendKeyEvent(
CreateCharacterKeyEvent(kRamenEmoji, KeyEventType::kReleased));
keyboard_service_->SendKeyEvent(
CreateCharacterKeyEvent('a', KeyEventType::kPressed));
keyboard_service_->SendKeyEvent(
CreateCharacterKeyEvent('a', KeyEventType::kReleased));
ExpectKeyEventsEqual(ExpectedKeyValue("", "a", kKeyDown),
ExpectedKeyValue("", "a", kKeyPress),
ExpectedKeyValue("", "a", kKeyUp));
}
IN_PROC_BROWSER_TEST_F(KeyboardInputTest, ShiftPrintableKeys) {
keyboard_service_->SendKeyEvent(
CreateKeyEvent(Key::kLeftShift, 0, KeyEventType::kPressed));
keyboard_service_->SendKeyEvent(
CreateKeyEvent(Key::kB, 'B', KeyEventType::kPressed));
keyboard_service_->SendKeyEvent(
CreateKeyEvent(Key::kKey1, '!', KeyEventType::kPressed));
keyboard_service_->SendKeyEvent(
CreateKeyEvent(Key::kSpace, ' ', KeyEventType::kPressed));
keyboard_service_->SendKeyEvent(
CreateKeyEvent(Key::kLeftShift, 0, KeyEventType::kReleased));
keyboard_service_->SendKeyEvent(
CreateKeyEvent(Key::kDot, '.', KeyEventType::kPressed));
// Note that non-character keys (e.g. shift, control) only generate key down
// and key up web events. They do not generate key pressed events.
ExpectKeyEventsEqual(ExpectedKeyValue("ShiftLeft", "Shift", kKeyDown),
ExpectedKeyValue("KeyB", "B", kKeyDown),
ExpectedKeyValue("KeyB", "B", kKeyPress),
ExpectedKeyValue("Digit1", "!", kKeyDown),
ExpectedKeyValue("Digit1", "!", kKeyPress),
ExpectedKeyValue("Space", " ", kKeyDown),
ExpectedKeyValue("Space", " ", kKeyPress),
ExpectedKeyValue("ShiftLeft", "Shift", kKeyUp),
ExpectedKeyValue("Period", ".", kKeyDown),
ExpectedKeyValue("Period", ".", kKeyPress));
}
IN_PROC_BROWSER_TEST_F(KeyboardInputTest, ShiftNonPrintableKeys) {
keyboard_service_->SendKeyEvent(
CreateKeyEvent(Key::kRightShift, 0, KeyEventType::kPressed));
keyboard_service_->SendKeyEvent(
CreateKeyEvent(Key::kEnter, fuchsia_ui_input3::NonPrintableKey::kEnter,
KeyEventType::kPressed));
keyboard_service_->SendKeyEvent(
CreateKeyEvent(Key::kLeftCtrl, 0, KeyEventType::kPressed));
keyboard_service_->SendKeyEvent(
CreateKeyEvent(Key::kRightShift, 0, KeyEventType::kReleased));
// Note that non-character keys (e.g. shift, control) only generate key down
// and key up web events. They do not generate key pressed events.
ExpectKeyEventsEqual(ExpectedKeyValue("ShiftRight", "Shift", kKeyDown),
ExpectedKeyValue("Enter", "Enter", kKeyDown),
ExpectedKeyValue("Enter", "Enter", kKeyPress),
ExpectedKeyValue("ControlLeft", "Control", kKeyDown),
ExpectedKeyValue("ShiftRight", "Shift", kKeyUp));
}
IN_PROC_BROWSER_TEST_F(KeyboardInputTest, RepeatedKeys) {
keyboard_service_->SendKeyEvent(
CreateKeyEvent(Key::kA, 'a', KeyEventType::kPressed, {.repeat = true}));
keyboard_service_->SendKeyEvent(CreateKeyEvent(
Key::kKey8, '8', KeyEventType::kPressed, {.repeat = true}));
// Note that non-character keys (e.g. shift, control) only generate key down
// and key up web events. They do not generate key pressed events.
ExpectKeyEventsEqual(
ExpectedKeyValue("KeyA", "a", kKeyDown, {.repeat = true}),
ExpectedKeyValue("KeyA", "a", kKeyPress, {.repeat = true}),
ExpectedKeyValue("Digit8", "8", kKeyDown, {.repeat = true}),
ExpectedKeyValue("Digit8", "8", kKeyPress, {.repeat = true}));
}
IN_PROC_BROWSER_TEST_F(KeyboardInputTest, AllSupportedWebModifierKeys) {
// All modifiers in the FIDL protocol that Chrome handles on the web.
//
// Missing modifiers:
// * LEFT_*/RIGHT_* are not valid by themselves.
// * FUNCTION and SYMBOL. See AllUnsupportedWebModifierKeys test.
const std::vector kAllSupportedModifiers = {
fuchsia_ui_input3::Modifiers::kCapsLock,
fuchsia_ui_input3::Modifiers::kNumLock,
fuchsia_ui_input3::Modifiers::kScrollLock,
fuchsia_ui_input3::Modifiers::kShift,
fuchsia_ui_input3::Modifiers::kAlt,
fuchsia_ui_input3::Modifiers::kAltGraph,
fuchsia_ui_input3::Modifiers::kMeta,
fuchsia_ui_input3::Modifiers::kCtrl};
for (const auto& modifier : kAllSupportedModifiers) {
keyboard_service_->SendKeyEvent(CreateKeyEvent(
Key::kM, 'm', KeyEventType::kPressed, {.modifiers = {modifier}}));
}
base::Value::List expected_events;
for (const auto& modifier : kAllSupportedModifiers) {
expected_events.Append(
ExpectedKeyValue("KeyM", "m", kKeyDown, {.modifiers = {modifier}}));
// Chrome doesn't emit keypress events when an ALT or CTRL modifier is
// present.
if (modifier != fuchsia_ui_input3::Modifiers::kAlt &&
modifier != fuchsia_ui_input3::Modifiers::kCtrl) {
expected_events.Append(
ExpectedKeyValue("KeyM", "m", kKeyPress, {.modifiers = {modifier}}));
}
}
ExpectKeyEventsEqual(std::move(expected_events));
}
IN_PROC_BROWSER_TEST_F(KeyboardInputTest, AllUnsupportedWebModifierKeys) {
// All modifiers in the FIDL protocol that Chrome doesn't handle on the web
// because they aren't included in
// https://crsrc.org/c/ui/events/blink/blink_event_util.cc;l=268?q=EventFlagsToWebEventModifiers
const std::vector kAllUnsupportedModifiers = {
fuchsia_ui_input3::Modifiers::kFunction,
fuchsia_ui_input3::Modifiers::kSymbol};
for (const auto& modifier : kAllUnsupportedModifiers) {
keyboard_service_->SendKeyEvent(CreateKeyEvent(
Key::kM, 'm', KeyEventType::kPressed, {.modifiers = {modifier}}));
}
base::Value::List expected_events;
for (size_t i = 0; i < kAllUnsupportedModifiers.size(); ++i) {
expected_events.Append(ExpectedKeyValue("KeyM", "m", kKeyDown, {}));
expected_events.Append(ExpectedKeyValue("KeyM", "m", kKeyPress, {}));
}
ExpectKeyEventsEqual(std::move(expected_events));
}
// This is a spot check to make sure that modifiers work with other keys and in
// combination with each other.
IN_PROC_BROWSER_TEST_F(KeyboardInputTest, AssortedModifierKeyCombos) {
// Test that sending LEFT/RIGHT SHIFT with agnostic SHIFT passes DCHECK.
keyboard_service_->SendKeyEvent(CreateKeyEvent(
Key::kA, 'a', KeyEventType::kPressed,
{.modifiers = {fuchsia_ui_input3::Modifiers::kShift,
fuchsia_ui_input3::Modifiers::kLeftShift,
fuchsia_ui_input3::Modifiers::kRightShift}}));
// Test that sending LEFT/RIGHT ALT with agnostic ALT passes DCHECK.
keyboard_service_->SendKeyEvent(
CreateKeyEvent(Key::kKey8, '8', KeyEventType::kPressed,
{.modifiers = {fuchsia_ui_input3::Modifiers::kAlt,
fuchsia_ui_input3::Modifiers::kLeftAlt,
fuchsia_ui_input3::Modifiers::kRightAlt}}));
// Test that sending LEFT/RIGHT META with agnostic META passes DCHECK.
keyboard_service_->SendKeyEvent(CreateKeyEvent(
Key::kB, 'b', KeyEventType::kPressed,
{.modifiers = {fuchsia_ui_input3::Modifiers::kMeta,
fuchsia_ui_input3::Modifiers::kLeftMeta,
fuchsia_ui_input3::Modifiers::kRightMeta}}));
// Test that sending LEFT/RIGHT CTRL with agnostic CTRL passes DCHECK.
keyboard_service_->SendKeyEvent(CreateKeyEvent(
Key::kLeft, 0, KeyEventType::kPressed,
{.modifiers = {fuchsia_ui_input3::Modifiers::kCtrl,
fuchsia_ui_input3::Modifiers::kLeftCtrl,
fuchsia_ui_input3::Modifiers::kRightCtrl}}));
keyboard_service_->SendKeyEvent(
CreateKeyEvent(Key::kP, 'p', KeyEventType::kPressed,
{.modifiers = {fuchsia_ui_input3::Modifiers::kCtrl,
fuchsia_ui_input3::Modifiers::kShift}}));
keyboard_service_->SendKeyEvent(
CreateKeyEvent(Key::kRight, 0, KeyEventType::kPressed,
{.modifiers = {fuchsia_ui_input3::Modifiers::kAltGraph}}));
keyboard_service_->SendKeyEvent(
CreateKeyEvent(Key::kUp, 0, KeyEventType::kPressed,
{.modifiers = {fuchsia_ui_input3::Modifiers::kCapsLock}}));
keyboard_service_->SendKeyEvent(
CreateKeyEvent(Key::kDown, 0, KeyEventType::kPressed,
{.modifiers = {fuchsia_ui_input3::Modifiers::kNumLock}}));
keyboard_service_->SendKeyEvent(CreateKeyEvent(
Key::kLeft, 0, KeyEventType::kPressed,
{.modifiers = {fuchsia_ui_input3::Modifiers::kScrollLock}}));
ExpectKeyEventsEqual(
ExpectedKeyValue("KeyA", "a", kKeyDown,
{.modifiers = {fuchsia_ui_input3::Modifiers::kShift}}),
ExpectedKeyValue("KeyA", "a", kKeyPress,
{.modifiers = {fuchsia_ui_input3::Modifiers::kShift}}),
ExpectedKeyValue("Digit8", "8", kKeyDown,
{.modifiers = {fuchsia_ui_input3::Modifiers::kAlt}}),
ExpectedKeyValue("KeyB", "b", kKeyDown,
{.modifiers = {fuchsia_ui_input3::Modifiers::kMeta}}),
ExpectedKeyValue("KeyB", "b", kKeyPress,
{.modifiers = {fuchsia_ui_input3::Modifiers::kMeta}}),
ExpectedKeyValue("ArrowLeft", "ArrowLeft", kKeyDown,
{.modifiers = {fuchsia_ui_input3::Modifiers::kCtrl}}),
ExpectedKeyValue("KeyP", "p", kKeyDown,
{.modifiers = {fuchsia_ui_input3::Modifiers::kCtrl,
fuchsia_ui_input3::Modifiers::kShift}}),
ExpectedKeyValue("KeyP", "p", kKeyPress,
{.modifiers = {fuchsia_ui_input3::Modifiers::kCtrl,
fuchsia_ui_input3::Modifiers::kShift}}),
ExpectedKeyValue(
"ArrowRight", "ArrowRight", kKeyDown,
{.modifiers = {fuchsia_ui_input3::Modifiers::kAltGraph}}),
ExpectedKeyValue(
"ArrowUp", "ArrowUp", kKeyDown,
{.modifiers = {fuchsia_ui_input3::Modifiers::kCapsLock}}),
ExpectedKeyValue("ArrowDown", "ArrowDown", kKeyDown,
{.modifiers = {fuchsia_ui_input3::Modifiers::kNumLock}}),
ExpectedKeyValue(
"ArrowLeft", "ArrowLeft", kKeyDown,
{.modifiers = {fuchsia_ui_input3::Modifiers::kScrollLock}}));
}
IN_PROC_BROWSER_TEST_F(KeyboardInputTest, Disconnect) {
// Disconnect the keyboard service.
keyboard_service_.reset();
frame_for_test_.navigation_listener().RunUntilTitleEquals("loaded");
// Make sure the page is still available and there are no crashes.
EXPECT_TRUE(
ExecuteJavaScript(frame_for_test_.ptr().get(), "true")->GetBool());
}
class KeyboardInputTestWithoutKeyboardFeature : public KeyboardInputTest {
public:
KeyboardInputTestWithoutKeyboardFeature() = default;
~KeyboardInputTestWithoutKeyboardFeature() override = default;
protected:
void SetUp() override {
scoped_feature_list_.InitWithFeatures({}, {});
WebEngineBrowserTest::SetUp();
}
void SetUpService() override {
keyboard_input_checker_.emplace(component_context_->additional_services());
}
std::optional<NeverConnectedChecker<fuchsia_ui_input3::Keyboard>>
keyboard_input_checker_;
};
IN_PROC_BROWSER_TEST_F(KeyboardInputTestWithoutKeyboardFeature, NoFeature) {
// Test will verify that |keyboard_input_checker_| never received a connection
// request at teardown time.
}
} // namespace