- Add the actual function for switching the keyboard layout

- Handle keyboard layout substitutes (like the "German (IBM)" layout)
- Refactor many parts of the code:
   * Always close hKey handles after they were successfully opened
   * Build the keyboard layout menu one time and not everytime, when it's opened
   * Use smaller sizes for some string variables, defined with CCH_LAYOUT_ID and CCH_ULONG_DEC.
     This also ensures that we don't retrieve bigger values, which would be invalid.
- Use a consistent indentation

svn path=/trunk/; revision=33062
This commit is contained in:
Colin Finck 2008-04-20 15:48:43 +00:00
parent 760ed27010
commit 6e8acacf27
2 changed files with 160 additions and 104 deletions

View file

@ -1,4 +1,12 @@
#include <kbswitch.h> /*
* PROJECT: Keyboard Layout Switcher
* FILE: base\applications\kbswitch\kbswitch.c
* PURPOSE: Switching Keyboard Layouts
* PROGRAMMERS: Dmitry Chapyshev (dmitry@reactos.org)
* Colin Finck (mail@colinfinck.de)
*/
#include "kbswitch.h"
#define WM_NOTIFYICONMSG (WM_USER + 248) #define WM_NOTIFYICONMSG (WM_USER + 248)
#define BUFSIZE 256 #define BUFSIZE 256
@ -9,13 +17,13 @@ HWND hwnd;
static VOID static VOID
AddTrayIcon(HWND hwnd, HICON hIcon) AddTrayIcon(HWND hwnd, HICON hIcon)
{ {
NOTIFYICONDATA tnid; NOTIFYICONDATA tnid;
tnid.cbSize = sizeof(NOTIFYICONDATA); tnid.cbSize = sizeof(NOTIFYICONDATA);
tnid.hWnd = hwnd; tnid.hWnd = hwnd;
tnid.uID = 1; tnid.uID = 1;
tnid.uFlags = NIF_ICON | NIF_MESSAGE; tnid.uFlags = NIF_ICON | NIF_MESSAGE;
tnid.uCallbackMessage = WM_NOTIFYICONMSG; tnid.uCallbackMessage = WM_NOTIFYICONMSG;
tnid.hIcon = hIcon; tnid.hIcon = hIcon;
Shell_NotifyIcon(NIM_ADD, &tnid); Shell_NotifyIcon(NIM_ADD, &tnid);
@ -26,156 +34,199 @@ AddTrayIcon(HWND hwnd, HICON hIcon)
static VOID static VOID
DelTrayIcon(HWND hwnd) DelTrayIcon(HWND hwnd)
{ {
NOTIFYICONDATA tnid; NOTIFYICONDATA tnid;
tnid.cbSize = sizeof(NOTIFYICONDATA); tnid.cbSize = sizeof(NOTIFYICONDATA);
tnid.hWnd = hwnd; tnid.hWnd = hwnd;
tnid.uID = 1; tnid.uID = 1;
Shell_NotifyIcon(NIM_DELETE, &tnid); Shell_NotifyIcon(NIM_DELETE, &tnid);
} }
static BOOL static BOOL
GetLayoutName(LPCTSTR lcid, LPTSTR name) GetLayoutID(LPTSTR szLayoutNum, LPTSTR szLCID)
{
DWORD dwBufLen;
DWORD dwTest;
HKEY hKey;
TCHAR szTempLCID[CCH_LAYOUT_ID + 1];
// Get the Layout ID
if (RegOpenKeyEx(HKEY_CURRENT_USER, _T("Keyboard Layout\\Preload"), 0, KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS)
{
dwBufLen = sizeof(szTempLCID);
if(RegQueryValueEx(hKey, szLayoutNum, NULL, NULL, (LPBYTE)szTempLCID, &dwBufLen) != ERROR_SUCCESS)
{
RegCloseKey(hKey);
return FALSE;
}
RegCloseKey(hKey);
}
// Look for a substitude of this layout
if(RegOpenKeyEx(HKEY_CURRENT_USER, _T("Keyboard Layout\\Substitutes"), 0, KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS)
{
dwBufLen = sizeof(szTempLCID);
if(RegQueryValueEx(hKey, szTempLCID, NULL, NULL, (LPBYTE)szLCID, &dwBufLen) != ERROR_SUCCESS)
{
// No substitute found, then use the old LCID
lstrcpy(szLCID, szTempLCID);
}
RegCloseKey(hKey);
}
else
{
// Substitutes key couldn't be opened, so use the old LCID
lstrcpy(szLCID, szTempLCID);
}
return TRUE;
}
static BOOL
GetLayoutName(LPTSTR szLayoutNum, LPTSTR szName)
{ {
HKEY hKey; HKEY hKey;
DWORD dwBufLen; DWORD dwBufLen;
TCHAR szBuf[BUFSIZE]; TCHAR szBuf[MAX_PATH];
TCHAR szLCID[CCH_LAYOUT_ID + 1];
_stprintf(szBuf, _T("SYSTEM\\CurrentControlSet\\Control\\Keyboard Layouts\\%s"),lcid); if(!GetLayoutID(szLayoutNum, szLCID))
return FALSE;
wsprintf(szBuf, _T("SYSTEM\\CurrentControlSet\\Control\\Keyboard Layouts\\%s"), szLCID);
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, (LPCTSTR)szBuf, 0, KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS) if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, (LPCTSTR)szBuf, 0, KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS)
{ {
dwBufLen = BUFSIZE; dwBufLen = MAX_PATH * sizeof(TCHAR);
if (RegQueryValueEx(hKey,_T("Layout Text"),NULL,NULL,(LPBYTE)name,&dwBufLen) == ERROR_SUCCESS)
if(RegQueryValueEx(hKey, _T("Layout Text"), NULL, NULL, (LPBYTE)szName, &dwBufLen) != ERROR_SUCCESS)
{ {
RegCloseKey(hKey); RegCloseKey(hKey);
return TRUE; return FALSE;
} }
RegCloseKey(hKey);
} }
return FALSE; return TRUE;
} }
static VOID static VOID
ActivateLayout(INT LayoutID) ActivateLayout(ULONG uLayoutNum)
{ {
TCHAR szLayoutID[MAX_PATH], szNewLayout[MAX_PATH]; HKL hKl;
HKEY hKey; TCHAR szLayoutNum[CCH_ULONG_DEC + 1];
DWORD dwBufLen; TCHAR szLCID[CCH_LAYOUT_ID + 1];
DWORD Ret;
_stprintf(szLayoutID, _T("%d"), LayoutID); _ultot(uLayoutNum, szLayoutNum, 10);
GetLayoutID(szLayoutNum, szLCID);
if (RegOpenKeyEx(HKEY_CURRENT_USER, _T("Keyboard Layout\\Preload"), 0, KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS) // Switch to the new keyboard layout
{ hKl = LoadKeyboardLayout(szLCID, KLF_ACTIVATE);
dwBufLen = MAX_PATH; Ret = SystemParametersInfo(SPI_SETDEFAULTINPUTLANG, 0, &hKl, SPIF_SENDWININICHANGE);
if (RegQueryValueEx(hKey, szLayoutID, NULL, NULL, (LPBYTE)szNewLayout, &dwBufLen) == ERROR_SUCCESS)
{
MessageBox(0, szNewLayout, _T(""), MB_OK);
RegCloseKey(hKey);
}
}
} }
static VOID static HMENU
ShowPopupMenu(HWND hwnd, POINT pt) BuildPopupMenu()
{ {
HMENU hMenu; HMENU hMenu;
HKEY hKey; HKEY hKey;
DWORD dwIndex = 0, dwSize, dwType; DWORD dwIndex, dwSize;
LONG Ret; TCHAR szLayoutNum[CCH_ULONG_DEC + 1];
TCHAR szBuf[MAX_PATH], szPreload[MAX_PATH], szName[MAX_PATH]; TCHAR szName[MAX_PATH];
hMenu = CreatePopupMenu(); hMenu = CreatePopupMenu();
if (RegOpenKeyEx(HKEY_CURRENT_USER, _T("Keyboard Layout\\Preload"), if (RegOpenKeyEx(HKEY_CURRENT_USER, _T("Keyboard Layout\\Preload"), 0, KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS)
0, KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS) {
{ for(dwIndex = 0; ; dwIndex++)
dwSize = MAX_PATH; {
Ret = RegEnumValue(hKey, dwIndex, szBuf, &dwSize, NULL, &dwType, NULL, NULL); dwSize = sizeof(szLayoutNum);
if (Ret == ERROR_SUCCESS) if(RegEnumValue(hKey, dwIndex, szLayoutNum, &dwSize, NULL, NULL, NULL, NULL) != ERROR_SUCCESS)
{ break;
while (Ret == ERROR_SUCCESS)
{
dwSize = MAX_PATH;
RegQueryValueEx(hKey, szBuf, NULL, NULL, (LPBYTE)szPreload, &dwSize);
GetLayoutName(szPreload, szName); if(!GetLayoutName(szLayoutNum, szName))
AppendMenu(hMenu, MF_STRING, _ttoi(szBuf), szName); break;
dwIndex++; AppendMenu(hMenu, MF_STRING, _ttoi(szLayoutNum), szName);
}
dwSize = MAX_PATH; RegCloseKey(hKey);
Ret = RegEnumValue(hKey, dwIndex, szBuf, &dwSize, NULL, &dwType, NULL, NULL); }
}
}
}
TrackPopupMenu(hMenu, 0, pt.x, pt.y, 0, hwnd, NULL); return hMenu;
DestroyMenu(hMenu);
RegCloseKey(hKey);
} }
LRESULT CALLBACK LRESULT CALLBACK
WndProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam) WndProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam)
{ {
POINT pt; static HMENU hPopupMenu;
switch (Message) switch (Message)
{ {
case WM_CREATE: case WM_CREATE:
AddTrayIcon(hwnd, LoadIcon(hInst, MAKEINTRESOURCE(IDI_MAIN))); AddTrayIcon(hwnd, LoadIcon(hInst, MAKEINTRESOURCE(IDI_MAIN)));
break; hPopupMenu = BuildPopupMenu(hwnd);
break;
case WM_NOTIFYICONMSG: case WM_NOTIFYICONMSG:
switch (lParam) switch (lParam)
{ {
case WM_LBUTTONDBLCLK: case WM_LBUTTONDBLCLK:
case WM_LBUTTONDOWN: case WM_LBUTTONDOWN:
case WM_RBUTTONDOWN: case WM_RBUTTONDOWN:
{ {
GetCursorPos(&pt); POINT pt;
ShowPopupMenu(hwnd, pt);
}
break;
}
break;
case WM_COMMAND: GetCursorPos(&pt);
ActivateLayout(LOWORD(wParam)); TrackPopupMenu(hPopupMenu, 0, pt.x, pt.y, 0, hwnd, NULL);
break; }
break;
}
break;
case WM_DESTROY: case WM_COMMAND:
DelTrayIcon(hwnd); ActivateLayout(LOWORD(wParam));
PostQuitMessage(0); break;
break;
}
return DefWindowProc(hwnd, Message, wParam, lParam); case WM_DESTROY:
DestroyMenu(hPopupMenu);
DelTrayIcon(hwnd);
PostQuitMessage(0);
break;
}
return DefWindowProc(hwnd, Message, wParam, lParam);
} }
INT WINAPI INT WINAPI
wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInst, LPTSTR lpCmdLine, INT nCmdShow) wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInst, LPTSTR lpCmdLine, INT nCmdShow)
{ {
WNDCLASS WndClass = {0}; WNDCLASS WndClass = {0};
MSG msg; MSG msg;
hInst = hInstance; hInst = hInstance;
WndClass.style = 0; WndClass.style = 0;
WndClass.lpfnWndProc = (WNDPROC)WndProc; WndClass.lpfnWndProc = (WNDPROC)WndProc;
WndClass.cbClsExtra = 0; WndClass.cbClsExtra = 0;
WndClass.cbWndExtra = 0; WndClass.cbWndExtra = 0;
WndClass.hInstance = hInstance; WndClass.hInstance = hInstance;
WndClass.hIcon = NULL; WndClass.hIcon = NULL;
WndClass.hCursor = NULL; WndClass.hCursor = NULL;
WndClass.hbrBackground = NULL; WndClass.hbrBackground = NULL;
WndClass.lpszMenuName = NULL; WndClass.lpszMenuName = NULL;
WndClass.lpszClassName = L"kbswitch"; WndClass.lpszClassName = L"kbswitch";
if (!RegisterClass(&WndClass)) return 0; if (!RegisterClass(&WndClass)) return 0;
hwnd = CreateWindow(L"kbswitch", L"kbswitch", 0, 0, 0, 1, 1, HWND_DESKTOP, NULL, hInstance, NULL); hwnd = CreateWindow(L"kbswitch", L"kbswitch", 0, 0, 0, 1, 1, HWND_DESKTOP, NULL, hInstance, NULL);
while(GetMessage(&msg,NULL,0,0)) while(GetMessage(&msg,NULL,0,0))
{ {

View file

@ -1,6 +1,11 @@
#include <stdlib.h>
#include <windows.h> #include <windows.h>
#include <tchar.h> #include <tchar.h>
#include <stdio.h>
#include <stdlib.h>
#include "resource.h" #include "resource.h"
// Character Count of a layout ID like "00000409"
#define CCH_LAYOUT_ID 8
// Maximum Character Count of a ULONG in decimal
#define CCH_ULONG_DEC 10