diff options
Diffstat (limited to 'TUI/windows.jai')
| -rw-r--r-- | TUI/windows.jai | 140 |
1 files changed, 87 insertions, 53 deletions
diff --git a/TUI/windows.jai b/TUI/windows.jai index ed8c996..f704262 100644 --- a/TUI/windows.jai +++ b/TUI/windows.jai @@ -4,33 +4,42 @@ #import "System"; #import "Windows"; -// https://learn.microsoft.com/en-us/windows/console/console-virtual-terminal-sequences -// https://learn.microsoft.com/en-us/windows/console/console-virtual-terminal-sequences#designate-character-set -// https://github.com/MicrosoftDocs/Console-Docs/blob/main/docs/console-virtual-terminal-sequences.md - + // https://learn.microsoft.com/windows/win32/winprog/windows-data-types + LPVOID :: *void; + LPDWORD :: *s32; + BOOL :: bool; + SHORT :: s16; + WORD :: u16; + DWORD :: s32; +// https://learn.microsoft.com/windows/console/console-virtual-terminal-sequences +// https://learn.microsoft.com/windows/console/console-virtual-terminal-sequences#designate-character-set +// https://github.com/MicrosoftDocs/Console-Docs/blob/main/docs/console-virtual-terminal-sequences.md - kernel32 :: #system_library "kernel32"; + kernel32 :: #system_library "kernel32"; - // https://learn.microsoft.com/en-us/windows/console/getconsolescreenbufferinfo + // https://learn.microsoft.com/windows/console/getconsolescreenbufferinfo GetConsoleScreenBufferInfo :: (hConsoleOutput: HANDLE, lpConsoleScreenBufferInfo: *CONSOLE_SCREEN_BUFFER_INFO) -> bool #foreign kernel32; - // https://learn.microsoft.com/en-us/windows/console/readconsole - ReadConsoleA :: (hConsoleInput: HANDLE, lpBuffer: *u8, nNumberOfCharsToRead: s32, lpNumberOfCharsRead: *s32, pInputControl := *void) -> bool #foreign kernel32; + // https://learn.microsoft.com/windows/console/readconsole + ReadConsoleA :: (hConsoleInput: HANDLE, lpBuffer: LPVOID, nNumberOfCharsToRead: DWORD, lpNumberOfCharsRead: LPVOID, pInputControl := LPVOID) -> bool #foreign kernel32; - // https://learn.microsoft.com/en-us/windows/console/getconsolemode - GetConsoleMode :: (hConsoleHandle: HANDLE, lpMode: *u32) -> bool #foreign kernel32; + // https://learn.microsoft.com/windows/console/getconsolemode + GetConsoleMode :: (hConsoleHandle: HANDLE, lpMode: *DWORD) -> BOOL #foreign kernel32; - // https://learn.microsoft.com/en-us/windows/console/setconsolemode - SetConsoleMode :: (hConsoleHandle: HANDLE, dwMode: u32) -> bool #foreign kernel32; + // https://learn.microsoft.com/windows/console/setconsolemode + SetConsoleMode :: (hConsoleHandle: HANDLE, dwMode: DWORD) -> BOOL #foreign kernel32; - // https://learn.microsoft.com/en-us/windows/win32/api/errhandlingapi/nf-errhandlingapi-getlasterror + // https://learn.microsoft.com/windows/win32/api/errhandlingapi/nf-errhandlingapi-getlasterror GetLastError :: () -> s32 #foreign kernel32; + // https://learn.microsoft.com/windows/win32/api/synchapi/nf-synchapi-waitforsingleobjectex + WaitForSingleObjectEx :: (hHandle: HANDLE, dwMilliseconds: DWORD, bAlertable: BOOL) -> s32 #foreign kernel32; // https://learn.microsoft.com/en-us/windows/console/setconsolemode + // https://learn.microsoft.com/en-us/windows/console/high-level-console-modes Console_Input_Mode :: enum_flags u32 { - _UNUSED_0001_; + ENABLE_PROCESSED_INPUT; // If enable, control keys (Ctrl+C, Backspace, ...) are processed by the system. 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_; @@ -45,6 +54,7 @@ } // https://learn.microsoft.com/en-us/windows/console/setconsolemode + // https://learn.microsoft.com/en-us/windows/console/high-level-console-modes Console_Output_Mode :: enum_flags u32 { ENABLE_PROCESSED_OUTPUT; // ENABLE_WRAP_AT_EOL_OUTPUT; // @@ -56,12 +66,6 @@ _UNUSED_0080_; } - - // https://learn.microsoft.com/en-us/windows/win32/winprog/windows-data-types - SHORT :: s16; - WORD :: u16; - DWORD :: s32; - COORD :: struct { X : SHORT; Y : SHORT; @@ -85,36 +89,69 @@ stdin: HANDLE; initial_stdin_mode: u32; - default_stdin_mode: Console_Input_Mode; - blocking_stdin_mode: Console_Input_Mode; - unblocking_stdin_mode: Console_Input_Mode; + raw_stdin_mode: Console_Input_Mode; stdout: HANDLE; initial_stdout_mode: u32; - default_stdout_mode: Console_Output_Mode; + raw_stdout_mode: Console_Output_Mode; -#scope_export +//////////////////////////////////////////////////////////////////////////////// +// Resize detection -OS_prepare_terminal :: () { - print("TODO TUI\n", to_standard_error = true); +resize_handler :: (signal_code : s32) #c_call { + /* TODO + Try to implement using: + https://learn.microsoft.com/en-us/windows/console/reading-input-buffer-events + https://learn.microsoft.com/en-us/windows/console/readconsoleinput + https://learn.microsoft.com/en-us/windows/console/getnumberofconsoleinputevents + */ + new_context : Context; + push_context new_context { + if signal_code != SIGWINCH then return; + atomic_swap(*was_resized, true); + } +} +prepare_resize_handler :: () { + /* TODO + sa : sigaction_t; + sa.sa_handler = resize_handler; + sigemptyset(*(sa.sa_mask)); + sa.sa_flags = SA_RESTART; + sigaction(SIGWINCH, *sa, null); + */ +} +restore_resize_handler :: () { + /* TODO + sa : sigaction_t; + sa.sa_handler = SIG_DFL; + sigaction(SIGWINCH, null, *sa); + */ +} + +//////////////////////////////////////////////////////////////////////////////// + +#scope_export + +OS_prepare_terminal :: () { + // stdin stdin = GetStdHandle(STD_INPUT_HANDLE); if stdin == INVALID_HANDLE_VALUE { print("Invalid input handler.", to_standard_error = true); return; } - if GetConsoleMode(stdin, *initial_stdin_mode) == false { + if xx GetConsoleMode(stdin, *initial_stdin_mode) == false { print("Failed to get input mode.", to_standard_error = true); return; } - 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; + raw_stdin_mode = (cast(Console_Input_Mode) initial_stdin_mode); + raw_stdin_mode |= (.ENABLE_VIRTUAL_TERMINAL_INPUT); + raw_stdin_mode &= ~(.ENABLE_LINE_INPUT | .ENABLE_PROCESSED_INPUT | .ENABLE_ECHO_INPUT); - if SetConsoleMode(stdin, xx default_stdin_mode) == false { + if SetConsoleMode(stdin, xx raw_stdin_mode) == false { print("Failed to set input mode: %.", GetLastError(), to_standard_error = true); return; } @@ -125,24 +162,25 @@ OS_prepare_terminal :: () { print("Invalid output handler.", to_standard_error = true); return; } - if GetConsoleMode(stdout, *initial_stdout_mode) == false { + if xx GetConsoleMode(stdout, *initial_stdout_mode) == false { print("Failed to get output mode.", to_standard_error = true); return; } - default_stdout_mode = (cast(Console_Output_Mode) initial_stdout_mode) | .ENABLE_PROCESSED_OUTPUT| .ENABLE_VIRTUAL_TERMINAL_PROCESSING; + raw_stdout_mode = (cast(Console_Output_Mode) initial_stdout_mode); + raw_stdout_mode |= (.ENABLE_VIRTUAL_TERMINAL_PROCESSING | .ENABLE_PROCESSED_OUTPUT | .ENABLE_WRAP_AT_EOL_OUTPUT); - if SetConsoleMode(stdout, xx default_stdout_mode) == false { + if SetConsoleMode(stdout, xx raw_stdout_mode) == false { print("Failed to set output mode: %.", GetLastError(), to_standard_error = true); return; } } OS_reset_terminal :: () { - if SetConsoleMode(stdin, initial_stdin_mode) == false { + if xx SetConsoleMode(stdin, initial_stdin_mode) == false { print("Failed to reset input mode: %.", GetLastError(), to_standard_error = true); return; } - if SetConsoleMode(stdout, initial_stdout_mode) == false { + if xx SetConsoleMode(stdout, initial_stdout_mode) == false { print("Failed to reset output mode: %.", GetLastError(), to_standard_error = true); return; } @@ -157,16 +195,6 @@ OS_flush_input :: inline () { */ } -OS_get_terminal_size :: () -> rows: int, columns: int { - - ScreenBufferInfo: CONSOLE_SCREEN_BUFFER_INFO; - GetConsoleScreenBufferInfo(stdout, *ScreenBufferInfo); - columns := ScreenBufferInfo.srWindow.Right - ScreenBufferInfo.srWindow.Left + 1; - rows := ScreenBufferInfo.srWindow.Bottom - ScreenBufferInfo.srWindow.Top + 1; - - return rows, columns; -} - OS_read_input :: (buffer: *u8, bytes_to_read: s64) -> bytes_read: s64, error: bool = false, error_message: string = "" { assert(bytes_to_read <= 0x7fff_ffff, "The Windows API only allows to read up to s32 bytes from the standard input."); bytes_read: s32; @@ -181,14 +209,20 @@ OS_read_input :: (buffer: *u8, bytes_to_read: s64) -> bytes_read: s64, error: bo OS_wait_for_input :: (timeout_milliseconds: s32) -> is_input_available: bool { /* TODO Try to implement using: - https://learn.microsoft.com/en-us/windows/console/reading-input-buffer-events - https://learn.microsoft.com/en-us/windows/console/readconsoleinput + https://learn.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-waitforsingleobjectex */ - fds := pollfd.[ .{ fd = STDIN_FILENO, events = POLLIN, revents = 0 } ]; - nfds := fds.count; - poll_return := poll(fds.data, xx nfds, xx timeout_milliseconds); // TODO Wait for input using poll syscall. This breaks and throws '-1 | 4 | Interrupted system call' when we resize the window while polling. + + poll_return := WaitForSingleObjectEx(stdin, timeout_milliseconds, true); error_code, error_message := get_error_value_and_string(); // FIXME Not used. - return ifx poll_return > 0 then true else false; + + // Possible values for poll_return TODO NOT BEING USED + WAIT_ABANDONED :: 0x00000080; + WAIT_IO_COMPLETION :: 0x000000C0; + WAIT_OBJECT_0 :: 0x00000000; + WAIT_TIMEOUT :: 0x00000102; + WAIT_FAILED :: 0xFFFFFFFF; + + return ifx poll_return == 0 then true else false; } OS_was_terminal_resized :: () -> bool { |
