From db933d5466943dc669dbdd3c1e180fc7f3e841af Mon Sep 17 00:00:00 2001 From: Bananymous Date: Thu, 11 Jan 2024 13:27:34 +0200 Subject: [PATCH] Kernel: Improve keymap file loading Now you can include other files in keymaps and set which keys are modifier keys Only keys that are set in keymap file are actually updated --- base-sysroot.tar.gz | Bin 631567 -> 631644 bytes kernel/kernel/Input/KeyboardLayout.cpp | 121 +++++++++++++++++++++---- 2 files changed, 103 insertions(+), 18 deletions(-) diff --git a/base-sysroot.tar.gz b/base-sysroot.tar.gz index 8cee689e52e5e7266679df1de2583118622bbc60..9de7dd100e77a0af8607649b5d0eccd0c8cc31c7 100644 GIT binary patch delta 4854 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 Ygq(kyN&SE5T+4KQcwOC!%L2^xKkOCwh5!Hn delta 4777 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 diff --git a/kernel/kernel/Input/KeyboardLayout.cpp b/kernel/kernel/Input/KeyboardLayout.cpp index 3fdfa83f..fa58b24a 100644 --- a/kernel/kernel/Input/KeyboardLayout.cpp +++ b/kernel/kernel/Input/KeyboardLayout.cpp @@ -107,18 +107,15 @@ namespace Kernel::Input return {}; } - BAN::ErrorOr KeyboardLayout::load_from_file(BAN::StringView path) + static BAN::ErrorOr> load_keymap_lines_and_parse_includes(BAN::StringView path) { - if (s_name_to_key.empty()) - TRY(initialize_name_to_key()); - - auto inode = TRY(VirtualFileSystem::get().file_from_absolute_path({ 0, 0, 0, 0 }, path, 0)).inode; + auto file = TRY(VirtualFileSystem::get().file_from_absolute_path({ 0, 0, 0, 0 }, path, 0)); BAN::String file_data; - TRY(file_data.resize(inode->size())); - TRY(inode->read(0, { reinterpret_cast(file_data.data()), file_data.size() })); + TRY(file_data.resize(file.inode->size())); + TRY(file.inode->read(0, BAN::ByteSpan { reinterpret_cast(file_data.data()), file_data.size() })); - auto new_layout = TRY(BAN::UniqPtr::create()); + BAN::Vector result; auto lines = TRY(file_data.sv().split('\n')); for (auto line : lines) @@ -127,10 +124,89 @@ namespace Kernel::Input 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(file.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 KeyboardLayout::load_from_file(BAN::StringView path) + { + if (s_name_to_key.empty()) + TRY(initialize_name_to_key()); + + auto new_layout = TRY(BAN::UniqPtr::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; } @@ -138,14 +214,14 @@ namespace Kernel::Input if (!keycode.has_value()) { dprintln("Invalid keycode '{}', keycode must number between [0, 0xFF[", parts.front()); - continue; + return BAN::Error::from_errno(EINVAL); } auto default_key = parse_key(parts[1]); if (!default_key.has_value()) { dprintln("Unrecognized key '{}'", parts[1]); - continue; + return BAN::Error::from_errno(EINVAL); } new_layout->m_keycode_to_key_normal[*keycode] = *default_key; @@ -158,32 +234,41 @@ namespace Kernel::Input if (pair.size() != 2) { dprintln("Invalid modifier format '{}', modifier format: MODIFIRER=KEY", parts[i]); - continue; + return BAN::Error::from_errno(EINVAL); } auto key = parse_key(pair.back()); if (!key.has_value()) { dprintln("Unrecognized key '{}'", pair.back()); - continue; + return BAN::Error::from_errno(EINVAL); } - if (pair.front() == "shift"sv) + if (shift_is_mod && pair.front() == "shift"sv) new_layout->m_keycode_to_key_shift[*keycode] = *key; - else if (pair.front() == "altgr"sv) + else if (altgr_is_mod && pair.front() == "altgr"sv) new_layout->m_keycode_to_key_altgr[*keycode] = *key; else { dprintln("Unrecognized modifier '{}'", pair.front()); - continue; + return BAN::Error::from_errno(EINVAL); } } } CriticalScope _; - m_keycode_to_key_normal = new_layout->m_keycode_to_key_normal; - m_keycode_to_key_shift = new_layout->m_keycode_to_key_shift; - m_keycode_to_key_altgr = new_layout->m_keycode_to_key_altgr; + + 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 {}; }