aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--TUI/unix.jai136
-rw-r--r--TUI/windows.jai64
2 files changed, 132 insertions, 68 deletions
diff --git a/TUI/unix.jai b/TUI/unix.jai
index 6bcf13a..20d1a2a 100644
--- a/TUI/unix.jai
+++ b/TUI/unix.jai
@@ -14,93 +14,158 @@
// Input modes.
+ // https://elixir.bootlin.com/glibc/latest/source/bits/termios.h
Input_Modes :: enum_flags u32 {
IGNBRK; // Ignore break condition.
BRKINT; // Signal interrupt on break.
IGNPAR; // Ignore characters with parity errors.
PARMRK; // Mark parity and framing errors.
+
INPCK; // Enable input parity check.
ISTRIP; // Strip 8th bit off characters.
INLCR; // Map NL to CR on input.
IGNCR; // Ignore CR.
+
ICRNL; // Map CR to NL on input.
IXON; // Enable start/stop output control.
IXOFF; // Enable start/stop input control.
IXANY; // Any character will restart after stop.
- __NOT_USED__;
+
+ _1000_;
IMAXBEL; // Ring bell when input queue is full.
IUCLC; // Translate upper case input to lower case.
+ _8000_;
+ }
+
+ // Output modes.
+ // https://elixir.bootlin.com/glibc/latest/source/bits/termios.h
+ Output_Modes :: enum_flags u32 {
+ OPOST; // Perform output processing.
+ ONLCR; // Map NL to CR-NL on output.
+ _UNUSED_0004_;
+ ONOEOT; // Discard EOT (^D) on output.
+ OCRNL; // Map CR to NL.
+ ONOCR; // Discard CR's when on column 0.
+ ONLRET; // Move to column 0 on NL.
+ _UNUSED_0080_;
}
+ // Control modes.
+ // https://elixir.bootlin.com/glibc/latest/source/bits/termios.h
+ Control_Modes :: enum_flags u32 {
+ CIGNORE; // Ignore these control flags.
+ _0002_;
+ _0004_;
+ _0008_;
+
+ _0010_;
+ _0020_;
+ _0040_;
+ _0080_;
+
+ _0100_;
+ _0200_;
+ CSTOPB; // Two stop bits instead of one.
+ CREAD; // Enable receiver.
+
+ PARENB; // Parity enable.
+ PARODD; // Odd parity instead of even.
+ HUPCL; // Hang up on last close.
+ CLOCAL; // Ignore modem status lines.
+
+ CRTSCTS; // RTS/CTS flow control.
+ CDTRCTS; // DTR/CTS flow control.
+ _0004_0000_;
+ _0008_0000_;
+
+ MDMBUF; // DTR/DCD flow control.
+ }
+
+ CHWFLOW :Control_Modes : (.MDMBUF | .CRTSCTS | .CDTRCTS); // All types of flow control.
+ CS5 :Control_Modes : 0x0000; // 5 bits per byte.
+ CS6 :Control_Modes : 0x0100; // 6 bits per byte.
+ CS7 :Control_Modes : 0x0200; // 7 bits per byte.
+ CS8 :Control_Modes : CS6|CS7; // 8 bits per byte.
+ CSIZE :Control_Modes : CS5|CS6|CS7|CS8; // Number of bits per byte (mask).
+
// Local modes.
+ // https://elixir.bootlin.com/glibc/latest/source/bits/termios.h
Local_Modes :: enum_flags u32 {
ECHOKE; // Visual erase for KILL.
ECHOE; // Visual erase for ERASE.
ECHOK; // Echo NL after KILL.
ECHO; // Enable echo.
+
ECHONL; // Echo NL even if ECHO is off.
ECHOPRT; // Hardcopy visual erase.
ECHOCTL; // Echo control characters as ^X.
ISIG; // Enable signals.
+
ICANON; // Do erase and kill processing.
ALTWERASE; // Alternate WERASE algorithm.
IEXTEN; // Enable DISCARD and LNEXT.
EXTPROC; // External processing.
+
+ _1000_;
+ _2000_;
+ _4000_;
+ _8000_;
+
+ _0001_0000_;
+ _0002_0000_;
+ // TODO Maybe reduce the amount of unused flags by setting the value when there are holes on the table.
+ // TOSTOP :: 0x0004_0000; // Send SIGTTOU for background output.
TOSTOP; // Send SIGTTOU for background output.
FLUSHO; // Output being flushed (state).
+
XCASE; // Canonical upper/lower case.
NOKERNINFO; // Disable VSTATUS.
+ _0040_0000_;
+ _0080_0000_;
+
+ _0100_0000_;
PENDIN; // Retype pending input (state).
+ _0400_0000_;
NOFLSH; // Disable flush after interrupt.
-
}
-
+
Terminal_IO_Mode :: struct {
- c_iflag : u32; // Input mode flags.
- c_oflag : u32; // Output mode flags.
- c_cflag : u32; // Control modes flags.
- c_lflag : u32; // Local modes flags.
- c_line : u8; // Line discipline.
- c_cc : [32]u8; // Control characters.
+ c_iflag : Input_Modes; // Input mode flags.
+ c_oflag : Output_Modes; // Output mode flags.
+ c_cflag : Control_Modes; // Control modes flags.
+ c_lflag : Local_Modes; // Local modes flags.
+ c_line : u8; // Line discipline.
+ c_cc : [32]u8; // Control characters.
c_ispeed : u32; // Input speed (baud rates).
c_ospeed : u32; // Output speed (baud rates).
}
- initial_tio_mode : Terminal_IO_Mode;
+ initial_tio_mode: Terminal_IO_Mode;
default_tio_mode: Terminal_IO_Mode;
- blocking_tio_mode: Terminal_IO_Mode;
- unblocking_tio_mode: Terminal_IO_Mode;
+ human_tio_mode: Terminal_IO_Mode;
#scope_export
OS_prepare_terminal :: () {
- // TODO Required to do unlocking input.
tcgetattr(STDIN_FILENO, *initial_tio_mode);
- default_tio_mode := initial_tio_mode;
- default_tio_mode.c_iflag &= 0xFFFFFA14;// ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON);
- default_tio_mode.c_oflag &= 0xFFFFFFFE;// ~OPOST;
- default_tio_mode.c_lflag &= 0xFFFF7FB4;// ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
- default_tio_mode.c_cflag &= 0xFFFFFECF;// ~(CSIZE | PARENB);
- default_tio_mode.c_cflag |= 0x00000030; // TODO WHAT IS THIS?
+ default_tio_mode = initial_tio_mode;
+ default_tio_mode.c_iflag &= ~(.IGNBRK | .BRKINT | .PARMRK | .ISTRIP | .INLCR | .IGNCR | .ICRNL | .IXOFF);
+ default_tio_mode.c_oflag &= ~(.OPOST);
+ default_tio_mode.c_cflag &= ~(CSIZE | .PARENB);
+ default_tio_mode.c_lflag &= ~(.ECHOCTL |.ECHO | .ECHOE | .ECHOKE);
- blocking_tio_mode = default_tio_mode;
- blocking_tio_mode.c_iflag |= xx cast(Input_Modes)(.IXOFF | .ICRNL);
- blocking_tio_mode.c_lflag |= xx cast(Local_Modes)(.NOKERNINFO | .ECHO | .ECHOE | .ECHOKE);
-
- unblocking_tio_mode = default_tio_mode;
- iflags: Input_Modes = (.IGNBRK | .BRKINT | .PARMRK | .ISTRIP | .INLCR | .IGNCR | .ICRNL | .IXON);
- unblocking_tio_mode.c_iflag &= xx ~(iflags);
- lflags: Local_Modes = (.ECHO | .ECHONL | .ICANON | .IEXTEN);
- unblocking_tio_mode.c_lflag &= xx ~lflags;
+ human_tio_mode = default_tio_mode;
+ human_tio_mode.c_iflag |= (.IXOFF | .ICRNL);
+ human_tio_mode.c_lflag |= (.NOKERNINFO | .ECHO | .ECHOE | .ECHOKE);
tcsetattr(STDIN_FILENO, 0, *default_tio_mode);
}
OS_reset_terminal :: () {
- tcsetattr(STDIN_FILENO, 0, *initial_tio_mode); // return echo
+ tcsetattr(STDIN_FILENO, 0, *initial_tio_mode);
}
OS_get_terminal_size :: () -> rows: int, columns: int {
@@ -125,19 +190,16 @@ OS_get_terminal_size :: () -> rows: int, columns: int {
return rows, columns;
}
-// TODO Maybe we should use a NON-BLOCKING state by default... and only change to blocking when performing a HUMAN read...?
-
OS_set_input_mode :: (mode: Input_Mode) {
+ tio_mode: *Terminal_IO_Mode = ---;
if mode == {
case .HUMAN;
- tcsetattr(STDIN_FILENO, 0, *blocking_tio_mode);
- // TODO get_error_value_and_string :: () -> (error_code: OS_Error_Code, description: string)
- case .MACHINE;
- tcsetattr(STDIN_FILENO, 0, *unblocking_tio_mode);
- // TODO get_error_value_and_string :: () -> (error_code: OS_Error_Code, description: string)
+ tio_mode = *human_tio_mode;
case;
- // TODO ERROR
+ tio_mode = *default_tio_mode;
}
+ tcsetattr(STDIN_FILENO, 0, tio_mode);
+ // TODO get_error_value_and_string :: () -> (error_code: OS_Error_Code, description: string)
}
OS_read_input :: (buffer: *u8, bytes_to_read: s64) -> bytes_read: s64, error: bool = false, error_message: string = "" {
diff --git a/TUI/windows.jai b/TUI/windows.jai
index 036b33b..68c2a1d 100644
--- a/TUI/windows.jai
+++ b/TUI/windows.jai
@@ -26,35 +26,36 @@
// https://learn.microsoft.com/en-us/windows/win32/api/errhandlingapi/nf-errhandlingapi-getlasterror
GetLastError :: () -> s32 #foreign kernel32;
- ENABLE_VIRTUAL_TERMINAL_INPUT :: 0x0200;
-
- ENABLE_PROCESSED_OUTPUT :: 0x0001;
- ENABLE_WRAP_AT_EOL_OUTPUT :: 0x0002;
- ENABLE_VIRTUAL_TERMINAL_PROCESSING :: 0x0004;
- DISABLE_NEWLINE_AUTO_RETURN :: 0x0008;
- ENABLE_LVB_GRID_WORLDWIDE :: 0x0010;
-
-
+
// https://learn.microsoft.com/en-us/windows/console/setconsolemode
- Console_Mode :: enum_flags u32 {
+ Console_Input_Mode :: enum_flags u32 {
_UNUSED_0001_;
- ENABLE_LINE_INPUT; // If enable, ReadFile or ReadConsole function return on CR; otherwise they return when one or more characters are available.
- ENABLE_ECHO_INPUT; // Echoes input on screen. Only available if ENABLE_LINE_INPUT is set.
+ ENABLE_LINE_INPUT; // If enable, ReadFile or ReadConsole function return on CR; otherwise they return when one or more characters are available.
+ ENABLE_ECHO_INPUT; // Echoes input on screen. Only available if ENABLE_LINE_INPUT is set.
_UNUSED_0008_;
- ENABLE_MOUSE_INPUT; //
- ENABLE_INSERT_MODE; // If enabled, text entered will be inserted at the current cursor location and all text following that location will not be overwritten. When disabled, all following text will be overwritten.
- _UNSED_0040_;
- _UNSED_0080_;
- _UNSED_0100_;
- ENABLE_VIRTUAL_TERMINAL_INPUT; //
- _UNSED_0400_;
- _UNSED_0800_;
- _UNSED_1000_;
- _UNSED_2000_;
- _UNSED_4000_;
- _UNSED_8000_;
+ ENABLE_MOUSE_INPUT; //
+ ENABLE_INSERT_MODE; // If enabled, text entered will be inserted at the current cursor location and all text following that location will not be overwritten. When disabled, all following text will be overwritten.
+ _UNUSED_0040_;
+ _UNUSED_0080_;
+ _UNUSED_0100_;
+ ENABLE_VIRTUAL_TERMINAL_INPUT; //
+ _UNUSED_0400_;
+ _UNUSED_0800_;
+ }
+
+ // https://learn.microsoft.com/en-us/windows/console/setconsolemode
+ Console_Output_Mode :: enum_flags u32 {
+ ENABLE_PROCESSED_OUTPUT; //
+ ENABLE_WRAP_AT_EOL_OUTPUT; //
+ ENABLE_VIRTUAL_TERMINAL_PROCESSING; //
+ DISABLE_NEWLINE_AUTO_RETURN; //
+ ENABLE_LVB_GRID_WORLDWIDE; //
+ _UNUSED_0020_;
+ _UNUSED_0040_;
+ _UNUSED_0080_;
}
+
// https://learn.microsoft.com/en-us/windows/win32/winprog/windows-data-types
SHORT :: s16;
WORD :: u16;
@@ -75,7 +76,6 @@
CONSOLE_SCREEN_BUFFER_INFO :: struct {
dwSize : COORD;
dwCursorPosition : COORD;
-
wAttributes : WORD;
srWindow : SMALL_RECT;
dwMaximumWindowSize : COORD;
@@ -84,13 +84,13 @@
stdin: HANDLE;
initial_stdin_mode: u32;
- default_stdin_mode: Console_Mode;
- blocking_stdin_mode: Console_Mode;
- unblocking_stdin_mode: Console_Mode;
+ default_stdin_mode: Console_Input_Mode;
+ blocking_stdin_mode: Console_Input_Mode;
+ unblocking_stdin_mode: Console_Input_Mode;
stdout: HANDLE;
initial_stdout_mode: u32;
- default_stdout_mode: Console_Mode;
+ default_stdout_mode: Console_Output_Mode;
#scope_export
@@ -109,7 +109,7 @@ OS_prepare_terminal :: () {
print("Failed to get input mode.", to_standard_error = true);
return;
}
- default_stdin_mode = (cast(Console_Mode) initial_stdin_mode) | .ENABLE_VIRTUAL_TERMINAL_INPUT;
+ default_stdin_mode = (cast(Console_Input_Mode) initial_stdin_mode) | .ENABLE_VIRTUAL_TERMINAL_INPUT;
blocking_stdin_mode = default_stdin_mode | .ENABLE_LINE_INPUT | .ENABLE_ECHO_INPUT;
unblocking_stdin_mode = default_stdin_mode & ~.ENABLE_LINE_INPUT & ~.ENABLE_ECHO_INPUT;
@@ -128,7 +128,7 @@ OS_prepare_terminal :: () {
print("Failed to get output mode.", to_standard_error = true);
return;
}
- default_stdout_mode = (cast(Console_Mode) initial_stdout_mode) | ENABLE_PROCESSED_OUTPUT| ENABLE_VIRTUAL_TERMINAL_PROCESSING;
+ default_stdout_mode = (cast(Console_Output_Mode) initial_stdout_mode) | .ENABLE_PROCESSED_OUTPUT| .ENABLE_VIRTUAL_TERMINAL_PROCESSING;
if SetConsoleMode(stdout, xx default_stdout_mode) == false {
print("Failed to set output mode: %.", GetLastError(), to_standard_error = true);
@@ -157,6 +157,8 @@ OS_get_terminal_size :: () -> rows: int, columns: int {
return rows, columns;
}
+// TODO Maybe we should use a NON-BLOCKING state by default... and only change to blocking when performing a HUMAN read...?
+
OS_set_input_mode :: (mode: Input_Mode) {
if mode == {
case .HUMAN;