Kernel: TTY now reads input byte by byte

This allows correct behaviour for character streams / keyboard
handling. Serial input can now send working ^C :D
This commit is contained in:
Bananymous 2023-09-07 15:06:27 +03:00
parent 5e1725abb2
commit b30af0edca
3 changed files with 55 additions and 82 deletions

View File

@ -29,7 +29,7 @@ namespace Kernel
static void initialize_devices(); static void initialize_devices();
void on_key_event(Input::KeyEvent); void on_key_event(Input::KeyEvent);
void handle_input(const uint8_t* ch); void handle_input_byte(uint8_t);
virtual bool is_tty() const override { return true; } virtual bool is_tty() const override { return true; }

View File

@ -244,12 +244,13 @@ namespace Kernel
if (m_serial.port() != COM1_PORT && m_serial.port() != COM2_PORT) if (m_serial.port() != COM1_PORT && m_serial.port() != COM2_PORT)
return; return;
static uint8_t buffer[128];
auto update_com = auto update_com =
[&](auto& device, auto& input_queue) [&](auto& device, auto& input_queue)
{ {
if (input_queue.empty()) if (input_queue.empty())
return; return;
uint8_t buffer[128];
uint8_t* ptr = buffer; uint8_t* ptr = buffer;
while (!input_queue.empty()) while (!input_queue.empty())
{ {
@ -262,7 +263,10 @@ namespace Kernel
ptr++; ptr++;
} }
*ptr = '\0'; *ptr = '\0';
device->handle_input(buffer);
ptr = buffer;
while (*ptr)
device->handle_input_byte(*ptr++);
}; };
CriticalScope _; CriticalScope _;

View File

@ -54,20 +54,7 @@ namespace Kernel
{ {
Input::KeyEvent event; Input::KeyEvent event;
ASSERT(MUST(Process::current().sys_read(fd, &event, sizeof(event))) == sizeof(event)); ASSERT(MUST(Process::current().sys_read(fd, &event, sizeof(event))) == sizeof(event));
TTY::current()->on_key_event(event);
TTY& current_tty = *TTY::current();
if (current_tty.m_foreground_pgrp &&
event.pressed() &&
event.ctrl() &&
!event.shift()
&& event.key == Input::Key::C
)
{
if (auto ret = Process::sys_kill(-current_tty.m_foreground_pgrp, SIGINT); ret.is_error())
dwarnln("TTY: {}", ret.error());
}
else
current_tty.on_key_event(event);
} }
}, nullptr }, nullptr
); );
@ -146,91 +133,73 @@ namespace Kernel
} }
} }
handle_input((const uint8_t*)ansi_c_str); if (ansi_c_str)
}
void TTY::handle_input(const uint8_t* ansi)
{ {
LockGuard _(m_lock); auto* ptr = (const uint8_t*)ansi_c_str;
while (*ptr)
bool eof = ansi && ( handle_input_byte(*ptr++);
ansi[0] == '\x04' || // ^D
ansi[0] == '\n' // \n
);
if (ansi && m_termios.canonical)
{
// EOF from ^D
if (ansi[0] == '\x04')
goto flush;
else if (ansi[0] == '\b')
{
ansi = nullptr;
do_backspace();
} }
} }
if (ansi == nullptr) void TTY::handle_input_byte(uint8_t ch)
{
if (ch == 0)
return; return;
for (size_t i = 0; ansi[i]; i++) LockGuard _(m_lock);
// ^C
if (ch == '\x03')
{ {
if (m_output.bytes >= m_output.buffer.size()) if (auto ret = Process::sys_kill(-m_foreground_pgrp, SIGINT); ret.is_error())
dwarnln("TTY: {}", ret.error());
return;
}
// ^D + canonical
if (ch == '\x04' && m_termios.canonical)
{ {
dprintln("TTY buffer full"); m_output.flush = true;
break; m_output.semaphore.unblock();
return;
} }
m_output.buffer[m_output.bytes++] = ansi[i];
// backspace + canonical
if (ch == '\b' && m_termios.canonical)
{
do_backspace();
return;
} }
m_output.buffer[m_output.bytes++] = ch;
if (m_termios.echo) if (m_termios.echo)
{ {
for (size_t i = 0; ansi[i]; i++) if ((ch <= 31 || ch == 127) && ch != '\n')
{
if (ansi[i] <= 26 && ansi[i] != 10)
{
putchar('^');
putchar('A' + ansi[i] - 1);
}
else if (ansi[i] == 27)
{ {
putchar('^'); putchar('^');
if (ch <= 26 && ch != 10)
putchar('A' + ch - 1);
else if (ch == 27)
putchar('['); putchar('[');
} else if (ch == 28)
else if (ansi[i] == 28)
{
putchar('^');
putchar('\\'); putchar('\\');
} else if (ch == 29)
else if (ansi[i] == 29)
{
putchar('^');
putchar(']'); putchar(']');
} else if (ch == 30)
else if (ansi[i] == 30)
{
putchar('^');
putchar('^');
}
else if (ansi[i] == 31)
{
putchar('^'); putchar('^');
else if (ch == 31)
putchar('_'); putchar('_');
} else if (ch == 127)
else if (ansi[i] == 127)
{
putchar('^');
putchar('?'); putchar('?');
} }
else else
{ {
putchar(ansi[i]); putchar(ch);
}
} }
} }
flush: if (ch == '\n' || !m_termios.canonical)
if (eof || !m_termios.canonical)
{ {
m_output.flush = true; m_output.flush = true;
m_output.semaphore.unblock(); m_output.semaphore.unblock();