mirror of
https://github.com/reactos/reactos.git
synced 2025-06-24 00:30:18 +00:00
[CTFMON][MSCTF][MSCTFIME][MSUTB] Move CTF modules to base/ctf (#8040)
This PR reorganizes the location of the CTF-related modules to improve grep-ability, understanding, and readability. New folder base/ctf will become incomplete Cicero, CTF or TSF (Text Services Framework). JIRA issue: CORE-19360 JIRA issue: CORE-19361 JIRA issue: CORE-19363 - Move ctfmon, msctf, msctfime, and msutb modules to new directory base/ctf. - Adapt CMakeLists.txt to this move. - Modify .github/labeler.yml and media/doc/WINESYNC.txt. - No code content changes except CMakeLists.txt, .github/labeler.yml, and media/doc/WINESYNC.txt.
This commit is contained in:
parent
2a0d98c2bc
commit
d4c64771cd
77 changed files with 9 additions and 11 deletions
695
base/ctf/msctf/mlng.cpp
Normal file
695
base/ctf/msctf/mlng.cpp
Normal file
|
@ -0,0 +1,695 @@
|
|||
/*
|
||||
* PROJECT: ReactOS msctf.dll
|
||||
* LICENSE: LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later)
|
||||
* PURPOSE: Multi-language handling of Cicero
|
||||
* COPYRIGHT: Copyright 2024 Katayama Hirofumi MZ <katayama.hirofumi.mz@gmail.com>
|
||||
*/
|
||||
|
||||
#define WIN32_NO_STATUS
|
||||
|
||||
#include <windows.h>
|
||||
#include <shellapi.h>
|
||||
#include <imm.h>
|
||||
#include <imm32_undoc.h>
|
||||
#include <shlobj.h>
|
||||
#include <shlwapi.h>
|
||||
#include <shlwapi_undoc.h>
|
||||
#include <msctf.h>
|
||||
#include <msctf_undoc.h>
|
||||
#include <strsafe.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include <cicreg.h>
|
||||
#include <cicarray.h>
|
||||
|
||||
#include <wine/debug.h>
|
||||
|
||||
#include "mlng.h"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(msctf);
|
||||
|
||||
extern CRITICAL_SECTION g_cs;
|
||||
|
||||
CicArray<MLNGINFO> *g_pMlngInfo = NULL;
|
||||
INT CStaticIconList::s_cx = 0;
|
||||
INT CStaticIconList::s_cy = 0;
|
||||
CStaticIconList g_IconList;
|
||||
|
||||
// Cache for GetSpecialKLID
|
||||
static HKL s_hCacheKL = NULL;
|
||||
static DWORD s_dwCacheKLID = 0;
|
||||
|
||||
/***********************************************************************
|
||||
* The helper funtions
|
||||
*/
|
||||
|
||||
/// @implemented
|
||||
DWORD GetSpecialKLID(_In_ HKL hKL)
|
||||
{
|
||||
assert(IS_SPECIAL_HKL(hKL));
|
||||
|
||||
if (s_hCacheKL == hKL && s_dwCacheKLID != 0)
|
||||
return s_dwCacheKLID;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
return s_dwCacheKLID;
|
||||
}
|
||||
|
||||
/// @implemented
|
||||
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(
|
||||
_In_ HKL hKL,
|
||||
_Out_ LPWSTR pszDesc,
|
||||
_In_ UINT cchDesc,
|
||||
_Out_ LPWSTR pszImeFileName,
|
||||
_In_ UINT cchImeFileName)
|
||||
{
|
||||
pszDesc[0] = pszImeFileName[0] = UNICODE_NULL;
|
||||
|
||||
if (!IS_IME_HKL(hKL))
|
||||
return GetHKLName(hKL, pszDesc, cchDesc);
|
||||
|
||||
if (GetKbdLayoutNameFromReg(hKL, pszDesc, cchDesc))
|
||||
return TRUE;
|
||||
|
||||
if (!::ImmGetDescriptionW(hKL, pszDesc, cchDesc))
|
||||
{
|
||||
*pszDesc = UNICODE_NULL;
|
||||
return GetHKLName(hKL, pszDesc, cchDesc);
|
||||
}
|
||||
|
||||
if (!::ImmGetIMEFileNameW(hKL, pszImeFileName, cchImeFileName))
|
||||
*pszImeFileName = UNICODE_NULL;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/// @implemented
|
||||
HICON GetIconFromFile(_In_ INT cx, _In_ INT cy, _In_ LPCWSTR pszFileName, _In_ INT iIcon)
|
||||
{
|
||||
HICON hIcon;
|
||||
|
||||
if (cx <= GetSystemMetrics(SM_CXSMICON))
|
||||
::ExtractIconExW(pszFileName, iIcon, NULL, &hIcon, 1);
|
||||
else
|
||||
::ExtractIconExW(pszFileName, iIcon, &hIcon, NULL, 1);
|
||||
|
||||
return hIcon;
|
||||
}
|
||||
|
||||
/// @implemented
|
||||
static BOOL EnsureIconImageList(VOID)
|
||||
{
|
||||
if (!CStaticIconList::s_cx)
|
||||
g_IconList.Init(::GetSystemMetrics(SM_CYSMICON), ::GetSystemMetrics(SM_CXSMICON));
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/// @implemented
|
||||
static INT GetPhysicalFontHeight(LOGFONTW *plf)
|
||||
{
|
||||
HDC hDC = ::GetDC(NULL);
|
||||
HFONT hFont = ::CreateFontIndirectW(plf);
|
||||
HGDIOBJ hFontOld = ::SelectObject(hDC, hFont);
|
||||
TEXTMETRICW tm;
|
||||
::GetTextMetricsW(hDC, &tm);
|
||||
INT ret = tm.tmExternalLeading + tm.tmHeight;
|
||||
::SelectObject(hDC, hFontOld);
|
||||
::DeleteObject(hFont);
|
||||
::ReleaseDC(NULL, hDC);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* Inat helper functions
|
||||
*/
|
||||
|
||||
/// @implemented
|
||||
INT InatAddIcon(_In_ HICON hIcon)
|
||||
{
|
||||
if (!EnsureIconImageList())
|
||||
return -1;
|
||||
return g_IconList.AddIcon(hIcon);
|
||||
}
|
||||
|
||||
/// @implemented
|
||||
HICON
|
||||
InatCreateIconBySize(
|
||||
_In_ LANGID LangID,
|
||||
_In_ INT nWidth,
|
||||
_In_ INT nHeight,
|
||||
_In_ const LOGFONTW *plf)
|
||||
{
|
||||
WCHAR szText[64];
|
||||
BOOL ret = ::GetLocaleInfoW(LangID, LOCALE_NOUSEROVERRIDE | LOCALE_SABBREVLANGNAME,
|
||||
szText, _countof(szText));
|
||||
if (!ret)
|
||||
szText[0] = szText[1] = L'?';
|
||||
|
||||
szText[2] = UNICODE_NULL;
|
||||
CharUpperW(szText);
|
||||
|
||||
HFONT hFont = ::CreateFontIndirectW(plf);
|
||||
if (!hFont)
|
||||
return NULL;
|
||||
|
||||
HDC hDC = ::GetDC(NULL);
|
||||
HDC hMemDC = ::CreateCompatibleDC(hDC);
|
||||
HBITMAP hbmColor = ::CreateCompatibleBitmap(hDC, nWidth, nHeight);
|
||||
HBITMAP hbmMask = ::CreateBitmap(nWidth, nHeight, 1, 1, NULL);
|
||||
::ReleaseDC(NULL, hDC);
|
||||
|
||||
HICON hIcon = NULL;
|
||||
HGDIOBJ hbmOld = ::SelectObject(hMemDC, hbmColor);
|
||||
HGDIOBJ hFontOld = ::SelectObject(hMemDC, hFont);
|
||||
if (hMemDC && hbmColor && hbmMask)
|
||||
{
|
||||
::SetBkColor(hMemDC, ::GetSysColor(COLOR_HIGHLIGHT));
|
||||
::SetTextColor(hMemDC, ::GetSysColor(COLOR_HIGHLIGHTTEXT));
|
||||
|
||||
RECT rc = { 0, 0, nWidth, nHeight };
|
||||
::ExtTextOutW(hMemDC, 0, 0, ETO_OPAQUE, &rc, L"", 0, NULL);
|
||||
|
||||
::DrawTextW(hMemDC, szText, 2, &rc, DT_SINGLELINE | DT_CENTER | DT_VCENTER);
|
||||
::SelectObject(hMemDC, hbmMask);
|
||||
|
||||
::PatBlt(hMemDC, 0, 0, nWidth, nHeight, BLACKNESS);
|
||||
|
||||
ICONINFO IconInfo = { TRUE, 0, 0, hbmMask, hbmColor };
|
||||
hIcon = ::CreateIconIndirect(&IconInfo);
|
||||
}
|
||||
::SelectObject(hMemDC, hFontOld);
|
||||
::SelectObject(hMemDC, hbmOld);
|
||||
|
||||
::DeleteObject(hbmMask);
|
||||
::DeleteObject(hbmColor);
|
||||
::DeleteDC(hMemDC);
|
||||
::DeleteObject(hFont);
|
||||
return hIcon;
|
||||
}
|
||||
|
||||
/// @implemented
|
||||
HICON InatCreateIcon(_In_ LANGID LangID)
|
||||
{
|
||||
INT cxSmIcon = ::GetSystemMetrics(SM_CXSMICON), cySmIcon = ::GetSystemMetrics(SM_CYSMICON);
|
||||
|
||||
LOGFONTW lf;
|
||||
if (!SystemParametersInfoW(SPI_GETICONTITLELOGFONT, sizeof(LOGFONTW), &lf, 0))
|
||||
return NULL;
|
||||
|
||||
if (cySmIcon < GetPhysicalFontHeight(&lf))
|
||||
{
|
||||
lf.lfWidth = 0;
|
||||
lf.lfHeight = - (7 * cySmIcon) / 10;
|
||||
}
|
||||
|
||||
return InatCreateIconBySize(LangID, cxSmIcon, cySmIcon, &lf);
|
||||
}
|
||||
|
||||
/// @implemented
|
||||
BOOL InatGetIconSize(_Out_ INT *pcx, _Out_ INT *pcy)
|
||||
{
|
||||
g_IconList.GetIconSize(pcx, pcy);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/// @implemented
|
||||
INT InatGetImageCount(VOID)
|
||||
{
|
||||
return g_IconList.GetImageCount();
|
||||
}
|
||||
|
||||
/// @implemented
|
||||
VOID InatRemoveAll(VOID)
|
||||
{
|
||||
if (CStaticIconList::s_cx)
|
||||
g_IconList.RemoveAll(FALSE);
|
||||
}
|
||||
|
||||
/// @implemented
|
||||
VOID UninitINAT(VOID)
|
||||
{
|
||||
g_IconList.RemoveAll(TRUE);
|
||||
|
||||
if (g_pMlngInfo)
|
||||
{
|
||||
delete g_pMlngInfo;
|
||||
g_pMlngInfo = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* MLNGINFO
|
||||
*/
|
||||
|
||||
/// @implemented
|
||||
void MLNGINFO::InitDesc()
|
||||
{
|
||||
if (m_bInitDesc)
|
||||
return;
|
||||
|
||||
WCHAR szDesc[MAX_PATH], szImeFileName[MAX_PATH];
|
||||
GetHKLDesctription(m_hKL, szDesc, (UINT)_countof(szDesc),
|
||||
szImeFileName, (UINT)_countof(szImeFileName));
|
||||
SetDesc(szDesc);
|
||||
m_bInitDesc = TRUE;
|
||||
}
|
||||
|
||||
/// @implemented
|
||||
void MLNGINFO::InitIcon()
|
||||
{
|
||||
if (m_bInitIcon)
|
||||
return;
|
||||
|
||||
WCHAR szDesc[MAX_PATH], szImeFileName[MAX_PATH];
|
||||
GetHKLDesctription(m_hKL, szDesc, (UINT)_countof(szDesc),
|
||||
szImeFileName, (UINT)_countof(szImeFileName));
|
||||
SetDesc(szDesc);
|
||||
m_bInitDesc = TRUE;
|
||||
|
||||
INT cxIcon, cyIcon;
|
||||
InatGetIconSize(&cxIcon, &cyIcon);
|
||||
|
||||
HICON hIcon = NULL;
|
||||
if (szImeFileName[0])
|
||||
hIcon = GetIconFromFile(cxIcon, cyIcon, szImeFileName, 0);
|
||||
|
||||
if (!hIcon)
|
||||
hIcon = InatCreateIcon(LOWORD(m_hKL));
|
||||
|
||||
if (hIcon)
|
||||
{
|
||||
m_iIconIndex = InatAddIcon(hIcon);
|
||||
::DestroyIcon(hIcon);
|
||||
}
|
||||
|
||||
m_bInitIcon = TRUE;
|
||||
}
|
||||
|
||||
/// @implemented
|
||||
LPCWSTR MLNGINFO::GetDesc()
|
||||
{
|
||||
if (!m_bInitDesc)
|
||||
InitDesc();
|
||||
|
||||
return m_szDesc;
|
||||
}
|
||||
|
||||
/// @implemented
|
||||
void MLNGINFO::SetDesc(LPCWSTR pszDesc)
|
||||
{
|
||||
StringCchCopyW(m_szDesc, _countof(m_szDesc), pszDesc);
|
||||
}
|
||||
|
||||
/// @implemented
|
||||
INT MLNGINFO::GetIconIndex()
|
||||
{
|
||||
if (!m_bInitIcon)
|
||||
InitIcon();
|
||||
|
||||
return m_iIconIndex;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* CStaticIconList
|
||||
*/
|
||||
|
||||
/// @implemented
|
||||
void CStaticIconList::Init(INT cxIcon, INT cyIcon)
|
||||
{
|
||||
::EnterCriticalSection(&g_cs);
|
||||
s_cx = cxIcon;
|
||||
s_cy = cyIcon;
|
||||
::LeaveCriticalSection(&g_cs);
|
||||
}
|
||||
|
||||
/// @implemented
|
||||
INT CStaticIconList::AddIcon(HICON hIcon)
|
||||
{
|
||||
::EnterCriticalSection(&g_cs);
|
||||
|
||||
INT iItem = -1;
|
||||
HICON hCopyIcon = ::CopyIcon(hIcon);
|
||||
if (hCopyIcon)
|
||||
{
|
||||
if (g_IconList.Add(hIcon))
|
||||
iItem = INT(g_IconList.size() - 1);
|
||||
}
|
||||
|
||||
::LeaveCriticalSection(&g_cs);
|
||||
return iItem;
|
||||
}
|
||||
|
||||
/// @implemented
|
||||
HICON CStaticIconList::ExtractIcon(INT iIcon)
|
||||
{
|
||||
HICON hCopyIcon = NULL;
|
||||
::EnterCriticalSection(&g_cs);
|
||||
if (iIcon <= (INT)g_IconList.size())
|
||||
hCopyIcon = ::CopyIcon(g_IconList[iIcon]);
|
||||
::LeaveCriticalSection(&g_cs);
|
||||
return hCopyIcon;
|
||||
}
|
||||
|
||||
/// @implemented
|
||||
void CStaticIconList::GetIconSize(INT *pcx, INT *pcy)
|
||||
{
|
||||
::EnterCriticalSection(&g_cs);
|
||||
*pcx = s_cx;
|
||||
*pcy = s_cy;
|
||||
::LeaveCriticalSection(&g_cs);
|
||||
}
|
||||
|
||||
/// @implemented
|
||||
INT CStaticIconList::GetImageCount()
|
||||
{
|
||||
::EnterCriticalSection(&g_cs);
|
||||
INT cItems = (INT)g_IconList.size();
|
||||
::LeaveCriticalSection(&g_cs);
|
||||
return cItems;
|
||||
}
|
||||
|
||||
/// @implemented
|
||||
void CStaticIconList::RemoveAll(BOOL bNoLock)
|
||||
{
|
||||
if (!bNoLock)
|
||||
::EnterCriticalSection(&g_cs);
|
||||
|
||||
for (size_t iItem = 0; iItem < g_IconList.size(); ++iItem)
|
||||
{
|
||||
::DestroyIcon(g_IconList[iItem]);
|
||||
}
|
||||
|
||||
clear();
|
||||
|
||||
if (!bNoLock)
|
||||
::LeaveCriticalSection(&g_cs);
|
||||
}
|
||||
|
||||
/// @implemented
|
||||
static BOOL CheckMlngInfo(VOID)
|
||||
{
|
||||
if (!g_pMlngInfo)
|
||||
return TRUE; // Needs creation
|
||||
|
||||
INT cKLs = ::GetKeyboardLayoutList(0, NULL);
|
||||
if (cKLs != TF_MlngInfoCount())
|
||||
return TRUE; // Needs refresh
|
||||
|
||||
if (!cKLs)
|
||||
return FALSE;
|
||||
|
||||
HKL *phKLs = (HKL*)cicMemAlloc(cKLs * sizeof(HKL));
|
||||
if (!phKLs)
|
||||
return FALSE;
|
||||
|
||||
::GetKeyboardLayoutList(cKLs, phKLs);
|
||||
|
||||
assert(g_pMlngInfo);
|
||||
|
||||
BOOL ret = FALSE;
|
||||
for (INT iKL = 0; iKL < cKLs; ++iKL)
|
||||
{
|
||||
if ((*g_pMlngInfo)[iKL].m_hKL != phKLs[iKL])
|
||||
{
|
||||
ret = TRUE; // Needs refresh
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
cicMemFree(phKLs);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/// @implemented
|
||||
static VOID DestroyMlngInfo(VOID)
|
||||
{
|
||||
if (!g_pMlngInfo)
|
||||
return;
|
||||
|
||||
delete g_pMlngInfo;
|
||||
g_pMlngInfo = NULL;
|
||||
}
|
||||
|
||||
/// @implemented
|
||||
static VOID CreateMlngInfo(VOID)
|
||||
{
|
||||
if (!g_pMlngInfo)
|
||||
{
|
||||
g_pMlngInfo = new(cicNoThrow) CicArray<MLNGINFO>();
|
||||
if (!g_pMlngInfo)
|
||||
return;
|
||||
}
|
||||
|
||||
if (!EnsureIconImageList())
|
||||
return;
|
||||
|
||||
INT cKLs = ::GetKeyboardLayoutList(0, NULL);
|
||||
HKL *phKLs = (HKL*)cicMemAllocClear(cKLs * sizeof(HKL));
|
||||
if (!phKLs)
|
||||
return;
|
||||
|
||||
::GetKeyboardLayoutList(cKLs, phKLs);
|
||||
|
||||
for (INT iKL = 0; iKL < cKLs; ++iKL)
|
||||
{
|
||||
MLNGINFO& info = (*g_pMlngInfo)[iKL];
|
||||
info.m_hKL = phKLs[iKL];
|
||||
info.m_bInitDesc = FALSE;
|
||||
info.m_bInitIcon = FALSE;
|
||||
}
|
||||
|
||||
cicMemFree(phKLs);
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* TF_InitMlngInfo (MSCTF.@)
|
||||
*
|
||||
* @implemented
|
||||
*/
|
||||
EXTERN_C VOID WINAPI TF_InitMlngInfo(VOID)
|
||||
{
|
||||
TRACE("()\n");
|
||||
|
||||
::EnterCriticalSection(&g_cs);
|
||||
|
||||
if (CheckMlngInfo())
|
||||
{
|
||||
DestroyMlngInfo();
|
||||
CreateMlngInfo();
|
||||
}
|
||||
|
||||
::LeaveCriticalSection(&g_cs);
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* TF_MlngInfoCount (MSCTF.@)
|
||||
*
|
||||
* @implemented
|
||||
*/
|
||||
EXTERN_C INT WINAPI TF_MlngInfoCount(VOID)
|
||||
{
|
||||
TRACE("()\n");
|
||||
|
||||
if (!g_pMlngInfo)
|
||||
return 0;
|
||||
|
||||
return (INT)g_pMlngInfo->size();
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* TF_InatExtractIcon (MSCTF.@)
|
||||
*
|
||||
* @implemented
|
||||
*/
|
||||
EXTERN_C HICON WINAPI TF_InatExtractIcon(_In_ INT iKL)
|
||||
{
|
||||
TRACE("(%d)\n", iKL);
|
||||
return g_IconList.ExtractIcon(iKL);
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* TF_GetMlngIconIndex (MSCTF.@)
|
||||
*
|
||||
* @implemented
|
||||
*/
|
||||
EXTERN_C INT WINAPI TF_GetMlngIconIndex(_In_ INT iKL)
|
||||
{
|
||||
TRACE("(%d)\n", iKL);
|
||||
|
||||
INT iIcon = -1;
|
||||
|
||||
::EnterCriticalSection(&g_cs);
|
||||
|
||||
assert(g_pMlngInfo);
|
||||
|
||||
if (iKL < (INT)g_pMlngInfo->size())
|
||||
iIcon = (*g_pMlngInfo)[iKL].GetIconIndex();
|
||||
|
||||
::LeaveCriticalSection(&g_cs);
|
||||
|
||||
return iIcon;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* TF_GetMlngHKL (MSCTF.@)
|
||||
*
|
||||
* @implemented
|
||||
*/
|
||||
EXTERN_C BOOL WINAPI
|
||||
TF_GetMlngHKL(
|
||||
_In_ INT iKL,
|
||||
_Out_opt_ HKL *phKL,
|
||||
_Out_opt_ LPWSTR pszDesc,
|
||||
_In_ INT cchDesc)
|
||||
{
|
||||
TRACE("(%d, %p, %p, %d)\n", iKL, phKL, pszDesc, cchDesc);
|
||||
|
||||
BOOL ret = FALSE;
|
||||
|
||||
::EnterCriticalSection(&g_cs);
|
||||
|
||||
assert(g_pMlngInfo);
|
||||
|
||||
if (iKL < (INT)g_pMlngInfo->size())
|
||||
{
|
||||
MLNGINFO& info = (*g_pMlngInfo)[iKL];
|
||||
|
||||
if (phKL)
|
||||
*phKL = info.m_hKL;
|
||||
|
||||
if (pszDesc)
|
||||
StringCchCopyW(pszDesc, cchDesc, info.GetDesc());
|
||||
|
||||
ret = TRUE;
|
||||
}
|
||||
|
||||
::LeaveCriticalSection(&g_cs);
|
||||
|
||||
return ret;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue