Kernel: Rework the whole input system

We now use Device abstraction that will allow us to provide devices
to userspace through /dev. Currently Shell reads from first and only
device (it being PS/2 Keyboard).
This commit is contained in:
Bananymous
2023-03-29 03:05:16 +03:00
parent e5c3486826
commit fa8e921ee8
16 changed files with 1339 additions and 775 deletions

View File

@@ -0,0 +1,334 @@
#include <BAN/ScopeGuard.h>
#include <kernel/ACPI.h>
#include <kernel/IDT.h>
#include <kernel/Input/PS2Controller.h>
#include <kernel/Input/PS2Keyboard.h>
#include <kernel/InterruptController.h>
#include <kernel/IO.h>
namespace Kernel::Input
{
namespace PS2
{
enum IOPort : uint8_t
{
DATA = 0x60,
STATUS = 0x64,
COMMAND = 0x64,
};
enum Status : uint8_t
{
OUTPUT_FULL = (1 << 0),
INPUT_FULL = (1 << 1),
SYSTEM = (1 << 2),
DEVICE_OR_CONTROLLER = (1 << 3),
TIMEOUT_ERROR = (1 << 6),
PARITY_ERROR = (1 << 7),
};
enum Config : uint8_t
{
INTERRUPT_FIRST_PORT = (1 << 0),
INTERRUPT_SECOND_PORT = (1 << 1),
SYSTEM_FLAG = (1 << 2),
ZERO1 = (1 << 3),
CLOCK_FIRST_PORT = (1 << 4),
CLOCK_SECOND_PORT = (1 << 5),
TRANSLATION_FIRST_PORT = (1 << 6),
ZERO2 = (1 << 7),
};
enum Command : uint8_t
{
READ_CONFIG = 0x20,
WRITE_CONFIG = 0x60,
DISABLE_SECOND_PORT = 0xA7,
ENABLE_SECOND_PORT = 0xA8,
TEST_SECOND_PORT = 0xA9,
TEST_CONTROLLER = 0xAA,
TEST_FIRST_PORT = 0xAB,
DISABLE_FIRST_PORT = 0xAD,
ENABLE_FIRST_PORT = 0xAE,
WRITE_TO_SECOND_PORT = 0xD4,
};
enum Response
{
TEST_FIRST_PORT_PASS = 0x00,
TEST_SECOND_PORT_PASS = 0x00,
TEST_CONTROLLER_PASS = 0x55,
SELF_TEST_PASS = 0xAA,
ACK = 0xFA,
};
enum DeviceCommand
{
ENABLE_SCANNING = 0xF4,
DISABLE_SCANNING = 0xF5,
IDENTIFY = 0xF2,
RESET = 0xFF,
};
enum IRQ
{
DEVICE0 = 1,
DEVICE1 = 12,
};
}
static constexpr uint64_t s_device_timeout_ms = 100;
static void controller_send_command(PS2::Command command)
{
IO::outb(PS2::IOPort::COMMAND, command);
}
static void controller_send_command(PS2::Command command, uint8_t data)
{
IO::outb(PS2::IOPort::COMMAND, command);
while (IO::inb(PS2::IOPort::STATUS) & PS2::Status::INPUT_FULL)
continue;
IO::outb(PS2::IOPort::DATA, data);
}
static uint8_t wait_and_read()
{
while (!(IO::inb(PS2::IOPort::STATUS) & PS2::Status::OUTPUT_FULL))
continue;
return IO::inb(PS2::IOPort::DATA);
}
static BAN::ErrorOr<void> device_send_byte(uint8_t device, uint8_t byte)
{
if (device == 1)
IO::outb(PS2::IOPort::COMMAND, PS2::Command::WRITE_TO_SECOND_PORT);
uint64_t timeout = PIT::ms_since_boot() + s_device_timeout_ms;
while (PIT::ms_since_boot() < timeout)
{
if (!(IO::inb(PS2::IOPort::STATUS) & PS2::Status::INPUT_FULL))
{
IO::outb(PS2::IOPort::DATA, byte);
return {};
}
}
return BAN::Error::from_c_string("PS/2 device timeout");
}
static BAN::ErrorOr<uint8_t> device_read_byte()
{
uint64_t timeout = PIT::ms_since_boot() + s_device_timeout_ms;
while (PIT::ms_since_boot() < timeout)
if (IO::inb(PS2::IOPort::STATUS) & PS2::Status::OUTPUT_FULL)
return IO::inb(PS2::IOPort::DATA);
return BAN::Error::from_c_string("PS/2 device timeout");
}
static BAN::ErrorOr<void> device_wait_ack()
{
while (TRY(device_read_byte()) != PS2::Response::ACK)
continue;;
return {};
}
void PS2Controller::device0_irq()
{
auto& controller = PS2Controller::get();
ASSERT(controller.m_devices[0] != nullptr);
controller.m_devices[0]->on_byte(IO::inb(PS2::IOPort::DATA));
}
void PS2Controller::device1_irq()
{
auto& controller = PS2Controller::get();
ASSERT(controller.m_devices[1] != nullptr);
controller.m_devices[1]->on_byte(IO::inb(PS2::IOPort::DATA));
}
static PS2Controller* s_instance = nullptr;
BAN::ErrorOr<void> PS2Controller::initialize()
{
ASSERT(s_instance == nullptr);
s_instance = new PS2Controller;
if (s_instance == nullptr)
return BAN::Error::from_errno(ENOMEM);
BAN::ScopeGuard guard([] { delete s_instance; });
TRY(s_instance->initialize_impl());
guard.disable();
return {};
}
PS2Controller& PS2Controller::get()
{
ASSERT(s_instance != nullptr);
return *s_instance;
}
BAN::ErrorOr<void> PS2Controller::initialize_impl()
{
// Step 1: Initialise USB Controllers
// FIXME
// Step 2: Determine if the PS/2 Controller Exists
if (false)
{
const ACPI::FADT* fadt = (const ACPI::FADT*)TRY(ACPI::get().get_header("FACP"));
bool ps2_exists = fadt->iapc_boot_arch & (1 << 1);
ACPI::get().unmap_header(fadt);
if (!ps2_exists)
return BAN::Error::from_c_string("PS2 Controller does not exist");
}
// Step 3: Disable Devices
controller_send_command(PS2::Command::DISABLE_FIRST_PORT);
controller_send_command(PS2::Command::DISABLE_SECOND_PORT);
// Step 4: Flush The Output Buffer
IO::inb(PS2::IOPort::DATA);
// Step 5: Set the Controller Configuration Byte
controller_send_command(PS2::Command::READ_CONFIG);
uint8_t config = wait_and_read();
config &= ~PS2::Config::INTERRUPT_FIRST_PORT;
config &= ~PS2::Config::INTERRUPT_SECOND_PORT;
config &= ~PS2::Config::TRANSLATION_FIRST_PORT;
controller_send_command(PS2::Command::WRITE_CONFIG, config);
// Step 6: Perform Controller Self Test
controller_send_command(PS2::Command::TEST_CONTROLLER);
if (wait_and_read() != PS2::Response::TEST_CONTROLLER_PASS)
return BAN::Error::from_c_string("PS/2 Controller self test failed");
// NOTE: self test might reset the device so we set the config byte again
controller_send_command(PS2::Command::WRITE_CONFIG, config);
// Step 7: Determine If There Are 2 Channels
bool valid_ports[2] { true, false };
if (config & PS2::Config::CLOCK_SECOND_PORT)
{
controller_send_command(PS2::Command::ENABLE_SECOND_PORT);
controller_send_command(PS2::Command::READ_CONFIG);
if (!(wait_and_read() & PS2::Config::CLOCK_SECOND_PORT))
valid_ports[1] = true;
controller_send_command(PS2::Command::DISABLE_SECOND_PORT);
}
// Step 8: Perform Interface Tests
controller_send_command(PS2::Command::TEST_FIRST_PORT);
if (wait_and_read() != PS2::Response::TEST_FIRST_PORT_PASS)
valid_ports[0] = false;
if (valid_ports[1])
{
controller_send_command(PS2::Command::TEST_SECOND_PORT);
if (wait_and_read() != PS2::Response::TEST_SECOND_PORT_PASS)
valid_ports[1] = false;
}
if (!valid_ports[0] && !valid_ports[1])
return BAN::Error::from_c_string("No ports available on Controller");
// Step 9: Enable Devices (and disable scanning)
for (uint8_t device = 0; device < 2; device++)
{
if (!valid_ports[device])
continue;
controller_send_command(device == 0 ? PS2::Command::ENABLE_FIRST_PORT : PS2::Command::ENABLE_SECOND_PORT);
if (set_scanning(device, false).is_error())
valid_ports[device] = false;
}
// Step 10: Reset Devices
for (uint8_t device = 0; device < 2; device++)
{
if (!valid_ports[device])
continue;
if (reset_device(device).is_error())
valid_ports[device] = false;
if (set_scanning(device, false).is_error())
valid_ports[device] = false;
}
// Step 11: Initialize Device Drivers
for (uint8_t device = 0; device < 2; device++)
{
if (!valid_ports[device])
continue;
if (auto res = initialize_device(device); res.is_error())
dprintln("{}", res.error());
}
if (m_devices[0])
{
IDT::register_irq_handler(PS2::IRQ::DEVICE0, device0_irq);
InterruptController::get().enable_irq(PS2::IRQ::DEVICE0);
config |= PS2::Config::INTERRUPT_FIRST_PORT;
DeviceManager::get().add_device(m_devices[0]);
}
if (m_devices[1])
{
IDT::register_irq_handler(PS2::IRQ::DEVICE1, device1_irq);
InterruptController::get().enable_irq(PS2::IRQ::DEVICE1);
config |= PS2::Config::INTERRUPT_SECOND_PORT;
DeviceManager::get().add_device(m_devices[1]);
}
controller_send_command(PS2::Command::WRITE_CONFIG, config);
return {};
}
BAN::ErrorOr<void> PS2Controller::initialize_device(uint8_t device)
{
TRY(device_send_byte(device, PS2::DeviceCommand::IDENTIFY));
TRY(device_wait_ack());
uint8_t bytes[2] {};
uint8_t index = 0;
for (uint8_t i = 0; i < 2; i++)
{
auto res = device_read_byte();
if (res.is_error())
break;
bytes[index++] = res.value();
}
// Standard PS/2 Mouse
if (index == 1 && (bytes[0] == 0x00))
return BAN::Error::from_c_string("PS/2 mouse not supported");
// MF2 Keyboard
if (index == 2 && (bytes[0] == 0xAB && bytes[1] == 0x83))
m_devices[device] = TRY(PS2Keyboard::create(*this));
if (m_devices[device])
return {};
return BAN::Error::from_format("Unhandled PS/2 device {}{} ({} bytes)", bytes[0], bytes[1], index);
}
void PS2Controller::send_byte(const PS2Device* device, uint8_t byte)
{
ASSERT(device != nullptr && (device == m_devices[0] || device == m_devices[1]));
uint8_t device_index = (device == m_devices[0]) ? 0 : 1;
MUST(device_send_byte(device_index, byte));
}
BAN::ErrorOr<void> PS2Controller::reset_device(uint8_t device)
{
TRY(device_send_byte(device, PS2::DeviceCommand::RESET));
TRY(device_wait_ack());
if (TRY(device_read_byte()) != PS2::Response::SELF_TEST_PASS)
return BAN::Error::from_c_string("Device reset failed");
return {};
}
BAN::ErrorOr<void> PS2Controller::set_scanning(uint8_t device, bool enabled)
{
TRY(device_send_byte(device, enabled ? PS2::DeviceCommand::ENABLE_SCANNING : PS2::DeviceCommand::DISABLE_SCANNING));
TRY(device_wait_ack());
return {};
}
}

View File

@@ -0,0 +1,244 @@
#include <BAN/ScopeGuard.h>
#include <kernel/CriticalScope.h>
#include <kernel/Input/PS2Keyboard.h>
#define SET_MASK(byte, mask, on_off) ((on_off) ? ((byte) | (mask)) : ((byte) & ~(mask)))
#define TOGGLE_MASK(byte, mask) ((byte) ^ (mask))
namespace Kernel::Input
{
namespace PS2
{
enum Response
{
KEY_ERROR_OR_BUFFER_OVERRUN1 = 0x00,
SELF_TEST_PASSED = 0xAA,
ECHO_RESPONSE = 0xEE,
ACK = 0xFA,
RESEND = 0xFE,
KEY_ERROR_OR_BUFFER_OVERRUN2 = 0xFF,
};
enum Scancode
{
SET_SCANCODE_SET1 = 1,
SET_SCANCODE_SET2 = 2,
SET_SCANCODE_SET3 = 3,
};
enum Leds
{
SCROLL_LOCK = (1 << 0),
NUM_LOCK = (1 << 1),
CAPS_LOCK = (1 << 2),
};
}
BAN::ErrorOr<PS2Keyboard*> PS2Keyboard::create(PS2Controller& controller)
{
PS2Keyboard* keyboard = new PS2Keyboard(controller);
if (keyboard == nullptr)
return BAN::Error::from_errno(ENOMEM);
BAN::ScopeGuard guard([keyboard] { delete keyboard; });
TRY(keyboard->initialize());
guard.disable();
return keyboard;
}
void PS2Keyboard::on_byte(uint8_t byte)
{
// NOTE: This implementation does not allow using commands
// that respond with more bytes than ACK
switch (m_state)
{
case State::WaitingAck:
{
switch (byte)
{
case PS2::Response::ACK:
m_command_queue.pop();
m_state = State::Normal;
break;
case PS2::Response::RESEND:
m_state = State::Normal;
break;
case PS2::Response::KEY_ERROR_OR_BUFFER_OVERRUN1:
case PS2::Response::KEY_ERROR_OR_BUFFER_OVERRUN2:
dwarnln("Key detection error or internal buffer overrun");
break;
default:
dwarnln("Unhandeled byte {2H}", byte);
break;
}
break;
}
case State::Normal:
{
m_byte_buffer[m_byte_index++] = byte;
if (byte != 0xE0 && byte != 0xF0)
buffer_has_key();
break;
}
}
}
BAN::ErrorOr<void> PS2Keyboard::initialize()
{
append_command_queue(Command::SET_LEDS, 0x00);
append_command_queue(Command::SCANCODE, PS2::Scancode::SET_SCANCODE_SET2);
append_command_queue(Command::ENABLE_SCANNING);
return {};
}
void PS2Keyboard::update()
{
if (m_state == State::WaitingAck)
return;
if (m_command_queue.empty())
return;
m_state = State::WaitingAck;
m_controller.send_byte(this, m_command_queue.front());
}
void PS2Keyboard::append_command_queue(uint8_t byte)
{
if (m_command_queue.full())
{
dwarnln("PS/2 command queue full");
return;
}
m_command_queue.push(byte);
}
void PS2Keyboard::append_command_queue(uint8_t byte1, uint8_t byte2)
{
if (m_command_queue.size() + 2 > m_command_queue.capacity())
{
dwarnln("PS/2 command queue full");
return;
}
m_command_queue.push(byte1);
m_command_queue.push(byte2);
}
void PS2Keyboard::buffer_has_key()
{
uint32_t scancode = 0;
bool extended = false;
bool released = false;
for (uint8_t i = 0; i < m_byte_index; i++)
{
if (m_byte_buffer[i] == 0xE0)
extended = true;
else if (m_byte_buffer[i] == 0xF0)
released = true;
else
scancode = (scancode << 8) | m_byte_buffer[i];
}
if (extended)
scancode |= 0x80000000;
m_byte_index = 0;
Key key = m_keymap.key_for_scancode_and_modifiers(scancode, m_modifiers);
if (key == Key::None)
return;
if (key == Input::Key::Invalid)
{
dprintln("unknown key for scancode {2H} {}", scancode & 0x7FFFFFFF, extended ? 'E' : ' ');
return;
}
uint8_t modifier_mask = 0;
uint8_t toggle_mask = 0;
switch (key)
{
case Input::Key::LeftShift:
case Input::Key::RightShift:
modifier_mask = (uint8_t)Input::KeyEvent::Modifier::Shift;
break;
case Input::Key::LeftCtrl:
case Input::Key::RightCtrl:
modifier_mask = (uint8_t)Input::KeyEvent::Modifier::Ctrl;
break;
case Input::Key::Alt:
modifier_mask = (uint8_t)Input::KeyEvent::Modifier::Alt;
break;
case Input::Key::AltGr:
modifier_mask = (uint8_t)Input::KeyEvent::Modifier::AltGr;
break;;
case Input::Key::ScrollLock:
toggle_mask = (uint8_t)Input::KeyEvent::Modifier::ScrollLock;
break;
case Input::Key::NumLock:
toggle_mask = (uint8_t)Input::KeyEvent::Modifier::NumLock;
break;
case Input::Key::CapsLock:
toggle_mask = (uint8_t)Input::KeyEvent::Modifier::CapsLock;
break;
default:
break;
}
if (modifier_mask)
{
if (released)
m_modifiers &= ~modifier_mask;
else
m_modifiers |= modifier_mask;
}
if (toggle_mask && !released)
{
m_modifiers ^= toggle_mask;
update_leds();
}
Input::KeyEvent event;
event.modifier = m_modifiers | (released ? (uint8_t)Input::KeyEvent::Modifier::Released : 0);
event.key = key;
if (m_event_queue.full())
{
dwarnln("PS/2 event queue full");
m_event_queue.pop();
}
m_event_queue.push(event);
}
void PS2Keyboard::update_leds()
{
uint8_t new_leds = 0;
if (m_modifiers & (uint8_t)Input::KeyEvent::Modifier::ScrollLock)
new_leds |= PS2::Leds::SCROLL_LOCK;
if (m_modifiers & (uint8_t)Input::KeyEvent::Modifier::NumLock)
new_leds |= PS2::Leds::NUM_LOCK;
if (m_modifiers & (uint8_t)Input::KeyEvent::Modifier::CapsLock)
new_leds |= PS2::Leds::CAPS_LOCK;
append_command_queue(Command::SET_LEDS, new_leds);
}
BAN::ErrorOr<void> PS2Keyboard::read(BAN::Span<uint8_t> output)
{
if (output.size() < sizeof(Input::KeyEvent))
return BAN::Error::from_c_string("Too small buffer for KeyEvent");
while (m_event_queue.empty())
PIT::sleep(1);
CriticalScope _;
*(Input::KeyEvent*)output.data() = m_event_queue.front();
m_event_queue.pop();
return {};
}
}

View File

@@ -0,0 +1,360 @@
#include <kernel/Input/PS2Keymap.h>
namespace Kernel::Input
{
PS2Keymap::PS2Keymap()
{
MUST(m_normal_keymap.resize(0xFF, Key::Invalid));
m_normal_keymap[0x01] = Key::F9;
m_normal_keymap[0x03] = Key::F5;
m_normal_keymap[0x04] = Key::F3;
m_normal_keymap[0x05] = Key::F1;
m_normal_keymap[0x06] = Key::F2;
m_normal_keymap[0x07] = Key::F11;
m_normal_keymap[0x09] = Key::F10;
m_normal_keymap[0x0A] = Key::F8;
m_normal_keymap[0x0B] = Key::F6;
m_normal_keymap[0x0C] = Key::F4;
m_normal_keymap[0x0D] = Key::Tab;
m_normal_keymap[0x0E] = Key::Section;
m_normal_keymap[0x11] = Key::Alt;
m_normal_keymap[0x12] = Key::LeftShift;
m_normal_keymap[0x14] = Key::LeftCtrl;
m_normal_keymap[0x15] = Key::Q;
m_normal_keymap[0x16] = Key::_1;
m_normal_keymap[0x1A] = Key::Z;
m_normal_keymap[0x1B] = Key::S;
m_normal_keymap[0x1C] = Key::A;
m_normal_keymap[0x1D] = Key::W;
m_normal_keymap[0x1E] = Key::_2;
m_normal_keymap[0x21] = Key::C;
m_normal_keymap[0x22] = Key::X;
m_normal_keymap[0x23] = Key::D;
m_normal_keymap[0x24] = Key::E;
m_normal_keymap[0x25] = Key::_4;
m_normal_keymap[0x26] = Key::_3;
m_normal_keymap[0x29] = Key::Space;
m_normal_keymap[0x2A] = Key::V;
m_normal_keymap[0x2B] = Key::F;
m_normal_keymap[0x2C] = Key::T;
m_normal_keymap[0x2D] = Key::R;
m_normal_keymap[0x2E] = Key::_5;
m_normal_keymap[0x31] = Key::N;
m_normal_keymap[0x32] = Key::B;
m_normal_keymap[0x33] = Key::H;
m_normal_keymap[0x34] = Key::G;
m_normal_keymap[0x35] = Key::Y;
m_normal_keymap[0x36] = Key::_6;
m_normal_keymap[0x3A] = Key::M;
m_normal_keymap[0x3B] = Key::J;
m_normal_keymap[0x3C] = Key::U;
m_normal_keymap[0x3D] = Key::_7;
m_normal_keymap[0x3E] = Key::_8;
m_normal_keymap[0x41] = Key::Comma;
m_normal_keymap[0x42] = Key::K;
m_normal_keymap[0x43] = Key::I;
m_normal_keymap[0x44] = Key::O;
m_normal_keymap[0x45] = Key::_0;
m_normal_keymap[0x46] = Key::_9;
m_normal_keymap[0x49] = Key::Period;
m_normal_keymap[0x4A] = Key::Hyphen;
m_normal_keymap[0x4B] = Key::L;
m_normal_keymap[0x4C] = Key::O_Umlaut;
m_normal_keymap[0x4D] = Key::P;
m_normal_keymap[0x4E] = Key::Plus;
m_normal_keymap[0x52] = Key::A_Umlaut;
m_normal_keymap[0x54] = Key::A_Ring;
m_normal_keymap[0x55] = Key::Acute;
m_normal_keymap[0x58] = Key::CapsLock;
m_normal_keymap[0x59] = Key::RightShift;
m_normal_keymap[0x59] = Key::RightShift;
m_normal_keymap[0x5A] = Key::Enter;
m_normal_keymap[0x5B] = Key::TwoDots;
m_normal_keymap[0x5D] = Key::SingleQuote;
m_normal_keymap[0x61] = Key::LessThan;
m_normal_keymap[0x66] = Key::Backspace;
m_normal_keymap[0x69] = Key::Numpad1;
m_normal_keymap[0x6B] = Key::Numpad4;
m_normal_keymap[0x6C] = Key::Numpad7;
m_normal_keymap[0x70] = Key::Numpad0;
m_normal_keymap[0x71] = Key::NumpadDecimal;
m_normal_keymap[0x72] = Key::Numpad2;
m_normal_keymap[0x73] = Key::Numpad5;
m_normal_keymap[0x74] = Key::Numpad6;
m_normal_keymap[0x75] = Key::Numpad8;
m_normal_keymap[0x76] = Key::Escape;
m_normal_keymap[0x77] = Key::NumLock;
m_normal_keymap[0x78] = Key::F11;
m_normal_keymap[0x79] = Key::NumpadPlus;
m_normal_keymap[0x7A] = Key::Numpad3;
m_normal_keymap[0x7B] = Key::NumpadMinus;
m_normal_keymap[0x7C] = Key::NumpadMultiply;
m_normal_keymap[0x7D] = Key::Numpad9;
m_normal_keymap[0x83] = Key::F7;
MUST(m_shift_keymap.resize(0xFF, Key::Invalid));
m_shift_keymap[0x01] = Key::F9;
m_shift_keymap[0x03] = Key::F5;
m_shift_keymap[0x04] = Key::F3;
m_shift_keymap[0x05] = Key::F1;
m_shift_keymap[0x06] = Key::F2;
m_shift_keymap[0x07] = Key::F11;
m_shift_keymap[0x09] = Key::F10;
m_shift_keymap[0x0A] = Key::F8;
m_shift_keymap[0x0B] = Key::F6;
m_shift_keymap[0x0C] = Key::F4;
m_shift_keymap[0x0D] = Key::Tab;
m_shift_keymap[0x0E] = Key::Half;
m_shift_keymap[0x11] = Key::Alt;
m_shift_keymap[0x12] = Key::LeftShift;
m_shift_keymap[0x14] = Key::LeftCtrl;
m_shift_keymap[0x15] = Key::Q;
m_shift_keymap[0x16] = Key::ExclamationMark;
m_shift_keymap[0x1A] = Key::Z;
m_shift_keymap[0x1B] = Key::S;
m_shift_keymap[0x1C] = Key::A;
m_shift_keymap[0x1D] = Key::W;
m_shift_keymap[0x1E] = Key::DoubleQuote;
m_shift_keymap[0x21] = Key::C;
m_shift_keymap[0x22] = Key::X;
m_shift_keymap[0x23] = Key::D;
m_shift_keymap[0x24] = Key::E;
m_shift_keymap[0x25] = Key::Currency;
m_shift_keymap[0x26] = Key::Hashtag;
m_shift_keymap[0x29] = Key::Space;
m_shift_keymap[0x2A] = Key::V;
m_shift_keymap[0x2B] = Key::F;
m_shift_keymap[0x2C] = Key::T;
m_shift_keymap[0x2D] = Key::R;
m_shift_keymap[0x2E] = Key::Percent;
m_shift_keymap[0x31] = Key::N;
m_shift_keymap[0x32] = Key::B;
m_shift_keymap[0x33] = Key::H;
m_shift_keymap[0x34] = Key::G;
m_shift_keymap[0x35] = Key::Y;
m_shift_keymap[0x36] = Key::Ampersand;
m_shift_keymap[0x3A] = Key::M;
m_shift_keymap[0x3B] = Key::J;
m_shift_keymap[0x3C] = Key::U;
m_shift_keymap[0x3D] = Key::Slash;
m_shift_keymap[0x3E] = Key::OpenBracet;
m_shift_keymap[0x41] = Key::Semicolon;
m_shift_keymap[0x42] = Key::K;
m_shift_keymap[0x43] = Key::I;
m_shift_keymap[0x44] = Key::O;
m_shift_keymap[0x45] = Key::Equals;
m_shift_keymap[0x46] = Key::CloseBracet;
m_shift_keymap[0x49] = Key::Period;
m_shift_keymap[0x4A] = Key::Hyphen;
m_shift_keymap[0x4B] = Key::L;
m_shift_keymap[0x4C] = Key::O_Umlaut;
m_shift_keymap[0x4D] = Key::P;
m_shift_keymap[0x4E] = Key::QuestionMark;
m_shift_keymap[0x52] = Key::A_Umlaut;
m_shift_keymap[0x54] = Key::A_Ring;
m_shift_keymap[0x55] = Key::BackTick;
m_shift_keymap[0x58] = Key::CapsLock;
m_shift_keymap[0x59] = Key::RightShift;
m_shift_keymap[0x59] = Key::RightShift;
m_shift_keymap[0x5A] = Key::Enter;
m_shift_keymap[0x5B] = Key::Caret;
m_shift_keymap[0x5D] = Key::Asterix;
m_shift_keymap[0x61] = Key::GreaterThan;
m_shift_keymap[0x66] = Key::Backspace;
m_shift_keymap[0x69] = Key::Numpad1;
m_shift_keymap[0x6B] = Key::Numpad4;
m_shift_keymap[0x6C] = Key::Numpad7;
m_shift_keymap[0x70] = Key::Numpad0;
m_shift_keymap[0x71] = Key::NumpadDecimal;
m_shift_keymap[0x72] = Key::Numpad2;
m_shift_keymap[0x73] = Key::Numpad5;
m_shift_keymap[0x74] = Key::Numpad6;
m_shift_keymap[0x75] = Key::Numpad8;
m_shift_keymap[0x76] = Key::Escape;
m_shift_keymap[0x77] = Key::NumLock;
m_shift_keymap[0x78] = Key::F11;
m_shift_keymap[0x79] = Key::NumpadPlus;
m_shift_keymap[0x7A] = Key::Numpad3;
m_shift_keymap[0x7B] = Key::NumpadMinus;
m_shift_keymap[0x7C] = Key::NumpadMultiply;
m_shift_keymap[0x7D] = Key::Numpad9;
m_shift_keymap[0x83] = Key::F7;
MUST(m_altgr_keymap.resize(0xFF, Key::Invalid));
m_altgr_keymap[0x01] = Key::F9;
m_altgr_keymap[0x03] = Key::F5;
m_altgr_keymap[0x04] = Key::F3;
m_altgr_keymap[0x05] = Key::F1;
m_altgr_keymap[0x06] = Key::F2;
m_altgr_keymap[0x07] = Key::F11;
m_altgr_keymap[0x09] = Key::F10;
m_altgr_keymap[0x0A] = Key::F8;
m_altgr_keymap[0x0B] = Key::F6;
m_altgr_keymap[0x0C] = Key::F4;
m_altgr_keymap[0x0D] = Key::Tab;
m_altgr_keymap[0x0E] = Key::None;
m_altgr_keymap[0x11] = Key::Alt;
m_altgr_keymap[0x12] = Key::LeftShift;
m_altgr_keymap[0x14] = Key::LeftCtrl;
m_altgr_keymap[0x15] = Key::Q;
m_altgr_keymap[0x16] = Key::None;
m_altgr_keymap[0x1A] = Key::Z;
m_altgr_keymap[0x1B] = Key::S;
m_altgr_keymap[0x1C] = Key::A;
m_altgr_keymap[0x1D] = Key::W;
m_altgr_keymap[0x1E] = Key::AtSign;
m_altgr_keymap[0x21] = Key::C;
m_altgr_keymap[0x22] = Key::X;
m_altgr_keymap[0x23] = Key::D;
m_altgr_keymap[0x24] = Key::E;
m_altgr_keymap[0x25] = Key::Dollar;
m_altgr_keymap[0x26] = Key::Pound;
m_altgr_keymap[0x29] = Key::Space;
m_altgr_keymap[0x2A] = Key::V;
m_altgr_keymap[0x2B] = Key::F;
m_altgr_keymap[0x2C] = Key::T;
m_altgr_keymap[0x2D] = Key::R;
m_altgr_keymap[0x2E] = Key::None;
m_altgr_keymap[0x31] = Key::N;
m_altgr_keymap[0x32] = Key::B;
m_altgr_keymap[0x33] = Key::H;
m_altgr_keymap[0x34] = Key::G;
m_altgr_keymap[0x35] = Key::Y;
m_altgr_keymap[0x36] = Key::None;
m_altgr_keymap[0x3A] = Key::M;
m_altgr_keymap[0x3B] = Key::J;
m_altgr_keymap[0x3C] = Key::U;
m_altgr_keymap[0x3D] = Key::OpenCurlyBrace;
m_altgr_keymap[0x3E] = Key::OpenBrace;
m_altgr_keymap[0x41] = Key::None;
m_altgr_keymap[0x42] = Key::K;
m_altgr_keymap[0x43] = Key::I;
m_altgr_keymap[0x44] = Key::O;
m_altgr_keymap[0x45] = Key::CloseCurlyBrace;
m_altgr_keymap[0x46] = Key::CloseBrace;
m_altgr_keymap[0x49] = Key::None;
m_altgr_keymap[0x4A] = Key::None;
m_altgr_keymap[0x4B] = Key::L;
m_altgr_keymap[0x4C] = Key::O_Umlaut;
m_altgr_keymap[0x4D] = Key::P;
m_altgr_keymap[0x4E] = Key::BackSlash;
m_altgr_keymap[0x52] = Key::A_Umlaut;
m_altgr_keymap[0x54] = Key::A_Ring;
m_altgr_keymap[0x55] = Key::None;
m_altgr_keymap[0x58] = Key::CapsLock;
m_altgr_keymap[0x59] = Key::RightShift;
m_altgr_keymap[0x59] = Key::RightShift;
m_altgr_keymap[0x5A] = Key::Enter;
m_altgr_keymap[0x5B] = Key::Tilde;
m_altgr_keymap[0x5D] = Key::None;
m_altgr_keymap[0x61] = Key::Pipe;
m_altgr_keymap[0x66] = Key::Backspace;
m_altgr_keymap[0x69] = Key::Numpad1;
m_altgr_keymap[0x6B] = Key::Numpad4;
m_altgr_keymap[0x6C] = Key::Numpad7;
m_altgr_keymap[0x70] = Key::Numpad0;
m_altgr_keymap[0x71] = Key::NumpadDecimal;
m_altgr_keymap[0x72] = Key::Numpad2;
m_altgr_keymap[0x73] = Key::Numpad5;
m_altgr_keymap[0x74] = Key::Numpad6;
m_altgr_keymap[0x75] = Key::Numpad8;
m_altgr_keymap[0x76] = Key::Escape;
m_altgr_keymap[0x77] = Key::NumLock;
m_altgr_keymap[0x78] = Key::F11;
m_altgr_keymap[0x79] = Key::NumpadPlus;
m_altgr_keymap[0x7A] = Key::Numpad3;
m_altgr_keymap[0x7B] = Key::NumpadMinus;
m_altgr_keymap[0x7C] = Key::NumpadMultiply;
m_altgr_keymap[0x7D] = Key::Numpad9;
m_altgr_keymap[0x83] = Key::F7;
MUST(m_extended_keymap.resize(0xFF, Key::Invalid));
m_extended_keymap[0x11] = Key::AltGr;
m_extended_keymap[0x14] = Key::RightCtrl;
m_extended_keymap[0x15] = Key::MediaPrevious;
m_extended_keymap[0x1F] = Key::Super;
m_extended_keymap[0x21] = Key::VolumeUp;
m_extended_keymap[0x23] = Key::VolumeMute;
m_extended_keymap[0x2B] = Key::Calculator;
m_extended_keymap[0x32] = Key::VolumeDown;
m_extended_keymap[0x34] = Key::MediaPlayPause;
m_extended_keymap[0x3B] = Key::MediaStop;
m_extended_keymap[0x4A] = Key::NumpadDivide;
m_extended_keymap[0x4D] = Key::MediaNext;
m_extended_keymap[0x5A] = Key::NumpadEnter;
m_extended_keymap[0x69] = Key::End;
m_extended_keymap[0x6B] = Key::ArrowLeft;
m_extended_keymap[0x6C] = Key::Home;
m_extended_keymap[0x70] = Key::Insert;
m_extended_keymap[0x71] = Key::Delete;
m_extended_keymap[0x72] = Key::ArrowDown;
m_extended_keymap[0x74] = Key::ArrowRight;
m_extended_keymap[0x75] = Key::ArrowUp;
m_extended_keymap[0x7A] = Key::PageUp;
m_extended_keymap[0x7D] = Key::PageDown;
}
Key PS2Keymap::key_for_scancode_and_modifiers(uint32_t scancode, uint8_t modifiers)
{
bool extended = scancode & 0x80000000;
scancode &= 0x7FFFFFFF;
KeyEvent dummy;
dummy.modifier = modifiers;
auto& keymap = extended ? m_extended_keymap :
dummy.shift() ? m_shift_keymap :
dummy.altgr() ? m_altgr_keymap :
m_normal_keymap;
if (scancode >= keymap.size())
return Key::Invalid;
Key key = keymap[scancode];
if (dummy.num_lock() && !(dummy.shift() || dummy.ctrl() || dummy.alt()))
{
switch (key)
{
case Key::Numpad0:
key = Key::Insert;
break;
case Key::Numpad1:
key = Key::End;
break;
case Key::Numpad2:
key = Key::ArrowDown;
break;
case Key::Numpad3:
key = Key::PageDown;
break;
case Key::Numpad4:
key = Key::ArrowLeft;
break;
case Key::Numpad5:
key = Key::None;
break;
case Key::Numpad6:
key = Key::ArrowRight;
break;
case Key::Numpad7:
key = Key::Home;
break;
case Key::Numpad8:
key = Key::ArrowUp;
break;
case Key::Numpad9:
key = Key::PageUp;
break;
case Key::NumpadDecimal:
key = Key::Delete;
break;
default:
break;
}
}
return keymap[scancode];
}
}