From e30952efee87cc8a63ba5ce415b891dd84b94514 Mon Sep 17 00:00:00 2001 From: Bananymous Date: Tue, 16 Jul 2024 11:23:44 +0300 Subject: [PATCH] Kernel: Implement key repeating for USB keyboard USB keyboards don't send repeating keys automatically, so it has to be emulated in software. --- kernel/include/kernel/USB/HID/Keyboard.h | 9 ++ kernel/kernel/USB/HID/Keyboard.cpp | 129 +++++++++++++++++++---- 2 files changed, 118 insertions(+), 20 deletions(-) diff --git a/kernel/include/kernel/USB/HID/Keyboard.h b/kernel/include/kernel/USB/HID/Keyboard.h index f91f1989..7a738e36 100644 --- a/kernel/include/kernel/USB/HID/Keyboard.h +++ b/kernel/include/kernel/USB/HID/Keyboard.h @@ -17,6 +17,8 @@ namespace Kernel void handle_variable(uint16_t usage_page, uint16_t usage, int64_t state) override; void handle_array(uint16_t usage_page, uint16_t usage) override; + void update() override; + private: USBKeyboard() : USBHIDDevice(InputDevice::Type::Keyboard) @@ -24,10 +26,17 @@ namespace Kernel ~USBKeyboard() = default; private: + SpinLock m_keyboard_lock; + InterruptState m_lock_state; + BAN::Array m_keyboard_state { false }; BAN::Array m_keyboard_state_temp { false }; uint8_t m_toggle_mask { 0 }; + BAN::Optional m_repeat_scancode; + uint8_t m_repeat_modifier { 0 }; + uint64_t m_next_repeat_event_ms { 0 }; + friend class BAN::RefPtr; }; diff --git a/kernel/kernel/USB/HID/Keyboard.cpp b/kernel/kernel/USB/HID/Keyboard.cpp index 40b96baf..d9bb5b70 100644 --- a/kernel/kernel/USB/HID/Keyboard.cpp +++ b/kernel/kernel/USB/HID/Keyboard.cpp @@ -1,3 +1,4 @@ +#include #include #include @@ -6,13 +7,18 @@ namespace Kernel { + static constexpr uint64_t s_repeat_initial_ms = 500; + static constexpr uint64_t s_repeat_interval_ms = 50; + static BAN::Optional s_scancode_to_keycode[0x100] {}; static bool s_scancode_to_keycode_initialized = false; static void initialize_scancode_to_keycode(); + static constexpr bool is_repeatable_scancode(uint8_t scancode); void USBKeyboard::start_report() { + m_lock_state = m_keyboard_lock.lock(); for (auto& val : m_keyboard_state_temp) val = false; } @@ -28,37 +34,39 @@ namespace Kernel // Modifier should be determined when converting to KeyEvent. uint8_t modifier = 0; - if (m_keyboard_state_temp[0xE1]) - modifier |= KeyModifier::LShift; - if (m_keyboard_state_temp[0xE5]) - modifier |= KeyModifier::RShift; - if (m_keyboard_state_temp[0xE0]) - modifier |= KeyModifier::LCtrl; - if (m_keyboard_state_temp[0xE4]) - modifier |= KeyModifier::RCtrl; - if (m_keyboard_state_temp[0xE2]) - modifier |= KeyModifier::LAlt; - if (m_keyboard_state_temp[0xE6]) - modifier |= KeyModifier::RAlt; - if (m_keyboard_state_temp[0x39] && !m_keyboard_state[0x39]) - m_toggle_mask ^= KeyModifier::CapsLock; - if (m_keyboard_state_temp[0x47] && !m_keyboard_state[0x47]) - m_toggle_mask ^= KeyModifier::ScrollLock; - if (m_keyboard_state_temp[0x53] && !m_keyboard_state[0x53]) - m_toggle_mask ^= KeyModifier::NumLock; +#define READ_MODIFIER(scancode, key_modifier) \ + if (m_keyboard_state_temp[scancode]) \ + modifier |= key_modifier; + READ_MODIFIER(0xE1, KeyModifier::LShift); + READ_MODIFIER(0xE5, KeyModifier::RShift); + READ_MODIFIER(0xE0, KeyModifier::LCtrl); + READ_MODIFIER(0xE4, KeyModifier::RCtrl); + READ_MODIFIER(0xE2, KeyModifier::LAlt); + READ_MODIFIER(0xE6, KeyModifier::RAlt); +#undef READ_MODIFIER + +#define READ_TOGGLE(scancode, key_modifier) \ + if (m_keyboard_state_temp[scancode] && !m_keyboard_state[scancode]) \ + m_toggle_mask ^= key_modifier; + READ_TOGGLE(0x39, KeyModifier::CapsLock); + READ_TOGGLE(0x47, KeyModifier::ScrollLock); + READ_TOGGLE(0x53, KeyModifier::NumLock); +#undef READ_TOGGLE modifier |= m_toggle_mask; + BAN::Optional new_scancode; for (size_t i = 0; i < m_keyboard_state.size(); i++) { if (m_keyboard_state[i] == m_keyboard_state_temp[i]) continue; + if (m_keyboard_state_temp[i] && is_repeatable_scancode(i)) + new_scancode = i; const bool pressed = m_keyboard_state_temp[i]; - if (pressed) - dprintln_if(DEBUG_KEYBOARD, "{2H}", i); + dprintln_if(DEBUG_KEYBOARD, "Pressed {2H}", i); auto opt_keycode = s_scancode_to_keycode[i]; if (opt_keycode.has_value()) @@ -71,10 +79,27 @@ namespace Kernel m_keyboard_state[i] = m_keyboard_state_temp[i]; } + + if (m_repeat_scancode.has_value() && !m_keyboard_state_temp[m_repeat_scancode.value()]) + m_repeat_scancode.clear(); + m_repeat_modifier = modifier; + + if (new_scancode.has_value()) + { + if (!m_repeat_scancode.has_value() || m_repeat_scancode.value() != new_scancode.value()) + { + m_repeat_scancode = new_scancode; + m_next_repeat_event_ms = SystemTimer::get().ms_since_boot() + s_repeat_initial_ms; + } + } + + m_keyboard_lock.unlock(m_lock_state); } void USBKeyboard::handle_variable(uint16_t usage_page, uint16_t usage, int64_t state) { + ASSERT(m_keyboard_lock.current_processor_has_lock()); + if (usage_page != 0x07) { dprintln_if(DEBUG_KEYBOARD, "Unsupported keyboard usage page {2H}", usage_page); @@ -88,6 +113,8 @@ namespace Kernel void USBKeyboard::handle_array(uint16_t usage_page, uint16_t usage) { + ASSERT(m_keyboard_lock.current_processor_has_lock()); + if (usage_page != 0x07) { dprintln_if(DEBUG_KEYBOARD, "Unsupported keyboard usage page {2H}", usage_page); @@ -97,12 +124,36 @@ namespace Kernel m_keyboard_state_temp[usage] = true; } + void USBKeyboard::update() + { + using KeyModifier = LibInput::KeyEvent::Modifier; + + SpinLockGuard _(m_keyboard_lock); + + if (!m_repeat_scancode.has_value() || SystemTimer::get().ms_since_boot() < m_next_repeat_event_ms) + return; + + auto opt_keycode = s_scancode_to_keycode[m_repeat_scancode.value()]; + if (!opt_keycode.has_value()) + return; + + LibInput::RawKeyEvent event; + event.keycode = opt_keycode.value(); + event.modifier = m_repeat_modifier | KeyModifier::Pressed; + add_event(BAN::ConstByteSpan::from(event)); + + m_next_repeat_event_ms += s_repeat_interval_ms; + } + void initialize_scancode_to_keycode() { using LibInput::keycode_function; using LibInput::keycode_normal; using LibInput::keycode_numpad; + for (auto& mapping : s_scancode_to_keycode) + mapping.clear(); + s_scancode_to_keycode[0x35] = keycode_normal(0, 0); s_scancode_to_keycode[0x1E] = keycode_normal(0, 1); s_scancode_to_keycode[0x1F] = keycode_normal(0, 2); @@ -211,4 +262,42 @@ namespace Kernel s_scancode_to_keycode_initialized = true; } + constexpr bool is_repeatable_scancode(uint8_t scancode) + { + switch (scancode) + { + case 0x00: // reserved + case 0x01: // error roll over + case 0x02: // post fail + case 0x03: // error undefined + case 0x29: // escape + case 0x39: // caps lock + case 0x3A: // f1 + case 0x3B: // f2 + case 0x3C: // f3 + case 0x3D: // f4 + case 0x3E: // f5 + case 0x3F: // f6 + case 0x40: // f7 + case 0x41: // f8 + case 0x42: // f9 + case 0x43: // f10 + case 0x44: // f11 + case 0x45: // f12 + case 0x47: // scroll lock + case 0x53: // num lock + case 0xE0: // left control + case 0xE1: // left shift + case 0xE2: // left alt + case 0xE3: // left super + case 0xE4: // right control + case 0xE5: // right shift + case 0xE6: // right alt + case 0xE7: // right super + return false; + default: + return true; + } + } + }