mirror of
https://github.com/reactos/reactos.git
synced 2024-12-28 18:15:11 +00:00
[KBSWITCH][CPL:INPUT][NTUSER][EXPLORER] Fix keyboard layout icon (#4815)
Fix keyboard layout icon in taskbar notification area. JIRA issue: CORE-11700, CORE-2699, CORE-18546
- Call ActivateKeyboardLayout to select the keyboard layout correctly.
- Modify WM_INPUTLANGCHANGEREQUEST parameter.
- Modify BroadcastSystemMessageW parameter.
- Revert Taskbar Notification Area MA_NOACTIVATE HACK 8344291
. This fixes Context Menu display.
- Load the "IME File" value and set the IME icon if necessary.
- Correctly implement global hooks.
This commit is contained in:
parent
a06f10d0c0
commit
36f7d1a953
8 changed files with 318 additions and 71 deletions
|
@ -2,7 +2,7 @@
|
||||||
add_rc_deps(kbswitch.rc ${CMAKE_CURRENT_SOURCE_DIR}/res/kbswitch.ico)
|
add_rc_deps(kbswitch.rc ${CMAKE_CURRENT_SOURCE_DIR}/res/kbswitch.ico)
|
||||||
add_executable(kbswitch kbswitch.c kbswitch.rc)
|
add_executable(kbswitch kbswitch.c kbswitch.rc)
|
||||||
set_module_type(kbswitch win32gui UNICODE)
|
set_module_type(kbswitch win32gui UNICODE)
|
||||||
add_importlibs(kbswitch advapi32 user32 shell32 gdi32 msvcrt kernel32)
|
add_importlibs(kbswitch advapi32 imm32 user32 shell32 gdi32 msvcrt kernel32)
|
||||||
add_cd_file(TARGET kbswitch DESTINATION reactos/system32 FOR all)
|
add_cd_file(TARGET kbswitch DESTINATION reactos/system32 FOR all)
|
||||||
|
|
||||||
add_subdirectory(kbsdll)
|
add_subdirectory(kbsdll)
|
||||||
|
|
|
@ -13,7 +13,7 @@ HINSTANCE hInstance = NULL;
|
||||||
HWND hKbSwitchWnd = NULL;
|
HWND hKbSwitchWnd = NULL;
|
||||||
|
|
||||||
static VOID
|
static VOID
|
||||||
SendMessageToMainWnd(UINT Msg, WPARAM wParam, LPARAM lParam)
|
PostMessageToMainWnd(UINT Msg, WPARAM wParam, LPARAM lParam)
|
||||||
{
|
{
|
||||||
PostMessage(hKbSwitchWnd, Msg, wParam, lParam);
|
PostMessage(hKbSwitchWnd, Msg, wParam, lParam);
|
||||||
}
|
}
|
||||||
|
@ -21,36 +21,40 @@ SendMessageToMainWnd(UINT Msg, WPARAM wParam, LPARAM lParam)
|
||||||
LRESULT CALLBACK
|
LRESULT CALLBACK
|
||||||
WinHookProc(int code, WPARAM wParam, LPARAM lParam)
|
WinHookProc(int code, WPARAM wParam, LPARAM lParam)
|
||||||
{
|
{
|
||||||
int id = GlobalAddAtom(_T("KBSWITCH"));
|
if (code < 0)
|
||||||
|
{
|
||||||
|
return CallNextHookEx(hWinHook, code, wParam, lParam);
|
||||||
|
}
|
||||||
|
|
||||||
switch (code)
|
switch (code)
|
||||||
{
|
{
|
||||||
case HCBT_SETFOCUS:
|
case HCBT_SETFOCUS:
|
||||||
{
|
{
|
||||||
if ((HWND)wParam != NULL)
|
HWND hwndFocus = (HWND)wParam;
|
||||||
|
if (hwndFocus && hwndFocus != hKbSwitchWnd)
|
||||||
{
|
{
|
||||||
if ((HWND)wParam != hKbSwitchWnd)
|
PostMessageToMainWnd(WM_WINDOW_ACTIVATE, wParam, lParam);
|
||||||
{
|
|
||||||
SendMessageToMainWnd(WM_WINDOW_ACTIVATE, wParam, lParam);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
GlobalDeleteAtom(id);
|
|
||||||
|
|
||||||
return CallNextHookEx(hWinHook, code, wParam, lParam);
|
return CallNextHookEx(hWinHook, code, wParam, lParam);
|
||||||
}
|
}
|
||||||
|
|
||||||
LRESULT CALLBACK
|
LRESULT CALLBACK
|
||||||
ShellHookProc(int code, WPARAM wParam, LPARAM lParam)
|
ShellHookProc(int code, WPARAM wParam, LPARAM lParam)
|
||||||
{
|
{
|
||||||
|
if (code < 0)
|
||||||
|
{
|
||||||
|
return CallNextHookEx(hShellHook, code, wParam, lParam);
|
||||||
|
}
|
||||||
|
|
||||||
switch (code)
|
switch (code)
|
||||||
{
|
{
|
||||||
case HSHELL_LANGUAGE:
|
case HSHELL_LANGUAGE:
|
||||||
{
|
{
|
||||||
SendMessageToMainWnd(WM_LANG_CHANGED, wParam, lParam);
|
PostMessageToMainWnd(WM_LANG_CHANGED, wParam, lParam);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -75,8 +79,16 @@ KbSwitchSetHooks(VOID)
|
||||||
VOID WINAPI
|
VOID WINAPI
|
||||||
KbSwitchDeleteHooks(VOID)
|
KbSwitchDeleteHooks(VOID)
|
||||||
{
|
{
|
||||||
if (hWinHook) UnhookWindowsHookEx(hWinHook);
|
if (hWinHook)
|
||||||
if (hShellHook) UnhookWindowsHookEx(hShellHook);
|
{
|
||||||
|
UnhookWindowsHookEx(hWinHook);
|
||||||
|
hWinHook = NULL;
|
||||||
|
}
|
||||||
|
if (hShellHook)
|
||||||
|
{
|
||||||
|
UnhookWindowsHookEx(hShellHook);
|
||||||
|
hShellHook = NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOL WINAPI
|
BOOL WINAPI
|
||||||
|
|
|
@ -8,6 +8,21 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "kbswitch.h"
|
#include "kbswitch.h"
|
||||||
|
#include <imm.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This program kbswitch is a mimic of Win2k's internat.exe.
|
||||||
|
* However, there are some differences.
|
||||||
|
*
|
||||||
|
* Comparing with WinNT4 ActivateKeyboardLayout, WinXP ActivateKeyboardLayout has
|
||||||
|
* process boundary, so we cannot activate the IME keyboard layout from the outer process.
|
||||||
|
* It needs special care.
|
||||||
|
*
|
||||||
|
* We use global hook by our kbsdll.dll, to watch the shell and the windows.
|
||||||
|
*
|
||||||
|
* It might not work correctly on Vista+ because keyboard layout change notification
|
||||||
|
* won't be generated in Vista+.
|
||||||
|
*/
|
||||||
|
|
||||||
#define WM_NOTIFYICONMSG (WM_USER + 248)
|
#define WM_NOTIFYICONMSG (WM_USER + 248)
|
||||||
|
|
||||||
|
@ -20,6 +35,7 @@ HANDLE hProcessHeap;
|
||||||
HMODULE g_hHookDLL = NULL;
|
HMODULE g_hHookDLL = NULL;
|
||||||
ULONG ulCurrentLayoutNum = 1;
|
ULONG ulCurrentLayoutNum = 1;
|
||||||
HICON g_hTrayIcon = NULL;
|
HICON g_hTrayIcon = NULL;
|
||||||
|
HWND g_hwndLastActive = NULL;
|
||||||
|
|
||||||
static BOOL
|
static BOOL
|
||||||
GetLayoutID(LPCTSTR szLayoutNum, LPTSTR szLCID, SIZE_T LCIDLength)
|
GetLayoutID(LPCTSTR szLayoutNum, LPTSTR szLCID, SIZE_T LCIDLength)
|
||||||
|
@ -65,6 +81,17 @@ GetLayoutID(LPCTSTR szLayoutNum, LPTSTR szLCID, SIZE_T LCIDLength)
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static BOOL
|
||||||
|
GetSystemLibraryPath(LPTSTR szPath, SIZE_T cchPath, LPCTSTR FileName)
|
||||||
|
{
|
||||||
|
if (!GetSystemDirectory(szPath, cchPath))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
StringCchCat(szPath, cchPath, TEXT("\\"));
|
||||||
|
StringCchCat(szPath, cchPath, FileName);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
static BOOL
|
static BOOL
|
||||||
GetLayoutName(LPCTSTR szLayoutNum, LPTSTR szName, SIZE_T NameLength)
|
GetLayoutName(LPCTSTR szLayoutNum, LPTSTR szName, SIZE_T NameLength)
|
||||||
{
|
{
|
||||||
|
@ -131,18 +158,86 @@ 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 TRUE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
RegCloseKey(hKey);
|
RegCloseKey(hKey);
|
||||||
return FALSE;
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static BOOL GetImeFile(LPTSTR szImeFile, SIZE_T cchImeFile, LPCTSTR szLCID)
|
||||||
|
{
|
||||||
|
HKEY hKey;
|
||||||
|
DWORD dwBufLen;
|
||||||
|
TCHAR szBuf[MAX_PATH];
|
||||||
|
|
||||||
|
szImeFile[0] = UNICODE_NULL;
|
||||||
|
|
||||||
|
if (_tcslen(szLCID) != CCH_LAYOUT_ID)
|
||||||
|
return FALSE; /* Invalid LCID */
|
||||||
|
|
||||||
|
if (szLCID[0] != TEXT('E') && szLCID[0] != TEXT('e'))
|
||||||
|
return FALSE; /* Not an IME HKL */
|
||||||
|
|
||||||
|
StringCchPrintf(szBuf, ARRAYSIZE(szBuf),
|
||||||
|
_T("SYSTEM\\CurrentControlSet\\Control\\Keyboard Layouts\\%s"), szLCID);
|
||||||
|
|
||||||
|
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, szBuf, 0, KEY_QUERY_VALUE, &hKey) != ERROR_SUCCESS)
|
||||||
|
{
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
dwBufLen = cchImeFile * sizeof(TCHAR);
|
||||||
|
if (RegQueryValueEx(hKey, _T("IME File"), NULL, NULL,
|
||||||
|
(LPBYTE)szImeFile, &dwBufLen) != ERROR_SUCCESS)
|
||||||
|
{
|
||||||
|
szImeFile[0] = UNICODE_NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
RegCloseKey(hKey);
|
||||||
|
|
||||||
|
return (szImeFile[0] != UNICODE_NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef struct tagLOAD_ICON
|
||||||
|
{
|
||||||
|
INT cxIcon, cyIcon;
|
||||||
|
HICON hIcon;
|
||||||
|
} LOAD_ICON, *PLOAD_ICON;
|
||||||
|
|
||||||
|
static BOOL CALLBACK
|
||||||
|
EnumResNameProc(
|
||||||
|
HMODULE hModule,
|
||||||
|
LPCTSTR lpszType,
|
||||||
|
LPTSTR lpszName,
|
||||||
|
LPARAM lParam)
|
||||||
|
{
|
||||||
|
PLOAD_ICON pLoadIcon = (PLOAD_ICON)lParam;
|
||||||
|
pLoadIcon->hIcon = (HICON)LoadImage(hModule, lpszName, IMAGE_ICON,
|
||||||
|
pLoadIcon->cxIcon, pLoadIcon->cyIcon,
|
||||||
|
LR_DEFAULTCOLOR);
|
||||||
|
if (pLoadIcon->hIcon)
|
||||||
|
return FALSE; /* Stop enumeration */
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static HICON FakeExtractIcon(LPCTSTR szIconPath, INT cxIcon, INT cyIcon)
|
||||||
|
{
|
||||||
|
LOAD_ICON LoadIcon = { cxIcon, cyIcon, NULL };
|
||||||
|
HMODULE hImeDLL = LoadLibraryEx(szIconPath, NULL, LOAD_LIBRARY_AS_DATAFILE);
|
||||||
|
if (hImeDLL)
|
||||||
|
{
|
||||||
|
EnumResourceNames(hImeDLL, RT_GROUP_ICON, EnumResNameProc, (LPARAM)&LoadIcon);
|
||||||
|
FreeLibrary(hImeDLL);
|
||||||
|
}
|
||||||
|
return LoadIcon.hIcon;
|
||||||
}
|
}
|
||||||
|
|
||||||
static HICON
|
static HICON
|
||||||
CreateTrayIcon(LPTSTR szLCID)
|
CreateTrayIcon(LPTSTR szLCID, LPCTSTR szImeFile OPTIONAL)
|
||||||
{
|
{
|
||||||
LANGID LangID;
|
LANGID LangID;
|
||||||
TCHAR szBuf[4];
|
TCHAR szBuf[4];
|
||||||
|
@ -155,6 +250,13 @@ CreateTrayIcon(LPTSTR szLCID)
|
||||||
HICON hIcon;
|
HICON hIcon;
|
||||||
INT cxIcon = GetSystemMetrics(SM_CXSMICON);
|
INT cxIcon = GetSystemMetrics(SM_CXSMICON);
|
||||||
INT cyIcon = GetSystemMetrics(SM_CYSMICON);
|
INT cyIcon = GetSystemMetrics(SM_CYSMICON);
|
||||||
|
TCHAR szPath[MAX_PATH];
|
||||||
|
|
||||||
|
if (szImeFile && szImeFile[0])
|
||||||
|
{
|
||||||
|
if (GetSystemLibraryPath(szPath, ARRAYSIZE(szPath), szImeFile))
|
||||||
|
return FakeExtractIcon(szPath, cxIcon, cyIcon);
|
||||||
|
}
|
||||||
|
|
||||||
/* Getting "EN", "FR", etc. from English, French, ... */
|
/* Getting "EN", "FR", etc. from English, French, ... */
|
||||||
LangID = LANGIDFROMLCID(_tcstoul(szLCID, NULL, 16));
|
LangID = LANGIDFROMLCID(_tcstoul(szLCID, NULL, 16));
|
||||||
|
@ -236,12 +338,14 @@ 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 szLCID[CCH_LAYOUT_ID + 1], szName[MAX_PATH];
|
||||||
|
TCHAR szImeFile[80];
|
||||||
|
|
||||||
GetLayoutID(_T("1"), szLCID, ARRAYSIZE(szLCID));
|
GetLayoutID(_T("1"), szLCID, ARRAYSIZE(szLCID));
|
||||||
GetLayoutName(_T("1"), szName, ARRAYSIZE(szName));
|
GetLayoutName(_T("1"), szName, ARRAYSIZE(szName));
|
||||||
|
GetImeFile(szImeFile, ARRAYSIZE(szImeFile), szLCID);
|
||||||
|
|
||||||
tnid.uCallbackMessage = WM_NOTIFYICONMSG;
|
tnid.uCallbackMessage = WM_NOTIFYICONMSG;
|
||||||
tnid.hIcon = CreateTrayIcon(szLCID);
|
tnid.hIcon = CreateTrayIcon(szLCID, 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);
|
||||||
|
@ -268,9 +372,12 @@ static VOID
|
||||||
UpdateTrayIcon(HWND hwnd, LPTSTR szLCID, LPTSTR szName)
|
UpdateTrayIcon(HWND hwnd, LPTSTR szLCID, 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];
|
||||||
|
|
||||||
|
GetImeFile(szImeFile, ARRAYSIZE(szImeFile), szLCID);
|
||||||
|
|
||||||
tnid.uCallbackMessage = WM_NOTIFYICONMSG;
|
tnid.uCallbackMessage = WM_NOTIFYICONMSG;
|
||||||
tnid.hIcon = CreateTrayIcon(szLCID);
|
tnid.hIcon = CreateTrayIcon(szLCID, 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);
|
||||||
|
@ -289,12 +396,12 @@ GetLayoutIDByHkl(HKL hKl, LPTSTR szLayoutID, SIZE_T LayoutIDLength)
|
||||||
static BOOL CALLBACK
|
static BOOL CALLBACK
|
||||||
EnumWindowsProc(HWND hwnd, LPARAM lParam)
|
EnumWindowsProc(HWND hwnd, LPARAM lParam)
|
||||||
{
|
{
|
||||||
PostMessage(hwnd, WM_INPUTLANGCHANGEREQUEST, 0, lParam);
|
PostMessage(hwnd, WM_INPUTLANGCHANGEREQUEST, INPUTLANGCHANGE_SYSCHARSET, lParam);
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static VOID
|
static VOID
|
||||||
ActivateLayout(HWND hwnd, ULONG uLayoutNum)
|
ActivateLayout(HWND hwnd, ULONG uLayoutNum, HWND hwndTarget OPTIONAL)
|
||||||
{
|
{
|
||||||
HKL hKl;
|
HKL hKl;
|
||||||
TCHAR szLayoutNum[CCH_ULONG_DEC + 1], szLCID[CCH_LAYOUT_ID + 1], szLangName[MAX_PATH];
|
TCHAR szLayoutNum[CCH_ULONG_DEC + 1], szLCID[CCH_LAYOUT_ID + 1], szLangName[MAX_PATH];
|
||||||
|
@ -311,10 +418,24 @@ ActivateLayout(HWND hwnd, ULONG uLayoutNum)
|
||||||
/* 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, szLCID, szLangName);
|
||||||
hKl = LoadKeyboardLayout(szLCID, KLF_ACTIVATE);
|
|
||||||
|
|
||||||
/* Post WM_INPUTLANGCHANGEREQUEST to every top-level window */
|
if (hwndTarget)
|
||||||
EnumWindows(EnumWindowsProc, (LPARAM) hKl);
|
SetForegroundWindow(hwndTarget);
|
||||||
|
|
||||||
|
hKl = LoadKeyboardLayout(szLCID, KLF_ACTIVATE);
|
||||||
|
if (hKl)
|
||||||
|
ActivateKeyboardLayout(hKl, KLF_SETFORPROCESS);
|
||||||
|
|
||||||
|
/* Post WM_INPUTLANGCHANGEREQUEST */
|
||||||
|
if (hwndTarget)
|
||||||
|
{
|
||||||
|
PostMessage(hwndTarget, WM_INPUTLANGCHANGEREQUEST,
|
||||||
|
INPUTLANGCHANGE_SYSCHARSET, (LPARAM)hKl);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
EnumWindows(EnumWindowsProc, (LPARAM) hKl);
|
||||||
|
}
|
||||||
|
|
||||||
ulCurrentLayoutNum = uLayoutNum;
|
ulCurrentLayoutNum = uLayoutNum;
|
||||||
}
|
}
|
||||||
|
@ -411,8 +532,16 @@ SetHooks(VOID)
|
||||||
VOID
|
VOID
|
||||||
DeleteHooks(VOID)
|
DeleteHooks(VOID)
|
||||||
{
|
{
|
||||||
if (KbSwitchDeleteHooks) KbSwitchDeleteHooks();
|
if (KbSwitchDeleteHooks)
|
||||||
if (g_hHookDLL) FreeLibrary(g_hHookDLL);
|
{
|
||||||
|
KbSwitchDeleteHooks();
|
||||||
|
KbSwitchDeleteHooks = NULL;
|
||||||
|
}
|
||||||
|
if (g_hHookDLL)
|
||||||
|
{
|
||||||
|
FreeLibrary(g_hHookDLL);
|
||||||
|
g_hHookDLL = NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ULONG
|
ULONG
|
||||||
|
@ -436,7 +565,7 @@ GetNextLayout(VOID)
|
||||||
return ulCurrentLayoutNum;
|
return ulCurrentLayoutNum;
|
||||||
}
|
}
|
||||||
|
|
||||||
LRESULT
|
UINT
|
||||||
UpdateLanguageDisplay(HWND hwnd, HKL hKl)
|
UpdateLanguageDisplay(HWND hwnd, HKL hKl)
|
||||||
{
|
{
|
||||||
TCHAR szLCID[MAX_PATH], szLangName[MAX_PATH];
|
TCHAR szLCID[MAX_PATH], szLangName[MAX_PATH];
|
||||||
|
@ -450,12 +579,76 @@ UpdateLanguageDisplay(HWND hwnd, HKL hKl)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
LRESULT
|
HWND
|
||||||
UpdateLanguageDisplayCurrent(HWND hwnd, WPARAM wParam)
|
GetTargetWindow(HWND hwndFore)
|
||||||
{
|
{
|
||||||
DWORD dwThreadID = GetWindowThreadProcessId((HWND)wParam, 0);
|
TCHAR szClass[64];
|
||||||
|
HWND hwndIME;
|
||||||
|
HWND hwndTarget = hwndFore;
|
||||||
|
if (hwndTarget == NULL)
|
||||||
|
hwndTarget = GetForegroundWindow();
|
||||||
|
|
||||||
|
GetClassName(hwndTarget, szClass, ARRAYSIZE(szClass));
|
||||||
|
if (_tcsicmp(szClass, szKbSwitcherName) == 0)
|
||||||
|
hwndTarget = g_hwndLastActive;
|
||||||
|
|
||||||
|
hwndIME = ImmGetDefaultIMEWnd(hwndTarget);
|
||||||
|
return (hwndIME ? hwndIME : hwndTarget);
|
||||||
|
}
|
||||||
|
|
||||||
|
UINT
|
||||||
|
UpdateLanguageDisplayCurrent(HWND hwnd, HWND hwndFore)
|
||||||
|
{
|
||||||
|
DWORD dwThreadID = GetWindowThreadProcessId(GetTargetWindow(hwndFore), NULL);
|
||||||
HKL hKL = GetKeyboardLayout(dwThreadID);
|
HKL hKL = GetKeyboardLayout(dwThreadID);
|
||||||
return UpdateLanguageDisplay(hwnd, hKL);
|
UpdateLanguageDisplay(hwnd, hKL);
|
||||||
|
|
||||||
|
if (IsWindow(g_hwndLastActive))
|
||||||
|
SetForegroundWindow(g_hwndLastActive);
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
TCHAR szClass[64];
|
||||||
|
|
||||||
|
hwndFore = GetAncestor(hwndFore, GA_ROOT);
|
||||||
|
|
||||||
|
if (!IsWindowVisible(hwndFore) || !GetClassName(hwndFore, szClass, ARRAYSIZE(szClass)))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
if (_tcsicmp(szClass, szKbSwitcherName) == 0 ||
|
||||||
|
_tcsicmp(szClass, TEXT("Shell_TrayWnd")) == 0)
|
||||||
|
{
|
||||||
|
return FALSE; /* Special window */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* FIXME: CONWND is multithreaded but KLF_SETFORPROCESS and
|
||||||
|
DefWindowProc.WM_INPUTLANGCHANGEREQUEST won't work yet */
|
||||||
|
if (_tcsicmp(szClass, TEXT("ConsoleWindowClass")) == 0)
|
||||||
|
{
|
||||||
|
HKL hKL = GetKeyboardLayout(0);
|
||||||
|
UpdateLanguageDisplay(hwnd, hKL);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_hwndLastActive = hwndFore;
|
||||||
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
LRESULT CALLBACK
|
LRESULT CALLBACK
|
||||||
|
@ -471,31 +664,30 @@ WndProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam)
|
||||||
case WM_CREATE:
|
case WM_CREATE:
|
||||||
{
|
{
|
||||||
if (!SetHooks())
|
if (!SetHooks())
|
||||||
|
{
|
||||||
|
MessageBox(NULL, TEXT("SetHooks failed."), NULL, MB_ICONERROR);
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
AddTrayIcon(hwnd);
|
AddTrayIcon(hwnd);
|
||||||
|
|
||||||
ActivateLayout(hwnd, ulCurrentLayoutNum);
|
ActivateLayout(hwnd, ulCurrentLayoutNum, NULL);
|
||||||
s_uTaskbarRestart = RegisterWindowMessage(TEXT("TaskbarCreated"));
|
s_uTaskbarRestart = RegisterWindowMessage(TEXT("TaskbarCreated"));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case WM_LANG_CHANGED:
|
case WM_LANG_CHANGED: /* Comes from kbsdll.dll and this module */
|
||||||
{
|
{
|
||||||
return UpdateLanguageDisplay(hwnd, (HKL)lParam);
|
UpdateLanguageDisplay(hwnd, (HKL)lParam);
|
||||||
}
|
|
||||||
|
|
||||||
case WM_LOAD_LAYOUT:
|
|
||||||
{
|
|
||||||
ULONG uNextNum = GetNextLayout();
|
|
||||||
if (ulCurrentLayoutNum != uNextNum)
|
|
||||||
ActivateLayout(hwnd, uNextNum);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case WM_WINDOW_ACTIVATE:
|
case WM_WINDOW_ACTIVATE: /* Comes from kbsdll.dll and this module */
|
||||||
{
|
{
|
||||||
return UpdateLanguageDisplayCurrent(hwnd, wParam);
|
HWND hwndFore = GetForegroundWindow();
|
||||||
|
if (RememberLastActive(hwnd, hwndFore))
|
||||||
|
return UpdateLanguageDisplayCurrent(hwnd, hwndFore);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case WM_NOTIFYICONMSG:
|
case WM_NOTIFYICONMSG:
|
||||||
|
@ -537,32 +729,73 @@ WndProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam)
|
||||||
{
|
{
|
||||||
case ID_EXIT:
|
case ID_EXIT:
|
||||||
{
|
{
|
||||||
SendMessage(hwnd, WM_CLOSE, 0, 0);
|
PostMessage(hwnd, WM_CLOSE, 0, 0);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case ID_PREFERENCES:
|
case ID_PREFERENCES:
|
||||||
{
|
{
|
||||||
SHELLEXECUTEINFO shInputDll = { sizeof(shInputDll) };
|
INT_PTR ret = (INT_PTR)ShellExecute(hwnd, NULL,
|
||||||
shInputDll.hwnd = hwnd;
|
TEXT("control.exe"), TEXT("input.dll"),
|
||||||
shInputDll.lpVerb = _T("open");
|
NULL, SW_SHOWNORMAL);
|
||||||
shInputDll.lpFile = _T("rundll32.exe");
|
if (ret <= 32)
|
||||||
shInputDll.lpParameters = _T("shell32.dll,Control_RunDLL input.dll");
|
MessageBox(hwnd, _T("Can't start input.dll"), NULL, MB_ICONERROR);
|
||||||
if (!ShellExecuteEx(&shInputDll))
|
|
||||||
MessageBox(hwnd, _T("Can't start input.dll"), NULL, MB_OK | MB_ICONERROR);
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case ID_NEXTLAYOUT:
|
case ID_NEXTLAYOUT:
|
||||||
{
|
{
|
||||||
ActivateLayout(hwnd, GetNextLayout());
|
HWND hwndTarget = (HWND)lParam, hwndTargetSave = NULL;
|
||||||
|
DWORD dwThreadID;
|
||||||
|
HKL hKL;
|
||||||
|
UINT uNum;
|
||||||
|
TCHAR szClass[64];
|
||||||
|
BOOL bCONWND = FALSE;
|
||||||
|
|
||||||
|
if (hwndTarget == NULL)
|
||||||
|
hwndTarget = g_hwndLastActive;
|
||||||
|
|
||||||
|
/* FIXME: CONWND is multithreaded but KLF_SETFORPROCESS and
|
||||||
|
DefWindowProc.WM_INPUTLANGCHANGEREQUEST won't work yet */
|
||||||
|
if (hwndTarget &&
|
||||||
|
GetClassName(hwndTarget, szClass, ARRAYSIZE(szClass)) &&
|
||||||
|
_tcsicmp(szClass, TEXT("ConsoleWindowClass")) == 0)
|
||||||
|
{
|
||||||
|
bCONWND = TRUE;
|
||||||
|
hwndTargetSave = hwndTarget;
|
||||||
|
hwndTarget = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hwndTarget)
|
||||||
|
{
|
||||||
|
dwThreadID = GetWindowThreadProcessId(hwndTarget, NULL);
|
||||||
|
hKL = GetKeyboardLayout(dwThreadID);
|
||||||
|
uNum = GetCurLayoutNum(hKL);
|
||||||
|
if (uNum != 0)
|
||||||
|
ulCurrentLayoutNum = uNum;
|
||||||
|
}
|
||||||
|
|
||||||
|
ActivateLayout(hwnd, GetNextLayout(), hwndTarget);
|
||||||
|
|
||||||
|
/* FIXME: CONWND is multithreaded but KLF_SETFORPROCESS and
|
||||||
|
DefWindowProc.WM_INPUTLANGCHANGEREQUEST won't work yet */
|
||||||
|
if (bCONWND)
|
||||||
|
{
|
||||||
|
ActivateLayout(hwnd, ulCurrentLayoutNum, hwndTargetSave);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
ActivateLayout(hwnd, LOWORD(wParam));
|
if (1 <= LOWORD(wParam) && LOWORD(wParam) <= 1000)
|
||||||
|
{
|
||||||
|
if (!IsWindow(g_hwndLastActive))
|
||||||
|
{
|
||||||
|
g_hwndLastActive = NULL;
|
||||||
|
}
|
||||||
|
ActivateLayout(hwnd, LOWORD(wParam), g_hwndLastActive);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -570,13 +803,10 @@ WndProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam)
|
||||||
|
|
||||||
case WM_SETTINGCHANGE:
|
case WM_SETTINGCHANGE:
|
||||||
{
|
{
|
||||||
if (wParam == SPI_SETDEFAULTINPUTLANG)
|
|
||||||
{
|
|
||||||
//FIXME: Should detect default language changes by CPL applet or by other tools and update UI
|
|
||||||
}
|
|
||||||
if (wParam == SPI_SETNONCLIENTMETRICS)
|
if (wParam == SPI_SETNONCLIENTMETRICS)
|
||||||
{
|
{
|
||||||
return UpdateLanguageDisplayCurrent(hwnd, wParam);
|
PostMessage(hwnd, WM_WINDOW_ACTIVATE, wParam, lParam);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -597,9 +827,13 @@ WndProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam)
|
||||||
AddTrayIcon(hwnd);
|
AddTrayIcon(hwnd);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
else if (Message == ShellHookMessage && wParam == HSHELL_LANGUAGE)
|
else if (Message == ShellHookMessage)
|
||||||
{
|
{
|
||||||
PostMessage(hwnd, WM_LANG_CHANGED, wParam, lParam);
|
if (wParam == HSHELL_LANGUAGE)
|
||||||
|
PostMessage(hwnd, WM_LANG_CHANGED, wParam, lParam);
|
||||||
|
else if (wParam == HSHELL_WINDOWACTIVATED)
|
||||||
|
PostMessage(hwnd, WM_WINDOW_ACTIVATE, wParam, lParam);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return DefWindowProc(hwnd, Message, wParam, lParam);
|
return DefWindowProc(hwnd, Message, wParam, lParam);
|
||||||
|
|
|
@ -22,7 +22,6 @@
|
||||||
#define WM_KEY_PRESSED (WM_USER + 10100)
|
#define WM_KEY_PRESSED (WM_USER + 10100)
|
||||||
#define WM_LANG_CHANGED (WM_USER + 10200)
|
#define WM_LANG_CHANGED (WM_USER + 10200)
|
||||||
#define WM_WINDOW_ACTIVATE (WM_USER + 10300)
|
#define WM_WINDOW_ACTIVATE (WM_USER + 10300)
|
||||||
#define WM_LOAD_LAYOUT (WM_USER + 10400)
|
|
||||||
|
|
||||||
typedef BOOL (WINAPI *PKBSWITCHSETHOOKS) (VOID);
|
typedef BOOL (WINAPI *PKBSWITCHSETHOOKS) (VOID);
|
||||||
typedef VOID (WINAPI *PKBSWITCHDELETEHOOKS) (VOID);
|
typedef VOID (WINAPI *PKBSWITCHDELETEHOOKS) (VOID);
|
||||||
|
|
|
@ -124,11 +124,6 @@ public:
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
LRESULT OnMouseActivate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
|
|
||||||
{
|
|
||||||
return MA_NOACTIVATE;
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOL GetMinimumSize(IN OUT PSIZE pSize)
|
BOOL GetMinimumSize(IN OUT PSIZE pSize)
|
||||||
{
|
{
|
||||||
SIZE szClock = { 0, 0 };
|
SIZE szClock = { 0, 0 };
|
||||||
|
@ -350,7 +345,6 @@ public:
|
||||||
|
|
||||||
BEGIN_MSG_MAP(CTrayNotifyWnd)
|
BEGIN_MSG_MAP(CTrayNotifyWnd)
|
||||||
MESSAGE_HANDLER(WM_CREATE, OnCreate)
|
MESSAGE_HANDLER(WM_CREATE, OnCreate)
|
||||||
MESSAGE_HANDLER(WM_MOUSEACTIVATE, OnMouseActivate)
|
|
||||||
MESSAGE_HANDLER(WM_THEMECHANGED, OnThemeChanged)
|
MESSAGE_HANDLER(WM_THEMECHANGED, OnThemeChanged)
|
||||||
MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground)
|
MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground)
|
||||||
MESSAGE_HANDLER(WM_SIZE, OnSize)
|
MESSAGE_HANDLER(WM_SIZE, OnSize)
|
||||||
|
|
|
@ -423,6 +423,9 @@ InputList_Process(VOID)
|
||||||
{
|
{
|
||||||
bRet = InputList_SetFontSubstitutes(pCurrent->pLocale->dwId);
|
bRet = InputList_SetFontSubstitutes(pCurrent->pLocale->dwId);
|
||||||
InputList_AddInputMethodToUserRegistry(hPreloadKey, hSubstKey, 1, pCurrent);
|
InputList_AddInputMethodToUserRegistry(hPreloadKey, hSubstKey, 1, pCurrent);
|
||||||
|
|
||||||
|
/* Activate the DEFAULT entry */
|
||||||
|
ActivateKeyboardLayout(pCurrent->hkl, KLF_RESET);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -450,12 +453,12 @@ InputList_Process(VOID)
|
||||||
/* Change the default keyboard language */
|
/* Change the default keyboard language */
|
||||||
if (SystemParametersInfoW(SPI_SETDEFAULTINPUTLANG, 0, &pCurrent->hkl, 0))
|
if (SystemParametersInfoW(SPI_SETDEFAULTINPUTLANG, 0, &pCurrent->hkl, 0))
|
||||||
{
|
{
|
||||||
DWORD dwRecipients = BSM_ALLCOMPONENTS | BSM_ALLDESKTOPS;
|
DWORD dwRecipients = BSM_ALLDESKTOPS | BSM_APPLICATIONS;
|
||||||
|
|
||||||
BroadcastSystemMessageW(BSF_POSTMESSAGE,
|
BroadcastSystemMessageW(BSF_POSTMESSAGE,
|
||||||
&dwRecipients,
|
&dwRecipients,
|
||||||
WM_INPUTLANGCHANGEREQUEST,
|
WM_INPUTLANGCHANGEREQUEST,
|
||||||
0,
|
INPUTLANGCHANGE_SYSCHARSET,
|
||||||
(LPARAM)pCurrent->hkl);
|
(LPARAM)pCurrent->hkl);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -960,7 +960,7 @@ IntDefWindowProc(
|
||||||
if (hwndSwitch)
|
if (hwndSwitch)
|
||||||
{
|
{
|
||||||
#define ID_NEXTLAYOUT 10003
|
#define ID_NEXTLAYOUT 10003
|
||||||
UserPostMessage(hwndSwitch, WM_COMMAND, ID_NEXTLAYOUT, 0);
|
UserPostMessage(hwndSwitch, WM_COMMAND, ID_NEXTLAYOUT, (LPARAM)UserHMGetHandle(Wnd));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2356,6 +2356,11 @@ ConWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
||||||
{
|
{
|
||||||
return DefWindowProcW(hWnd, msg, wParam, lParam);
|
return DefWindowProcW(hWnd, msg, wParam, lParam);
|
||||||
}
|
}
|
||||||
|
/* Detect Alt+Shift */
|
||||||
|
if (wParam == VK_SHIFT && (msg == WM_SYSKEYDOWN || msg == WM_SYSKEYUP))
|
||||||
|
{
|
||||||
|
return DefWindowProcW(hWnd, msg, wParam, lParam);
|
||||||
|
}
|
||||||
|
|
||||||
OnKey(GuiData, msg, wParam, lParam);
|
OnKey(GuiData, msg, wParam, lParam);
|
||||||
break;
|
break;
|
||||||
|
|
Loading…
Reference in a new issue