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];
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
ScanCode &= 0x7F; /* Remove KEY_PRESSED bit */
|
||||
|
@ -97,7 +97,7 @@ namespace KernelConsole
|
||||
PaintCallback PaintCB = nullptr;
|
||||
CursorCallback CursorCB = nullptr;
|
||||
|
||||
std::mutex Mutex;
|
||||
std::mutex vt_mutex;
|
||||
|
||||
public:
|
||||
termios *GetTermios() { return &this->TerminalConfig; }
|
||||
@ -124,6 +124,7 @@ namespace KernelConsole
|
||||
void csi_cnl(ANSIArgument *Args, int ArgsCount);
|
||||
void csi_cpl(ANSIArgument *Args, int ArgsCount);
|
||||
void csi_cha(ANSIArgument *Args, int ArgsCount);
|
||||
void ProcessControlCharacter(char c);
|
||||
void Process(char c);
|
||||
|
||||
TerminalCell *GetCell(size_t index) { return &Cells[index]; }
|
||||
|
@ -34,8 +34,34 @@ namespace TTY
|
||||
public:
|
||||
TerminalBuffer(size_t Size) : Buffer(Size), ReadIndex(0), WriteIndex(0) {}
|
||||
|
||||
ssize_t Read(char *OutputBuffer, size_t Size);
|
||||
ssize_t Write(const char *InputBuffer, size_t Size);
|
||||
ssize_t Read(char *OutputBuffer, 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()
|
||||
{
|
||||
@ -57,9 +83,10 @@ namespace TTY
|
||||
class TeletypeDriver
|
||||
{
|
||||
protected:
|
||||
termios TerminalConfig;
|
||||
winsize TerminalSize;
|
||||
termios TerminalConfig{};
|
||||
winsize TerminalSize{};
|
||||
TerminalBuffer TermBuf;
|
||||
pid_t ProcessGroup;
|
||||
|
||||
public:
|
||||
virtual int Open(int Flags, mode_t Mode);
|
||||
@ -69,7 +96,7 @@ namespace TTY
|
||||
virtual int Ioctl(unsigned long Request, void *Argp);
|
||||
|
||||
TeletypeDriver();
|
||||
virtual ~TeletypeDriver();
|
||||
virtual ~TeletypeDriver() = default;
|
||||
};
|
||||
|
||||
class PTYDevice
|
||||
@ -81,10 +108,18 @@ namespace TTY
|
||||
TerminalBuffer TermBuf;
|
||||
|
||||
public:
|
||||
PTYMaster();
|
||||
~PTYMaster();
|
||||
ssize_t Read(void *Buffer, size_t Size);
|
||||
ssize_t Write(const void *Buffer, size_t Size);
|
||||
PTYMaster() : TermBuf(1024) {}
|
||||
~PTYMaster() = default;
|
||||
|
||||
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
|
||||
@ -93,22 +128,48 @@ namespace TTY
|
||||
TerminalBuffer TermBuf;
|
||||
|
||||
public:
|
||||
PTYSlave();
|
||||
~PTYSlave();
|
||||
ssize_t Read(void *Buffer, size_t Size);
|
||||
ssize_t Write(const void *Buffer, size_t Size);
|
||||
PTYSlave() : TermBuf(1024) {}
|
||||
~PTYSlave() = default;
|
||||
|
||||
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;
|
||||
PTYSlave Slave;
|
||||
|
||||
public:
|
||||
PTYDevice();
|
||||
~PTYDevice();
|
||||
int Open();
|
||||
int Close();
|
||||
ssize_t Read(void *Buffer, size_t Size);
|
||||
ssize_t Write(const void *Buffer, size_t Size);
|
||||
PTYDevice() : Master(), Slave() {}
|
||||
~PTYDevice() = default;
|
||||
|
||||
int Open()
|
||||
{
|
||||
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
|
||||
@ -118,8 +179,14 @@ namespace TTY
|
||||
std::mutex PTYMutex;
|
||||
|
||||
public:
|
||||
PTMXDevice();
|
||||
~PTMXDevice();
|
||||
PTMXDevice() = default;
|
||||
|
||||
~PTMXDevice()
|
||||
{
|
||||
for (auto pty : PTYs)
|
||||
delete pty;
|
||||
}
|
||||
|
||||
int Open();
|
||||
int Close();
|
||||
PTYDevice *CreatePTY();
|
||||
|
@ -24,16 +24,6 @@
|
||||
|
||||
namespace TTY
|
||||
{
|
||||
PTMXDevice::PTMXDevice()
|
||||
{
|
||||
}
|
||||
|
||||
PTMXDevice::~PTMXDevice()
|
||||
{
|
||||
for (auto pty : PTYs)
|
||||
delete pty;
|
||||
}
|
||||
|
||||
int PTMXDevice::Open()
|
||||
{
|
||||
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
|
||||
{
|
||||
ssize_t TerminalBuffer::Read(char *OutputBuffer, size_t Size)
|
||||
TeletypeDriver::TeletypeDriver() : TermBuf(1024)
|
||||
{
|
||||
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 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,
|
||||
};
|
||||
if (thisProcess)
|
||||
this->ProcessGroup = thisProcess->Security.ProcessGroupID;
|
||||
else
|
||||
this->ProcessGroup = 0;
|
||||
|
||||
/*
|
||||
- ICRNL - Map Carriage Return to New Line
|
||||
@ -110,32 +46,24 @@ namespace TTY
|
||||
|
||||
- ECHO - Echo input characters
|
||||
- ICANON - Enable canonical input (enable line editing)
|
||||
- ISIG - Enable signals
|
||||
*/
|
||||
this->TerminalConfig.c_iflag = /*ICRNL |*/ IXON;
|
||||
this->TerminalConfig.c_oflag = OPOST | ONLCR;
|
||||
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[VQUIT] = 0x1C; /* ^\ */
|
||||
this->TerminalConfig.c_cc[VERASE] = 0x7F; /* DEL */
|
||||
this->TerminalConfig.c_cc[VKILL] = 0x15; /* ^U */
|
||||
this->TerminalConfig.c_cc[VEOF] = 0x04; /* ^D */
|
||||
this->TerminalConfig.c_cc[VTIME] = 0; /* Timeout for non-canonical read */
|
||||
this->TerminalConfig.c_cc[VMIN] = 1; /* Minimum number of characters for non-canonical read */
|
||||
this->TerminalConfig.c_cc[VSWTC] = 0; /* ^O */
|
||||
this->TerminalConfig.c_cc[VSTART] = 0x11; /* ^Q */
|
||||
this->TerminalConfig.c_cc[VSTOP] = 0x13; /* ^S */
|
||||
this->TerminalConfig.c_cc[VSUSP] = 0x1A; /* ^Z */
|
||||
this->TerminalConfig.c_cc[VEOL] = 0x00; /* NUL */
|
||||
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()
|
||||
{
|
||||
this->TerminalConfig.c_cc[VINTR] = 'C' - 0x40;
|
||||
this->TerminalConfig.c_cc[VQUIT] = '\\' - 0x40;
|
||||
this->TerminalConfig.c_cc[VERASE] = '\177';
|
||||
this->TerminalConfig.c_cc[VKILL] = 'U' - 0x40;
|
||||
this->TerminalConfig.c_cc[VEOF] = 'D' - 0x40;
|
||||
this->TerminalConfig.c_cc[VSTART] = 'Q' - 0x40;
|
||||
this->TerminalConfig.c_cc[VSTOP] = 'S' - 0x40;
|
||||
this->TerminalConfig.c_cc[VSUSP] = 'Z' - 0x40;
|
||||
this->TerminalConfig.c_cc[VREPRINT] = 'R' - 0x40;
|
||||
this->TerminalConfig.c_cc[VDISCARD] = 'O' - 0x40;
|
||||
this->TerminalConfig.c_cc[VWERASE] = 'W' - 0x40;
|
||||
this->TerminalConfig.c_cc[VLNEXT] = 'V' - 0x40;
|
||||
}
|
||||
}
|
||||
|
@ -29,26 +29,27 @@ namespace KernelConsole
|
||||
{
|
||||
int VirtualTerminal::Open(int Flags, mode_t Mode)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(Mutex);
|
||||
std::lock_guard<std::mutex> lock(vt_mutex);
|
||||
stub;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int VirtualTerminal::Close()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(Mutex);
|
||||
std::lock_guard<std::mutex> lock(vt_mutex);
|
||||
stub;
|
||||
return 0;
|
||||
}
|
||||
|
||||
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{};
|
||||
|
||||
/* FIXME: this is a hack, "static" is not a good idea */
|
||||
static bool upperCase = false;
|
||||
static bool controlKey = false;
|
||||
|
||||
RecheckKeyboard:
|
||||
while (DriverManager->GlobalKeyboardInputReports.Count() == 0)
|
||||
@ -65,6 +66,36 @@ namespace KernelConsole
|
||||
upperCase = false;
|
||||
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))
|
||||
goto RecheckKeyboard;
|
||||
@ -99,7 +130,7 @@ namespace KernelConsole
|
||||
|
||||
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;
|
||||
debug("string: \"%*s\"", Size, buf);
|
||||
@ -117,7 +148,7 @@ namespace KernelConsole
|
||||
|
||||
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)
|
||||
{
|
||||
@ -166,14 +197,14 @@ namespace KernelConsole
|
||||
}
|
||||
case TIOCGPGRP:
|
||||
{
|
||||
*((pid_t *)Argp) = thisProcess->Security.ProcessGroupID;
|
||||
debug("returning pgid %d", thisProcess->Security.ProcessGroupID);
|
||||
*((pid_t *)Argp) = this->ProcessGroup;
|
||||
debug("returning pgid %d", this->ProcessGroup);
|
||||
return 0;
|
||||
}
|
||||
case TIOCSPGRP:
|
||||
{
|
||||
thisProcess->Security.ProcessGroupID = *((pid_t *)Argp);
|
||||
debug("updated pgid to %d", thisProcess->Security.ProcessGroupID);
|
||||
this->ProcessGroup = *((pid_t *)Argp);
|
||||
debug("updated pgid to %d", this->ProcessGroup);
|
||||
return 0;
|
||||
}
|
||||
case TIOCGSID:
|
||||
@ -461,6 +492,133 @@ namespace KernelConsole
|
||||
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)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
@ -496,6 +654,15 @@ namespace KernelConsole
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if (this->TerminalConfig.c_lflag & ICANON)
|
||||
{
|
||||
if ((c > 0x00 && c <= 0x1F) && c != '\x1b')
|
||||
{
|
||||
this->ProcessControlCharacter(c);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
ANSIParser *parser = &this->Parser;
|
||||
|
||||
switch (parser->State)
|
||||
@ -636,30 +803,28 @@ namespace KernelConsole
|
||||
|
||||
- ECHO - Echo input characters
|
||||
- ICANON - Enable canonical input (enable line editing)
|
||||
- ISIG - Enable signals
|
||||
*/
|
||||
this->TerminalConfig.c_iflag = /*ICRNL |*/ IXON;
|
||||
this->TerminalConfig.c_oflag = OPOST | ONLCR;
|
||||
this->TerminalConfig.c_cflag = CS8 | CREAD | HUPCL;
|
||||
this->TerminalConfig.c_lflag = ECHO | ICANON;
|
||||
this->TerminalConfig.c_lflag &= ~ICANON; /* FIXME: not ready for this yet */
|
||||
this->TerminalConfig.c_lflag = ECHO | ICANON | ISIG;
|
||||
|
||||
this->TerminalConfig.c_cc[VINTR] = 'C' - 0x40;
|
||||
this->TerminalConfig.c_cc[VQUIT] = '\\' - 0x40;
|
||||
this->TerminalConfig.c_cc[VERASE] = '\177';
|
||||
this->TerminalConfig.c_cc[VKILL] = 'U' - 0x40;
|
||||
this->TerminalConfig.c_cc[VEOF] = 'D' - 0x40;
|
||||
this->TerminalConfig.c_cc[VSTART] = 'Q' - 0x40;
|
||||
this->TerminalConfig.c_cc[VSTOP] = 'S' - 0x40;
|
||||
this->TerminalConfig.c_cc[VSUSP] = 'Z' - 0x40;
|
||||
this->TerminalConfig.c_cc[VREPRINT] = 'R' - 0x40;
|
||||
this->TerminalConfig.c_cc[VDISCARD] = 'O' - 0x40;
|
||||
this->TerminalConfig.c_cc[VWERASE] = 'W' - 0x40;
|
||||
this->TerminalConfig.c_cc[VLNEXT] = 'V' - 0x40;
|
||||
|
||||
this->TerminalConfig.c_cc[VINTR] = 0x03; /* ^C */
|
||||
this->TerminalConfig.c_cc[VQUIT] = 0x1C; /* ^\ */
|
||||
this->TerminalConfig.c_cc[VERASE] = 0x7F; /* DEL */
|
||||
this->TerminalConfig.c_cc[VKILL] = 0x15; /* ^U */
|
||||
this->TerminalConfig.c_cc[VEOF] = 0x04; /* ^D */
|
||||
this->TerminalConfig.c_cc[VTIME] = 0; /* Timeout for non-canonical read */
|
||||
this->TerminalConfig.c_cc[VMIN] = 1; /* Minimum number of characters for non-canonical read */
|
||||
this->TerminalConfig.c_cc[VSWTC] = 0; /* ^O */
|
||||
this->TerminalConfig.c_cc[VSTART] = 0x11; /* ^Q */
|
||||
this->TerminalConfig.c_cc[VSTOP] = 0x13; /* ^S */
|
||||
this->TerminalConfig.c_cc[VSUSP] = 0x1A; /* ^Z */
|
||||
this->TerminalConfig.c_cc[VEOL] = 0x00; /* NUL */
|
||||
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) */
|
||||
|
||||
this->Cells = new TerminalCell[Rows * Columns];
|
||||
|
||||
@ -667,8 +832,5 @@ namespace KernelConsole
|
||||
(Rows * Columns) * sizeof(TerminalCell));
|
||||
}
|
||||
|
||||
VirtualTerminal::~VirtualTerminal()
|
||||
{
|
||||
delete[] this->Cells;
|
||||
}
|
||||
VirtualTerminal::~VirtualTerminal() { delete[] this->Cells; }
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user