comparison src/os_win32.c @ 13314:65c3e8259124 v8.0.1531

patch 8.0.1531: cannot use 24 bit colors in MS-Windows console commit https://github.com/vim/vim/commit/cafafb381a04e33f3ce9cd15dd9f94b73226831f Author: Bram Moolenaar <Bram@vim.org> Date: Thu Feb 22 21:07:09 2018 +0100 patch 8.0.1531: cannot use 24 bit colors in MS-Windows console Problem: Cannot use 24 bit colors in MS-Windows console. Solution: Add support for vcon. (Nobuhiro Takasaki, Ken Takasaki, fixes #1270, fixes #2060)
author Christian Brabandt <cb@256bit.org>
date Thu, 22 Feb 2018 21:15:05 +0100
parents ee1a1276a759
children 69517d67421f
comparison
equal deleted inserted replaced
13313:97fb19f36653 13314:65c3e8259124
201 static int win32_getattrs(char_u *name); 201 static int win32_getattrs(char_u *name);
202 static int win32_setattrs(char_u *name, int attrs); 202 static int win32_setattrs(char_u *name, int attrs);
203 static int win32_set_archive(char_u *name); 203 static int win32_set_archive(char_u *name);
204 204
205 #ifndef FEAT_GUI_W32 205 #ifndef FEAT_GUI_W32
206 static int vtp_working = 0;
207 static void vtp_init();
208 static void vtp_exit();
209 static int vtp_printf(char *format, ...);
210 static void vtp_sgr_bulk(int arg);
211 static void vtp_sgr_bulks(int argc, int *argv);
212
213 static guicolor_T save_console_bg_rgb;
214 static guicolor_T save_console_fg_rgb;
215
216 # ifdef FEAT_TERMGUICOLORS
217 # define USE_VTP (vtp_working && p_tgc)
218 # else
219 # define USE_VTP 0
220 # endif
221
222 static void set_console_color_rgb(void);
223 static void reset_console_color_rgb(void);
224 #endif
225
226 /* This flag is newly created from Windows 10 */
227 #ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING
228 # define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004
229 #endif
230
231 #ifndef FEAT_GUI_W32
206 static int suppress_winsize = 1; /* don't fiddle with console */ 232 static int suppress_winsize = 1; /* don't fiddle with console */
207 #endif 233 #endif
208 234
209 static char_u *exe_path = NULL; 235 static char_u *exe_path = NULL;
210 236
211 static BOOL win8_or_later = FALSE; 237 static BOOL win8_or_later = FALSE;
212 238
213 #ifndef FEAT_GUI_W32 239 #ifndef FEAT_GUI_W32
240 /* Dynamic loading for portability */
241 typedef struct _DYN_CONSOLE_SCREEN_BUFFER_INFOEX
242 {
243 ULONG cbSize;
244 COORD dwSize;
245 COORD dwCursorPosition;
246 WORD wAttributes;
247 SMALL_RECT srWindow;
248 COORD dwMaximumWindowSize;
249 WORD wPopupAttributes;
250 BOOL bFullscreenSupported;
251 COLORREF ColorTable[16];
252 } DYN_CONSOLE_SCREEN_BUFFER_INFOEX, *PDYN_CONSOLE_SCREEN_BUFFER_INFOEX;
253 typedef BOOL (WINAPI *PfnGetConsoleScreenBufferInfoEx)(HANDLE, PDYN_CONSOLE_SCREEN_BUFFER_INFOEX);
254 static PfnGetConsoleScreenBufferInfoEx pGetConsoleScreenBufferInfoEx;
255 typedef BOOL (WINAPI *PfnSetConsoleScreenBufferInfoEx)(HANDLE, PDYN_CONSOLE_SCREEN_BUFFER_INFOEX);
256 static PfnSetConsoleScreenBufferInfoEx pSetConsoleScreenBufferInfoEx;
257 static BOOL has_csbiex = FALSE;
258
259 /*
260 * Get version number including build number
261 */
262 typedef BOOL (WINAPI *PfnRtlGetVersion)(LPOSVERSIONINFOW);
263 # define MAKE_VER(major, minor, build) \
264 (((major) << 24) | ((minor) << 16) | (build))
265
266 static DWORD
267 get_build_number(void)
268 {
269 OSVERSIONINFOW osver = {sizeof(OSVERSIONINFOW)};
270 HMODULE hNtdll;
271 PfnRtlGetVersion pRtlGetVersion;
272 DWORD ver = MAKE_VER(0, 0, 0);
273
274 hNtdll = GetModuleHandle("ntdll.dll");
275 if (hNtdll != NULL)
276 {
277 pRtlGetVersion =
278 (PfnRtlGetVersion)GetProcAddress(hNtdll, "RtlGetVersion");
279 pRtlGetVersion(&osver);
280 ver = MAKE_VER(min(osver.dwMajorVersion, 255),
281 min(osver.dwMinorVersion, 255),
282 min(osver.dwBuildNumber, 32767));
283 }
284 return ver;
285 }
286
287
214 /* 288 /*
215 * Version of ReadConsoleInput() that works with IME. 289 * Version of ReadConsoleInput() that works with IME.
216 * Works around problems on Windows 8. 290 * Works around problems on Windows 8.
217 */ 291 */
218 static BOOL 292 static BOOL
2535 if (cterm_normal_bg_color == 0) 2609 if (cterm_normal_bg_color == 0)
2536 cterm_normal_bg_color = ((g_attrCurrent >> 4) & 0xf) + 1; 2610 cterm_normal_bg_color = ((g_attrCurrent >> 4) & 0xf) + 1;
2537 2611
2538 /* set termcap codes to current text attributes */ 2612 /* set termcap codes to current text attributes */
2539 update_tcap(g_attrCurrent); 2613 update_tcap(g_attrCurrent);
2614 swap_tcap();
2540 2615
2541 GetConsoleCursorInfo(g_hConOut, &g_cci); 2616 GetConsoleCursorInfo(g_hConOut, &g_cci);
2542 GetConsoleMode(g_hConIn, &g_cmodein); 2617 GetConsoleMode(g_hConIn, &g_cmodein);
2543 GetConsoleMode(g_hConOut, &g_cmodeout); 2618 GetConsoleMode(g_hConOut, &g_cmodeout);
2544 2619
2575 #endif 2650 #endif
2576 2651
2577 #ifdef FEAT_CLIPBOARD 2652 #ifdef FEAT_CLIPBOARD
2578 win_clip_init(); 2653 win_clip_init();
2579 #endif 2654 #endif
2655
2656 vtp_init();
2580 } 2657 }
2581 2658
2582 /* 2659 /*
2583 * non-GUI version of mch_exit(). 2660 * non-GUI version of mch_exit().
2584 * Shut down and exit with status `r' 2661 * Shut down and exit with status `r'
2586 */ 2663 */
2587 void 2664 void
2588 mch_exit(int r) 2665 mch_exit(int r)
2589 { 2666 {
2590 exiting = TRUE; 2667 exiting = TRUE;
2668
2669 vtp_exit();
2591 2670
2592 stoptermcap(); 2671 stoptermcap();
2593 if (g_fWindInitCalled) 2672 if (g_fWindInitCalled)
2594 settmode(TMODE_COOK); 2673 settmode(TMODE_COOK);
2595 2674
3799 ENABLE_ECHO_INPUT); 3878 ENABLE_ECHO_INPUT);
3800 #ifdef FEAT_MOUSE 3879 #ifdef FEAT_MOUSE
3801 if (g_fMouseActive) 3880 if (g_fMouseActive)
3802 cmodein |= ENABLE_MOUSE_INPUT; 3881 cmodein |= ENABLE_MOUSE_INPUT;
3803 #endif 3882 #endif
3804 cmodeout &= ~(ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT); 3883 cmodeout &= ~(
3884 #ifdef FEAT_TERMGUICOLORS
3885 /* Do not turn off the ENABLE_PROCESSRD_OUTPUT flag when using
3886 * VTP. */
3887 ((vtp_working) ? 0 : ENABLE_PROCESSED_OUTPUT) |
3888 #else
3889 ENABLE_PROCESSED_OUTPUT |
3890 #endif
3891 ENABLE_WRAP_AT_EOL_OUTPUT);
3805 bEnableHandler = TRUE; 3892 bEnableHandler = TRUE;
3806 } 3893 }
3807 else /* cooked */ 3894 else /* cooked */
3808 { 3895 {
3809 cmodein |= (ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT | 3896 cmodein |= (ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT |
5446 * characteristics, including the buffer size and the window 5533 * characteristics, including the buffer size and the window
5447 * size. Since we will be redrawing the screen, we don't need 5534 * size. Since we will be redrawing the screen, we don't need
5448 * to restore the actual contents of the buffer. 5535 * to restore the actual contents of the buffer.
5449 */ 5536 */
5450 RestoreConsoleBuffer(&g_cbTermcap, FALSE); 5537 RestoreConsoleBuffer(&g_cbTermcap, FALSE);
5538 reset_console_color_rgb();
5451 SetConsoleWindowInfo(g_hConOut, TRUE, &g_cbTermcap.Info.srWindow); 5539 SetConsoleWindowInfo(g_hConOut, TRUE, &g_cbTermcap.Info.srWindow);
5452 Rows = g_cbTermcap.Info.dwSize.Y; 5540 Rows = g_cbTermcap.Info.dwSize.Y;
5453 Columns = g_cbTermcap.Info.dwSize.X; 5541 Columns = g_cbTermcap.Info.dwSize.X;
5454 } 5542 }
5455 else 5543 else
5458 * This is our first time entering termcap mode. Clear the console 5546 * This is our first time entering termcap mode. Clear the console
5459 * screen buffer, and resize the buffer to match the current window 5547 * screen buffer, and resize the buffer to match the current window
5460 * size. We will use this as the size of our editing environment. 5548 * size. We will use this as the size of our editing environment.
5461 */ 5549 */
5462 ClearConsoleBuffer(g_attrCurrent); 5550 ClearConsoleBuffer(g_attrCurrent);
5551 set_console_color_rgb();
5463 ResizeConBufAndWindow(g_hConOut, Columns, Rows); 5552 ResizeConBufAndWindow(g_hConOut, Columns, Rows);
5464 } 5553 }
5465 5554
5466 #ifdef FEAT_TITLE 5555 #ifdef FEAT_TITLE
5467 resettitle(); 5556 resettitle();
5506 cb = exiting ? &g_cbOrig : &g_cbNonTermcap; 5595 cb = exiting ? &g_cbOrig : &g_cbNonTermcap;
5507 #else 5596 #else
5508 cb = &g_cbNonTermcap; 5597 cb = &g_cbNonTermcap;
5509 #endif 5598 #endif
5510 RestoreConsoleBuffer(cb, p_rs); 5599 RestoreConsoleBuffer(cb, p_rs);
5600 reset_console_color_rgb();
5511 SetConsoleCursorInfo(g_hConOut, &g_cci); 5601 SetConsoleCursorInfo(g_hConOut, &g_cci);
5512 5602
5513 if (p_rs || exiting) 5603 if (p_rs || exiting)
5514 { 5604 {
5515 /* 5605 /*
5560 DWORD n) 5650 DWORD n)
5561 { 5651 {
5562 DWORD dwDummy; 5652 DWORD dwDummy;
5563 5653
5564 FillConsoleOutputCharacter(g_hConOut, ' ', n, coord, &dwDummy); 5654 FillConsoleOutputCharacter(g_hConOut, ' ', n, coord, &dwDummy);
5565 FillConsoleOutputAttribute(g_hConOut, g_attrCurrent, n, coord, &dwDummy); 5655
5656 if (!USE_VTP)
5657 FillConsoleOutputAttribute(g_hConOut, g_attrCurrent, n, coord, &dwDummy);
5658 else
5659 FillConsoleOutputAttribute(g_hConOut, 0, n, coord, &dwDummy);
5566 } 5660 }
5567 5661
5568 5662
5569 /* 5663 /*
5570 * Clear the screen 5664 * Clear the screen
5571 */ 5665 */
5572 static void 5666 static void
5573 clear_screen(void) 5667 clear_screen(void)
5574 { 5668 {
5575 g_coord.X = g_coord.Y = 0; 5669 g_coord.X = g_coord.Y = 0;
5576 clear_chars(g_coord, Rows * Columns); 5670
5671 if (!USE_VTP)
5672 clear_chars(g_coord, Rows * Columns);
5673 else
5674 {
5675 set_console_color_rgb();
5676 gotoxy(1, 1);
5677 vtp_printf("\033[2J");
5678 }
5577 } 5679 }
5578 5680
5579 5681
5580 /* 5682 /*
5581 * Clear to end of display 5683 * Clear to end of display
5582 */ 5684 */
5583 static void 5685 static void
5584 clear_to_end_of_display(void) 5686 clear_to_end_of_display(void)
5585 { 5687 {
5586 clear_chars(g_coord, (Rows - g_coord.Y - 1) 5688 COORD save = g_coord;
5689
5690 if (!USE_VTP)
5691 clear_chars(g_coord, (Rows - g_coord.Y - 1)
5587 * Columns + (Columns - g_coord.X)); 5692 * Columns + (Columns - g_coord.X));
5693 else
5694 {
5695 set_console_color_rgb();
5696 gotoxy(g_coord.X + 1, g_coord.Y + 1);
5697 vtp_printf("\033[0J");
5698
5699 gotoxy(save.X + 1, save.Y + 1);
5700 g_coord = save;
5701 }
5588 } 5702 }
5589 5703
5590 5704
5591 /* 5705 /*
5592 * Clear to end of line 5706 * Clear to end of line
5593 */ 5707 */
5594 static void 5708 static void
5595 clear_to_end_of_line(void) 5709 clear_to_end_of_line(void)
5596 { 5710 {
5597 clear_chars(g_coord, Columns - g_coord.X); 5711 COORD save = g_coord;
5712
5713 if (!USE_VTP)
5714 clear_chars(g_coord, Columns - g_coord.X);
5715 else
5716 {
5717 set_console_color_rgb();
5718 gotoxy(g_coord.X + 1, g_coord.Y + 1);
5719 vtp_printf("\033[0K");
5720
5721 gotoxy(save.X + 1, save.Y + 1);
5722 g_coord = save;
5723 }
5598 } 5724 }
5599 5725
5600 5726
5601 /* 5727 /*
5602 * Scroll the scroll region up by `cLines' lines 5728 * Scroll the scroll region up by `cLines' lines
5631 5757
5632 g_srScrollRegion.Left = left; 5758 g_srScrollRegion.Left = left;
5633 g_srScrollRegion.Top = top; 5759 g_srScrollRegion.Top = top;
5634 g_srScrollRegion.Right = right; 5760 g_srScrollRegion.Right = right;
5635 g_srScrollRegion.Bottom = bottom; 5761 g_srScrollRegion.Bottom = bottom;
5762
5763 if (USE_VTP)
5764 vtp_printf("\033[%d;%dr", top + 1, bottom + 1);
5636 } 5765 }
5637 5766
5638 5767
5639 /* 5768 /*
5640 * Insert `cLines' lines at the current cursor position 5769 * Insert `cLines' lines at the current cursor position
5652 source.Left = 0; 5781 source.Left = 0;
5653 source.Top = g_coord.Y; 5782 source.Top = g_coord.Y;
5654 source.Right = g_srScrollRegion.Right; 5783 source.Right = g_srScrollRegion.Right;
5655 source.Bottom = g_srScrollRegion.Bottom - cLines; 5784 source.Bottom = g_srScrollRegion.Bottom - cLines;
5656 5785
5657 fill.Char.AsciiChar = ' '; 5786 if (!USE_VTP)
5658 fill.Attributes = g_attrCurrent; 5787 {
5659 5788 fill.Char.AsciiChar = ' ';
5660 ScrollConsoleScreenBuffer(g_hConOut, &source, NULL, dest, &fill); 5789 fill.Attributes = g_attrCurrent;
5790
5791 ScrollConsoleScreenBuffer(g_hConOut, &source, NULL, dest, &fill);
5792 }
5793 else
5794 {
5795 set_console_color_rgb();
5796
5797 gotoxy(1, source.Top + 1);
5798 vtp_printf("\033[%dT", cLines);
5799 }
5661 5800
5662 /* Here we have to deal with a win32 console flake: If the scroll 5801 /* Here we have to deal with a win32 console flake: If the scroll
5663 * region looks like abc and we scroll c to a and fill with d we get 5802 * region looks like abc and we scroll c to a and fill with d we get
5664 * cbd... if we scroll block c one line at a time to a, we get cdd... 5803 * cbd... if we scroll block c one line at a time to a, we get cdd...
5665 * vim expects cdd consistently... So we have to deal with that 5804 * vim expects cdd consistently... So we have to deal with that
5694 source.Left = 0; 5833 source.Left = 0;
5695 source.Top = g_coord.Y + cLines; 5834 source.Top = g_coord.Y + cLines;
5696 source.Right = g_srScrollRegion.Right; 5835 source.Right = g_srScrollRegion.Right;
5697 source.Bottom = g_srScrollRegion.Bottom; 5836 source.Bottom = g_srScrollRegion.Bottom;
5698 5837
5699 fill.Char.AsciiChar = ' '; 5838 if (!USE_VTP)
5700 fill.Attributes = g_attrCurrent; 5839 {
5701 5840 fill.Char.AsciiChar = ' ';
5702 ScrollConsoleScreenBuffer(g_hConOut, &source, NULL, dest, &fill); 5841 fill.Attributes = g_attrCurrent;
5842
5843 ScrollConsoleScreenBuffer(g_hConOut, &source, NULL, dest, &fill);
5844 }
5845 else
5846 {
5847 set_console_color_rgb();
5848
5849 gotoxy(1, source.Top + 1);
5850 vtp_printf("\033[%dS", cLines);
5851 }
5703 5852
5704 /* Here we have to deal with a win32 console flake: If the scroll 5853 /* Here we have to deal with a win32 console flake: If the scroll
5705 * region looks like abc and we scroll c to a and fill with d we get 5854 * region looks like abc and we scroll c to a and fill with d we get
5706 * cbd... if we scroll block c one line at a time to a, we get cdd... 5855 * cbd... if we scroll block c one line at a time to a, we get cdd...
5707 * vim expects cdd consistently... So we have to deal with that 5856 * vim expects cdd consistently... So we have to deal with that
5733 return; 5882 return;
5734 5883
5735 /* external cursor coords are 1-based; internal are 0-based */ 5884 /* external cursor coords are 1-based; internal are 0-based */
5736 g_coord.X = x - 1; 5885 g_coord.X = x - 1;
5737 g_coord.Y = y - 1; 5886 g_coord.Y = y - 1;
5738 SetConsoleCursorPosition(g_hConOut, g_coord); 5887
5888 if (!USE_VTP)
5889 SetConsoleCursorPosition(g_hConOut, g_coord);
5890 else
5891 vtp_printf("\033[%d;%dH", y, x);
5739 } 5892 }
5740 5893
5741 5894
5742 /* 5895 /*
5743 * Set the current text attribute = (foreground | background) 5896 * Set the current text attribute = (foreground | background)
5755 static void 5908 static void
5756 textcolor(WORD wAttr) 5909 textcolor(WORD wAttr)
5757 { 5910 {
5758 g_attrCurrent = (g_attrCurrent & 0xf0) + (wAttr & 0x0f); 5911 g_attrCurrent = (g_attrCurrent & 0xf0) + (wAttr & 0x0f);
5759 5912
5760 SetConsoleTextAttribute(g_hConOut, g_attrCurrent); 5913 if (!USE_VTP)
5914 SetConsoleTextAttribute(g_hConOut, g_attrCurrent);
5915 else
5916 vtp_sgr_bulk(wAttr);
5761 } 5917 }
5762 5918
5763 5919
5764 static void 5920 static void
5765 textbackground(WORD wAttr) 5921 textbackground(WORD wAttr)
5766 { 5922 {
5767 g_attrCurrent = (g_attrCurrent & 0x0f) + ((wAttr & 0x0f) << 4); 5923 g_attrCurrent = (g_attrCurrent & 0x0f) + ((wAttr & 0x0f) << 4);
5768 5924
5769 SetConsoleTextAttribute(g_hConOut, g_attrCurrent); 5925 if (!USE_VTP)
5926 SetConsoleTextAttribute(g_hConOut, g_attrCurrent);
5927 else
5928 vtp_sgr_bulk(wAttr);
5770 } 5929 }
5771 5930
5772 5931
5773 /* 5932 /*
5774 * restore the default text attribute (whatever we started with) 5933 * restore the default text attribute (whatever we started with)
5775 */ 5934 */
5776 static void 5935 static void
5777 normvideo(void) 5936 normvideo(void)
5778 { 5937 {
5779 textattr(g_attrDefault); 5938 if (!USE_VTP)
5939 textattr(g_attrDefault);
5940 else
5941 vtp_sgr_bulk(0);
5780 } 5942 }
5781 5943
5782 5944
5783 static WORD g_attrPreStandout = 0; 5945 static WORD g_attrPreStandout = 0;
5784 5946
5787 */ 5949 */
5788 static void 5950 static void
5789 standout(void) 5951 standout(void)
5790 { 5952 {
5791 g_attrPreStandout = g_attrCurrent; 5953 g_attrPreStandout = g_attrCurrent;
5954
5792 textattr((WORD) (g_attrCurrent|FOREGROUND_INTENSITY|BACKGROUND_INTENSITY)); 5955 textattr((WORD) (g_attrCurrent|FOREGROUND_INTENSITY|BACKGROUND_INTENSITY));
5793 } 5956 }
5794 5957
5795 5958
5796 /* 5959 /*
5798 */ 5961 */
5799 static void 5962 static void
5800 standend(void) 5963 standend(void)
5801 { 5964 {
5802 if (g_attrPreStandout) 5965 if (g_attrPreStandout)
5803 {
5804 textattr(g_attrPreStandout); 5966 textattr(g_attrPreStandout);
5805 g_attrPreStandout = 0; 5967
5806 } 5968 g_attrPreStandout = 0;
5807 } 5969 }
5808 5970
5809 5971
5810 /* 5972 /*
5811 * Set normal fg/bg color, based on T_ME. Called when t_me has been set. 5973 * Set normal fg/bg color, based on T_ME. Called when t_me has been set.
5816 char_u *p; 5978 char_u *p;
5817 int n; 5979 int n;
5818 5980
5819 cterm_normal_fg_color = (g_attrDefault & 0xf) + 1; 5981 cterm_normal_fg_color = (g_attrDefault & 0xf) + 1;
5820 cterm_normal_bg_color = ((g_attrDefault >> 4) & 0xf) + 1; 5982 cterm_normal_bg_color = ((g_attrDefault >> 4) & 0xf) + 1;
5821 if (T_ME[0] == ESC && T_ME[1] == '|') 5983 if (
5984 #ifdef FEAT_TERMGUICOLORS
5985 !p_tgc &&
5986 #endif
5987 T_ME[0] == ESC && T_ME[1] == '|')
5822 { 5988 {
5823 p = T_ME + 2; 5989 p = T_ME + 2;
5824 n = getdigits(&p); 5990 n = getdigits(&p);
5825 if (*p == 'm' && n > 0) 5991 if (*p == 'm' && n > 0)
5826 { 5992 {
5827 cterm_normal_fg_color = (n & 0xf) + 1; 5993 cterm_normal_fg_color = (n & 0xf) + 1;
5828 cterm_normal_bg_color = ((n >> 4) & 0xf) + 1; 5994 cterm_normal_bg_color = ((n >> 4) & 0xf) + 1;
5829 } 5995 }
5830 } 5996 }
5997 #ifdef FEAT_TERMGUICOLORS
5998 cterm_normal_fg_gui_color = INVALCOLOR;
5999 cterm_normal_bg_gui_color = INVALCOLOR;
6000 #endif
5831 } 6001 }
5832 6002
5833 6003
5834 /* 6004 /*
5835 * visual bell: flash the screen 6005 * visual bell: flash the screen
5849 coordOrigin, &dwDummy); 6019 coordOrigin, &dwDummy);
5850 FillConsoleOutputAttribute(g_hConOut, attrFlash, Rows * Columns, 6020 FillConsoleOutputAttribute(g_hConOut, attrFlash, Rows * Columns,
5851 coordOrigin, &dwDummy); 6021 coordOrigin, &dwDummy);
5852 6022
5853 Sleep(15); /* wait for 15 msec */ 6023 Sleep(15); /* wait for 15 msec */
5854 WriteConsoleOutputAttribute(g_hConOut, oldattrs, Rows * Columns, 6024 if (!USE_VTP)
6025 WriteConsoleOutputAttribute(g_hConOut, oldattrs, Rows * Columns,
5855 coordOrigin, &dwDummy); 6026 coordOrigin, &dwDummy);
5856 vim_free(oldattrs); 6027 vim_free(oldattrs);
5857 } 6028 }
5858 6029
5859 6030
5899 } 6070 }
5900 MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)pchBuf, cbToWrite, 6071 MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)pchBuf, cbToWrite,
5901 unicodebuf, unibuflen); 6072 unicodebuf, unibuflen);
5902 6073
5903 cells = mb_string2cells(pchBuf, cbToWrite); 6074 cells = mb_string2cells(pchBuf, cbToWrite);
5904 FillConsoleOutputAttribute(g_hConOut, g_attrCurrent, cells, 6075
5905 coord, &written); 6076 if (!USE_VTP)
5906 /* When writing fails or didn't write a single character, pretend one 6077 {
5907 * character was written, otherwise we get stuck. */ 6078 FillConsoleOutputAttribute(g_hConOut, g_attrCurrent, cells,
5908 if (WriteConsoleOutputCharacterW(g_hConOut, unicodebuf, length, 6079 coord, &written);
5909 coord, &cchwritten) == 0 6080 /* When writing fails or didn't write a single character, pretend one
5910 || cchwritten == 0) 6081 * character was written, otherwise we get stuck. */
5911 cchwritten = 1; 6082 if (WriteConsoleOutputCharacterW(g_hConOut, unicodebuf, length,
6083 coord, &cchwritten) == 0
6084 || cchwritten == 0)
6085 cchwritten = 1;
6086 }
6087 else
6088 {
6089 if (WriteConsoleW(g_hConOut, unicodebuf, length, &cchwritten,
6090 NULL) == 0 || cchwritten == 0)
6091 cchwritten = 1;
6092 }
5912 6093
5913 if (cchwritten == length) 6094 if (cchwritten == length)
5914 { 6095 {
5915 written = cbToWrite; 6096 written = cbToWrite;
5916 g_coord.X += (SHORT)cells; 6097 g_coord.X += (SHORT)cells;
5925 } 6106 }
5926 } 6107 }
5927 else 6108 else
5928 #endif 6109 #endif
5929 { 6110 {
5930 FillConsoleOutputAttribute(g_hConOut, g_attrCurrent, cbToWrite, 6111 if (!USE_VTP)
5931 coord, &written); 6112 {
5932 /* When writing fails or didn't write a single character, pretend one 6113 FillConsoleOutputAttribute(g_hConOut, g_attrCurrent, cbToWrite,
5933 * character was written, otherwise we get stuck. */ 6114 coord, &written);
5934 if (WriteConsoleOutputCharacter(g_hConOut, (LPCSTR)pchBuf, cbToWrite, 6115 /* When writing fails or didn't write a single character, pretend one
5935 coord, &written) == 0 6116 * character was written, otherwise we get stuck. */
5936 || written == 0) 6117 if (WriteConsoleOutputCharacter(g_hConOut, (LPCSTR)pchBuf, cbToWrite,
5937 written = 1; 6118 coord, &written) == 0
6119 || written == 0)
6120 written = 1;
6121 }
6122 else
6123 {
6124 if (WriteConsole(g_hConOut, (LPCSTR)pchBuf, cbToWrite, &written,
6125 NULL) == 0 || written == 0)
6126 written = 1;
6127 }
5938 6128
5939 g_coord.X += (SHORT) written; 6129 g_coord.X += (SHORT) written;
5940 } 6130 }
5941 6131
5942 while (g_coord.X > g_srScrollRegion.Right) 6132 while (g_coord.X > g_srScrollRegion.Right)
6058 { 6248 {
6059 #ifdef MCH_WRITE_DUMP 6249 #ifdef MCH_WRITE_DUMP
6060 char_u *old_s = s; 6250 char_u *old_s = s;
6061 #endif 6251 #endif
6062 char_u *p; 6252 char_u *p;
6063 int arg1 = 0, arg2 = 0; 6253 int arg1 = 0, arg2 = 0, argc = 0, args[16];
6064 6254
6065 switch (s[2]) 6255 switch (s[2])
6066 { 6256 {
6067 /* one or two numeric arguments, separated by ';' */
6068
6069 case '0': case '1': case '2': case '3': case '4': 6257 case '0': case '1': case '2': case '3': case '4':
6070 case '5': case '6': case '7': case '8': case '9': 6258 case '5': case '6': case '7': case '8': case '9':
6071 p = s + 2; 6259 p = s + 1;
6072 arg1 = getdigits(&p); /* no check for length! */ 6260 do
6261 {
6262 ++p;
6263 args[argc] = getdigits(&p);
6264 argc += (argc < 15) ? 1 : 0;
6265 if (p > s + len)
6266 break;
6267 } while (*p == ';');
6268
6073 if (p > s + len) 6269 if (p > s + len)
6074 break; 6270 break;
6075 6271
6076 if (*p == ';') 6272 arg1 = args[0];
6273 arg2 = args[1];
6274 if (*p == 'm')
6077 { 6275 {
6078 ++p; 6276 if (argc == 1 && args[0] == 0)
6079 arg2 = getdigits(&p); /* no check for length! */ 6277 normvideo();
6080 if (p > s + len) 6278 else if (argc == 1)
6081 break; 6279 {
6082 6280 if (USE_VTP)
6083 if (*p == 'H') 6281 textcolor((WORD) arg1);
6084 gotoxy(arg2, arg1); 6282 else
6085 else if (*p == 'r') 6283 textattr((WORD) arg1);
6086 set_scroll_region(0, arg1 - 1, Columns - 1, arg2 - 1); 6284 }
6285 else if (USE_VTP)
6286 vtp_sgr_bulks(argc, args);
6087 } 6287 }
6088 else if (*p == 'A') 6288 else if (argc == 2 && *p == 'H')
6089 { 6289 {
6090 /* move cursor up arg1 lines in same column */ 6290 gotoxy(arg2, arg1);
6291 }
6292 else if (argc == 2 && *p == 'r')
6293 {
6294 set_scroll_region(0, arg1 - 1, Columns - 1, arg2 - 1);
6295 }
6296 else if (argc == 1 && *p == 'A')
6297 {
6091 gotoxy(g_coord.X + 1, 6298 gotoxy(g_coord.X + 1,
6092 max(g_srScrollRegion.Top, g_coord.Y - arg1) + 1); 6299 max(g_srScrollRegion.Top, g_coord.Y - arg1) + 1);
6093 } 6300 }
6094 else if (*p == 'C') 6301 else if (argc == 1 && *p == 'b')
6095 { 6302 {
6096 /* move cursor right arg1 columns in same line */ 6303 textbackground((WORD) arg1);
6304 }
6305 else if (argc == 1 && *p == 'C')
6306 {
6097 gotoxy(min(g_srScrollRegion.Right, g_coord.X + arg1) + 1, 6307 gotoxy(min(g_srScrollRegion.Right, g_coord.X + arg1) + 1,
6098 g_coord.Y + 1); 6308 g_coord.Y + 1);
6099 } 6309 }
6100 else if (*p == 'H') 6310 else if (argc == 1 && *p == 'f')
6311 {
6312 textcolor((WORD) arg1);
6313 }
6314 else if (argc == 1 && *p == 'H')
6101 { 6315 {
6102 gotoxy(1, arg1); 6316 gotoxy(1, arg1);
6103 } 6317 }
6104 else if (*p == 'L') 6318 else if (argc == 1 && *p == 'L')
6105 { 6319 {
6106 insert_lines(arg1); 6320 insert_lines(arg1);
6107 } 6321 }
6108 else if (*p == 'm') 6322 else if (argc == 1 && *p == 'M')
6109 {
6110 if (arg1 == 0)
6111 normvideo();
6112 else
6113 textattr((WORD) arg1);
6114 }
6115 else if (*p == 'f')
6116 {
6117 textcolor((WORD) arg1);
6118 }
6119 else if (*p == 'b')
6120 {
6121 textbackground((WORD) arg1);
6122 }
6123 else if (*p == 'M')
6124 { 6323 {
6125 delete_lines(arg1); 6324 delete_lines(arg1);
6126 } 6325 }
6127 6326
6128 len -= (int)(p - s); 6327 len -= (int)(p - s);
6129 s = p + 1; 6328 s = p + 1;
6130 break; 6329 break;
6131 6330
6132
6133 /* Three-character escape sequences */
6134
6135 case 'A': 6331 case 'A':
6136 /* move cursor up one line in same column */
6137 gotoxy(g_coord.X + 1, 6332 gotoxy(g_coord.X + 1,
6138 max(g_srScrollRegion.Top, g_coord.Y - 1) + 1); 6333 max(g_srScrollRegion.Top, g_coord.Y - 1) + 1);
6139 goto got3; 6334 goto got3;
6140 6335
6141 case 'B': 6336 case 'B':
6142 visual_bell(); 6337 visual_bell();
6143 goto got3; 6338 goto got3;
6144 6339
6145 case 'C': 6340 case 'C':
6146 /* move cursor right one column in same line */
6147 gotoxy(min(g_srScrollRegion.Right, g_coord.X + 1) + 1, 6341 gotoxy(min(g_srScrollRegion.Right, g_coord.X + 1) + 1,
6148 g_coord.Y + 1); 6342 g_coord.Y + 1);
6149 goto got3; 6343 goto got3;
6150 6344
6151 case 'E': 6345 case 'E':
7240 vim_free(envbuf); 7434 vim_free(envbuf);
7241 } 7435 }
7242 7436
7243 return 0; 7437 return 0;
7244 } 7438 }
7439
7440 #ifndef FEAT_GUI_W32
7441
7442 /*
7443 * Support for 256 colors and 24-bit colors was added in Windows 10
7444 * version 1703 (Creators update).
7445 */
7446 # define VTP_FIRST_SUPPORT_BUILD MAKE_VER(10, 0, 15063)
7447
7448 static void
7449 vtp_init(void)
7450 {
7451 DWORD ver, mode;
7452 HMODULE hKerneldll;
7453 DYN_CONSOLE_SCREEN_BUFFER_INFOEX csbi;
7454
7455 ver = get_build_number();
7456 vtp_working = (ver >= VTP_FIRST_SUPPORT_BUILD) ? 1 : 0;
7457 GetConsoleMode(g_hConOut, &mode);
7458 mode |= (ENABLE_PROCESSED_OUTPUT | ENABLE_VIRTUAL_TERMINAL_PROCESSING);
7459 if (SetConsoleMode(g_hConOut, mode) == 0)
7460 vtp_working = 0;
7461
7462 /* Use functions supported from Vista */
7463 hKerneldll = GetModuleHandle("kernel32.dll");
7464 if (hKerneldll != NULL)
7465 {
7466 pGetConsoleScreenBufferInfoEx =
7467 (PfnGetConsoleScreenBufferInfoEx)GetProcAddress(
7468 hKerneldll, "GetConsoleScreenBufferInfoEx");
7469 pSetConsoleScreenBufferInfoEx =
7470 (PfnSetConsoleScreenBufferInfoEx)GetProcAddress(
7471 hKerneldll, "SetConsoleScreenBufferInfoEx");
7472 if (pGetConsoleScreenBufferInfoEx != NULL
7473 && pSetConsoleScreenBufferInfoEx != NULL)
7474 has_csbiex = TRUE;
7475 }
7476
7477 csbi.cbSize = sizeof(csbi);
7478 if (has_csbiex)
7479 pGetConsoleScreenBufferInfoEx(g_hConOut, &csbi);
7480 save_console_bg_rgb = (guicolor_T)csbi.ColorTable[0];
7481 save_console_fg_rgb = (guicolor_T)csbi.ColorTable[7];
7482
7483 set_console_color_rgb();
7484 }
7485
7486 static void
7487 vtp_exit(void)
7488 {
7489 reset_console_color_rgb();
7490 }
7491
7492 static int
7493 vtp_printf(
7494 char *format,
7495 ...)
7496 {
7497 char_u buf[100];
7498 va_list list;
7499 DWORD result;
7500
7501 va_start(list, format);
7502 vim_vsnprintf((char *)buf, 100, (char *)format, list);
7503 va_end(list);
7504 WriteConsoleA(g_hConOut, buf, (DWORD)STRLEN(buf), &result, NULL);
7505 return (int)result;
7506 }
7507
7508 static void
7509 vtp_sgr_bulk(
7510 int arg)
7511 {
7512 int args[1];
7513
7514 args[0] = arg;
7515 vtp_sgr_bulks(1, args);
7516 }
7517
7518 static void
7519 vtp_sgr_bulks(
7520 int argc,
7521 int *args
7522 )
7523 {
7524 /* 2('\033[') + 4('255.') * 16 + NUL */
7525 char_u buf[2 + (4 * 16) + 1];
7526 char_u *p;
7527 int i;
7528
7529 p = buf;
7530 *p++ = '\033';
7531 *p++ = '[';
7532
7533 for (i = 0; i < argc; ++i)
7534 {
7535 p += vim_snprintf((char *)p, 4, "%d", args[i] & 0xff);
7536 *p++ = ';';
7537 }
7538 p--;
7539 *p++ = 'm';
7540 *p = NUL;
7541 vtp_printf((char *)buf);
7542 }
7543
7544 static void
7545 set_console_color_rgb(void)
7546 {
7547 # ifdef FEAT_TERMGUICOLORS
7548 DYN_CONSOLE_SCREEN_BUFFER_INFOEX csbi;
7549 int id;
7550 guicolor_T fg = INVALCOLOR;
7551 guicolor_T bg = INVALCOLOR;
7552
7553 if (!USE_VTP)
7554 return;
7555
7556 id = syn_name2id((char_u *)"Normal");
7557 if (id > 0)
7558 syn_id2colors(id, &fg, &bg);
7559 if (fg == INVALCOLOR)
7560 fg = 0xc0c0c0; /* white text */
7561 if (bg == INVALCOLOR)
7562 bg = 0x000000; /* black background */
7563 fg = (GetRValue(fg) << 16) | (GetGValue(fg) << 8) | GetBValue(fg);
7564 bg = (GetRValue(bg) << 16) | (GetGValue(bg) << 8) | GetBValue(bg);
7565
7566 csbi.cbSize = sizeof(csbi);
7567 if (has_csbiex)
7568 pGetConsoleScreenBufferInfoEx(g_hConOut, &csbi);
7569
7570 csbi.cbSize = sizeof(csbi);
7571 csbi.srWindow.Right += 1;
7572 csbi.srWindow.Bottom += 1;
7573 csbi.ColorTable[0] = (COLORREF)bg;
7574 csbi.ColorTable[7] = (COLORREF)fg;
7575 if (has_csbiex)
7576 pSetConsoleScreenBufferInfoEx(g_hConOut, &csbi);
7577 # endif
7578 }
7579
7580 static void
7581 reset_console_color_rgb(void)
7582 {
7583 # ifdef FEAT_TERMGUICOLORS
7584 DYN_CONSOLE_SCREEN_BUFFER_INFOEX csbi;
7585
7586 csbi.cbSize = sizeof(csbi);
7587 if (has_csbiex)
7588 pGetConsoleScreenBufferInfoEx(g_hConOut, &csbi);
7589
7590 csbi.cbSize = sizeof(csbi);
7591 csbi.srWindow.Right += 1;
7592 csbi.srWindow.Bottom += 1;
7593 csbi.ColorTable[0] = (COLORREF)save_console_bg_rgb;
7594 csbi.ColorTable[7] = (COLORREF)save_console_fg_rgb;
7595 if (has_csbiex)
7596 pSetConsoleScreenBufferInfoEx(g_hConOut, &csbi);
7597 # endif
7598 }
7599
7600 void
7601 control_console_color_rgb(void)
7602 {
7603 if (USE_VTP)
7604 set_console_color_rgb();
7605 else
7606 reset_console_color_rgb();
7607 }
7608
7609 int
7610 has_vtp_working(void)
7611 {
7612 return vtp_working;
7613 }
7614
7615 int
7616 use_vtp(void)
7617 {
7618 return USE_VTP;
7619 }
7620
7621 #endif