1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-25 18:47:34 +00:00

Kernel+Userland: Implement support for PS2 scan code set 2

This scan code set is more advanced than the basic scan code set 1, and
is required to be supported for some bare metal hardware that might not
properly enable the PS2 first port translation in the i8042 controller.

LibWeb can now also generate bindings for keyboard events like the Pause
key, as well as other function keys (such as Right Alt, etc).

The logic for handling scan code sets is implemented by the PS2 keyboard
driver and is abstracted from the main HID KeyboardDevice code which
only handles "standard" KeyEvent(s).
This commit is contained in:
Liav A 2023-12-30 06:19:04 +02:00 committed by Andrew Kaster
parent cae184d7cf
commit c8f27d7cb8
12 changed files with 991 additions and 439 deletions

View file

@ -20,309 +20,46 @@
namespace Kernel {
static constexpr KeyCode unshifted_key_map[0x80] = {
Key_Invalid,
Key_Escape,
Key_1,
Key_2,
Key_3,
Key_4,
Key_5,
Key_6,
Key_7,
Key_8,
Key_9,
Key_0,
Key_Minus,
Key_Equal,
Key_Backspace,
Key_Tab, // 15
Key_Q,
Key_W,
Key_E,
Key_R,
Key_T,
Key_Y,
Key_U,
Key_I,
Key_O,
Key_P,
Key_LeftBracket,
Key_RightBracket,
Key_Return, // 28
Key_Control, // 29
Key_A,
Key_S,
Key_D,
Key_F,
Key_G,
Key_H,
Key_J,
Key_K,
Key_L,
Key_Semicolon,
Key_Apostrophe,
Key_Backtick,
Key_LeftShift, // 42
Key_Backslash,
Key_Z,
Key_X,
Key_C,
Key_V,
Key_B,
Key_N,
Key_M,
Key_Comma,
Key_Period,
Key_Slash,
Key_RightShift, // 54
Key_Asterisk,
Key_Alt, // 56
Key_Space, // 57
Key_CapsLock, // 58
Key_F1,
Key_F2,
Key_F3,
Key_F4,
Key_F5,
Key_F6,
Key_F7,
Key_F8,
Key_F9,
Key_F10,
Key_NumLock,
Key_Invalid, // 70
Key_Home,
Key_Up,
Key_PageUp,
Key_Minus,
Key_Left,
Key_Invalid,
Key_Right, // 77
Key_Plus,
Key_End,
Key_Down, // 80
Key_PageDown,
Key_Insert,
Key_Delete, // 83
Key_Invalid,
Key_Invalid,
Key_Backslash,
Key_F11,
Key_F12,
Key_Invalid,
Key_Invalid,
Key_Super,
Key_Invalid,
Key_Menu,
};
static constexpr KeyCode shifted_key_map[0x100] = {
Key_Invalid,
Key_Escape,
Key_ExclamationPoint,
Key_AtSign,
Key_Hashtag,
Key_Dollar,
Key_Percent,
Key_Circumflex,
Key_Ampersand,
Key_Asterisk,
Key_LeftParen,
Key_RightParen,
Key_Underscore,
Key_Plus,
Key_Backspace,
Key_Tab,
Key_Q,
Key_W,
Key_E,
Key_R,
Key_T,
Key_Y,
Key_U,
Key_I,
Key_O,
Key_P,
Key_LeftBrace,
Key_RightBrace,
Key_Return,
Key_Control,
Key_A,
Key_S,
Key_D,
Key_F,
Key_G,
Key_H,
Key_J,
Key_K,
Key_L,
Key_Colon,
Key_DoubleQuote,
Key_Tilde,
Key_LeftShift, // 42
Key_Pipe,
Key_Z,
Key_X,
Key_C,
Key_V,
Key_B,
Key_N,
Key_M,
Key_LessThan,
Key_GreaterThan,
Key_QuestionMark,
Key_RightShift, // 54
Key_Asterisk,
Key_Alt,
Key_Space, // 57
Key_CapsLock, // 58
Key_F1,
Key_F2,
Key_F3,
Key_F4,
Key_F5,
Key_F6,
Key_F7,
Key_F8,
Key_F9,
Key_F10,
Key_NumLock,
Key_Invalid, // 70
Key_Home,
Key_Up,
Key_PageUp,
Key_Minus,
Key_Left,
Key_Invalid,
Key_Right, // 77
Key_Plus,
Key_End,
Key_Down, // 80
Key_PageDown,
Key_Insert,
Key_Delete, // 83
Key_Invalid,
Key_Invalid,
Key_Pipe,
Key_F11,
Key_F12,
Key_Invalid,
Key_Invalid,
Key_Super,
Key_Invalid,
Key_Menu,
};
void KeyboardDevice::handle_scan_code_input_event(ScanCodeEvent event)
void KeyboardDevice::handle_input_event(KeyEvent queued_event)
{
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;
case 0x1c:
case 0x35:
if (event.e0_prefix)
update_modifier(Mod_Keypad, event.pressed);
break;
case 0x37:
case 0x47:
case 0x48:
case 0x49:
case 0x4a:
case 0x4b:
case 0x4c:
case 0x4d:
case 0x4e:
case 0x4f:
case 0x50:
case 0x51:
case 0x52:
case 0x53:
if (!event.e0_prefix)
update_modifier(Mod_Keypad, event.pressed);
break;
}
if (queued_event.key == Key_NumLock && queued_event.is_press())
m_num_lock_on = !m_num_lock_on;
KeyCode key = (m_modifiers & Mod_Shift) ? shifted_key_map[event.scan_code_value] : unshifted_key_map[event.scan_code_value];
queued_event.flags |= m_modifiers;
if ((m_modifiers == (Mod_Alt | Mod_Shift) || m_modifiers == (Mod_Ctrl | Mod_Alt | Mod_Shift)) && key == Key_F12) {
if (queued_event.is_press() && (m_modifiers == (Mod_Alt | Mod_Shift) || m_modifiers == (Mod_Ctrl | Mod_Alt | Mod_Shift)) && queued_event.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 ((m_modifiers & Mod_Alt) != 0 && key >= Key_1 && key < Key_1 + ConsoleManagement::s_max_virtual_consoles) {
// 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 && !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];
if (newKey != Key_Invalid) {
key = newKey;
}
{
auto key = queued_event.key;
if (queued_event.is_press() && (m_modifiers & Mod_Alt) != 0 && key >= Key_1 && key < Key_1 + ConsoleManagement::s_max_virtual_consoles) {
// 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);
}));
}
}
Event queued_event;
queued_event.key = key;
queued_event.map_entry_index = event.scan_code_value & 0xFF;
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, m_num_lock_on);
// 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) {
if (mapped_key != KeyCode::Key_Invalid)
queued_event.key = mapped_key;
key = mapped_key;
}
if (!g_caps_lock_remapped_to_ctrl && key == Key_CapsLock && event.pressed)
if (!g_caps_lock_remapped_to_ctrl && queued_event.key == Key_CapsLock && queued_event.is_press())
m_caps_lock_on = !m_caps_lock_on;
if (g_caps_lock_remapped_to_ctrl && key == Key_CapsLock) {
m_caps_lock_to_ctrl_pressed = event.pressed;
queued_event.caps_lock_on = m_caps_lock_on;
if (g_caps_lock_remapped_to_ctrl && queued_event.key == Key_CapsLock) {
m_caps_lock_to_ctrl_pressed = queued_event.is_press();
update_modifier(Mod_Ctrl, m_caps_lock_to_ctrl_pressed);
}
if (event.pressed)
queued_event.flags |= Is_Press;
if (queued_event.map_entry_index != 0xFF)
queued_event.code_point = HIDManagement::the().get_char_from_character_map(queued_event, queued_event.map_entry_index);
{
SpinlockLocker locker(HIDManagement::the().m_client_lock);