mirror of
https://github.com/EnderIce2/Fennix.git
synced 2025-05-28 15:34:31 +00:00
feat(kernel/tty): implement processing control characters (^C, ^D, etc)
This commit is contained in:
parent
5293bb2039
commit
11d326b693
@ -331,6 +331,80 @@ namespace Driver
|
|||||||
: ScanCodeConversionTableLower[ScanCode];
|
: ScanCodeConversionTableLower[ScanCode];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char GetControlCharacter(KeyScanCodes ScanCode)
|
||||||
|
{
|
||||||
|
ScanCode = static_cast<KeyScanCodes>(static_cast<int>(ScanCode) & 0x7F); /* Remove KEY_PRESSED bit */
|
||||||
|
switch (ScanCode)
|
||||||
|
{
|
||||||
|
case KEY_2:
|
||||||
|
return 0x00; /* Ctrl-@ (NUL) */
|
||||||
|
case KEY_A:
|
||||||
|
return 0x01; /* Ctrl-A (SOH) */
|
||||||
|
case KEY_B:
|
||||||
|
return 0x02; /* Ctrl-B (STX) */
|
||||||
|
case KEY_C:
|
||||||
|
return 0x03; /* Ctrl-C (ETX) */
|
||||||
|
case KEY_D:
|
||||||
|
return 0x04; /* Ctrl-D (EOT) */
|
||||||
|
case KEY_E:
|
||||||
|
return 0x05; /* Ctrl-E (ENQ) */
|
||||||
|
case KEY_F:
|
||||||
|
return 0x06; /* Ctrl-F (ACK) */
|
||||||
|
case KEY_G:
|
||||||
|
return 0x07; /* Ctrl-G (BEL) */
|
||||||
|
case KEY_H:
|
||||||
|
return 0x08; /* Ctrl-H (BS) */
|
||||||
|
case KEY_I:
|
||||||
|
return 0x09; /* Ctrl-I (HT) */
|
||||||
|
case KEY_J:
|
||||||
|
return 0x0A; /* Ctrl-J (LF) */
|
||||||
|
case KEY_K:
|
||||||
|
return 0x0B; /* Ctrl-K (VT) */
|
||||||
|
case KEY_L:
|
||||||
|
return 0x0C; /* Ctrl-L (FF) */
|
||||||
|
case KEY_M:
|
||||||
|
return 0x0D; /* Ctrl-M (CR) */
|
||||||
|
case KEY_N:
|
||||||
|
return 0x0E; /* Ctrl-N (SO) */
|
||||||
|
case KEY_O:
|
||||||
|
return 0x0F; /* Ctrl-O (SI) */
|
||||||
|
case KEY_P:
|
||||||
|
return 0x10; /* Ctrl-P (DLE) */
|
||||||
|
case KEY_Q:
|
||||||
|
return 0x11; /* Ctrl-Q (DC1) */
|
||||||
|
case KEY_R:
|
||||||
|
return 0x12; /* Ctrl-R (DC2) */
|
||||||
|
case KEY_S:
|
||||||
|
return 0x13; /* Ctrl-S (DC3) */
|
||||||
|
case KEY_T:
|
||||||
|
return 0x14; /* Ctrl-T (DC4) */
|
||||||
|
case KEY_U:
|
||||||
|
return 0x15; /* Ctrl-U (NAK) */
|
||||||
|
case KEY_V:
|
||||||
|
return 0x16; /* Ctrl-V (SYN) */
|
||||||
|
case KEY_W:
|
||||||
|
return 0x17; /* Ctrl-W (ETB) */
|
||||||
|
case KEY_X:
|
||||||
|
return 0x18; /* Ctrl-X (CAN) */
|
||||||
|
case KEY_Y:
|
||||||
|
return 0x19; /* Ctrl-Y (EM) */
|
||||||
|
case KEY_Z:
|
||||||
|
return 0x1A; /* Ctrl-Z (SUB) */
|
||||||
|
case KEY_LEFT_BRACKET:
|
||||||
|
return 0x1B; /* Ctrl-[ (ESC) */
|
||||||
|
case KEY_BACKSLASH:
|
||||||
|
return 0x1C; /* Ctrl-\ (FS) */
|
||||||
|
case KEY_RIGHT_BRACKET:
|
||||||
|
return 0x1D; /* Ctrl-] (GS) */
|
||||||
|
case KEY_6:
|
||||||
|
return 0x1E; /* Ctrl-^ (RS) */
|
||||||
|
case KEY_MINUS:
|
||||||
|
return 0x1F; /* Ctrl-_ (US) */
|
||||||
|
default:
|
||||||
|
return 0x00; /* Not a control character */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool IsValidChar(uint8_t ScanCode)
|
bool IsValidChar(uint8_t ScanCode)
|
||||||
{
|
{
|
||||||
ScanCode &= 0x7F; /* Remove KEY_PRESSED bit */
|
ScanCode &= 0x7F; /* Remove KEY_PRESSED bit */
|
||||||
|
@ -97,7 +97,7 @@ namespace KernelConsole
|
|||||||
PaintCallback PaintCB = nullptr;
|
PaintCallback PaintCB = nullptr;
|
||||||
CursorCallback CursorCB = nullptr;
|
CursorCallback CursorCB = nullptr;
|
||||||
|
|
||||||
std::mutex Mutex;
|
std::mutex vt_mutex;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
termios *GetTermios() { return &this->TerminalConfig; }
|
termios *GetTermios() { return &this->TerminalConfig; }
|
||||||
@ -124,6 +124,7 @@ namespace KernelConsole
|
|||||||
void csi_cnl(ANSIArgument *Args, int ArgsCount);
|
void csi_cnl(ANSIArgument *Args, int ArgsCount);
|
||||||
void csi_cpl(ANSIArgument *Args, int ArgsCount);
|
void csi_cpl(ANSIArgument *Args, int ArgsCount);
|
||||||
void csi_cha(ANSIArgument *Args, int ArgsCount);
|
void csi_cha(ANSIArgument *Args, int ArgsCount);
|
||||||
|
void ProcessControlCharacter(char c);
|
||||||
void Process(char c);
|
void Process(char c);
|
||||||
|
|
||||||
TerminalCell *GetCell(size_t index) { return &Cells[index]; }
|
TerminalCell *GetCell(size_t index) { return &Cells[index]; }
|
||||||
|
@ -34,8 +34,34 @@ namespace TTY
|
|||||||
public:
|
public:
|
||||||
TerminalBuffer(size_t Size) : Buffer(Size), ReadIndex(0), WriteIndex(0) {}
|
TerminalBuffer(size_t Size) : Buffer(Size), ReadIndex(0), WriteIndex(0) {}
|
||||||
|
|
||||||
ssize_t Read(char *OutputBuffer, size_t Size);
|
ssize_t Read(char *OutputBuffer, size_t Size)
|
||||||
ssize_t Write(const char *InputBuffer, size_t Size);
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(Mutex);
|
||||||
|
size_t bytesRead = 0;
|
||||||
|
|
||||||
|
while (bytesRead < Size && ReadIndex != WriteIndex)
|
||||||
|
{
|
||||||
|
OutputBuffer[bytesRead++] = Buffer[ReadIndex];
|
||||||
|
ReadIndex = (ReadIndex + 1) % Buffer.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
return bytesRead;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t Write(const char *InputBuffer, size_t Size)
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(Mutex);
|
||||||
|
size_t bytesWritten = 0;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < Size; ++i)
|
||||||
|
{
|
||||||
|
Buffer[WriteIndex] = InputBuffer[i];
|
||||||
|
WriteIndex = (WriteIndex + 1) % Buffer.size();
|
||||||
|
bytesWritten++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return bytesWritten;
|
||||||
|
}
|
||||||
|
|
||||||
void DrainOutput()
|
void DrainOutput()
|
||||||
{
|
{
|
||||||
@ -57,9 +83,10 @@ namespace TTY
|
|||||||
class TeletypeDriver
|
class TeletypeDriver
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
termios TerminalConfig;
|
termios TerminalConfig{};
|
||||||
winsize TerminalSize;
|
winsize TerminalSize{};
|
||||||
TerminalBuffer TermBuf;
|
TerminalBuffer TermBuf;
|
||||||
|
pid_t ProcessGroup;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual int Open(int Flags, mode_t Mode);
|
virtual int Open(int Flags, mode_t Mode);
|
||||||
@ -69,7 +96,7 @@ namespace TTY
|
|||||||
virtual int Ioctl(unsigned long Request, void *Argp);
|
virtual int Ioctl(unsigned long Request, void *Argp);
|
||||||
|
|
||||||
TeletypeDriver();
|
TeletypeDriver();
|
||||||
virtual ~TeletypeDriver();
|
virtual ~TeletypeDriver() = default;
|
||||||
};
|
};
|
||||||
|
|
||||||
class PTYDevice
|
class PTYDevice
|
||||||
@ -81,10 +108,18 @@ namespace TTY
|
|||||||
TerminalBuffer TermBuf;
|
TerminalBuffer TermBuf;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
PTYMaster();
|
PTYMaster() : TermBuf(1024) {}
|
||||||
~PTYMaster();
|
~PTYMaster() = default;
|
||||||
ssize_t Read(void *Buffer, size_t Size);
|
|
||||||
ssize_t Write(const void *Buffer, size_t Size);
|
ssize_t Read(void *Buffer, size_t Size)
|
||||||
|
{
|
||||||
|
return TermBuf.Read((char *)Buffer, Size);
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t Write(const void *Buffer, size_t Size)
|
||||||
|
{
|
||||||
|
return TermBuf.Write((const char *)Buffer, Size);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class PTYSlave
|
class PTYSlave
|
||||||
@ -93,22 +128,48 @@ namespace TTY
|
|||||||
TerminalBuffer TermBuf;
|
TerminalBuffer TermBuf;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
PTYSlave();
|
PTYSlave() : TermBuf(1024) {}
|
||||||
~PTYSlave();
|
~PTYSlave() = default;
|
||||||
ssize_t Read(void *Buffer, size_t Size);
|
|
||||||
ssize_t Write(const void *Buffer, size_t Size);
|
ssize_t Read(void *Buffer, size_t Size)
|
||||||
|
{
|
||||||
|
return TermBuf.Read((char *)Buffer, Size);
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t Write(const void *Buffer, size_t Size)
|
||||||
|
{
|
||||||
|
return TermBuf.Write((const char *)Buffer, Size);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
PTYMaster Master;
|
PTYMaster Master;
|
||||||
PTYSlave Slave;
|
PTYSlave Slave;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
PTYDevice();
|
PTYDevice() : Master(), Slave() {}
|
||||||
~PTYDevice();
|
~PTYDevice() = default;
|
||||||
int Open();
|
|
||||||
int Close();
|
int Open()
|
||||||
ssize_t Read(void *Buffer, size_t Size);
|
{
|
||||||
ssize_t Write(const void *Buffer, size_t Size);
|
stub;
|
||||||
|
return -ENOSYS;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Close()
|
||||||
|
{
|
||||||
|
stub;
|
||||||
|
return -ENOSYS;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t Read(void *Buffer, size_t Size)
|
||||||
|
{
|
||||||
|
return Slave.Read(Buffer, Size);
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t Write(const void *Buffer, size_t Size)
|
||||||
|
{
|
||||||
|
return Master.Write(Buffer, Size);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class PTMXDevice
|
class PTMXDevice
|
||||||
@ -118,8 +179,14 @@ namespace TTY
|
|||||||
std::mutex PTYMutex;
|
std::mutex PTYMutex;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
PTMXDevice();
|
PTMXDevice() = default;
|
||||||
~PTMXDevice();
|
|
||||||
|
~PTMXDevice()
|
||||||
|
{
|
||||||
|
for (auto pty : PTYs)
|
||||||
|
delete pty;
|
||||||
|
}
|
||||||
|
|
||||||
int Open();
|
int Open();
|
||||||
int Close();
|
int Close();
|
||||||
PTYDevice *CreatePTY();
|
PTYDevice *CreatePTY();
|
||||||
|
@ -24,16 +24,6 @@
|
|||||||
|
|
||||||
namespace TTY
|
namespace TTY
|
||||||
{
|
{
|
||||||
PTMXDevice::PTMXDevice()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
PTMXDevice::~PTMXDevice()
|
|
||||||
{
|
|
||||||
for (auto pty : PTYs)
|
|
||||||
delete pty;
|
|
||||||
}
|
|
||||||
|
|
||||||
int PTMXDevice::Open()
|
int PTMXDevice::Open()
|
||||||
{
|
{
|
||||||
stub;
|
stub;
|
||||||
|
@ -1,95 +0,0 @@
|
|||||||
/*
|
|
||||||
This file is part of Fennix Kernel.
|
|
||||||
|
|
||||||
Fennix Kernel is free software: you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU General Public License as
|
|
||||||
published by the Free Software Foundation, either version 3 of
|
|
||||||
the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
Fennix Kernel is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <tty.hpp>
|
|
||||||
#include <filesystem/ioctl.hpp>
|
|
||||||
#include <string.h>
|
|
||||||
#include <errno.h>
|
|
||||||
|
|
||||||
#include "../kernel.h"
|
|
||||||
|
|
||||||
namespace TTY
|
|
||||||
{
|
|
||||||
PTYDevice::PTYDevice()
|
|
||||||
: Master(), Slave()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
PTYDevice::~PTYDevice()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
int PTYDevice::Open()
|
|
||||||
{
|
|
||||||
stub;
|
|
||||||
return -ENOSYS;
|
|
||||||
}
|
|
||||||
|
|
||||||
int PTYDevice::Close()
|
|
||||||
{
|
|
||||||
stub;
|
|
||||||
return -ENOSYS;
|
|
||||||
}
|
|
||||||
|
|
||||||
ssize_t PTYDevice::Read(void *Buffer, size_t Size)
|
|
||||||
{
|
|
||||||
return Slave.Read(Buffer, Size);
|
|
||||||
}
|
|
||||||
|
|
||||||
ssize_t PTYDevice::Write(const void *Buffer, size_t Size)
|
|
||||||
{
|
|
||||||
return Master.Write(Buffer, Size);
|
|
||||||
}
|
|
||||||
|
|
||||||
PTYDevice::PTYMaster::PTYMaster()
|
|
||||||
: TermBuf(1024)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
PTYDevice::PTYMaster::~PTYMaster()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
ssize_t PTYDevice::PTYMaster::Read(void *Buffer, size_t Size)
|
|
||||||
{
|
|
||||||
return TermBuf.Read((char *)Buffer, Size);
|
|
||||||
}
|
|
||||||
|
|
||||||
ssize_t PTYDevice::PTYMaster::Write(const void *Buffer, size_t Size)
|
|
||||||
{
|
|
||||||
return TermBuf.Write((const char *)Buffer, Size);
|
|
||||||
}
|
|
||||||
|
|
||||||
PTYDevice::PTYSlave::PTYSlave()
|
|
||||||
: TermBuf(1024)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
PTYDevice::PTYSlave::~PTYSlave()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
ssize_t PTYDevice::PTYSlave::Read(void *Buffer, size_t Size)
|
|
||||||
{
|
|
||||||
return TermBuf.Read((char *)Buffer, Size);
|
|
||||||
}
|
|
||||||
|
|
||||||
ssize_t PTYDevice::PTYSlave::Write(const void *Buffer, size_t Size)
|
|
||||||
{
|
|
||||||
return TermBuf.Write((const char *)Buffer, Size);
|
|
||||||
}
|
|
||||||
}
|
|
@ -26,76 +26,12 @@
|
|||||||
|
|
||||||
namespace TTY
|
namespace TTY
|
||||||
{
|
{
|
||||||
ssize_t TerminalBuffer::Read(char *OutputBuffer, size_t Size)
|
TeletypeDriver::TeletypeDriver() : TermBuf(1024)
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock(Mutex);
|
if (thisProcess)
|
||||||
size_t bytesRead = 0;
|
this->ProcessGroup = thisProcess->Security.ProcessGroupID;
|
||||||
|
else
|
||||||
while (bytesRead < Size && ReadIndex != WriteIndex)
|
this->ProcessGroup = 0;
|
||||||
{
|
|
||||||
OutputBuffer[bytesRead++] = Buffer[ReadIndex];
|
|
||||||
ReadIndex = (ReadIndex + 1) % Buffer.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
return bytesRead;
|
|
||||||
}
|
|
||||||
|
|
||||||
ssize_t TerminalBuffer::Write(const char *InputBuffer, size_t Size)
|
|
||||||
{
|
|
||||||
std::lock_guard<std::mutex> lock(Mutex);
|
|
||||||
size_t bytesWritten = 0;
|
|
||||||
|
|
||||||
for (size_t i = 0; i < Size; ++i)
|
|
||||||
{
|
|
||||||
Buffer[WriteIndex] = InputBuffer[i];
|
|
||||||
WriteIndex = (WriteIndex + 1) % Buffer.size();
|
|
||||||
bytesWritten++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return bytesWritten;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ======================================================================== */
|
|
||||||
|
|
||||||
int TeletypeDriver::Open(int Flags, mode_t Mode)
|
|
||||||
{
|
|
||||||
warn("Unimplemented open(%#x, %#x)", Flags, Mode);
|
|
||||||
return -ENOSYS;
|
|
||||||
}
|
|
||||||
|
|
||||||
int TeletypeDriver::Close()
|
|
||||||
{
|
|
||||||
warn("Unimplemented close()");
|
|
||||||
return -ENOSYS;
|
|
||||||
}
|
|
||||||
|
|
||||||
ssize_t TeletypeDriver::Read(void *Buffer, size_t Size, off_t Offset)
|
|
||||||
{
|
|
||||||
warn("Unimplemented read(%#lx, %#lx, %#lx)", Buffer, Size, Offset);
|
|
||||||
return -ENOSYS;
|
|
||||||
}
|
|
||||||
|
|
||||||
ssize_t TeletypeDriver::Write(const void *Buffer, size_t Size, off_t Offset)
|
|
||||||
{
|
|
||||||
warn("Unimplemented write(%#lx, %#lx, %#lx)", Buffer, Size, Offset);
|
|
||||||
return -ENOSYS;
|
|
||||||
}
|
|
||||||
|
|
||||||
int TeletypeDriver::Ioctl(unsigned long Request, void *Argp)
|
|
||||||
{
|
|
||||||
warn("Unimplemented ioctl(%#lx, %#lx)", Request, Argp);
|
|
||||||
return -ENOSYS;
|
|
||||||
}
|
|
||||||
|
|
||||||
TeletypeDriver::TeletypeDriver()
|
|
||||||
: TermBuf(1024)
|
|
||||||
{
|
|
||||||
this->TerminalSize = {
|
|
||||||
.ws_row = 0,
|
|
||||||
.ws_col = 0,
|
|
||||||
.ws_xpixel = 0,
|
|
||||||
.ws_ypixel = 0,
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
- ICRNL - Map Carriage Return to New Line
|
- ICRNL - Map Carriage Return to New Line
|
||||||
@ -110,32 +46,24 @@ namespace TTY
|
|||||||
|
|
||||||
- ECHO - Echo input characters
|
- ECHO - Echo input characters
|
||||||
- ICANON - Enable canonical input (enable line editing)
|
- ICANON - Enable canonical input (enable line editing)
|
||||||
|
- ISIG - Enable signals
|
||||||
*/
|
*/
|
||||||
this->TerminalConfig.c_iflag = /*ICRNL |*/ IXON;
|
this->TerminalConfig.c_iflag = /*ICRNL |*/ IXON;
|
||||||
this->TerminalConfig.c_oflag = OPOST | ONLCR;
|
this->TerminalConfig.c_oflag = OPOST | ONLCR;
|
||||||
this->TerminalConfig.c_cflag = CS8 | CREAD | HUPCL;
|
this->TerminalConfig.c_cflag = CS8 | CREAD | HUPCL;
|
||||||
this->TerminalConfig.c_lflag = ECHO | ICANON;
|
this->TerminalConfig.c_lflag = ECHO | ICANON | ISIG;
|
||||||
|
|
||||||
this->TerminalConfig.c_cc[VINTR] = 0x03; /* ^C */
|
this->TerminalConfig.c_cc[VINTR] = 'C' - 0x40;
|
||||||
this->TerminalConfig.c_cc[VQUIT] = 0x1C; /* ^\ */
|
this->TerminalConfig.c_cc[VQUIT] = '\\' - 0x40;
|
||||||
this->TerminalConfig.c_cc[VERASE] = 0x7F; /* DEL */
|
this->TerminalConfig.c_cc[VERASE] = '\177';
|
||||||
this->TerminalConfig.c_cc[VKILL] = 0x15; /* ^U */
|
this->TerminalConfig.c_cc[VKILL] = 'U' - 0x40;
|
||||||
this->TerminalConfig.c_cc[VEOF] = 0x04; /* ^D */
|
this->TerminalConfig.c_cc[VEOF] = 'D' - 0x40;
|
||||||
this->TerminalConfig.c_cc[VTIME] = 0; /* Timeout for non-canonical read */
|
this->TerminalConfig.c_cc[VSTART] = 'Q' - 0x40;
|
||||||
this->TerminalConfig.c_cc[VMIN] = 1; /* Minimum number of characters for non-canonical read */
|
this->TerminalConfig.c_cc[VSTOP] = 'S' - 0x40;
|
||||||
this->TerminalConfig.c_cc[VSWTC] = 0; /* ^O */
|
this->TerminalConfig.c_cc[VSUSP] = 'Z' - 0x40;
|
||||||
this->TerminalConfig.c_cc[VSTART] = 0x11; /* ^Q */
|
this->TerminalConfig.c_cc[VREPRINT] = 'R' - 0x40;
|
||||||
this->TerminalConfig.c_cc[VSTOP] = 0x13; /* ^S */
|
this->TerminalConfig.c_cc[VDISCARD] = 'O' - 0x40;
|
||||||
this->TerminalConfig.c_cc[VSUSP] = 0x1A; /* ^Z */
|
this->TerminalConfig.c_cc[VWERASE] = 'W' - 0x40;
|
||||||
this->TerminalConfig.c_cc[VEOL] = 0x00; /* NUL */
|
this->TerminalConfig.c_cc[VLNEXT] = 'V' - 0x40;
|
||||||
this->TerminalConfig.c_cc[VREPRINT] = 0x12; /* ^R */
|
|
||||||
this->TerminalConfig.c_cc[VDISCARD] = 0x14; /* ^T */
|
|
||||||
this->TerminalConfig.c_cc[VWERASE] = 0x17; /* ^W */
|
|
||||||
this->TerminalConfig.c_cc[VLNEXT] = 0x19; /* ^Y */
|
|
||||||
this->TerminalConfig.c_cc[VEOL2] = 0x7F; /* DEL (or sometimes EOF) */
|
|
||||||
}
|
|
||||||
|
|
||||||
TeletypeDriver::~TeletypeDriver()
|
|
||||||
{
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -29,26 +29,27 @@ namespace KernelConsole
|
|||||||
{
|
{
|
||||||
int VirtualTerminal::Open(int Flags, mode_t Mode)
|
int VirtualTerminal::Open(int Flags, mode_t Mode)
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock(Mutex);
|
std::lock_guard<std::mutex> lock(vt_mutex);
|
||||||
stub;
|
stub;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int VirtualTerminal::Close()
|
int VirtualTerminal::Close()
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock(Mutex);
|
std::lock_guard<std::mutex> lock(vt_mutex);
|
||||||
stub;
|
stub;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
ssize_t VirtualTerminal::Read(void *Buffer, size_t Size, off_t Offset)
|
ssize_t VirtualTerminal::Read(void *Buffer, size_t Size, off_t Offset)
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock(Mutex);
|
std::lock_guard<std::mutex> lock(vt_mutex);
|
||||||
|
|
||||||
KeyboardReport report{};
|
KeyboardReport report{};
|
||||||
|
|
||||||
/* FIXME: this is a hack, "static" is not a good idea */
|
/* FIXME: this is a hack, "static" is not a good idea */
|
||||||
static bool upperCase = false;
|
static bool upperCase = false;
|
||||||
|
static bool controlKey = false;
|
||||||
|
|
||||||
RecheckKeyboard:
|
RecheckKeyboard:
|
||||||
while (DriverManager->GlobalKeyboardInputReports.Count() == 0)
|
while (DriverManager->GlobalKeyboardInputReports.Count() == 0)
|
||||||
@ -65,6 +66,36 @@ namespace KernelConsole
|
|||||||
upperCase = false;
|
upperCase = false;
|
||||||
goto RecheckKeyboard;
|
goto RecheckKeyboard;
|
||||||
}
|
}
|
||||||
|
else if (pkey == KEY_LEFT_CTRL || pkey == KEY_RIGHT_CTRL)
|
||||||
|
{
|
||||||
|
if (report.Key & KEY_PRESSED)
|
||||||
|
controlKey = true;
|
||||||
|
else
|
||||||
|
controlKey = false;
|
||||||
|
debug("controlKey = %d", controlKey);
|
||||||
|
goto RecheckKeyboard;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (controlKey && this->TerminalConfig.c_lflag & ICANON)
|
||||||
|
{
|
||||||
|
if (report.Key & KEY_PRESSED)
|
||||||
|
{
|
||||||
|
char cc = Driver::GetControlCharacter(report.Key);
|
||||||
|
if (cc == 0x00)
|
||||||
|
goto RecheckKeyboard;
|
||||||
|
|
||||||
|
if (this->TerminalConfig.c_lflag & ECHO)
|
||||||
|
{
|
||||||
|
char c = Driver::GetScanCode(report.Key, true);
|
||||||
|
this->Append('^');
|
||||||
|
this->Append(c);
|
||||||
|
this->Append('\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
this->Process(cc);
|
||||||
|
goto RecheckKeyboard;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!(report.Key & KEY_PRESSED))
|
if (!(report.Key & KEY_PRESSED))
|
||||||
goto RecheckKeyboard;
|
goto RecheckKeyboard;
|
||||||
@ -99,7 +130,7 @@ namespace KernelConsole
|
|||||||
|
|
||||||
ssize_t VirtualTerminal::Write(const void *Buffer, size_t Size, off_t Offset)
|
ssize_t VirtualTerminal::Write(const void *Buffer, size_t Size, off_t Offset)
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock(Mutex);
|
std::lock_guard<std::mutex> lock(vt_mutex);
|
||||||
|
|
||||||
char *buf = (char *)Buffer;
|
char *buf = (char *)Buffer;
|
||||||
debug("string: \"%*s\"", Size, buf);
|
debug("string: \"%*s\"", Size, buf);
|
||||||
@ -117,7 +148,7 @@ namespace KernelConsole
|
|||||||
|
|
||||||
int VirtualTerminal::Ioctl(unsigned long Request, void *Argp)
|
int VirtualTerminal::Ioctl(unsigned long Request, void *Argp)
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock(Mutex);
|
std::lock_guard<std::mutex> lock(vt_mutex);
|
||||||
|
|
||||||
switch (Request)
|
switch (Request)
|
||||||
{
|
{
|
||||||
@ -166,14 +197,14 @@ namespace KernelConsole
|
|||||||
}
|
}
|
||||||
case TIOCGPGRP:
|
case TIOCGPGRP:
|
||||||
{
|
{
|
||||||
*((pid_t *)Argp) = thisProcess->Security.ProcessGroupID;
|
*((pid_t *)Argp) = this->ProcessGroup;
|
||||||
debug("returning pgid %d", thisProcess->Security.ProcessGroupID);
|
debug("returning pgid %d", this->ProcessGroup);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
case TIOCSPGRP:
|
case TIOCSPGRP:
|
||||||
{
|
{
|
||||||
thisProcess->Security.ProcessGroupID = *((pid_t *)Argp);
|
this->ProcessGroup = *((pid_t *)Argp);
|
||||||
debug("updated pgid to %d", thisProcess->Security.ProcessGroupID);
|
debug("updated pgid to %d", this->ProcessGroup);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
case TIOCGSID:
|
case TIOCGSID:
|
||||||
@ -461,6 +492,133 @@ namespace KernelConsole
|
|||||||
CursorCB(&Cursor);
|
CursorCB(&Cursor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void VirtualTerminal::ProcessControlCharacter(char c)
|
||||||
|
{
|
||||||
|
auto ccheck = [&](int v)
|
||||||
|
{
|
||||||
|
return (this->TerminalConfig.c_cc[v] != 0x00 &&
|
||||||
|
this->TerminalConfig.c_cc[v] == c);
|
||||||
|
};
|
||||||
|
|
||||||
|
auto ciflag = [&](int f)
|
||||||
|
{
|
||||||
|
return (this->TerminalConfig.c_iflag & f) != 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
auto clflag = [&](int f)
|
||||||
|
{
|
||||||
|
return (this->TerminalConfig.c_lflag & f) != 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (ciflag(IXON) && ccheck(VSTOP))
|
||||||
|
{
|
||||||
|
fixme("flow control: stopping output");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ciflag(IXON) && ccheck(VSTART))
|
||||||
|
{
|
||||||
|
fixme("flow control: resuming output");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (clflag(ISIG))
|
||||||
|
{
|
||||||
|
if (ccheck(VINTR))
|
||||||
|
{
|
||||||
|
if (this->ProcessGroup == 0)
|
||||||
|
{
|
||||||
|
debug("Process group is 0!!!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto proc : thisProcess->GetContext()->GetProcessList())
|
||||||
|
{
|
||||||
|
if (proc->Security.ProcessGroupID != this->ProcessGroup)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
debug("Sending signal SIGINT to %s(%d)", proc->Name, proc->ID);
|
||||||
|
proc->SendSignal(SIGINT);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (ccheck(VQUIT))
|
||||||
|
{
|
||||||
|
if (this->ProcessGroup == 0)
|
||||||
|
{
|
||||||
|
debug("Process group is 0!!!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto proc : thisProcess->GetContext()->GetProcessList())
|
||||||
|
{
|
||||||
|
if (proc->Security.ProcessGroupID != this->ProcessGroup)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
debug("Sending signal SIGQUIT to %s(%d)", proc->Name, proc->ID);
|
||||||
|
proc->SendSignal(SIGQUIT);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (ccheck(VSUSP))
|
||||||
|
{
|
||||||
|
if (this->ProcessGroup == 0)
|
||||||
|
{
|
||||||
|
debug("Process group is 0!!!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto proc : thisProcess->GetContext()->GetProcessList())
|
||||||
|
{
|
||||||
|
if (proc->Security.ProcessGroupID != this->ProcessGroup)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
debug("Sending signal SIGTSTP to %s(%d)", proc->Name, proc->ID);
|
||||||
|
proc->SendSignal(SIGTSTP);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c == '\r')
|
||||||
|
{
|
||||||
|
if (ciflag(IGNCR))
|
||||||
|
return;
|
||||||
|
if (ciflag(ICRNL))
|
||||||
|
c = '\n';
|
||||||
|
}
|
||||||
|
else if (c == '\n' && (ciflag(INLCR)))
|
||||||
|
c = '\r';
|
||||||
|
|
||||||
|
if (clflag(ICANON))
|
||||||
|
{
|
||||||
|
if (ccheck(VERASE))
|
||||||
|
{
|
||||||
|
if (this->Cursor.X > 0)
|
||||||
|
{
|
||||||
|
this->Cursor.X--;
|
||||||
|
this->Append('\b');
|
||||||
|
this->Append(' ');
|
||||||
|
this->Append('\b');
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (ccheck(VKILL))
|
||||||
|
{
|
||||||
|
fixme("clear the current line");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (clflag(ECHO))
|
||||||
|
{
|
||||||
|
if (c == '\n')
|
||||||
|
this->Append('\n');
|
||||||
|
else
|
||||||
|
this->Append(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void VirtualTerminal::Process(char c)
|
void VirtualTerminal::Process(char c)
|
||||||
{
|
{
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
@ -496,6 +654,15 @@ namespace KernelConsole
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if (this->TerminalConfig.c_lflag & ICANON)
|
||||||
|
{
|
||||||
|
if ((c > 0x00 && c <= 0x1F) && c != '\x1b')
|
||||||
|
{
|
||||||
|
this->ProcessControlCharacter(c);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ANSIParser *parser = &this->Parser;
|
ANSIParser *parser = &this->Parser;
|
||||||
|
|
||||||
switch (parser->State)
|
switch (parser->State)
|
||||||
@ -636,30 +803,28 @@ namespace KernelConsole
|
|||||||
|
|
||||||
- ECHO - Echo input characters
|
- ECHO - Echo input characters
|
||||||
- ICANON - Enable canonical input (enable line editing)
|
- ICANON - Enable canonical input (enable line editing)
|
||||||
|
- ISIG - Enable signals
|
||||||
*/
|
*/
|
||||||
this->TerminalConfig.c_iflag = /*ICRNL |*/ IXON;
|
this->TerminalConfig.c_iflag = /*ICRNL |*/ IXON;
|
||||||
this->TerminalConfig.c_oflag = OPOST | ONLCR;
|
this->TerminalConfig.c_oflag = OPOST | ONLCR;
|
||||||
this->TerminalConfig.c_cflag = CS8 | CREAD | HUPCL;
|
this->TerminalConfig.c_cflag = CS8 | CREAD | HUPCL;
|
||||||
this->TerminalConfig.c_lflag = ECHO | ICANON;
|
this->TerminalConfig.c_lflag = ECHO | ICANON | ISIG;
|
||||||
this->TerminalConfig.c_lflag &= ~ICANON; /* FIXME: not ready for this yet */
|
|
||||||
|
|
||||||
this->TerminalConfig.c_cc[VINTR] = 0x03; /* ^C */
|
this->TerminalConfig.c_cc[VINTR] = 'C' - 0x40;
|
||||||
this->TerminalConfig.c_cc[VQUIT] = 0x1C; /* ^\ */
|
this->TerminalConfig.c_cc[VQUIT] = '\\' - 0x40;
|
||||||
this->TerminalConfig.c_cc[VERASE] = 0x7F; /* DEL */
|
this->TerminalConfig.c_cc[VERASE] = '\177';
|
||||||
this->TerminalConfig.c_cc[VKILL] = 0x15; /* ^U */
|
this->TerminalConfig.c_cc[VKILL] = 'U' - 0x40;
|
||||||
this->TerminalConfig.c_cc[VEOF] = 0x04; /* ^D */
|
this->TerminalConfig.c_cc[VEOF] = 'D' - 0x40;
|
||||||
this->TerminalConfig.c_cc[VTIME] = 0; /* Timeout for non-canonical read */
|
this->TerminalConfig.c_cc[VSTART] = 'Q' - 0x40;
|
||||||
this->TerminalConfig.c_cc[VMIN] = 1; /* Minimum number of characters for non-canonical read */
|
this->TerminalConfig.c_cc[VSTOP] = 'S' - 0x40;
|
||||||
this->TerminalConfig.c_cc[VSWTC] = 0; /* ^O */
|
this->TerminalConfig.c_cc[VSUSP] = 'Z' - 0x40;
|
||||||
this->TerminalConfig.c_cc[VSTART] = 0x11; /* ^Q */
|
this->TerminalConfig.c_cc[VREPRINT] = 'R' - 0x40;
|
||||||
this->TerminalConfig.c_cc[VSTOP] = 0x13; /* ^S */
|
this->TerminalConfig.c_cc[VDISCARD] = 'O' - 0x40;
|
||||||
this->TerminalConfig.c_cc[VSUSP] = 0x1A; /* ^Z */
|
this->TerminalConfig.c_cc[VWERASE] = 'W' - 0x40;
|
||||||
this->TerminalConfig.c_cc[VEOL] = 0x00; /* NUL */
|
this->TerminalConfig.c_cc[VLNEXT] = 'V' - 0x40;
|
||||||
this->TerminalConfig.c_cc[VREPRINT] = 0x12; /* ^R */
|
|
||||||
this->TerminalConfig.c_cc[VDISCARD] = 0x14; /* ^T */
|
this->TerminalConfig.c_cc[VTIME] = 0; /* Timeout for non-canonical read */
|
||||||
this->TerminalConfig.c_cc[VWERASE] = 0x17; /* ^W */
|
this->TerminalConfig.c_cc[VMIN] = 1; /* Minimum number of characters for non-canonical read */
|
||||||
this->TerminalConfig.c_cc[VLNEXT] = 0x19; /* ^Y */
|
|
||||||
this->TerminalConfig.c_cc[VEOL2] = 0x7F; /* DEL (or sometimes EOF) */
|
|
||||||
|
|
||||||
this->Cells = new TerminalCell[Rows * Columns];
|
this->Cells = new TerminalCell[Rows * Columns];
|
||||||
|
|
||||||
@ -667,8 +832,5 @@ namespace KernelConsole
|
|||||||
(Rows * Columns) * sizeof(TerminalCell));
|
(Rows * Columns) * sizeof(TerminalCell));
|
||||||
}
|
}
|
||||||
|
|
||||||
VirtualTerminal::~VirtualTerminal()
|
VirtualTerminal::~VirtualTerminal() { delete[] this->Cells; }
|
||||||
{
|
|
||||||
delete[] this->Cells;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user