blob: 6a0f18de3b6a5510e55f0fdf6d5d6a84b52848ce [file] [log] [blame]
// Copyright 2017 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "keyboard.h"
#include <array>
#include <hid/hid.h>
#include <hid/usages.h>
#include <zxtest/zxtest.h>
#include "keyboard-vt100.h"
#include "src/ui/input/lib/hid-input-report/keyboard.h"
#include "src/ui/lib/key_util/key_util.h"
namespace {
namespace fuchsia_input_report = fuchsia_input_report;
// State reported to keypress_handler().
uint8_t g_keycode;
int g_modifiers;
bool g_got_keypress = false;
void keypress_handler(uint8_t keycode, int modifiers) {
g_keycode = keycode;
g_modifiers = modifiers;
g_got_keypress = true;
}
void expect_keypress(uint8_t expected_keycode, int expected_modifiers, uint8_t expected_char) {
EXPECT_EQ(g_got_keypress, true);
g_got_keypress = false;
EXPECT_EQ(g_keycode, expected_keycode);
EXPECT_EQ(g_modifiers, expected_modifiers);
std::array<char, 4> output = {};
uint32_t length =
hid_key_to_vt100_code(g_keycode, g_modifiers, qwerty_map, output.data(), output.size());
if (expected_char == 0) {
EXPECT_EQ(length, 0);
} else {
ASSERT_EQ(length, 1);
EXPECT_EQ(output[0], expected_char);
}
}
class KeyboardInputHelper {
public:
KeyboardInputHelper(async_dispatcher_t* dispatcher)
: keyboard_(dispatcher, keypress_handler, true) {}
~KeyboardInputHelper() {}
void WriteReportBuf(std::vector<uint32_t> keys) {
fidl::FidlAllocator allocator;
fuchsia_input_report::wire::InputReport input_report(allocator);
fuchsia_input_report::wire::KeyboardInputReport keyboard_input_report(allocator);
size_t index = 0;
fidl::VectorView<fuchsia_input::wire::Key> fidl_keys(allocator, keys.size());
for (auto& key : keys) {
auto fidl_key =
*key_util::hid_key_to_fuchsia_key3(hid::USAGE(hid::usage::Page::kKeyboardKeypad, key));
fidl_keys[index++] = static_cast<fuchsia_input::wire::Key>(fidl_key);
}
keyboard_input_report.set_pressed_keys3(allocator, std::move(fidl_keys));
input_report.set_keyboard(allocator, std::move(keyboard_input_report));
keyboard_.ProcessInput(input_report);
}
// Byte 0 contains one bit per modifier key.
void set_modifiers_byte(uint8_t value) {}
// Bytes 2+ contain USB HID key codes.
void set_first_keycode(uint8_t value) {}
private:
Keyboard keyboard_;
};
TEST(GfxConsoleKeyboardTests, KeyboardInputThread) {
async::Loop loop = async::Loop(&kAsyncLoopConfigNeverAttachToThread);
KeyboardInputHelper helper(loop.dispatcher());
std::vector<uint32_t> keypresses;
// Test pressing keys without any modifiers.
keypresses = {HID_USAGE_KEY_M};
helper.WriteReportBuf(keypresses);
ASSERT_NO_FAILURES(expect_keypress(HID_USAGE_KEY_M, 0, 'm'));
keypresses = {HID_USAGE_KEY_6};
helper.WriteReportBuf(keypresses);
ASSERT_NO_FAILURES(expect_keypress(HID_USAGE_KEY_6, 0, '6'));
// Press a modifier (but no other keys).
keypresses = {HID_USAGE_KEY_LEFT_SHIFT};
helper.WriteReportBuf(keypresses);
ASSERT_NO_FAILURES(expect_keypress(HID_USAGE_KEY_LEFT_SHIFT, MOD_LSHIFT, '\0'));
// Test keys with modifiers pressed.
// Test Shift-N.
keypresses = {HID_USAGE_KEY_LEFT_SHIFT, HID_USAGE_KEY_N};
helper.WriteReportBuf(keypresses);
ASSERT_NO_FAILURES(expect_keypress(HID_USAGE_KEY_N, MOD_LSHIFT, 'N'));
// Test Shift-8.
keypresses = {HID_USAGE_KEY_LEFT_SHIFT, HID_USAGE_KEY_8};
helper.WriteReportBuf(keypresses);
ASSERT_NO_FAILURES(expect_keypress(HID_USAGE_KEY_8, MOD_LSHIFT, '*'));
// Test Ctrl modifier.
keypresses = {HID_USAGE_KEY_LEFT_CTRL};
helper.WriteReportBuf(keypresses);
ASSERT_NO_FAILURES(expect_keypress(HID_USAGE_KEY_LEFT_CTRL, MOD_LCTRL, '\0'));
// Test Ctrl-J.
keypresses = {HID_USAGE_KEY_J, HID_USAGE_KEY_LEFT_CTRL};
helper.WriteReportBuf(keypresses);
ASSERT_NO_FAILURES(expect_keypress(HID_USAGE_KEY_J, MOD_LCTRL, 10));
// Test Ctrl-1. The Ctrl modifier should be ignored in this case so
// that we just get '1'.
keypresses = {HID_USAGE_KEY_1, HID_USAGE_KEY_LEFT_CTRL};
helper.WriteReportBuf(keypresses);
ASSERT_NO_FAILURES(expect_keypress(HID_USAGE_KEY_1, MOD_LCTRL, '1'));
// Try Shift and Ctrl together.
keypresses = {HID_USAGE_KEY_LEFT_SHIFT, HID_USAGE_KEY_LEFT_CTRL};
helper.WriteReportBuf(keypresses);
ASSERT_NO_FAILURES(expect_keypress(HID_USAGE_KEY_LEFT_SHIFT, MOD_LSHIFT | MOD_LCTRL, '\0'));
// Test Shift-Ctrl-J. This should be equivalent to Ctrl-J.
keypresses = {HID_USAGE_KEY_LEFT_SHIFT, HID_USAGE_KEY_LEFT_CTRL, HID_USAGE_KEY_J};
helper.WriteReportBuf(keypresses);
ASSERT_NO_FAILURES(expect_keypress(HID_USAGE_KEY_J, MOD_LSHIFT | MOD_LCTRL, 10));
// Test Shift-Ctrl-1. This should be equivalent to Shift-1.
keypresses = {HID_USAGE_KEY_LEFT_SHIFT, HID_USAGE_KEY_LEFT_CTRL, HID_USAGE_KEY_1};
helper.WriteReportBuf(keypresses);
ASSERT_NO_FAILURES(expect_keypress(HID_USAGE_KEY_1, MOD_LSHIFT | MOD_LCTRL, '!'));
}
TEST(GfxConsoleKeyboardTests, CapsLock) {
async::Loop loop = async::Loop(&kAsyncLoopConfigNeverAttachToThread);
KeyboardInputHelper helper(loop.dispatcher());
std::vector<uint32_t> keypresses;
keypresses = {HID_USAGE_KEY_CAPSLOCK};
helper.WriteReportBuf(keypresses);
ASSERT_NO_FAILURES(expect_keypress(HID_USAGE_KEY_CAPSLOCK, MOD_CAPSLOCK, '\0'));
// Test that letters are capitalized.
keypresses = {HID_USAGE_KEY_M};
helper.WriteReportBuf(keypresses);
ASSERT_NO_FAILURES(expect_keypress(HID_USAGE_KEY_M, MOD_CAPSLOCK, 'M'));
// Non-letter characters should not be affected. This isn't Shift Lock.
keypresses = {HID_USAGE_KEY_1};
helper.WriteReportBuf(keypresses);
ASSERT_NO_FAILURES(expect_keypress(HID_USAGE_KEY_1, MOD_CAPSLOCK, '1'));
// Test unsetting Caps Lock.
keypresses = {HID_USAGE_KEY_CAPSLOCK};
helper.WriteReportBuf(keypresses);
ASSERT_NO_FAILURES(expect_keypress(HID_USAGE_KEY_CAPSLOCK, 0, '\0'));
keypresses = {HID_USAGE_KEY_M};
helper.WriteReportBuf(keypresses);
ASSERT_NO_FAILURES(expect_keypress(HID_USAGE_KEY_M, 0, 'm'));
}
TEST(GfxConsoleKeyboardTests, CapsLockWithShift) {
async::Loop loop = async::Loop(&kAsyncLoopConfigNeverAttachToThread);
KeyboardInputHelper helper(loop.dispatcher());
std::vector<uint32_t> keypresses;
keypresses = {HID_USAGE_KEY_LEFT_SHIFT};
helper.WriteReportBuf(keypresses);
ASSERT_NO_FAILURES(expect_keypress(HID_USAGE_KEY_LEFT_SHIFT, MOD_LSHIFT, '\0'));
keypresses = {HID_USAGE_KEY_LEFT_SHIFT, HID_USAGE_KEY_CAPSLOCK};
helper.WriteReportBuf(keypresses);
ASSERT_NO_FAILURES(expect_keypress(HID_USAGE_KEY_CAPSLOCK, MOD_LSHIFT | MOD_CAPSLOCK, '\0'));
// Shift should undo the effect of Caps Lock for letters.
keypresses = {HID_USAGE_KEY_LEFT_SHIFT, HID_USAGE_KEY_M};
helper.WriteReportBuf(keypresses);
ASSERT_NO_FAILURES(expect_keypress(HID_USAGE_KEY_M, MOD_LSHIFT | MOD_CAPSLOCK, 'm'));
keypresses = {HID_USAGE_KEY_LEFT_SHIFT, HID_USAGE_KEY_1};
helper.WriteReportBuf(keypresses);
ASSERT_NO_FAILURES(expect_keypress(HID_USAGE_KEY_1, MOD_LSHIFT | MOD_CAPSLOCK, '!'));
// Test unsetting Caps Lock.
keypresses = {HID_USAGE_KEY_LEFT_SHIFT, HID_USAGE_KEY_CAPSLOCK};
helper.WriteReportBuf(keypresses);
ASSERT_NO_FAILURES(expect_keypress(HID_USAGE_KEY_CAPSLOCK, MOD_LSHIFT, '\0'));
keypresses = {HID_USAGE_KEY_LEFT_SHIFT, HID_USAGE_KEY_M};
helper.WriteReportBuf(keypresses);
ASSERT_NO_FAILURES(expect_keypress(HID_USAGE_KEY_M, MOD_LSHIFT, 'M'));
}
} // namespace