And skip unsupported private sequences, instead of printing them.
Unified · Split
| @@ -285,6 +285,10 @@ int mp_console_fputs(HANDLE wstream, bstr str) · 284 unmodified lines | ||
| 285 | 285 | // CSI - Control Sequence Introducer |
| 286 | 286 | next += 2; |
| 287 | 287 | |
| 288 | + // private sequences | |
| 289 | + bool priv = next[0] == '?'; | |
| 290 | + next += priv; | |
| 291 | + | |
| 288 | 292 | // CSI codes generally follow this syntax: |
| 289 | 293 | // "\033[" [ <i> (';' <i> )* ] <c> |
| 290 | 294 | // where <i> are integers, and <c> a single char command code. |
| @@ -308,18 +312,84 @@ int mp_console_fputs(HANDLE wstream, bstr str) · 17 unmodified lines | ||
| 308 | 312 | CONSOLE_SCREEN_BUFFER_INFO info; |
| 309 | 313 | GetConsoleScreenBufferInfo(wstream, &info); |
| 310 | 314 | switch (code) { |
| 311 | − case 'K': { // erase to end of line | |
| 312 | − COORD at = info.dwCursorPosition; | |
| 313 | − int len = info.dwSize.X - at.X; | |
| 314 | − FillConsoleOutputCharacterW(wstream, ' ', len, at, &(DWORD){0}); | |
| 315 | − SetConsoleCursorPosition(wstream, at); | |
| 315 | + case 'K': { // erase line | |
| 316 | + COORD cursor_pos = info.dwCursorPosition; | |
| 317 | + COORD at = cursor_pos; | |
| 318 | + int len; | |
| 319 | + switch (num_params ? params[0] : 0) { | |
| 320 | + case 1: | |
| 321 | + len = at.X; | |
| 322 | + at.X = 0; | |
| 323 | + break; | |
| 324 | + case 2: | |
| 325 | + len = info.dwSize.X; | |
| 326 | + at.X = 0; | |
| 327 | + break; | |
| 328 | + case 0: | |
| 329 | + default: | |
| 330 | + len = info.dwSize.X - at.X; | |
| 331 | + } | |
| 332 | + FillConsoleOutputCharacterW(wstream, L' ', len, at, &(DWORD){0}); | |
| 333 | + SetConsoleCursorPosition(wstream, cursor_pos); | |
| 334 | + break; | |
| 335 | + } | |
| 336 | + case 'B': { // cursor down | |
| 337 | + info.dwCursorPosition.Y += !num_params ? 1 : params[0]; | |
| 338 | + SetConsoleCursorPosition(wstream, info.dwCursorPosition); | |
| 316 | 339 | break; |
| 317 | 340 | } |
| 318 | 341 | case 'A': { // cursor up |
| 319 | − info.dwCursorPosition.Y -= 1; | |
| 342 | + info.dwCursorPosition.Y -= !num_params ? 1 : params[0]; | |
| 320 | 343 | SetConsoleCursorPosition(wstream, info.dwCursorPosition); |
| 321 | 344 | break; |
| 322 | 345 | } |
| 346 | + case 'J': { | |
| 347 | + // Only full screen clear is supported | |
| 348 | + if (!num_params || params[0] != 2) | |
| 349 | + break; | |
| 350 | + | |
| 351 | + COORD top_left = {0, 0}; | |
| 352 | + FillConsoleOutputCharacterW(wstream, L' ', info.dwSize.X * info.dwSize.Y, | |
| 353 | + top_left, &(DWORD){0}); | |
| 354 | + SetConsoleCursorPosition(wstream, top_left); | |
| 355 | + break; | |
| 356 | + } | |
| 357 | + case 'f': { | |
| 358 | + if (num_params != 2) | |
| 359 | + break; | |
| 360 | + SetConsoleCursorPosition(wstream, (COORD){params[0], params[1]}); | |
| 361 | + break; | |
| 362 | + } | |
| 363 | + case 'l': { | |
| 364 | + if (!priv || !num_params) | |
| 365 | + break; | |
| 366 | + | |
| 367 | + switch (params[0]) { | |
| 368 | + case 25:; // hide the cursor | |
| 369 | + CONSOLE_CURSOR_INFO cursor_info; | |
| 370 | + if (!GetConsoleCursorInfo(wstream, &cursor_info)) | |
| 371 | + break; | |
| 372 | + cursor_info.bVisible = FALSE; | |
| 373 | + SetConsoleCursorInfo(wstream, &cursor_info); | |
| 374 | + break; | |
| 375 | + } | |
| 376 | + break; | |
| 377 | + } | |
| 378 | + case 'h': { | |
| 379 | + if (!priv || !num_params) | |
| 380 | + break; | |
| 381 | + | |
| 382 | + switch (params[0]) { | |
| 383 | + case 25:; // show the cursor | |
| 384 | + CONSOLE_CURSOR_INFO cursor_info; | |
| 385 | + if (!GetConsoleCursorInfo(wstream, &cursor_info)) | |
| 386 | + break; | |
| 387 | + cursor_info.bVisible = TRUE; | |
| 388 | + SetConsoleCursorInfo(wstream, &cursor_info); | |
| 389 | + break; | |
| 390 | + } | |
| 391 | + break; | |
| 392 | + } | |
| 323 | 393 | case 'm': { // "SGR" |
| 324 | 394 | short attr = info.wAttributes; |
| 325 | 395 | if (num_params == 0) // reset |