diff options
Diffstat (limited to 'osdep/terminal-win.c')
-rw-r--r-- | osdep/terminal-win.c | 137 |
1 files changed, 113 insertions, 24 deletions
diff --git a/osdep/terminal-win.c b/osdep/terminal-win.c index 3672f3a763..dc8e10407d 100644 --- a/osdep/terminal-win.c +++ b/osdep/terminal-win.c @@ -18,14 +18,12 @@ * License along with mpv. If not, see <http://www.gnu.org/licenses/>. */ -#include "config.h" #include <fcntl.h> #include <stdio.h> #include <stdint.h> #include <string.h> #include <windows.h> #include <io.h> -#include <pthread.h> #include <assert.h> #include "common/common.h" #include "input/keycodes.h" @@ -55,20 +53,17 @@ static void attempt_native_out_vt(HANDLE hOut, DWORD basemode) SetConsoleMode(hOut, basemode); } -static bool is_native_out_vt(HANDLE hOut) -{ - DWORD cmode; - return GetConsoleMode(hOut, &cmode) && - (cmode & ENABLE_VIRTUAL_TERMINAL_PROCESSING) && - !(cmode & DISABLE_NEWLINE_AUTO_RETURN); -} +#define hSTDIN GetStdHandle(STD_INPUT_HANDLE) #define hSTDOUT GetStdHandle(STD_OUTPUT_HANDLE) #define hSTDERR GetStdHandle(STD_ERROR_HANDLE) #define FOREGROUND_ALL (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE) #define BACKGROUND_ALL (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE) +static bool is_console[STDERR_FILENO + 1]; +static bool is_vt[STDERR_FILENO + 1]; +static bool utf8_output; static short stdoutAttrs = 0; // copied from the screen buffer on init static const unsigned char ansi2win32[8] = { 0, @@ -93,9 +88,26 @@ static const unsigned char ansi2win32bg[8] = { static bool running; static HANDLE death; -static pthread_t input_thread; +static mp_thread input_thread; static struct input_ctx *input_ctx; +static bool is_native_out_vt_internal(HANDLE hOut) +{ + DWORD cmode; + return GetConsoleMode(hOut, &cmode) && + (cmode & ENABLE_VIRTUAL_TERMINAL_PROCESSING) && + !(cmode & DISABLE_NEWLINE_AUTO_RETURN); +} + +static bool is_native_out_vt(HANDLE hOut) +{ + if (hOut == hSTDOUT) + return is_vt[STDOUT_FILENO]; + if (hOut == hSTDERR) + return is_vt[STDERR_FILENO]; + return is_native_out_vt_internal(hOut); +} + void terminal_get_size(int *w, int *h) { CONSOLE_SCREEN_BUFFER_INFO cinfo; @@ -106,6 +118,10 @@ void terminal_get_size(int *w, int *h) } } +void terminal_get_size2(int *rows, int *cols, int *px_width, int *px_height) +{ +} + static bool has_input_events(HANDLE h) { DWORD num_events; @@ -156,9 +172,9 @@ static void read_input(HANDLE in) } } -static void *input_thread_fn(void *ptr) +static MP_THREAD_VOID input_thread_fn(void *ptr) { - mpthread_set_name("terminal"); + mp_thread_set_name("terminal/input"); HANDLE in = ptr; HANDLE stuff[2] = {in, death}; while (1) { @@ -167,7 +183,7 @@ static void *input_thread_fn(void *ptr) break; read_input(in); } - return NULL; + MP_THREAD_RETURN(); } void terminal_setup_getch(struct input_ctx *ictx) @@ -181,7 +197,7 @@ void terminal_setup_getch(struct input_ctx *ictx) death = CreateEventW(NULL, TRUE, FALSE, NULL); if (!death) return; - if (pthread_create(&input_thread, NULL, input_thread_fn, in)) { + if (mp_thread_create(&input_thread, input_thread_fn, in)) { CloseHandle(death); return; } @@ -189,14 +205,21 @@ void terminal_setup_getch(struct input_ctx *ictx) } } +DWORD tmp_buffers_key = FLS_OUT_OF_INDEXES; +struct tmp_buffers { + bstr write_console_buf; + wchar_t *write_console_wbuf; +}; + void terminal_uninit(void) { if (running) { SetEvent(death); - pthread_join(input_thread, NULL); + mp_thread_join(input_thread); input_ctx = NULL; running = false; } + FlsFree(tmp_buffers_key); } bool terminal_in_background(void) @@ -204,16 +227,53 @@ bool terminal_in_background(void) return false; } -void mp_write_console_ansi(HANDLE wstream, char *buf) +int mp_console_vfprintf(HANDLE wstream, const char *format, va_list args) { - wchar_t *wbuf = mp_from_utf8(NULL, buf); - wchar_t *pos = wbuf; + struct tmp_buffers *buffers = FlsGetValue(tmp_buffers_key); + bool free_buf = false; + if (!buffers) { + buffers = talloc_zero(NULL, struct tmp_buffers); + free_buf = !FlsSetValue(tmp_buffers_key, buffers); + } - while (*pos) { - if (is_native_out_vt(wstream)) { - WriteConsoleW(wstream, pos, wcslen(pos), NULL, NULL); - break; + buffers->write_console_buf.len = 0; + bstr_xappend_vasprintf(buffers, &buffers->write_console_buf, format, args); + + int ret = mp_console_fputs(wstream, buffers->write_console_buf); + + if (free_buf) + talloc_free(buffers); + + return ret; +} + +int mp_console_fputs(HANDLE wstream, bstr str) +{ + struct tmp_buffers *buffers = FlsGetValue(tmp_buffers_key); + bool free_buf = false; + if (!buffers) { + buffers = talloc_zero(NULL, struct tmp_buffers); + free_buf = !FlsSetValue(tmp_buffers_key, buffers); + } + + bool vt = is_native_out_vt(wstream); + int wlen = 0; + wchar_t *pos = NULL; + if (!utf8_output || !vt) { + wlen = bstr_to_wchar(buffers, str, &buffers->write_console_wbuf); + pos = buffers->write_console_wbuf; + } + + if (vt) { + if (utf8_output) { + WriteConsoleA(wstream, str.start, str.len, NULL, NULL); + } else { + WriteConsoleW(wstream, pos, wlen, NULL, NULL); } + goto done; + } + + while (*pos) { wchar_t *next = wcschr(pos, '\033'); if (!next) { WriteConsoleW(wstream, pos, wcslen(pos), NULL, NULL); @@ -350,7 +410,13 @@ void mp_write_console_ansi(HANDLE wstream, char *buf) pos = next; } - talloc_free(wbuf); +done:; + int ret = buffers->write_console_buf.len; + + if (free_buf) + talloc_free(buffers); + + return ret; } static bool is_a_console(HANDLE h) @@ -358,6 +424,17 @@ static bool is_a_console(HANDLE h) return GetConsoleMode(h, &(DWORD){0}); } +bool mp_check_console(void *handle) +{ + if (handle == hSTDIN) + return is_console[STDIN_FILENO]; + if (handle == hSTDOUT) + return is_console[STDOUT_FILENO]; + if (handle == hSTDERR) + return is_console[STDERR_FILENO]; + return is_a_console(handle); +} + static void reopen_console_handle(DWORD std, int fd, FILE *stream) { HANDLE handle = GetStdHandle(std); @@ -367,7 +444,6 @@ static void reopen_console_handle(DWORD std, int fd, FILE *stream) } else { freopen("CONOUT$", "wt", stream); } - setvbuf(stream, NULL, _IONBF, 0); // Set the low-level FD to the new handle value, since mp_subprocess2 // callers might rely on low-level FDs being set. Note, with this @@ -418,6 +494,19 @@ void terminal_init(void) cmode |= (ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT); attempt_native_out_vt(hSTDOUT, cmode); attempt_native_out_vt(hSTDERR, cmode); + + // Init for mp_check_console(), this never changes during runtime + is_console[STDIN_FILENO] = is_a_console(hSTDIN); + is_console[STDOUT_FILENO] = is_a_console(hSTDOUT); + is_console[STDERR_FILENO] = is_a_console(hSTDERR); + + // Init for is_native_out_vt(), this is never disabled/changed during runtime + is_vt[STDOUT_FILENO] = is_native_out_vt_internal(hSTDOUT); + is_vt[STDERR_FILENO] = is_native_out_vt_internal(hSTDERR); + GetConsoleScreenBufferInfo(hSTDOUT, &cinfo); stdoutAttrs = cinfo.wAttributes; + + tmp_buffers_key = FlsAlloc((PFLS_CALLBACK_FUNCTION)talloc_free); + utf8_output = SetConsoleOutputCP(CP_UTF8); } |