BuildSystem: Move all userpace libraries under the userspace directory

As the number of libraries is increasing, root directory starts to
expand. This adds better organization for libraries
This commit is contained in:
2024-06-18 13:14:35 +03:00
parent 1b5a01a6c9
commit c69919738b
157 changed files with 46 additions and 30 deletions

View File

@@ -0,0 +1,24 @@
cmake_minimum_required(VERSION 3.26)
project(libinput CXX)
set(LIBINPUT_SOURCES
KeyEvent.cpp
KeyboardLayout.cpp
)
add_custom_target(libinput-headers
COMMAND ${CMAKE_COMMAND} -E copy_directory_if_different ${CMAKE_CURRENT_SOURCE_DIR}/include/ ${BANAN_INCLUDE}/
DEPENDS sysroot
)
add_library(libinput ${LIBINPUT_SOURCES})
target_link_libraries(libinput PUBLIC libc ban)
add_custom_target(libinput-install
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_BINARY_DIR}/libinput.a ${BANAN_LIB}/
DEPENDS libinput
BYPRODUCTS ${BANAN_LIB}/libinput.a
)
set(CMAKE_STATIC_LIBRARY_PREFIX "")

View File

@@ -0,0 +1,121 @@
#include <BAN/Array.h>
#include <LibInput/KeyEvent.h>
#include <ctype.h>
#include <string.h>
namespace LibInput
{
const char* key_to_utf8(Key key, uint16_t modifier)
{
static constexpr const char* utf8_lower[] = {
nullptr, nullptr,
"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z",
"å", "ä", "ö",
"0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, " ",
"!", "\"", "#", "¤", "%", "&", "/", "§", "½",
"(", ")", "[", "]", "{", "}",
"=", "?", "+", "\\", "´", "`", "¨", "¸", nullptr, "@", "£", "$", "",
nullptr, "\t", nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
"'", "*", "^", "~", nullptr, nullptr, nullptr, nullptr,
",", ";", ".", ":", "-", "_", nullptr, nullptr, "<", ">", "|", "¬", "¦",
"0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
"+", "-", "*", "/", nullptr, ",",
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
};
static_assert((size_t)Key::Count == sizeof(utf8_lower) / sizeof(*utf8_lower));
static constexpr const char* utf8_upper[] = {
nullptr, nullptr,
"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z",
"Å", "Ä", "Ö",
"0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, " ",
"!", "\"", "#", "¤", "%", "&", "/", "§", "½",
"(", ")", "[", "]", "{", "}",
"=", "?", "+", "\\", "´", "`", "¨", "¸", nullptr, "@", "£", "$", "",
nullptr, "\t", nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
"'", "*", "^", "~", nullptr, nullptr, nullptr, nullptr,
",", ";", ".", ":", "-", "_", nullptr, nullptr, "<", ">", "|", "¬", "¦",
"0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
"+", "-", "*", "/", nullptr, ",",
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
};
static_assert((size_t)Key::Count == sizeof(utf8_upper) / sizeof(*utf8_lower));
KeyEvent event { .modifier = modifier, .key = key };
return (event.shift() ^ event.caps_lock()) ? utf8_upper[static_cast<uint8_t>(key)] : utf8_lower[static_cast<uint8_t>(key)];
}
const char* key_to_utf8_ansi(Key key, uint16_t modifier)
{
static constexpr const char* utf8_lower[] = {
nullptr, nullptr,
"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z",
"å", "ä", "ö",
"0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
/*"Insert", "PrintScreen", "Delete", "Home", "End", "PageUp", "PageDown",*/ nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, "\n", " ",
"!", "\"", "#", "¤", "%", "&", "/", "§", "½",
"(", ")", "[", "]", "{", "}",
"=", "?", "+", "\\", "´", "`", "¨", "¸", "\b \b", "@", "£", "$", "",
nullptr, "\t", nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
"'", "*", "^", "~", "\e[A", "\e[B", "\e[D", "\e[C",
",", ";", ".", ":", "-", "_", nullptr, nullptr, "<", ">", "|", "¬", "¦",
"0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
"+", "-", "*", "/", "\n", ",",
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
};
static_assert((size_t)Key::Count == sizeof(utf8_lower) / sizeof(*utf8_lower));
static constexpr const char* utf8_upper[] = {
nullptr, nullptr,
"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z",
"Å", "Ä", "Ö",
"0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
/*"Insert", "PrintScreen", "Delete", "Home", "End", "PageUp", "PageDown",*/ nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, "\n", " ",
"!", "\"", "#", "¤", "%", "&", "/", "§", "½",
"(", ")", "[", "]", "{", "}",
"=", "?", "+", "\\", "´", "`", "¨", "¸", "\b \b", "@", "£", "$", "",
nullptr, "\t", nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
"'", "*", "^", "~", "\e[A", "\e[B", "\e[D", "\e[C",
",", ";", ".", ":", "-", "_", nullptr, nullptr, "<", ">", "|", "¬", "¦",
"0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
"+", "-", "*", "/", "\n", ",",
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
};
static_assert((size_t)Key::Count == sizeof(utf8_upper) / sizeof(*utf8_upper));
static constexpr const char* utf8_ctrl[] = {
nullptr, nullptr,
"\x01", "\x02", "\x03", "\x04", "\x05", "\x06", "\x07", "\x08", "\x09", "\x0A", "\x0B", "\x0C", "\x0D", "\x0E", "\x0F", "\x10", "\x11", "\x12", "\x13", "\x14", "\x15", "\x16", "\x17", "\x18", "\x19", "\x1A",
"Å", "Ä", "Ö",
"0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
/*"Insert", "PrintScreen", "Delete", "Home", "End", "PageUp", "PageDown",*/ nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, "\n", " ",
"!", "\"", "#", "¤", "%", "&", "/", "§", "½",
"(", ")", "[", "]", "{", "}",
"=", "?", "+", "\\", "´", "`", "¨", "¸", "\b \b", "@", "£", "$", "",
nullptr, "\t", nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
"'", "*", "^", "~", "\e[A", "\e[B", "\e[D", "\e[C",
",", ";", ".", ":", "-", "_", nullptr, nullptr, "<", ">", "|", "¬", "¦",
"0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
"+", "-", "*", "/", "\n", ",",
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
};
static_assert((size_t)Key::Count == sizeof(utf8_upper) / sizeof(*utf8_upper));
KeyEvent event { .modifier = modifier, .key = key };
if (event.ctrl())
return utf8_ctrl[static_cast<uint8_t>(key)];
if (event.shift() ^ event.caps_lock())
return utf8_upper[static_cast<uint8_t>(key)];
return utf8_lower[static_cast<uint8_t>(key)];
}
}

View File

@@ -0,0 +1,474 @@
#include <BAN/Debug.h>
#include <BAN/HashMap.h>
#include <BAN/String.h>
#include <BAN/StringView.h>
#include <LibInput/KeyboardLayout.h>
#if __is_kernel
#include <kernel/FS/VirtualFileSystem.h>
#else
#include <fcntl.h>
#include <limits.h>
#include <sys/stat.h>
#endif
#include <ctype.h>
namespace LibInput
{
struct StringViewLower
{
BAN::StringView value;
StringViewLower(BAN::StringView sv)
: value(sv)
{ }
bool operator==(const StringViewLower& other) const
{
if (value.size() != other.value.size())
return false;
for (size_t i = 0; i < value.size(); i++)
if (tolower(value[i]) != tolower(other.value[i]))
return false;
return true;
}
};
struct StringViewLowerHash
{
BAN::hash_t operator()(const StringViewLower& value) const
{
constexpr BAN::hash_t FNV_offset_basis = 0x811c9dc5;
constexpr BAN::hash_t FNV_prime = 0x01000193;
BAN::hash_t hash = FNV_offset_basis;
for (size_t i = 0; i < value.value.size(); i++)
{
hash *= FNV_prime;
hash ^= (uint8_t)tolower(value.value[i]);
}
return hash;
}
};
static BAN::UniqPtr<KeyboardLayout> s_instance;
BAN::ErrorOr<void> KeyboardLayout::initialize()
{
ASSERT(!s_instance);
s_instance = TRY(BAN::UniqPtr<KeyboardLayout>::create());
return {};
}
KeyboardLayout& KeyboardLayout::get()
{
ASSERT(s_instance);
return *s_instance;
}
KeyboardLayout::KeyboardLayout()
{
for (auto& key : m_keycode_to_key_normal)
key = Key::None;
for (auto& key : m_keycode_to_key_shift)
key = Key::None;
for (auto& key : m_keycode_to_key_altgr)
key = Key::None;
}
KeyEvent KeyboardLayout::key_event_from_raw(RawKeyEvent event)
{
KeyEvent result;
result.modifier = event.modifier;
if (result.shift())
result.key = m_keycode_to_key_shift[event.keycode];
else if (result.ralt())
result.key = m_keycode_to_key_altgr[event.keycode];
else
result.key = m_keycode_to_key_normal[event.keycode];
return result;
}
static BAN::Optional<uint8_t> parse_keycode(BAN::StringView str)
{
if (str.size() > 3)
return {};
uint16_t keycode = 0;
for (char c : str)
{
if (!isdigit(c))
return {};
keycode = (keycode * 10) + (c - '0');
}
if (keycode >= 0xFF)
return {};
return keycode;
}
static BAN::HashMap<StringViewLower, Key, StringViewLowerHash> s_name_to_key;
static BAN::ErrorOr<void> initialize_name_to_key();
static BAN::Optional<Key> parse_key(BAN::StringView name)
{
if (s_name_to_key.contains(name))
return s_name_to_key[name];
return {};
}
static BAN::ErrorOr<BAN::Vector<BAN::String>> load_keymap_lines_and_parse_includes(BAN::StringView path)
{
BAN::String file_data;
BAN::String canonical_path;
#if __is_kernel
{
auto file = TRY(Kernel::VirtualFileSystem::get().file_from_absolute_path({ 0, 0, 0, 0 }, path, 0));
TRY(file_data.resize(file.inode->size()));
TRY(file.inode->read(0, BAN::ByteSpan { reinterpret_cast<uint8_t*>(file_data.data()), file_data.size() }));
canonical_path = file.canonical_path;
}
#else
{
char null_path[PATH_MAX];
strncpy(null_path, path.data(), path.size());
null_path[path.size()] = '\0';
struct stat st;
if (stat(null_path, &st) == -1)
return BAN::Error::from_errno(errno);
TRY(file_data.resize(st.st_size));
int fd = open(null_path, O_RDONLY);
if (fd == -1)
return BAN::Error::from_errno(errno);
ssize_t nread = read(fd, file_data.data(), st.st_size);
close(fd);
if (nread != st.st_size)
return BAN::Error::from_errno(errno);
MUST(canonical_path.append(path));
}
#endif
BAN::Vector<BAN::String> result;
auto lines = TRY(file_data.sv().split('\n'));
for (auto line : lines)
{
auto parts = TRY(line.split([](char c) -> bool { return isspace(c); }));
if (parts.empty() || parts.front().front() == '#')
continue;
if (parts.front() == "include"sv)
{
if (parts.size() != 2)
{
dprintln("Invalid modifier instruction in keymap '{}'", line);
dprintln(" format: include \"PATH\"");
return BAN::Error::from_errno(EINVAL);
}
if (parts[1].size() < 2 || parts[1].front() != '"' || parts[1].back() != '"')
{
dprintln("Invalid modifier instruction in keymap '{}'", line);
dprintln(" format: include \"PATH\"");
return BAN::Error::from_errno(EINVAL);
}
parts[1] = parts[1].substring(1, parts[1].size() - 2);
BAN::String include_path;
TRY(include_path.append(canonical_path));
ASSERT(include_path.sv().contains('/'));
while (include_path.back() != '/')
include_path.pop_back();
TRY(include_path.append(parts[1]));
auto new_lines = TRY(load_keymap_lines_and_parse_includes(include_path));
TRY(result.reserve(result.size() + new_lines.size()));
for (auto& line : new_lines)
TRY(result.push_back(BAN::move(line)));
}
else
{
BAN::String line_str;
TRY(line_str.append(line));
TRY(result.push_back(BAN::move(line_str)));
}
}
return result;
}
BAN::ErrorOr<void> KeyboardLayout::load_from_file(BAN::StringView path)
{
if (s_name_to_key.empty())
TRY(initialize_name_to_key());
auto new_layout = TRY(BAN::UniqPtr<KeyboardLayout>::create());
bool shift_is_mod = false;
bool altgr_is_mod = false;
auto lines = TRY(load_keymap_lines_and_parse_includes(path));
for (const auto& line : lines)
{
auto parts = TRY(line.sv().split([](char c) -> bool { return isspace(c); }));
if (parts.empty() || parts.front().front() == '#')
continue;
if (parts.size() == 1)
{
dprintln("Invalid line in keymap '{}'", line);
dprintln(" format: KEYCODE KEY [MODIFIER=KEY]...");
dprintln(" format: mod MODIFIER");
dprintln(" format: include \"PATH\"");
return BAN::Error::from_errno(EINVAL);
}
if (parts.front() == "mod"sv)
{
if (parts.size() != 2)
{
dprintln("Invalid modifier instruction in keymap '{}'", line);
dprintln(" format: mod MODIFIER");
return BAN::Error::from_errno(EINVAL);
}
if (parts[1] == "shift"sv)
shift_is_mod = true;
else if (parts[1] == "altgr"sv)
altgr_is_mod = true;
else
{
dprintln("Unrecognized modifier '{}'", parts[1]);
return BAN::Error::from_errno(EINVAL);
}
continue;
}
auto keycode = parse_keycode(parts.front());
if (!keycode.has_value())
{
dprintln("Invalid keycode '{}', keycode must number between [0, 0xFF[", parts.front());
return BAN::Error::from_errno(EINVAL);
}
auto default_key = parse_key(parts[1]);
if (!default_key.has_value())
{
dprintln("Unrecognized key '{}'", parts[1]);
return BAN::Error::from_errno(EINVAL);
}
new_layout->m_keycode_to_key_normal[*keycode] = *default_key;
new_layout->m_keycode_to_key_shift[*keycode] = *default_key;
new_layout->m_keycode_to_key_altgr[*keycode] = *default_key;
for (size_t i = 2; i < parts.size(); i++)
{
auto pair = TRY(parts[i].split('='));
if (pair.size() != 2)
{
dprintln("Invalid modifier format '{}', modifier format: MODIFIRER=KEY", parts[i]);
return BAN::Error::from_errno(EINVAL);
}
auto key = parse_key(pair.back());
if (!key.has_value())
{
dprintln("Unrecognized key '{}'", pair.back());
return BAN::Error::from_errno(EINVAL);
}
if (shift_is_mod && pair.front() == "shift"sv)
new_layout->m_keycode_to_key_shift[*keycode] = *key;
else if (altgr_is_mod && pair.front() == "altgr"sv)
new_layout->m_keycode_to_key_altgr[*keycode] = *key;
else
{
dprintln("Unrecognized modifier '{}'", pair.front());
return BAN::Error::from_errno(EINVAL);
}
}
}
for (size_t i = 0; i < new_layout->m_keycode_to_key_normal.size(); i++)
if (new_layout->m_keycode_to_key_normal[i] != Key::None)
m_keycode_to_key_normal[i] = new_layout->m_keycode_to_key_normal[i];
for (size_t i = 0; i < new_layout->m_keycode_to_key_shift.size(); i++)
if (new_layout->m_keycode_to_key_shift[i] != Key::None)
m_keycode_to_key_shift[i] = new_layout->m_keycode_to_key_shift[i];
for (size_t i = 0; i < new_layout->m_keycode_to_key_altgr.size(); i++)
if (new_layout->m_keycode_to_key_altgr[i] != Key::None)
m_keycode_to_key_altgr[i] = new_layout->m_keycode_to_key_altgr[i];
return {};
}
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wstack-usage="
static BAN::ErrorOr<void> initialize_name_to_key()
{
ASSERT(s_name_to_key.empty());
TRY(s_name_to_key.insert("A_Ring"sv, Key::A_Ring));
TRY(s_name_to_key.insert("A_Umlaut"sv, Key::A_Umlaut));
TRY(s_name_to_key.insert("A"sv, Key::A));
TRY(s_name_to_key.insert("Acute"sv, Key::Acute));
TRY(s_name_to_key.insert("AltGr"sv, Key::AltGr));
TRY(s_name_to_key.insert("Ampersand"sv, Key::Ampersand));
TRY(s_name_to_key.insert("ArrowDown"sv, Key::ArrowDown));
TRY(s_name_to_key.insert("ArrowLeft"sv, Key::ArrowLeft));
TRY(s_name_to_key.insert("ArrowRight"sv, Key::ArrowRight));
TRY(s_name_to_key.insert("ArrowUp"sv, Key::ArrowUp));
TRY(s_name_to_key.insert("Asterix"sv, Key::Asterix));
TRY(s_name_to_key.insert("AtSign"sv, Key::AtSign));
TRY(s_name_to_key.insert("B"sv, Key::B));
TRY(s_name_to_key.insert("BackSlash"sv, Key::BackSlash));
TRY(s_name_to_key.insert("Backspace"sv, Key::Backspace));
TRY(s_name_to_key.insert("BackTick"sv, Key::BackTick));
TRY(s_name_to_key.insert("BrokenBar"sv, Key::BrokenBar));
TRY(s_name_to_key.insert("C"sv, Key::C));
TRY(s_name_to_key.insert("Calculator"sv, Key::Calculator));
TRY(s_name_to_key.insert("CapsLock"sv, Key::CapsLock));
TRY(s_name_to_key.insert("Caret"sv, Key::Caret));
TRY(s_name_to_key.insert("Cedilla"sv, Key::Cedilla));
TRY(s_name_to_key.insert("CloseCurlyBracket"sv, Key::CloseCurlyBracket));
TRY(s_name_to_key.insert("CloseParenthesis"sv, Key::CloseParenthesis));
TRY(s_name_to_key.insert("CloseSquareBracket"sv, Key::CloseSquareBracket));
TRY(s_name_to_key.insert("Colon"sv, Key::Colon));
TRY(s_name_to_key.insert("Comma"sv, Key::Comma));
TRY(s_name_to_key.insert("Currency"sv, Key::Currency));
TRY(s_name_to_key.insert("D"sv, Key::D));
TRY(s_name_to_key.insert("Delete"sv, Key::Delete));
TRY(s_name_to_key.insert("Dollar"sv, Key::Dollar));
TRY(s_name_to_key.insert("DoubleQuote"sv, Key::DoubleQuote));
TRY(s_name_to_key.insert("E"sv, Key::E));
TRY(s_name_to_key.insert("End"sv, Key::End));
TRY(s_name_to_key.insert("Enter"sv, Key::Enter));
TRY(s_name_to_key.insert("Equals"sv, Key::Equals));
TRY(s_name_to_key.insert("Escape"sv, Key::Escape));
TRY(s_name_to_key.insert("Euro"sv, Key::Euro));
TRY(s_name_to_key.insert("Exclamation"sv, Key::ExclamationMark));
TRY(s_name_to_key.insert("ExclamationMark"sv, Key::ExclamationMark));
TRY(s_name_to_key.insert("F"sv, Key::F));
TRY(s_name_to_key.insert("F1"sv, Key::F1));
TRY(s_name_to_key.insert("F10"sv, Key::F10));
TRY(s_name_to_key.insert("F11"sv, Key::F11));
TRY(s_name_to_key.insert("F12"sv, Key::F12));
TRY(s_name_to_key.insert("F2"sv, Key::F2));
TRY(s_name_to_key.insert("F3"sv, Key::F3));
TRY(s_name_to_key.insert("F4"sv, Key::F4));
TRY(s_name_to_key.insert("F5"sv, Key::F5));
TRY(s_name_to_key.insert("F6"sv, Key::F6));
TRY(s_name_to_key.insert("F7"sv, Key::F7));
TRY(s_name_to_key.insert("F8"sv, Key::F8));
TRY(s_name_to_key.insert("F9"sv, Key::F9));
TRY(s_name_to_key.insert("G"sv, Key::G));
TRY(s_name_to_key.insert("GreaterThan"sv, Key::GreaterThan));
TRY(s_name_to_key.insert("H"sv, Key::H));
TRY(s_name_to_key.insert("Half"sv, Key::Half));
TRY(s_name_to_key.insert("Hashtag"sv, Key::Hashtag));
TRY(s_name_to_key.insert("Home"sv, Key::Home));
TRY(s_name_to_key.insert("Hyphen"sv, Key::Hyphen));
TRY(s_name_to_key.insert("I"sv, Key::I));
TRY(s_name_to_key.insert("Insert"sv, Key::Insert));
TRY(s_name_to_key.insert("J"sv, Key::J));
TRY(s_name_to_key.insert("K"sv, Key::K));
TRY(s_name_to_key.insert("Key0"sv, Key::_0));
TRY(s_name_to_key.insert("Key1"sv, Key::_1));
TRY(s_name_to_key.insert("Key2"sv, Key::_2));
TRY(s_name_to_key.insert("Key3"sv, Key::_3));
TRY(s_name_to_key.insert("Key4"sv, Key::_4));
TRY(s_name_to_key.insert("Key5"sv, Key::_5));
TRY(s_name_to_key.insert("Key6"sv, Key::_6));
TRY(s_name_to_key.insert("Key7"sv, Key::_7));
TRY(s_name_to_key.insert("Key8"sv, Key::_8));
TRY(s_name_to_key.insert("Key9"sv, Key::_9));
TRY(s_name_to_key.insert("L"sv, Key::L));
TRY(s_name_to_key.insert("LAlt"sv, Key::LeftAlt));
TRY(s_name_to_key.insert("LControl"sv, Key::LeftCtrl));
TRY(s_name_to_key.insert("LeftAlt"sv, Key::LeftAlt));
TRY(s_name_to_key.insert("LeftControl"sv, Key::LeftCtrl));
TRY(s_name_to_key.insert("LeftShift"sv, Key::LeftShift));
TRY(s_name_to_key.insert("LessThan"sv, Key::LessThan));
TRY(s_name_to_key.insert("LShift"sv, Key::LeftShift));
TRY(s_name_to_key.insert("M"sv, Key::M));
TRY(s_name_to_key.insert("MediaNext"sv, Key::MediaNext));
TRY(s_name_to_key.insert("MediaPlayPause"sv, Key::MediaPlayPause));
TRY(s_name_to_key.insert("MediaPrevious"sv, Key::MediaPrevious));
TRY(s_name_to_key.insert("MediaStop"sv, Key::MediaStop));
TRY(s_name_to_key.insert("N"sv, Key::N));
TRY(s_name_to_key.insert("Negation"sv, Key::Negation));
TRY(s_name_to_key.insert("None"sv, Key::None));
TRY(s_name_to_key.insert("NumLock"sv, Key::NumLock));
TRY(s_name_to_key.insert("Numpad0"sv, Key::Numpad0));
TRY(s_name_to_key.insert("Numpad1"sv, Key::Numpad1));
TRY(s_name_to_key.insert("Numpad2"sv, Key::Numpad2));
TRY(s_name_to_key.insert("Numpad3"sv, Key::Numpad3));
TRY(s_name_to_key.insert("Numpad4"sv, Key::Numpad4));
TRY(s_name_to_key.insert("Numpad5"sv, Key::Numpad5));
TRY(s_name_to_key.insert("Numpad6"sv, Key::Numpad6));
TRY(s_name_to_key.insert("Numpad7"sv, Key::Numpad7));
TRY(s_name_to_key.insert("Numpad8"sv, Key::Numpad8));
TRY(s_name_to_key.insert("Numpad9"sv, Key::Numpad9));
TRY(s_name_to_key.insert("NumpadDecimal"sv, Key::NumpadDecimal));
TRY(s_name_to_key.insert("NumpadDivide"sv, Key::NumpadDivide));
TRY(s_name_to_key.insert("NumpadEnter"sv, Key::NumpadEnter));
TRY(s_name_to_key.insert("NumpadMinus"sv, Key::NumpadMinus));
TRY(s_name_to_key.insert("NumpadMultiply"sv, Key::NumpadMultiply));
TRY(s_name_to_key.insert("NumpadPlus"sv, Key::NumpadPlus));
TRY(s_name_to_key.insert("O_Umlaut"sv, Key::O_Umlaut));
TRY(s_name_to_key.insert("O"sv, Key::O));
TRY(s_name_to_key.insert("OpenCurlyBracket"sv, Key::OpenCurlyBracket));
TRY(s_name_to_key.insert("OpenParenthesis"sv, Key::OpenParenthesis));
TRY(s_name_to_key.insert("OpenSquareBracket"sv, Key::OpenSquareBracket));
TRY(s_name_to_key.insert("P"sv, Key::P));
TRY(s_name_to_key.insert("PageDown"sv, Key::PageDown));
TRY(s_name_to_key.insert("PageUp"sv, Key::PageUp));
TRY(s_name_to_key.insert("Percent"sv, Key::Percent));
TRY(s_name_to_key.insert("Period"sv, Key::Period));
TRY(s_name_to_key.insert("Pipe"sv, Key::Pipe));
TRY(s_name_to_key.insert("Plus"sv, Key::Plus));
TRY(s_name_to_key.insert("Pound"sv, Key::Pound));
TRY(s_name_to_key.insert("PrintScreen"sv, Key::PrintScreen));
TRY(s_name_to_key.insert("Q"sv, Key::Q));
TRY(s_name_to_key.insert("Question"sv, Key::QuestionMark));
TRY(s_name_to_key.insert("QuestionMark"sv, Key::QuestionMark));
TRY(s_name_to_key.insert("R"sv, Key::R));
TRY(s_name_to_key.insert("RAlt"sv, Key::RightAlt));
TRY(s_name_to_key.insert("RControl"sv, Key::RightCtrl));
TRY(s_name_to_key.insert("RightAlt"sv, Key::RightAlt));
TRY(s_name_to_key.insert("RightControl"sv, Key::RightCtrl));
TRY(s_name_to_key.insert("RightShift"sv, Key::RightShift));
TRY(s_name_to_key.insert("RShift"sv, Key::RightShift));
TRY(s_name_to_key.insert("S"sv, Key::S));
TRY(s_name_to_key.insert("ScrollLock"sv, Key::ScrollLock));
TRY(s_name_to_key.insert("Section"sv, Key::Section));
TRY(s_name_to_key.insert("Semicolon"sv, Key::Semicolon));
TRY(s_name_to_key.insert("SingleQuote"sv, Key::SingleQuote));
TRY(s_name_to_key.insert("Slash"sv, Key::Slash));
TRY(s_name_to_key.insert("Space"sv, Key::Space));
TRY(s_name_to_key.insert("Super"sv, Key::Super));
TRY(s_name_to_key.insert("T"sv, Key::T));
TRY(s_name_to_key.insert("Tab"sv, Key::Tab));
TRY(s_name_to_key.insert("Tilde"sv, Key::Tilde));
TRY(s_name_to_key.insert("TwoDots"sv, Key::TwoDots));
TRY(s_name_to_key.insert("U"sv, Key::U));
TRY(s_name_to_key.insert("Underscore"sv, Key::Underscore));
TRY(s_name_to_key.insert("V"sv, Key::V));
TRY(s_name_to_key.insert("VolumeDown"sv, Key::VolumeDown));
TRY(s_name_to_key.insert("VolumeMute"sv, Key::VolumeMute));
TRY(s_name_to_key.insert("VolumeUp"sv, Key::VolumeUp));
TRY(s_name_to_key.insert("W"sv, Key::W));
TRY(s_name_to_key.insert("X"sv, Key::X));
TRY(s_name_to_key.insert("Y"sv, Key::Y));
TRY(s_name_to_key.insert("Z"sv, Key::Z));
return {};
}
#pragma GCC diagnostic pop
}

View File

@@ -0,0 +1,106 @@
#pragma once
#include <stdint.h>
namespace LibInput
{
/*
Key Code:
bits 4:0 column (from left)
bits 7:5 row (from top)
*/
#define BANAN_CONSTEVAL_STATIC_ASSERT(cond) do { int dummy = 1 / (cond); } while (false)
consteval uint8_t keycode_function(uint8_t index)
{
BANAN_CONSTEVAL_STATIC_ASSERT(index <= 0b11111);
return index;
}
consteval uint8_t keycode_normal(uint8_t row, uint8_t col)
{
BANAN_CONSTEVAL_STATIC_ASSERT(row <= 0b111 - 1);
BANAN_CONSTEVAL_STATIC_ASSERT(col < 0b11111 - 8);
return ((row + 1) << 5) | col;
}
consteval uint8_t keycode_numpad(uint8_t row, uint8_t col)
{
BANAN_CONSTEVAL_STATIC_ASSERT(row <= 0b111 - 1);
BANAN_CONSTEVAL_STATIC_ASSERT(col <= 8);
return ((row + 1) << 5) | (col + 0b11111 - 8);
}
enum class Key
{
Invalid, None,
A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z,
A_Ring, A_Umlaut, O_Umlaut,
_0, _1, _2, _3, _4, _5, _6, _7, _8, _9,
F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12,
Insert, PrintScreen, Delete, Home, End, PageUp, PageDown, Enter, Space,
ExclamationMark, DoubleQuote, Hashtag, Currency, Percent, Ampersand, Slash, Section, Half,
OpenParenthesis, CloseParenthesis, OpenSquareBracket, CloseSquareBracket, OpenCurlyBracket, CloseCurlyBracket,
Equals, QuestionMark, Plus, BackSlash, Acute, BackTick, TwoDots, Cedilla, Backspace, AtSign, Pound, Dollar, Euro,
Escape, Tab, CapsLock, LeftShift, LeftCtrl, Super, LeftAlt, RightAlt, AltGr = RightAlt, RightCtrl, RightShift,
SingleQuote, Asterix, Caret, Tilde, ArrowUp, ArrowDown, ArrowLeft, ArrowRight,
Comma, Semicolon, Period, Colon, Hyphen, Underscore, NumLock, ScrollLock, LessThan, GreaterThan, Pipe, Negation, BrokenBar,
Numpad0, Numpad1, Numpad2, Numpad3, Numpad4, Numpad5, Numpad6, Numpad7, Numpad8, Numpad9,
NumpadPlus, NumpadMinus, NumpadMultiply, NumpadDivide, NumpadEnter, NumpadDecimal,
VolumeMute, VolumeUp, VolumeDown, Calculator, MediaPlayPause, MediaStop, MediaPrevious, MediaNext,
Count,
};
// KeyEvent with general keycode
struct RawKeyEvent
{
uint16_t modifier;
uint8_t keycode;
};
// KeyEvent with key parsed from keycode
struct KeyEvent
{
enum Modifier : uint16_t
{
LShift = (1 << 0),
RShift = (1 << 1),
LCtrl = (1 << 2),
RCtrl = (1 << 3),
LAlt = (1 << 4),
RAlt = (1 << 5),
CapsLock = (1 << 6),
NumLock = (1 << 7),
ScrollLock = (1 << 8),
Pressed = (1 << 9),
};
bool lshift() const { return modifier & Modifier::LShift; }
bool rshift() const { return modifier & Modifier::RShift; }
bool shift() const { return lshift() || rshift(); }
bool lctrl() const { return modifier & Modifier::LCtrl; }
bool rctrl() const { return modifier & Modifier::RCtrl; }
bool ctrl() const { return lctrl() || rctrl(); }
bool lalt() const { return modifier & Modifier::LAlt; }
bool ralt() const { return modifier & Modifier::RAlt; }
bool alt() const { return lalt() || ralt(); }
bool caps_lock() const { return modifier & Modifier::CapsLock; }
bool num_lock() const { return modifier & Modifier::NumLock; }
bool scroll_lock() const { return modifier & Modifier::ScrollLock; }
bool pressed() const { return modifier & Modifier::Pressed; }
bool released() const { return !pressed(); }
uint16_t modifier;
Key key;
};
const char* key_to_utf8(Key key, uint16_t modifier);
const char* key_to_utf8_ansi(Key key, uint16_t modifier);
}

View File

@@ -0,0 +1,30 @@
#pragma once
#include <BAN/Array.h>
#include <BAN/StringView.h>
#include <BAN/UniqPtr.h>
#include <LibInput/KeyEvent.h>
namespace LibInput
{
class KeyboardLayout
{
public:
static BAN::ErrorOr<void> initialize();
static KeyboardLayout& get();
KeyEvent key_event_from_raw(RawKeyEvent);
BAN::ErrorOr<void> load_from_file(BAN::StringView path);
private:
KeyboardLayout();
private:
BAN::Array<Key, 0xFF> m_keycode_to_key_normal;
BAN::Array<Key, 0xFF> m_keycode_to_key_shift;
BAN::Array<Key, 0xFF> m_keycode_to_key_altgr;
friend class BAN::UniqPtr<KeyboardLayout>;
};
}

View File

@@ -0,0 +1,48 @@
#pragma once
#include <stdint.h>
namespace LibInput
{
enum class MouseButton
{
Left, Right, Middle, Extra1, Extra2
};
struct MouseButtonEvent
{
MouseButton button;
bool pressed;
};
struct MouseMoveEvent
{
int32_t rel_x;
int32_t rel_y;
};
struct MouseScrollEvent
{
int32_t scroll;
};
enum class MouseEventType
{
MouseButtonEvent,
MouseMoveEvent,
MouseScrollEvent,
};
struct MouseEvent
{
MouseEventType type;
union
{
MouseButtonEvent button_event;
MouseMoveEvent move_event;
MouseScrollEvent scroll_event;
};
};
}