feat(kernel/tty): implement processing control characters (^C, ^D, etc)

This commit is contained in:
EnderIce2 2025-04-13 09:49:09 +00:00
parent 5293bb2039
commit 11d326b693
Signed by: enderice2
GPG Key ID: FEB6B8A8507BA62E
7 changed files with 377 additions and 250 deletions

View File

@ -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 */

View File

@ -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]; }

View File

@ -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();

View File

@ -24,16 +24,6 @@
namespace TTY
{
PTMXDevice::PTMXDevice()
{
}
PTMXDevice::~PTMXDevice()
{
for (auto pty : PTYs)
delete pty;
}
int PTMXDevice::Open()
{
stub;

View File

@ -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);
}
}

View File

@ -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;
}
}

View File

@ -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; }
}