diff options
Diffstat (limited to 'Kernel/Devices/HID/KeyboardDevice.cpp')
-rw-r--r-- | Kernel/Devices/HID/KeyboardDevice.cpp | 100 |
1 files changed, 75 insertions, 25 deletions
diff --git a/Kernel/Devices/HID/KeyboardDevice.cpp b/Kernel/Devices/HID/KeyboardDevice.cpp index e71dc7143a..7daf6335b3 100644 --- a/Kernel/Devices/HID/KeyboardDevice.cpp +++ b/Kernel/Devices/HID/KeyboardDevice.cpp @@ -1,6 +1,6 @@ /* * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> - * Copyright (c) 2021, Liav A. <liavalb@hotmail.co.il> + * Copyright (c) 2021-2023, Liav A. <liavalb@hotmail.co.il> * Copyright (c) 2021, Edwin Hoksberg <mail@edwinhoksberg.nl> * * SPDX-License-Identifier: BSD-2-Clause @@ -9,9 +9,14 @@ #include <AK/Assertions.h> #include <AK/Types.h> #include <Kernel/API/Ioctl.h> +#include <Kernel/API/KeyCode.h> +#include <Kernel/Devices/DeviceManagement.h> #include <Kernel/Devices/HID/KeyboardDevice.h> +#include <Kernel/Scheduler.h> #include <Kernel/Sections.h> +#include <Kernel/TTY/ConsoleManagement.h> #include <Kernel/TTY/VirtualConsole.h> +#include <Kernel/WorkQueue.h> namespace Kernel { @@ -209,16 +214,58 @@ static constexpr KeyCode shifted_key_map[0x100] = { Key_Menu, }; -void KeyboardDevice::key_state_changed(u8 scan_code, bool pressed) +void KeyboardDevice::handle_scan_code_input_event(ScanCodeEvent event) { - KeyCode key = (m_modifiers & Mod_Shift) ? shifted_key_map[scan_code] : unshifted_key_map[scan_code]; + m_entropy_source.add_random_event(event.scan_code_value); + switch (event.scan_code_value) { + case 0x38: + if (event.e0_prefix) + update_modifier(Mod_AltGr, event.pressed); + else + update_modifier(Mod_Alt, event.pressed); + break; + case 0x1d: + update_modifier(Mod_Ctrl, event.pressed); + break; + case 0x5b: + m_left_super_pressed = event.pressed; + update_modifier(Mod_Super, m_left_super_pressed || m_right_super_pressed); + break; + case 0x5c: + m_right_super_pressed = event.pressed; + update_modifier(Mod_Super, m_left_super_pressed || m_right_super_pressed); + break; + case 0x2a: + m_left_shift_pressed = event.pressed; + update_modifier(Mod_Shift, m_left_shift_pressed || m_right_shift_pressed); + break; + case 0x36: + m_right_shift_pressed = event.pressed; + update_modifier(Mod_Shift, m_left_shift_pressed || m_right_shift_pressed); + break; + } + + KeyCode key = (m_modifiers & Mod_Shift) ? shifted_key_map[event.scan_code_value] : unshifted_key_map[event.scan_code_value]; + + if ((m_modifiers == (Mod_Alt | Mod_Shift) || m_modifiers == (Mod_Ctrl | Mod_Alt | Mod_Shift)) && key == Key_F12) { + // Alt+Shift+F12 pressed, dump some kernel state to the debug console. + ConsoleManagement::the().switch_to_debug(); + Scheduler::dump_scheduler_state(m_modifiers == (Mod_Ctrl | Mod_Alt | Mod_Shift)); + } - if (key == Key_NumLock && pressed) + if ((m_modifiers & Mod_Alt) != 0 && key >= Key_1 && key <= Key_1 + ConsoleManagement::s_max_virtual_consoles + 1) { + // FIXME: Do something sanely here if we can't allocate a work queue? + MUST(g_io_work->try_queue([key]() { + ConsoleManagement::the().switch_to(key - Key_1); + })); + } + + if (key == Key_NumLock && event.pressed) m_num_lock_on = !m_num_lock_on; - if (m_num_lock_on && !m_has_e0_prefix) { - if (scan_code >= 0x47 && scan_code <= 0x53) { - u8 index = scan_code - 0x47; + if (m_num_lock_on && !event.e0_prefix) { + if (event.scan_code_value >= 0x47 && event.scan_code_value <= 0x53) { + u8 index = event.scan_code_value - 0x47; constexpr KeyCode numpad_key_map[13] = { Key_7, Key_8, Key_9, Key_Invalid, Key_4, Key_5, Key_6, Key_Invalid, Key_1, Key_2, Key_3, Key_0, Key_Comma }; KeyCode newKey = numpad_key_map[index]; @@ -228,48 +275,51 @@ void KeyboardDevice::key_state_changed(u8 scan_code, bool pressed) } } - Event event; - event.key = key; - event.scancode = m_has_e0_prefix ? 0xe000 + scan_code : scan_code; - event.flags = m_modifiers; - event.e0_prefix = m_has_e0_prefix; - event.caps_lock_on = m_caps_lock_on; - event.code_point = HIDManagement::the().get_char_from_character_map(event); + Event queued_event; + queued_event.key = key; + queued_event.scancode = event.e0_prefix ? 0xe000 + event.scan_code_value : event.scan_code_value; + queued_event.flags = m_modifiers; + queued_event.e0_prefix = event.e0_prefix; + queued_event.caps_lock_on = m_caps_lock_on; + queued_event.code_point = HIDManagement::the().get_char_from_character_map(queued_event); - // If using a non-QWERTY layout, event.key needs to be updated to be the same as event.code_point - KeyCode mapped_key = code_point_to_key_code(event.code_point); + // If using a non-QWERTY layout, queued_event.key needs to be updated to be the same as event.code_point + KeyCode mapped_key = code_point_to_key_code(queued_event.code_point); if (mapped_key != KeyCode::Key_Invalid) { - event.key = mapped_key; + queued_event.key = mapped_key; key = mapped_key; } - if (!g_caps_lock_remapped_to_ctrl && key == Key_CapsLock && pressed) + if (!g_caps_lock_remapped_to_ctrl && key == Key_CapsLock && event.pressed) m_caps_lock_on = !m_caps_lock_on; if (g_caps_lock_remapped_to_ctrl && key == Key_CapsLock) { - m_caps_lock_to_ctrl_pressed = pressed; + m_caps_lock_to_ctrl_pressed = event.pressed; update_modifier(Mod_Ctrl, m_caps_lock_to_ctrl_pressed); } - if (pressed) - event.flags |= Is_Press; + if (event.pressed) + queued_event.flags |= Is_Press; { SpinlockLocker locker(HIDManagement::the().m_client_lock); if (HIDManagement::the().m_client) - HIDManagement::the().m_client->on_key_pressed(event); + HIDManagement::the().m_client->on_key_pressed(queued_event); } { SpinlockLocker lock(m_queue_lock); - m_queue.enqueue(event); + m_queue.enqueue(queued_event); } - m_has_e0_prefix = false; - evaluate_block_conditions(); } +ErrorOr<NonnullRefPtr<KeyboardDevice>> KeyboardDevice::try_to_initialize() +{ + return *TRY(DeviceManagement::try_create_device<KeyboardDevice>()); +} + // FIXME: UNMAP_AFTER_INIT is fine for now, but for hot-pluggable devices // like USB keyboards, we need to remove this UNMAP_AFTER_INIT KeyboardDevice::KeyboardDevice() |