comparison src/os_win32.c @ 7080:1a34f5272977 v7.4.852

commit https://github.com/vim/vim/commit/ac360bf2ca293735fc7c6654dc2b3066f4c62488 Author: Bram Moolenaar <Bram@vim.org> Date: Tue Sep 1 20:31:20 2015 +0200 patch 7.4.852 Problem: On MS-Windows console Vim uses ANSI APIs for keyboard input and console output, it cannot input/output Unicode characters. Solution: Use Unicode APIs for console I/O. (Ken Takata, Yasuhiro Matsumoto)
author Christian Brabandt <cb@256bit.org>
date Tue, 01 Sep 2015 20:45:04 +0200
parents 383d6f39669b
children aaf96b1aa605
comparison
equal deleted inserted replaced
7079:1d7d1607be8a 7080:1a34f5272977
211 static void textbackground(WORD wAttr); 211 static void textbackground(WORD wAttr);
212 static void standout(void); 212 static void standout(void);
213 static void standend(void); 213 static void standend(void);
214 static void visual_bell(void); 214 static void visual_bell(void);
215 static void cursor_visible(BOOL fVisible); 215 static void cursor_visible(BOOL fVisible);
216 static BOOL write_chars(LPCSTR pchBuf, DWORD cchToWrite); 216 static DWORD write_chars(char_u *pchBuf, DWORD cbToWrite);
217 static char_u tgetch(int *pmodifiers, char_u *pch2); 217 static WCHAR tgetch(int *pmodifiers, WCHAR *pch2);
218 static void create_conin(void); 218 static void create_conin(void);
219 static int s_cursor_visible = TRUE; 219 static int s_cursor_visible = TRUE;
220 static int did_create_conin = FALSE; 220 static int did_create_conin = FALSE;
221 #else 221 #else
222 static int s_dont_use_vimrun = TRUE; 222 static int s_dont_use_vimrun = TRUE;
263 return (s_dwMax > 0) ? TRUE : FALSE; 263 return (s_dwMax > 0) ? TRUE : FALSE;
264 264
265 if (!win8_or_later) 265 if (!win8_or_later)
266 { 266 {
267 if (nLength == -1) 267 if (nLength == -1)
268 return PeekConsoleInput(hInput, lpBuffer, 1, lpEvents); 268 return PeekConsoleInputW(hInput, lpBuffer, 1, lpEvents);
269 return ReadConsoleInput(hInput, lpBuffer, 1, &dwEvents); 269 return ReadConsoleInputW(hInput, lpBuffer, 1, &dwEvents);
270 } 270 }
271 271
272 if (s_dwMax == 0) 272 if (s_dwMax == 0)
273 { 273 {
274 if (nLength == -1) 274 if (nLength == -1)
275 return PeekConsoleInput(hInput, lpBuffer, 1, lpEvents); 275 return PeekConsoleInputW(hInput, lpBuffer, 1, lpEvents);
276 if (!ReadConsoleInput(hInput, s_irCache, IRSIZE, &dwEvents)) 276 if (!ReadConsoleInputW(hInput, s_irCache, IRSIZE, &dwEvents))
277 return FALSE; 277 return FALSE;
278 s_dwIndex = 0; 278 s_dwIndex = 0;
279 s_dwMax = dwEvents; 279 s_dwMax = dwEvents;
280 if (dwEvents == 0) 280 if (dwEvents == 0)
281 { 281 {
866 # pragma warning(disable: 4748) 866 # pragma warning(disable: 4748)
867 # pragma optimize("", off) 867 # pragma optimize("", off)
868 #endif 868 #endif
869 869
870 #if defined(__GNUC__) && !defined(__MINGW32__) && !defined(__CYGWIN__) 870 #if defined(__GNUC__) && !defined(__MINGW32__) && !defined(__CYGWIN__)
871 # define AChar AsciiChar 871 # define UChar UnicodeChar
872 #else 872 #else
873 # define AChar uChar.AsciiChar 873 # define UChar uChar.UnicodeChar
874 #endif 874 #endif
875 875
876 /* The return code indicates key code size. */ 876 /* The return code indicates key code size. */
877 static int 877 static int
878 #ifdef __BORLANDC__ 878 #ifdef __BORLANDC__
887 static BYTE abKeystate[256]; 887 static BYTE abKeystate[256];
888 888
889 889
890 if (s_iIsDead == 2) 890 if (s_iIsDead == 2)
891 { 891 {
892 pker->AChar = (CHAR) awAnsiCode[1]; 892 pker->UChar = (WCHAR) awAnsiCode[1];
893 s_iIsDead = 0; 893 s_iIsDead = 0;
894 return 1; 894 return 1;
895 } 895 }
896 896
897 if (pker->AChar != 0) 897 if (pker->UChar != 0)
898 return 1; 898 return 1;
899 899
900 vim_memset(abKeystate, 0, sizeof (abKeystate)); 900 vim_memset(abKeystate, 0, sizeof (abKeystate));
901 901
902 // Should only be non-NULL on NT 4.0 902 // Should only be non-NULL on NT 4.0
907 if ((*s_pfnGetConsoleKeyboardLayoutName)(szKLID)) 907 if ((*s_pfnGetConsoleKeyboardLayoutName)(szKLID))
908 (void)LoadKeyboardLayout(szKLID, KLF_ACTIVATE); 908 (void)LoadKeyboardLayout(szKLID, KLF_ACTIVATE);
909 } 909 }
910 910
911 /* Clear any pending dead keys */ 911 /* Clear any pending dead keys */
912 ToAscii(VK_SPACE, MapVirtualKey(VK_SPACE, 0), abKeystate, awAnsiCode, 0); 912 ToUnicode(VK_SPACE, MapVirtualKey(VK_SPACE, 0), abKeystate, awAnsiCode, 2, 0);
913 913
914 if (uMods & SHIFT_PRESSED) 914 if (uMods & SHIFT_PRESSED)
915 abKeystate[VK_SHIFT] = 0x80; 915 abKeystate[VK_SHIFT] = 0x80;
916 if (uMods & CAPSLOCK_ON) 916 if (uMods & CAPSLOCK_ON)
917 abKeystate[VK_CAPITAL] = 1; 917 abKeystate[VK_CAPITAL] = 1;
920 { 920 {
921 abKeystate[VK_CONTROL] = abKeystate[VK_LCONTROL] = 921 abKeystate[VK_CONTROL] = abKeystate[VK_LCONTROL] =
922 abKeystate[VK_MENU] = abKeystate[VK_RMENU] = 0x80; 922 abKeystate[VK_MENU] = abKeystate[VK_RMENU] = 0x80;
923 } 923 }
924 924
925 s_iIsDead = ToAscii(pker->wVirtualKeyCode, pker->wVirtualScanCode, 925 s_iIsDead = ToUnicode(pker->wVirtualKeyCode, pker->wVirtualScanCode,
926 abKeystate, awAnsiCode, 0); 926 abKeystate, awAnsiCode, 2, 0);
927 927
928 if (s_iIsDead > 0) 928 if (s_iIsDead > 0)
929 pker->AChar = (CHAR) awAnsiCode[0]; 929 pker->UChar = (WCHAR) awAnsiCode[0];
930 930
931 return s_iIsDead; 931 return s_iIsDead;
932 } 932 }
933 933
934 #ifdef _MSC_VER 934 #ifdef _MSC_VER
951 * Decode a KEY_EVENT into one or two keystrokes 951 * Decode a KEY_EVENT into one or two keystrokes
952 */ 952 */
953 static BOOL 953 static BOOL
954 decode_key_event( 954 decode_key_event(
955 KEY_EVENT_RECORD *pker, 955 KEY_EVENT_RECORD *pker,
956 char_u *pch, 956 WCHAR *pch,
957 char_u *pch2, 957 WCHAR *pch2,
958 int *pmodifiers, 958 int *pmodifiers,
959 BOOL fDoPost) 959 BOOL fDoPost)
960 { 960 {
961 int i; 961 int i;
962 const int nModifs = pker->dwControlKeyState & (SHIFT | ALT | CTRL); 962 const int nModifs = pker->dwControlKeyState & (SHIFT | ALT | CTRL);
980 default: 980 default:
981 break; 981 break;
982 } 982 }
983 983
984 /* special cases */ 984 /* special cases */
985 if ((nModifs & CTRL) != 0 && (nModifs & ~CTRL) == 0 && pker->AChar == NUL) 985 if ((nModifs & CTRL) != 0 && (nModifs & ~CTRL) == 0 && pker->UChar == NUL)
986 { 986 {
987 /* Ctrl-6 is Ctrl-^ */ 987 /* Ctrl-6 is Ctrl-^ */
988 if (pker->wVirtualKeyCode == '6') 988 if (pker->wVirtualKeyCode == '6')
989 { 989 {
990 *pch = Ctrl_HAT; 990 *pch = Ctrl_HAT;
1042 1042
1043 if (i < 0) 1043 if (i < 0)
1044 *pch = NUL; 1044 *pch = NUL;
1045 else 1045 else
1046 { 1046 {
1047 *pch = (i > 0) ? pker->AChar : NUL; 1047 *pch = (i > 0) ? pker->UChar : NUL;
1048 1048
1049 if (pmodifiers != NULL) 1049 if (pmodifiers != NULL)
1050 { 1050 {
1051 /* Pass on the ALT key as a modifier, but only when not combined 1051 /* Pass on the ALT key as a modifier, but only when not combined
1052 * with CTRL (which is ALTGR). */ 1052 * with CTRL (which is ALTGR). */
1434 WaitForChar(long msec) 1434 WaitForChar(long msec)
1435 { 1435 {
1436 DWORD dwNow = 0, dwEndTime = 0; 1436 DWORD dwNow = 0, dwEndTime = 0;
1437 INPUT_RECORD ir; 1437 INPUT_RECORD ir;
1438 DWORD cRecords; 1438 DWORD cRecords;
1439 char_u ch, ch2; 1439 WCHAR ch, ch2;
1440 1440
1441 if (msec > 0) 1441 if (msec > 0)
1442 /* Wait until the specified time has elapsed. */ 1442 /* Wait until the specified time has elapsed. */
1443 dwEndTime = GetTickCount() + msec; 1443 dwEndTime = GetTickCount() + msec;
1444 else if (msec < 0) 1444 else if (msec < 0)
1521 if (ir.EventType == KEY_EVENT && ir.Event.KeyEvent.bKeyDown) 1521 if (ir.EventType == KEY_EVENT && ir.Event.KeyEvent.bKeyDown)
1522 { 1522 {
1523 #ifdef FEAT_MBYTE_IME 1523 #ifdef FEAT_MBYTE_IME
1524 /* Windows IME sends two '\n's with only one 'ENTER'. First: 1524 /* Windows IME sends two '\n's with only one 'ENTER'. First:
1525 * wVirtualKeyCode == 13. second: wVirtualKeyCode == 0 */ 1525 * wVirtualKeyCode == 13. second: wVirtualKeyCode == 0 */
1526 if (ir.Event.KeyEvent.uChar.UnicodeChar == 0 1526 if (ir.Event.KeyEvent.UChar == 0
1527 && ir.Event.KeyEvent.wVirtualKeyCode == 13) 1527 && ir.Event.KeyEvent.wVirtualKeyCode == 13)
1528 { 1528 {
1529 read_console_input(g_hConIn, &ir, 1, &cRecords); 1529 read_console_input(g_hConIn, &ir, 1, &cRecords);
1530 continue; 1530 continue;
1531 } 1531 }
1584 } 1584 }
1585 1585
1586 /* 1586 /*
1587 * Get a keystroke or a mouse event 1587 * Get a keystroke or a mouse event
1588 */ 1588 */
1589 static char_u 1589 static WCHAR
1590 tgetch(int *pmodifiers, char_u *pch2) 1590 tgetch(int *pmodifiers, WCHAR *pch2)
1591 { 1591 {
1592 char_u ch; 1592 WCHAR ch;
1593 1593
1594 for (;;) 1594 for (;;)
1595 { 1595 {
1596 INPUT_RECORD ir; 1596 INPUT_RECORD ir;
1597 DWORD cRecords = 0; 1597 DWORD cRecords = 0;
1656 int len; 1656 int len;
1657 int c; 1657 int c;
1658 #define TYPEAHEADLEN 20 1658 #define TYPEAHEADLEN 20
1659 static char_u typeahead[TYPEAHEADLEN]; /* previously typed bytes. */ 1659 static char_u typeahead[TYPEAHEADLEN]; /* previously typed bytes. */
1660 static int typeaheadlen = 0; 1660 static int typeaheadlen = 0;
1661 #ifdef FEAT_MBYTE
1662 static char_u *rest = NULL; /* unconverted rest of previous read */
1663 static int restlen = 0;
1664 int unconverted;
1665 #endif
1666 1661
1667 /* First use any typeahead that was kept because "buf" was too small. */ 1662 /* First use any typeahead that was kept because "buf" was too small. */
1668 if (typeaheadlen > 0) 1663 if (typeaheadlen > 0)
1669 goto theend; 1664 goto theend;
1670 1665
1759 g_nMouseClick = -1; 1754 g_nMouseClick = -1;
1760 } 1755 }
1761 else 1756 else
1762 #endif 1757 #endif
1763 { 1758 {
1764 char_u ch2 = NUL; 1759 WCHAR ch2 = NUL;
1765 int modifiers = 0; 1760 int modifiers = 0;
1766 1761
1767 c = tgetch(&modifiers, &ch2); 1762 c = tgetch(&modifiers, &ch2);
1768
1769 #ifdef FEAT_MBYTE
1770 /* stolen from fill_input_buf() in ui.c */
1771 if (rest != NULL)
1772 {
1773 /* Use remainder of previous call, starts with an invalid
1774 * character that may become valid when reading more. */
1775 if (restlen > TYPEAHEADLEN - typeaheadlen)
1776 unconverted = TYPEAHEADLEN - typeaheadlen;
1777 else
1778 unconverted = restlen;
1779 mch_memmove(typeahead + typeaheadlen, rest, unconverted);
1780 if (unconverted == restlen)
1781 {
1782 vim_free(rest);
1783 rest = NULL;
1784 }
1785 else
1786 {
1787 restlen -= unconverted;
1788 mch_memmove(rest, rest + unconverted, restlen);
1789 }
1790 typeaheadlen += unconverted;
1791 }
1792 else
1793 unconverted = 0;
1794 #endif
1795 1763
1796 if (typebuf_changed(tb_change_cnt)) 1764 if (typebuf_changed(tb_change_cnt))
1797 { 1765 {
1798 /* "buf" may be invalid now if a client put something in the 1766 /* "buf" may be invalid now if a client put something in the
1799 * typeahead buffer and "buf" is in the typeahead buffer. */ 1767 * typeahead buffer and "buf" is in the typeahead buffer. */
1814 #endif 1782 #endif
1815 { 1783 {
1816 int n = 1; 1784 int n = 1;
1817 int conv = FALSE; 1785 int conv = FALSE;
1818 1786
1819 typeahead[typeaheadlen] = c; 1787 #ifdef FEAT_MBYTE
1788 if (ch2 == NUL)
1789 {
1790 int i;
1791 char_u *p;
1792 WCHAR ch[2];
1793
1794 ch[0] = c;
1795 if (c >= 0xD800 && c <= 0xDBFF) /* High surrogate */
1796 {
1797 ch[1] = tgetch(&modifiers, &ch2);
1798 n++;
1799 }
1800 p = utf16_to_enc(ch, &n);
1801 if (p != NULL)
1802 {
1803 for (i = 0; i < n; i++)
1804 typeahead[typeaheadlen + i] = p[i];
1805 vim_free(p);
1806 }
1807 }
1808 else
1809 #endif
1810 typeahead[typeaheadlen] = c;
1820 if (ch2 != NUL) 1811 if (ch2 != NUL)
1821 { 1812 {
1822 typeahead[typeaheadlen + 1] = 3; 1813 typeahead[typeaheadlen + n] = 3;
1823 typeahead[typeaheadlen + 2] = ch2; 1814 typeahead[typeaheadlen + n + 1] = (char_u)ch2;
1824 n += 2; 1815 n += 2;
1825 } 1816 }
1826 #ifdef FEAT_MBYTE
1827 /* Only convert normal characters, not special keys. Need to
1828 * convert before applying ALT, otherwise mapping <M-x> breaks
1829 * when 'tenc' is set. */
1830 if (input_conv.vc_type != CONV_NONE
1831 && (ch2 == NUL || c != K_NUL))
1832 {
1833 conv = TRUE;
1834 typeaheadlen -= unconverted;
1835 n = convert_input_safe(typeahead + typeaheadlen,
1836 n + unconverted, TYPEAHEADLEN - typeaheadlen,
1837 rest == NULL ? &rest : NULL, &restlen);
1838 }
1839 #endif
1840 1817
1841 if (conv) 1818 if (conv)
1842 { 1819 {
1843 char_u *p = typeahead + typeaheadlen; 1820 char_u *p = typeahead + typeaheadlen;
1844 1821
5364 #endif 5341 #endif
5365 } 5342 }
5366 5343
5367 5344
5368 /* 5345 /*
5369 * write `cchToWrite' characters in `pchBuf' to the screen 5346 * write `cbToWrite' bytes in `pchBuf' to the screen
5370 * Returns the number of characters actually written (at least one). 5347 * Returns the number of bytes actually written (at least one).
5371 */ 5348 */
5372 static BOOL 5349 static DWORD
5373 write_chars( 5350 write_chars(
5374 LPCSTR pchBuf, 5351 char_u *pchBuf,
5375 DWORD cchToWrite) 5352 DWORD cbToWrite)
5376 { 5353 {
5377 COORD coord = g_coord; 5354 COORD coord = g_coord;
5378 DWORD written; 5355 DWORD written;
5379 5356
5380 FillConsoleOutputAttribute(g_hConOut, g_attrCurrent, cchToWrite, 5357 #ifdef FEAT_MBYTE
5381 coord, &written); 5358 if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
5382 /* When writing fails or didn't write a single character, pretend one 5359 {
5383 * character was written, otherwise we get stuck. */ 5360 static WCHAR *unicodebuf = NULL;
5384 if (WriteConsoleOutputCharacter(g_hConOut, pchBuf, cchToWrite, 5361 static int unibuflen = 0;
5385 coord, &written) == 0 5362 int length;
5386 || written == 0) 5363 DWORD n, cchwritten, cells;
5387 written = 1; 5364
5388 5365 length = MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)pchBuf, cbToWrite, 0, 0);
5389 g_coord.X += (SHORT) written; 5366 if (unicodebuf == NULL || length > unibuflen)
5367 {
5368 vim_free(unicodebuf);
5369 unicodebuf = (WCHAR *)lalloc(length * sizeof(WCHAR), FALSE);
5370 unibuflen = length;
5371 }
5372 MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)pchBuf, cbToWrite,
5373 unicodebuf, unibuflen);
5374
5375 cells = mb_string2cells(pchBuf, cbToWrite);
5376 FillConsoleOutputAttribute(g_hConOut, g_attrCurrent, cells,
5377 coord, &written);
5378 /* When writing fails or didn't write a single character, pretend one
5379 * character was written, otherwise we get stuck. */
5380 if (WriteConsoleOutputCharacterW(g_hConOut, unicodebuf, length,
5381 coord, &cchwritten) == 0
5382 || cchwritten == 0)
5383 cchwritten = 1;
5384
5385 if (cchwritten == length)
5386 {
5387 written = cbToWrite;
5388 g_coord.X += (SHORT)cells;
5389 }
5390 else
5391 {
5392 char_u *p = pchBuf;
5393 for (n = 0; n < cchwritten; n++)
5394 mb_cptr_adv(p);
5395 written = p - pchBuf;
5396 g_coord.X += (SHORT)mb_string2cells(pchBuf, written);
5397 }
5398 }
5399 else
5400 #endif
5401 {
5402 FillConsoleOutputAttribute(g_hConOut, g_attrCurrent, cbToWrite,
5403 coord, &written);
5404 /* When writing fails or didn't write a single character, pretend one
5405 * character was written, otherwise we get stuck. */
5406 if (WriteConsoleOutputCharacter(g_hConOut, (LPCSTR)pchBuf, cbToWrite,
5407 coord, &written) == 0
5408 || written == 0)
5409 written = 1;
5410
5411 g_coord.X += (SHORT) written;
5412 }
5390 5413
5391 while (g_coord.X > g_srScrollRegion.Right) 5414 while (g_coord.X > g_srScrollRegion.Right)
5392 { 5415 {
5393 g_coord.X -= (SHORT) Columns; 5416 g_coord.X -= (SHORT) Columns;
5394 if (g_coord.Y < g_srScrollRegion.Bottom) 5417 if (g_coord.Y < g_srScrollRegion.Bottom)