diff options
author | wm4 <wm4@nowhere> | 2014-08-21 22:11:38 +0200 |
---|---|---|
committer | wm4 <wm4@nowhere> | 2014-08-21 22:45:58 +0200 |
commit | 47b29094c34bdf0aab9f213c8eb2347993e4d505 (patch) | |
tree | 3c68821d10cd713c6d515705b79d1513160bd494 /osdep/terminal-win.c | |
parent | 218ace2b02e2f2a867c4b792d4a1ec03015d7294 (diff) | |
download | mpv-47b29094c34bdf0aab9f213c8eb2347993e4d505.tar.bz2 mpv-47b29094c34bdf0aab9f213c8eb2347993e4d505.tar.xz |
win32: emulate some ANSI terminal escape codes
We already redirect all terminal output through our own wrappers (for
the sake of UTF-8), so we might as well use it to handle ANSI escape
codes.
This also changes behavior on UNIX: we don't retrieve some escape codes
per terminfo anymore, and just hardcode them. Every terminal should
understand them.
The advantage is that we can pretend to have a real terminal in the
normal player code, and Windows atrocities are locked away in glue
code.
Diffstat (limited to 'osdep/terminal-win.c')
-rw-r--r-- | osdep/terminal-win.c | 84 |
1 files changed, 75 insertions, 9 deletions
diff --git a/osdep/terminal-win.c b/osdep/terminal-win.c index 19603d87d1..9b985d7378 100644 --- a/osdep/terminal-win.c +++ b/osdep/terminal-win.c @@ -33,12 +33,11 @@ #include "input/keycodes.h" #include "input/input.h" #include "terminal.h" +#include "osdep/io.h" #include "osdep/w32_keyboard.h" int screen_width = 79; int screen_height = 24; -char *terminal_erase_to_end_of_line = ""; -char *terminal_cursor_up = ""; #define hSTDOUT GetStdHandle(STD_OUTPUT_HANDLE) #define hSTDERR GetStdHandle(STD_ERROR_HANDLE) @@ -58,7 +57,7 @@ void get_screen_size(void) { CONSOLE_SCREEN_BUFFER_INFO cinfo; if (GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &cinfo)) { - screen_width = cinfo.dwMaximumWindowSize.X; + screen_width = cinfo.dwMaximumWindowSize.X - 1; screen_height = cinfo.dwMaximumWindowSize.Y; } } @@ -177,13 +176,80 @@ bool terminal_in_background(void) return false; } -void terminal_set_foreground_color(FILE *stream, int c) +static void write_console_text(HANDLE *wstream, char *buf) { - HANDLE *wstream = stream == stderr ? hSTDERR : hSTDOUT; - if (c < 0 || c >= 8) { // reset or invalid - SetConsoleTextAttribute(wstream, stdoutAttrs); - } else { - SetConsoleTextAttribute(wstream, ansi2win32[c] | FOREGROUND_INTENSITY); + wchar_t *out = mp_from_utf8(NULL, buf); + size_t out_len = wcslen(out); + WriteConsoleW(wstream, out, out_len, NULL, NULL); + talloc_free(out); +} + +// Mutates the input argument (buf), because we're evil. +void mp_write_console_ansi(HANDLE *wstream, char *buf) +{ + while (*buf) { + char *next = strchr(buf, '\033'); + if (!next) { + write_console_text(wstream, buf); + break; + } + next[0] = '\0'; // mutate input for fun and profit + write_console_text(wstream, buf); + if (next[1] != '[') { + write_console_text(wstream, "\033"); + buf = next; + continue; + } + next += 2; + // ANSI codes generally follow this syntax: + // "\033[" [ <i> (';' <i> )* ] <c> + // where <i> are integers, and <c> a single char command code. + // Also see: http://en.wikipedia.org/wiki/ANSI_escape_code#CSI_codes + int params[2] = {-1, -1}; // 'm' might be unlimited; ignore that + int num_params = 0; + while (num_params < 2) { + char *end = next; + long p = strtol(next, &end, 10); + if (end == next) + break; + next = end; + params[num_params++] = p; + if (next[0] != ';' || !next[0]) + break; + next += 1; + } + char code = next[0]; + if (code) + next += 1; + CONSOLE_SCREEN_BUFFER_INFO info; + GetConsoleScreenBufferInfo(wstream, &info); + switch (code) { + case 'K': { // erase to end of line + COORD at = info.dwCursorPosition; + int len = info.dwSize.X - at.X; + FillConsoleOutputCharacterW(wstream, ' ', len, at, &(DWORD){0}); + SetConsoleCursorPosition(wstream, at); + break; + } + case 'A': { // cursor up + info.dwCursorPosition.Y -= 1; + SetConsoleCursorPosition(wstream, info.dwCursorPosition); + break; + } + case 'm': { // "SGR" + for (int n = 0; n < num_params; n++) { + int p = params[n]; + if (p <= 0) { + SetConsoleTextAttribute(wstream, stdoutAttrs); + } else if (p >= 0 && p < 8) { + SetConsoleTextAttribute(wstream, + ansi2win32[p] | FOREGROUND_INTENSITY); + } + } + break; + } + } + buf = next; } } |