2008-04-20 15:48:43 +00:00
|
|
|
/*
|
|
|
|
* PROJECT: Keyboard Layout Switcher
|
2015-09-09 13:13:35 +00:00
|
|
|
* FILE: base/applications/kbswitch/kbswitch.c
|
2008-04-20 15:48:43 +00:00
|
|
|
* PURPOSE: Switching Keyboard Layouts
|
|
|
|
* PROGRAMMERS: Dmitry Chapyshev (dmitry@reactos.org)
|
|
|
|
* Colin Finck (mail@colinfinck.de)
|
2022-08-23 22:31:46 +00:00
|
|
|
* Katayama Hirofumi MZ (katayama.hirofumi.mz@gmail.com)
|
2008-04-20 15:48:43 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include "kbswitch.h"
|
2008-04-20 10:41:34 +00:00
|
|
|
|
|
|
|
#define WM_NOTIFYICONMSG (WM_USER + 248)
|
2022-08-24 01:21:50 +00:00
|
|
|
#define CX_ICON 16
|
|
|
|
#define CY_ICON 16
|
2008-04-20 10:41:34 +00:00
|
|
|
|
2016-08-06 20:48:33 +00:00
|
|
|
PKBSWITCHSETHOOKS KbSwitchSetHooks = NULL;
|
|
|
|
PKBSWITCHDELETEHOOKS KbSwitchDeleteHooks = NULL;
|
2016-08-09 21:41:05 +00:00
|
|
|
UINT ShellHookMessage = 0;
|
2022-08-23 22:31:46 +00:00
|
|
|
DWORD dwAltShiftHotKeyId = 0, dwShiftAltHotKeyId = 0;
|
2008-04-27 17:14:58 +00:00
|
|
|
|
2008-04-27 15:40:42 +00:00
|
|
|
static BOOL
|
2016-08-06 20:48:33 +00:00
|
|
|
GetLayoutID(LPTSTR szLayoutNum, LPTSTR szLCID, SIZE_T LCIDLength);
|
2008-04-27 15:40:42 +00:00
|
|
|
|
2008-05-04 20:58:15 +00:00
|
|
|
static BOOL
|
2016-08-06 20:48:33 +00:00
|
|
|
GetLayoutName(LPTSTR szLayoutNum, LPTSTR szName, SIZE_T NameLength);
|
2008-05-04 20:58:15 +00:00
|
|
|
|
2008-04-20 10:41:34 +00:00
|
|
|
HINSTANCE hInst;
|
2008-04-24 17:57:48 +00:00
|
|
|
HANDLE hProcessHeap;
|
2008-05-20 12:53:31 +00:00
|
|
|
HMODULE hDllLib;
|
|
|
|
ULONG ulCurrentLayoutNum = 1;
|
2008-04-20 10:41:34 +00:00
|
|
|
|
2008-04-27 15:40:42 +00:00
|
|
|
static HICON
|
|
|
|
CreateTrayIcon(LPTSTR szLCID)
|
|
|
|
{
|
2022-08-24 01:21:50 +00:00
|
|
|
LANGID LangID;
|
2008-04-27 15:40:42 +00:00
|
|
|
TCHAR szBuf[3];
|
2022-08-24 01:21:50 +00:00
|
|
|
HDC hdc;
|
|
|
|
HBITMAP hbmColor, hbmMono, hBmpOld;
|
2008-04-27 15:40:42 +00:00
|
|
|
RECT rect;
|
2008-09-20 09:05:24 +00:00
|
|
|
HFONT hFontOld, hFont = NULL;
|
2008-04-27 15:40:42 +00:00
|
|
|
ICONINFO IconInfo;
|
|
|
|
HICON hIcon = NULL;
|
2022-08-24 01:21:50 +00:00
|
|
|
LOGFONT lf;
|
2008-04-27 15:40:42 +00:00
|
|
|
|
2022-08-24 01:21:50 +00:00
|
|
|
/* Getting "EN", "FR", etc. from English, French, ... */
|
|
|
|
LangID = (LANGID)_tcstoul(szLCID, NULL, 16);
|
|
|
|
if (!GetLocaleInfo(LangID, LOCALE_SISO639LANGNAME, szBuf, ARRAYSIZE(szBuf)))
|
2008-04-27 15:40:42 +00:00
|
|
|
{
|
2016-08-06 20:48:33 +00:00
|
|
|
StringCchCopy(szBuf, ARRAYSIZE(szBuf), _T("??"));
|
2008-04-27 15:40:42 +00:00
|
|
|
}
|
2022-08-24 01:21:50 +00:00
|
|
|
CharUpper(szBuf);
|
|
|
|
|
|
|
|
/* Create hdc, hbmColor and hbmMono */
|
|
|
|
hdc = CreateCompatibleDC(NULL);
|
|
|
|
hbmColor = CreateCompatibleBitmap(hdc, CX_ICON, CY_ICON);
|
|
|
|
hbmMono = CreateBitmap(CX_ICON, CY_ICON, 1, 1, NULL);
|
|
|
|
|
|
|
|
/* Create a font */
|
|
|
|
ZeroMemory(&lf, sizeof(lf));
|
|
|
|
lf.lfHeight = -11;
|
|
|
|
lf.lfCharSet = ANSI_CHARSET;
|
|
|
|
lstrcpyn(lf.lfFaceName, _T("Tahoma"), ARRAYSIZE(lf.lfFaceName));
|
|
|
|
hFont = CreateFontIndirect(&lf);
|
|
|
|
|
|
|
|
SetRect(&rect, 0, 0, CX_ICON, CY_ICON);
|
|
|
|
|
|
|
|
/* Draw hbmColor */
|
|
|
|
hBmpOld = SelectObject(hdc, hbmColor);
|
|
|
|
SetDCBrushColor(hdc, GetSysColor(COLOR_HIGHLIGHT));
|
|
|
|
FillRect(hdc, &rect, (HBRUSH)GetStockObject(DC_BRUSH));
|
|
|
|
hFontOld = SelectObject(hdc, hFont);
|
|
|
|
SetTextColor(hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));
|
|
|
|
SetBkMode(hdc, TRANSPARENT);
|
|
|
|
DrawText(hdc, szBuf, 2, &rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER);
|
|
|
|
SelectObject(hdc, hFontOld);
|
|
|
|
SelectObject(hdc, hBmpOld);
|
|
|
|
|
|
|
|
/* Fill hbmMono by black */
|
|
|
|
hBmpOld = SelectObject(hdc, hbmMono);
|
|
|
|
PatBlt(hdc, 0, 0, CX_ICON, CY_ICON, BLACKNESS);
|
|
|
|
SelectObject(hdc, hBmpOld);
|
|
|
|
|
|
|
|
/* Create an icon from hbmColor and hbmMono */
|
|
|
|
IconInfo.hbmColor = hbmColor;
|
|
|
|
IconInfo.hbmMask = hbmMono;
|
|
|
|
IconInfo.fIcon = TRUE;
|
|
|
|
hIcon = CreateIconIndirect(&IconInfo);
|
|
|
|
|
|
|
|
/* Clean up */
|
|
|
|
DeleteObject(hbmColor);
|
|
|
|
DeleteObject(hbmMono);
|
|
|
|
DeleteObject(hFont);
|
2008-12-18 12:32:46 +00:00
|
|
|
DeleteDC(hdc);
|
2008-04-27 15:40:42 +00:00
|
|
|
|
|
|
|
return hIcon;
|
|
|
|
}
|
|
|
|
|
2008-04-20 10:41:34 +00:00
|
|
|
static VOID
|
2008-04-27 15:40:42 +00:00
|
|
|
AddTrayIcon(HWND hwnd)
|
2008-04-20 10:41:34 +00:00
|
|
|
{
|
2008-04-20 15:48:43 +00:00
|
|
|
NOTIFYICONDATA tnid;
|
2008-04-27 15:40:42 +00:00
|
|
|
TCHAR szLCID[CCH_LAYOUT_ID + 1];
|
2008-05-04 20:58:15 +00:00
|
|
|
TCHAR szName[MAX_PATH];
|
2008-04-27 15:40:42 +00:00
|
|
|
|
2016-08-06 20:48:33 +00:00
|
|
|
GetLayoutID(_T("1"), szLCID, ARRAYSIZE(szLCID));
|
|
|
|
GetLayoutName(_T("1"), szName, ARRAYSIZE(szName));
|
2008-04-20 10:41:34 +00:00
|
|
|
|
2016-08-06 20:48:33 +00:00
|
|
|
memset(&tnid, 0, sizeof(tnid));
|
2008-04-20 10:41:34 +00:00
|
|
|
tnid.cbSize = sizeof(NOTIFYICONDATA);
|
|
|
|
tnid.hWnd = hwnd;
|
|
|
|
tnid.uID = 1;
|
2008-05-04 20:58:15 +00:00
|
|
|
tnid.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
|
2008-04-20 15:48:43 +00:00
|
|
|
tnid.uCallbackMessage = WM_NOTIFYICONMSG;
|
2008-04-27 15:40:42 +00:00
|
|
|
tnid.hIcon = CreateTrayIcon(szLCID);
|
2008-04-20 10:41:34 +00:00
|
|
|
|
2016-08-06 20:48:33 +00:00
|
|
|
StringCchCopy(tnid.szTip, ARRAYSIZE(tnid.szTip), szName);
|
2008-05-04 20:58:15 +00:00
|
|
|
|
2008-04-20 10:41:34 +00:00
|
|
|
Shell_NotifyIcon(NIM_ADD, &tnid);
|
|
|
|
}
|
|
|
|
|
|
|
|
static VOID
|
|
|
|
DelTrayIcon(HWND hwnd)
|
|
|
|
{
|
2008-04-20 15:48:43 +00:00
|
|
|
NOTIFYICONDATA tnid;
|
2008-04-20 10:41:34 +00:00
|
|
|
|
2016-08-06 20:48:33 +00:00
|
|
|
memset(&tnid, 0, sizeof(tnid));
|
2008-04-20 15:48:43 +00:00
|
|
|
tnid.cbSize = sizeof(NOTIFYICONDATA);
|
|
|
|
tnid.hWnd = hwnd;
|
|
|
|
tnid.uID = 1;
|
2008-04-20 10:41:34 +00:00
|
|
|
|
2008-04-20 15:48:43 +00:00
|
|
|
Shell_NotifyIcon(NIM_DELETE, &tnid);
|
2008-04-20 10:41:34 +00:00
|
|
|
}
|
|
|
|
|
2008-04-27 15:40:42 +00:00
|
|
|
static VOID
|
2008-05-04 20:58:15 +00:00
|
|
|
UpdateTrayIcon(HWND hwnd, LPTSTR szLCID, LPTSTR szName)
|
2008-04-27 15:40:42 +00:00
|
|
|
{
|
|
|
|
NOTIFYICONDATA tnid;
|
|
|
|
|
2016-08-06 20:48:33 +00:00
|
|
|
memset(&tnid, 0, sizeof(tnid));
|
2008-04-27 15:40:42 +00:00
|
|
|
tnid.cbSize = sizeof(NOTIFYICONDATA);
|
|
|
|
tnid.hWnd = hwnd;
|
|
|
|
tnid.uID = 1;
|
2008-05-20 12:53:31 +00:00
|
|
|
tnid.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
|
2008-04-27 15:40:42 +00:00
|
|
|
tnid.uCallbackMessage = WM_NOTIFYICONMSG;
|
|
|
|
tnid.hIcon = CreateTrayIcon(szLCID);
|
|
|
|
|
2016-08-06 20:48:33 +00:00
|
|
|
StringCchCopy(tnid.szTip, ARRAYSIZE(tnid.szTip), szName);
|
2008-05-04 20:58:15 +00:00
|
|
|
|
2008-04-27 15:40:42 +00:00
|
|
|
Shell_NotifyIcon(NIM_MODIFY, &tnid);
|
|
|
|
}
|
|
|
|
|
2008-04-20 10:41:34 +00:00
|
|
|
static BOOL
|
2016-08-06 20:48:33 +00:00
|
|
|
GetLayoutID(LPTSTR szLayoutNum, LPTSTR szLCID, SIZE_T LCIDLength)
|
2008-04-20 15:48:43 +00:00
|
|
|
{
|
|
|
|
DWORD dwBufLen;
|
2008-04-24 17:57:48 +00:00
|
|
|
DWORD dwRes;
|
2008-04-20 15:48:43 +00:00
|
|
|
HKEY hKey;
|
2008-04-24 17:57:48 +00:00
|
|
|
TCHAR szTempLCID[CCH_LAYOUT_ID + 1];
|
2008-04-20 15:48:43 +00:00
|
|
|
|
|
|
|
// Get the Layout ID
|
|
|
|
if (RegOpenKeyEx(HKEY_CURRENT_USER, _T("Keyboard Layout\\Preload"), 0, KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS)
|
|
|
|
{
|
2008-04-24 17:57:48 +00:00
|
|
|
dwBufLen = sizeof(szTempLCID);
|
|
|
|
dwRes = RegQueryValueEx(hKey, szLayoutNum, NULL, NULL, (LPBYTE)szTempLCID, &dwBufLen);
|
2008-04-20 15:48:43 +00:00
|
|
|
|
2008-04-24 17:57:48 +00:00
|
|
|
if (dwRes != ERROR_SUCCESS)
|
2008-04-20 15:48:43 +00:00
|
|
|
{
|
|
|
|
RegCloseKey(hKey);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
RegCloseKey(hKey);
|
|
|
|
}
|
|
|
|
|
2016-11-05 14:55:55 +00:00
|
|
|
// Look for a substitute of this layout
|
2008-04-22 19:01:56 +00:00
|
|
|
if (RegOpenKeyEx(HKEY_CURRENT_USER, _T("Keyboard Layout\\Substitutes"), 0, KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS)
|
2008-04-20 15:48:43 +00:00
|
|
|
{
|
2008-04-24 17:57:48 +00:00
|
|
|
dwBufLen = sizeof(szTempLCID);
|
2008-04-20 15:48:43 +00:00
|
|
|
|
2008-04-22 19:01:56 +00:00
|
|
|
if (RegQueryValueEx(hKey, szTempLCID, NULL, NULL, (LPBYTE)szLCID, &dwBufLen) != ERROR_SUCCESS)
|
2008-04-20 15:48:43 +00:00
|
|
|
{
|
|
|
|
// No substitute found, then use the old LCID
|
2016-08-06 20:48:33 +00:00
|
|
|
StringCchCopy(szLCID, LCIDLength, szTempLCID);
|
2008-04-20 15:48:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
RegCloseKey(hKey);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Substitutes key couldn't be opened, so use the old LCID
|
2016-08-06 20:48:33 +00:00
|
|
|
StringCchCopy(szLCID, LCIDLength, szTempLCID);
|
2008-04-20 15:48:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2008-05-20 12:53:31 +00:00
|
|
|
VOID
|
2016-08-06 20:48:33 +00:00
|
|
|
GetLayoutIDByHkl(HKL hKl, LPTSTR szLayoutID, SIZE_T LayoutIDLength)
|
2008-05-20 12:53:31 +00:00
|
|
|
{
|
|
|
|
/*
|
|
|
|
FIXME!!! This way of getting layout ID incorrect!
|
|
|
|
This will not work correctly for 0001040a, 00010410, etc
|
|
|
|
*/
|
2016-08-06 20:48:33 +00:00
|
|
|
StringCchPrintf(szLayoutID, LayoutIDLength, _T("%08x"), LOWORD(hKl));
|
2008-05-20 12:53:31 +00:00
|
|
|
}
|
|
|
|
|
2008-04-20 15:48:43 +00:00
|
|
|
static BOOL
|
2016-08-06 20:48:33 +00:00
|
|
|
GetLayoutName(LPTSTR szLayoutNum, LPTSTR szName, SIZE_T NameLength)
|
2008-04-20 10:41:34 +00:00
|
|
|
{
|
|
|
|
HKEY hKey;
|
|
|
|
DWORD dwBufLen;
|
2008-05-02 06:42:45 +00:00
|
|
|
TCHAR szBuf[MAX_PATH], szDispName[MAX_PATH], szIndex[MAX_PATH], szPath[MAX_PATH];
|
2008-04-20 15:48:43 +00:00
|
|
|
TCHAR szLCID[CCH_LAYOUT_ID + 1];
|
2008-05-02 06:42:45 +00:00
|
|
|
HANDLE hLib;
|
2008-06-22 21:59:27 +00:00
|
|
|
UINT i, j, k;
|
2008-04-20 10:41:34 +00:00
|
|
|
|
2016-08-06 20:48:33 +00:00
|
|
|
if (!GetLayoutID(szLayoutNum, szLCID, ARRAYSIZE(szLCID)))
|
2008-04-20 15:48:43 +00:00
|
|
|
return FALSE;
|
|
|
|
|
2016-08-06 20:48:33 +00:00
|
|
|
StringCchPrintf(szBuf, ARRAYSIZE(szBuf), _T("SYSTEM\\CurrentControlSet\\Control\\Keyboard Layouts\\%s"), szLCID);
|
2008-04-20 10:41:34 +00:00
|
|
|
|
|
|
|
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, (LPCTSTR)szBuf, 0, KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS)
|
|
|
|
{
|
2016-08-06 20:48:33 +00:00
|
|
|
dwBufLen = sizeof(szDispName);
|
2008-04-20 15:48:43 +00:00
|
|
|
|
2008-05-02 06:42:45 +00:00
|
|
|
if (RegQueryValueEx(hKey, _T("Layout Display Name"), NULL, NULL, (LPBYTE)szDispName, &dwBufLen) == ERROR_SUCCESS)
|
2008-04-20 10:41:34 +00:00
|
|
|
{
|
2008-05-02 06:42:45 +00:00
|
|
|
if (szDispName[0] == '@')
|
|
|
|
{
|
2016-08-06 20:48:33 +00:00
|
|
|
size_t len = _tcslen(szDispName);
|
|
|
|
|
|
|
|
for (i = 0; i < len; i++)
|
2008-05-02 06:42:45 +00:00
|
|
|
{
|
|
|
|
if ((szDispName[i] == ',') && (szDispName[i + 1] == '-'))
|
|
|
|
{
|
|
|
|
for (j = i + 2, k = 0; j < _tcslen(szDispName)+1; j++, k++)
|
|
|
|
{
|
|
|
|
szIndex[k] = szDispName[j];
|
|
|
|
}
|
|
|
|
szDispName[i - 1] = '\0';
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
else szDispName[i] = szDispName[i + 1];
|
|
|
|
}
|
|
|
|
|
2016-08-06 20:48:33 +00:00
|
|
|
if (ExpandEnvironmentStrings(szDispName, szPath, ARRAYSIZE(szPath)))
|
2008-05-02 06:42:45 +00:00
|
|
|
{
|
|
|
|
hLib = LoadLibrary(szPath);
|
|
|
|
if (hLib)
|
|
|
|
{
|
2016-08-06 20:48:33 +00:00
|
|
|
if (LoadString(hLib, _ttoi(szIndex), szPath, ARRAYSIZE(szPath)) != 0)
|
2008-05-02 06:42:45 +00:00
|
|
|
{
|
2016-08-06 20:48:33 +00:00
|
|
|
StringCchCopy(szName, NameLength, szPath);
|
2008-05-02 06:42:45 +00:00
|
|
|
RegCloseKey(hKey);
|
2008-09-20 09:05:24 +00:00
|
|
|
FreeLibrary(hLib);
|
2008-05-02 06:42:45 +00:00
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
FreeLibrary(hLib);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2008-04-20 10:41:34 +00:00
|
|
|
}
|
2008-04-20 15:48:43 +00:00
|
|
|
|
2016-08-06 20:48:33 +00:00
|
|
|
dwBufLen = NameLength * sizeof(TCHAR);
|
2008-05-02 06:42:45 +00:00
|
|
|
|
|
|
|
if (RegQueryValueEx(hKey, _T("Layout Text"), NULL, NULL, (LPBYTE)szName, &dwBufLen) == ERROR_SUCCESS)
|
|
|
|
{
|
|
|
|
RegCloseKey(hKey);
|
|
|
|
return TRUE;
|
|
|
|
}
|
2008-12-18 19:38:01 +00:00
|
|
|
|
|
|
|
RegCloseKey(hKey);
|
2008-04-20 10:41:34 +00:00
|
|
|
}
|
|
|
|
|
2008-05-02 06:42:45 +00:00
|
|
|
return FALSE;
|
2008-04-20 10:41:34 +00:00
|
|
|
}
|
|
|
|
|
2008-04-22 19:01:56 +00:00
|
|
|
BOOL CALLBACK
|
|
|
|
EnumWindowsProc(HWND hwnd, LPARAM lParam)
|
|
|
|
{
|
2008-05-20 12:53:31 +00:00
|
|
|
PostMessage(hwnd, WM_INPUTLANGCHANGEREQUEST, 0, lParam);
|
2008-04-22 20:01:08 +00:00
|
|
|
return TRUE;
|
2008-04-22 19:01:56 +00:00
|
|
|
}
|
|
|
|
|
2008-04-20 10:41:34 +00:00
|
|
|
static VOID
|
2008-04-27 15:40:42 +00:00
|
|
|
ActivateLayout(HWND hwnd, ULONG uLayoutNum)
|
2008-04-20 10:41:34 +00:00
|
|
|
{
|
2008-04-20 15:48:43 +00:00
|
|
|
HKL hKl;
|
|
|
|
TCHAR szLayoutNum[CCH_ULONG_DEC + 1];
|
|
|
|
TCHAR szLCID[CCH_LAYOUT_ID + 1];
|
2008-05-20 18:02:39 +00:00
|
|
|
TCHAR szLangName[MAX_PATH];
|
2008-04-20 15:48:43 +00:00
|
|
|
|
|
|
|
_ultot(uLayoutNum, szLayoutNum, 10);
|
2016-08-06 20:48:33 +00:00
|
|
|
GetLayoutID(szLayoutNum, szLCID, ARRAYSIZE(szLCID));
|
2008-04-20 15:48:43 +00:00
|
|
|
|
|
|
|
// Switch to the new keyboard layout
|
2016-08-06 20:48:33 +00:00
|
|
|
GetLocaleInfo((LANGID)_tcstoul(szLCID, NULL, 16), LOCALE_SLANGUAGE, (LPTSTR)szLangName, ARRAYSIZE(szLangName));
|
2008-05-20 18:02:39 +00:00
|
|
|
UpdateTrayIcon(hwnd, szLCID, szLangName);
|
2008-04-20 15:48:43 +00:00
|
|
|
hKl = LoadKeyboardLayout(szLCID, KLF_ACTIVATE);
|
2008-05-20 12:53:31 +00:00
|
|
|
|
2008-04-24 17:57:48 +00:00
|
|
|
EnumWindows(EnumWindowsProc, (LPARAM) hKl);
|
2008-05-20 12:53:31 +00:00
|
|
|
|
|
|
|
ulCurrentLayoutNum = uLayoutNum;
|
2008-04-20 10:41:34 +00:00
|
|
|
}
|
|
|
|
|
2008-04-20 15:48:43 +00:00
|
|
|
static HMENU
|
2015-09-04 00:21:03 +00:00
|
|
|
BuildLeftPopupMenu(VOID)
|
2008-04-20 10:41:34 +00:00
|
|
|
{
|
2008-04-20 15:48:43 +00:00
|
|
|
HMENU hMenu;
|
|
|
|
HKEY hKey;
|
|
|
|
DWORD dwIndex, dwSize;
|
|
|
|
TCHAR szLayoutNum[CCH_ULONG_DEC + 1];
|
|
|
|
TCHAR szName[MAX_PATH];
|
|
|
|
|
|
|
|
hMenu = CreatePopupMenu();
|
|
|
|
|
2008-04-24 17:57:48 +00:00
|
|
|
// Add the keyboard layouts to the popup menu
|
2008-04-20 15:48:43 +00:00
|
|
|
if (RegOpenKeyEx(HKEY_CURRENT_USER, _T("Keyboard Layout\\Preload"), 0, KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS)
|
|
|
|
{
|
2016-08-06 20:48:33 +00:00
|
|
|
for (dwIndex = 0; ; dwIndex++)
|
2008-04-20 15:48:43 +00:00
|
|
|
{
|
|
|
|
dwSize = sizeof(szLayoutNum);
|
2016-08-06 20:48:33 +00:00
|
|
|
if (RegEnumValue(hKey, dwIndex, szLayoutNum, &dwSize, NULL, NULL, NULL, NULL) != ERROR_SUCCESS)
|
2008-04-20 15:48:43 +00:00
|
|
|
break;
|
|
|
|
|
2016-08-06 20:48:33 +00:00
|
|
|
if (!GetLayoutName(szLayoutNum, szName, ARRAYSIZE(szName)))
|
2008-04-20 15:48:43 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
AppendMenu(hMenu, MF_STRING, _ttoi(szLayoutNum), szName);
|
|
|
|
}
|
|
|
|
|
2016-08-06 20:48:33 +00:00
|
|
|
CheckMenuItem(hMenu, ulCurrentLayoutNum, MF_CHECKED);
|
2008-07-20 19:08:35 +00:00
|
|
|
|
2008-04-20 15:48:43 +00:00
|
|
|
RegCloseKey(hKey);
|
|
|
|
}
|
|
|
|
|
2008-05-02 07:58:03 +00:00
|
|
|
return hMenu;
|
|
|
|
}
|
|
|
|
|
2008-05-20 12:53:31 +00:00
|
|
|
BOOL
|
2015-09-04 00:21:03 +00:00
|
|
|
SetHooks(VOID)
|
2008-05-20 12:53:31 +00:00
|
|
|
{
|
|
|
|
hDllLib = LoadLibrary(_T("kbsdll.dll"));
|
2016-08-06 20:48:33 +00:00
|
|
|
if (!hDllLib)
|
|
|
|
{
|
|
|
|
return FALSE;
|
|
|
|
}
|
2008-05-20 12:53:31 +00:00
|
|
|
|
2016-08-06 20:48:33 +00:00
|
|
|
KbSwitchSetHooks = (PKBSWITCHSETHOOKS) GetProcAddress(hDllLib, "KbSwitchSetHooks");
|
|
|
|
KbSwitchDeleteHooks = (PKBSWITCHDELETEHOOKS) GetProcAddress(hDllLib, "KbSwitchDeleteHooks");
|
2008-05-20 12:53:31 +00:00
|
|
|
|
2016-08-06 20:48:33 +00:00
|
|
|
if (KbSwitchSetHooks == NULL || KbSwitchDeleteHooks == NULL)
|
|
|
|
{
|
2008-05-20 12:53:31 +00:00
|
|
|
return FALSE;
|
2016-08-06 20:48:33 +00:00
|
|
|
}
|
2008-05-20 12:53:31 +00:00
|
|
|
|
|
|
|
return KbSwitchSetHooks();
|
|
|
|
}
|
|
|
|
|
|
|
|
VOID
|
2015-09-04 00:21:03 +00:00
|
|
|
DeleteHooks(VOID)
|
2008-05-20 12:53:31 +00:00
|
|
|
{
|
|
|
|
if (KbSwitchDeleteHooks) KbSwitchDeleteHooks();
|
|
|
|
if (hDllLib) FreeLibrary(hDllLib);
|
|
|
|
}
|
|
|
|
|
|
|
|
ULONG
|
2015-09-04 00:21:03 +00:00
|
|
|
GetNextLayout(VOID)
|
2008-05-20 12:53:31 +00:00
|
|
|
{
|
|
|
|
TCHAR szLayoutNum[3 + 1], szLayoutID[CCH_LAYOUT_ID + 1];
|
|
|
|
ULONG Ret = ulCurrentLayoutNum;
|
|
|
|
|
|
|
|
_ultot(ulCurrentLayoutNum, szLayoutNum, 10);
|
2016-08-06 20:48:33 +00:00
|
|
|
if (!GetLayoutID(szLayoutNum, szLayoutID, ARRAYSIZE(szLayoutID)))
|
2008-05-20 12:53:31 +00:00
|
|
|
{
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
_ultot(Ret + 1, szLayoutNum, 10);
|
|
|
|
|
2016-08-06 20:48:33 +00:00
|
|
|
if (GetLayoutID(szLayoutNum, szLayoutID, ARRAYSIZE(szLayoutID)))
|
2008-05-20 12:53:31 +00:00
|
|
|
{
|
|
|
|
return (Ret + 1);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
_ultot(Ret - 1, szLayoutNum, 10);
|
2016-08-06 20:48:33 +00:00
|
|
|
if (GetLayoutID(szLayoutNum, szLayoutID, ARRAYSIZE(szLayoutID)))
|
2008-05-20 12:53:31 +00:00
|
|
|
return (Ret - 1);
|
|
|
|
else
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2018-01-22 14:49:33 +00:00
|
|
|
LRESULT
|
|
|
|
UpdateLanguageDisplay(HWND hwnd, HKL hKl)
|
|
|
|
{
|
|
|
|
static TCHAR szLCID[MAX_PATH], szLangName[MAX_PATH];
|
|
|
|
|
|
|
|
GetLayoutIDByHkl(hKl, szLCID, ARRAYSIZE(szLCID));
|
|
|
|
GetLocaleInfo((LANGID)_tcstoul(szLCID, NULL, 16), LOCALE_SLANGUAGE, (LPTSTR)szLangName, ARRAYSIZE(szLangName));
|
|
|
|
UpdateTrayIcon(hwnd, szLCID, szLangName);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
LRESULT
|
|
|
|
UpdateLanguageDisplayCurrent(HWND hwnd, WPARAM wParam)
|
|
|
|
{
|
|
|
|
return UpdateLanguageDisplay(hwnd, GetKeyboardLayout(GetWindowThreadProcessId((HWND)wParam, 0)));
|
|
|
|
}
|
|
|
|
|
2022-08-23 22:31:46 +00:00
|
|
|
VOID DoRegisterAltShiftHotKeys(HWND hwnd)
|
|
|
|
{
|
|
|
|
dwAltShiftHotKeyId = GlobalAddAtom(TEXT("ReactOS Alt+Shift"));
|
|
|
|
dwShiftAltHotKeyId = GlobalAddAtom(TEXT("ReactOS Shift+Alt"));
|
|
|
|
|
|
|
|
RegisterHotKey(hwnd, dwAltShiftHotKeyId, MOD_ALT | MOD_SHIFT, VK_SHIFT);
|
|
|
|
RegisterHotKey(hwnd, dwShiftAltHotKeyId, MOD_ALT | MOD_SHIFT, VK_MENU);
|
|
|
|
}
|
|
|
|
|
|
|
|
VOID DoUnregisterAltShiftHotKeys(HWND hwnd)
|
|
|
|
{
|
|
|
|
UnregisterHotKey(hwnd, dwAltShiftHotKeyId);
|
|
|
|
UnregisterHotKey(hwnd, dwShiftAltHotKeyId);
|
|
|
|
|
|
|
|
GlobalDeleteAtom(dwAltShiftHotKeyId);
|
|
|
|
GlobalDeleteAtom(dwShiftAltHotKeyId);
|
|
|
|
dwAltShiftHotKeyId = dwShiftAltHotKeyId = 0;
|
|
|
|
}
|
|
|
|
|
2008-04-20 10:41:34 +00:00
|
|
|
LRESULT CALLBACK
|
|
|
|
WndProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam)
|
|
|
|
{
|
2022-08-24 00:11:36 +00:00
|
|
|
static HMENU s_hMenu;
|
|
|
|
static HMENU s_hRightPopupMenu;
|
2015-06-26 17:18:26 +00:00
|
|
|
static UINT s_uTaskbarRestart;
|
2008-04-20 15:48:43 +00:00
|
|
|
|
|
|
|
switch (Message)
|
|
|
|
{
|
|
|
|
case WM_CREATE:
|
2008-05-20 12:53:31 +00:00
|
|
|
{
|
|
|
|
SetHooks();
|
2008-04-27 15:40:42 +00:00
|
|
|
AddTrayIcon(hwnd);
|
2022-08-24 00:11:36 +00:00
|
|
|
|
|
|
|
s_hMenu = LoadMenu(hInst, MAKEINTRESOURCE(IDR_POPUP));
|
|
|
|
s_hRightPopupMenu = GetSubMenu(s_hMenu, 0);
|
2008-06-22 21:59:27 +00:00
|
|
|
|
2008-06-24 09:59:35 +00:00
|
|
|
ActivateLayout(hwnd, ulCurrentLayoutNum);
|
2015-06-26 17:18:26 +00:00
|
|
|
s_uTaskbarRestart = RegisterWindowMessage(TEXT("TaskbarCreated"));
|
2008-06-24 09:59:35 +00:00
|
|
|
|
2022-08-23 22:31:46 +00:00
|
|
|
DoRegisterAltShiftHotKeys(hwnd);
|
2008-06-22 21:59:27 +00:00
|
|
|
return 0;
|
2008-05-20 12:53:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
case WM_LANG_CHANGED:
|
|
|
|
{
|
2018-01-22 14:49:33 +00:00
|
|
|
return UpdateLanguageDisplay(hwnd, (HKL)lParam);
|
2008-05-20 12:53:31 +00:00
|
|
|
}
|
|
|
|
|
2022-08-23 22:31:46 +00:00
|
|
|
case WM_HOTKEY:
|
2008-05-20 12:53:31 +00:00
|
|
|
{
|
2022-08-23 22:31:46 +00:00
|
|
|
if (wParam != dwAltShiftHotKeyId && wParam != dwShiftAltHotKeyId)
|
|
|
|
break;
|
2008-06-22 21:59:27 +00:00
|
|
|
|
2022-08-23 22:31:46 +00:00
|
|
|
/* FALL THROUGH */
|
|
|
|
}
|
|
|
|
|
|
|
|
case WM_LOAD_LAYOUT:
|
|
|
|
{
|
|
|
|
ULONG uNextNum = GetNextLayout();
|
|
|
|
if (ulCurrentLayoutNum != uNextNum)
|
|
|
|
ActivateLayout(hwnd, uNextNum);
|
2008-06-22 21:59:27 +00:00
|
|
|
return 0;
|
2008-05-20 12:53:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
case WM_WINDOW_ACTIVATE:
|
|
|
|
{
|
2018-01-22 14:49:33 +00:00
|
|
|
return UpdateLanguageDisplayCurrent(hwnd, wParam);
|
2008-05-20 12:53:31 +00:00
|
|
|
}
|
2008-04-20 15:48:43 +00:00
|
|
|
|
|
|
|
case WM_NOTIFYICONMSG:
|
|
|
|
switch (lParam)
|
|
|
|
{
|
2015-06-27 17:15:38 +00:00
|
|
|
case WM_RBUTTONUP:
|
|
|
|
case WM_LBUTTONUP:
|
2008-04-20 15:48:43 +00:00
|
|
|
{
|
|
|
|
POINT pt;
|
|
|
|
|
|
|
|
GetCursorPos(&pt);
|
2008-04-24 17:57:48 +00:00
|
|
|
SetForegroundWindow(hwnd);
|
2008-06-22 21:59:27 +00:00
|
|
|
|
2015-06-27 17:15:38 +00:00
|
|
|
if (lParam == WM_LBUTTONUP)
|
2008-06-22 21:59:27 +00:00
|
|
|
{
|
|
|
|
HMENU hLeftPopupMenu;
|
|
|
|
/* Rebuild the left popup menu on every click to take care of keyboard layout changes */
|
|
|
|
hLeftPopupMenu = BuildLeftPopupMenu();
|
2008-05-02 07:58:03 +00:00
|
|
|
TrackPopupMenu(hLeftPopupMenu, 0, pt.x, pt.y, 0, hwnd, NULL);
|
2008-06-22 21:59:27 +00:00
|
|
|
DestroyMenu(hLeftPopupMenu);
|
|
|
|
}
|
2008-05-02 07:58:03 +00:00
|
|
|
else
|
2008-06-22 21:59:27 +00:00
|
|
|
{
|
2022-08-24 00:11:36 +00:00
|
|
|
TrackPopupMenu(s_hRightPopupMenu, 0, pt.x, pt.y, 0, hwnd, NULL);
|
2008-06-22 21:59:27 +00:00
|
|
|
}
|
|
|
|
|
2008-04-24 17:57:48 +00:00
|
|
|
PostMessage(hwnd, WM_NULL, 0, 0);
|
2008-06-22 21:59:27 +00:00
|
|
|
|
|
|
|
return 0;
|
2008-04-20 15:48:43 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case WM_COMMAND:
|
2008-04-24 17:57:48 +00:00
|
|
|
switch (LOWORD(wParam))
|
|
|
|
{
|
|
|
|
case ID_EXIT:
|
|
|
|
SendMessage(hwnd, WM_CLOSE, 0, 0);
|
2008-06-22 21:59:27 +00:00
|
|
|
return 0;
|
2008-04-22 20:01:08 +00:00
|
|
|
|
2008-04-24 17:57:48 +00:00
|
|
|
case ID_PREFERENCES:
|
|
|
|
{
|
|
|
|
SHELLEXECUTEINFO shInputDll = {0};
|
2008-04-22 20:01:08 +00:00
|
|
|
|
|
|
|
shInputDll.cbSize = sizeof(shInputDll);
|
|
|
|
shInputDll.hwnd = hwnd;
|
|
|
|
shInputDll.lpVerb = _T("open");
|
2008-05-02 06:42:45 +00:00
|
|
|
shInputDll.lpFile = _T("rundll32.exe");
|
2008-04-22 20:01:08 +00:00
|
|
|
shInputDll.lpParameters = _T("shell32.dll,Control_RunDLL input.dll");
|
2008-04-24 17:57:48 +00:00
|
|
|
|
|
|
|
if (!ShellExecuteEx(&shInputDll))
|
2008-04-22 20:01:08 +00:00
|
|
|
MessageBox(hwnd, _T("Can't start input.dll"), NULL, MB_OK | MB_ICONERROR);
|
2017-02-05 15:42:23 +00:00
|
|
|
|
|
|
|
return 0;
|
2008-04-24 17:57:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
default:
|
2008-04-27 15:40:42 +00:00
|
|
|
ActivateLayout(hwnd, LOWORD(wParam));
|
2008-06-22 21:59:27 +00:00
|
|
|
return 0;
|
2008-04-24 17:57:48 +00:00
|
|
|
}
|
2008-04-20 15:48:43 +00:00
|
|
|
break;
|
|
|
|
|
2008-05-04 20:58:15 +00:00
|
|
|
case WM_SETTINGCHANGE:
|
2008-06-22 21:59:27 +00:00
|
|
|
{
|
2008-06-24 09:59:35 +00:00
|
|
|
if (wParam == SPI_SETDEFAULTINPUTLANG)
|
|
|
|
{
|
|
|
|
//FIXME: Should detect default language changes by CPL applet or by other tools and update UI
|
|
|
|
}
|
2018-01-22 14:49:33 +00:00
|
|
|
if (wParam == SPI_SETNONCLIENTMETRICS)
|
|
|
|
{
|
|
|
|
return UpdateLanguageDisplayCurrent(hwnd, wParam);
|
|
|
|
}
|
2008-05-20 12:53:31 +00:00
|
|
|
}
|
|
|
|
break;
|
2008-05-04 20:58:15 +00:00
|
|
|
|
2008-04-20 15:48:43 +00:00
|
|
|
case WM_DESTROY:
|
2008-05-20 12:53:31 +00:00
|
|
|
{
|
2022-08-23 22:31:46 +00:00
|
|
|
DoUnregisterAltShiftHotKeys(hwnd);
|
2008-05-20 12:53:31 +00:00
|
|
|
DeleteHooks();
|
2022-08-24 00:11:36 +00:00
|
|
|
DestroyMenu(s_hMenu);
|
2008-04-20 15:48:43 +00:00
|
|
|
DelTrayIcon(hwnd);
|
|
|
|
PostQuitMessage(0);
|
2008-06-22 21:59:27 +00:00
|
|
|
|
|
|
|
return 0;
|
2008-05-20 12:53:31 +00:00
|
|
|
}
|
2015-06-26 17:18:26 +00:00
|
|
|
|
|
|
|
default:
|
|
|
|
if(Message == s_uTaskbarRestart)
|
|
|
|
AddTrayIcon(hwnd);
|
|
|
|
break;
|
2008-04-20 15:48:43 +00:00
|
|
|
}
|
|
|
|
|
2016-08-09 21:41:05 +00:00
|
|
|
if (Message == ShellHookMessage && wParam == HSHELL_LANGUAGE)
|
|
|
|
{
|
|
|
|
PostMessage(hwnd, WM_LANG_CHANGED, wParam, lParam);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-04-20 15:48:43 +00:00
|
|
|
return DefWindowProc(hwnd, Message, wParam, lParam);
|
2008-04-20 10:41:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
INT WINAPI
|
2008-04-24 17:57:48 +00:00
|
|
|
_tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInst, LPTSTR lpCmdLine, INT nCmdShow)
|
2008-04-20 10:41:34 +00:00
|
|
|
{
|
2008-04-20 15:48:43 +00:00
|
|
|
WNDCLASS WndClass = {0};
|
|
|
|
MSG msg;
|
2013-06-16 22:49:04 +00:00
|
|
|
HANDLE hMutex;
|
2016-08-09 21:41:05 +00:00
|
|
|
HWND hwnd;
|
2013-06-16 22:49:04 +00:00
|
|
|
|
2013-06-16 22:04:48 +00:00
|
|
|
switch (GetUserDefaultUILanguage())
|
|
|
|
{
|
2016-08-06 20:48:33 +00:00
|
|
|
case MAKELANGID(LANG_HEBREW, SUBLANG_DEFAULT):
|
|
|
|
SetProcessDefaultLayout(LAYOUT_RTL);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
2013-06-16 22:04:48 +00:00
|
|
|
}
|
2008-04-27 17:14:58 +00:00
|
|
|
|
|
|
|
hMutex = CreateMutex(NULL, FALSE, szKbSwitcherName);
|
2012-03-15 20:56:26 +00:00
|
|
|
if (!hMutex)
|
2008-04-27 17:14:58 +00:00
|
|
|
return 1;
|
2008-04-20 10:41:34 +00:00
|
|
|
|
2012-03-15 20:56:26 +00:00
|
|
|
if (GetLastError() == ERROR_ALREADY_EXISTS)
|
|
|
|
{
|
|
|
|
CloseHandle(hMutex);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2008-04-20 15:48:43 +00:00
|
|
|
hInst = hInstance;
|
2008-04-24 17:57:48 +00:00
|
|
|
hProcessHeap = GetProcessHeap();
|
2008-04-20 10:41:34 +00:00
|
|
|
|
2008-04-20 15:48:43 +00:00
|
|
|
WndClass.style = 0;
|
2014-10-11 12:39:50 +00:00
|
|
|
WndClass.lpfnWndProc = WndProc;
|
2008-04-20 15:48:43 +00:00
|
|
|
WndClass.cbClsExtra = 0;
|
|
|
|
WndClass.cbWndExtra = 0;
|
|
|
|
WndClass.hInstance = hInstance;
|
|
|
|
WndClass.hIcon = NULL;
|
|
|
|
WndClass.hCursor = NULL;
|
|
|
|
WndClass.hbrBackground = NULL;
|
|
|
|
WndClass.lpszMenuName = NULL;
|
2008-04-27 17:14:58 +00:00
|
|
|
WndClass.lpszClassName = szKbSwitcherName;
|
2008-04-20 10:41:34 +00:00
|
|
|
|
2008-04-24 17:57:48 +00:00
|
|
|
if (!RegisterClass(&WndClass))
|
2012-03-15 20:56:26 +00:00
|
|
|
{
|
|
|
|
CloseHandle(hMutex);
|
2008-04-24 17:57:48 +00:00
|
|
|
return 1;
|
2012-03-15 20:56:26 +00:00
|
|
|
}
|
2008-04-20 10:41:34 +00:00
|
|
|
|
2016-08-09 21:41:05 +00:00
|
|
|
hwnd = CreateWindow(szKbSwitcherName, NULL, 0, 0, 0, 1, 1, HWND_DESKTOP, NULL, hInstance, NULL);
|
|
|
|
ShellHookMessage = RegisterWindowMessage(L"SHELLHOOK");
|
|
|
|
RegisterShellHookWindow(hwnd);
|
2008-04-20 10:41:34 +00:00
|
|
|
|
|
|
|
while(GetMessage(&msg,NULL,0,0))
|
|
|
|
{
|
|
|
|
TranslateMessage(&msg);
|
|
|
|
DispatchMessage(&msg);
|
|
|
|
}
|
|
|
|
|
2012-03-15 20:56:26 +00:00
|
|
|
CloseHandle(hMutex);
|
2008-04-27 17:14:58 +00:00
|
|
|
|
2008-04-20 10:41:34 +00:00
|
|
|
return 0;
|
|
|
|
}
|