You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
908 lines
23 KiB
908 lines
23 KiB
/**************************************************************************\
|
|
* Module Name: layout.c (corresponds to Win95 ime.c)
|
|
*
|
|
* Copyright (c) 1985 - 1999, Microsoft Corporation
|
|
*
|
|
* IME Keyboard Layout related functionality
|
|
*
|
|
* History:
|
|
* 03-Jan-1996 wkwok Created
|
|
\**************************************************************************/
|
|
|
|
#include "precomp.h"
|
|
#pragma hdrstop
|
|
|
|
/*
|
|
* Local Defines.
|
|
*/
|
|
#define szLZOpenFileW "LZOpenFileW"
|
|
#define szLZCopy "LZCopy"
|
|
#define szLZClose "LZClose"
|
|
|
|
typedef HFILE (WINAPI *LPFNLZOPENFILEW)(LPTSTR, LPOFSTRUCT, WORD);
|
|
typedef LONG (WINAPI *LPFNLZCOPY)(INT, INT);
|
|
typedef VOID (WINAPI *LPFNLZCLOSE)(INT);
|
|
|
|
/*
|
|
* Local Routines.
|
|
*/
|
|
UINT StrToUInt(LPWSTR);
|
|
VOID UIntToStr(UINT, ULONG, LPWSTR, USHORT);
|
|
BOOL CopyImeFile(LPWSTR, LPCWSTR);
|
|
INT GetImeLayout(PIMELAYOUT, INT);
|
|
BOOL WriteImeLayout(HKL, LPCWSTR, LPCWSTR);
|
|
HKL AssignNewLayout(INT, PIMELAYOUT, HKL);
|
|
|
|
|
|
/***************************************************************************\
|
|
* ImmGetIMEFileNameW
|
|
*
|
|
* Gets the description of the IME with the specified HKL.
|
|
*
|
|
* History:
|
|
* 28-Feb-1995 wkwok Created
|
|
\***************************************************************************/
|
|
|
|
UINT WINAPI ImmGetDescriptionW(
|
|
HKL hKL,
|
|
LPWSTR lpwszDescription,
|
|
UINT uBufLen)
|
|
{
|
|
IMEINFOEX iiex;
|
|
UINT uRet;
|
|
|
|
if (!ImmGetImeInfoEx(&iiex, ImeInfoExKeyboardLayout, &hKL))
|
|
return 0;
|
|
|
|
#if defined(CUAS_ENABLE)
|
|
if (!IS_IME_KBDLAYOUT(hKL))
|
|
return 0;
|
|
#endif
|
|
|
|
uRet = wcslen(iiex.wszImeDescription);
|
|
|
|
/*
|
|
* ask buffer length
|
|
*/
|
|
if (uBufLen == 0)
|
|
return uRet;
|
|
|
|
if (uBufLen > uRet) {
|
|
wcscpy(lpwszDescription, iiex.wszImeDescription);
|
|
}
|
|
else {
|
|
uRet = uBufLen - 1;
|
|
wcsncpy(lpwszDescription, iiex.wszImeDescription, uRet);
|
|
lpwszDescription[uRet] = L'\0';
|
|
}
|
|
|
|
return uRet;
|
|
}
|
|
|
|
|
|
/***************************************************************************\
|
|
* ImmGetIMEFileNameA
|
|
*
|
|
* Gets the description of the IME with the specified HKL.
|
|
*
|
|
* History:
|
|
* 28-Feb-1995 wkwok Created
|
|
\***************************************************************************/
|
|
|
|
UINT WINAPI ImmGetDescriptionA(
|
|
HKL hKL,
|
|
LPSTR lpszDescription,
|
|
UINT uBufLen)
|
|
{
|
|
IMEINFOEX iiex;
|
|
INT i;
|
|
BOOL bUDC;
|
|
|
|
if (!ImmGetImeInfoEx(&iiex, ImeInfoExKeyboardLayout, &hKL))
|
|
return 0;
|
|
|
|
#if defined(CUAS_ENABLE)
|
|
if (!IS_IME_KBDLAYOUT(hKL))
|
|
return 0;
|
|
#endif
|
|
|
|
i = WideCharToMultiByte(CP_ACP,
|
|
(DWORD)0,
|
|
(LPWSTR)iiex.wszImeDescription, // src
|
|
wcslen(iiex.wszImeDescription),
|
|
lpszDescription, // dest
|
|
uBufLen,
|
|
(LPSTR)NULL,
|
|
(LPBOOL)&bUDC);
|
|
|
|
if (uBufLen != 0)
|
|
lpszDescription[i] = '\0';
|
|
|
|
return (UINT)i;
|
|
}
|
|
|
|
|
|
/***************************************************************************\
|
|
* ImmGetIMEFileNameW
|
|
*
|
|
* Gets the file name of the IME with the specified HKL.
|
|
*
|
|
* History:
|
|
* 28-Feb-1995 wkwok Created
|
|
\***************************************************************************/
|
|
|
|
UINT WINAPI ImmGetIMEFileNameW(
|
|
HKL hKL,
|
|
LPWSTR lpwszFile,
|
|
UINT uBufLen)
|
|
{
|
|
IMEINFOEX iiex;
|
|
UINT uRet;
|
|
|
|
if (!ImmGetImeInfoEx(&iiex, ImeInfoExKeyboardLayout, &hKL))
|
|
return 0;
|
|
|
|
#if defined(CUAS_ENABLE)
|
|
if (!IS_IME_KBDLAYOUT(hKL))
|
|
{
|
|
//
|
|
// #602631
|
|
//
|
|
// Ichitaro12 ATOKLIB.DLL does not check the return value of
|
|
// ImmGetIMEFileName()
|
|
//
|
|
if (uBufLen)
|
|
*lpwszFile = L'\0';
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
uRet = wcslen(iiex.wszImeFile);
|
|
|
|
/*
|
|
* ask buffer length
|
|
*/
|
|
if (uBufLen == 0)
|
|
return uRet;
|
|
|
|
if (uBufLen > uRet) {
|
|
wcscpy(lpwszFile, iiex.wszImeFile);
|
|
}
|
|
else {
|
|
uRet = uBufLen - 1;
|
|
wcsncpy(lpwszFile, iiex.wszImeFile, uRet);
|
|
lpwszFile[uRet] = L'\0';
|
|
}
|
|
|
|
return uRet;
|
|
}
|
|
|
|
|
|
/***************************************************************************\
|
|
* ImmGetIMEFileNameA
|
|
*
|
|
* Gets the file name of the IME with the specified HKL.
|
|
*
|
|
* History:
|
|
* 28-Feb-1995 wkwok Created
|
|
\***************************************************************************/
|
|
|
|
UINT WINAPI ImmGetIMEFileNameA(
|
|
HKL hKL,
|
|
LPSTR lpszFile,
|
|
UINT uBufLen)
|
|
{
|
|
IMEINFOEX iiex;
|
|
INT i;
|
|
BOOL bUDC;
|
|
|
|
if (!ImmGetImeInfoEx(&iiex, ImeInfoExKeyboardLayout, &hKL))
|
|
return 0;
|
|
|
|
#if defined(CUAS_ENABLE)
|
|
if (!IS_IME_KBDLAYOUT(hKL))
|
|
{
|
|
//
|
|
// #602631
|
|
//
|
|
// Ichitaro12 ATOKLIB.DLL does not check the return value of
|
|
// ImmGetIMEFileName()
|
|
//
|
|
if (uBufLen)
|
|
*lpszFile = '\0';
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
i = WideCharToMultiByte(CP_ACP,
|
|
(DWORD)0,
|
|
(LPWSTR)iiex.wszImeFile, // src
|
|
wcslen(iiex.wszImeFile),
|
|
lpszFile, // dest
|
|
uBufLen,
|
|
(LPSTR)NULL,
|
|
(LPBOOL)&bUDC);
|
|
|
|
if (uBufLen != 0)
|
|
lpszFile[i] = '\0';
|
|
|
|
return i;
|
|
}
|
|
|
|
|
|
/***************************************************************************\
|
|
* ImmGetProperty
|
|
*
|
|
* Gets the property and capability of the IME with the specified HKL.
|
|
*
|
|
* History:
|
|
* 28-Feb-1995 wkwok Created
|
|
\***************************************************************************/
|
|
|
|
DWORD WINAPI ImmGetProperty(
|
|
HKL hKL,
|
|
DWORD dwIndex)
|
|
{
|
|
IMEINFOEX iiex;
|
|
PIMEDPI pImeDpi = NULL;
|
|
PIMEINFO pImeInfo;
|
|
DWORD dwRet;
|
|
|
|
if (!ImmGetImeInfoEx(&iiex, ImeInfoExKeyboardLayout, &hKL))
|
|
return 0;
|
|
|
|
if (dwIndex == IGP_GETIMEVERSION)
|
|
return iiex.dwImeWinVersion;
|
|
|
|
if (iiex.fLoadFlag != IMEF_LOADED) {
|
|
pImeDpi = FindOrLoadImeDpi(hKL);
|
|
if (pImeDpi == NULL) {
|
|
RIPMSG0(RIP_WARNING, "ImmGetProperty: load IME failure.");
|
|
return 0;
|
|
}
|
|
pImeInfo = &pImeDpi->ImeInfo;
|
|
}
|
|
else {
|
|
pImeInfo = &iiex.ImeInfo;
|
|
}
|
|
|
|
switch (dwIndex) {
|
|
case IGP_PROPERTY:
|
|
dwRet = pImeInfo->fdwProperty;
|
|
break;
|
|
|
|
case IGP_CONVERSION:
|
|
dwRet = pImeInfo->fdwConversionCaps;
|
|
break;
|
|
|
|
case IGP_SENTENCE:
|
|
dwRet = pImeInfo->fdwSentenceCaps;
|
|
break;
|
|
|
|
case IGP_UI:
|
|
dwRet = pImeInfo->fdwUICaps;
|
|
break;
|
|
|
|
case IGP_SETCOMPSTR:
|
|
dwRet = pImeInfo->fdwSCSCaps;
|
|
break;
|
|
|
|
case IGP_SELECT:
|
|
dwRet = pImeInfo->fdwSelectCaps;
|
|
break;
|
|
|
|
default:
|
|
RIPMSG1(RIP_WARNING, "ImmGetProperty: wrong index %lx.", dwIndex);
|
|
dwRet = 0;
|
|
break;
|
|
}
|
|
|
|
ImmUnlockImeDpi(pImeDpi);
|
|
|
|
return dwRet;
|
|
}
|
|
|
|
|
|
HKL WINAPI ImmInstallIMEW(
|
|
LPCWSTR lpszIMEFileName,
|
|
LPCWSTR lpszLayoutText)
|
|
{
|
|
LPWSTR lpwszImeFileName;
|
|
LPWSTR lpwszImeFilePart;
|
|
LPWSTR lpwszImeCopiedPath;
|
|
int i, nIMEs;
|
|
PIMELAYOUT pImeLayout = NULL;
|
|
HKL hImeKL, hLangKL;
|
|
WCHAR szKeyName[HEX_ASCII_SIZE];
|
|
IMEINFOEX iiex;
|
|
|
|
lpwszImeFileName = ImmLocalAlloc(0, (MAX_PATH+1) * sizeof(WCHAR));
|
|
if (lpwszImeFileName == NULL)
|
|
return (HKL)0;
|
|
|
|
lpwszImeCopiedPath = ImmLocalAlloc(0, (MAX_PATH+1) * sizeof(WCHAR));
|
|
if (lpwszImeCopiedPath == NULL) {
|
|
ImmLocalFree(lpwszImeFileName);
|
|
return (HKL)0;
|
|
}
|
|
|
|
/*
|
|
* Get the file name only into lpwszImeFilePart
|
|
*/
|
|
GetFullPathNameW(lpszIMEFileName, MAX_PATH,
|
|
lpwszImeFileName, &lpwszImeFilePart);
|
|
|
|
CharUpper(lpwszImeFileName);
|
|
|
|
if (lpwszImeFilePart == NULL) {
|
|
ImmLocalFree(lpwszImeFileName);
|
|
ImmLocalFree(lpwszImeCopiedPath);
|
|
return (HKL)0;
|
|
}
|
|
|
|
hImeKL = hLangKL = iiex.hkl = (HKL)0;
|
|
|
|
wcsncpy(iiex.wszImeFile, lpwszImeFilePart, IM_FILE_SIZE-1);
|
|
iiex.wszImeFile[IM_FILE_SIZE - 1] = L'\0';
|
|
|
|
if (LoadVersionInfo(&iiex) && iiex.hkl != (HKL)0) {
|
|
hLangKL = iiex.hkl;
|
|
}
|
|
else {
|
|
ImmLocalFree(lpwszImeFileName);
|
|
ImmLocalFree(lpwszImeCopiedPath);
|
|
return (HKL)0;
|
|
}
|
|
|
|
nIMEs = GetImeLayout(NULL, 0);
|
|
if (nIMEs != 0) {
|
|
pImeLayout = (PIMELAYOUT)ImmLocalAlloc(0, nIMEs * sizeof(IMELAYOUT));
|
|
if (pImeLayout == NULL) {
|
|
ImmLocalFree(lpwszImeFileName);
|
|
ImmLocalFree(lpwszImeCopiedPath);
|
|
return (HKL)0;
|
|
}
|
|
|
|
GetImeLayout(pImeLayout, nIMEs);
|
|
|
|
for (i=0; i < nIMEs; i++) {
|
|
if (_wcsicmp(pImeLayout[i].szImeName, lpwszImeFilePart) == 0) {
|
|
/*
|
|
* We got the same IME name, ISV wants to upgrade.
|
|
*/
|
|
if (LOWORD(HandleToUlong(hLangKL)) != LOWORD(HandleToUlong(pImeLayout[i].hImeKL))) {
|
|
/*
|
|
* IME name conflict, blow out!
|
|
*/
|
|
RIPMSG0(RIP_WARNING, "ImmInstallIME: different language!");
|
|
goto ImmInstallIMEWFailed;
|
|
}
|
|
|
|
hImeKL = pImeLayout[i].hImeKL;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (ImmGetImeInfoEx(&iiex, ImeInfoExImeFileName, lpwszImeFilePart)) {
|
|
/*
|
|
* The specified IME has been activated. Unload it first.
|
|
*/
|
|
if (!UnloadKeyboardLayout(iiex.hkl)) {
|
|
hImeKL = (HKL)0;
|
|
goto ImmInstallIMEWFailed;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* We will copy to system directory
|
|
*/
|
|
#if 0
|
|
i = (INT)GetSystemDirectory(lpwszImeCopiedPath, MAX_PATH);
|
|
lpwszImeCopiedPath[i] = L'\0';
|
|
AddBackslash(lpwszImeCopiedPath);
|
|
wcscat(lpwszImeCopiedPath, lpwszImeFilePart);
|
|
#else
|
|
GetSystemPathName(lpwszImeCopiedPath, lpwszImeFilePart, MAX_PATH);
|
|
#endif
|
|
CharUpper(lpwszImeCopiedPath);
|
|
|
|
if (_wcsicmp(lpwszImeFileName, lpwszImeCopiedPath) != 0) {
|
|
/*
|
|
* path is different, need to copy into system directory
|
|
*/
|
|
if (!CopyImeFile(lpwszImeFileName, lpwszImeCopiedPath)) {
|
|
hImeKL = (HKL)0;
|
|
goto ImmInstallIMEWFailed;
|
|
}
|
|
}
|
|
|
|
if (hImeKL == 0) {
|
|
hImeKL = AssignNewLayout(nIMEs, pImeLayout, hLangKL);
|
|
}
|
|
|
|
if (hImeKL != 0) {
|
|
/*
|
|
* Write HKL under "keyboard layouts"
|
|
*/
|
|
if (WriteImeLayout(hImeKL, lpwszImeFilePart, lpszLayoutText)) {
|
|
UIntToStr(HandleToUlong(hImeKL), 16, szKeyName, sizeof(szKeyName));
|
|
hImeKL = LoadKeyboardLayout(szKeyName, KLF_REPLACELANG);
|
|
}
|
|
else {
|
|
hImeKL = (HKL)0;
|
|
}
|
|
}
|
|
|
|
ImmInstallIMEWFailed:
|
|
if (pImeLayout != NULL)
|
|
ImmLocalFree(pImeLayout);
|
|
ImmLocalFree(lpwszImeFileName);
|
|
ImmLocalFree(lpwszImeCopiedPath);
|
|
|
|
return (HKL)hImeKL;
|
|
}
|
|
|
|
|
|
HKL WINAPI ImmInstallIMEA(
|
|
LPCSTR lpszIMEFileName,
|
|
LPCSTR lpszLayoutText)
|
|
{
|
|
HKL hKL;
|
|
LPWSTR lpwszIMEFileName;
|
|
LPWSTR lpwszLayoutText;
|
|
DWORD cbIMEFileName;
|
|
DWORD cbLayoutText;
|
|
INT i;
|
|
|
|
cbIMEFileName = strlen(lpszIMEFileName) + sizeof(CHAR);
|
|
cbLayoutText = strlen(lpszLayoutText) + sizeof(CHAR);
|
|
|
|
lpwszIMEFileName = ImmLocalAlloc(0, cbIMEFileName * sizeof(WCHAR));
|
|
if (lpwszIMEFileName == NULL) {
|
|
RIPMSG0(RIP_WARNING, "ImmInstallIMEA: memory failure!");
|
|
return (HKL)0;
|
|
}
|
|
|
|
lpwszLayoutText = ImmLocalAlloc(0, cbLayoutText * sizeof(WCHAR));
|
|
if (lpwszLayoutText == NULL) {
|
|
RIPMSG0(RIP_WARNING, "ImmInstallIMEA: memory failure!");
|
|
ImmLocalFree(lpwszIMEFileName);
|
|
return (HKL)0;
|
|
}
|
|
|
|
i = MultiByteToWideChar(CP_ACP,
|
|
(DWORD)MB_PRECOMPOSED,
|
|
(LPSTR)lpszIMEFileName, // src
|
|
(INT)strlen(lpszIMEFileName),
|
|
(LPWSTR)lpwszIMEFileName, // dest
|
|
(INT)cbIMEFileName);
|
|
lpwszIMEFileName[i] = L'\0';
|
|
|
|
i = MultiByteToWideChar(CP_ACP,
|
|
(DWORD)MB_PRECOMPOSED,
|
|
(LPSTR)lpszLayoutText, // src
|
|
(INT)strlen(lpszLayoutText),
|
|
(LPWSTR)lpwszLayoutText, // dest
|
|
(INT)cbLayoutText);
|
|
lpwszLayoutText[i] = L'\0';
|
|
|
|
hKL = ImmInstallIMEW(lpwszIMEFileName, lpwszLayoutText);
|
|
|
|
ImmLocalFree(lpwszLayoutText);
|
|
ImmLocalFree(lpwszIMEFileName);
|
|
|
|
return hKL;
|
|
}
|
|
|
|
|
|
/***************************************************************************\
|
|
* ImmIsIME
|
|
*
|
|
* Checks whether the specified hKL is a HKL of an IME or not.
|
|
*
|
|
* History:
|
|
* 28-Feb-1995 wkwok Created
|
|
\***************************************************************************/
|
|
|
|
BOOL WINAPI ImmIsIME(
|
|
HKL hKL)
|
|
{
|
|
IMEINFOEX iiex;
|
|
|
|
#if !defined(CUAS_ENABLE)
|
|
if (!ImmGetImeInfoEx(&iiex, ImeInfoExKeyboardLayout, &hKL))
|
|
return FALSE;
|
|
#else
|
|
if (!ImmGetImeInfoEx(&iiex, ImeInfoExKeyboardLayoutWithCUAS, &hKL))
|
|
return FALSE;
|
|
#endif
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
UINT StrToUInt(
|
|
LPWSTR lpsz)
|
|
{
|
|
UNICODE_STRING Value;
|
|
UINT ReturnValue;
|
|
|
|
Value.Length = wcslen(lpsz) * sizeof(WCHAR);
|
|
Value.Buffer = lpsz;
|
|
|
|
/*
|
|
* Convert string to int.
|
|
*/
|
|
RtlUnicodeStringToInteger(&Value, 16, &ReturnValue);
|
|
return(ReturnValue);
|
|
}
|
|
|
|
|
|
VOID UIntToStr(
|
|
UINT Value,
|
|
ULONG Base,
|
|
LPWSTR lpsz,
|
|
USHORT dwBufLen)
|
|
{
|
|
UNICODE_STRING String;
|
|
|
|
String.Length = dwBufLen;
|
|
String.MaximumLength = dwBufLen;
|
|
String.Buffer = lpsz;
|
|
|
|
/*
|
|
* Convert int to string.
|
|
*/
|
|
RtlIntegerToUnicodeString(Value, Base, &String);
|
|
}
|
|
|
|
|
|
BOOL CopyImeFile(
|
|
LPWSTR lpwszImeFileName,
|
|
LPCWSTR lpwszImeCopiedPath)
|
|
{
|
|
HMODULE hLzExpandDll;
|
|
BOOL fUnloadExpandDll;
|
|
LPFNLZOPENFILEW lpfnLZOpenFileW;
|
|
LPFNLZCOPY lpfnLZCopy;
|
|
LPFNLZCLOSE lpfnLZClose;
|
|
OFSTRUCT ofStruc;
|
|
HFILE hfSource, hfDest;
|
|
LPSTR lpszImeCopiedPath;
|
|
INT i, cbBuffer;
|
|
BOOL fRet = FALSE;
|
|
|
|
hLzExpandDll = GetModuleHandle(L"LZ32");
|
|
if (hLzExpandDll) {
|
|
fUnloadExpandDll = FALSE;
|
|
} else {
|
|
WCHAR szLzExpand[MAX_PATH];
|
|
|
|
GetSystemPathName(szLzExpand, L"LZ32", MAX_PATH);
|
|
hLzExpandDll = LoadLibrary(szLzExpand);
|
|
if (!hLzExpandDll) {
|
|
return FALSE;
|
|
}
|
|
|
|
fUnloadExpandDll = TRUE;
|
|
}
|
|
|
|
#define GET_PROC(x) \
|
|
if (!(lpfn##x = (PVOID) GetProcAddress(hLzExpandDll, sz##x))) { \
|
|
goto CopyImeFileFailed; }
|
|
|
|
GET_PROC(LZOpenFileW);
|
|
GET_PROC(LZCopy);
|
|
GET_PROC(LZClose);
|
|
|
|
#undef GET_PROC
|
|
|
|
cbBuffer = (wcslen(lpwszImeCopiedPath) + 1) * sizeof(WCHAR);
|
|
|
|
if ((lpszImeCopiedPath = ImmLocalAlloc(0, cbBuffer)) == NULL)
|
|
goto CopyImeFileFailed;
|
|
|
|
i = WideCharToMultiByte(CP_ACP,
|
|
(DWORD)0,
|
|
lpwszImeCopiedPath, // src
|
|
wcslen(lpwszImeCopiedPath),
|
|
lpszImeCopiedPath, // dest
|
|
cbBuffer,
|
|
(LPSTR)NULL,
|
|
(LPBOOL)NULL);
|
|
if (i == 0) {
|
|
ImmLocalFree(lpszImeCopiedPath);
|
|
goto CopyImeFileFailed;
|
|
}
|
|
|
|
lpszImeCopiedPath[i] = '\0';
|
|
|
|
hfSource = (*lpfnLZOpenFileW)(lpwszImeFileName, &ofStruc, OF_READ);
|
|
if (hfSource < 0) {
|
|
ImmLocalFree(lpszImeCopiedPath);
|
|
goto CopyImeFileFailed;
|
|
}
|
|
|
|
hfDest = OpenFile(lpszImeCopiedPath, &ofStruc, OF_CREATE);
|
|
if (hfDest != HFILE_ERROR) {
|
|
if ((*lpfnLZCopy)(hfSource, hfDest) >= 0) {
|
|
fRet = TRUE;
|
|
}
|
|
_lclose(hfDest);
|
|
}
|
|
|
|
(*lpfnLZClose)(hfSource);
|
|
|
|
ImmLocalFree(lpszImeCopiedPath);
|
|
|
|
CopyImeFileFailed:
|
|
if (fUnloadExpandDll)
|
|
FreeLibrary(hLzExpandDll);
|
|
|
|
return fRet;
|
|
}
|
|
|
|
|
|
INT GetImeLayout(
|
|
PIMELAYOUT pImeLayout,
|
|
INT cEntery)
|
|
{
|
|
int i, nIMEs;
|
|
HKEY hKeyKbdLayout;
|
|
HKEY hKeyOneIME;
|
|
WCHAR szKeyName[HEX_ASCII_SIZE];
|
|
WCHAR szImeFileName[IM_FILE_SIZE];
|
|
CONST DWORD dwKeyNameSize = ARRAY_SIZE(szKeyName);
|
|
DWORD dwTmp;
|
|
|
|
RegOpenKey(HKEY_LOCAL_MACHINE, gszRegKbdLayout, &hKeyKbdLayout);
|
|
|
|
for (i = 0, nIMEs = 0;
|
|
RegEnumKey(hKeyKbdLayout, i, szKeyName, dwKeyNameSize) == ERROR_SUCCESS;
|
|
i++)
|
|
{
|
|
if (szKeyName[0] != L'E' && szKeyName[0] != L'e')
|
|
continue; // this is not an IME based keyboard layout.
|
|
|
|
if (pImeLayout != NULL) {
|
|
|
|
if (nIMEs >= cEntery)
|
|
break;
|
|
|
|
RegOpenKey(hKeyKbdLayout, szKeyName, &hKeyOneIME);
|
|
|
|
dwTmp = IM_FILE_SIZE;
|
|
|
|
RegQueryValueEx(hKeyOneIME,
|
|
gszValImeFile,
|
|
NULL,
|
|
NULL,
|
|
(LPBYTE)szImeFileName,
|
|
&dwTmp);
|
|
|
|
// avoid length problem
|
|
szImeFileName[IM_FILE_SIZE - 1] = L'\0';
|
|
|
|
RegCloseKey(hKeyOneIME);
|
|
|
|
CharUpper(szImeFileName);
|
|
|
|
pImeLayout[nIMEs].hImeKL = (HKL)IntToPtr( StrToUInt(szKeyName) );
|
|
wcscpy(pImeLayout[nIMEs].szKeyName, szKeyName);
|
|
wcscpy(pImeLayout[nIMEs].szImeName, szImeFileName);
|
|
}
|
|
|
|
nIMEs++;
|
|
}
|
|
|
|
RegCloseKey(hKeyKbdLayout);
|
|
|
|
return nIMEs;
|
|
}
|
|
|
|
|
|
BOOL WriteImeLayout(
|
|
HKL hImeKL,
|
|
LPCWSTR lpwszImeFilePart,
|
|
LPCWSTR lpszLayoutText)
|
|
{
|
|
int i;
|
|
HKEY hKeyKbdLayout;
|
|
HKEY hKeyOneIME;
|
|
HKEY hKeyKbdOrder;
|
|
WCHAR szKeyName[HEX_ASCII_SIZE];
|
|
WCHAR szImeFileName[IM_FILE_SIZE];
|
|
WCHAR szOrderNum[HEX_ASCII_SIZE];
|
|
WCHAR szOrderKeyName[HEX_ASCII_SIZE];
|
|
DWORD dwTmp;
|
|
|
|
if (RegOpenKey(HKEY_LOCAL_MACHINE,
|
|
gszRegKbdLayout,
|
|
&hKeyKbdLayout) != ERROR_SUCCESS) {
|
|
RIPMSG0(RIP_WARNING, "WriteImeLayout: RegOpenKey() failed!");
|
|
return FALSE;
|
|
}
|
|
|
|
UIntToStr(HandleToUlong(hImeKL), 16, szKeyName, sizeof(szKeyName));
|
|
|
|
if (RegCreateKey(hKeyKbdLayout,
|
|
szKeyName,
|
|
&hKeyOneIME) != ERROR_SUCCESS) {
|
|
RIPMSG0(RIP_WARNING, "WriteImeLayout: RegCreateKey() failed!");
|
|
RegCloseKey(hKeyKbdLayout);
|
|
return FALSE;
|
|
}
|
|
|
|
if (RegSetValueExW(hKeyOneIME,
|
|
gszValImeFile,
|
|
0,
|
|
REG_SZ,
|
|
(CONST BYTE*)lpwszImeFilePart,
|
|
(wcslen(lpwszImeFilePart) + 1) * sizeof(WCHAR)) != ERROR_SUCCESS) {
|
|
goto WriteImeLayoutFail;
|
|
}
|
|
|
|
if (RegSetValueExW(hKeyOneIME,
|
|
gszValLayoutText,
|
|
0,
|
|
REG_SZ,
|
|
(CONST BYTE*)lpszLayoutText,
|
|
(wcslen(lpszLayoutText) + 1) * sizeof(WCHAR)) != ERROR_SUCCESS) {
|
|
goto WriteImeLayoutFail;
|
|
}
|
|
|
|
switch (LANGIDFROMHKL(hImeKL)) {
|
|
case LANG_JAPANESE:
|
|
wcscpy(szImeFileName, L"kbdjpn.dll");
|
|
break;
|
|
case LANG_KOREAN:
|
|
wcscpy(szImeFileName, L"kbdkor.dll");
|
|
break;
|
|
case LANG_CHINESE:
|
|
default:
|
|
wcscpy(szImeFileName, L"kbdus.dll");
|
|
break;
|
|
}
|
|
|
|
if (RegSetValueExW(hKeyOneIME,
|
|
gszValLayoutFile,
|
|
0,
|
|
REG_SZ,
|
|
(CONST BYTE*)szImeFileName,
|
|
(wcslen(szImeFileName) + 1) * sizeof(WCHAR)) != ERROR_SUCCESS) {
|
|
goto WriteImeLayoutFail;
|
|
}
|
|
|
|
RegCloseKey(hKeyOneIME);
|
|
RegCloseKey(hKeyKbdLayout);
|
|
|
|
/*
|
|
* Update CurrentUser's preload keyboard layout setting
|
|
*/
|
|
RegCreateKey(HKEY_CURRENT_USER, gszRegKbdOrder, &hKeyKbdOrder);
|
|
|
|
for (i = 1; i < 1024; i++) {
|
|
UIntToStr(i, 10, szOrderNum, sizeof(szOrderNum));
|
|
|
|
dwTmp = sizeof(szOrderKeyName);
|
|
if (RegQueryValueEx(hKeyKbdOrder,
|
|
szOrderNum,
|
|
NULL,
|
|
NULL,
|
|
(LPBYTE)szOrderKeyName,
|
|
&dwTmp) != ERROR_SUCCESS) {
|
|
break;
|
|
}
|
|
|
|
if (_wcsicmp(szKeyName, szOrderKeyName) == 0) {
|
|
/*
|
|
* We have the same value in the preload!
|
|
* OK, ISV is developing their IMEs
|
|
* so even it is in preload, but it can not be loaded
|
|
*/
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (i < 1024) {
|
|
/*
|
|
* Write a subkey under "preload"
|
|
*/
|
|
RegSetValueExW(hKeyKbdOrder,
|
|
szOrderNum,
|
|
0,
|
|
REG_SZ,
|
|
(CONST BYTE*)szKeyName,
|
|
(lstrlen(szKeyName) + 1) * sizeof(WCHAR));
|
|
RegCloseKey(hKeyKbdOrder);
|
|
}
|
|
else {
|
|
RegCloseKey(hKeyKbdOrder);
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
WriteImeLayoutFail:
|
|
RegCloseKey(hKeyOneIME);
|
|
RegDeleteKey(hKeyKbdLayout, szKeyName);
|
|
RegCloseKey(hKeyKbdLayout);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
#define IMELANGID(hkl) \
|
|
LOWORD(HandleToUlong(hkl))
|
|
|
|
#define IMELAYOUTID(hkl) \
|
|
HIWORD(HandleToUlong(hkl))
|
|
|
|
HKL AssignNewLayout(
|
|
INT nIMEs,
|
|
PIMELAYOUT pImeLayout,
|
|
HKL hLangKL)
|
|
{
|
|
DWORD dwNewId = 0;
|
|
DWORD dwHighId = 0xE01F;
|
|
DWORD dwLowId = 0xE0FF;
|
|
INT i;
|
|
|
|
/*
|
|
* We prefer the value higher than E01F for ISVs, we will use
|
|
* E001 ~ E01F in Microsoft .INF file
|
|
*/
|
|
|
|
/*
|
|
* Find out the high and low one
|
|
*/
|
|
for (i = 0; i < nIMEs; ++i) {
|
|
/*
|
|
* Let's try to keep the previous behavior, not to
|
|
* have the duplicated hiword in hkl.
|
|
*/
|
|
if (IMELAYOUTID(pImeLayout[i].hImeKL) > dwHighId) {
|
|
dwHighId = IMELAYOUTID(pImeLayout[i].hImeKL);
|
|
}
|
|
if (IMELAYOUTID(pImeLayout[i].hImeKL) < dwLowId) {
|
|
dwLowId = IMELAYOUTID(pImeLayout[i].hImeKL);
|
|
}
|
|
}
|
|
|
|
if (dwHighId < 0xE0FF) {
|
|
dwNewId = dwHighId + 1;
|
|
} else if (dwLowId > 0xE001) {
|
|
dwNewId = dwLowId - 1;
|
|
} else {
|
|
/*
|
|
* Need to find out unused hKL using full search.
|
|
* Find it one by one.
|
|
*/
|
|
DWORD dwId;
|
|
|
|
for (dwId = 0xE020; dwId < 0xE100; ++dwId) {
|
|
for (i = 0; i < nIMEs; ++i) {
|
|
if (IMELAYOUTID(pImeLayout[i].hImeKL) == dwId &&
|
|
IMELANGID(pImeLayout[i].hImeKL) == IMELANGID(hLangKL)) {
|
|
// conflicts with existing IME, try the next dwLowId
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (i >= nIMEs) {
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
if (dwId < 0xE100) {
|
|
dwNewId = dwId;
|
|
}
|
|
}
|
|
|
|
if (dwNewId == 0) {
|
|
return NULL;
|
|
}
|
|
|
|
return (HKL)UIntToPtr(MAKELONG(IMELANGID(hLangKL), dwNewId));
|
|
}
|