kernel+libc+sh: Make the TTY device actually follow termios rules
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
Like, so much more termios compatibility!
This commit is contained in:
parent
efd5bae7a5
commit
de6fe7f7c2
@ -98,7 +98,11 @@ Result<int> luna_main(int argc, char** argv)
|
|||||||
auto maybe_cmd = input_file->read_line();
|
auto maybe_cmd = input_file->read_line();
|
||||||
if (maybe_cmd.has_error())
|
if (maybe_cmd.has_error())
|
||||||
{
|
{
|
||||||
if (maybe_cmd.error() == EINTR) continue;
|
if (maybe_cmd.error() == EINTR)
|
||||||
|
{
|
||||||
|
os::println("");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
return maybe_cmd.release_error();
|
return maybe_cmd.release_error();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -150,6 +154,8 @@ Result<int> luna_main(int argc, char** argv)
|
|||||||
{
|
{
|
||||||
int sig = WTERMSIG(status);
|
int sig = WTERMSIG(status);
|
||||||
if (sig != SIGINT && sig != SIGQUIT) os::println("[sh] Process %d exited: %s", child, strsignal(sig));
|
if (sig != SIGINT && sig != SIGQUIT) os::println("[sh] Process %d exited: %s", child, strsignal(sig));
|
||||||
|
else
|
||||||
|
os::println("");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,13 +3,14 @@
|
|||||||
|
|
||||||
namespace Keyboard
|
namespace Keyboard
|
||||||
{
|
{
|
||||||
enum Modifiers
|
struct KeyboardState
|
||||||
{
|
{
|
||||||
LeftControl = 1,
|
bool ignore_next { false };
|
||||||
LeftAlt = 2,
|
bool left_shift { false };
|
||||||
|
bool right_shift { false };
|
||||||
|
bool left_control { false };
|
||||||
|
bool capslock { false };
|
||||||
};
|
};
|
||||||
|
|
||||||
Option<char> decode_scancode(u8 scancode);
|
Option<char> decode_scancode_tty(u8 scancode, KeyboardState& state);
|
||||||
|
|
||||||
int modifiers();
|
|
||||||
}
|
}
|
||||||
|
@ -147,8 +147,7 @@ void io_thread()
|
|||||||
u8 scancode;
|
u8 scancode;
|
||||||
while (!scancode_queue.try_pop(scancode)) kernel_wait_for_event();
|
while (!scancode_queue.try_pop(scancode)) kernel_wait_for_event();
|
||||||
|
|
||||||
char key;
|
ConsoleDevice::did_press_or_release_key(scancode);
|
||||||
if (Keyboard::decode_scancode(scancode).try_set_value(key)) ConsoleDevice::did_press_key(key);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
#include "arch/Keyboard.h"
|
#include "arch/Keyboard.h"
|
||||||
|
#include <luna/CType.h>
|
||||||
|
|
||||||
// PS/2 keyboard decoding routine.
|
// PS/2 keyboard decoding routine.
|
||||||
|
|
||||||
@ -28,11 +29,6 @@ static bool should_ignore_key(u8 scancode)
|
|||||||
return (scancode > 0x3A && scancode < 0x47) || scancode == TAB || scancode == F11 || scancode == F12;
|
return (scancode > 0x3A && scancode < 0x47) || scancode == TAB || scancode == F11 || scancode == F12;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool g_ignore_next { false };
|
|
||||||
static bool g_left_shift { false };
|
|
||||||
static bool g_right_shift { false };
|
|
||||||
static bool g_capslock { false };
|
|
||||||
|
|
||||||
constexpr char key_table[] = {
|
constexpr char key_table[] = {
|
||||||
'\0',
|
'\0',
|
||||||
'\1', // escape
|
'\1', // escape
|
||||||
@ -117,28 +113,26 @@ constexpr char shifted_key_table[] = {
|
|||||||
'.', // keypad .
|
'.', // keypad .
|
||||||
};
|
};
|
||||||
|
|
||||||
static bool is_shifted()
|
static bool is_shifted(const Keyboard::KeyboardState& state)
|
||||||
{
|
{
|
||||||
if (g_capslock) return !(g_left_shift || g_right_shift);
|
if (state.capslock) return !(state.left_shift || state.right_shift);
|
||||||
return g_left_shift || g_right_shift;
|
return state.left_shift || state.right_shift;
|
||||||
}
|
}
|
||||||
|
|
||||||
int g_modifiers = 0;
|
|
||||||
|
|
||||||
namespace Keyboard
|
namespace Keyboard
|
||||||
{
|
{
|
||||||
Option<char> decode_scancode(u8 scancode)
|
Option<char> decode_scancode_tty(u8 scancode, KeyboardState& state)
|
||||||
{
|
{
|
||||||
if (g_ignore_next)
|
if (state.ignore_next)
|
||||||
{
|
{
|
||||||
g_ignore_next = false;
|
state.ignore_next = false;
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: Support extended scancodes.
|
// FIXME: Support extended scancodes.
|
||||||
if (scancode == EXTENDED_KEY_CODE)
|
if (scancode == EXTENDED_KEY_CODE)
|
||||||
{
|
{
|
||||||
g_ignore_next = true;
|
state.ignore_next = true;
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -146,35 +140,27 @@ namespace Keyboard
|
|||||||
|
|
||||||
if (scancode == LEFT_SHIFT)
|
if (scancode == LEFT_SHIFT)
|
||||||
{
|
{
|
||||||
g_left_shift = !released;
|
state.left_shift = !released;
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (scancode == RIGHT_SHIFT)
|
if (scancode == RIGHT_SHIFT)
|
||||||
{
|
{
|
||||||
g_right_shift = !released;
|
state.right_shift = !released;
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (scancode == CAPS_LOCK)
|
if (scancode == CAPS_LOCK)
|
||||||
{
|
{
|
||||||
if (!released) g_capslock = !g_capslock;
|
if (!released) state.capslock = !state.capslock;
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (scancode == LEFT_ALT)
|
|
||||||
{
|
|
||||||
if (released) g_modifiers &= ~LeftAlt;
|
|
||||||
else
|
|
||||||
g_modifiers |= LeftAlt;
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (scancode == LEFT_CONTROL)
|
if (scancode == LEFT_CONTROL)
|
||||||
{
|
{
|
||||||
if (released) g_modifiers &= ~LeftControl;
|
if (released) state.left_control = false;
|
||||||
else
|
else
|
||||||
g_modifiers |= LeftControl;
|
state.left_control = true;
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -182,12 +168,20 @@ namespace Keyboard
|
|||||||
|
|
||||||
if (released) return {};
|
if (released) return {};
|
||||||
|
|
||||||
if (is_shifted()) return shifted_key_table[scancode];
|
if (state.left_control)
|
||||||
|
{
|
||||||
|
char key;
|
||||||
|
if (is_shifted(state)) key = shifted_key_table[scancode];
|
||||||
|
else
|
||||||
|
key = key_table[scancode];
|
||||||
|
if (_islower(key)) key = (char)_toupper(key);
|
||||||
|
if (_isupper(key)) return key - 0x40;
|
||||||
|
if (key == '@') return key - 0x40;
|
||||||
|
if (key > 'Z' && key < '`') return key - 0x40;
|
||||||
|
if (key == '?') return 0x7f;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_shifted(state)) return shifted_key_table[scancode];
|
||||||
return key_table[scancode];
|
return key_table[scancode];
|
||||||
}
|
}
|
||||||
|
|
||||||
int modifiers()
|
|
||||||
{
|
|
||||||
return g_modifiers;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,36 +1,34 @@
|
|||||||
#include "fs/devices/ConsoleDevice.h"
|
#include "fs/devices/ConsoleDevice.h"
|
||||||
#include "Log.h"
|
#include "Log.h"
|
||||||
#include "arch/Keyboard.h"
|
|
||||||
#include "fs/devices/DeviceRegistry.h"
|
#include "fs/devices/DeviceRegistry.h"
|
||||||
#include "memory/MemoryManager.h"
|
#include "memory/MemoryManager.h"
|
||||||
#include "thread/Scheduler.h"
|
#include "thread/Scheduler.h"
|
||||||
#include "video/TextConsole.h"
|
#include "video/TextConsole.h"
|
||||||
#include <bits/ioctl-defs.h>
|
#include <bits/ioctl-defs.h>
|
||||||
#include <bits/termios.h>
|
|
||||||
#include <luna/Buffer.h>
|
|
||||||
#include <luna/CString.h>
|
#include <luna/CString.h>
|
||||||
|
#include <luna/CType.h>
|
||||||
#include <luna/Units.h>
|
#include <luna/Units.h>
|
||||||
#include <luna/Vector.h>
|
#include <luna/Vector.h>
|
||||||
|
|
||||||
static Buffer g_console_input;
|
Vector<SharedPtr<ConsoleDevice>> ConsoleDevice::m_console_devices;
|
||||||
static bool g_eof { false };
|
|
||||||
static bool g_echo { true };
|
|
||||||
static bool g_stop_background_output { false };
|
|
||||||
|
|
||||||
static Option<pid_t> g_foreground_process_group;
|
|
||||||
|
|
||||||
Result<void> ConsoleDevice::create()
|
Result<void> ConsoleDevice::create()
|
||||||
{
|
{
|
||||||
auto device = (SharedPtr<Device>)TRY(make_shared<ConsoleDevice>());
|
auto device = TRY(make_shared<ConsoleDevice>());
|
||||||
g_foreground_process_group = {};
|
device->m_settings.c_lflag = ECHO | ECHOE | ECHOCTL | ISIG | ICANON;
|
||||||
|
device->m_settings.c_cc[VEOF] = '\4';
|
||||||
|
device->m_settings.c_cc[VERASE] = '\b';
|
||||||
|
device->m_settings.c_cc[VINTR] = '\3';
|
||||||
|
device->m_settings.c_cc[VQUIT] = '\x1c';
|
||||||
|
TRY(m_console_devices.try_append(device));
|
||||||
return DeviceRegistry::register_special_device(DeviceRegistry::Console, 0, device);
|
return DeviceRegistry::register_special_device(DeviceRegistry::Console, 0, device);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Result<void> handle_background_process_group(bool can_succeed, int signo)
|
Result<void> ConsoleDevice::handle_background_process_group(bool can_succeed, int signo) const
|
||||||
{
|
{
|
||||||
if (!g_foreground_process_group.has_value()) return {};
|
if (!m_foreground_process_group.has_value()) return {};
|
||||||
|
|
||||||
auto foreground_pgrp = g_foreground_process_group.value();
|
auto foreground_pgrp = m_foreground_process_group.value();
|
||||||
|
|
||||||
auto* current = Scheduler::current();
|
auto* current = Scheduler::current();
|
||||||
if ((pid_t)current->pgid == foreground_pgrp) return {};
|
if ((pid_t)current->pgid == foreground_pgrp) return {};
|
||||||
@ -51,22 +49,22 @@ Result<usize> ConsoleDevice::read(u8* buf, usize, usize length) const
|
|||||||
{
|
{
|
||||||
TRY(handle_background_process_group(false, SIGTTIN));
|
TRY(handle_background_process_group(false, SIGTTIN));
|
||||||
|
|
||||||
if (length > g_console_input.size()) length = g_console_input.size();
|
if (length > m_input_buffer.size()) length = m_input_buffer.size();
|
||||||
|
|
||||||
memcpy(buf, g_console_input.data(), length);
|
memcpy(buf, m_input_buffer.data(), length);
|
||||||
|
|
||||||
memmove(g_console_input.data(), g_console_input.data() + length, g_console_input.size() - length);
|
memmove(m_input_buffer.data(), m_input_buffer.data() + length, m_input_buffer.size() - length);
|
||||||
|
|
||||||
g_console_input.try_resize(g_console_input.size() - length).release_value();
|
m_input_buffer.try_resize(m_input_buffer.size() - length).release_value();
|
||||||
|
|
||||||
if (!length && g_eof) g_eof = false;
|
if (!length && m_may_read_without_blocking) m_may_read_without_blocking = false;
|
||||||
|
|
||||||
return length;
|
return length;
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<usize> ConsoleDevice::write(const u8* buf, usize, usize length)
|
Result<usize> ConsoleDevice::write(const u8* buf, usize, usize length)
|
||||||
{
|
{
|
||||||
if (g_stop_background_output) TRY(handle_background_process_group(true, SIGTTOU));
|
if (m_settings.c_lflag & TOSTOP) TRY(handle_background_process_group(true, SIGTTOU));
|
||||||
|
|
||||||
TextConsole::write((const char*)buf, length);
|
TextConsole::write((const char*)buf, length);
|
||||||
return length;
|
return length;
|
||||||
@ -74,78 +72,124 @@ Result<usize> ConsoleDevice::write(const u8* buf, usize, usize length)
|
|||||||
|
|
||||||
bool ConsoleDevice::blocking() const
|
bool ConsoleDevice::blocking() const
|
||||||
{
|
{
|
||||||
return g_eof ? false : g_console_input.size() == 0;
|
return m_may_read_without_blocking ? false : m_input_buffer.size() == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Vector<u8> g_temp_input;
|
void ConsoleDevice::did_press_or_release_key(u8 scancode)
|
||||||
|
|
||||||
void ConsoleDevice::did_press_key(char key)
|
|
||||||
{
|
{
|
||||||
if (key == '\b')
|
for (const auto& device : m_console_devices) { device->process_key_event(scancode); }
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConsoleDevice::process_key_event(u8 scancode)
|
||||||
|
{
|
||||||
|
auto rc = Keyboard::decode_scancode_tty(scancode, m_kb_state);
|
||||||
|
if (!rc.has_value()) return;
|
||||||
|
char key = rc.value();
|
||||||
|
check(key >= 0);
|
||||||
|
|
||||||
|
bool is_special_character { false };
|
||||||
|
|
||||||
|
if (is_canonical())
|
||||||
{
|
{
|
||||||
if (g_temp_input.try_pop().has_value())
|
if (key == m_settings.c_cc[VERASE])
|
||||||
{
|
{
|
||||||
if (g_echo) TextConsole::putwchar(L'\b');
|
auto maybe_char = m_line_buffer.try_pop();
|
||||||
|
if (maybe_char.has_value() && maybe_char.value())
|
||||||
|
{
|
||||||
|
if ((m_settings.c_lflag & ECHO) && (m_settings.c_lflag & ECHOE))
|
||||||
|
{
|
||||||
|
TextConsole::putwchar(L'\b');
|
||||||
|
if (_iscntrl(maybe_char.value())) TextConsole::putwchar(L'\b');
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((m_settings.c_lflag & ECHOE)) return;
|
||||||
|
else
|
||||||
|
is_special_character = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
if (key == m_settings.c_cc[VEOF])
|
||||||
}
|
|
||||||
|
|
||||||
// Ctrl+D
|
|
||||||
if (key == 'd' && (Keyboard::modifiers() == Keyboard::LeftControl))
|
|
||||||
{
|
|
||||||
if (g_temp_input.size() == 0) g_eof = true;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (key == 'c' && (Keyboard::modifiers() == Keyboard::LeftControl))
|
|
||||||
{
|
|
||||||
g_temp_input.clear();
|
|
||||||
|
|
||||||
if (g_echo) TextConsole::wprintln(L"^C");
|
|
||||||
|
|
||||||
if (g_foreground_process_group.has_value())
|
|
||||||
{
|
{
|
||||||
Scheduler::for_each_in_process_group(g_foreground_process_group.value(), [](Thread* thread) {
|
m_input_buffer.append_data(m_line_buffer.data(), m_line_buffer.size());
|
||||||
thread->send_signal(SIGINT);
|
m_line_buffer.clear();
|
||||||
return true;
|
|
||||||
});
|
m_may_read_without_blocking = true;
|
||||||
|
is_special_character = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
if (m_settings.c_lflag & ISIG)
|
||||||
|
{
|
||||||
|
if (key == m_settings.c_cc[VINTR])
|
||||||
|
{
|
||||||
|
if (!(m_settings.c_lflag & NOFLSH)) m_line_buffer.clear();
|
||||||
|
|
||||||
|
if (m_foreground_process_group.has_value())
|
||||||
|
{
|
||||||
|
Scheduler::for_each_in_process_group(m_foreground_process_group.value(), [](Thread* thread) {
|
||||||
|
thread->send_signal(SIGINT);
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
is_special_character = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (key == m_settings.c_cc[VQUIT])
|
||||||
|
{
|
||||||
|
if (!(m_settings.c_lflag & NOFLSH)) m_line_buffer.clear();
|
||||||
|
|
||||||
|
if (m_foreground_process_group.has_value())
|
||||||
|
{
|
||||||
|
Scheduler::for_each_in_process_group(m_foreground_process_group.value(), [](Thread* thread) {
|
||||||
|
thread->send_signal(SIGQUIT);
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
is_special_character = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (key == 'e' && (Keyboard::modifiers() == (Keyboard::LeftAlt | Keyboard::LeftControl)))
|
if (!is_special_character)
|
||||||
{
|
{
|
||||||
Scheduler::dump_state();
|
if (is_canonical())
|
||||||
return;
|
{
|
||||||
|
m_line_buffer.try_append((u8)key);
|
||||||
|
|
||||||
|
if (key == '\n')
|
||||||
|
{
|
||||||
|
m_input_buffer.append_data(m_line_buffer.data(), m_line_buffer.size());
|
||||||
|
m_line_buffer.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
m_input_buffer.append_data((u8*)&key, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (key == 'm' && (Keyboard::modifiers() == (Keyboard::LeftAlt | Keyboard::LeftControl)))
|
if (!(m_settings.c_lflag & ECHO)) return;
|
||||||
|
|
||||||
|
if (_iscntrl(key))
|
||||||
{
|
{
|
||||||
kinfoln("Total memory: %s", to_dynamic_unit(MemoryManager::total()).release_value().chars());
|
if (m_settings.c_lflag & ECHOCTL)
|
||||||
kinfoln("Free memory: %s", to_dynamic_unit(MemoryManager::free()).release_value().chars());
|
{
|
||||||
kinfoln("Used memory: %s", to_dynamic_unit(MemoryManager::used()).release_value().chars());
|
bool should_echo = true;
|
||||||
kinfoln("Reserved memory: %s", to_dynamic_unit(MemoryManager::reserved()).release_value().chars());
|
if (key == '\n' || key == '\0' || key == m_settings.c_cc[VEOF]) should_echo = false;
|
||||||
return;
|
|
||||||
|
if (should_echo)
|
||||||
|
{
|
||||||
|
char caret_notation[3] = { '^', '\0', '\0' };
|
||||||
|
if (key == 0x7f) caret_notation[1] = '?';
|
||||||
|
else
|
||||||
|
caret_notation[1] = key + 0x40;
|
||||||
|
|
||||||
|
TextConsole::print(caret_notation);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
TextConsole::putchar(key);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
if (key == 'h' && (Keyboard::modifiers() == (Keyboard::LeftAlt | Keyboard::LeftControl)))
|
TextConsole::putchar(key);
|
||||||
{
|
|
||||||
dump_heap_usage();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
g_temp_input.try_append((u8)key);
|
|
||||||
|
|
||||||
if (key == '\n')
|
|
||||||
{
|
|
||||||
g_console_input.append_data(g_temp_input.data(), g_temp_input.size());
|
|
||||||
g_temp_input.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!g_echo) return;
|
|
||||||
TextConsole::putchar(key);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<u64> ConsoleDevice::ioctl(int request, void* arg)
|
Result<u64> ConsoleDevice::ioctl(int request, void* arg)
|
||||||
@ -153,27 +197,13 @@ Result<u64> ConsoleDevice::ioctl(int request, void* arg)
|
|||||||
switch (request)
|
switch (request)
|
||||||
{
|
{
|
||||||
case TCGETS: {
|
case TCGETS: {
|
||||||
struct termios tc
|
|
||||||
{
|
|
||||||
.c_lflag = 0
|
|
||||||
};
|
|
||||||
|
|
||||||
if (g_echo) tc.c_lflag |= ECHO;
|
return MemoryManager::copy_to_user_typed((struct termios*)arg, &m_settings) ? 0 : err(EFAULT);
|
||||||
if (g_stop_background_output) tc.c_lflag |= TOSTOP;
|
|
||||||
return MemoryManager::copy_to_user_typed((struct termios*)arg, &tc) ? 0 : err(EFAULT);
|
|
||||||
}
|
}
|
||||||
case TCSETS: {
|
case TCSETS: {
|
||||||
TRY(handle_background_process_group(true, SIGTTOU));
|
TRY(handle_background_process_group(true, SIGTTOU));
|
||||||
|
|
||||||
struct termios tc;
|
if (!MemoryManager::copy_from_user_typed((const struct termios*)arg, &m_settings)) return err(EFAULT);
|
||||||
if (!MemoryManager::copy_from_user_typed((const struct termios*)arg, &tc)) return err(EFAULT);
|
|
||||||
if (tc.c_lflag & ECHO) g_echo = true;
|
|
||||||
else
|
|
||||||
g_echo = false;
|
|
||||||
|
|
||||||
if (tc.c_lflag & TOSTOP) g_stop_background_output = true;
|
|
||||||
else
|
|
||||||
g_stop_background_output = false;
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -190,11 +220,11 @@ Result<u64> ConsoleDevice::ioctl(int request, void* arg)
|
|||||||
});
|
});
|
||||||
if (!pgid_exists) return err(EPERM);
|
if (!pgid_exists) return err(EPERM);
|
||||||
|
|
||||||
g_foreground_process_group = pgid;
|
m_foreground_process_group = pgid;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
case TIOCGPGRP: {
|
case TIOCGPGRP: {
|
||||||
pid_t pgid = g_foreground_process_group.value_or((pid_t)next_thread_id());
|
pid_t pgid = m_foreground_process_group.value_or((pid_t)next_thread_id());
|
||||||
if (!MemoryManager::copy_to_user_typed((pid_t*)arg, &pgid)) return err(EFAULT);
|
if (!MemoryManager::copy_to_user_typed((pid_t*)arg, &pgid)) return err(EFAULT);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
#include "arch/Keyboard.h"
|
||||||
#include "fs/devices/DeviceRegistry.h"
|
#include "fs/devices/DeviceRegistry.h"
|
||||||
|
#include <bits/termios.h>
|
||||||
|
#include <luna/Buffer.h>
|
||||||
|
|
||||||
class ConsoleDevice : public Device
|
class ConsoleDevice : public Device
|
||||||
{
|
{
|
||||||
@ -11,7 +14,7 @@ class ConsoleDevice : public Device
|
|||||||
|
|
||||||
Result<usize> write(const u8*, usize, usize) override;
|
Result<usize> write(const u8*, usize, usize) override;
|
||||||
|
|
||||||
static void did_press_key(char key);
|
static void did_press_or_release_key(u8 scancode);
|
||||||
|
|
||||||
bool blocking() const override;
|
bool blocking() const override;
|
||||||
|
|
||||||
@ -28,4 +31,24 @@ class ConsoleDevice : public Device
|
|||||||
}
|
}
|
||||||
|
|
||||||
virtual ~ConsoleDevice() = default;
|
virtual ~ConsoleDevice() = default;
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct termios m_settings;
|
||||||
|
mutable Buffer m_input_buffer;
|
||||||
|
Option<pid_t> m_foreground_process_group {};
|
||||||
|
Vector<u8> m_line_buffer;
|
||||||
|
mutable Keyboard::KeyboardState m_kb_state;
|
||||||
|
|
||||||
|
static Vector<SharedPtr<ConsoleDevice>> m_console_devices;
|
||||||
|
|
||||||
|
void process_key_event(u8 scancode);
|
||||||
|
|
||||||
|
mutable bool m_may_read_without_blocking { false };
|
||||||
|
|
||||||
|
inline bool is_canonical() const
|
||||||
|
{
|
||||||
|
return m_settings.c_lflag & ICANON;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<void> handle_background_process_group(bool can_succeed, int signo) const;
|
||||||
};
|
};
|
||||||
|
@ -101,6 +101,10 @@ namespace TextConsole
|
|||||||
if (should_scroll()) scroll();
|
if (should_scroll()) scroll();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case L'\t': {
|
||||||
|
wprint(L" ");
|
||||||
|
break;
|
||||||
|
}
|
||||||
case L'\r': g_x_position = 0; break;
|
case L'\r': g_x_position = 0; break;
|
||||||
case L'\b':
|
case L'\b':
|
||||||
if (g_x_position != 0)
|
if (g_x_position != 0)
|
||||||
@ -210,11 +214,11 @@ namespace TextConsole
|
|||||||
|
|
||||||
u16 rows()
|
u16 rows()
|
||||||
{
|
{
|
||||||
return Framebuffer::height() / FONT_HEIGHT;
|
return (u16)Framebuffer::height() / FONT_HEIGHT;
|
||||||
}
|
}
|
||||||
|
|
||||||
u16 cols()
|
u16 cols()
|
||||||
{
|
{
|
||||||
return Framebuffer::width() / FONT_WIDTH;
|
return (u16)Framebuffer::width() / FONT_WIDTH;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
#ifndef _BITS_FIXED_SIZE_TYPES_H
|
#ifndef _BITS_FIXED_SIZE_TYPES_H
|
||||||
#define _BITS_FIXED_SIZE_TYPES_H
|
#define _BITS_FIXED_SIZE_TYPES_H
|
||||||
|
|
||||||
#if !defined(_SYS_TYPES_H) && !defined(_BITS_SETJMP_TYPES_H) && !defined(_BITS_MAKEDEV_H)
|
#if !defined(_SYS_TYPES_H) && !defined(_BITS_SETJMP_TYPES_H) && !defined(_BITS_MAKEDEV_H) && !defined(_BITS_TERMIOS_H)
|
||||||
#error "Never include bits/fixed-size-types.h, use the standard <stdint.h> header instead."
|
#error "Never include bits/fixed-size-types.h, use the standard <stdint.h> header instead."
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -3,25 +3,41 @@
|
|||||||
#ifndef _BITS_TERMIOS_H
|
#ifndef _BITS_TERMIOS_H
|
||||||
#define _BITS_TERMIOS_H
|
#define _BITS_TERMIOS_H
|
||||||
|
|
||||||
|
#include <bits/fixed-size-types.h>
|
||||||
|
|
||||||
typedef long tcflag_t;
|
typedef long tcflag_t;
|
||||||
|
typedef char cc_t;
|
||||||
|
|
||||||
|
#define NCCS 4
|
||||||
|
|
||||||
|
#define VEOF 0
|
||||||
|
#define VERASE 1
|
||||||
|
#define VINTR 2
|
||||||
|
#define VQUIT 3
|
||||||
|
|
||||||
// VERY incomplete termios structure.
|
// VERY incomplete termios structure.
|
||||||
struct termios
|
struct termios
|
||||||
{
|
{
|
||||||
tcflag_t c_lflag;
|
tcflag_t c_lflag;
|
||||||
|
cc_t c_cc[NCCS];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct winsize
|
struct winsize
|
||||||
{
|
{
|
||||||
u16 ws_row;
|
__u16_t ws_row;
|
||||||
u16 ws_col;
|
__u16_t ws_col;
|
||||||
u16 ws_xpixel;
|
__u16_t ws_xpixel;
|
||||||
u16 ws_ypixel;
|
__u16_t ws_ypixel;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Values for c_lflag.
|
// Values for c_lflag.
|
||||||
#define ECHO 1
|
#define ECHO 1
|
||||||
#define TOSTOP 2
|
#define TOSTOP 2
|
||||||
|
#define ECHOCTL 4
|
||||||
|
#define ISIG 8
|
||||||
|
#define ICANON 16
|
||||||
|
#define ECHOE 32
|
||||||
|
#define NOFLSH 64
|
||||||
|
|
||||||
// termios ioctl() requests.
|
// termios ioctl() requests.
|
||||||
#define TCGETS 0
|
#define TCGETS 0
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
|
|
||||||
#define _POSIX_CHOWN_RESTRICTED 200112L
|
#define _POSIX_CHOWN_RESTRICTED 200112L
|
||||||
#define _POSIX_SHELL 200112L
|
#define _POSIX_SHELL 200112L
|
||||||
|
#define _POSIX_VDISABLE (-2)
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C"
|
extern "C"
|
||||||
|
Loading…
Reference in New Issue
Block a user