acadia/lib/mammoth/input/keyboard.cpp

279 lines
5.6 KiB
C++

#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 == kBackspace) {
c = '\b';
} 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