| To: vim_dev@googlegroups.com |
| Subject: Patch 7.4.852 |
| Fcc: outbox |
| From: Bram Moolenaar <Bram@moolenaar.net> |
| Mime-Version: 1.0 |
| Content-Type: text/plain; charset=UTF-8 |
| Content-Transfer-Encoding: 8bit |
| |
| |
| 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) |
| Files: src/os_win32.c, src/ui.c, runtime/doc/options.txt |
| |
| |
| |
| |
| |
| *** 213,220 **** |
| static void standend(void); |
| static void visual_bell(void); |
| static void cursor_visible(BOOL fVisible); |
| ! static BOOL write_chars(LPCSTR pchBuf, DWORD cchToWrite); |
| ! static char_u tgetch(int *pmodifiers, char_u *pch2); |
| static void create_conin(void); |
| static int s_cursor_visible = TRUE; |
| static int did_create_conin = FALSE; |
| --- 213,220 ---- |
| static void standend(void); |
| static void visual_bell(void); |
| static void cursor_visible(BOOL fVisible); |
| ! static DWORD write_chars(char_u *pchBuf, DWORD cbToWrite); |
| ! static WCHAR tgetch(int *pmodifiers, WCHAR *pch2); |
| static void create_conin(void); |
| static int s_cursor_visible = TRUE; |
| static int did_create_conin = FALSE; |
| |
| *** 265,279 **** |
| if (!win8_or_later) |
| { |
| if (nLength == -1) |
| ! return PeekConsoleInput(hInput, lpBuffer, 1, lpEvents); |
| ! return ReadConsoleInput(hInput, lpBuffer, 1, &dwEvents); |
| } |
| |
| if (s_dwMax == 0) |
| { |
| if (nLength == -1) |
| ! return PeekConsoleInput(hInput, lpBuffer, 1, lpEvents); |
| ! if (!ReadConsoleInput(hInput, s_irCache, IRSIZE, &dwEvents)) |
| return FALSE; |
| s_dwIndex = 0; |
| s_dwMax = dwEvents; |
| --- 265,279 ---- |
| if (!win8_or_later) |
| { |
| if (nLength == -1) |
| ! return PeekConsoleInputW(hInput, lpBuffer, 1, lpEvents); |
| ! return ReadConsoleInputW(hInput, lpBuffer, 1, &dwEvents); |
| } |
| |
| if (s_dwMax == 0) |
| { |
| if (nLength == -1) |
| ! return PeekConsoleInputW(hInput, lpBuffer, 1, lpEvents); |
| ! if (!ReadConsoleInputW(hInput, s_irCache, IRSIZE, &dwEvents)) |
| return FALSE; |
| s_dwIndex = 0; |
| s_dwMax = dwEvents; |
| |
| *** 868,876 **** |
| #endif |
| |
| #if defined(__GNUC__) && !defined(__MINGW32__) && !defined(__CYGWIN__) |
| ! # define AChar AsciiChar |
| #else |
| ! # define AChar uChar.AsciiChar |
| #endif |
| |
| /* The return code indicates key code size. */ |
| --- 868,876 ---- |
| #endif |
| |
| #if defined(__GNUC__) && !defined(__MINGW32__) && !defined(__CYGWIN__) |
| ! # define UChar UnicodeChar |
| #else |
| ! # define UChar uChar.UnicodeChar |
| #endif |
| |
| /* The return code indicates key code size. */ |
| |
| *** 889,900 **** |
| |
| if (s_iIsDead == 2) |
| { |
| ! pker->AChar = (CHAR) awAnsiCode[1]; |
| s_iIsDead = 0; |
| return 1; |
| } |
| |
| ! if (pker->AChar != 0) |
| return 1; |
| |
| vim_memset(abKeystate, 0, sizeof (abKeystate)); |
| --- 889,900 ---- |
| |
| if (s_iIsDead == 2) |
| { |
| ! pker->UChar = (WCHAR) awAnsiCode[1]; |
| s_iIsDead = 0; |
| return 1; |
| } |
| |
| ! if (pker->UChar != 0) |
| return 1; |
| |
| vim_memset(abKeystate, 0, sizeof (abKeystate)); |
| |
| *** 909,915 **** |
| } |
| |
| /* Clear any pending dead keys */ |
| ! ToAscii(VK_SPACE, MapVirtualKey(VK_SPACE, 0), abKeystate, awAnsiCode, 0); |
| |
| if (uMods & SHIFT_PRESSED) |
| abKeystate[VK_SHIFT] = 0x80; |
| --- 909,915 ---- |
| } |
| |
| /* Clear any pending dead keys */ |
| ! ToUnicode(VK_SPACE, MapVirtualKey(VK_SPACE, 0), abKeystate, awAnsiCode, 2, 0); |
| |
| if (uMods & SHIFT_PRESSED) |
| abKeystate[VK_SHIFT] = 0x80; |
| |
| *** 922,932 **** |
| abKeystate[VK_MENU] = abKeystate[VK_RMENU] = 0x80; |
| } |
| |
| ! s_iIsDead = ToAscii(pker->wVirtualKeyCode, pker->wVirtualScanCode, |
| ! abKeystate, awAnsiCode, 0); |
| |
| if (s_iIsDead > 0) |
| ! pker->AChar = (CHAR) awAnsiCode[0]; |
| |
| return s_iIsDead; |
| } |
| --- 922,932 ---- |
| abKeystate[VK_MENU] = abKeystate[VK_RMENU] = 0x80; |
| } |
| |
| ! s_iIsDead = ToUnicode(pker->wVirtualKeyCode, pker->wVirtualScanCode, |
| ! abKeystate, awAnsiCode, 2, 0); |
| |
| if (s_iIsDead > 0) |
| ! pker->UChar = (WCHAR) awAnsiCode[0]; |
| |
| return s_iIsDead; |
| } |
| |
| *** 953,960 **** |
| static BOOL |
| decode_key_event( |
| KEY_EVENT_RECORD *pker, |
| ! char_u *pch, |
| ! char_u *pch2, |
| int *pmodifiers, |
| BOOL fDoPost) |
| { |
| --- 953,960 ---- |
| static BOOL |
| decode_key_event( |
| KEY_EVENT_RECORD *pker, |
| ! WCHAR *pch, |
| ! WCHAR *pch2, |
| int *pmodifiers, |
| BOOL fDoPost) |
| { |
| |
| *** 982,988 **** |
| } |
| |
| /* special cases */ |
| ! if ((nModifs & CTRL) != 0 && (nModifs & ~CTRL) == 0 && pker->AChar == NUL) |
| { |
| /* Ctrl-6 is Ctrl-^ */ |
| if (pker->wVirtualKeyCode == '6') |
| --- 982,988 ---- |
| } |
| |
| /* special cases */ |
| ! if ((nModifs & CTRL) != 0 && (nModifs & ~CTRL) == 0 && pker->UChar == NUL) |
| { |
| /* Ctrl-6 is Ctrl-^ */ |
| if (pker->wVirtualKeyCode == '6') |
| |
| *** 1044,1050 **** |
| *pch = NUL; |
| else |
| { |
| ! *pch = (i > 0) ? pker->AChar : NUL; |
| |
| if (pmodifiers != NULL) |
| { |
| --- 1044,1050 ---- |
| *pch = NUL; |
| else |
| { |
| ! *pch = (i > 0) ? pker->UChar : NUL; |
| |
| if (pmodifiers != NULL) |
| { |
| |
| *** 1436,1442 **** |
| DWORD dwNow = 0, dwEndTime = 0; |
| INPUT_RECORD ir; |
| DWORD cRecords; |
| ! char_u ch, ch2; |
| |
| if (msec > 0) |
| /* Wait until the specified time has elapsed. */ |
| --- 1436,1442 ---- |
| DWORD dwNow = 0, dwEndTime = 0; |
| INPUT_RECORD ir; |
| DWORD cRecords; |
| ! WCHAR ch, ch2; |
| |
| if (msec > 0) |
| /* Wait until the specified time has elapsed. */ |
| |
| *** 1523,1529 **** |
| #ifdef FEAT_MBYTE_IME |
| /* Windows IME sends two '\n's with only one 'ENTER'. First: |
| * wVirtualKeyCode == 13. second: wVirtualKeyCode == 0 */ |
| ! if (ir.Event.KeyEvent.uChar.UnicodeChar == 0 |
| && ir.Event.KeyEvent.wVirtualKeyCode == 13) |
| { |
| read_console_input(g_hConIn, &ir, 1, &cRecords); |
| --- 1523,1529 ---- |
| #ifdef FEAT_MBYTE_IME |
| /* Windows IME sends two '\n's with only one 'ENTER'. First: |
| * wVirtualKeyCode == 13. second: wVirtualKeyCode == 0 */ |
| ! if (ir.Event.KeyEvent.UChar == 0 |
| && ir.Event.KeyEvent.wVirtualKeyCode == 13) |
| { |
| read_console_input(g_hConIn, &ir, 1, &cRecords); |
| |
| *** 1586,1595 **** |
| /* |
| * Get a keystroke or a mouse event |
| */ |
| ! static char_u |
| ! tgetch(int *pmodifiers, char_u *pch2) |
| { |
| ! char_u ch; |
| |
| for (;;) |
| { |
| --- 1586,1595 ---- |
| /* |
| * Get a keystroke or a mouse event |
| */ |
| ! static WCHAR |
| ! tgetch(int *pmodifiers, WCHAR *pch2) |
| { |
| ! WCHAR ch; |
| |
| for (;;) |
| { |
| |
| *** 1658,1668 **** |
| #define TYPEAHEADLEN 20 |
| static char_u typeahead[TYPEAHEADLEN]; /* previously typed bytes. */ |
| static int typeaheadlen = 0; |
| - #ifdef FEAT_MBYTE |
| - static char_u *rest = NULL; /* unconverted rest of previous read */ |
| - static int restlen = 0; |
| - int unconverted; |
| - #endif |
| |
| /* First use any typeahead that was kept because "buf" was too small. */ |
| if (typeaheadlen > 0) |
| --- 1658,1663 ---- |
| |
| *** 1761,1798 **** |
| else |
| #endif |
| { |
| ! char_u ch2 = NUL; |
| int modifiers = 0; |
| |
| c = tgetch(&modifiers, &ch2); |
| |
| - #ifdef FEAT_MBYTE |
| - /* stolen from fill_input_buf() in ui.c */ |
| - if (rest != NULL) |
| - { |
| - /* Use remainder of previous call, starts with an invalid |
| - * character that may become valid when reading more. */ |
| - if (restlen > TYPEAHEADLEN - typeaheadlen) |
| - unconverted = TYPEAHEADLEN - typeaheadlen; |
| - else |
| - unconverted = restlen; |
| - mch_memmove(typeahead + typeaheadlen, rest, unconverted); |
| - if (unconverted == restlen) |
| - { |
| - vim_free(rest); |
| - rest = NULL; |
| - } |
| - else |
| - { |
| - restlen -= unconverted; |
| - mch_memmove(rest, rest + unconverted, restlen); |
| - } |
| - typeaheadlen += unconverted; |
| - } |
| - else |
| - unconverted = 0; |
| - #endif |
| - |
| if (typebuf_changed(tb_change_cnt)) |
| { |
| /* "buf" may be invalid now if a client put something in the |
| --- 1756,1766 ---- |
| else |
| #endif |
| { |
| ! WCHAR ch2 = NUL; |
| int modifiers = 0; |
| |
| c = tgetch(&modifiers, &ch2); |
| |
| if (typebuf_changed(tb_change_cnt)) |
| { |
| /* "buf" may be invalid now if a client put something in the |
| |
| *** 1816,1842 **** |
| int n = 1; |
| int conv = FALSE; |
| |
| - typeahead[typeaheadlen] = c; |
| - if (ch2 != NUL) |
| - { |
| - typeahead[typeaheadlen + 1] = 3; |
| - typeahead[typeaheadlen + 2] = ch2; |
| - n += 2; |
| - } |
| #ifdef FEAT_MBYTE |
| ! /* Only convert normal characters, not special keys. Need to |
| ! * convert before applying ALT, otherwise mapping <M-x> breaks |
| ! * when 'tenc' is set. */ |
| ! if (input_conv.vc_type != CONV_NONE |
| ! && (ch2 == NUL || c != K_NUL)) |
| { |
| ! conv = TRUE; |
| ! typeaheadlen -= unconverted; |
| ! n = convert_input_safe(typeahead + typeaheadlen, |
| ! n + unconverted, TYPEAHEADLEN - typeaheadlen, |
| ! rest == NULL ? &rest : NULL, &restlen); |
| } |
| #endif |
| |
| if (conv) |
| { |
| --- 1784,1819 ---- |
| int n = 1; |
| int conv = FALSE; |
| |
| #ifdef FEAT_MBYTE |
| ! if (ch2 == NUL) |
| { |
| ! int i; |
| ! char_u *p; |
| ! WCHAR ch[2]; |
| ! |
| ! ch[0] = c; |
| ! if (c >= 0xD800 && c <= 0xDBFF) /* High surrogate */ |
| ! { |
| ! ch[1] = tgetch(&modifiers, &ch2); |
| ! n++; |
| ! } |
| ! p = utf16_to_enc(ch, &n); |
| ! if (p != NULL) |
| ! { |
| ! for (i = 0; i < n; i++) |
| ! typeahead[typeaheadlen + i] = p[i]; |
| ! vim_free(p); |
| ! } |
| } |
| + else |
| #endif |
| + typeahead[typeaheadlen] = c; |
| + if (ch2 != NUL) |
| + { |
| + typeahead[typeaheadlen + n] = 3; |
| + typeahead[typeaheadlen + n + 1] = (char_u)ch2; |
| + n += 2; |
| + } |
| |
| if (conv) |
| { |
| |
| *** 5366,5392 **** |
| |
| |
| /* |
| ! * write `cchToWrite' characters in `pchBuf' to the screen |
| ! * Returns the number of characters actually written (at least one). |
| */ |
| ! static BOOL |
| write_chars( |
| ! LPCSTR pchBuf, |
| ! DWORD cchToWrite) |
| { |
| COORD coord = g_coord; |
| DWORD written; |
| |
| ! FillConsoleOutputAttribute(g_hConOut, g_attrCurrent, cchToWrite, |
| ! coord, &written); |
| ! /* When writing fails or didn't write a single character, pretend one |
| ! * character was written, otherwise we get stuck. */ |
| ! if (WriteConsoleOutputCharacter(g_hConOut, pchBuf, cchToWrite, |
| ! coord, &written) == 0 |
| ! || written == 0) |
| ! written = 1; |
| |
| ! g_coord.X += (SHORT) written; |
| |
| while (g_coord.X > g_srScrollRegion.Right) |
| { |
| --- 5343,5415 ---- |
| |
| |
| /* |
| ! * write `cbToWrite' bytes in `pchBuf' to the screen |
| ! * Returns the number of bytes actually written (at least one). |
| */ |
| ! static DWORD |
| write_chars( |
| ! char_u *pchBuf, |
| ! DWORD cbToWrite) |
| { |
| COORD coord = g_coord; |
| DWORD written; |
| |
| ! #ifdef FEAT_MBYTE |
| ! if (enc_codepage >= 0 && (int)GetACP() != enc_codepage) |
| ! { |
| ! static WCHAR *unicodebuf = NULL; |
| ! static int unibuflen = 0; |
| ! int length; |
| ! DWORD n, cchwritten, cells; |
| ! |
| ! length = MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)pchBuf, cbToWrite, 0, 0); |
| ! if (unicodebuf == NULL || length > unibuflen) |
| ! { |
| ! vim_free(unicodebuf); |
| ! unicodebuf = (WCHAR *)lalloc(length * sizeof(WCHAR), FALSE); |
| ! unibuflen = length; |
| ! } |
| ! MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)pchBuf, cbToWrite, |
| ! unicodebuf, unibuflen); |
| ! |
| ! cells = mb_string2cells(pchBuf, cbToWrite); |
| ! FillConsoleOutputAttribute(g_hConOut, g_attrCurrent, cells, |
| ! coord, &written); |
| ! /* When writing fails or didn't write a single character, pretend one |
| ! * character was written, otherwise we get stuck. */ |
| ! if (WriteConsoleOutputCharacterW(g_hConOut, unicodebuf, length, |
| ! coord, &cchwritten) == 0 |
| ! || cchwritten == 0) |
| ! cchwritten = 1; |
| ! |
| ! if (cchwritten == length) |
| ! { |
| ! written = cbToWrite; |
| ! g_coord.X += (SHORT)cells; |
| ! } |
| ! else |
| ! { |
| ! char_u *p = pchBuf; |
| ! for (n = 0; n < cchwritten; n++) |
| ! mb_cptr_adv(p); |
| ! written = p - pchBuf; |
| ! g_coord.X += (SHORT)mb_string2cells(pchBuf, written); |
| ! } |
| ! } |
| ! else |
| ! #endif |
| ! { |
| ! FillConsoleOutputAttribute(g_hConOut, g_attrCurrent, cbToWrite, |
| ! coord, &written); |
| ! /* When writing fails or didn't write a single character, pretend one |
| ! * character was written, otherwise we get stuck. */ |
| ! if (WriteConsoleOutputCharacter(g_hConOut, (LPCSTR)pchBuf, cbToWrite, |
| ! coord, &written) == 0 |
| ! || written == 0) |
| ! written = 1; |
| |
| ! g_coord.X += (SHORT) written; |
| ! } |
| |
| while (g_coord.X > g_srScrollRegion.Right) |
| { |
| |
| |
| |
| *** 42,48 **** |
| /* Don't output anything in silent mode ("ex -s") unless 'verbose' set */ |
| if (!(silent_mode && p_verbose == 0)) |
| { |
| ! #ifdef FEAT_MBYTE |
| char_u *tofree = NULL; |
| |
| if (output_conv.vc_type != CONV_NONE) |
| --- 42,48 ---- |
| /* Don't output anything in silent mode ("ex -s") unless 'verbose' set */ |
| if (!(silent_mode && p_verbose == 0)) |
| { |
| ! #if defined(FEAT_MBYTE) && !defined(WIN3264) |
| char_u *tofree = NULL; |
| |
| if (output_conv.vc_type != CONV_NONE) |
| |
| *** 56,62 **** |
| |
| mch_write(s, len); |
| |
| ! #ifdef FEAT_MBYTE |
| if (output_conv.vc_type != CONV_NONE) |
| vim_free(tofree); |
| #endif |
| --- 56,62 ---- |
| |
| mch_write(s, len); |
| |
| ! #if defined(FEAT_MBYTE) && !defined(WIN3264) |
| if (output_conv.vc_type != CONV_NONE) |
| vim_free(tofree); |
| #endif |
| |
| |
| |
| *** 7377,7390 **** |
| the GUI it only applies to the keyboard ( 'encoding' is used for the |
| display). Except for the Mac when 'macatsui' is off, then |
| 'termencoding' should be "macroman". |
| - In the Win32 console version the default value is the console codepage |
| - when it differs from the ANSI codepage. |
| *E617* |
| Note: This does not apply to the GTK+ 2 GUI. After the GUI has been |
| successfully initialized, 'termencoding' is forcibly set to "utf-8". |
| Any attempts to set a different value will be rejected, and an error |
| message is shown. |
| ! For the Win32 GUI 'termencoding' is not used for typed characters, |
| because the Win32 system always passes Unicode characters. |
| When empty, the same encoding is used as for the 'encoding' option. |
| This is the normal value. |
| --- 7396,7407 ---- |
| the GUI it only applies to the keyboard ( 'encoding' is used for the |
| display). Except for the Mac when 'macatsui' is off, then |
| 'termencoding' should be "macroman". |
| *E617* |
| Note: This does not apply to the GTK+ 2 GUI. After the GUI has been |
| successfully initialized, 'termencoding' is forcibly set to "utf-8". |
| Any attempts to set a different value will be rejected, and an error |
| message is shown. |
| ! For the Win32 GUI and console versions 'termencoding' is not used, |
| because the Win32 system always passes Unicode characters. |
| When empty, the same encoding is used as for the 'encoding' option. |
| This is the normal value. |
| |
| |
| |
| *** 743,744 **** |
| --- 743,746 ---- |
| { /* Add new patch number below this line */ |
| + /**/ |
| + 852, |
| /**/ |
| |
| -- |
| (letter from Mark to Mike, about the film's probable certificate) |
| I would like to get back to the Censor and agree to lose the shits, take |
| the odd Jesus Christ out and lose Oh fuck off, but to retain 'fart in |
| your general direction', 'castanets of your testicles' and 'oral sex' |
| and ask him for an 'A' rating on that basis. |
| "Monty Python and the Holy Grail" PYTHON (MONTY) PICTURES LTD |
| |
| /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ |
| /// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\ |
| \\\ an exciting new programming language -- http://www.Zimbu.org /// |
| \\\ help me help AIDS victims -- http://ICCF-Holland.org /// |