mirror of
https://github.com/reactos/reactos.git
synced 2025-08-05 00:45:43 +00:00
[MSCTF] Implement GetHKLSubstitute (#6589)
Implementing the back-end of the Language bar... JIRA issue: CORE-19361 - Rename GetLocaleInfoString as GetHKLName. - Implement GetHKLSubstitute helper function. - Fix GetHKLDesctription function.
This commit is contained in:
parent
fcbcc5b30c
commit
0c65ceca3c
3 changed files with 176 additions and 86 deletions
|
@ -33,6 +33,6 @@ add_library(msctf MODULE
|
||||||
set_module_type(msctf win32dll UNICODE)
|
set_module_type(msctf win32dll UNICODE)
|
||||||
target_link_libraries(msctf uuid wine cicero)
|
target_link_libraries(msctf uuid wine cicero)
|
||||||
add_importlibs(msctf user32 advapi32 advapi32_vista msvcrt kernel32 ntdll)
|
add_importlibs(msctf user32 advapi32 advapi32_vista msvcrt kernel32 ntdll)
|
||||||
add_delay_importlibs(msctf shell32 ole32 oleaut32 imm32 gdi32)
|
add_delay_importlibs(msctf shell32 shlwapi ole32 oleaut32 imm32 gdi32)
|
||||||
add_pch(msctf precomp.h SOURCE)
|
add_pch(msctf precomp.h SOURCE)
|
||||||
add_cd_file(TARGET msctf DESTINATION reactos/system32 FOR all)
|
add_cd_file(TARGET msctf DESTINATION reactos/system32 FOR all)
|
||||||
|
|
|
@ -11,8 +11,12 @@
|
||||||
#include <shellapi.h>
|
#include <shellapi.h>
|
||||||
#include <imm.h>
|
#include <imm.h>
|
||||||
#include <imm32_undoc.h>
|
#include <imm32_undoc.h>
|
||||||
|
#include <shlobj.h>
|
||||||
|
#include <shlwapi.h>
|
||||||
|
#include <shlwapi_undoc.h>
|
||||||
#include <msctf.h>
|
#include <msctf.h>
|
||||||
#include <strsafe.h>
|
#include <strsafe.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
#include <cicreg.h>
|
#include <cicreg.h>
|
||||||
#include <cicarray.h>
|
#include <cicarray.h>
|
||||||
|
@ -30,30 +34,152 @@ INT CStaticIconList::s_cx = 0;
|
||||||
INT CStaticIconList::s_cy = 0;
|
INT CStaticIconList::s_cy = 0;
|
||||||
CStaticIconList g_IconList;
|
CStaticIconList g_IconList;
|
||||||
|
|
||||||
|
// Cache for GetSpecialKLID
|
||||||
|
static HKL s_hCacheKL = NULL;
|
||||||
|
static DWORD s_dwCacheKLID = 0;
|
||||||
|
|
||||||
/***********************************************************************
|
/***********************************************************************
|
||||||
* The helper funtions
|
* The helper funtions
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/// @unimplemented
|
/// @implemented
|
||||||
static VOID
|
DWORD GetSpecialKLID(_In_ HKL hKL)
|
||||||
GetLocaleInfoString(_In_ HKL hKL, _Out_ LPWSTR pszDesc, _In_ UINT cchDesc)
|
|
||||||
{
|
{
|
||||||
if (!::GetLocaleInfoW(LOWORD(hKL), LOCALE_SLANGUAGE, pszDesc, cchDesc))
|
assert(IS_SPECIAL_HKL(hKL));
|
||||||
*pszDesc = UNICODE_NULL;
|
|
||||||
#if 0
|
if (s_hCacheKL == hKL && s_dwCacheKLID != 0)
|
||||||
if (HIWORD(hKL) != LOWORD(hKL))
|
return s_dwCacheKLID;
|
||||||
GetKbdLayoutName(hKL, pszDesc, cchDesc);
|
|
||||||
#endif
|
s_dwCacheKLID = 0;
|
||||||
|
|
||||||
|
CicRegKey regKey1;
|
||||||
|
LSTATUS error = regKey1.Open(HKEY_LOCAL_MACHINE,
|
||||||
|
L"SYSTEM\\CurrentControlSet\\Control\\Keyboard Layouts");
|
||||||
|
if (error != ERROR_SUCCESS)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
WCHAR szName[16], szLayoutId[16];
|
||||||
|
const DWORD dwSpecialId = SPECIALIDFROMHKL(hKL);
|
||||||
|
for (DWORD dwIndex = 0; ; ++dwIndex)
|
||||||
|
{
|
||||||
|
error = ::RegEnumKeyW(regKey1, dwIndex, szName, _countof(szName));
|
||||||
|
szName[_countof(szName) - 1] = UNICODE_NULL; // Avoid buffer overrun
|
||||||
|
if (error != ERROR_SUCCESS)
|
||||||
|
break;
|
||||||
|
|
||||||
|
CicRegKey regKey2;
|
||||||
|
error = regKey2.Open(regKey1, szName);
|
||||||
|
if (error != ERROR_SUCCESS)
|
||||||
|
break;
|
||||||
|
|
||||||
|
error = regKey2.QuerySz(L"Layout Id", szLayoutId, _countof(szLayoutId));
|
||||||
|
szLayoutId[_countof(szLayoutId) - 1] = UNICODE_NULL; // Avoid buffer overrun
|
||||||
|
if (error == ERROR_SUCCESS)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
DWORD dwLayoutId = wcstoul(szLayoutId, NULL, 16);
|
||||||
|
if (dwLayoutId == dwSpecialId)
|
||||||
|
{
|
||||||
|
s_hCacheKL = hKL;
|
||||||
|
s_dwCacheKLID = wcstoul(szName, NULL, 16);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @unimplemented
|
return s_dwCacheKLID;
|
||||||
HKL GetHKLSubstitute(_In_ HKL hKL)
|
|
||||||
{
|
|
||||||
return hKL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @implemented
|
/// @implemented
|
||||||
static VOID
|
DWORD GetHKLSubstitute(_In_ HKL hKL)
|
||||||
|
{
|
||||||
|
if (IS_IME_HKL(hKL))
|
||||||
|
return HandleToUlong(hKL);
|
||||||
|
|
||||||
|
DWORD dwKLID;
|
||||||
|
if (HIWORD(hKL) == LOWORD(hKL))
|
||||||
|
dwKLID = LOWORD(hKL);
|
||||||
|
else if (IS_SPECIAL_HKL(hKL))
|
||||||
|
dwKLID = GetSpecialKLID(hKL);
|
||||||
|
else
|
||||||
|
dwKLID = HandleToUlong(hKL);
|
||||||
|
|
||||||
|
if (dwKLID == 0)
|
||||||
|
return HandleToUlong(hKL);
|
||||||
|
|
||||||
|
CicRegKey regKey;
|
||||||
|
LSTATUS error = regKey.Open(HKEY_CURRENT_USER, L"Keyboard Layout\\Substitutes");
|
||||||
|
if (error == ERROR_SUCCESS)
|
||||||
|
{
|
||||||
|
WCHAR szName[MAX_PATH], szValue[MAX_PATH];
|
||||||
|
DWORD dwIndex, dwValue;
|
||||||
|
for (dwIndex = 0; ; ++dwIndex)
|
||||||
|
{
|
||||||
|
error = regKey.EnumValue(dwIndex, szName, _countof(szName));
|
||||||
|
szName[_countof(szName) - 1] = UNICODE_NULL; // Avoid buffer overrun
|
||||||
|
if (error != ERROR_SUCCESS)
|
||||||
|
break;
|
||||||
|
|
||||||
|
error = regKey.QuerySz(szName, szValue, _countof(szValue));
|
||||||
|
szValue[_countof(szValue) - 1] = UNICODE_NULL; // Avoid buffer overrun
|
||||||
|
if (error != ERROR_SUCCESS)
|
||||||
|
break;
|
||||||
|
|
||||||
|
dwValue = wcstoul(szValue, NULL, 16);
|
||||||
|
if ((dwKLID & ~SPECIAL_MASK) == dwValue)
|
||||||
|
{
|
||||||
|
dwKLID = wcstoul(szName, NULL, 16);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return dwKLID;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @implemented
|
||||||
|
static BOOL
|
||||||
|
GetKbdLayoutNameFromReg(_In_ HKL hKL, _Out_ LPWSTR pszDesc, _In_ UINT cchDesc)
|
||||||
|
{
|
||||||
|
const DWORD dwKLID = GetHKLSubstitute(hKL);
|
||||||
|
|
||||||
|
WCHAR szSubKey[MAX_PATH];
|
||||||
|
StringCchPrintfW(szSubKey, _countof(szSubKey),
|
||||||
|
L"SYSTEM\\CurrentControlSet\\Control\\Keyboard Layouts\\%08lX",
|
||||||
|
dwKLID);
|
||||||
|
|
||||||
|
CicRegKey regKey;
|
||||||
|
LSTATUS error = regKey.Open(HKEY_LOCAL_MACHINE, szSubKey);
|
||||||
|
if (error != ERROR_SUCCESS)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
if (SHLoadRegUIStringW(regKey, L"Layout Display Name", pszDesc, cchDesc) == S_OK)
|
||||||
|
{
|
||||||
|
pszDesc[cchDesc - 1] = UNICODE_NULL; // Avoid buffer overrun
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
error = regKey.QuerySz(L"Layout Text", pszDesc, cchDesc);
|
||||||
|
pszDesc[cchDesc - 1] = UNICODE_NULL; // Avoid buffer overrun
|
||||||
|
return (error == ERROR_SUCCESS);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @implemented
|
||||||
|
static BOOL
|
||||||
|
GetHKLName(_In_ HKL hKL, _Out_ LPWSTR pszDesc, _In_ UINT cchDesc)
|
||||||
|
{
|
||||||
|
if (::GetLocaleInfoW(LOWORD(hKL), LOCALE_SLANGUAGE, pszDesc, cchDesc))
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
*pszDesc = UNICODE_NULL;
|
||||||
|
|
||||||
|
if (LOWORD(hKL) == HIWORD(hKL))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
return GetKbdLayoutNameFromReg(hKL, pszDesc, cchDesc);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @implemented
|
||||||
|
static BOOL
|
||||||
GetHKLDesctription(
|
GetHKLDesctription(
|
||||||
_In_ HKL hKL,
|
_In_ HKL hKL,
|
||||||
_Out_ LPWSTR pszDesc,
|
_Out_ LPWSTR pszDesc,
|
||||||
|
@ -64,38 +190,21 @@ GetHKLDesctription(
|
||||||
pszDesc[0] = pszImeFileName[0] = UNICODE_NULL;
|
pszDesc[0] = pszImeFileName[0] = UNICODE_NULL;
|
||||||
|
|
||||||
if (!IS_IME_HKL(hKL))
|
if (!IS_IME_HKL(hKL))
|
||||||
{
|
return GetHKLName(hKL, pszDesc, cchDesc);
|
||||||
GetLocaleInfoString(hKL, pszDesc, cchDesc);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
hKL = GetHKLSubstitute(hKL);
|
if (GetKbdLayoutNameFromReg(hKL, pszDesc, cchDesc))
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
WCHAR szSubKey[MAX_PATH];
|
if (!::ImmGetDescriptionW(hKL, pszDesc, cchDesc))
|
||||||
StringCchPrintfW(szSubKey, _countof(szSubKey),
|
|
||||||
L"SYSTEM\\CurrentControlSet\\Control\\Keyboard Layouts\\%08lX",
|
|
||||||
HandleToUlong(hKL));
|
|
||||||
|
|
||||||
HKEY hKey;
|
|
||||||
LSTATUS error = ::RegOpenKeyExW(HKEY_LOCAL_MACHINE, szSubKey, 0, KEY_READ, &hKey);
|
|
||||||
if (error == ERROR_SUCCESS)
|
|
||||||
{
|
|
||||||
DWORD cbDesc = cchDesc * sizeof(WCHAR);
|
|
||||||
error = ::RegQueryValueExW(hKey, L"Layout Display Name", NULL, NULL,
|
|
||||||
(LPBYTE)pszDesc, &cbDesc);
|
|
||||||
pszDesc[cbDesc / sizeof(WCHAR) - 1] = UNICODE_NULL; // Avoid buffer overrun
|
|
||||||
::RegCloseKey(hKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pszDesc[0] == UNICODE_NULL && !::ImmGetDescriptionW(hKL, pszDesc, cchDesc))
|
|
||||||
{
|
{
|
||||||
*pszDesc = UNICODE_NULL;
|
*pszDesc = UNICODE_NULL;
|
||||||
GetLocaleInfoString(hKL, pszDesc, cchDesc);
|
return GetHKLName(hKL, pszDesc, cchDesc);
|
||||||
}
|
}
|
||||||
else if (!::ImmGetIMEFileNameW(hKL, pszImeFileName, cchImeFileName))
|
|
||||||
{
|
if (!::ImmGetIMEFileNameW(hKL, pszImeFileName, cchImeFileName))
|
||||||
*pszImeFileName = UNICODE_NULL;
|
*pszImeFileName = UNICODE_NULL;
|
||||||
}
|
|
||||||
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @implemented
|
/// @implemented
|
||||||
|
@ -263,25 +372,11 @@ void MLNGINFO::InitDesc()
|
||||||
if (m_bInitDesc)
|
if (m_bInitDesc)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
WCHAR szDesc[MAX_PATH], szFileName[MAX_PATH];
|
WCHAR szDesc[MAX_PATH], szImeFileName[MAX_PATH];
|
||||||
GetHKLDesctription(m_hKL, szDesc, (UINT)_countof(szDesc),
|
GetHKLDesctription(m_hKL, szDesc, (UINT)_countof(szDesc),
|
||||||
szFileName, (UINT)_countof(szFileName));
|
szImeFileName, (UINT)_countof(szImeFileName));
|
||||||
SetDesc(szDesc);
|
SetDesc(szDesc);
|
||||||
m_bInitDesc = TRUE;
|
m_bInitDesc = TRUE;
|
||||||
|
|
||||||
::EnterCriticalSection(&g_cs);
|
|
||||||
|
|
||||||
for (size_t iKL = 0; iKL < g_pMlngInfo->size(); ++iKL)
|
|
||||||
{
|
|
||||||
auto& info = (*g_pMlngInfo)[iKL];
|
|
||||||
if (info.m_hKL == m_hKL)
|
|
||||||
{
|
|
||||||
info.m_bInitDesc = TRUE;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
::LeaveCriticalSection(&g_cs);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @implemented
|
/// @implemented
|
||||||
|
@ -290,41 +385,29 @@ void MLNGINFO::InitIcon()
|
||||||
if (m_bInitIcon)
|
if (m_bInitIcon)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
WCHAR szDesc[MAX_PATH], szFileName[MAX_PATH];
|
WCHAR szDesc[MAX_PATH], szImeFileName[MAX_PATH];
|
||||||
GetHKLDesctription(m_hKL, szDesc, _countof(szDesc), szFileName, _countof(szFileName));
|
GetHKLDesctription(m_hKL, szDesc, (UINT)_countof(szDesc),
|
||||||
|
szImeFileName, (UINT)_countof(szImeFileName));
|
||||||
SetDesc(szDesc);
|
SetDesc(szDesc);
|
||||||
m_bInitDesc = TRUE;
|
m_bInitDesc = TRUE;
|
||||||
|
|
||||||
INT cxIcon, cyIcon;
|
INT cxIcon, cyIcon;
|
||||||
InatGetIconSize(&cxIcon, &cyIcon);
|
InatGetIconSize(&cxIcon, &cyIcon);
|
||||||
if (szFileName[0])
|
|
||||||
{
|
HICON hIcon = NULL;
|
||||||
HICON hIcon = GetIconFromFile(cxIcon, cyIcon, szFileName, 0);
|
if (szImeFileName[0])
|
||||||
|
hIcon = GetIconFromFile(cxIcon, cyIcon, szImeFileName, 0);
|
||||||
|
|
||||||
if (!hIcon)
|
if (!hIcon)
|
||||||
hIcon = InatCreateIcon(LOWORD(m_hKL));
|
hIcon = InatCreateIcon(LOWORD(m_hKL));
|
||||||
|
|
||||||
if (hIcon)
|
if (hIcon)
|
||||||
{
|
{
|
||||||
m_iIconIndex = InatAddIcon(hIcon);
|
m_iIconIndex = InatAddIcon(hIcon);
|
||||||
::DestroyIcon(hIcon);
|
::DestroyIcon(hIcon);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
::EnterCriticalSection(&g_cs);
|
m_bInitIcon = TRUE;
|
||||||
|
|
||||||
for (size_t iItem = 0; iItem < g_pMlngInfo->size(); ++iItem)
|
|
||||||
{
|
|
||||||
auto& item = (*g_pMlngInfo)[iItem];
|
|
||||||
if (item.m_hKL == m_hKL)
|
|
||||||
{
|
|
||||||
item.m_bInitDesc = TRUE;
|
|
||||||
item.m_bInitIcon = TRUE;
|
|
||||||
item.m_iIconIndex = m_iIconIndex;
|
|
||||||
item.SetDesc(szDesc);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
::LeaveCriticalSection(&g_cs);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @implemented
|
/// @implemented
|
||||||
|
@ -332,6 +415,7 @@ LPCWSTR MLNGINFO::GetDesc()
|
||||||
{
|
{
|
||||||
if (!m_bInitDesc)
|
if (!m_bInitDesc)
|
||||||
InitDesc();
|
InitDesc();
|
||||||
|
|
||||||
return m_szDesc;
|
return m_szDesc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -445,6 +529,8 @@ static BOOL CheckMlngInfo(VOID)
|
||||||
|
|
||||||
::GetKeyboardLayoutList(cKLs, phKLs);
|
::GetKeyboardLayoutList(cKLs, phKLs);
|
||||||
|
|
||||||
|
assert(g_pMlngInfo);
|
||||||
|
|
||||||
BOOL ret = FALSE;
|
BOOL ret = FALSE;
|
||||||
for (INT iKL = 0; iKL < cKLs; ++iKL)
|
for (INT iKL = 0; iKL < cKLs; ++iKL)
|
||||||
{
|
{
|
||||||
|
@ -559,6 +645,8 @@ EXTERN_C INT WINAPI TF_GetMlngIconIndex(_In_ INT iKL)
|
||||||
|
|
||||||
::EnterCriticalSection(&g_cs);
|
::EnterCriticalSection(&g_cs);
|
||||||
|
|
||||||
|
assert(g_pMlngInfo);
|
||||||
|
|
||||||
if (iKL < (INT)g_pMlngInfo->size())
|
if (iKL < (INT)g_pMlngInfo->size())
|
||||||
iIcon = (*g_pMlngInfo)[iKL].GetIconIndex();
|
iIcon = (*g_pMlngInfo)[iKL].GetIconIndex();
|
||||||
|
|
||||||
|
@ -585,6 +673,8 @@ TF_GetMlngHKL(
|
||||||
|
|
||||||
::EnterCriticalSection(&g_cs);
|
::EnterCriticalSection(&g_cs);
|
||||||
|
|
||||||
|
assert(g_pMlngInfo);
|
||||||
|
|
||||||
if (iKL < (INT)g_pMlngInfo->size())
|
if (iKL < (INT)g_pMlngInfo->size())
|
||||||
{
|
{
|
||||||
MLNGINFO& info = (*g_pMlngInfo)[iKL];
|
MLNGINFO& info = (*g_pMlngInfo)[iKL];
|
||||||
|
|
|
@ -53,7 +53,7 @@ BOOL InatGetIconSize(_Out_ INT *pcx, _Out_ INT *pcy);
|
||||||
INT InatGetImageCount(VOID);
|
INT InatGetImageCount(VOID);
|
||||||
VOID InatRemoveAll(VOID);
|
VOID InatRemoveAll(VOID);
|
||||||
|
|
||||||
HKL GetHKLSubstitute(_In_ HKL hKL);
|
DWORD GetHKLSubstitute(_In_ HKL hKL);
|
||||||
HICON GetIconFromFile(_In_ INT cx, _In_ INT cy, _In_ LPCWSTR pszFileName, _In_ INT iIcon);
|
HICON GetIconFromFile(_In_ INT cx, _In_ INT cy, _In_ LPCWSTR pszFileName, _In_ INT iIcon);
|
||||||
|
|
||||||
VOID UninitINAT(VOID);
|
VOID UninitINAT(VOID);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue