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

@ -8,113 +8,140 @@
#include <AK/Types.h>
#define ENUMERATE_KEY_CODES \
__ENUMERATE_KEY_CODE(Invalid, "Invalid") \
__ENUMERATE_KEY_CODE(Escape, "Escape") \
__ENUMERATE_KEY_CODE(Tab, "Tab") \
__ENUMERATE_KEY_CODE(Backspace, "Backspace") \
__ENUMERATE_KEY_CODE(Return, "Return") \
__ENUMERATE_KEY_CODE(Insert, "Insert") \
__ENUMERATE_KEY_CODE(Delete, "Delete") \
__ENUMERATE_KEY_CODE(PrintScreen, "PrintScreen") \
__ENUMERATE_KEY_CODE(SysRq, "SysRq") \
__ENUMERATE_KEY_CODE(Home, "Home") \
__ENUMERATE_KEY_CODE(End, "End") \
__ENUMERATE_KEY_CODE(Left, "Left") \
__ENUMERATE_KEY_CODE(Up, "Up") \
__ENUMERATE_KEY_CODE(Right, "Right") \
__ENUMERATE_KEY_CODE(Down, "Down") \
__ENUMERATE_KEY_CODE(PageUp, "PageUp") \
__ENUMERATE_KEY_CODE(PageDown, "PageDown") \
__ENUMERATE_KEY_CODE(LeftShift, "LeftShift") \
__ENUMERATE_KEY_CODE(RightShift, "RightShift") \
__ENUMERATE_KEY_CODE(Control, "Ctrl") \
__ENUMERATE_KEY_CODE(Alt, "Alt") \
__ENUMERATE_KEY_CODE(CapsLock, "CapsLock") \
__ENUMERATE_KEY_CODE(NumLock, "NumLock") \
__ENUMERATE_KEY_CODE(ScrollLock, "ScrollLock") \
__ENUMERATE_KEY_CODE(F1, "F1") \
__ENUMERATE_KEY_CODE(F2, "F2") \
__ENUMERATE_KEY_CODE(F3, "F3") \
__ENUMERATE_KEY_CODE(F4, "F4") \
__ENUMERATE_KEY_CODE(F5, "F5") \
__ENUMERATE_KEY_CODE(F6, "F6") \
__ENUMERATE_KEY_CODE(F7, "F7") \
__ENUMERATE_KEY_CODE(F8, "F8") \
__ENUMERATE_KEY_CODE(F9, "F9") \
__ENUMERATE_KEY_CODE(F10, "F10") \
__ENUMERATE_KEY_CODE(F11, "F11") \
__ENUMERATE_KEY_CODE(F12, "F12") \
__ENUMERATE_KEY_CODE(Space, "Space") \
__ENUMERATE_KEY_CODE(ExclamationPoint, "!") \
__ENUMERATE_KEY_CODE(DoubleQuote, "\"") \
__ENUMERATE_KEY_CODE(Hashtag, "#") \
__ENUMERATE_KEY_CODE(Dollar, "$") \
__ENUMERATE_KEY_CODE(Percent, "%") \
__ENUMERATE_KEY_CODE(Ampersand, "&") \
__ENUMERATE_KEY_CODE(Apostrophe, "'") \
__ENUMERATE_KEY_CODE(LeftParen, "(") \
__ENUMERATE_KEY_CODE(RightParen, ")") \
__ENUMERATE_KEY_CODE(Asterisk, "*") \
__ENUMERATE_KEY_CODE(Plus, "+") \
__ENUMERATE_KEY_CODE(Comma, ",") \
__ENUMERATE_KEY_CODE(Minus, "-") \
__ENUMERATE_KEY_CODE(Period, ".") \
__ENUMERATE_KEY_CODE(Slash, "/") \
__ENUMERATE_KEY_CODE(0, "0") \
__ENUMERATE_KEY_CODE(1, "1") \
__ENUMERATE_KEY_CODE(2, "2") \
__ENUMERATE_KEY_CODE(3, "3") \
__ENUMERATE_KEY_CODE(4, "4") \
__ENUMERATE_KEY_CODE(5, "5") \
__ENUMERATE_KEY_CODE(6, "6") \
__ENUMERATE_KEY_CODE(7, "7") \
__ENUMERATE_KEY_CODE(8, "8") \
__ENUMERATE_KEY_CODE(9, "9") \
__ENUMERATE_KEY_CODE(Colon, ":") \
__ENUMERATE_KEY_CODE(Semicolon, ";") \
__ENUMERATE_KEY_CODE(LessThan, "<") \
__ENUMERATE_KEY_CODE(Equal, "=") \
__ENUMERATE_KEY_CODE(GreaterThan, ">") \
__ENUMERATE_KEY_CODE(QuestionMark, "?") \
__ENUMERATE_KEY_CODE(AtSign, "@") \
__ENUMERATE_KEY_CODE(A, "A") \
__ENUMERATE_KEY_CODE(B, "B") \
__ENUMERATE_KEY_CODE(C, "C") \
__ENUMERATE_KEY_CODE(D, "D") \
__ENUMERATE_KEY_CODE(E, "E") \
__ENUMERATE_KEY_CODE(F, "F") \
__ENUMERATE_KEY_CODE(G, "G") \
__ENUMERATE_KEY_CODE(H, "H") \
__ENUMERATE_KEY_CODE(I, "I") \
__ENUMERATE_KEY_CODE(J, "J") \
__ENUMERATE_KEY_CODE(K, "K") \
__ENUMERATE_KEY_CODE(L, "L") \
__ENUMERATE_KEY_CODE(M, "M") \
__ENUMERATE_KEY_CODE(N, "N") \
__ENUMERATE_KEY_CODE(O, "O") \
__ENUMERATE_KEY_CODE(P, "P") \
__ENUMERATE_KEY_CODE(Q, "Q") \
__ENUMERATE_KEY_CODE(R, "R") \
__ENUMERATE_KEY_CODE(S, "S") \
__ENUMERATE_KEY_CODE(T, "T") \
__ENUMERATE_KEY_CODE(U, "U") \
__ENUMERATE_KEY_CODE(V, "V") \
__ENUMERATE_KEY_CODE(W, "W") \
__ENUMERATE_KEY_CODE(X, "X") \
__ENUMERATE_KEY_CODE(Y, "Y") \
__ENUMERATE_KEY_CODE(Z, "Z") \
__ENUMERATE_KEY_CODE(LeftBracket, "[") \
__ENUMERATE_KEY_CODE(RightBracket, "]") \
__ENUMERATE_KEY_CODE(Backslash, "\\") \
__ENUMERATE_KEY_CODE(Circumflex, "^") \
__ENUMERATE_KEY_CODE(Underscore, "_") \
__ENUMERATE_KEY_CODE(LeftBrace, "{") \
__ENUMERATE_KEY_CODE(RightBrace, "}") \
__ENUMERATE_KEY_CODE(Pipe, "|") \
__ENUMERATE_KEY_CODE(Tilde, "~") \
__ENUMERATE_KEY_CODE(Backtick, "`") \
__ENUMERATE_KEY_CODE(Super, "Super") \
#define ENUMERATE_KEY_CODES \
__ENUMERATE_KEY_CODE(Invalid, "Invalid") \
__ENUMERATE_KEY_CODE(Escape, "Escape") \
__ENUMERATE_KEY_CODE(Tab, "Tab") \
__ENUMERATE_KEY_CODE(Backspace, "Backspace") \
__ENUMERATE_KEY_CODE(Return, "Return") \
__ENUMERATE_KEY_CODE(Insert, "Insert") \
__ENUMERATE_KEY_CODE(Delete, "Delete") \
__ENUMERATE_KEY_CODE(PrintScreen, "PrintScreen") \
__ENUMERATE_KEY_CODE(PauseBreak, "PauseBreak") \
__ENUMERATE_KEY_CODE(SysRq, "SysRq") \
__ENUMERATE_KEY_CODE(Home, "Home") \
__ENUMERATE_KEY_CODE(End, "End") \
__ENUMERATE_KEY_CODE(Left, "Left") \
__ENUMERATE_KEY_CODE(Up, "Up") \
__ENUMERATE_KEY_CODE(Right, "Right") \
__ENUMERATE_KEY_CODE(Down, "Down") \
__ENUMERATE_KEY_CODE(PageUp, "PageUp") \
__ENUMERATE_KEY_CODE(PageDown, "PageDown") \
__ENUMERATE_KEY_CODE(LeftShift, "LeftShift") \
__ENUMERATE_KEY_CODE(RightShift, "RightShift") \
__ENUMERATE_KEY_CODE(Control, "Ctrl") \
__ENUMERATE_KEY_CODE(RightControl, "RightCtrl") \
__ENUMERATE_KEY_CODE(Alt, "Alt") \
__ENUMERATE_KEY_CODE(RightAlt, "Alt") \
__ENUMERATE_KEY_CODE(CapsLock, "CapsLock") \
__ENUMERATE_KEY_CODE(NumLock, "NumLock") \
__ENUMERATE_KEY_CODE(ScrollLock, "ScrollLock") \
__ENUMERATE_KEY_CODE(F1, "F1") \
__ENUMERATE_KEY_CODE(F2, "F2") \
__ENUMERATE_KEY_CODE(F3, "F3") \
__ENUMERATE_KEY_CODE(F4, "F4") \
__ENUMERATE_KEY_CODE(F5, "F5") \
__ENUMERATE_KEY_CODE(F6, "F6") \
__ENUMERATE_KEY_CODE(F7, "F7") \
__ENUMERATE_KEY_CODE(F8, "F8") \
__ENUMERATE_KEY_CODE(F9, "F9") \
__ENUMERATE_KEY_CODE(F10, "F10") \
__ENUMERATE_KEY_CODE(F11, "F11") \
__ENUMERATE_KEY_CODE(F12, "F12") \
__ENUMERATE_KEY_CODE(Space, "Space") \
__ENUMERATE_KEY_CODE(ExclamationPoint, "!") \
__ENUMERATE_KEY_CODE(DoubleQuote, "\"") \
__ENUMERATE_KEY_CODE(Hashtag, "#") \
__ENUMERATE_KEY_CODE(Dollar, "$") \
__ENUMERATE_KEY_CODE(Percent, "%") \
__ENUMERATE_KEY_CODE(Ampersand, "&") \
__ENUMERATE_KEY_CODE(Apostrophe, "'") \
__ENUMERATE_KEY_CODE(LeftParen, "(") \
__ENUMERATE_KEY_CODE(RightParen, ")") \
__ENUMERATE_KEY_CODE(Asterisk, "*") \
__ENUMERATE_KEY_CODE(Plus, "+") \
__ENUMERATE_KEY_CODE(Comma, ",") \
__ENUMERATE_KEY_CODE(Minus, "-") \
__ENUMERATE_KEY_CODE(Period, ".") \
__ENUMERATE_KEY_CODE(Slash, "/") \
__ENUMERATE_KEY_CODE(0, "0") \
__ENUMERATE_KEY_CODE(1, "1") \
__ENUMERATE_KEY_CODE(2, "2") \
__ENUMERATE_KEY_CODE(3, "3") \
__ENUMERATE_KEY_CODE(4, "4") \
__ENUMERATE_KEY_CODE(5, "5") \
__ENUMERATE_KEY_CODE(6, "6") \
__ENUMERATE_KEY_CODE(7, "7") \
__ENUMERATE_KEY_CODE(8, "8") \
__ENUMERATE_KEY_CODE(9, "9") \
__ENUMERATE_KEY_CODE(Colon, ":") \
__ENUMERATE_KEY_CODE(Semicolon, ";") \
__ENUMERATE_KEY_CODE(LessThan, "<") \
__ENUMERATE_KEY_CODE(Equal, "=") \
__ENUMERATE_KEY_CODE(GreaterThan, ">") \
__ENUMERATE_KEY_CODE(QuestionMark, "?") \
__ENUMERATE_KEY_CODE(AtSign, "@") \
__ENUMERATE_KEY_CODE(A, "A") \
__ENUMERATE_KEY_CODE(B, "B") \
__ENUMERATE_KEY_CODE(C, "C") \
__ENUMERATE_KEY_CODE(D, "D") \
__ENUMERATE_KEY_CODE(E, "E") \
__ENUMERATE_KEY_CODE(F, "F") \
__ENUMERATE_KEY_CODE(G, "G") \
__ENUMERATE_KEY_CODE(H, "H") \
__ENUMERATE_KEY_CODE(I, "I") \
__ENUMERATE_KEY_CODE(J, "J") \
__ENUMERATE_KEY_CODE(K, "K") \
__ENUMERATE_KEY_CODE(L, "L") \
__ENUMERATE_KEY_CODE(M, "M") \
__ENUMERATE_KEY_CODE(N, "N") \
__ENUMERATE_KEY_CODE(O, "O") \
__ENUMERATE_KEY_CODE(P, "P") \
__ENUMERATE_KEY_CODE(Q, "Q") \
__ENUMERATE_KEY_CODE(R, "R") \
__ENUMERATE_KEY_CODE(S, "S") \
__ENUMERATE_KEY_CODE(T, "T") \
__ENUMERATE_KEY_CODE(U, "U") \
__ENUMERATE_KEY_CODE(V, "V") \
__ENUMERATE_KEY_CODE(W, "W") \
__ENUMERATE_KEY_CODE(X, "X") \
__ENUMERATE_KEY_CODE(Y, "Y") \
__ENUMERATE_KEY_CODE(Z, "Z") \
__ENUMERATE_KEY_CODE(LeftBracket, "[") \
__ENUMERATE_KEY_CODE(RightBracket, "]") \
__ENUMERATE_KEY_CODE(Backslash, "\\") \
__ENUMERATE_KEY_CODE(Circumflex, "^") \
__ENUMERATE_KEY_CODE(Underscore, "_") \
__ENUMERATE_KEY_CODE(LeftBrace, "{") \
__ENUMERATE_KEY_CODE(RightBrace, "}") \
__ENUMERATE_KEY_CODE(Pipe, "|") \
__ENUMERATE_KEY_CODE(Tilde, "~") \
__ENUMERATE_KEY_CODE(Backtick, "`") \
__ENUMERATE_KEY_CODE(Super, "Super") \
__ENUMERATE_KEY_CODE(BrowserSearch, "BrowserSearch") \
__ENUMERATE_KEY_CODE(BrowserFavorites, "BrowserFavorites") \
__ENUMERATE_KEY_CODE(BrowserHome, "BrowserHome") \
__ENUMERATE_KEY_CODE(PreviousTrack, "PreviousTrack") \
__ENUMERATE_KEY_CODE(BrowserBack, "BrowserBack") \
__ENUMERATE_KEY_CODE(BrowserForward, "BrowserForward") \
__ENUMERATE_KEY_CODE(BrowserRefresh, "BrowserRefresh") \
__ENUMERATE_KEY_CODE(BrowserStop, "BrowserStop") \
__ENUMERATE_KEY_CODE(VolumeDown, "VolumeDown") \
__ENUMERATE_KEY_CODE(VolumeUp, "VolumeUp") \
__ENUMERATE_KEY_CODE(Wake, "Wake") \
__ENUMERATE_KEY_CODE(Sleep, "Sleep") \
__ENUMERATE_KEY_CODE(NextTrack, "NextTrack") \
__ENUMERATE_KEY_CODE(MediaSelect, "MediaSelect") \
__ENUMERATE_KEY_CODE(Email, "Email") \
__ENUMERATE_KEY_CODE(MyComputer, "MyComputer") \
__ENUMERATE_KEY_CODE(Power, "Power") \
__ENUMERATE_KEY_CODE(Stop, "Stop") \
__ENUMERATE_KEY_CODE(LeftGUI, "LeftGUI") \
__ENUMERATE_KEY_CODE(Mute, "Mute") \
__ENUMERATE_KEY_CODE(RightGUI, "RightGUI") \
__ENUMERATE_KEY_CODE(Calculator, "Calculator") \
__ENUMERATE_KEY_CODE(Apps, "Apps") \
__ENUMERATE_KEY_CODE(PlayPause, "PlayPause") \
__ENUMERATE_KEY_CODE(Menu, "Menu")
enum KeyCode : u8 {
@ -143,11 +170,10 @@ enum KeyModifier {
struct KeyEvent {
KeyCode key { Key_Invalid };
u8 map_entry_index { 0 };
u32 scancode { 0 };
u64 scancode { 0 };
u32 code_point { 0 };
u8 flags { 0 };
bool caps_lock_on { false };
bool e0_prefix { false };
bool alt() const { return flags & Mod_Alt; }
bool ctrl() const { return flags & Mod_Ctrl; }
bool shift() const { return flags & Mod_Shift; }

View file

@ -120,7 +120,7 @@ UNMAP_AFTER_INIT bool I8042Controller::check_existence_via_probing(Badge<HIDMana
}
}
UNMAP_AFTER_INIT ErrorOr<void> I8042Controller::detect_devices()
UNMAP_AFTER_INIT ErrorOr<void> I8042Controller::detect_devices(EnableKeyboardFirstPortTranslation enable_first_port_translation)
{
u8 configuration;
{
@ -135,7 +135,13 @@ UNMAP_AFTER_INIT ErrorOr<void> I8042Controller::detect_devices()
configuration = TRY(do_wait_then_read_any_input(I8042Port::Buffer));
configuration &= ~I8042ConfigurationFlag::FirstPS2PortInterrupt;
configuration &= ~I8042ConfigurationFlag::SecondPS2PortInterrupt;
configuration |= I8042ConfigurationFlag::FirstPS2PortTranslation;
// FIXME: Don't enable translation for the first i8042 port if nothing is connected
// or even worse - a mouse device, because we will get garbage data.
if (enable_first_port_translation == EnableKeyboardFirstPortTranslation::Yes)
configuration |= I8042ConfigurationFlag::FirstPS2PortTranslation;
else
configuration &= ~I8042ConfigurationFlag::FirstPS2PortTranslation;
TRY(do_wait_then_write(I8042Port::Command, I8042Command::WriteConfiguration));
TRY(do_wait_then_write(I8042Port::Buffer, configuration));
@ -197,7 +203,9 @@ UNMAP_AFTER_INIT ErrorOr<void> I8042Controller::detect_devices()
// FIXME: Actually figure out the connected PS2 device type
m_first_ps2_port.device_type = PS2DeviceType::StandardKeyboard;
auto keyboard_device = TRY(KeyboardDevice::try_to_initialize());
auto error_or_device = PS2KeyboardDevice::try_to_initialize(*this, I8042PortIndex::FirstPort, *keyboard_device);
// FIXME: Determine if the user wants to operate in scan code set 3.
auto keyboard_device_scan_code_set = enable_first_port_translation == EnableKeyboardFirstPortTranslation::Yes ? ScanCodeSet::Set1 : ScanCodeSet::Set2;
auto error_or_device = PS2KeyboardDevice::try_to_initialize(*this, I8042PortIndex::FirstPort, keyboard_device_scan_code_set, *keyboard_device);
if (error_or_device.is_error()) {
dbgln("I8042: Keyboard device failed to initialize, disable");
m_first_port_available = false;

View file

@ -94,7 +94,12 @@ class I8042Controller final : public SerialIOController {
public:
static ErrorOr<NonnullRefPtr<I8042Controller>> create();
ErrorOr<void> detect_devices();
enum class EnableKeyboardFirstPortTranslation {
Yes,
No
};
ErrorOr<void> detect_devices(EnableKeyboardFirstPortTranslation);
virtual ErrorOr<void> send_command(PortIndex, DeviceCommand command) override;
virtual ErrorOr<void> send_command(PortIndex, DeviceCommand command, u8 data) override;

View file

@ -0,0 +1,32 @@
/*
* Copyright (c) 2023, Liav A. <liavalb@hotmail.co.il>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <AK/Types.h>
#include <Kernel/API/KeyCode.h>
namespace Kernel {
enum class ScanCodeSet {
Set1 = 1,
Set2 = 2,
Set3 = 3,
};
struct KeyCodeEntry {
KeyCode key_code;
u8 map_entry_index;
};
struct RawKeyEvent {
KeyCodeEntry code_entry;
u64 scancode { 0 };
bool is_press_down { false };
bool is_press() const { return is_press_down; }
};
}

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);

View file

@ -34,8 +34,6 @@ public:
virtual ErrorOr<size_t> write(OpenFileDescription&, u64, UserOrKernelBuffer const&, size_t) override { return EINVAL; }
virtual bool can_write(OpenFileDescription const&, u64) const override { return true; }
void handle_scan_code_input_event(ScanCodeEvent);
// ^File
virtual ErrorOr<void> ioctl(OpenFileDescription&, unsigned request, Userspace<void*> arg) override;
@ -47,6 +45,11 @@ public:
m_modifiers &= ~modifier;
}
u8 modifiers() const { return m_modifiers; }
void handle_input_event(KeyEvent);
bool num_lock_on() const { return m_num_lock_on; }
protected:
KeyboardDevice();
mutable Spinlock<LockRank::None> m_queue_lock {};
@ -58,10 +61,6 @@ protected:
bool m_caps_lock_to_ctrl_pressed { false };
bool m_caps_lock_on { false };
bool m_num_lock_on { false };
bool m_left_shift_pressed { false };
bool m_right_shift_pressed { false };
bool m_left_super_pressed { false };
bool m_right_super_pressed { false };
void key_state_changed(u8 raw, bool pressed);
};

View file

@ -167,7 +167,7 @@ UNMAP_AFTER_INIT ErrorOr<void> HIDManagement::enumerate()
// Note: If we happen to not have i8042 just return "gracefully" for now.
if (!has_i8042_controller)
return {};
if (auto result_or_error = i8042_controller->detect_devices(); result_or_error.is_error())
if (auto result_or_error = i8042_controller->detect_devices(I8042Controller::EnableKeyboardFirstPortTranslation::No); result_or_error.is_error())
return {};
m_hid_serial_io_controllers.with([&](auto& list) {
list.append(i8042_controller);
@ -188,10 +188,10 @@ HIDManagement& HIDManagement::the()
return *s_the;
}
u32 HIDManagement::get_char_from_character_map(KeyEvent event, bool num_lock_on) const
u32 HIDManagement::get_char_from_character_map(KeyEvent event, u8 index) const
{
VERIFY(index < CHAR_MAP_SIZE);
auto modifiers = event.modifiers();
auto index = event.scancode & 0xFF; // Index is last byte of scan code.
auto caps_lock_on = event.caps_lock_on;
u32 code_point = 0;
@ -215,19 +215,6 @@ u32 HIDManagement::get_char_from_character_map(KeyEvent event, bool num_lock_on)
code_point |= 0x20;
}
if (event.e0_prefix && event.key == Key_Slash) {
// If Key_Slash (scancode = 0x35) mapped to other form "/", we fix num pad key of "/" with this case.
code_point = '/';
} else if (event.e0_prefix && event.key != Key_Return) {
// Except for `keypad-/` and 'keypad-return', all e0 scan codes are not actually characters. i.e., `keypad-0` and
// `Insert` have the same scancode except for the prefix, but insert should not have a code_point.
code_point = 0;
} else if (!num_lock_on && !event.e0_prefix && event.scancode >= 0x47 && event.scancode <= 0x53 && event.key != Key_Minus && event.key != Key_Plus) {
// When Num Lock is off, some numpad keys have the same function as some of the extended keys like Home, End, PgDown, arrows etc.
// These keys should have the code_point set to 0.
code_point = 0;
}
return code_point;
}

View file

@ -48,7 +48,7 @@ public:
SpinlockProtected<KeymapData, LockRank::None>& keymap_data() { return m_keymap_data; }
u32 get_char_from_character_map(KeyEvent, bool) const;
u32 get_char_from_character_map(KeyEvent, u8) const;
void set_client(KeyboardClient* client);
void set_maps(NonnullOwnPtr<KString> character_map_name, Keyboard::CharacterMapData const& character_map);

View file

@ -19,28 +19,699 @@
namespace Kernel {
void PS2KeyboardDevice::handle_byte_read_from_serial_input(u8 byte)
// clang-format off
static constexpr KeyCodeEntry unshifted_scan_code_set1_key_map[0x80] = {
{ Key_Invalid, 0xFF }, { Key_Escape, 1 }, { Key_1, 2 }, { Key_2, 3 },
{ Key_3, 4 }, { Key_4, 5 }, { Key_5, 6 }, { Key_6, 7 },
{ Key_7, 8 }, { Key_8, 9 }, { Key_9, 0x0A }, { Key_0, 0x0B },
{ Key_Minus, 0x0C }, { Key_Equal, 0x0D }, { Key_Backspace, 0x0E }, { Key_Tab, 0x0F },
{ Key_Q, 0x10 }, { Key_W, 0x11 }, { Key_E, 0x12 }, { Key_R, 0x13 },
{ Key_T, 0x14 }, { Key_Y, 0x15 }, { Key_U, 0x16 }, { Key_I, 0x17 },
{ Key_O, 0x18 }, { Key_P, 0x19 }, { Key_LeftBracket, 0x1A }, { Key_RightBracket, 0x1B },
{ Key_Return, 0x1C }, { Key_Control, 0x1D }, { Key_A, 0x1E }, { Key_S, 0x1F },
{ Key_D, 0x20 }, { Key_F, 0x21 }, { Key_G, 0x22 }, { Key_H, 0x23 },
{ Key_J, 0x24 }, { Key_K, 0x25 }, { Key_L, 0x26 }, { Key_Semicolon, 0x27 },
{ Key_Apostrophe, 0x28 }, { Key_Backtick, 0x29 }, { Key_LeftShift, 0xFF }, { Key_Backslash, 0x2B },
{ Key_Z, 0x2C }, { Key_X, 0x2D }, { Key_C, 0x2E }, { Key_V, 0x2F },
{ Key_B, 0x30 }, { Key_N, 0x31 }, { Key_M, 0x32 }, { Key_Comma, 0x33 },
{ Key_Period, 0x34 }, { Key_Slash, 0x35 }, { Key_RightShift, 0xFF }, { Key_Asterisk, 0x37 },
{ Key_Alt, 0xFF }, { Key_Space, 0x39 }, { Key_CapsLock, 0xFF }, { Key_F1, 0xFF },
{ Key_F2, 0xFF }, { Key_F3, 0xFF }, { Key_F4, 0xFF }, { Key_F5, 0xFF },
{ Key_F6, 0xFF }, { Key_F7, 0xFF }, { Key_F8, 0xFF }, { Key_F9, 0xFF },
{ Key_F10, 0xFF }, { Key_NumLock, 0xFF }, { Key_ScrollLock, 0xFF }, { Key_Home, 0xFF },
{ Key_Up, 0xFF }, { Key_PageUp, 0xFF }, { Key_Minus, 0x4A }, { Key_Left, 0xFF },
{ Key_Invalid, 0xFF }, { Key_Right, 0xFF }, { Key_Plus, 0xFF }, { Key_End, 0xFF },
{ Key_Down, 0xFF }, { Key_PageDown, 0xFF }, { Key_Insert, 0xFF }, { Key_Delete, 0xFF },
{ Key_Invalid, 0xFF }, { Key_Invalid, 0xFF }, { Key_Backslash, 0x56 }, { Key_F11, 0xFF },
{ Key_F12, 0xFF }, { Key_Invalid, 0xFF }, { Key_Invalid, 0xFF }, { Key_Super, 0xFF },
{ Key_Invalid, 0xFF }, { Key_Menu, 0xFF },
};
// clang-format on
// clang-format off
static constexpr KeyCodeEntry shifted_scan_code_set1_key_map[0x100] = {
{ Key_Invalid, 0xFF }, { Key_Escape, 1 }, { Key_Escape, 2 }, { Key_AtSign, 3 },
{ Key_Hashtag, 4 }, { Key_Dollar, 5 }, { Key_Percent, 6 }, { Key_Circumflex, 7 },
{ Key_Ampersand, 8 }, { Key_Asterisk, 9 }, { Key_LeftParen, 0x0A }, { Key_RightParen, 0x0B },
{ Key_Underscore, 0xC }, { Key_Plus, 0xFF }, { Key_Backspace, 0x0E }, { Key_Tab, 0x0F },
{ Key_Q, 0x10 }, { Key_W, 0x11 }, { Key_E, 0x12 }, { Key_R, 0x13 },
{ Key_T, 0x14 }, { Key_Y, 0x15 }, { Key_U, 0x16 }, { Key_I, 0x17 },
{ Key_O, 0x18 }, { Key_P, 0x19 }, { Key_LeftBrace, 0x1A }, { Key_RightBrace, 0x1B },
{ Key_Return, 0x1C }, { Key_Control, 0x1D }, { Key_A, 0x1E }, { Key_S, 0x1F },
{ Key_D, 0x20 }, { Key_F, 0x21 }, { Key_G, 0x22 }, { Key_H, 0x23 },
{ Key_J, 0x24 }, { Key_K, 0x25 }, { Key_L, 0x26 }, { Key_Colon, 0x27 },
{ Key_DoubleQuote, 0x28 }, { Key_Tilde, 0x29 }, { Key_LeftShift, 0xFF }, { Key_Pipe, 0x2B },
{ Key_Z, 0x2C }, { Key_X, 0x2D }, { Key_C, 0x2E }, { Key_V, 0x2F },
{ Key_B, 0x30 }, { Key_N, 0x31 }, { Key_M, 0x32 }, { Key_LessThan, 0x33 },
{ Key_GreaterThan, 0x34 }, { Key_QuestionMark, 0x35 }, { Key_RightShift, 0x36 }, { Key_Asterisk, 0x37 },
{ Key_Alt, 0x38 }, { Key_Space, 0x39 }, { Key_CapsLock, 0x3A }, { Key_F1, 0x3B },
{ Key_F2, 0x3C }, { Key_F3, 0x3D }, { Key_F4, 0x3E }, { Key_F5, 0x3F },
{ Key_F6, 0x40 }, { Key_F7, 0x41 }, { Key_F8, 0x42 }, { Key_F9, 0x43 },
{ Key_F10, 0x44 }, { Key_NumLock, 0x45 }, { Key_ScrollLock, 0x46 }, { Key_Home, 0x47 },
{ Key_Up, 0x48 }, { Key_PageUp, 0x49 }, { Key_Minus, 0x0C }, { Key_Left, 0x4B },
{ Key_Invalid, 0xFF }, { Key_Right, 0xFF }, { Key_Plus, 0xFF }, { Key_End, 0xFF },
{ Key_Down, 0xFF }, { Key_PageDown, 0xFF }, { Key_Insert, 0xFF }, { Key_Delete, 0xFF },
{ Key_Invalid, 0xFF }, { Key_Invalid, 0xFF }, { Key_Pipe, 0x56 }, { Key_F11, 0xFF },
{ Key_F12, 0xFF }, { Key_Invalid, 0xFF }, { Key_Invalid, 0xFF }, { Key_Super, 0xFF },
{ Key_Invalid, 0xFF }, { Key_Menu, 0xFF },
};
// clang-format on
// clang-format off
static constexpr KeyCodeEntry unshifted_simple_scan_code_set2_key_map_with_key_num_pad[0x84] = {
{ Key_Invalid, 0xFF }, { Key_F9, 0x43 }, { Key_Invalid, 0xFF }, { Key_F5, 0x3F },
{ Key_F3, 0x3D }, { Key_F1, 0x3B }, { Key_F2, 0x3C }, { Key_F12, 0xFF },
{ Key_Invalid, 0xFF }, { Key_F10, 0x44 }, { Key_F8, 0x42 }, { Key_F6, 0x40 },
{ Key_F4, 0x3E }, { Key_Tab, 0x0F }, { Key_Backtick, 0x29 }, { Key_Invalid, 0xFF },
{ Key_Invalid, 0xFF }, { Key_Alt, 0x38 }, { Key_LeftShift, 0x2A }, { Key_Invalid, 0xFF },
{ Key_Control, 0x1D }, { Key_Q, 0x10 }, { Key_1, 2 }, { Key_Invalid, 0xFF },
{ Key_Invalid, 0xFF }, { Key_Invalid, 0xFF }, { Key_Z, 0x2C }, { Key_S, 0x1F },
{ Key_A, 0x1E }, { Key_W, 0x11 }, { Key_2, 3 }, { Key_Invalid, 0xFF },
{ Key_Invalid, 0xFF }, { Key_C, 0x2E }, { Key_X, 0x2D }, { Key_D, 0x20 },
{ Key_E, 0x12 }, { Key_4, 5 }, { Key_3, 4 }, { Key_Invalid, 0xFF },
{ Key_Invalid, 0xFF }, { Key_Space, 0x39 }, { Key_V, 0x2F }, { Key_F, 0x21 },
{ Key_T, 0x14 }, { Key_R, 0x13 }, { Key_5, 6 }, { Key_Invalid, 0xFF },
{ Key_Invalid, 0xFF }, { Key_N, 0x31 }, { Key_B, 0x30 }, { Key_H, 0x23 },
{ Key_G, 0x22 }, { Key_Y, 0x15 }, { Key_6, 7 }, { Key_Invalid, 0xFF },
{ Key_Invalid, 0xFF }, { Key_Invalid, 0xFF }, { Key_M, 0x32 }, { Key_J, 0x24 },
{ Key_U, 0x16 }, { Key_7, 8 }, { Key_8, 9 }, { Key_Invalid, 0xFF },
{ Key_Invalid, 0xFF }, { Key_Comma, 0x33 }, { Key_K, 0x25 }, { Key_I, 0x17 },
{ Key_O, 0x18 }, { Key_0, 0x0B }, { Key_9, 0x0A }, { Key_Invalid, 0xFF },
{ Key_Invalid, 0xFF }, { Key_Period, 0x34 }, { Key_Slash, 0x35 }, { Key_L, 0x26 },
{ Key_Semicolon, 0x27 }, { Key_P, 0x19 }, { Key_Minus, 0x0C }, { Key_Invalid, 0xFF },
{ Key_Invalid, 0xFF }, { Key_Invalid, 0xFF }, { Key_Apostrophe, 0x28 }, { Key_Invalid, 0xFF },
{ Key_LeftBracket, 0x1A }, { Key_Equal, 0x0D }, { Key_Invalid, 0xFF }, { Key_Invalid, 0xFF },
{ Key_CapsLock, 0x3A }, { Key_RightShift, 0x36 }, { Key_Return, 0x1C }, { Key_RightBracket, 0x1B },
{ Key_Invalid, 0xFF }, { Key_Backslash, 0x2B }, { Key_Invalid, 0xFF }, { Key_Invalid, 0xFF },
{ Key_Invalid, 0xFF }, { Key_Invalid, 0xFF }, { Key_Invalid, 0xFF }, { Key_Invalid, 0xFF },
{ Key_Invalid, 0xFF }, { Key_Invalid, 0xFF }, { Key_Backspace, 0x0E }, { Key_Invalid, 0xFF },
// Keypad numbers from here
{ Key_Invalid, 0xFF }, { Key_1, 2 }, { Key_Invalid, 0xFF }, { Key_4, 5 },
{ Key_7, 8 }, { Key_Invalid, 0xFF }, { Key_Invalid, 0xFF }, { Key_Invalid, 0xFF },
{ Key_0, 0x0B }, { Key_Period, 0x34 }, { Key_2, 3 }, { Key_5, 6 },
{ Key_6, 7 }, { Key_8, 9 }, { Key_Escape, 1 }, { Key_NumLock, 0x45 },
{ Key_F11, 0xFF }, { Key_Plus, 0xFF }, { Key_3, 4 }, { Key_Minus, 0x0C },
{ Key_Asterisk, 0x37 }, { Key_9, 0x0A }, { Key_ScrollLock, 0x46 }, { Key_Invalid, 0xFF },
{ Key_Invalid, 0xFF }, { Key_Invalid, 0xFF }, { Key_Invalid, 0xFF }, { Key_F7, 0x41 },
};
// clang-format on
// clang-format off
static constexpr KeyCodeEntry unshifted_simple_scan_code_set2_key_map_with_disabled_key_num_pad[0x84] = {
{ Key_Invalid, 0xFF }, { Key_F9, 0x43 }, { Key_Invalid, 0xFF }, { Key_F5, 0x3F },
{ Key_F3, 0x3D }, { Key_F1, 0x3B }, { Key_F2, 0x3C }, { Key_F12, 0xFF },
{ Key_Invalid, 0xFF }, { Key_F10, 0x44 }, { Key_F8, 0x42 }, { Key_F6, 0x40 },
{ Key_F4, 0x3E }, { Key_Tab, 0x0F }, { Key_Backtick, 0x29 }, { Key_Invalid, 0xFF },
{ Key_Invalid, 0xFF }, { Key_Alt, 0x38 }, { Key_LeftShift, 0x2A }, { Key_Invalid, 0xFF },
{ Key_Control, 0x1D }, { Key_Q, 0x10 }, { Key_1, 2 }, { Key_Invalid, 0xFF },
{ Key_Invalid, 0xFF }, { Key_Invalid, 0xFF }, { Key_Z, 0x2C }, { Key_S, 0x1F },
{ Key_A, 0x1E }, { Key_W, 0x11 }, { Key_2, 3 }, { Key_Invalid, 0xFF },
{ Key_Invalid, 0xFF }, { Key_C, 0x2E }, { Key_X, 0x2D }, { Key_D, 0x20 },
{ Key_E, 0x12 }, { Key_4, 5 }, { Key_3, 4 }, { Key_Invalid, 0xFF },
{ Key_Invalid, 0xFF }, { Key_Space, 0x39 }, { Key_V, 0x2F }, { Key_F, 0x21 },
{ Key_T, 0x14 }, { Key_R, 0x13 }, { Key_5, 6 }, { Key_Invalid, 0xFF },
{ Key_Invalid, 0xFF }, { Key_N, 0x31 }, { Key_B, 0x30 }, { Key_H, 0x23 },
{ Key_G, 0x22 }, { Key_Y, 0x15 }, { Key_6, 7 }, { Key_Invalid, 0xFF },
{ Key_Invalid, 0xFF }, { Key_Invalid, 0xFF }, { Key_M, 0x32 }, { Key_J, 0x24 },
{ Key_U, 0x16 }, { Key_7, 8 }, { Key_8, 9 }, { Key_Invalid, 0xFF },
{ Key_Invalid, 0xFF }, { Key_Comma, 0x33 }, { Key_K, 0x25 }, { Key_I, 0x17 },
{ Key_O, 0x18 }, { Key_0, 0x0B }, { Key_9, 0x0A }, { Key_Invalid, 0xFF },
{ Key_Invalid, 0xFF }, { Key_Period, 0x34 }, { Key_Slash, 0x35 }, { Key_L, 0x26 },
{ Key_Semicolon, 0x27 }, { Key_P, 0x19 }, { Key_Underscore, 0x0C }, { Key_Invalid, 0xFF },
{ Key_Invalid, 0xFF }, { Key_Invalid, 0xFF }, { Key_Apostrophe, 0x28 }, { Key_Invalid, 0xFF },
{ Key_LeftBracket, 0x1A }, { Key_Equal, 0x0D }, { Key_Invalid, 0xFF }, { Key_Invalid, 0xFF },
{ Key_CapsLock, 0x3A }, { Key_RightShift, 0x36 }, { Key_Return, 0x1C }, { Key_RightBracket, 0x1B },
{ Key_Invalid, 0xFF }, { Key_Backslash, 0x2B }, { Key_Invalid, 0xFF }, { Key_Invalid, 0xFF },
{ Key_Invalid, 0xFF }, { Key_Invalid, 0xFF }, { Key_Invalid, 0xFF }, { Key_Invalid, 0xFF },
{ Key_Invalid, 0xFF }, { Key_Invalid, 0xFF }, { Key_Backspace, 0x0E }, { Key_Invalid, 0xFF },
// Keypad numbers from here, and disabled or converted to arrows
{ Key_Invalid, 0xFF }, { Key_Invalid, 0xFF }, { Key_Invalid, 0xFF }, { Key_Left, 0x4B },
{ Key_Invalid, 0xFF }, { Key_Invalid, 0xFF }, { Key_Invalid, 0xFF }, { Key_Invalid, 0xFF },
{ Key_Insert, 0xFF }, { Key_Delete, 0xFF }, { Key_Down, 0xFF }, { Key_Invalid, 0xFF },
{ Key_Right, 0xFF }, { Key_Up, 0x48 }, { Key_Escape, 1 }, { Key_NumLock, 0x45 },
{ Key_F11, 0xFF }, { Key_Plus, 0xFF }, { Key_Invalid, 0xFF }, { Key_Minus, 0x0C },
{ Key_Asterisk, 0x37 }, { Key_Invalid, 0xFF }, { Key_ScrollLock, 0x46 }, { Key_Invalid, 0xFF },
{ Key_Invalid, 0xFF }, { Key_Invalid, 0xFF }, { Key_Invalid, 0xFF }, { Key_F7, 0x41 },
};
// clang-format on
// clang-format off
static constexpr KeyCodeEntry shifted_simple_scan_code_set2_key_map_with_key_num_pad[0x84] = {
{ Key_Invalid, 0xFF }, { Key_F9, 0x43 }, { Key_Invalid, 0xFF }, { Key_F5, 0x3F },
{ Key_F3, 0x3D }, { Key_F1, 0x3B }, { Key_F2, 0x3C }, { Key_F12, 0xFF },
{ Key_Invalid, 0xFF }, { Key_F10, 0x44 }, { Key_F8, 0x42 }, { Key_F6, 0x40 },
{ Key_F4, 0x3E }, { Key_Tab, 0x0F }, { Key_Backtick, 0x29 }, { Key_Invalid, 0xFF },
{ Key_Invalid, 0xFF }, { Key_Alt, 0x38 }, { Key_LeftShift, 0x2A }, { Key_Invalid, 0xFF },
{ Key_Control, 0x1D }, { Key_Slash, 0x35 }, { Key_Escape, 2 }, { Key_Invalid, 0xFF },
{ Key_Invalid, 0xFF }, { Key_Invalid, 0xFF }, { Key_Z, 0x2C }, { Key_S, 0x1F },
{ Key_A, 0x1E }, { Key_W, 0x11 }, { Key_AtSign, 3 }, { Key_Invalid, 0xFF },
{ Key_Invalid, 0xFF }, { Key_C, 0x2E }, { Key_X, 0x2D }, { Key_D, 0x20 },
{ Key_E, 0x12 }, { Key_Dollar, 5 }, { Key_Hashtag, 4 }, { Key_Invalid, 0xFF },
{ Key_Invalid, 0xFF }, { Key_Space, 0x39 }, { Key_V, 0x2F }, { Key_F, 0x21 },
{ Key_T, 0x14 }, { Key_R, 0x13 }, { Key_Percent, 6 }, { Key_Invalid, 0xFF },
{ Key_Invalid, 0xFF }, { Key_N, 0x31 }, { Key_B, 0x30 }, { Key_H, 0x23 },
{ Key_G, 0x22 }, { Key_Y, 0x15 }, { Key_Circumflex, 7 }, { Key_Invalid, 0xFF },
{ Key_Invalid, 0xFF }, { Key_Invalid, 0xFF }, { Key_M, 0x32 }, { Key_J, 0x24 },
{ Key_U, 0x16 }, { Key_Ampersand, 8 }, { Key_Asterisk, 0x37 }, { Key_Invalid, 0xFF },
{ Key_Invalid, 0xFF }, { Key_LessThan, 0x33 }, { Key_K, 0x25 }, { Key_I, 0x17 },
{ Key_O, 0x18 }, { Key_RightParen, 0x0B }, { Key_LeftParen, 0x0A }, { Key_Invalid, 0xFF },
{ Key_Invalid, 0xFF }, { Key_GreaterThan, 0x34 }, { Key_Slash, 0x35 }, { Key_L, 0x26 },
{ Key_Semicolon, 0x27 }, { Key_P, 0x19 }, { Key_Minus, 0x0C }, { Key_Invalid, 0xFF },
{ Key_Invalid, 0xFF }, { Key_Invalid, 0xFF }, { Key_DoubleQuote, 0x28 }, { Key_Invalid, 0xFF },
{ Key_LeftBrace, 0x1A }, { Key_Plus, 0xFF }, { Key_Invalid, 0xFF }, { Key_Invalid, 0xFF },
{ Key_CapsLock, 0x3A }, { Key_RightShift, 0x36 }, { Key_Return, 0x1C }, { Key_RightBrace, 0x1B },
{ Key_Invalid, 0xFF }, { Key_Pipe, 0x2B }, { Key_Invalid, 0xFF }, { Key_Invalid, 0xFF },
{ Key_Invalid, 0xFF }, { Key_Invalid, 0xFF }, { Key_Invalid, 0xFF }, { Key_Invalid, 0xFF },
{ Key_Invalid, 0xFF }, { Key_Invalid, 0xFF }, { Key_Backspace, 0x0E }, { Key_Invalid, 0xFF },
// Keypad numbers from here
{ Key_Invalid, 0xFF }, { Key_1, 2 }, { Key_Invalid, 0xFF }, { Key_4, 5 },
{ Key_7, 8 }, { Key_Invalid, 0xFF }, { Key_Invalid, 0xFF }, { Key_Invalid, 0xFF },
{ Key_0, 0x0B }, { Key_Period, 0x34 }, { Key_2, 3 }, { Key_5, 6 },
{ Key_6, 7 }, { Key_8, 9 }, { Key_Escape, 1 }, { Key_NumLock, 0x45 },
{ Key_F11, 0xFF }, { Key_Plus, 0xFF }, { Key_3, 4 }, { Key_Minus, 0x0C },
{ Key_Asterisk, 0x37 }, { Key_9, 0x0A }, { Key_ScrollLock, 0x46 }, { Key_Invalid, 0xFF },
{ Key_Invalid, 0xFF }, { Key_Invalid, 0xFF }, { Key_Invalid, 0xFF }, { Key_F7, 0x41 },
};
// clang-format on
// clang-format off
static constexpr KeyCodeEntry shifted_simple_scan_code_set2_key_map_with_disabled_key_num_pad[0x84] = {
{ Key_Invalid, 0xFF }, { Key_F9, 0x43 }, { Key_Invalid, 0xFF }, { Key_F5, 0x3F },
{ Key_F3, 0x3D }, { Key_F1, 0x3B }, { Key_F2, 0x3C }, { Key_F12, 0xFF },
{ Key_Invalid, 0xFF }, { Key_F10, 0x44 }, { Key_F8, 0x42 }, { Key_F6, 0x40 },
{ Key_F4, 0x3E }, { Key_Tab, 0x0F }, { Key_Backtick, 0x29 }, { Key_Invalid, 0xFF },
{ Key_Invalid, 0xFF }, { Key_Alt, 0x38 }, { Key_LeftShift, 0x2A }, { Key_Invalid, 0xFF },
{ Key_Control, 0x1D }, { Key_Slash, 0x35 }, { Key_Escape, 2 }, { Key_Invalid, 0xFF },
{ Key_Invalid, 0xFF }, { Key_Invalid, 0xFF }, { Key_Z, 0x2C }, { Key_S, 0x1F },
{ Key_A, 0x1E }, { Key_W, 0x11 }, { Key_AtSign, 3 }, { Key_Invalid, 0xFF },
{ Key_Invalid, 0xFF }, { Key_C, 0x2E }, { Key_X, 0x2D }, { Key_D, 0x20 },
{ Key_E, 0x12 }, { Key_Dollar, 5 }, { Key_Hashtag, 4 }, { Key_Invalid, 0xFF },
{ Key_Invalid, 0xFF }, { Key_Space, 0x39 }, { Key_V, 0x2F }, { Key_F, 0x21 },
{ Key_T, 0x14 }, { Key_R, 0x13 }, { Key_Percent, 6 }, { Key_Invalid, 0xFF },
{ Key_Invalid, 0xFF }, { Key_N, 0x31 }, { Key_B, 0x30 }, { Key_H, 0x23 },
{ Key_G, 0x22 }, { Key_Y, 0x15 }, { Key_Circumflex, 7 }, { Key_Invalid, 0xFF },
{ Key_Invalid, 0xFF }, { Key_Invalid, 0xFF }, { Key_M, 0x32 }, { Key_J, 0x24 },
{ Key_U, 0x16 }, { Key_Ampersand, 8 }, { Key_Asterisk, 0x37 }, { Key_Invalid, 0xFF },
{ Key_Invalid, 0xFF }, { Key_LessThan, 0xFF}, { Key_K, 0x25 }, { Key_I, 0x17 },
{ Key_O, 0x18 }, { Key_RightParen, 0x0B }, { Key_LeftParen, 0x0A }, { Key_Invalid, 0xFF },
{ Key_Invalid, 0xFF }, { Key_Period, 0x34 }, { Key_Slash, 0x35 }, { Key_L, 0x26 },
{ Key_Semicolon, 0x27 }, { Key_P, 0x19 }, { Key_Underscore, 0x0C }, { Key_Invalid, 0xFF },
{ Key_Invalid, 0xFF }, { Key_Invalid, 0xFF }, { Key_DoubleQuote, 0x28 }, { Key_Invalid, 0xFF },
{ Key_LeftBrace, 0x1A }, { Key_Plus, 0xFF }, { Key_Invalid, 0xFF }, { Key_Invalid, 0xFF },
{ Key_CapsLock, 0x3A }, { Key_RightShift, 0x36 }, { Key_Return, 0x1C }, { Key_RightBrace, 0x1B },
{ Key_Invalid, 0xFF }, { Key_Pipe, 0x2B }, { Key_Invalid, 0xFF }, { Key_Invalid, 0xFF },
{ Key_Invalid, 0xFF }, { Key_Invalid, 0xFF }, { Key_Invalid, 0xFF }, { Key_Invalid, 0xFF },
{ Key_Invalid, 0xFF }, { Key_Invalid, 0xFF }, { Key_Backspace, 0x0E }, { Key_Invalid, 0xFF },
// Keypad numbers from here, and disabled or converted to arrows
{ Key_Invalid, 0xFF }, { Key_Invalid, 0xFF }, { Key_Invalid, 0xFF }, { Key_Left, 0x4B },
{ Key_7, 8 }, { Key_Invalid, 0xFF }, { Key_Invalid, 0xFF }, { Key_Invalid, 0xFF },
{ Key_Insert, 0xFF }, { Key_Delete, 0xFF }, { Key_Down, 0xFF }, { Key_Invalid, 0xFF },
{ Key_Right, 0xFF }, { Key_Up, 0x48 }, { Key_Escape, 1 }, { Key_NumLock, 0x45 },
{ Key_F11, 0xFF }, { Key_Plus, 0xFF }, { Key_Invalid, 0xFF }, { Key_Minus, 0x0C },
{ Key_Asterisk, 0x37 }, { Key_Invalid, 0xFF }, { Key_ScrollLock, 0x46 }, { Key_Invalid, 0xFF },
{ Key_Invalid, 0xFF }, { Key_Invalid, 0xFF }, { Key_Invalid, 0xFF }, { Key_F7, 0x41 },
};
// clang-format on
// Note: First scan code starts at actual 0xE0, 0x10, but we start from 0xE0, 0x0
// Note: All keycode are for pressing buttons, not releasing...
// clang-format off
static constexpr KeyCodeEntry unshifted_scan_code_set2_e0_key_map[0x80] = {
{ Key_Invalid, 0xFF }, { Key_Invalid, 0xFF }, { Key_Invalid, 0xFF }, { Key_Invalid, 0xFF },
{ Key_Invalid, 0xFF }, { Key_Invalid, 0xFF }, { Key_Invalid, 0xFF }, { Key_Invalid, 0xFF },
{ Key_Invalid, 0xFF }, { Key_Invalid, 0xFF }, { Key_Invalid, 0xFF }, { Key_Invalid, 0xFF },
{ Key_Invalid, 0xFF }, { Key_Invalid, 0xFF }, { Key_Invalid, 0xFF }, { Key_Invalid, 0xFF },
{ Key_BrowserSearch, 0xFF }, { Key_RightAlt, 0xFF }, { Key_Invalid, 0xFF }, { Key_Invalid, 0xFF },
{ Key_RightControl, 0xFF }, { Key_PreviousTrack, 0xFF }, { Key_Invalid, 0xFF }, { Key_Invalid, 0xFF },
{ Key_BrowserFavorites, 0xFF }, { Key_Invalid, 0xFF }, { Key_Invalid, 0xFF }, { Key_Invalid, 0xFF },
{ Key_Invalid, 0xFF }, { Key_Invalid, 0xFF }, { Key_Invalid, 0xFF }, { Key_LeftGUI, 0xFF },
{ Key_BrowserRefresh, 0xFF }, { Key_VolumeDown, 0xFF }, { Key_Invalid, 0xFF }, { Key_Mute, 0xFF },
{ Key_Invalid, 0xFF }, { Key_Invalid, 0xFF }, { Key_Invalid, 0xFF }, { Key_RightGUI, 0xFF },
{ Key_BrowserStop, 0xFF }, { Key_Invalid, 0xFF }, { Key_Invalid, 0xFF }, { Key_Calculator, 0xFF },
{ Key_Invalid, 0xFF }, { Key_Invalid, 0xFF }, { Key_Invalid, 0xFF }, { Key_Apps, 0xFF },
{ Key_BrowserForward, 0xFF }, { Key_Invalid, 0xFF }, { Key_VolumeUp, 0xFF }, { Key_Invalid, 0xFF },
{ Key_PlayPause, 0xFF }, { Key_Invalid, 0xFF }, { Key_Invalid, 0xFF }, { Key_Power, 0xFF },
{ Key_BrowserBack, 0xFF }, { Key_Invalid, 0xFF }, { Key_BrowserHome, 0xFF }, { Key_Stop, 0xFF },
{ Key_Invalid, 0xFF }, { Key_Invalid, 0xFF }, { Key_Invalid, 0xFF }, { Key_Sleep, 0xFF },
{ Key_MyComputer, 0xFF }, { Key_Invalid, 0xFF }, { Key_Invalid, 0xFF }, { Key_Invalid, 0xFF },
{ Key_Invalid, 0xFF }, { Key_Invalid, 0xFF }, { Key_Invalid, 0xFF }, { Key_Invalid, 0xFF },
{ Key_Email, 0xFF }, { Key_Invalid, 0xFF }, { Key_Slash, 0x35 }, { Key_Invalid, 0xFF },
{ Key_Invalid, 0xFF }, { Key_NextTrack, 0xFF }, { Key_Invalid, 0xFF }, { Key_Invalid, 0xFF },
{ Key_MediaSelect, 0xFF}, { Key_Invalid, 0xFF }, { Key_Invalid, 0xFF }, { Key_Invalid, 0xFF },
{ Key_Invalid, 0xFF }, { Key_Invalid, 0xFF }, { Key_Invalid, 0xFF }, { Key_Invalid, 0xFF },
{ Key_Invalid, 0xFF }, { Key_Invalid, 0xFF }, { Key_Return, 0x1C }, { Key_Invalid, 0xFF },
{ Key_Invalid, 0xFF }, { Key_Invalid, 0xFF }, { Key_Wake, 0xFF }, { Key_Invalid, 0xFF },
{ Key_Invalid, 0xFF }, { Key_Invalid, 0xFF }, { Key_Invalid, 0xFF }, { Key_Invalid, 0xFF },
{ Key_Invalid, 0xFF }, { Key_Invalid, 0xFF }, { Key_Invalid, 0xFF }, { Key_Invalid, 0xFF },
{ Key_Invalid, 0xFF }, { Key_End, 0xFF }, { Key_Invalid, 0xFF }, { Key_Left, 0xFF },
{ Key_Home, 0x47 }, { Key_Invalid, 0xFF }, { Key_Invalid, 0xFF }, { Key_Invalid, 0xFF },
{ Key_Insert, 0xFF }, { Key_Delete, 0xFF }, { Key_Down, 0xFF }, { Key_Invalid, 0xFF },
{ Key_Right, 0xFF }, { Key_Up, 0xFF }, { Key_Invalid, 0xFF }, { Key_Invalid, 0xFF },
{ Key_Invalid, 0xFF }, { Key_Invalid, 0xFF }, { Key_PageDown, 0xFF }, { Key_Invalid, 0xFF },
{ Key_Invalid, 0xFF }, { Key_PageUp, 0x49 }, { Key_Invalid, 0xFF }, { Key_Invalid, 0xFF },
};
// clang-format on
RawKeyEvent PS2KeyboardDevice::generate_raw_key_event_input_from_set1(ScanCodeEvent event)
{
RawKeyEvent key_event {};
VERIFY(event.sent_scan_code_set == ScanCodeSet::Set1);
bool has_e0_prefix = event.scan_code_bytes[0] == 0xe0;
if (has_e0_prefix)
VERIFY(event.bytes_count == 2);
else
VERIFY(event.bytes_count == 1);
u8 byte = has_e0_prefix ? event.scan_code_bytes[1] : event.scan_code_bytes[0];
bool pressed = !(byte & 0x80);
u8 ch = byte & 0x7f;
key_event.is_press_down = pressed;
m_entropy_source.add_random_event(byte);
switch (ch) {
case 0x38:
if (has_e0_prefix)
m_keyboard_device->update_modifier(Mod_AltGr, key_event.is_press());
else
m_keyboard_device->update_modifier(Mod_Alt, key_event.is_press());
break;
case 0x1d:
m_keyboard_device->update_modifier(Mod_Ctrl, key_event.is_press());
break;
case 0x5b:
m_left_super_pressed = key_event.is_press();
m_keyboard_device->update_modifier(Mod_Super, m_left_super_pressed || m_right_super_pressed);
break;
case 0x5c:
m_right_super_pressed = key_event.is_press();
m_keyboard_device->update_modifier(Mod_Super, m_left_super_pressed || m_right_super_pressed);
break;
case 0x2a:
m_left_shift_pressed = key_event.is_press();
m_keyboard_device->update_modifier(Mod_Shift, m_left_shift_pressed || m_right_shift_pressed);
break;
case 0x36:
m_right_shift_pressed = key_event.is_press();
m_keyboard_device->update_modifier(Mod_Shift, m_left_shift_pressed || m_right_shift_pressed);
break;
case 0x1c:
case 0x35:
if (has_e0_prefix)
m_keyboard_device->update_modifier(Mod_Keypad, key_event.is_press());
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 (!has_e0_prefix)
m_keyboard_device->update_modifier(Mod_Keypad, key_event.is_press());
break;
}
key_event.code_entry = (m_keyboard_device->modifiers() & Mod_Shift) ? shifted_scan_code_set1_key_map[ch] : unshifted_scan_code_set1_key_map[ch];
key_event.scancode = has_e0_prefix ? 0xe000 + ch : ch;
return key_event;
}
Optional<RawKeyEvent> PS2KeyboardDevice::generate_raw_key_event_input_from_set2(ScanCodeEvent event)
{
VERIFY(event.sent_scan_code_set == ScanCodeSet::Set2);
auto get_key_from_standard_key_map = [this](u8 byte) -> KeyCodeEntry {
if (!(m_keyboard_device->modifiers() & Mod_Shift))
return (m_keyboard_device->num_lock_on()) ? unshifted_simple_scan_code_set2_key_map_with_key_num_pad[byte] : unshifted_simple_scan_code_set2_key_map_with_disabled_key_num_pad[byte];
return (m_keyboard_device->num_lock_on()) ? shifted_simple_scan_code_set2_key_map_with_key_num_pad[byte] : shifted_simple_scan_code_set2_key_map_with_disabled_key_num_pad[byte];
};
RawKeyEvent key_event {};
if (event.bytes_count == 1) {
auto byte = event.scan_code_bytes[0];
key_event.code_entry = get_key_from_standard_key_map(byte);
key_event.scancode = byte;
key_event.is_press_down = true;
m_entropy_source.add_random_event(byte);
} else if (event.bytes_count == 2) {
auto byte_prefix = event.scan_code_bytes[0];
auto byte = event.scan_code_bytes[1];
if (byte_prefix == 0xe0) {
key_event.code_entry = unshifted_scan_code_set2_e0_key_map[byte];
key_event.scancode = 0xe000 + byte;
key_event.is_press_down = true;
} else if (byte_prefix == 0xf0) {
key_event.code_entry = get_key_from_standard_key_map(byte);
key_event.scancode = 0xf000 + byte;
} else {
VERIFY_NOT_REACHED();
}
m_entropy_source.add_random_event(byte);
} else if (event.bytes_count == 3) {
auto first_byte_prefix = event.scan_code_bytes[0];
auto second_byte_prefix = event.scan_code_bytes[1];
if (first_byte_prefix != 0xe0
|| second_byte_prefix != 0xf0) {
return Optional<RawKeyEvent> {};
}
auto byte = event.scan_code_bytes[2];
key_event.code_entry = unshifted_scan_code_set2_e0_key_map[byte];
key_event.scancode = 0xe0f000 + byte;
m_entropy_source.add_random_event(byte);
} else if (event.bytes_count == 4) {
// 0xE0, 0x12, 0xE0, 0x7C - print screen pressed
auto first_byte_prefix = event.scan_code_bytes[0];
auto second_byte_prefix = event.scan_code_bytes[1];
auto third_byte_prefix = event.scan_code_bytes[2];
auto fourth_byte_prefix = event.scan_code_bytes[3];
if (first_byte_prefix != 0xe0
|| second_byte_prefix != 0x12
|| third_byte_prefix != 0xe0
|| fourth_byte_prefix != 0x7c) {
return Optional<RawKeyEvent> {};
}
key_event.code_entry = KeyCodeEntry { Key_PrintScreen, 0xFF };
key_event.scancode = 0xe012e07c;
key_event.is_press_down = true;
} else if (event.bytes_count == 6) {
// 0xE0, 0xF0, 0x7C, 0xE0, 0xF0, 0x12 - print screen released
auto first_byte_prefix = event.scan_code_bytes[0];
auto second_byte_prefix = event.scan_code_bytes[1];
auto third_byte_prefix = event.scan_code_bytes[2];
auto fourth_byte_prefix = event.scan_code_bytes[3];
auto fifth_byte_prefix = event.scan_code_bytes[4];
auto sixth_byte_prefix = event.scan_code_bytes[5];
if (first_byte_prefix != 0xe0
|| second_byte_prefix != 0xf0
|| third_byte_prefix != 0x7c
|| fourth_byte_prefix != 0xe0
|| fifth_byte_prefix != 0xf0
|| sixth_byte_prefix != 0x12) {
return Optional<RawKeyEvent> {};
}
key_event.code_entry = KeyCodeEntry { Key_PrintScreen, 0xFF };
key_event.scancode = 0xe0f07ce0f012;
} else if (event.bytes_count == 8) {
// 0xE1, 0x14, 0x77, 0xE1, 0xF0, 0x14, 0xF0, 0x77 - pause pressed
auto first_byte_prefix = event.scan_code_bytes[0];
auto second_byte_prefix = event.scan_code_bytes[1];
auto third_byte_prefix = event.scan_code_bytes[2];
auto fourth_byte_prefix = event.scan_code_bytes[3];
auto fifth_byte_prefix = event.scan_code_bytes[4];
auto sixth_byte_prefix = event.scan_code_bytes[5];
auto seventh_byte_prefix = event.scan_code_bytes[6];
auto eight_byte_prefix = event.scan_code_bytes[7];
if (first_byte_prefix != 0xe1
|| second_byte_prefix != 0x14
|| third_byte_prefix != 0x77
|| fourth_byte_prefix != 0xe1
|| fifth_byte_prefix != 0xf0
|| sixth_byte_prefix != 0x14
|| seventh_byte_prefix != 0xf0
|| eight_byte_prefix != 0x77) {
return Optional<RawKeyEvent> {};
}
key_event.code_entry = KeyCodeEntry { Key_PauseBreak, 0xFF };
key_event.scancode = 0xe11477e1f014f077;
}
switch (key_event.code_entry.key_code) {
case Key_RightAlt:
m_keyboard_device->update_modifier(Mod_AltGr, key_event.is_press());
break;
case Key_Alt:
m_keyboard_device->update_modifier(Mod_Alt, key_event.is_press());
break;
case Key_Control:
m_keyboard_device->update_modifier(Mod_Ctrl, key_event.is_press());
break;
case Key_Super:
m_left_super_pressed = key_event.is_press();
m_keyboard_device->update_modifier(Mod_Super, m_left_super_pressed || m_right_super_pressed);
break;
case Key_LeftShift:
m_left_shift_pressed = key_event.is_press();
m_keyboard_device->update_modifier(Mod_Shift, m_left_shift_pressed || m_right_shift_pressed);
break;
case Key_RightShift:
m_right_shift_pressed = key_event.is_press();
m_keyboard_device->update_modifier(Mod_Shift, m_left_shift_pressed || m_right_shift_pressed);
break;
default:
break;
}
return key_event;
}
void PS2KeyboardDevice::handle_scan_code_input_event(ScanCodeEvent event)
{
RawKeyEvent raw_event {};
if (event.sent_scan_code_set == ScanCodeSet::Set1) {
raw_event = generate_raw_key_event_input_from_set1(event);
} else if (event.sent_scan_code_set == ScanCodeSet::Set2) {
auto possible_raw_event = generate_raw_key_event_input_from_set2(event);
if (!possible_raw_event.has_value()) {
dmesgln("PS2KeyboardDevice BUG: Invalid scan code (set 2) event, length: {}, bytes: {}", event.bytes_count, event.scan_code_bytes.span().trim(event.bytes_count));
return;
}
raw_event = possible_raw_event.release_value();
} else if (event.sent_scan_code_set == ScanCodeSet::Set3) {
// FIXME: Implement support for scan code set 3!
VERIFY_NOT_REACHED();
} else {
VERIFY_NOT_REACHED();
}
KeyEvent queued_event = {
.key = raw_event.code_entry.key_code,
.map_entry_index = raw_event.code_entry.map_entry_index,
.scancode = raw_event.scancode,
.flags = raw_event.is_press() ? (u8)Is_Press : (u8)0,
};
// NOTE: This piece of code is needed for the ScanCodeSet::Set1 to ensure some keys could
// function properly.
if (event.sent_scan_code_set == ScanCodeSet::Set1) {
if ((queued_event.scancode & 0xe000) && queued_event.key == Key_Slash) {
// If Key_Slash (scancode = 0x35) mapped to other form "/", we fix num pad key of "/" with this case.
queued_event.code_point = '/';
} else if ((queued_event.scancode & 0xe000) && queued_event.key != Key_Return) {
// Except for `keypad-/` and 'keypad-return', all e0 scan codes are not actually characters. i.e., `keypad-0` and
// `Insert` have the same scancode except for the prefix, but insert should not have a code_point.
queued_event.code_point = 0;
}
}
// NOTE: This piece of code is needed for the ScanCodeSet::Set1 when NumLock is enabled
// because we don't have special mappings when NumLock is enabled for this scan code set.
// Scan code set 2 handling code in handle_scan_code_input_event_set2() already handles this fine.
if (event.sent_scan_code_set == ScanCodeSet::Set1 && m_keyboard_device->num_lock_on() && !(queued_event.scancode & 0xe000)) {
if (queued_event.scancode >= 0x47 && queued_event.scancode <= 0x53) {
u8 index = queued_event.scancode - 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) {
queued_event.key = newKey;
}
}
}
m_keyboard_device->handle_input_event(queued_event);
}
void PS2KeyboardDevice::handle_byte_read_for_scan_code_set1(u8 byte)
{
u8 ch = byte & 0x7f;
bool pressed = !(byte & 0x80);
dbgln_if(KEYBOARD_DEBUG, "Keyboard::handle_byte_read_for_scan_code_set1: {:#02x} {}", ch, (pressed ? "down" : "up"));
if (byte == 0xe0) {
m_has_e0_prefix = true;
return;
}
ScanCodeEvent event {};
event.pressed = pressed;
event.e0_prefix = m_has_e0_prefix;
event.sent_scan_code_set = ScanCodeSet::Set1;
if (m_has_e0_prefix) {
event.scan_code_bytes[0] = 0xe0;
event.scan_code_bytes[1] = byte;
event.bytes_count = 2;
} else {
event.scan_code_bytes[0] = byte;
event.bytes_count = 1;
}
m_has_e0_prefix = false;
dbgln_if(KEYBOARD_DEBUG, "Keyboard::handle_byte_read_from_serial_input: {:#02x} {}", ch, (pressed ? "down" : "up"));
event.scan_code_value = ch;
m_keyboard_device->handle_scan_code_input_event(event);
handle_scan_code_input_event(event);
}
UNMAP_AFTER_INIT ErrorOr<NonnullOwnPtr<PS2KeyboardDevice>> PS2KeyboardDevice::try_to_initialize(SerialIOController const& serial_io_controller, SerialIOController::PortIndex port_index, KeyboardDevice const& keyboard_device)
void PS2KeyboardDevice::handle_byte_read_for_scan_code_set2(u8 byte)
{
auto device = TRY(adopt_nonnull_own_or_enomem(new (nothrow) PS2KeyboardDevice(serial_io_controller, port_index, keyboard_device)));
dbgln_if(KEYBOARD_DEBUG, "Keyboard::handle_byte_read_for_scan_code_set2: {:#02x}", byte);
ScanCodeEvent event {};
event.sent_scan_code_set = ScanCodeSet::Set2;
if (m_received_bytes_count == 0) {
if (byte == 0xe0 || byte == 0xf0 || byte == 0xe1) {
m_received_bytes[0] = byte;
m_received_bytes_count++;
return;
}
event.scan_code_bytes[0] = byte;
event.bytes_count = 1;
m_received_bytes_count = 0;
handle_scan_code_input_event(event);
return;
} else if (m_received_bytes_count == 1) {
if (byte == 0xf0) {
VERIFY(m_received_bytes[0] == 0xe0);
m_received_bytes[1] = byte;
m_received_bytes_count++;
return;
}
if (m_received_bytes[0] == 0xe0 && byte == 0x12) {
m_received_bytes[1] = byte;
m_received_bytes_count++;
return;
}
if (m_received_bytes[0] == 0xe1 && byte == 0x14) {
m_received_bytes[1] = byte;
m_received_bytes_count++;
return;
}
event.scan_code_bytes[0] = m_received_bytes[0];
event.scan_code_bytes[1] = byte;
event.bytes_count = 2;
m_received_bytes_count = 0;
handle_scan_code_input_event(event);
return;
} else if (m_received_bytes_count == 2) {
if (m_received_bytes[0] == 0xe0 && m_received_bytes[1] == 0x12 && byte == 0xe0) {
m_received_bytes[2] = byte;
m_received_bytes_count++;
return;
}
if (m_received_bytes[0] == 0xe0 && m_received_bytes[1] == 0xf0 && byte == 0x7c) {
m_received_bytes[2] = byte;
m_received_bytes_count++;
return;
}
if (m_received_bytes[0] == 0xe1) {
VERIFY(m_received_bytes[1] == 0x14);
m_received_bytes[2] = byte;
m_received_bytes_count++;
return;
}
event.scan_code_bytes[0] = m_received_bytes[0];
event.scan_code_bytes[1] = m_received_bytes[1];
event.scan_code_bytes[2] = byte;
event.bytes_count = 3;
m_received_bytes_count = 0;
handle_scan_code_input_event(event);
return;
} else if (m_received_bytes_count == 3) {
if (m_received_bytes[0] == 0xe0
&& m_received_bytes[1] == 0x12
&& m_received_bytes[2] == 0xe0
&& byte == 0x7c) {
ScanCodeEvent event {};
event.sent_scan_code_set = ScanCodeSet::Set2;
event.scan_code_bytes[0] = m_received_bytes[0];
event.scan_code_bytes[1] = m_received_bytes[1];
event.scan_code_bytes[2] = m_received_bytes[2];
event.scan_code_bytes[3] = byte;
event.bytes_count = 4;
m_received_bytes_count = 0;
handle_scan_code_input_event(event);
return;
}
m_received_bytes[3] = byte;
m_received_bytes_count++;
return;
} else if (m_received_bytes_count == 4) {
m_received_bytes[4] = byte;
m_received_bytes_count++;
return;
} else if (m_received_bytes_count == 5) {
if (m_received_bytes[0] == 0xe0
&& m_received_bytes[1] == 0xf0
&& m_received_bytes[2] == 0x7c
&& m_received_bytes[3] == 0xe0
&& m_received_bytes[4] == 0xf0
&& byte == 0x12) {
event.scan_code_bytes[0] = m_received_bytes[0];
event.scan_code_bytes[1] = m_received_bytes[1];
event.scan_code_bytes[2] = m_received_bytes[2];
event.scan_code_bytes[3] = m_received_bytes[3];
event.scan_code_bytes[4] = m_received_bytes[4];
event.scan_code_bytes[5] = byte;
event.bytes_count = 6;
m_received_bytes_count = 0;
handle_scan_code_input_event(event);
return;
}
m_received_bytes[5] = byte;
m_received_bytes_count++;
return;
} else if (m_received_bytes_count == 6) {
m_received_bytes[6] = byte;
m_received_bytes_count++;
return;
} else if (m_received_bytes_count == 7) {
event.scan_code_bytes[0] = m_received_bytes[0];
event.scan_code_bytes[1] = m_received_bytes[1];
event.scan_code_bytes[2] = m_received_bytes[2];
event.scan_code_bytes[3] = m_received_bytes[3];
event.scan_code_bytes[4] = m_received_bytes[4];
event.scan_code_bytes[5] = m_received_bytes[5];
event.scan_code_bytes[6] = m_received_bytes[6];
event.scan_code_bytes[7] = byte;
event.bytes_count = 8;
m_received_bytes_count = 0;
handle_scan_code_input_event(event);
return;
} else {
VERIFY_NOT_REACHED();
}
}
void PS2KeyboardDevice::handle_byte_read_from_serial_input(u8 byte)
{
switch (m_scan_code_set) {
case ScanCodeSet::Set1:
handle_byte_read_for_scan_code_set1(byte);
break;
case ScanCodeSet::Set2:
handle_byte_read_for_scan_code_set2(byte);
break;
default:
VERIFY_NOT_REACHED();
}
}
UNMAP_AFTER_INIT ErrorOr<NonnullOwnPtr<PS2KeyboardDevice>> PS2KeyboardDevice::try_to_initialize(SerialIOController const& serial_io_controller, SerialIOController::PortIndex port_index, ScanCodeSet scan_code_set, KeyboardDevice const& keyboard_device)
{
auto device = TRY(adopt_nonnull_own_or_enomem(new (nothrow) PS2KeyboardDevice(serial_io_controller, port_index, scan_code_set, keyboard_device)));
TRY(device->initialize());
return device;
}
@ -74,9 +745,10 @@ UNMAP_AFTER_INIT ErrorOr<void> PS2KeyboardDevice::initialize()
// FIXME: UNMAP_AFTER_INIT might not be correct, because in practice PS/2 devices
// are hot pluggable.
UNMAP_AFTER_INIT PS2KeyboardDevice::PS2KeyboardDevice(SerialIOController const& serial_io_controller, SerialIOController::PortIndex port_index, KeyboardDevice const& keyboard_device)
UNMAP_AFTER_INIT PS2KeyboardDevice::PS2KeyboardDevice(SerialIOController const& serial_io_controller, SerialIOController::PortIndex port_index, ScanCodeSet scan_code_set, KeyboardDevice const& keyboard_device)
: SerialIODevice(serial_io_controller, port_index)
, m_keyboard_device(keyboard_device)
, m_scan_code_set(scan_code_set)
{
}

View file

@ -10,6 +10,7 @@
#include <AK/Types.h>
#include <Kernel/API/KeyCode.h>
#include <Kernel/Bus/SerialIO/Device.h>
#include <Kernel/Devices/HID/Definitions.h>
#include <Kernel/Devices/HID/KeyboardDevice.h>
#include <Kernel/Security/Random.h>
@ -19,7 +20,7 @@ class PS2KeyboardDevice final : public SerialIODevice {
friend class DeviceManagement;
public:
static ErrorOr<NonnullOwnPtr<PS2KeyboardDevice>> try_to_initialize(SerialIOController const&, SerialIOController::PortIndex port_index, KeyboardDevice const&);
static ErrorOr<NonnullOwnPtr<PS2KeyboardDevice>> try_to_initialize(SerialIOController const&, SerialIOController::PortIndex port_index, ScanCodeSet scan_code_set, KeyboardDevice const&);
virtual ~PS2KeyboardDevice() override;
ErrorOr<void> initialize();
@ -27,11 +28,37 @@ public:
virtual void handle_byte_read_from_serial_input(u8 byte) override;
private:
PS2KeyboardDevice(SerialIOController const&, SerialIOController::PortIndex port_index, KeyboardDevice const&);
PS2KeyboardDevice(SerialIOController const&, SerialIOController::PortIndex port_index, ScanCodeSet scan_code_set, KeyboardDevice const&);
RawKeyEvent generate_raw_key_event_input_from_set1(ScanCodeEvent);
Optional<RawKeyEvent> generate_raw_key_event_input_from_set2(ScanCodeEvent);
void handle_scan_code_input_event(ScanCodeEvent event);
void handle_byte_read_for_scan_code_set1(u8 byte);
void handle_byte_read_for_scan_code_set2(u8 byte);
// NOTE: This boolean variable is only used with ScanCodeSet::Set1
// because it only has one prefix defined in the scan code set.
bool m_has_e0_prefix { false };
// NOTE: This array and its counter are used only when m_scan_code_set
// is set to ScanCodeSet::Set2, because that scan code requires us to
// manage scan codes with multiple bytes.
// According to the scan code set 2 table, a key press (or release)
// can generate up to 8 bytes.
Array<u8, 8> m_received_bytes;
size_t m_received_bytes_count { 0 };
bool m_left_shift_pressed { false };
bool m_right_shift_pressed { false };
bool m_left_super_pressed { false };
bool m_right_super_pressed { false };
NonnullRefPtr<KeyboardDevice> const m_keyboard_device;
ScanCodeSet const m_scan_code_set { ScanCodeSet::Set1 };
EntropySource m_entropy_source;
};
}

View file

@ -7,13 +7,14 @@
#pragma once
#include <AK/Types.h>
#include <Kernel/Devices/HID/Definitions.h>
namespace Kernel {
struct ScanCodeEvent {
u32 scan_code_value { 0 };
bool pressed { false };
bool e0_prefix { false };
Array<u8, 8> scan_code_bytes;
ScanCodeSet sent_scan_code_set { ScanCodeSet::Set1 };
u8 bytes_count { 0 };
};
}

View file

@ -143,8 +143,9 @@ static ErrorOr<Optional<String>> get_event_named_key(KeyCode platform_key)
// 3.2. Modifier Keys, https://www.w3.org/TR/uievents-key/#keys-modifier
case KeyCode::Key_Alt:
return "Alt"_string;
// FIXME: AltGraph
return "AltLeft"_string;
case KeyCode::Key_RightAlt:
return "AltRight"_string;
case KeyCode::Key_CapsLock:
return "CapsLock"_string;
case KeyCode::Key_Control:
@ -457,7 +458,9 @@ static ErrorOr<String> get_event_code(KeyCode platform_key, unsigned modifiers)
// 3.1.2. Functional Keys, https://www.w3.org/TR/uievents-code/#key-alphanumeric-functional
case KeyCode::Key_Alt:
return "Alt"_string; // FIXME: Detect left vs. right key.
return "AltLeft"_string;
case KeyCode::Key_RightAlt:
return "AltRight"_string;
case KeyCode::Key_Backspace:
return "Backspace"_string;
case KeyCode::Key_CapsLock:
@ -465,7 +468,9 @@ static ErrorOr<String> get_event_code(KeyCode platform_key, unsigned modifiers)
case KeyCode::Key_Menu:
return "ContextMenu"_string;
case KeyCode::Key_Control:
return "Control"_string; // FIXME: Detect left vs. right key.
return "ControlLeft"_string;
case KeyCode::Key_RightControl:
return "ControlRight"_string;
case KeyCode::Key_Return:
return "Enter"_string;
case KeyCode::Key_Super:
@ -540,7 +545,60 @@ static ErrorOr<String> get_event_code(KeyCode platform_key, unsigned modifiers)
return "PrintScreen"_string;
case KeyCode::Key_ScrollLock:
return "ScrollLock"_string;
// FIXME: Pause
case KeyCode::Key_PauseBreak:
return "Pause"_string;
// 3.6. Media Section, https://www.w3.org/TR/uievents-code/#media-keys
case KeyCode::Key_BrowserSearch:
return "BrowserSearch"_string;
case KeyCode::Key_BrowserFavorites:
return "BrowserFavorites"_string;
case KeyCode::Key_BrowserHome:
return "BrowserHome"_string;
case KeyCode::Key_PreviousTrack:
return "PreviousTrack"_string;
case KeyCode::Key_BrowserBack:
return "BrowserBack"_string;
case KeyCode::Key_BrowserForward:
return "BrowserForward"_string;
case KeyCode::Key_BrowserRefresh:
return "BrowserRefresh"_string;
case KeyCode::Key_BrowserStop:
return "BrowserStop"_string;
case KeyCode::Key_VolumeDown:
return "AudioVolumeDown"_string;
case KeyCode::Key_VolumeUp:
return "AudioVolumeUp"_string;
case KeyCode::Key_Wake:
return "WakeUp"_string;
case KeyCode::Key_Sleep:
return "Sleep"_string;
case KeyCode::Key_NextTrack:
return "NextTrack"_string;
case KeyCode::Key_MediaSelect:
return "MediaSelect"_string;
case KeyCode::Key_Email:
return "LaunchMail"_string;
case KeyCode::Key_Power:
return "Power"_string;
case KeyCode::Key_Stop:
return "MediaStop"_string;
case KeyCode::Key_PlayPause:
return "MediaPlayPause"_string;
case KeyCode::Key_Mute:
return "AudioVolumeMute"_string;
case KeyCode::Key_Calculator:
return "LaunchApp2"_string;
case KeyCode::Key_MyComputer:
return "LaunchApp1"_string;
// FIXME: Are these correct?
case KeyCode::Key_LeftGUI:
return "LaunchApp2"_string;
case KeyCode::Key_RightGUI:
case KeyCode::Key_Apps:
return "LaunchApp1"_string;
// 3.7. Legacy, Non-Standard and Special Keys, https://www.w3.org/TR/uievents-code/#key-legacy
case KeyCode::Key_Invalid: