[Mammoth] Add a keyboard library that translates scancode to keycodes.
This commit is contained in:
parent
aecae8e41f
commit
2bc64b045c
|
@ -1,5 +1,6 @@
|
||||||
add_library(mammoth STATIC
|
add_library(mammoth STATIC
|
||||||
file/file.cpp
|
file/file.cpp
|
||||||
|
input/keyboard.cpp
|
||||||
ipc/channel.cpp
|
ipc/channel.cpp
|
||||||
ipc/endpoint_client.cpp
|
ipc/endpoint_client.cpp
|
||||||
ipc/endpoint_server.cpp
|
ipc/endpoint_server.cpp
|
||||||
|
@ -25,6 +26,7 @@ target_link_libraries(mammoth
|
||||||
glacier
|
glacier
|
||||||
victoriafalls_yunq
|
victoriafalls_yunq
|
||||||
yellowstone_yunq
|
yellowstone_yunq
|
||||||
|
voyageurs_yunq
|
||||||
zion_stub
|
zion_stub
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,173 @@
|
||||||
|
#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();
|
||||||
|
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
|
|
@ -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
|
|
@ -2,6 +2,7 @@ add_executable(teton
|
||||||
framebuffer/console.cpp
|
framebuffer/console.cpp
|
||||||
framebuffer/framebuffer.cpp
|
framebuffer/framebuffer.cpp
|
||||||
framebuffer/psf.cpp
|
framebuffer/psf.cpp
|
||||||
|
keyboard_listener.cpp
|
||||||
teton.cpp
|
teton.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
#include "keyboard_listener.h"
|
||||||
|
|
||||||
|
void KeyboardListener::HandleCharacter(char c) { console_.WriteChar(c); }
|
|
@ -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_;
|
||||||
|
};
|
|
@ -2,12 +2,12 @@
|
||||||
#include <mammoth/util/debug.h>
|
#include <mammoth/util/debug.h>
|
||||||
#include <mammoth/util/init.h>
|
#include <mammoth/util/init.h>
|
||||||
#include <victoriafalls/victoriafalls.yunq.client.h>
|
#include <victoriafalls/victoriafalls.yunq.client.h>
|
||||||
#include <voyageurs/voyageurs.yunq.client.h>
|
|
||||||
#include <yellowstone/yellowstone.yunq.client.h>
|
#include <yellowstone/yellowstone.yunq.client.h>
|
||||||
|
|
||||||
#include "framebuffer/console.h"
|
#include "framebuffer/console.h"
|
||||||
#include "framebuffer/framebuffer.h"
|
#include "framebuffer/framebuffer.h"
|
||||||
#include "framebuffer/psf.h"
|
#include "framebuffer/psf.h"
|
||||||
|
#include "keyboard_listener.h"
|
||||||
|
|
||||||
uint64_t main(uint64_t init_port) {
|
uint64_t main(uint64_t init_port) {
|
||||||
ParseInitPort(init_port);
|
ParseInitPort(init_port);
|
||||||
|
@ -37,26 +37,12 @@ uint64_t main(uint64_t init_port) {
|
||||||
console.WriteChar(i);
|
console.WriteChar(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
GetEndpointRequest req;
|
KeyboardListener listener(console);
|
||||||
req.set_endpoint_name("voyageurs");
|
listener.Register();
|
||||||
Endpoint endpoint;
|
|
||||||
RET_ERR(client.GetEndpoint(req, endpoint));
|
|
||||||
|
|
||||||
VoyageursClient voyaguers(endpoint.endpoint());
|
Thread lthread = listener.Listen();
|
||||||
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));
|
|
||||||
|
|
||||||
while (true) {
|
check(lthread.Join());
|
||||||
ASSIGN_OR_RETURN(char c, server.RecvChar());
|
|
||||||
if (c != '\0') {
|
|
||||||
console.WriteChar(c);
|
|
||||||
dbgln("{}", c);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return glcr::OK;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,92 +2,6 @@
|
||||||
|
|
||||||
#include <mammoth/util/debug.h>
|
#include <mammoth/util/debug.h>
|
||||||
|
|
||||||
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) {
|
void InterruptEnter(void* void_keyboard) {
|
||||||
KeyboardDriver* keyboard = static_cast<KeyboardDriver*>(void_keyboard);
|
KeyboardDriver* keyboard = static_cast<KeyboardDriver*>(void_keyboard);
|
||||||
|
|
||||||
|
@ -111,10 +25,9 @@ void KeyboardDriver::InterruptLoop() {
|
||||||
uint64_t num_bytes = 1;
|
uint64_t num_bytes = 1;
|
||||||
uint64_t num_caps = 0;
|
uint64_t num_caps = 0;
|
||||||
check(ZPortRecv(irq_cap_, &num_bytes, &scancode, &num_caps, nullptr));
|
check(ZPortRecv(irq_cap_, &num_bytes, &scancode, &num_caps, nullptr));
|
||||||
dbgln("Scan {x}", scancode);
|
|
||||||
|
|
||||||
for (mmth::PortClient& client : listeners_) {
|
for (mmth::PortClient& client : listeners_) {
|
||||||
client.WriteByte(ScancodeToChar(scancode));
|
client.WriteByte(scancode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue