From 01bd1b0df605d644ae31e8f1f81d926a5d8c7099 Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Sat, 28 Jul 2012 19:57:57 +0300 Subject: [PATCH] Fix non-ASCII input in non-GUI frames on MS-Windows. (Bug#12055) src/w32inevt.c: Include w32inevt.h. (w32_read_console_input): New inline function, calls either ReadConsoleInputA or ReadConsoleInputW, depending on the value of w32_console_unicode_input. (fill_queue): Call w32_read_console_input instead of ReadConsoleInput. (w32_kbd_patch_key, key_event): Use the codepage returned by GetConsoleCP, rather than the ANSI codepage returned by GetLocaleInfo. (key_event): use uChar.UnicodeChar only if w32_console_unicode_input is non-zero. src/w32console.c: Include w32heap.h. : New global variable. (initialize_w32_display): Set w32_console_unicode_input to 1 on NT family of Windows, zero otherwise. src/w32inevt.h: Declare w32_console_unicode_input. lisp/international/mule-cmds.el (set-locale-environment): In a console session on MS-Windows, set up keyboard and terminal encoding from the OEM codepage, not the ANSI codepage. --- lisp/ChangeLog | 7 +++++ lisp/international/mule-cmds.el | 41 +++++++++++++++++------------ src/ChangeLog | 18 +++++++++++++ src/w32console.c | 7 +++++ src/w32inevt.c | 46 +++++++++++++++++++++------------ src/w32inevt.h | 2 ++ 6 files changed, 89 insertions(+), 32 deletions(-) diff --git a/lisp/ChangeLog b/lisp/ChangeLog index 24477cf87e..7d69eefc86 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog @@ -1,3 +1,10 @@ +2012-07-28 Eli Zaretskii + + * international/mule-cmds.el (set-locale-environment): In a + console session on MS-Windows, set up keyboard and terminal + encoding from the OEM codepage, not the ANSI codepage. + (Bug#12055) + 2012-07-28 Chong Yidong * progmodes/gdb-mi.el (gdb-place-breakpoints): Fix the call to diff --git a/lisp/international/mule-cmds.el b/lisp/international/mule-cmds.el index 93c0cbf47f..b122721c96 100644 --- a/lisp/international/mule-cmds.el +++ b/lisp/international/mule-cmds.el @@ -2655,23 +2655,32 @@ See also `locale-charset-language-names', `locale-language-names', ;; On Windows, override locale-coding-system, ;; default-file-name-coding-system, keyboard-coding-system, - ;; terminal-coding-system with system codepage. + ;; terminal-coding-system with the appropriate codepages. (when (boundp 'w32-ansi-code-page) - (let ((code-page-coding (intern (format "cp%d" w32-ansi-code-page)))) - (when (coding-system-p code-page-coding) - (unless frame (setq locale-coding-system code-page-coding)) - (set-keyboard-coding-system code-page-coding frame) - (set-terminal-coding-system code-page-coding frame) - ;; Set default-file-name-coding-system last, so that Emacs - ;; doesn't try to use cpNNNN when it defines keyboard and - ;; terminal encoding. That's because the above two lines - ;; will want to load code-pages.el, where cpNNNN are - ;; defined; if default-file-name-coding-system were set to - ;; cpNNNN while these two lines run, Emacs will want to use - ;; it for encoding the file name it wants to load. And that - ;; will fail, since cpNNNN is not yet usable until - ;; code-pages.el finishes loading. - (setq default-file-name-coding-system code-page-coding)))) + (let ((ansi-code-page-coding (intern (format "cp%d" w32-ansi-code-page))) + (oem-code-page-coding + (intern (format "cp%d" (w32-get-console-codepage)))) + (oem-code-page-output-coding + (intern (format "cp%d" (w32-get-console-output-codepage)))) + ansi-cs-p oem-cs-p oem-o-cs-p) + (setq ansi-cs-p (coding-system-p ansi-code-page-coding)) + (setq oem-cs-p (coding-system-p oem-code-page-coding)) + (setq oem-o-cs-p (coding-system-p oem-code-page-output-coding)) + ;; Set the keyboard and display encoding to either the current + ;; ANSI codepage of the OEM codepage, depending on whether + ;; this is a GUI or a TTY frame. + (when ansi-cs-p + (unless frame (setq locale-coding-system ansi-code-page-coding)) + (when (display-graphic-p frame) + (set-keyboard-coding-system ansi-code-page-coding frame) + (set-terminal-coding-system ansi-code-page-coding frame)) + (setq default-file-name-coding-system ansi-code-page-coding)) + (when oem-cs-p + (unless (display-graphic-p frame) + (set-keyboard-coding-system oem-code-page-coding frame) + (set-terminal-coding-system + (if oem-o-cs-p oem-code-page-output-coding oem-code-page-coding) + frame))))) (when (eq system-type 'darwin) ;; On Darwin, file names are always encoded in utf-8, no matter diff --git a/src/ChangeLog b/src/ChangeLog index 8d0e7caf4e..6457fc2209 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,5 +1,23 @@ 2012-07-28 Eli Zaretskii + Fix non-ASCII input in non-GUI frames on MS-Windows. (Bug#12055) + * w32inevt.c: Include w32inevt.h. + (w32_read_console_input): New inline function, calls either + ReadConsoleInputA or ReadConsoleInputW, depending on the value of + w32_console_unicode_input. + (fill_queue): Call w32_read_console_input instead of ReadConsoleInput. + (w32_kbd_patch_key, key_event): Use the codepage returned by + GetConsoleCP, rather than the ANSI codepage returned by GetLocaleInfo. + (key_event): use uChar.UnicodeChar only if + w32_console_unicode_input is non-zero. + + * w32console.c: Include w32heap.h. + : New global variable. + (initialize_w32_display): Set w32_console_unicode_input to 1 on NT + family of Windows, zero otherwise. + + * w32inevt.h: Declare w32_console_unicode_input. + * xdisp.c (init_iterator): Don't reference tip_frame in a build --without-x. (Bug#11742) diff --git a/src/w32console.c b/src/w32console.c index 42d89cca6d..c3a1c5d86b 100644 --- a/src/w32console.c +++ b/src/w32console.c @@ -37,6 +37,7 @@ along with GNU Emacs. If not, see . */ #include "termhooks.h" #include "termchar.h" #include "dispextern.h" +#include "w32heap.h" /* for os_subtype */ #include "w32inevt.h" /* from window.c */ @@ -67,6 +68,7 @@ static CONSOLE_CURSOR_INFO prev_console_cursor; #endif HANDLE keyboard_handle; +int w32_console_unicode_input; /* Setting this as the ctrl handler prevents emacs from being killed when @@ -786,6 +788,11 @@ initialize_w32_display (struct terminal *term) info.srWindow.Left); } + if (os_subtype == OS_NT) + w32_console_unicode_input = 1; + else + w32_console_unicode_input = 0; + /* Setup w32_display_info structure for this frame. */ w32_initialize_display_info (build_string ("Console")); diff --git a/src/w32inevt.c b/src/w32inevt.c index a85fdbbe43..8d041194ca 100644 --- a/src/w32inevt.c +++ b/src/w32inevt.c @@ -41,6 +41,7 @@ along with GNU Emacs. If not, see . */ #include "termchar.h" #include "w32heap.h" #include "w32term.h" +#include "w32inevt.h" /* stdin, from w32console.c */ extern HANDLE keyboard_handle; @@ -61,6 +62,15 @@ static INPUT_RECORD *queue_ptr = event_queue, *queue_end = event_queue; /* Temporarily store lead byte of DBCS input sequences. */ static char dbcs_lead = 0; +static inline BOOL +w32_read_console_input (HANDLE h, INPUT_RECORD *rec, DWORD recsize, + DWORD *waiting) +{ + return (w32_console_unicode_input + ? ReadConsoleInputW (h, rec, recsize, waiting) + : ReadConsoleInputA (h, rec, recsize, waiting)); +} + static int fill_queue (BOOL block) { @@ -80,8 +90,8 @@ fill_queue (BOOL block) return 0; } - rc = ReadConsoleInput (keyboard_handle, event_queue, EVENT_QUEUE_SIZE, - &events_waiting); + rc = w32_read_console_input (keyboard_handle, event_queue, EVENT_QUEUE_SIZE, + &events_waiting); if (!rc) return -1; queue_ptr = event_queue; @@ -224,7 +234,7 @@ w32_kbd_patch_key (KEY_EVENT_RECORD *event) #endif /* On NT, call ToUnicode instead and then convert to the current - locale's default codepage. */ + console input codepage. */ if (os_subtype == OS_NT) { WCHAR buf[128]; @@ -233,14 +243,9 @@ w32_kbd_patch_key (KEY_EVENT_RECORD *event) keystate, buf, 128, 0); if (isdead > 0) { - char cp[20]; - int cpId; + int cpId = GetConsoleCP (); event->uChar.UnicodeChar = buf[isdead - 1]; - - GetLocaleInfo (GetThreadLocale (), - LOCALE_IDEFAULTANSICODEPAGE, cp, 20); - cpId = atoi (cp); isdead = WideCharToMultiByte (cpId, 0, buf, isdead, ansi_code, 4, NULL, NULL); } @@ -447,26 +452,34 @@ key_event (KEY_EVENT_RECORD *event, struct input_event *emacs_ev, int *isdead) } else if (event->uChar.AsciiChar > 0) { + /* Pure ASCII characters < 128. */ emacs_ev->kind = ASCII_KEYSTROKE_EVENT; emacs_ev->code = event->uChar.AsciiChar; } - else if (event->uChar.UnicodeChar > 0) + else if (event->uChar.UnicodeChar > 0 + && w32_console_unicode_input) { + /* Unicode codepoint; only valid if we are using Unicode + console input mode. */ emacs_ev->kind = MULTIBYTE_CHAR_KEYSTROKE_EVENT; emacs_ev->code = event->uChar.UnicodeChar; } else { - /* Fallback for non-Unicode versions of Windows. */ + /* Fallback handling of non-ASCII characters for non-Unicode + versions of Windows, and for non-Unicode input on NT + family of Windows. Only characters in the current + console codepage are supported by this fallback. */ wchar_t code; char dbcs[2]; - char cp[20]; int cpId; - /* Get the codepage to interpret this key with. */ - GetLocaleInfo (GetThreadLocale (), - LOCALE_IDEFAULTANSICODEPAGE, cp, 20); - cpId = atoi (cp); + /* Get the current console input codepage to interpret this + key with. Note that the system defaults for the OEM + codepage could have been changed by calling SetConsoleCP + or w32-set-console-codepage, so using GetLocaleInfo to + get LOCALE_IDEFAULTCODEPAGE is not TRT here. */ + cpId = GetConsoleCP (); dbcs[0] = dbcs_lead; dbcs[1] = event->uChar.AsciiChar; @@ -501,6 +514,7 @@ key_event (KEY_EVENT_RECORD *event, struct input_event *emacs_ev, int *isdead) } else { + /* Function keys and other non-character keys. */ emacs_ev->kind = NON_ASCII_KEYSTROKE_EVENT; emacs_ev->code = event->wVirtualKeyCode; } diff --git a/src/w32inevt.h b/src/w32inevt.h index d228637abf..5386f2aa96 100644 --- a/src/w32inevt.h +++ b/src/w32inevt.h @@ -19,6 +19,8 @@ along with GNU Emacs. If not, see . */ #ifndef EMACS_W32INEVT_H #define EMACS_W32INEVT_H +extern int w32_console_unicode_input; + extern int w32_console_read_socket (struct terminal *term, int numchars, struct input_event *hold_quit); extern void w32_console_mouse_position (FRAME_PTR *f, int insist, -- 2.20.1