From 2bc64b045c55c31619c5ed328d378f272ec804c7 Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Sun, 26 Nov 2023 11:21:56 -0800 Subject: [PATCH] [Mammoth] Add a keyboard library that translates scancode to keycodes. --- lib/mammoth/CMakeLists.txt | 2 + lib/mammoth/input/keyboard.cpp | 173 +++++++++++++++++++++ lib/mammoth/input/keyboard.h | 88 +++++++++++ sys/teton/CMakeLists.txt | 1 + sys/teton/keyboard_listener.cpp | 3 + sys/teton/keyboard_listener.h | 12 ++ sys/teton/teton.cpp | 26 +--- sys/voyageurs/keyboard/keyboard_driver.cpp | 89 +---------- 8 files changed, 286 insertions(+), 108 deletions(-) create mode 100644 lib/mammoth/input/keyboard.cpp create mode 100644 lib/mammoth/input/keyboard.h create mode 100644 sys/teton/keyboard_listener.cpp create mode 100644 sys/teton/keyboard_listener.h diff --git a/lib/mammoth/CMakeLists.txt b/lib/mammoth/CMakeLists.txt index 47a4429..ea431ab 100644 --- a/lib/mammoth/CMakeLists.txt +++ b/lib/mammoth/CMakeLists.txt @@ -1,5 +1,6 @@ add_library(mammoth STATIC file/file.cpp + input/keyboard.cpp ipc/channel.cpp ipc/endpoint_client.cpp ipc/endpoint_server.cpp @@ -25,6 +26,7 @@ target_link_libraries(mammoth glacier victoriafalls_yunq yellowstone_yunq + voyageurs_yunq zion_stub ) diff --git a/lib/mammoth/input/keyboard.cpp b/lib/mammoth/input/keyboard.cpp new file mode 100644 index 0000000..7f6cb83 --- /dev/null +++ b/lib/mammoth/input/keyboard.cpp @@ -0,0 +1,173 @@ +#include "input/keyboard.h" + +#include +#include +#include + +#include "util/debug.h" + +namespace mmth { +namespace { + +void KeyboardListenerEntry(void* keyboard_base) { + reinterpret_cast(keyboard_base)->ListenLoop(); +} + +} // namespace + +KeyboardListenerBase::KeyboardListenerBase() { + auto server_or = PortServer::Create(); + if (!server_or) { + crash("Failed to create server", server_or.error()); + } + server_ = server_or.value(); +} + +void KeyboardListenerBase::Register() { + YellowstoneClient client(gInitEndpointCap); + + GetEndpointRequest req; + req.set_endpoint_name("voyageurs"); + Endpoint endpt; + check(client.GetEndpoint(req, endpt)); + + VoyageursClient vclient(endpt.endpoint()); + KeyboardListener listn; + + // TODO: Create a "ASSIGN_OR_CRASH" macro to simplify this. + auto client_or = server_.CreateClient(); + if (!client_or.ok()) { + crash("Failed to create client", client_or.error()); + } + listn.set_port_capability(client_or.value().cap()); + None n; + check(vclient.RegisterKeyboardListener(listn, n)); +} + +Thread KeyboardListenerBase::Listen() { + return Thread(KeyboardListenerEntry, this); +} + +void KeyboardListenerBase::ListenLoop() { + while (true) { + auto scancode_or = server_.RecvChar(); + if (!scancode_or.ok()) { + check(scancode_or.error()); + } + uint8_t scancode = scancode_or.value(); + Keycode k = ScancodeToKeycode(scancode); + Action a = ScancodeToAction(scancode); + HandleKeycode(k, a); + } +} + +void KeyboardListenerBase::HandleKeycode(Keycode code, Action action) { + char c = '\0'; + + if (action == kPressed) { + if (code >= kA && code <= kZ) { + const char* alpha = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + c = alpha[code - kA]; + } else if (code >= k1 && code <= k0) { + const char* num = "1234567890"; + c = num[code - k1]; + } else if (code == kEnter) { + c = '\n'; + } else if (code == kSpace) { + c = ' '; + } + } + + if (c != '\0') { + HandleCharacter(c); + } +} + +Keycode KeyboardListenerBase::ScancodeToKeycode(uint8_t scancode) { + // Cancel out the released bit. + scancode &= 0x7F; + switch (scancode) { + case 0x02: + return k1; + case 0x03: + return k2; + case 0x04: + return k3; + case 0x05: + return k4; + case 0x06: + return k5; + case 0x07: + return k6; + case 0x08: + return k7; + case 0x09: + return k8; + case 0x0A: + return k9; + case 0x0B: + return k0; + case 0x10: + return kQ; + case 0x11: + return kW; + case 0x12: + return kE; + case 0x13: + return kR; + case 0x14: + return kT; + case 0x15: + return kY; + case 0x16: + return kU; + case 0x17: + return kI; + case 0x18: + return kO; + case 0x19: + return kP; + case 0x1E: + return kA; + case 0x1F: + return kS; + case 0x20: + return kD; + case 0x21: + return kF; + case 0x22: + return kG; + case 0x23: + return kH; + case 0x24: + return kJ; + case 0x25: + return kK; + case 0x26: + return kL; + case 0x2C: + return kZ; + case 0x2D: + return kX; + case 0x2E: + return kC; + case 0x2F: + return kV; + case 0x30: + return kB; + case 0x31: + return kN; + case 0x32: + return kM; + } + + dbgln("Unknown scancode {x}", scancode); + + return kUnknownKeycode; +} + +Action KeyboardListenerBase::ScancodeToAction(uint8_t scancode) { + return (scancode & 0x80) ? kReleased : kPressed; +} + +} // namespace mmth diff --git a/lib/mammoth/input/keyboard.h b/lib/mammoth/input/keyboard.h new file mode 100644 index 0000000..c12f7dc --- /dev/null +++ b/lib/mammoth/input/keyboard.h @@ -0,0 +1,88 @@ +#pragma once + +#include "mammoth/ipc/port_server.h" +#include "mammoth/proc/thread.h" + +namespace mmth { + +enum Keycode { + kUnknownKeycode = 0x0, + + kA = 0x1, + kB = 0x2, + kC = 0x3, + kD = 0x4, + kE = 0x5, + kF = 0x6, + kG = 0x7, + kH = 0x8, + kI = 0x9, + kJ = 0xA, + kK = 0xB, + kL = 0xC, + kM = 0xD, + kN = 0xE, + kO = 0xF, + kP = 0x10, + kQ = 0x11, + kR = 0x12, + kS = 0x13, + kT = 0x14, + kU = 0x15, + kV = 0x16, + kW = 0x17, + kX = 0x18, + kY = 0x19, + kZ = 0x1A, + + k1 = 0x20, + k2 = 0x21, + k3 = 0x22, + k4 = 0x23, + k5 = 0x24, + k6 = 0x25, + k7 = 0x26, + k8 = 0x27, + k9 = 0x28, + k0 = 0x29, + + kSpace = 0x30, + kEnter = 0x31, +}; + +enum Action { + kUnknownAction, + kPressed, + kReleased, +}; + +class KeyboardListenerBase { + public: + KeyboardListenerBase(); + KeyboardListenerBase(const KeyboardListenerBase&) = delete; + KeyboardListenerBase(KeyboardListenerBase&&) = delete; + + void Register(); + + Thread Listen(); + + void ListenLoop(); + + // Override this to recieve all raw keycodes. By default + // this function will try to translate each keycode into + // a printable character and call HandleCharacter. + virtual void HandleKeycode(Keycode code, Action action); + + // This function is called by the default HandleKeycode + // implementation if you do not override it. If it recieves + // input that corresponds to a printable character it will + virtual void HandleCharacter(char c){}; + + private: + PortServer server_; + + Keycode ScancodeToKeycode(uint8_t scancode); + Action ScancodeToAction(uint8_t scancode); +}; + +} // namespace mmth diff --git a/sys/teton/CMakeLists.txt b/sys/teton/CMakeLists.txt index c8e05e6..d24f2c5 100644 --- a/sys/teton/CMakeLists.txt +++ b/sys/teton/CMakeLists.txt @@ -2,6 +2,7 @@ add_executable(teton framebuffer/console.cpp framebuffer/framebuffer.cpp framebuffer/psf.cpp + keyboard_listener.cpp teton.cpp ) diff --git a/sys/teton/keyboard_listener.cpp b/sys/teton/keyboard_listener.cpp new file mode 100644 index 0000000..ae2ddff --- /dev/null +++ b/sys/teton/keyboard_listener.cpp @@ -0,0 +1,3 @@ +#include "keyboard_listener.h" + +void KeyboardListener::HandleCharacter(char c) { console_.WriteChar(c); } diff --git a/sys/teton/keyboard_listener.h b/sys/teton/keyboard_listener.h new file mode 100644 index 0000000..d0e8eb8 --- /dev/null +++ b/sys/teton/keyboard_listener.h @@ -0,0 +1,12 @@ +#include + +#include "framebuffer/console.h" + +class KeyboardListener : public mmth::KeyboardListenerBase { + public: + KeyboardListener(Console& c) : mmth::KeyboardListenerBase(), console_(c) {} + virtual void HandleCharacter(char c) override; + + private: + Console& console_; +}; diff --git a/sys/teton/teton.cpp b/sys/teton/teton.cpp index 5c00071..0ea7f94 100644 --- a/sys/teton/teton.cpp +++ b/sys/teton/teton.cpp @@ -2,12 +2,12 @@ #include #include #include -#include #include #include "framebuffer/console.h" #include "framebuffer/framebuffer.h" #include "framebuffer/psf.h" +#include "keyboard_listener.h" uint64_t main(uint64_t init_port) { ParseInitPort(init_port); @@ -37,26 +37,12 @@ uint64_t main(uint64_t init_port) { console.WriteChar(i); } - GetEndpointRequest req; - req.set_endpoint_name("voyageurs"); - Endpoint endpoint; - RET_ERR(client.GetEndpoint(req, endpoint)); + KeyboardListener listener(console); + listener.Register(); - VoyageursClient voyaguers(endpoint.endpoint()); - ASSIGN_OR_RETURN(mmth::PortServer server, mmth::PortServer::Create()); - KeyboardListener listener; - ASSIGN_OR_RETURN(mmth::PortClient pclient, server.CreateClient()); - listener.set_port_capability(pclient.cap()); - None n; - RET_ERR(voyaguers.RegisterKeyboardListener(listener, n)); + Thread lthread = listener.Listen(); - while (true) { - ASSIGN_OR_RETURN(char c, server.RecvChar()); - if (c != '\0') { - console.WriteChar(c); - dbgln("{}", c); - } - } + check(lthread.Join()); - return 0; + return glcr::OK; } diff --git a/sys/voyageurs/keyboard/keyboard_driver.cpp b/sys/voyageurs/keyboard/keyboard_driver.cpp index 8215e9e..f96a3ad 100644 --- a/sys/voyageurs/keyboard/keyboard_driver.cpp +++ b/sys/voyageurs/keyboard/keyboard_driver.cpp @@ -2,92 +2,6 @@ #include -namespace { - -char ScancodeToChar(uint8_t code) { - switch (code) { - case 0x02: - return '1'; - case 0x03: - return '2'; - case 0x04: - return '3'; - case 0x05: - return '4'; - case 0x06: - return '5'; - case 0x07: - return '6'; - case 0x08: - return '7'; - case 0x09: - return '8'; - case 0x0A: - return '9'; - case 0x0B: - return '0'; - case 0x10: - return 'Q'; - case 0x11: - return 'W'; - case 0x12: - return 'E'; - case 0x13: - return 'R'; - case 0x14: - return 'T'; - case 0x15: - return 'Y'; - case 0x16: - return 'U'; - case 0x17: - return 'I'; - case 0x18: - return 'O'; - case 0x19: - return 'P'; - case 0x1E: - return 'A'; - case 0x1F: - return 'S'; - case 0x20: - return 'D'; - case 0x21: - return 'F'; - case 0x22: - return 'G'; - case 0x23: - return 'H'; - case 0x24: - return 'J'; - case 0x25: - return 'K'; - case 0x26: - return 'L'; - case 0x2C: - return 'Z'; - case 0x2D: - return 'X'; - case 0x2E: - return 'Y'; - case 0x2F: - return 'C'; - case 0x30: - return 'V'; - case 0x31: - return 'B'; - case 0x32: - return 'N'; - case 0x33: - return 'M'; - } - - dbgln("Unhandled scancode {x}", code); - return '\0'; -} - -} // namespace - void InterruptEnter(void* void_keyboard) { KeyboardDriver* keyboard = static_cast(void_keyboard); @@ -111,10 +25,9 @@ void KeyboardDriver::InterruptLoop() { uint64_t num_bytes = 1; uint64_t num_caps = 0; check(ZPortRecv(irq_cap_, &num_bytes, &scancode, &num_caps, nullptr)); - dbgln("Scan {x}", scancode); for (mmth::PortClient& client : listeners_) { - client.WriteByte(ScancodeToChar(scancode)); + client.WriteByte(scancode); } } }