mirror of
https://github.com/reactos/reactos.git
synced 2025-08-06 02:43:09 +00:00
[KERNEL32][CONSRV] Retrieve the best-suited language ID corresponding to the active console output code page. (#4301)
CORE-17601, CORE-17803 Replaces PR #4281. Implement SrvGetConsoleLangId() (server-side) and set the new current thread's locale after connecting to a console, or changing its output code page. Based on API tracing on Windows 2003, as well as on comments and code gathered from: https://github.com/microsoft/terminal Tests results are listed in PR #4301.
This commit is contained in:
parent
ba516ff0f5
commit
3e44a5d71c
6 changed files with 131 additions and 18 deletions
|
@ -1375,8 +1375,6 @@ AllocConsole(VOID)
|
||||||
ULONG AppNameLength = 128 * sizeof(WCHAR);
|
ULONG AppNameLength = 128 * sizeof(WCHAR);
|
||||||
ULONG CurDirLength = (MAX_PATH + 1) * sizeof(WCHAR);
|
ULONG CurDirLength = (MAX_PATH + 1) * sizeof(WCHAR);
|
||||||
|
|
||||||
LCID lcid;
|
|
||||||
|
|
||||||
RtlEnterCriticalSection(&ConsoleLock);
|
RtlEnterCriticalSection(&ConsoleLock);
|
||||||
|
|
||||||
if (NtCurrentPeb()->ProcessParameters->ConsoleHandle)
|
if (NtCurrentPeb()->ProcessParameters->ConsoleHandle)
|
||||||
|
@ -1427,8 +1425,8 @@ AllocConsole(VOID)
|
||||||
/* Initialize Console Ctrl Handling */
|
/* Initialize Console Ctrl Handling */
|
||||||
InitializeCtrlHandling();
|
InitializeCtrlHandling();
|
||||||
|
|
||||||
/* Sets the current console locale for this thread */
|
/* Sync the current thread's LangId with the console's one */
|
||||||
SetTEBLangID(lcid);
|
SetTEBLangID();
|
||||||
}
|
}
|
||||||
|
|
||||||
Quit:
|
Quit:
|
||||||
|
@ -2500,6 +2498,9 @@ SetConsoleOutputCP(UINT wCodePageID)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Sync the current thread's LangId with the console's one */
|
||||||
|
SetTEBLangID();
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2676,9 +2677,7 @@ AttachConsole(DWORD dwProcessId)
|
||||||
{
|
{
|
||||||
BOOL Success;
|
BOOL Success;
|
||||||
CONSOLE_START_INFO ConsoleStartInfo;
|
CONSOLE_START_INFO ConsoleStartInfo;
|
||||||
|
|
||||||
DWORD dummy;
|
DWORD dummy;
|
||||||
LCID lcid;
|
|
||||||
|
|
||||||
RtlEnterCriticalSection(&ConsoleLock);
|
RtlEnterCriticalSection(&ConsoleLock);
|
||||||
|
|
||||||
|
@ -2711,8 +2710,8 @@ AttachConsole(DWORD dwProcessId)
|
||||||
/* Initialize Console Ctrl Handling */
|
/* Initialize Console Ctrl Handling */
|
||||||
InitializeCtrlHandling();
|
InitializeCtrlHandling();
|
||||||
|
|
||||||
/* Sets the current console locale for this thread */
|
/* Sync the current thread's LangId with the console's one */
|
||||||
SetTEBLangID(lcid);
|
SetTEBLangID();
|
||||||
}
|
}
|
||||||
|
|
||||||
Quit:
|
Quit:
|
||||||
|
@ -3067,6 +3066,48 @@ UnregisterConsoleIME(VOID)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief
|
||||||
|
* Internal helper function used to synchronize the current
|
||||||
|
* thread's language ID with the one from the console.
|
||||||
|
**/
|
||||||
|
VOID
|
||||||
|
SetTEBLangID(VOID)
|
||||||
|
{
|
||||||
|
CONSOLE_API_MESSAGE ApiMessage;
|
||||||
|
PCONSOLE_GETLANGID LangIdRequest = &ApiMessage.Data.LangIdRequest;
|
||||||
|
|
||||||
|
/* Retrieve the "best-suited" language ID corresponding
|
||||||
|
* to the active console output code page. */
|
||||||
|
LangIdRequest->ConsoleHandle = NtCurrentPeb()->ProcessParameters->ConsoleHandle;
|
||||||
|
|
||||||
|
CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage,
|
||||||
|
NULL,
|
||||||
|
CSR_CREATE_API_NUMBER(CONSRV_SERVERDLL_INDEX, ConsolepGetLangId),
|
||||||
|
sizeof(*LangIdRequest));
|
||||||
|
if (!NT_SUCCESS(ApiMessage.Status))
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* No best console language ID: keep the current thread's one.
|
||||||
|
* Since this internal function only modifies an optional setting,
|
||||||
|
* don't set any last error, as it could otherwise mess with the
|
||||||
|
* main last error set by the caller.
|
||||||
|
*/
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We succeeded, set the current thread's language ID by
|
||||||
|
* modifying its locale -- Windows <= 2003 does not have
|
||||||
|
* the concept of a separate thread UI language.
|
||||||
|
* Ignore the returned value.
|
||||||
|
*/
|
||||||
|
if (!SetThreadLocale(MAKELCID(LangIdRequest->LangId, SORT_DEFAULT)))
|
||||||
|
{
|
||||||
|
DPRINT1("SetTEBLangID: Could not set thread locale to console lang ID %lu\n",
|
||||||
|
LangIdRequest->LangId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
BOOL
|
BOOL
|
||||||
|
|
|
@ -342,14 +342,13 @@ ConDllInitialize(IN ULONG Reason,
|
||||||
PRTL_USER_PROCESS_PARAMETERS Parameters = NtCurrentPeb()->ProcessParameters;
|
PRTL_USER_PROCESS_PARAMETERS Parameters = NtCurrentPeb()->ProcessParameters;
|
||||||
BOOLEAN InServerProcess = FALSE;
|
BOOLEAN InServerProcess = FALSE;
|
||||||
CONSRV_API_CONNECTINFO ConnectInfo;
|
CONSRV_API_CONNECTINFO ConnectInfo;
|
||||||
LCID lcid;
|
|
||||||
|
|
||||||
if (Reason != DLL_PROCESS_ATTACH)
|
if (Reason != DLL_PROCESS_ATTACH)
|
||||||
{
|
{
|
||||||
if ((Reason == DLL_THREAD_ATTACH) && IsConsoleApp())
|
if ((Reason == DLL_THREAD_ATTACH) && IsConsoleApp())
|
||||||
{
|
{
|
||||||
/* Sets the current console locale for the new thread */
|
/* Sync the new thread's LangId with the console's one */
|
||||||
SetTEBLangID(lcid);
|
SetTEBLangID();
|
||||||
}
|
}
|
||||||
else if (Reason == DLL_PROCESS_DETACH)
|
else if (Reason == DLL_PROCESS_DETACH)
|
||||||
{
|
{
|
||||||
|
@ -522,8 +521,8 @@ ConDllInitialize(IN ULONG Reason,
|
||||||
|
|
||||||
InputWaitHandle = ConnectInfo.ConsoleStartInfo.InputWaitHandle;
|
InputWaitHandle = ConnectInfo.ConsoleStartInfo.InputWaitHandle;
|
||||||
|
|
||||||
/* Sets the current console locale for this thread */
|
/* Sync the current thread's LangId with the console's one */
|
||||||
SetTEBLangID(lcid);
|
SetTEBLangID();
|
||||||
}
|
}
|
||||||
|
|
||||||
DPRINT("Console setup: 0x%p, 0x%p, 0x%p, 0x%p\n",
|
DPRINT("Console setup: 0x%p, 0x%p, 0x%p, 0x%p\n",
|
||||||
|
|
|
@ -60,7 +60,8 @@ GetConsoleInputWaitHandle(VOID);
|
||||||
HANDLE
|
HANDLE
|
||||||
TranslateStdHandle(HANDLE hHandle);
|
TranslateStdHandle(HANDLE hHandle);
|
||||||
|
|
||||||
#define SetTEBLangID(p) (p)
|
VOID
|
||||||
|
SetTEBLangID(VOID);
|
||||||
|
|
||||||
VOID
|
VOID
|
||||||
SetUpConsoleInfo(IN BOOLEAN CaptureTitle,
|
SetUpConsoleInfo(IN BOOLEAN CaptureTitle,
|
||||||
|
|
|
@ -859,6 +859,12 @@ typedef struct _CONSOLE_SETINPUTOUTPUTCP
|
||||||
HANDLE EventHandle;
|
HANDLE EventHandle;
|
||||||
} CONSOLE_SETINPUTOUTPUTCP, *PCONSOLE_SETINPUTOUTPUTCP;
|
} CONSOLE_SETINPUTOUTPUTCP, *PCONSOLE_SETINPUTOUTPUTCP;
|
||||||
|
|
||||||
|
typedef struct _CONSOLE_GETLANGID
|
||||||
|
{
|
||||||
|
HANDLE ConsoleHandle;
|
||||||
|
LANGID LangId;
|
||||||
|
} CONSOLE_GETLANGID, *PCONSOLE_GETLANGID;
|
||||||
|
|
||||||
typedef struct _CONSOLE_GETKBDLAYOUTNAME
|
typedef struct _CONSOLE_GETKBDLAYOUTNAME
|
||||||
{
|
{
|
||||||
HANDLE ConsoleHandle;
|
HANDLE ConsoleHandle;
|
||||||
|
@ -991,6 +997,7 @@ typedef struct _CONSOLE_API_MESSAGE
|
||||||
/* Input and Output Code Pages; keyboard */
|
/* Input and Output Code Pages; keyboard */
|
||||||
CONSOLE_GETINPUTOUTPUTCP GetConsoleCPRequest;
|
CONSOLE_GETINPUTOUTPUTCP GetConsoleCPRequest;
|
||||||
CONSOLE_SETINPUTOUTPUTCP SetConsoleCPRequest;
|
CONSOLE_SETINPUTOUTPUTCP SetConsoleCPRequest;
|
||||||
|
CONSOLE_GETLANGID LangIdRequest;
|
||||||
CONSOLE_GETKBDLAYOUTNAME GetKbdLayoutNameRequest;
|
CONSOLE_GETKBDLAYOUTNAME GetKbdLayoutNameRequest;
|
||||||
|
|
||||||
/* Virtual DOS Machine */
|
/* Virtual DOS Machine */
|
||||||
|
|
|
@ -19,6 +19,15 @@
|
||||||
#define CP_GB2312 936 // Chinese Simplified (GB2312)
|
#define CP_GB2312 936 // Chinese Simplified (GB2312)
|
||||||
#define CP_BIG5 950 // Chinese Traditional (Big5)
|
#define CP_BIG5 950 // Chinese Traditional (Big5)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* "Human-understandable" names for the previous standard code pages.
|
||||||
|
* Taken from https://github.com/microsoft/terminal/blob/main/src/inc/unicode.hpp
|
||||||
|
*/
|
||||||
|
#define CP_JAPANESE CP_SHIFTJIS
|
||||||
|
#define CP_KOREAN CP_HANGUL
|
||||||
|
#define CP_CHINESE_SIMPLIFIED CP_GB2312
|
||||||
|
#define CP_CHINESE_TRADITIONAL CP_BIG5
|
||||||
|
|
||||||
/* IsFarEastCP(CodePage) */
|
/* IsFarEastCP(CodePage) */
|
||||||
#define IsCJKCodePage(CodePage) \
|
#define IsCJKCodePage(CodePage) \
|
||||||
((CodePage) == CP_SHIFTJIS || (CodePage) == CP_HANGUL || \
|
((CodePage) == CP_SHIFTJIS || (CodePage) == CP_HANGUL || \
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
#define COBJMACROS
|
#define COBJMACROS
|
||||||
#include <shlobj.h>
|
#include <shlobj.h>
|
||||||
|
|
||||||
|
#include "../concfg/font.h"
|
||||||
#include <alias.h>
|
#include <alias.h>
|
||||||
#include <history.h>
|
#include <history.h>
|
||||||
#include "procinit.h"
|
#include "procinit.h"
|
||||||
|
@ -2014,10 +2014,66 @@ CSR_API(SrvSetConsoleNlsMode)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* API_NUMBER: ConsolepGetLangId */
|
/* API_NUMBER: ConsolepGetLangId */
|
||||||
CSR_API(SrvGetConsoleLangId)
|
CON_API(SrvGetConsoleLangId,
|
||||||
|
CONSOLE_GETLANGID, LangIdRequest)
|
||||||
{
|
{
|
||||||
DPRINT1("%s not yet implemented\n", __FUNCTION__);
|
/*
|
||||||
return STATUS_NOT_IMPLEMENTED;
|
* Quoting MS Terminal, see function GetConsoleLangId() at
|
||||||
|
* https://github.com/microsoft/terminal/blob/main/src/host/srvinit.cpp#L655
|
||||||
|
* "Only attempt to return the Lang ID if the Windows ACP on console
|
||||||
|
* launch was an East Asian Code Page."
|
||||||
|
*
|
||||||
|
* The underlying logic is as follows:
|
||||||
|
*
|
||||||
|
* - When the current user's UI language is *not* CJK, the user expects
|
||||||
|
* to not see any CJK output to the console by default, even if its
|
||||||
|
* output has been set to a CJK code page (this is possible when CJK
|
||||||
|
* fonts are installed on the system). That is, of course, unless if
|
||||||
|
* the attached console program chooses to actually output CJK text.
|
||||||
|
* Whatever current language of the running program's thread should
|
||||||
|
* be kept: STATUS_NOT_SUPPORTED is returned.
|
||||||
|
*
|
||||||
|
* - When the current user's UI language *is* CJK, the user expects to
|
||||||
|
* see CJK output to the console by default when its code page is CJK.
|
||||||
|
* A valid LangId is returned in this case to ensure this.
|
||||||
|
* However, if the console code page is not CJK, then it is evident
|
||||||
|
* that CJK text will not be able to be correctly shown, and therefore
|
||||||
|
* we should fall back to a standard language that can be shown, namely
|
||||||
|
* en-US english, instead of keeping the current language.
|
||||||
|
*/
|
||||||
|
|
||||||
|
BYTE UserCharSet = CodePageToCharSet(GetACP());
|
||||||
|
if (!IsCJKCharSet(UserCharSet))
|
||||||
|
return STATUS_NOT_SUPPORTED;
|
||||||
|
|
||||||
|
/* Return a "best-suited" language ID corresponding
|
||||||
|
* to the active console output code page. */
|
||||||
|
switch (Console->OutputCodePage)
|
||||||
|
{
|
||||||
|
/** ReactOS-specific: do nothing if the code page is UTF-8. This will allow
|
||||||
|
** programs to naturally output in whatever current language they are. **/
|
||||||
|
case CP_UTF8:
|
||||||
|
return STATUS_NOT_SUPPORTED;
|
||||||
|
/** End ReactOS-specific **/
|
||||||
|
case CP_JAPANESE:
|
||||||
|
LangIdRequest->LangId = MAKELANGID(LANG_JAPANESE, SUBLANG_DEFAULT);
|
||||||
|
break;
|
||||||
|
case CP_KOREAN:
|
||||||
|
LangIdRequest->LangId = MAKELANGID(LANG_KOREAN, SUBLANG_KOREAN);
|
||||||
|
break;
|
||||||
|
case CP_CHINESE_SIMPLIFIED:
|
||||||
|
LangIdRequest->LangId = MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED);
|
||||||
|
break;
|
||||||
|
case CP_CHINESE_TRADITIONAL:
|
||||||
|
LangIdRequest->LangId = MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_TRADITIONAL);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
/* Default to en-US english otherwise */
|
||||||
|
LangIdRequest->LangId = MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* EOF */
|
/* EOF */
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue