Implemented simple IO for getting keyboard input.

This commit is contained in:
Patrick 2024-01-20 01:13:29 +01:00
parent d711938821
commit f4bad14fcd
9 changed files with 584 additions and 306 deletions

View File

@ -25,7 +25,7 @@ public:
using iterator = pointer;
using const_iterator = const_pointer;
T _elements[N];
T _elements[N] = {};
constexpr reference operator[](size_type pos) noexcept
{

View File

@ -8,10 +8,19 @@
namespace std
{
using ::EOF;
using ::putchar;
using ::puts;
using ::printf;
using ::vprintf;
using ::snprintf;
using ::vsnprintf;
using ::fgets;
using ::fgetc;
using ::getc;
using ::getchar;
}
#endif // !defined(BAD_APPLE_OS_CSTDIO_INCLUDED)

View File

@ -4,6 +4,7 @@
#if !defined(BAD_APPLE_OS_DRIVERS_PS2_HPP_INCLUDED)
#define BAD_APPLE_OS_DRIVERS_PS2_HPP_INCLUDED
#include <array>
#include "drivers/pic.hpp"
namespace baos::ps2
@ -77,6 +78,7 @@ enum class Scancode
ENTER = 0x5A,
BRACKET_CLOSE = 0x5B,
BACKSLASH = 0x5D,
GRAVE = 0x61,
BACKSPACE = 0x66,
KP_1 = 0x69,
KP_4 = 0x6B,
@ -98,46 +100,61 @@ enum class Scancode
SCROLLOCK = 0x7E,
F7 = 0x83,
MM_WWW_SEARCH = 0xE010,
RIGHT_ALT = 0xE011,
RIGHT_CONTROL = 0xE014,
MM_PREV_TRACK = 0xE015,
LEFT_GUI = 0xE01F,
MM_WWW_FAVORITES = 0xE020,
MM_VOLUME_DOWN = 0xE021,
MM_MUTE = 0xE023,
RIGHT_GUI = 0xE027,
MM_WWW_STOP = 0xE028,
MM_CALCULATOR = 0xE02B,
APPS = 0xE02F,
MM_WWW_FORWARD = 0xE030,
MM_VOLUME_UP = 0xE032,
MM_PLAY_PAUSE = 0xE034,
ACPI_POWER = 0xE037,
MM_WWW_BACK = 0xE038,
MM_WWW_HOME = 0xE03A,
MM_STOP = 0xE03B,
ACPI_SLEEP = 0xE03F,
MM_MY_COMPUTER = 0xE040,
MM_EMAIL = 0xE048,
KP_SLASH = 0xE04A,
MM_NEXT_TRACK = 0xE04D,
MM_MEDIA_SELECT = 0xE050,
KP_ENTER = 0xE05A,
ACPI_WAKE = 0xE05E,
END = 0xE069,
ARROW_LEFT = 0xE06B,
HOME = 0xE06C,
INSERT = 0xE070,
DELETE = 0xE071,
ARROW_DOWN = 0xE072,
ARROW_RIGHT = 0xE074,
ARROW_UP = 0xE075,
PAGE_DOWN = 0xE07A,
PAGE_UP = 0xE07D,
MM_WWW_SEARCH = 0x0110,
RIGHT_ALT = 0x0111,
RIGHT_CONTROL = 0x0114,
MM_PREV_TRACK = 0x0115,
LEFT_GUI = 0x011F,
MM_WWW_FAVORITES = 0x0120,
MM_VOLUME_DOWN = 0x0121,
MM_MUTE = 0x0123,
RIGHT_GUI = 0x0127,
MM_WWW_STOP = 0x0128,
MM_CALCULATOR = 0x012B,
APPS = 0x012F,
MM_WWW_FORWARD = 0x0130,
MM_VOLUME_UP = 0x0132,
MM_PLAY_PAUSE = 0x0134,
ACPI_POWER = 0x0137,
MM_WWW_BACK = 0x0138,
MM_WWW_HOME = 0x013A,
MM_STOP = 0x013B,
ACPI_SLEEP = 0x013F,
MM_MY_COMPUTER = 0x0140,
MM_EMAIL = 0x0148,
KP_SLASH = 0x014A,
MM_NEXT_TRACK = 0x014D,
MM_MEDIA_SELECT = 0x0150,
KP_ENTER = 0x015A,
ACPI_WAKE = 0x015E,
END = 0x0169,
ARROW_LEFT = 0x016B,
HOME = 0x016C,
INSERT = 0x0170,
DELETE = 0x0171,
ARROW_DOWN = 0x0172,
ARROW_RIGHT = 0x0174,
ARROW_UP = 0x0175,
PAGE_DOWN = 0x017A,
PAGE_UP = 0x017D,
PRINT_SCREEN = 0xF000,
PAUSE = 0xF001
PRINT_SCREEN = 0x017E,
PAUSE = 0x017F
};
inline constexpr std::uint16_t MAX_SCANCODE = static_cast<std::uint16_t>(Scancode::PAUSE) + 1;
struct Keymap
{
std::array<char, MAX_SCANCODE> regularKeys;
std::array<char, MAX_SCANCODE> shiftedKeys;
std::array<char, MAX_SCANCODE> altGredKeys;
constexpr void set(Scancode scancode, char regular, char shifted = '\0', char altgred = '\0') noexcept
{
regularKeys[static_cast<unsigned>(scancode)] = regular;
shiftedKeys[static_cast<unsigned>(scancode)] = shifted;
altGredKeys[static_cast<unsigned>(scancode)] = altgred;
}
};
struct KeyEvent
@ -152,8 +169,11 @@ struct KeyEvent
__attribute__((interrupt))
void isrKeyboard(InterruptFrame* interruptFrame) noexcept;
[[nodiscard]] bool isKeyDown(Scancode scancode) noexcept;
[[nodiscard]] bool readKey(KeyEvent& outEvent) noexcept;
[[nodiscard]] bool readChar(char& outChar) noexcept;
[[nodiscard]] const char* keyName(Scancode scancode) noexcept;
[[nodiscard]] bool keyToChar(Scancode scancode, char& outChar) noexcept;
}
#endif // !defined(BAD_APPLE_OS_DRIVERS_PS2_HPP_INCLUDED)

View File

@ -0,0 +1,44 @@
#pragma once
#if !defined(BAD_APPLE_OS_OS_TOOLS_RINGBUFFER_HPP_INCLUDED)
#define BAD_APPLE_OS_OS_TOOLS_RINGBUFFER_HPP_INCLUDED
#include <array>
#include <cstddef>
namespace baos
{
template<typename T, std::size_t SIZE>
class RingBuffer
{
private:
std::array<T, SIZE> mElements;
std::size_t mBufferedElements = 0;
std::size_t mPosition = 0;
public:
[[nodiscard]] bool full() const noexcept { return mBufferedElements == SIZE; }
[[nodiscard]] bool empty() const noexcept { return mBufferedElements == 0; }
bool append(T element) noexcept
{
if (full()) {
return false;
}
mElements[mPosition] = std::move(element);
++mBufferedElements;
mPosition = (mPosition + 1) % SIZE;
return true;
}
bool next(T& outElement) noexcept
{
if (empty()) {
return false;
}
outElement = std::move(mElements[(mPosition + SIZE - mBufferedElements) % SIZE]);
--mBufferedElements;
return true;
}
};
}
#endif // !defined(BAD_APPLE_OS_OS_TOOLS_RINGBUFFER_HPP_INCLUDED)

View File

@ -8,8 +8,16 @@
#include <stddef.h>
#include "./detail/common.h"
#define stdin __stdin
BA_EXTERN_C_BEGIN
typedef struct __file FILE;
extern FILE* __stdin;
static int EOF = -1;
int putchar(int chr) BA_CXX_NOEXCEPT;
int puts(const char* str) BA_CXX_NOEXCEPT;
int printf(const char* format, ...) BA_CXX_NOEXCEPT __attribute__((format(printf, 1, 2)));
@ -17,6 +25,11 @@ int vprintf(const char* format, va_list vlist) BA_CXX_NOEXCEPT;
int snprintf(char* buffer, size_t bufferSize, const char* format, ...) BA_CXX_NOEXCEPT __attribute__((format(printf, 3, 4)));
int vsnprintf(char* buffer, size_t bufferSize, const char* format, va_list vlist) BA_CXX_NOEXCEPT;
int fgetc(FILE* stream) BA_CXX_NOEXCEPT;
char* fgets(char* buffer, int count, FILE* stream) BA_CXX_NOEXCEPT;
inline int getc(FILE* stream) BA_CXX_NOEXCEPT { return fgetc(stream); }
inline int getchar() BA_CXX_NOEXCEPT { return fgetc(stdin); }
BA_EXTERN_C_END
#endif // !defined(BAD_APPLE_OS_STDIO_H_INCLUDED)

View File

@ -1,6 +1,16 @@
#include <cstdio>
extern "C" void main()
{
// __asm__ __volatile__("cli");
while(true);
while(true)
{
int chr = std::getchar();
if (chr != std::EOF)
{
putchar(chr);
}
}
}

View File

@ -2,13 +2,37 @@
#include <stdio.h>
#include <algorithm>
#include <cassert>
#include <cstring>
#include <utility>
#include <stdarg.h>
#include "drivers/ps2.hpp"
#include "os/serial.hpp"
#include "os/tty.hpp"
#include "os/tools/printf_helper.hpp"
#include "os/tools/ringbuffer.hpp"
struct __file
{
protected:
static constexpr unsigned BUFFER_SIZE = 4096;
baos::RingBuffer<char, BUFFER_SIZE> mBuffer;
bool mEof = false;
bool mError = false;
protected:
virtual bool underflow() noexcept = 0;
public:
[[nodiscard]] bool isEof() const noexcept { return mEof; }
[[nodiscard]] bool isError() const noexcept { return mError; }
bool readChar(char& outChar) noexcept
{
while (!mBuffer.next(outChar)) {
if (!underflow()) {
return false;
}
}
return true;
}
};
namespace
{
@ -34,10 +58,33 @@ struct BufferPrinter
}
}
};
class StdinFile : public __file
{
public:
bool underflow() noexcept override
{
while (mBuffer.empty())
{
char chr;
while (!mBuffer.full() && baos::ps2::readChar(chr))
{
mBuffer.append(chr);
if (chr == '\n') {
break;
}
}
}
return true;
}
};
StdinFile gStdin;
}
extern "C"
{
FILE* __stdin = &gStdin;
int putchar(int chr) noexcept
{
tty::putChar(static_cast<char>(chr));
@ -100,5 +147,42 @@ int vsnprintf(char* buffer, size_t bufferSize, const char* format, va_list vlist
}
return length;
}
int fgetc(FILE* stream) noexcept
{
char chr;
if (!stream->readChar(chr))
{
return EOF;
}
return chr;
}
char* fgets(char* buffer, int count, FILE* stream) noexcept
{
if (count < 1) {
return nullptr;
}
if (count == 1)
{
*buffer = '\0';
return buffer;
}
int pos = 0;
for (; pos < count - 1; ++pos)
{
if (!stream->readChar(buffer[pos]))
{
if (stream->isError() || pos == 0)
{
return nullptr;
}
break;
}
}
buffer[pos] = '\0';
return buffer;
}
} // extern "C"

View File

@ -1,12 +1,296 @@
#include "drivers/ps2.hpp"
#include <cstdint>
#include <array>
#include "drivers/pic.hpp"
#include "os/port.hpp"
namespace baos::ps2
{
namespace
{
// <editor-fold desc="KEYMAP_EN_US">
const constinit Keymap KEYMAP_EN_US = []()
{
Keymap keymap = {};
keymap.set(Scancode::BACKTICK, '`', '~');
keymap.set(Scancode::_0, '0', ')');
keymap.set(Scancode::_1, '1', '!');
keymap.set(Scancode::_2, '2', '@');
keymap.set(Scancode::_3, '3', '#');
keymap.set(Scancode::_4, '4', '$');
keymap.set(Scancode::_5, '5', '%');
keymap.set(Scancode::_6, '6', '^');
keymap.set(Scancode::_7, '7', '&');
keymap.set(Scancode::_8, '8', '*');
keymap.set(Scancode::_9, '9', '(');
keymap.set(Scancode::A, 'a', 'A');
keymap.set(Scancode::B, 'b', 'B');
keymap.set(Scancode::C, 'c', 'C');
keymap.set(Scancode::D, 'd', 'D');
keymap.set(Scancode::E, 'e', 'E');
keymap.set(Scancode::F, 'f', 'F');
keymap.set(Scancode::G, 'g', 'G');
keymap.set(Scancode::H, 'h', 'H');
keymap.set(Scancode::I, 'i', 'I');
keymap.set(Scancode::J, 'j', 'J');
keymap.set(Scancode::K, 'k', 'K');
keymap.set(Scancode::L, 'l', 'L');
keymap.set(Scancode::M, 'm', 'M');
keymap.set(Scancode::N, 'n', 'N');
keymap.set(Scancode::O, 'o', 'O');
keymap.set(Scancode::P, 'p', 'P');
keymap.set(Scancode::Q, 'q', 'Q');
keymap.set(Scancode::R, 'r', 'R');
keymap.set(Scancode::S, 's', 'S');
keymap.set(Scancode::T, 't', 'T');
keymap.set(Scancode::U, 'u', 'U');
keymap.set(Scancode::V, 'v', 'V');
keymap.set(Scancode::W, 'w', 'W');
keymap.set(Scancode::X, 'x', 'X');
keymap.set(Scancode::Y, 'y', 'Y');
keymap.set(Scancode::Z, 'z', 'Z');
keymap.set(Scancode::ENTER, '\n');
keymap.set(Scancode::MINUS, '-', '_');
keymap.set(Scancode::EQUALS, '=', '+');
keymap.set(Scancode::TAB, '\t');
keymap.set(Scancode::BRACKET_OPEN, '[', '{');
keymap.set(Scancode::BRACKET_CLOSE, ']', '}');
keymap.set(Scancode::BACKSLASH, '\\', '|');
keymap.set(Scancode::SEMICOLON, ';', ':');
keymap.set(Scancode::APOSTROPHE, '\'', '"');
keymap.set(Scancode::GRAVE, '`', '~');
keymap.set(Scancode::COMMA, ',', '<');
keymap.set(Scancode::DOT, '.', '>');
keymap.set(Scancode::SLASH, '/', '?');
keymap.set(Scancode::KP_ENTER, '\n');
keymap.set(Scancode::KP_0, '0');
keymap.set(Scancode::KP_1, '1');
keymap.set(Scancode::KP_2, '2');
keymap.set(Scancode::KP_3, '3');
keymap.set(Scancode::KP_4, '4');
keymap.set(Scancode::KP_5, '5');
keymap.set(Scancode::KP_6, '6');
keymap.set(Scancode::KP_7, '7');
keymap.set(Scancode::KP_8, '8');
keymap.set(Scancode::KP_9, '9');
keymap.set(Scancode::KP_SLASH, '/');
keymap.set(Scancode::KP_ASTERISK, '*');
keymap.set(Scancode::KP_MINUS, '-');
keymap.set(Scancode::KP_PLUS, '+');
return keymap;
}();
//</editor-fold>
//<editor-fold desc="KEYMAP_DE_DE">
const constinit Keymap KEYMAP_DE_DE = []()
{
Keymap keymap = {};
keymap.set(Scancode::BACKTICK, '^' /*'°'*/);
keymap.set(Scancode::_0, '0', '=', '}');
keymap.set(Scancode::_1, '1', '!');
keymap.set(Scancode::_2, '2', '"');
keymap.set(Scancode::_3, '3' /*'§'*/);
keymap.set(Scancode::_4, '4', '$');
keymap.set(Scancode::_5, '5', '%');
keymap.set(Scancode::_6, '6', '&');
keymap.set(Scancode::_7, '7', '/', '{');
keymap.set(Scancode::_8, '8', '(', '[');
keymap.set(Scancode::_9, '9', ')', ']');
keymap.set(Scancode::A, 'a', 'A');
keymap.set(Scancode::B, 'b', 'B');
keymap.set(Scancode::C, 'c', 'C');
keymap.set(Scancode::D, 'd', 'D');
keymap.set(Scancode::E, 'e', 'E' /*, '€' */);
keymap.set(Scancode::F, 'f', 'F');
keymap.set(Scancode::G, 'g', 'G');
keymap.set(Scancode::H, 'h', 'H');
keymap.set(Scancode::I, 'i', 'I');
keymap.set(Scancode::J, 'j', 'J');
keymap.set(Scancode::K, 'k', 'K');
keymap.set(Scancode::L, 'l', 'L');
keymap.set(Scancode::M, 'm', 'M');
keymap.set(Scancode::N, 'n', 'N');
keymap.set(Scancode::O, 'o', 'O');
keymap.set(Scancode::P, 'p', 'P');
keymap.set(Scancode::Q, 'q', 'Q', '@');
keymap.set(Scancode::R, 'r', 'R');
keymap.set(Scancode::S, 's', 'S');
keymap.set(Scancode::T, 't', 'T');
keymap.set(Scancode::U, 'u', 'U');
keymap.set(Scancode::V, 'v', 'V');
keymap.set(Scancode::W, 'w', 'W');
keymap.set(Scancode::X, 'x', 'X');
keymap.set(Scancode::Y, 'y', 'Y');
keymap.set(Scancode::Z, 'z', 'Z');
keymap.set(Scancode::ENTER, '\n');
keymap.set(Scancode::MINUS, '?' /* ß */, '?', '\\');
keymap.set(Scancode::EQUALS, '`' /* ´ */, '`');
keymap.set(Scancode::TAB, '\t');
// keymap.set(Scancode::BRACKET_OPEN, 'ü', 'Ü');
keymap.set(Scancode::BRACKET_CLOSE, '+', '*', '~');
// keymap.set(Scancode::BACKSLASH, '\\', '|');
// keymap.set(Scancode::SEMICOLON, 'ö', 'Ö');
// keymap.set(Scancode::APOSTROPHE, 'ä', 'Ä');
keymap.set(Scancode::GRAVE, '<', '>', '|');
keymap.set(Scancode::COMMA, ',', ';');
keymap.set(Scancode::DOT, '.', ':');
keymap.set(Scancode::SLASH, '-', '_');
keymap.set(Scancode::KP_ENTER, '\n');
keymap.set(Scancode::KP_0, '0');
keymap.set(Scancode::KP_1, '1');
keymap.set(Scancode::KP_2, '2');
keymap.set(Scancode::KP_3, '3');
keymap.set(Scancode::KP_4, '4');
keymap.set(Scancode::KP_5, '5');
keymap.set(Scancode::KP_6, '6');
keymap.set(Scancode::KP_7, '7');
keymap.set(Scancode::KP_8, '8');
keymap.set(Scancode::KP_9, '9');
keymap.set(Scancode::KP_SLASH, '/');
keymap.set(Scancode::KP_ASTERISK, '*');
keymap.set(Scancode::KP_MINUS, '-');
keymap.set(Scancode::KP_PLUS, '+');
return keymap;
}();
//</editor-fold>
//<editor-fold desc="SCANCODE_NAMES">
const constinit std::array<const char*, MAX_SCANCODE> SCANCODE_NAMES = []()
{
std::array<const char*, MAX_SCANCODE> names;
names.fill("INVALID");
names[static_cast<unsigned>(Scancode::F9)] = "F9";
names[static_cast<unsigned>(Scancode::F5)] = "F5";
names[static_cast<unsigned>(Scancode::F3)] = "F3";
names[static_cast<unsigned>(Scancode::F1)] = "F1";
names[static_cast<unsigned>(Scancode::F2)] = "F2";
names[static_cast<unsigned>(Scancode::F12)] = "F12";
names[static_cast<unsigned>(Scancode::F10)] = "F10";
names[static_cast<unsigned>(Scancode::F8)] = "F8";
names[static_cast<unsigned>(Scancode::F6)] = "F6";
names[static_cast<unsigned>(Scancode::F4)] = "F4";
names[static_cast<unsigned>(Scancode::TAB)] = "TAB";
names[static_cast<unsigned>(Scancode::BACKTICK)] = "BACKTICK";
names[static_cast<unsigned>(Scancode::LEFT_ALT)] = "LEFT_ALT";
names[static_cast<unsigned>(Scancode::LEFT_SHIFT)] = "LEFT_SHIFT";
names[static_cast<unsigned>(Scancode::LEFT_CONTROL)] = "LEFT_CONTROL";
names[static_cast<unsigned>(Scancode::Q)] = "Q";
names[static_cast<unsigned>(Scancode::_1)] = "_1";
names[static_cast<unsigned>(Scancode::Z)] = "Z";
names[static_cast<unsigned>(Scancode::S)] = "S";
names[static_cast<unsigned>(Scancode::A)] = "A";
names[static_cast<unsigned>(Scancode::W)] = "W";
names[static_cast<unsigned>(Scancode::_2)] = "_2";
names[static_cast<unsigned>(Scancode::C)] = "C";
names[static_cast<unsigned>(Scancode::X)] = "X";
names[static_cast<unsigned>(Scancode::D)] = "D";
names[static_cast<unsigned>(Scancode::E)] = "E";
names[static_cast<unsigned>(Scancode::_4)] = "_4";
names[static_cast<unsigned>(Scancode::_3)] = "_3";
names[static_cast<unsigned>(Scancode::SPACE)] = "SPACE";
names[static_cast<unsigned>(Scancode::V)] = "V";
names[static_cast<unsigned>(Scancode::F)] = "F";
names[static_cast<unsigned>(Scancode::T)] = "T";
names[static_cast<unsigned>(Scancode::R)] = "R";
names[static_cast<unsigned>(Scancode::_5)] = "_5";
names[static_cast<unsigned>(Scancode::N)] = "N";
names[static_cast<unsigned>(Scancode::B)] = "B";
names[static_cast<unsigned>(Scancode::H)] = "H";
names[static_cast<unsigned>(Scancode::G)] = "G";
names[static_cast<unsigned>(Scancode::Y)] = "Y";
names[static_cast<unsigned>(Scancode::_6)] = "_6";
names[static_cast<unsigned>(Scancode::M)] = "M";
names[static_cast<unsigned>(Scancode::J)] = "J";
names[static_cast<unsigned>(Scancode::U)] = "U";
names[static_cast<unsigned>(Scancode::_7)] = "_7";
names[static_cast<unsigned>(Scancode::_8)] = "_8";
names[static_cast<unsigned>(Scancode::COMMA)] = "COMMA";
names[static_cast<unsigned>(Scancode::K)] = "K";
names[static_cast<unsigned>(Scancode::I)] = "I";
names[static_cast<unsigned>(Scancode::O)] = "O";
names[static_cast<unsigned>(Scancode::_0)] = "_0";
names[static_cast<unsigned>(Scancode::_9)] = "_9";
names[static_cast<unsigned>(Scancode::DOT)] = "DOT";
names[static_cast<unsigned>(Scancode::SLASH)] = "SLASH";
names[static_cast<unsigned>(Scancode::L)] = "L";
names[static_cast<unsigned>(Scancode::SEMICOLON)] = "SEMICOLON";
names[static_cast<unsigned>(Scancode::P)] = "P";
names[static_cast<unsigned>(Scancode::MINUS)] = "MINUS";
names[static_cast<unsigned>(Scancode::APOSTROPHE)] = "APOSTROPHE";
names[static_cast<unsigned>(Scancode::BRACKET_OPEN)] = "BRACKET_OPEN";
names[static_cast<unsigned>(Scancode::EQUALS)] = "EQUALS";
names[static_cast<unsigned>(Scancode::CAPSLOCK)] = "CAPSLOCK";
names[static_cast<unsigned>(Scancode::RIGHT_SHIFT)] = "RIGHT_SHIFT";
names[static_cast<unsigned>(Scancode::ENTER)] = "ENTER";
names[static_cast<unsigned>(Scancode::BRACKET_CLOSE)] = "BRACKET_CLOSE";
names[static_cast<unsigned>(Scancode::BACKSLASH)] = "BACKSLASH";
names[static_cast<unsigned>(Scancode::GRAVE)] = "GRAVE";
names[static_cast<unsigned>(Scancode::BACKSPACE)] = "BACKSPACE";
names[static_cast<unsigned>(Scancode::KP_1)] = "KP_1";
names[static_cast<unsigned>(Scancode::KP_4)] = "KP_4";
names[static_cast<unsigned>(Scancode::KP_7)] = "KP_7";
names[static_cast<unsigned>(Scancode::KP_0)] = "KP_0";
names[static_cast<unsigned>(Scancode::KP_DOT)] = "KP_DOT";
names[static_cast<unsigned>(Scancode::KP_2)] = "KP_2";
names[static_cast<unsigned>(Scancode::KP_5)] = "KP_5";
names[static_cast<unsigned>(Scancode::KP_6)] = "KP_6";
names[static_cast<unsigned>(Scancode::KP_8)] = "KP_8";
names[static_cast<unsigned>(Scancode::ESCAPE)] = "ESCAPE";
names[static_cast<unsigned>(Scancode::NUMLOCK)] = "NUMLOCK";
names[static_cast<unsigned>(Scancode::F11)] = "F11";
names[static_cast<unsigned>(Scancode::KP_PLUS)] = "KP_PLUS";
names[static_cast<unsigned>(Scancode::KP_3)] = "KP_3";
names[static_cast<unsigned>(Scancode::KP_MINUS)] = "KP_MINUS";
names[static_cast<unsigned>(Scancode::KP_ASTERISK)] = "KP_ASTERISK";
names[static_cast<unsigned>(Scancode::KP_9)] = "KP_9";
names[static_cast<unsigned>(Scancode::SCROLLOCK)] = "SCROLLOCK";
names[static_cast<unsigned>(Scancode::F7)] = "F7";
names[static_cast<unsigned>(Scancode::MM_WWW_SEARCH)] = "MM_WWW_SEARCH";
names[static_cast<unsigned>(Scancode::RIGHT_ALT)] = "RIGHT_ALT";
names[static_cast<unsigned>(Scancode::RIGHT_CONTROL)] = "RIGHT_CONTROL";
names[static_cast<unsigned>(Scancode::MM_PREV_TRACK)] = "MM_PREV_TRACK";
names[static_cast<unsigned>(Scancode::LEFT_GUI)] = "LEFT_GUI";
names[static_cast<unsigned>(Scancode::MM_WWW_FAVORITES)] = "MM_WWW_FAVORITES";
names[static_cast<unsigned>(Scancode::MM_VOLUME_DOWN)] = "MM_VOLUME_DOWN";
names[static_cast<unsigned>(Scancode::MM_MUTE)] = "MM_MUTE";
names[static_cast<unsigned>(Scancode::RIGHT_GUI)] = "RIGHT_GUI";
names[static_cast<unsigned>(Scancode::MM_WWW_STOP)] = "MM_WWW_STOP";
names[static_cast<unsigned>(Scancode::MM_CALCULATOR)] = "MM_CALCULATOR";
names[static_cast<unsigned>(Scancode::APPS)] = "APPS";
names[static_cast<unsigned>(Scancode::MM_WWW_FORWARD)] = "MM_WWW_FORWARD";
names[static_cast<unsigned>(Scancode::MM_VOLUME_UP)] = "MM_VOLUME_UP";
names[static_cast<unsigned>(Scancode::MM_PLAY_PAUSE)] = "MM_PLAY_PAUSE";
names[static_cast<unsigned>(Scancode::ACPI_POWER)] = "ACPI_POWER";
names[static_cast<unsigned>(Scancode::MM_WWW_BACK)] = "MM_WWW_BACK";
names[static_cast<unsigned>(Scancode::MM_WWW_HOME)] = "MM_WWW_HOME";
names[static_cast<unsigned>(Scancode::MM_STOP)] = "MM_STOP";
names[static_cast<unsigned>(Scancode::ACPI_SLEEP)] = "ACPI_SLEEP";
names[static_cast<unsigned>(Scancode::MM_MY_COMPUTER)] = "MM_MY_COMPUTER";
names[static_cast<unsigned>(Scancode::MM_EMAIL)] = "MM_EMAIL";
names[static_cast<unsigned>(Scancode::KP_SLASH)] = "KP_SLASH";
names[static_cast<unsigned>(Scancode::MM_NEXT_TRACK)] = "MM_NEXT_TRACK";
names[static_cast<unsigned>(Scancode::MM_MEDIA_SELECT)] = "MM_MEDIA_SELECT";
names[static_cast<unsigned>(Scancode::KP_ENTER)] = "KP_ENTER";
names[static_cast<unsigned>(Scancode::ACPI_WAKE)] = "ACPI_WAKE";
names[static_cast<unsigned>(Scancode::END)] = "END";
names[static_cast<unsigned>(Scancode::ARROW_LEFT)] = "ARROW_LEFT";
names[static_cast<unsigned>(Scancode::HOME)] = "HOME";
names[static_cast<unsigned>(Scancode::INSERT)] = "INSERT";
names[static_cast<unsigned>(Scancode::DELETE)] = "DELETE";
names[static_cast<unsigned>(Scancode::ARROW_DOWN)] = "ARROW_DOWN";
names[static_cast<unsigned>(Scancode::ARROW_RIGHT)] = "ARROW_RIGHT";
names[static_cast<unsigned>(Scancode::ARROW_UP)] = "ARROW_UP";
names[static_cast<unsigned>(Scancode::PAGE_DOWN)] = "PAGE_DOWN";
names[static_cast<unsigned>(Scancode::PAGE_UP)] = "PAGE_UP";
names[static_cast<unsigned>(Scancode::PRINT_SCREEN)] = "PRINT_SCREEN";
names[static_cast<unsigned>(Scancode::PAUSE)] = "PAUSE";
return names;
}();
//</editor-fold>
inline constexpr std::uint16_t PORT_PS2_DATA = 0x60;
inline constexpr std::uint16_t PORT_PS2_STATUS = 0x64;
inline constexpr std::uint8_t FLAG_PS2_OUTPUT_FULL = (1 << 0);
@ -38,6 +322,8 @@ std::uint8_t gKeyboardBuffer[KEY_BUFFER_LENGTH];
unsigned gBufferedKeys = 0;
unsigned gKeyPos = 0;
constinit std::array<std::uint8_t, (MAX_SCANCODE + 7) / 8> gKeyStates;
__attribute__((no_caller_saved_registers))
void pushKey(std::uint8_t data) noexcept
{
@ -48,10 +334,24 @@ void pushKey(std::uint8_t data) noexcept
++gBufferedKeys;
gKeyPos = (gKeyPos + 1) % KEY_BUFFER_LENGTH;
}
void setKeyDown(Scancode scancode, bool down) noexcept
{
const std::uint16_t index = static_cast<std::uint16_t>(scancode);
const std::uint16_t byte = index / 8;
const std::uint16_t bit = index % 8;
if (down)
{
gKeyStates[byte] |= (1 << bit);
}
else
{
gKeyStates[byte] &= ~(1 << bit);
}
}
}
namespace baos::ps2
{
inline bool waitForResponse(unsigned tries = -1) noexcept
{
for (unsigned t = 0; t < tries; ++t)
@ -219,11 +519,20 @@ void isrKeyboard(InterruptFrame* interruptFrame) noexcept
return result;
}
bool isKeyDown(Scancode scancode) noexcept
{
const std::uint16_t index = static_cast<std::uint16_t>(scancode);
const std::uint16_t byte = index / 8;
const std::uint16_t bit = index % 8;
return (gKeyStates[byte] & (1 << bit)) != 0;
}
bool gNextIsRelease = false;
bool gNextIsExtended = false;
bool gNextIsMoreExtended = false;
bool gNextIsExtendedest = false;
bool gPrevWasExtendedest = false;
bool gNextIsExtended = false; // we've scanned a 0xE0 and are waiting for the second half
bool gNextIsMoreExtended = false; // we've scanned a 0xE0 and a 0x12, and are waiting for the rest of the print screen key (TODO: print screen up is probably broken!)
bool gNextIsExtendedest = false; // this is getting hilarious... this basically means we're somewhere inside the 0xE1, 0x14, 0x77, 0xE1, 0xF0, 0x14, 0xF0, 0x77 sequence for the pause key
bool gPrevWasExtendedest = false; // we just sent the pause key press, send a release after (because it doesn't get generated)
bool readKey(KeyEvent& outEvent) noexcept
{
@ -292,273 +601,61 @@ bool readKey(KeyEvent& outEvent) noexcept
}
else
{
scancode |= 0xE000;
scancode |= 0x0100;
}
}
outEvent.scancode = static_cast<Scancode>(scancode);
outEvent.down = !gNextIsRelease;
outEvent.repeat = false; // TODO
outEvent.repeat = outEvent.down && isKeyDown(outEvent.scancode);
setKeyDown(outEvent.scancode, outEvent.down);
// reset state
gNextIsExtendedest = gNextIsMoreExtended = gNextIsRelease = gNextIsExtended = false;
return true;
}
bool readChar(char& outChar) noexcept
{
KeyEvent event;
while (readKey(event))
{
if (!event.down) {
continue;
}
if (keyToChar(event.scancode, outChar)) {
return true;
}
}
return false;
}
const char* keyName(Scancode scancode) noexcept
{
switch (scancode)
return SCANCODE_NAMES[static_cast<unsigned>(scancode)];
}
bool keyToChar(Scancode scancode, char& outChar) noexcept
{
const Keymap& keymap = KEYMAP_DE_DE;
char result = '\0';
if (isKeyDown(Scancode::RIGHT_ALT))
{
case Scancode::INVALID:
default:
return "INVALID";
case Scancode::F9:
return "F9";
case Scancode::F5:
return "F5";
case Scancode::F3:
return "F3";
case Scancode::F1:
return "F1";
case Scancode::F2:
return "F2";
case Scancode::F12:
return "F12";
case Scancode::F10:
return "F10";
case Scancode::F8:
return "F8";
case Scancode::F6:
return "F6";
case Scancode::F4:
return "F4";
case Scancode::TAB:
return "TAB";
case Scancode::BACKTICK:
return "BACKTICK";
case Scancode::LEFT_ALT:
return "LEFT_ALT";
case Scancode::LEFT_SHIFT:
return "LEFT_SHIFT";
case Scancode::LEFT_CONTROL:
return "LEFT_CONTROL";
case Scancode::Q:
return "Q";
case Scancode::_1:
return "_1";
case Scancode::Z:
return "Z";
case Scancode::S:
return "S";
case Scancode::A:
return "A";
case Scancode::W:
return "W";
case Scancode::_2:
return "_2";
case Scancode::C:
return "C";
case Scancode::X:
return "X";
case Scancode::D:
return "D";
case Scancode::E:
return "E";
case Scancode::_4:
return "_4";
case Scancode::_3:
return "_3";
case Scancode::SPACE:
return "SPACE";
case Scancode::V:
return "V";
case Scancode::F:
return "F";
case Scancode::T:
return "T";
case Scancode::R:
return "R";
case Scancode::_5:
return "_5";
case Scancode::N:
return "N";
case Scancode::B:
return "B";
case Scancode::H:
return "H";
case Scancode::G:
return "G";
case Scancode::Y:
return "Y";
case Scancode::_6:
return "_6";
case Scancode::M:
return "M";
case Scancode::J:
return "J";
case Scancode::U:
return "U";
case Scancode::_7:
return "_7";
case Scancode::_8:
return "_8";
case Scancode::COMMA:
return "COMMA";
case Scancode::K:
return "K";
case Scancode::I:
return "I";
case Scancode::O:
return "O";
case Scancode::_0:
return "_0";
case Scancode::_9:
return "_9";
case Scancode::DOT:
return "DOT";
case Scancode::SLASH:
return "SLASH";
case Scancode::L:
return "L";
case Scancode::SEMICOLON:
return "SEMICOLON";
case Scancode::P:
return "P";
case Scancode::MINUS:
return "MINUS";
case Scancode::APOSTROPHE:
return "APOSTROPHE";
case Scancode::BRACKET_OPEN:
return "BRACKET_OPEN";
case Scancode::EQUALS:
return "EQUALS";
case Scancode::CAPSLOCK:
return "CAPSLOCK";
case Scancode::RIGHT_SHIFT:
return "RIGHT_SHIFT";
case Scancode::ENTER:
return "ENTER";
case Scancode::BRACKET_CLOSE:
return "BRACKET_CLOSE";
case Scancode::BACKSLASH:
return "BACKSLASH";
case Scancode::BACKSPACE:
return "BACKSPACE";
case Scancode::KP_1:
return "KP_1";
case Scancode::KP_4:
return "KP_4";
case Scancode::KP_7:
return "KP_7";
case Scancode::KP_0:
return "KP_0";
case Scancode::KP_DOT:
return "KP_DOT";
case Scancode::KP_2:
return "KP_2";
case Scancode::KP_5:
return "KP_5";
case Scancode::KP_6:
return "KP_6";
case Scancode::KP_8:
return "KP_8";
case Scancode::ESCAPE:
return "ESCAPE";
case Scancode::NUMLOCK:
return "NUMLOCK";
case Scancode::F11:
return "F11";
case Scancode::KP_PLUS:
return "KP_PLUS";
case Scancode::KP_3:
return "KP_3";
case Scancode::KP_MINUS:
return "KP_MINUS";
case Scancode::KP_ASTERISK:
return "KP_ASTERISK";
case Scancode::KP_9:
return "KP_9";
case Scancode::SCROLLOCK:
return "SCROLLOCK";
case Scancode::F7:
return "F7";
case Scancode::MM_WWW_SEARCH:
return "MM_WWW_SEARCH";
case Scancode::RIGHT_ALT:
return "RIGHT_ALT";
case Scancode::RIGHT_CONTROL:
return "RIGHT_CONTROL";
case Scancode::MM_PREV_TRACK:
return "MM_PREV_TRACK";
case Scancode::LEFT_GUI:
return "LEFT_GUI";
case Scancode::MM_WWW_FAVORITES:
return "MM_WWW_FAVORITES";
case Scancode::MM_VOLUME_DOWN:
return "MM_VOLUME_DOWN";
case Scancode::MM_MUTE:
return "MM_MUTE";
case Scancode::RIGHT_GUI:
return "RIGHT_GUI";
case Scancode::MM_WWW_STOP:
return "MM_WWW_STOP";
case Scancode::MM_CALCULATOR:
return "MM_CALCULATOR";
case Scancode::APPS:
return "APPS";
case Scancode::MM_WWW_FORWARD:
return "MM_WWW_FORWARD";
case Scancode::MM_VOLUME_UP:
return "MM_VOLUME_UP";
case Scancode::MM_PLAY_PAUSE:
return "MM_PLAY_PAUSE";
case Scancode::ACPI_POWER:
return "ACPI_POWER";
case Scancode::MM_WWW_BACK:
return "MM_WWW_BACK";
case Scancode::MM_WWW_HOME:
return "MM_WWW_HOME";
case Scancode::MM_STOP:
return "MM_STOP";
case Scancode::ACPI_SLEEP:
return "ACPI_SLEEP";
case Scancode::MM_MY_COMPUTER:
return "MM_MY_COMPUTER";
case Scancode::MM_EMAIL:
return "MM_EMAIL";
case Scancode::KP_SLASH:
return "KP_SLASH";
case Scancode::MM_NEXT_TRACK:
return "MM_NEXT_TRACK";
case Scancode::MM_MEDIA_SELECT:
return "MM_MEDIA_SELECT";
case Scancode::KP_ENTER:
return "KP_ENTER";
case Scancode::ACPI_WAKE:
return "ACPI_WAKE";
case Scancode::END:
return "END";
case Scancode::ARROW_LEFT:
return "ARROW_LEFT";
case Scancode::HOME:
return "HOME";
case Scancode::INSERT:
return "INSERT";
case Scancode::DELETE:
return "DELETE";
case Scancode::ARROW_DOWN:
return "ARROW_DOWN";
case Scancode::ARROW_RIGHT:
return "ARROW_RIGHT";
case Scancode::ARROW_UP:
return "ARROW_UP";
case Scancode::PAGE_DOWN:
return "PAGE_DOWN";
case Scancode::PAGE_UP:
return "PAGE_UP";
case Scancode::PRINT_SCREEN:
return "PRINT_SCREEN";
case Scancode::PAUSE:
return "PAUSE";
result = keymap.altGredKeys[static_cast<unsigned>(scancode)];
}
else if (isKeyDown(Scancode::LEFT_SHIFT) || isKeyDown(Scancode::RIGHT_SHIFT))
{
result = keymap.shiftedKeys[static_cast<unsigned>(scancode)];
}
else
{
result = keymap.regularKeys[static_cast<unsigned>(scancode)];
}
if (result != '\0')
{
outChar = result;
return true;
}
return false;
}
}

View File

@ -243,7 +243,8 @@ void kernel_main()
std::puts("This is BadAppleOS and everything is fine!\n");
__enterUsermode(SEGIDX_USER_CODE, SEGIDX_USER_DATA, &tss.rsp0, &main);
// __enterUsermode(SEGIDX_USER_CODE, SEGIDX_USER_DATA, &tss.rsp0, &main);
main(); // for now run it in kernel mode, user mode doesn't work yet
while (true)
{
ps2::KeyEvent event;