Compare commits

..

7 Commits

Author SHA1 Message Date
Drew Galbraith f01b447af4 [Mammoth] Add keycodes for all non-fn keys. 2023-11-26 12:12:27 -08:00
Drew Galbraith a83893d110 [Mammoth] Add keycodes for most symbol scancodes and shift. 2023-11-26 11:48:30 -08:00
Drew Galbraith 7f2b01438d [Teton] Just print a simple promp on the screen. 2023-11-26 11:29:15 -08:00
Drew Galbraith 2bc64b045c [Mammoth] Add a keyboard library that translates scancode to keycodes. 2023-11-26 11:21:56 -08:00
Drew Galbraith aecae8e41f [Teton] Fix offset in console to write correct character. 2023-11-25 19:56:08 -08:00
Drew Galbraith 1b7d2b9085 [Teton/Voyageurs] Subscribe to scancodes in teton and print them to screen.
Right now there appears to be an error with the font so that the
proper character is received but we write an incorect character to the
screen (off by one?).
2023-11-25 19:48:06 -08:00
Drew Galbraith ea17c143cc [Voyageurs] Register with yellowstone. 2023-11-25 19:37:04 -08:00
12 changed files with 455 additions and 13 deletions

View File

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

View File

@ -0,0 +1,276 @@
#include "input/keyboard.h"
#include <voyageurs/voyageurs.yunq.client.h>
#include <yellowstone/yellowstone.yunq.client.h>
#include <zglobal.h>
#include "util/debug.h"
namespace mmth {
namespace {
void KeyboardListenerEntry(void* keyboard_base) {
reinterpret_cast<KeyboardListenerBase*>(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();
if (scancode == 0xE0) {
extended_on_ = true;
continue;
}
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) {
if (IsShift()) {
const char* alpha = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
c = alpha[code - kA];
} else {
const char* alpha = "abcdefghijklmnopqrstuvwxyz";
c = alpha[code - kA];
}
} else if (code >= k1 && code <= k0) {
if (IsShift()) {
const char* num = "!@#$%^&*()";
c = num[code - k1];
} else {
const char* num = "1234567890";
c = num[code - k1];
}
} else if (code >= kMinus && code <= kBacktick) {
if (IsShift()) {
const char* sym = "_+{}|?:\"<>~";
c = sym[code - kMinus];
} else {
const char* sym = "-=[]\\/;',.`";
c = sym[code - kMinus];
}
} else if (code == kEnter) {
c = '\n';
} else if (code == kSpace) {
c = ' ';
} else if (code == kTab) {
c = '\t';
} else if (code == kLShift) {
lshift_ = true;
} else if (code == kRShift) {
rshift_ = true;
}
} else if (action == kReleased) {
if (code == kLShift) {
lshift_ = false;
} else if (code == kRShift) {
rshift_ = false;
}
}
if (c != '\0') {
HandleCharacter(c);
}
}
Keycode KeyboardListenerBase::ScancodeToKeycode(uint8_t scancode) {
// Cancel out the released bit.
scancode &= 0x7F;
if (extended_on_) {
extended_on_ = false;
switch (scancode) {
case 0x1D:
return kRCtrl;
case 0x38:
return kRAlt;
case 0x48:
return kUp;
case 0x4B:
return kLeft;
case 0x4D:
return kRight;
case 0x50:
return kDown;
case 0x53:
return kDelete;
case 0x5B:
return kSuper;
}
dbgln("Unknown extended scancode {x}", scancode);
return kUnknownKeycode;
}
switch (scancode) {
case 0x01:
return kEsc;
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 0x0C:
return kMinus;
case 0x0D:
return kEquals;
case 0x0E:
return kBackspace;
case 0x0F:
return kTab;
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 0x1A:
return kLBrace;
case 0x1B:
return kRBrace;
case 0x1C:
return kEnter;
case 0x1D:
return kLCtrl;
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 0x27:
return kSemicolon;
case 0x28:
return kQuote;
case 0x29:
return kBacktick;
case 0x2A:
return kLShift;
case 0x2B:
return kBSlash;
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;
case 0x33:
return kComma;
case 0x34:
return kPeriod;
case 0x35:
return kFSlash;
case 0x36:
return kRShift;
case 0x38:
return kLAlt;
case 0x39:
return kSpace;
}
dbgln("Unknown scancode {x}", scancode);
return kUnknownKeycode;
}
Action KeyboardListenerBase::ScancodeToAction(uint8_t scancode) {
return (scancode & 0x80) ? kReleased : kPressed;
}
} // namespace mmth

View File

@ -0,0 +1,123 @@
#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,
kTab = 0x32,
kBackspace = 0x33,
kDelete = 0x34,
kMinus = 0x40,
kEquals = 0x41,
kLBrace = 0x42,
kRBrace = 0x43,
kBSlash = 0x44,
kFSlash = 0x45,
kSemicolon = 0x46,
kQuote = 0x47,
kComma = 0x48,
kPeriod = 0x49,
kBacktick = 0x4A,
kLShift = 0x50,
kRShift = 0x51,
kLCtrl = 0x52,
kRCtrl = 0x53,
kLAlt = 0x54,
kRAlt = 0x55,
kSuper = 0x56,
kEsc = 0x57,
kUp = 0x58,
kDown = 0x59,
kLeft = 0x5A,
kRight = 0x5B,
};
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_;
bool extended_on_ = false;
bool lshift_ = false;
bool rshift_ = false;
Keycode ScancodeToKeycode(uint8_t scancode);
Action ScancodeToAction(uint8_t scancode);
bool IsShift() { return lshift_ || rshift_; }
};
} // namespace mmth

View File

@ -47,4 +47,12 @@ glcr::ErrorCode PortServer::PollForIntCap(uint64_t *msg, uint64_t *cap) {
return glcr::OK;
}
glcr::ErrorOr<char> PortServer::RecvChar() {
uint64_t bytes = 1;
uint64_t caps = 0;
char byte;
RET_ERR(ZPortRecv(port_cap_, &bytes, &byte, &caps, nullptr));
return byte;
}
} // namespace mmth

View File

@ -18,6 +18,8 @@ class PortServer {
glcr::ErrorCode RecvCap(uint64_t* num_bytes, char* msg, uint64_t* cap);
glcr::ErrorCode PollForIntCap(uint64_t* msg, uint64_t* cap);
glcr::ErrorOr<char> RecvChar();
z_cap_t cap() { return port_cap_; }
private:

View File

@ -2,6 +2,7 @@ add_executable(teton
framebuffer/console.cpp
framebuffer/framebuffer.cpp
framebuffer/psf.cpp
keyboard_listener.cpp
teton.cpp
)
@ -13,6 +14,7 @@ target_link_libraries(teton
glacier
mammoth
victoriafalls_yunq
voyageurs_yunq
yellowstone_yunq
)

View File

@ -19,12 +19,12 @@ void Console::WriteChar(char c) {
uint8_t* glyph = psf_.glyph(c);
for (uint32_t r = fb_row; r < fb_row + psf_.height(); r++) {
for (uint32_t c = fb_col; c < fb_col + psf_.width(); c++) {
uint8_t glyph_offset = psf_.width() - (c - fb_col) - 1;
if ((glyph[r] & (1 << glyph_offset))) {
framebuf_.DrawPixel(r, c, 0xFFFFFFF);
for (uint32_t j = fb_col; j < fb_col + psf_.width(); j++) {
uint8_t glyph_offset = psf_.width() - (j - fb_col) - 1;
if ((glyph[r - fb_row] & (1 << glyph_offset))) {
framebuf_.DrawPixel(r, j, 0xFFFFFFF);
} else {
framebuf_.DrawPixel(r, c, 0);
framebuf_.DrawPixel(r, j, 0);
}
}
}

View File

@ -0,0 +1,3 @@
#include "keyboard_listener.h"
void KeyboardListener::HandleCharacter(char c) { console_.WriteChar(c); }

View File

@ -0,0 +1,12 @@
#include <mammoth/input/keyboard.h>
#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_;
};

View File

@ -1,3 +1,4 @@
#include <mammoth/ipc/port_server.h>
#include <mammoth/util/debug.h>
#include <mammoth/util/init.h>
#include <victoriafalls/victoriafalls.yunq.client.h>
@ -6,6 +7,7 @@
#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);
@ -28,13 +30,16 @@ uint64_t main(uint64_t init_port) {
Psf psf("/default8x16.psfu");
psf.DumpHeader();
Console console(fbuf, psf);
console.WriteString("Hello World!\n");
for (uint8_t i = 0x20; i < 0x7E; i++) {
console.WriteChar(i);
}
// 3. Write a line to the screen.
Console console(fbuf, psf);
console.WriteChar('>');
return 0;
KeyboardListener listener(console);
listener.Register();
Thread lthread = listener.Listen();
check(lthread.Join());
return glcr::OK;
}

View File

@ -25,7 +25,6 @@ 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(scancode);

View File

@ -1,6 +1,7 @@
#include <mammoth/util/debug.h>
#include <mammoth/util/init.h>
#include <yellowstone/yellowstone.yunq.client.h>
#include "keyboard/keyboard_driver.h"
#include "voyageurs_server.h"
@ -20,6 +21,15 @@ uint64_t main(uint64_t init_port) {
Thread server_thread = server->RunServer();
YellowstoneClient yellowstone(gInitEndpointCap);
RegisterEndpointRequest req;
req.set_endpoint_name("voyageurs");
ASSIGN_OR_RETURN(VoyageursClient client, server->CreateClient());
req.set_endpoint_capability(client.Capability());
Empty empty;
check(yellowstone.RegisterEndpoint(req, empty));
check(server_thread.Join());
check(keyboard_thread.Join());