[KBSWITCH] Rely on GetKeyboardLayoutList for getting list (#5263)

- Use GetKeyboardLayoutList to get the keyboard list instead of using Preload registry key.
- Get the special IDs from registry to handle special HKLs in newly-added LoadSpecialIds function.
- Add GetKLIDFromHKL, GetHKLFromLayoutNum, UpdateLayoutList, and GetKLIDFromLayoutNum helper functions.
CORE-13145, CORE-10667, CORE-18924
This commit is contained in:
Katayama Hirofumi MZ 2023-05-03 07:45:35 +09:00 committed by GitHub
parent e6bced7a35
commit a0bef1998e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -26,6 +26,13 @@
* won't be generated in Vista+. * won't be generated in Vista+.
*/ */
#define IME_MASK (0xE0000000UL)
#define SPECIAL_MASK (0xF0000000UL)
#define IS_IME_HKL(hKL) ((((ULONG_PTR)(hKL)) & 0xF0000000) == IME_MASK)
#define IS_SPECIAL_HKL(hKL) ((((ULONG_PTR)(hKL)) & 0xF0000000) == SPECIAL_MASK)
#define SPECIALIDFROMHKL(hKL) ((WORD)(HIWORD(hKL) & 0x0FFF))
#define WM_NOTIFYICONMSG (WM_USER + 248) #define WM_NOTIFYICONMSG (WM_USER + 248)
PKBSWITCHSETHOOKS KbSwitchSetHooks = NULL; PKBSWITCHSETHOOKS KbSwitchSetHooks = NULL;
@ -35,52 +42,158 @@ UINT ShellHookMessage = 0;
HINSTANCE hInst; HINSTANCE hInst;
HANDLE hProcessHeap; HANDLE hProcessHeap;
HMODULE g_hHookDLL = NULL; HMODULE g_hHookDLL = NULL;
ULONG ulCurrentLayoutNum = 1; INT g_nCurrentLayoutNum = 1;
HICON g_hTrayIcon = NULL; HICON g_hTrayIcon = NULL;
HWND g_hwndLastActive = NULL; HWND g_hwndLastActive = NULL;
INT g_cKLs = 0;
HKL g_ahKLs[64];
static BOOL typedef struct
GetLayoutID(LPCTSTR szLayoutNum, LPTSTR szLCID, SIZE_T LCIDLength)
{ {
DWORD dwBufLen, dwRes; DWORD dwLayoutId;
HKEY hKey; HKL hKL;
TCHAR szTempLCID[CCH_LAYOUT_ID + 1]; TCHAR szKLID[CCH_LAYOUT_ID + 1];
} SPECIAL_ID, *PSPECIAL_ID;
/* Get the Layout ID */ SPECIAL_ID g_SpecialIds[80];
if (RegOpenKeyEx(HKEY_CURRENT_USER, _T("Keyboard Layout\\Preload"), 0, KEY_QUERY_VALUE, INT g_cSpecialIds = 0;
&hKey) == ERROR_SUCCESS)
static VOID LoadSpecialIds(VOID)
{
TCHAR szKLID[KL_NAMELENGTH], szLayoutId[16];
DWORD dwSize, dwIndex;
HKEY hKey, hLayoutKey;
g_cSpecialIds = 0;
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
TEXT("SYSTEM\\CurrentControlSet\\Control\\Keyboard Layouts"),
0, KEY_READ, &hKey) != ERROR_SUCCESS)
{ {
dwBufLen = sizeof(szTempLCID); return;
dwRes = RegQueryValueEx(hKey, szLayoutNum, NULL, NULL, (LPBYTE)szTempLCID, &dwBufLen);
if (dwRes != ERROR_SUCCESS)
{
RegCloseKey(hKey);
return FALSE;
}
RegCloseKey(hKey);
} }
/* Look for a substitute of this layout */ for (dwIndex = 0; dwIndex < 1000; ++dwIndex)
if (RegOpenKeyEx(HKEY_CURRENT_USER, _T("Keyboard Layout\\Substitutes"), 0,
KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS)
{ {
dwBufLen = sizeof(szTempLCID); dwSize = ARRAYSIZE(szKLID);
if (RegQueryValueEx(hKey, szTempLCID, NULL, NULL, (LPBYTE)szLCID, &dwBufLen) != ERROR_SUCCESS) if (RegEnumKeyEx(hKey, dwIndex, szKLID, &dwSize, NULL, NULL, NULL, NULL) != ERROR_SUCCESS)
break;
if (RegOpenKeyEx(hKey, szKLID, 0, KEY_READ, &hLayoutKey) != ERROR_SUCCESS)
continue;
dwSize = sizeof(szLayoutId);
if (RegQueryValueEx(hLayoutKey, TEXT("Layout Id"), NULL, NULL,
(LPBYTE)szLayoutId, &dwSize) == ERROR_SUCCESS)
{ {
/* No substitute found, then use the old LCID */ DWORD dwKLID = _tcstoul(szKLID, NULL, 16);
StringCchCopy(szLCID, LCIDLength, szTempLCID); WORD wLangId = LOWORD(dwKLID), wLayoutId = LOWORD(_tcstoul(szLayoutId, NULL, 16));
HKL hKL = (HKL)(LONG_PTR)(SPECIAL_MASK | MAKELONG(wLangId, wLayoutId));
/* Add a special ID */
g_SpecialIds[g_cSpecialIds].dwLayoutId = wLayoutId;
g_SpecialIds[g_cSpecialIds].hKL = hKL;
StringCchCopy(g_SpecialIds[g_cSpecialIds].szKLID,
ARRAYSIZE(g_SpecialIds[g_cSpecialIds].szKLID), szKLID);
++g_cSpecialIds;
} }
RegCloseKey(hKey); RegCloseKey(hLayoutKey);
if (g_cSpecialIds >= ARRAYSIZE(g_SpecialIds))
{
OutputDebugStringA("g_SpecialIds is full!");
break;
}
}
RegCloseKey(hKey);
}
static VOID
GetKLIDFromHKL(HKL hKL, LPTSTR szKLID, SIZE_T KLIDLength)
{
szKLID[0] = 0;
if (IS_IME_HKL(hKL))
{
StringCchPrintf(szKLID, KLIDLength, _T("%08lx"), (DWORD)(DWORD_PTR)hKL);
return;
}
if (IS_SPECIAL_HKL(hKL))
{
INT i;
for (i = 0; i < g_cSpecialIds; ++i)
{
if (g_SpecialIds[i].hKL == hKL)
{
StringCchCopy(szKLID, KLIDLength, g_SpecialIds[i].szKLID);
return;
}
}
} }
else else
{ {
/* Substitutes key couldn't be opened, so use the old LCID */ StringCchPrintf(szKLID, KLIDLength, _T("%08lx"), LOWORD(hKL));
StringCchCopy(szLCID, LCIDLength, szTempLCID); }
}
static VOID UpdateLayoutList(HKL hKL OPTIONAL)
{
INT iKL;
if (!hKL)
{
if (0 <= (g_nCurrentLayoutNum - 1) && (g_nCurrentLayoutNum - 1) < g_cKLs)
{
hKL = g_ahKLs[g_nCurrentLayoutNum - 1];
}
else
{
HWND hwndTarget = (g_hwndLastActive ? g_hwndLastActive : GetForegroundWindow());
DWORD dwTID = GetWindowThreadProcessId(hwndTarget, NULL);
hKL = GetKeyboardLayout(dwTID);
}
} }
return TRUE; g_cKLs = GetKeyboardLayoutList(ARRAYSIZE(g_ahKLs), g_ahKLs);
g_nCurrentLayoutNum = -1;
for (iKL = 0; iKL < g_cKLs; ++iKL)
{
if (g_ahKLs[iKL] == hKL)
{
g_nCurrentLayoutNum = iKL + 1;
break;
}
}
if (g_nCurrentLayoutNum == -1 && g_cKLs < ARRAYSIZE(g_ahKLs))
{
g_nCurrentLayoutNum = g_cKLs;
g_ahKLs[g_cKLs++] = hKL;
}
}
static HKL GetHKLFromLayoutNum(INT nLayoutNum)
{
if (0 <= (nLayoutNum - 1) && (nLayoutNum - 1) < g_cKLs)
{
return g_ahKLs[nLayoutNum - 1];
}
else
{
HWND hwndTarget = (g_hwndLastActive ? g_hwndLastActive : GetForegroundWindow());
DWORD dwTID = GetWindowThreadProcessId(hwndTarget, NULL);
return GetKeyboardLayout(dwTID);
}
}
static VOID
GetKLIDFromLayoutNum(INT nLayoutNum, LPTSTR szKLID, SIZE_T KLIDLength)
{
GetKLIDFromHKL(GetHKLFromLayoutNum(nLayoutNum), szKLID, KLIDLength);
} }
static BOOL static BOOL
@ -95,21 +208,19 @@ GetSystemLibraryPath(LPTSTR szPath, SIZE_T cchPath, LPCTSTR FileName)
} }
static BOOL static BOOL
GetLayoutName(LPCTSTR szLayoutNum, LPTSTR szName, SIZE_T NameLength) GetLayoutName(INT nLayoutNum, LPTSTR szName, SIZE_T NameLength)
{ {
HKEY hKey; HKEY hKey;
HRESULT hr; HRESULT hr;
DWORD dwBufLen; DWORD dwBufLen;
TCHAR szBuf[MAX_PATH]; TCHAR szBuf[MAX_PATH], szKLID[CCH_LAYOUT_ID + 1];
TCHAR szLCID[CCH_LAYOUT_ID + 1];
if (!GetLayoutID(szLayoutNum, szLCID, ARRAYSIZE(szLCID))) GetKLIDFromLayoutNum(nLayoutNum, szKLID, ARRAYSIZE(szKLID));
return FALSE;
StringCchPrintf(szBuf, ARRAYSIZE(szBuf), StringCchPrintf(szBuf, ARRAYSIZE(szBuf),
_T("SYSTEM\\CurrentControlSet\\Control\\Keyboard Layouts\\%s"), szLCID); _T("SYSTEM\\CurrentControlSet\\Control\\Keyboard Layouts\\%s"), szKLID);
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, szBuf, 0, KEY_QUERY_VALUE, &hKey) != ERROR_SUCCESS) if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, szBuf, 0, KEY_READ, &hKey) != ERROR_SUCCESS)
return FALSE; return FALSE;
/* Use "Layout Display Name" value as an entry name if possible */ /* Use "Layout Display Name" value as an entry name if possible */
@ -123,17 +234,17 @@ GetLayoutName(LPCTSTR szLayoutNum, LPTSTR szName, SIZE_T NameLength)
/* Otherwise, use "Layout Text" value as an entry name */ /* Otherwise, use "Layout Text" value as an entry name */
dwBufLen = NameLength * sizeof(TCHAR); dwBufLen = NameLength * sizeof(TCHAR);
if (RegQueryValueEx(hKey, _T("Layout Text"), NULL, NULL, if (RegQueryValueEx(hKey, _T("Layout Text"), NULL, NULL,
(LPBYTE)szName, &dwBufLen) != ERROR_SUCCESS) (LPBYTE)szName, &dwBufLen) == ERROR_SUCCESS)
{ {
RegCloseKey(hKey); RegCloseKey(hKey);
return FALSE; return TRUE;
} }
RegCloseKey(hKey); RegCloseKey(hKey);
return TRUE; return FALSE;
} }
static BOOL GetImeFile(LPTSTR szImeFile, SIZE_T cchImeFile, LPCTSTR szLCID) static BOOL GetImeFile(LPTSTR szImeFile, SIZE_T cchImeFile, LPCTSTR szKLID)
{ {
HKEY hKey; HKEY hKey;
DWORD dwBufLen; DWORD dwBufLen;
@ -141,19 +252,17 @@ static BOOL GetImeFile(LPTSTR szImeFile, SIZE_T cchImeFile, LPCTSTR szLCID)
szImeFile[0] = UNICODE_NULL; szImeFile[0] = UNICODE_NULL;
if (_tcslen(szLCID) != CCH_LAYOUT_ID) if (_tcslen(szKLID) != CCH_LAYOUT_ID)
return FALSE; /* Invalid LCID */ return FALSE; /* Invalid LCID */
if (szLCID[0] != TEXT('E') && szLCID[0] != TEXT('e')) if (szKLID[0] != TEXT('E') && szKLID[0] != TEXT('e'))
return FALSE; /* Not an IME HKL */ return FALSE; /* Not an IME HKL */
StringCchPrintf(szBuf, ARRAYSIZE(szBuf), StringCchPrintf(szBuf, ARRAYSIZE(szBuf),
_T("SYSTEM\\CurrentControlSet\\Control\\Keyboard Layouts\\%s"), szLCID); _T("SYSTEM\\CurrentControlSet\\Control\\Keyboard Layouts\\%s"), szKLID);
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, szBuf, 0, KEY_QUERY_VALUE, &hKey) != ERROR_SUCCESS) if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, szBuf, 0, KEY_QUERY_VALUE, &hKey) != ERROR_SUCCESS)
{
return FALSE; return FALSE;
}
dwBufLen = cchImeFile * sizeof(TCHAR); dwBufLen = cchImeFile * sizeof(TCHAR);
if (RegQueryValueEx(hKey, _T("IME File"), NULL, NULL, if (RegQueryValueEx(hKey, _T("IME File"), NULL, NULL,
@ -223,7 +332,7 @@ static HBITMAP BitmapFromIcon(HICON hIcon)
} }
static HICON static HICON
CreateTrayIcon(LPTSTR szLCID, LPCTSTR szImeFile OPTIONAL) CreateTrayIcon(LPTSTR szKLID, LPCTSTR szImeFile OPTIONAL)
{ {
LANGID LangID; LANGID LangID;
TCHAR szBuf[4]; TCHAR szBuf[4];
@ -245,7 +354,7 @@ CreateTrayIcon(LPTSTR szLCID, LPCTSTR szImeFile OPTIONAL)
} }
/* Getting "EN", "FR", etc. from English, French, ... */ /* Getting "EN", "FR", etc. from English, French, ... */
LangID = LANGIDFROMLCID(_tcstoul(szLCID, NULL, 16)); LangID = LANGIDFROMLCID(_tcstoul(szKLID, NULL, 16));
if (GetLocaleInfo(LangID, if (GetLocaleInfo(LangID,
LOCALE_SABBREVLANGNAME | LOCALE_NOUSEROVERRIDE, LOCALE_SABBREVLANGNAME | LOCALE_NOUSEROVERRIDE,
szBuf, szBuf,
@ -323,15 +432,14 @@ static VOID
AddTrayIcon(HWND hwnd) AddTrayIcon(HWND hwnd)
{ {
NOTIFYICONDATA tnid = { sizeof(tnid), hwnd, 1, NIF_ICON | NIF_MESSAGE | NIF_TIP }; NOTIFYICONDATA tnid = { sizeof(tnid), hwnd, 1, NIF_ICON | NIF_MESSAGE | NIF_TIP };
TCHAR szLCID[CCH_LAYOUT_ID + 1], szName[MAX_PATH]; TCHAR szKLID[CCH_LAYOUT_ID + 1], szName[MAX_PATH], szImeFile[80];
TCHAR szImeFile[80];
GetLayoutID(_T("1"), szLCID, ARRAYSIZE(szLCID)); GetKLIDFromLayoutNum(g_nCurrentLayoutNum, szKLID, ARRAYSIZE(szKLID));
GetLayoutName(_T("1"), szName, ARRAYSIZE(szName)); GetLayoutName(g_nCurrentLayoutNum, szName, ARRAYSIZE(szName));
GetImeFile(szImeFile, ARRAYSIZE(szImeFile), szLCID); GetImeFile(szImeFile, ARRAYSIZE(szImeFile), szKLID);
tnid.uCallbackMessage = WM_NOTIFYICONMSG; tnid.uCallbackMessage = WM_NOTIFYICONMSG;
tnid.hIcon = CreateTrayIcon(szLCID, szImeFile); tnid.hIcon = CreateTrayIcon(szKLID, szImeFile);
StringCchCopy(tnid.szTip, ARRAYSIZE(tnid.szTip), szName); StringCchCopy(tnid.szTip, ARRAYSIZE(tnid.szTip), szName);
Shell_NotifyIcon(NIM_ADD, &tnid); Shell_NotifyIcon(NIM_ADD, &tnid);
@ -355,15 +463,15 @@ DeleteTrayIcon(HWND hwnd)
} }
static VOID static VOID
UpdateTrayIcon(HWND hwnd, LPTSTR szLCID, LPTSTR szName) UpdateTrayIcon(HWND hwnd, LPTSTR szKLID, LPTSTR szName)
{ {
NOTIFYICONDATA tnid = { sizeof(tnid), hwnd, 1, NIF_ICON | NIF_MESSAGE | NIF_TIP }; NOTIFYICONDATA tnid = { sizeof(tnid), hwnd, 1, NIF_ICON | NIF_MESSAGE | NIF_TIP };
TCHAR szImeFile[80]; TCHAR szImeFile[80];
GetImeFile(szImeFile, ARRAYSIZE(szImeFile), szLCID); GetImeFile(szImeFile, ARRAYSIZE(szImeFile), szKLID);
tnid.uCallbackMessage = WM_NOTIFYICONMSG; tnid.uCallbackMessage = WM_NOTIFYICONMSG;
tnid.hIcon = CreateTrayIcon(szLCID, szImeFile); tnid.hIcon = CreateTrayIcon(szKLID, szImeFile);
StringCchCopy(tnid.szTip, ARRAYSIZE(tnid.szTip), szName); StringCchCopy(tnid.szTip, ARRAYSIZE(tnid.szTip), szName);
Shell_NotifyIcon(NIM_MODIFY, &tnid); Shell_NotifyIcon(NIM_MODIFY, &tnid);
@ -373,12 +481,6 @@ UpdateTrayIcon(HWND hwnd, LPTSTR szLCID, LPTSTR szName)
g_hTrayIcon = tnid.hIcon; g_hTrayIcon = tnid.hIcon;
} }
static VOID
GetLayoutIDByHkl(HKL hKl, LPTSTR szLayoutID, SIZE_T LayoutIDLength)
{
StringCchPrintf(szLayoutID, LayoutIDLength, _T("%08lx"), (DWORD)(DWORD_PTR)(hKl));
}
static BOOL CALLBACK static BOOL CALLBACK
EnumWindowsProc(HWND hwnd, LPARAM lParam) EnumWindowsProc(HWND hwnd, LPARAM lParam)
{ {
@ -390,25 +492,24 @@ static VOID
ActivateLayout(HWND hwnd, ULONG uLayoutNum, HWND hwndTarget OPTIONAL, BOOL bNoActivate) ActivateLayout(HWND hwnd, ULONG uLayoutNum, HWND hwndTarget OPTIONAL, BOOL bNoActivate)
{ {
HKL hKl; HKL hKl;
TCHAR szLayoutNum[CCH_ULONG_DEC + 1], szLCID[CCH_LAYOUT_ID + 1], szLangName[MAX_PATH]; TCHAR szKLID[CCH_LAYOUT_ID + 1], szLangName[MAX_PATH];
LANGID LangID; LANGID LangID;
/* The layout number starts from one. Zero is invalid */ /* The layout number starts from one. Zero is invalid */
if (uLayoutNum == 0 || uLayoutNum > 0xFF) /* Invalid */ if (uLayoutNum == 0 || uLayoutNum > 0xFF) /* Invalid */
return; return;
_ultot(uLayoutNum, szLayoutNum, 10); GetKLIDFromLayoutNum(uLayoutNum, szKLID, ARRAYSIZE(szKLID));
GetLayoutID(szLayoutNum, szLCID, ARRAYSIZE(szLCID)); LangID = (LANGID)_tcstoul(szKLID, NULL, 16);
LangID = (LANGID)_tcstoul(szLCID, NULL, 16);
/* Switch to the new keyboard layout */ /* Switch to the new keyboard layout */
GetLocaleInfo(LangID, LOCALE_SLANGUAGE, szLangName, ARRAYSIZE(szLangName)); GetLocaleInfo(LangID, LOCALE_SLANGUAGE, szLangName, ARRAYSIZE(szLangName));
UpdateTrayIcon(hwnd, szLCID, szLangName); UpdateTrayIcon(hwnd, szKLID, szLangName);
if (hwndTarget && !bNoActivate) if (hwndTarget && !bNoActivate)
SetForegroundWindow(hwndTarget); SetForegroundWindow(hwndTarget);
hKl = LoadKeyboardLayout(szLCID, KLF_ACTIVATE); hKl = LoadKeyboardLayout(szKLID, KLF_ACTIVATE);
if (hKl) if (hKl)
ActivateKeyboardLayout(hKl, KLF_SETFORPROCESS); ActivateKeyboardLayout(hKl, KLF_SETFORPROCESS);
@ -423,97 +524,47 @@ ActivateLayout(HWND hwnd, ULONG uLayoutNum, HWND hwndTarget OPTIONAL, BOOL bNoAc
EnumWindows(EnumWindowsProc, (LPARAM) hKl); EnumWindows(EnumWindowsProc, (LPARAM) hKl);
} }
ulCurrentLayoutNum = uLayoutNum; g_nCurrentLayoutNum = uLayoutNum;
} }
static HMENU static HMENU
BuildLeftPopupMenu(VOID) BuildLeftPopupMenu(VOID)
{ {
HMENU hMenu = CreatePopupMenu(); HMENU hMenu = CreatePopupMenu();
HKEY hKey; TCHAR szName[MAX_PATH], szKLID[CCH_LAYOUT_ID + 1], szImeFile[80];
DWORD dwIndex, dwSize;
TCHAR szLayoutNum[CCH_ULONG_DEC + 1], szName[MAX_PATH];
TCHAR szLCID[CCH_LAYOUT_ID + 1], szImeFile[80];
HICON hIcon; HICON hIcon;
MENUITEMINFO mii = { sizeof(mii) }; MENUITEMINFO mii = { sizeof(mii) };
INT iKL;
/* Add the keyboard layouts to the popup menu */ for (iKL = 0; iKL < g_cKLs; ++iKL)
if (RegOpenKeyEx(HKEY_CURRENT_USER, _T("Keyboard Layout\\Preload"), 0,
KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS)
{ {
for (dwIndex = 0; ; dwIndex++) GetKLIDFromHKL(g_ahKLs[iKL], szKLID, ARRAYSIZE(szKLID));
GetImeFile(szImeFile, ARRAYSIZE(szImeFile), szKLID);
if (!GetLayoutName(iKL + 1, szName, ARRAYSIZE(szName)))
continue;
mii.fMask = MIIM_ID | MIIM_STRING;
mii.wID = iKL + 1;
mii.dwTypeData = szName;
hIcon = CreateTrayIcon(szKLID, szImeFile);
if (hIcon)
{ {
dwSize = sizeof(szLayoutNum); mii.hbmpItem = BitmapFromIcon(hIcon);
if (RegEnumValue(hKey, dwIndex, szLayoutNum, &dwSize, NULL, NULL, if (mii.hbmpItem)
NULL, NULL) != ERROR_SUCCESS) mii.fMask |= MIIM_BITMAP;
{
break;
}
GetLayoutID(szLayoutNum, szLCID, ARRAYSIZE(szLCID));
GetImeFile(szImeFile, ARRAYSIZE(szImeFile), szLCID);
if (!GetLayoutName(szLayoutNum, szName, ARRAYSIZE(szName)))
continue;
mii.fMask = MIIM_ID | MIIM_STRING;
mii.wID = _ttoi(szLayoutNum);
mii.dwTypeData = szName;
hIcon = CreateTrayIcon(szLCID, szImeFile);
if (hIcon)
{
mii.hbmpItem = BitmapFromIcon(hIcon);
if (mii.hbmpItem)
mii.fMask |= MIIM_BITMAP;
}
InsertMenuItem(hMenu, -1, TRUE, &mii);
DestroyIcon(hIcon);
} }
CheckMenuItem(hMenu, ulCurrentLayoutNum, MF_CHECKED); InsertMenuItem(hMenu, -1, TRUE, &mii);
DestroyIcon(hIcon);
RegCloseKey(hKey);
} }
CheckMenuItem(hMenu, g_nCurrentLayoutNum, MF_CHECKED);
return hMenu; return hMenu;
} }
static ULONG
GetMaxLayoutNum(VOID)
{
HKEY hKey;
ULONG dwIndex, dwSize, uLayoutNum, uMaxLayoutNum = 0;
TCHAR szLayoutNum[CCH_ULONG_DEC + 1], szLayoutID[CCH_LAYOUT_ID + 1];
/* Get the maximum layout number in the Preload key */
if (RegOpenKeyEx(HKEY_CURRENT_USER, _T("Keyboard Layout\\Preload"), 0,
KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS)
{
for (dwIndex = 0; ; dwIndex++)
{
dwSize = sizeof(szLayoutNum);
if (RegEnumValue(hKey, dwIndex, szLayoutNum, &dwSize, NULL, NULL,
NULL, NULL) != ERROR_SUCCESS)
{
break;
}
if (GetLayoutID(szLayoutNum, szLayoutID, ARRAYSIZE(szLayoutID)))
{
uLayoutNum = _ttoi(szLayoutNum);
if (uMaxLayoutNum < uLayoutNum)
uMaxLayoutNum = uLayoutNum;
}
}
RegCloseKey(hKey);
}
return uMaxLayoutNum;
}
BOOL BOOL
SetHooks(VOID) SetHooks(VOID)
{ {
@ -549,37 +600,36 @@ DeleteHooks(VOID)
} }
} }
static UINT GetLayoutNum(HKL hKL)
{
INT iKL;
for (iKL = 0; iKL < g_cKLs; ++iKL)
{
if (g_ahKLs[iKL] == hKL)
return iKL + 1;
}
return 0;
}
ULONG ULONG
GetNextLayout(VOID) GetNextLayout(VOID)
{ {
TCHAR szLayoutNum[3 + 1], szLayoutID[CCH_LAYOUT_ID + 1]; return (g_nCurrentLayoutNum % g_cKLs) + 1;
ULONG uLayoutNum, uMaxNum = GetMaxLayoutNum();
for (uLayoutNum = ulCurrentLayoutNum + 1; ; ++uLayoutNum)
{
if (uLayoutNum > uMaxNum)
uLayoutNum = 1;
if (uLayoutNum == ulCurrentLayoutNum)
break;
_ultot(uLayoutNum, szLayoutNum, 10);
if (GetLayoutID(szLayoutNum, szLayoutID, ARRAYSIZE(szLayoutID)))
return uLayoutNum;
}
return ulCurrentLayoutNum;
} }
UINT UINT
UpdateLanguageDisplay(HWND hwnd, HKL hKl) UpdateLanguageDisplay(HWND hwnd, HKL hKL)
{ {
TCHAR szLCID[MAX_PATH], szLangName[MAX_PATH]; TCHAR szKLID[MAX_PATH], szLangName[MAX_PATH];
LANGID LangID; LANGID LangID;
GetLayoutIDByHkl(hKl, szLCID, ARRAYSIZE(szLCID)); GetKLIDFromHKL(hKL, szKLID, ARRAYSIZE(szKLID));
LangID = (LANGID)_tcstoul(szLCID, NULL, 16); LangID = (LANGID)_tcstoul(szKLID, NULL, 16);
GetLocaleInfo(LangID, LOCALE_SLANGUAGE, szLangName, ARRAYSIZE(szLangName)); GetLocaleInfo(LangID, LOCALE_SLANGUAGE, szLangName, ARRAYSIZE(szLangName));
UpdateTrayIcon(hwnd, szLCID, szLangName); UpdateTrayIcon(hwnd, szKLID, szLangName);
g_nCurrentLayoutNum = GetLayoutNum(hKL);
return 0; return 0;
} }
@ -611,21 +661,6 @@ UpdateLanguageDisplayCurrent(HWND hwnd, HWND hwndFore)
return 0; return 0;
} }
static UINT GetCurLayoutNum(HKL hKL)
{
UINT i, nCount;
HKL ahKL[256];
nCount = GetKeyboardLayoutList(ARRAYSIZE(ahKL), ahKL);
for (i = 0; i < nCount; ++i)
{
if (ahKL[i] == hKL)
return i + 1;
}
return 0;
}
static BOOL RememberLastActive(HWND hwnd, HWND hwndFore) static BOOL RememberLastActive(HWND hwnd, HWND hwndFore)
{ {
TCHAR szClass[64]; TCHAR szClass[64];
@ -641,8 +676,7 @@ static BOOL RememberLastActive(HWND hwnd, HWND hwndFore)
return FALSE; /* Special window */ return FALSE; /* Special window */
} }
/* FIXME: CONWND is multithreaded but KLF_SETFORPROCESS and /* FIXME: CONWND needs special handling */
DefWindowProc.WM_INPUTLANGCHANGEREQUEST won't work yet */
if (_tcsicmp(szClass, TEXT("ConsoleWindowClass")) == 0) if (_tcsicmp(szClass, TEXT("ConsoleWindowClass")) == 0)
{ {
HKL hKL = GetKeyboardLayout(0); HKL hKL = GetKeyboardLayout(0);
@ -671,15 +705,19 @@ WndProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam)
return -1; return -1;
} }
LoadSpecialIds();
UpdateLayoutList(NULL);
AddTrayIcon(hwnd); AddTrayIcon(hwnd);
ActivateLayout(hwnd, ulCurrentLayoutNum, NULL, TRUE); ActivateLayout(hwnd, g_nCurrentLayoutNum, NULL, TRUE);
s_uTaskbarRestart = RegisterWindowMessage(TEXT("TaskbarCreated")); s_uTaskbarRestart = RegisterWindowMessage(TEXT("TaskbarCreated"));
break; break;
} }
case WM_LANG_CHANGED: /* Comes from kbsdll.dll and this module */ case WM_LANG_CHANGED: /* Comes from kbsdll.dll and this module */
{ {
UpdateLayoutList((HKL)lParam);
UpdateLanguageDisplay(hwnd, (HKL)lParam); UpdateLanguageDisplay(hwnd, (HKL)lParam);
break; break;
} }
@ -757,8 +795,7 @@ WndProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam)
if (hwndTarget == NULL) if (hwndTarget == NULL)
hwndTarget = g_hwndLastActive; hwndTarget = g_hwndLastActive;
/* FIXME: CONWND is multithreaded but KLF_SETFORPROCESS and /* FIXME: CONWND needs special handling */
DefWindowProc.WM_INPUTLANGCHANGEREQUEST won't work yet */
if (hwndTarget && if (hwndTarget &&
GetClassName(hwndTarget, szClass, ARRAYSIZE(szClass)) && GetClassName(hwndTarget, szClass, ARRAYSIZE(szClass)) &&
_tcsicmp(szClass, TEXT("ConsoleWindowClass")) == 0) _tcsicmp(szClass, TEXT("ConsoleWindowClass")) == 0)
@ -772,19 +809,17 @@ WndProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam)
{ {
dwThreadID = GetWindowThreadProcessId(hwndTarget, NULL); dwThreadID = GetWindowThreadProcessId(hwndTarget, NULL);
hKL = GetKeyboardLayout(dwThreadID); hKL = GetKeyboardLayout(dwThreadID);
uNum = GetCurLayoutNum(hKL); uNum = GetLayoutNum(hKL);
if (uNum != 0) if (uNum != 0)
ulCurrentLayoutNum = uNum; g_nCurrentLayoutNum = uNum;
} }
ActivateLayout(hwnd, GetNextLayout(), hwndTarget, TRUE); ActivateLayout(hwnd, GetNextLayout(), hwndTarget, TRUE);
/* FIXME: CONWND is multithreaded but KLF_SETFORPROCESS and /* FIXME: CONWND needs special handling */
DefWindowProc.WM_INPUTLANGCHANGEREQUEST won't work yet */
if (bCONWND) if (bCONWND)
{ ActivateLayout(hwnd, g_nCurrentLayoutNum, hwndTargetSave, TRUE);
ActivateLayout(hwnd, ulCurrentLayoutNum, hwndTargetSave, TRUE);
}
break; break;
} }
@ -826,6 +861,7 @@ WndProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam)
{ {
if (Message == s_uTaskbarRestart) if (Message == s_uTaskbarRestart)
{ {
UpdateLayoutList(NULL);
AddTrayIcon(hwnd); AddTrayIcon(hwnd);
break; break;
} }