ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

kbswitch.c
Go to the documentation of this file.
00001 /*
00002  * PROJECT:         Keyboard Layout Switcher
00003  * FILE:            base\applications\kbswitch\kbswitch.c
00004  * PURPOSE:         Switching Keyboard Layouts
00005  * PROGRAMMERS:     Dmitry Chapyshev (dmitry@reactos.org)
00006  *                  Colin Finck (mail@colinfinck.de)
00007  */
00008 
00009 #include "kbswitch.h"
00010 
00011 #define WM_NOTIFYICONMSG (WM_USER + 248)
00012 
00013 PROC KbSwitchSetHooks    = NULL;
00014 PROC KbSwitchDeleteHooks = NULL;
00015 
00016 
00017 static BOOL
00018 GetLayoutID(LPTSTR szLayoutNum, LPTSTR szLCID);
00019 
00020 static BOOL
00021 GetLayoutName(LPTSTR szLayoutNum, LPTSTR szName);
00022 
00023 HINSTANCE hInst;
00024 HANDLE    hProcessHeap;
00025 HMODULE   hDllLib;
00026 ULONG     ulCurrentLayoutNum = 1;
00027 
00028 static HICON
00029 CreateTrayIcon(LPTSTR szLCID)
00030 {
00031     LANGID lId;
00032     TCHAR szBuf[3];
00033     HDC hdc, hdcsrc;
00034     HBITMAP hBitmap, hBmpNew, hBmpOld;
00035     RECT rect;
00036     HFONT hFontOld, hFont = NULL;
00037     ICONINFO IconInfo;
00038     HICON hIcon = NULL;
00039 
00040     lId = (LANGID)_tcstoul(szLCID, NULL, 16);
00041     if (GetLocaleInfo(lId,
00042                       LOCALE_SISO639LANGNAME,
00043                       szBuf,
00044                       sizeof(szBuf) / sizeof(TCHAR)) == 0)
00045     {
00046         lstrcpy(szBuf, _T("??\0"));
00047     }
00048 
00049     hdcsrc = GetDC(NULL);
00050     hdc = CreateCompatibleDC(hdcsrc);
00051     hBitmap = CreateCompatibleBitmap(hdcsrc, 16, 16);
00052     ReleaseDC(NULL, hdcsrc);
00053 
00054     if (hdc && hBitmap)
00055     {
00056         hBmpNew = CreateBitmap(16, 16, 1, 1, NULL);
00057         if (hBmpNew)
00058         {
00059             hBmpOld = SelectObject(hdc, hBitmap);
00060             rect.right = 16;
00061             rect.left = 0;
00062             rect.bottom = 16;
00063             rect.top = 0;
00064 
00065             SetBkColor(hdc, GetSysColor(COLOR_HIGHLIGHT));
00066             SetTextColor(hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));
00067 
00068             ExtTextOut(hdc, rect.left, rect.top, ETO_OPAQUE, &rect, _T(""), 0, NULL);
00069 
00070             hFont = CreateFont(-11, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, ANSI_CHARSET,
00071                                OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
00072                                DEFAULT_QUALITY, FF_DONTCARE, _T("Tahoma"));
00073 
00074             hFontOld = SelectObject(hdc, hFont);
00075             DrawText(hdc, _tcsupr(szBuf), 2, &rect, DT_SINGLELINE|DT_CENTER|DT_VCENTER);
00076             SelectObject(hdc, hBmpNew);
00077             PatBlt(hdc, 0, 0, 16, 16, BLACKNESS);
00078             SelectObject(hdc, hBmpOld);
00079             SelectObject(hdc, hFontOld);
00080 
00081             IconInfo.hbmColor = hBitmap;
00082             IconInfo.hbmMask = hBmpNew;
00083             IconInfo.fIcon = TRUE;
00084 
00085             hIcon = CreateIconIndirect(&IconInfo);
00086 
00087             DeleteObject(hBmpNew);
00088             DeleteObject(hBmpOld);
00089             DeleteObject(hFont);
00090         }
00091     }
00092 
00093     DeleteDC(hdc);
00094     DeleteObject(hBitmap);
00095 
00096     return hIcon;
00097 }
00098 
00099 static VOID
00100 AddTrayIcon(HWND hwnd)
00101 {
00102     NOTIFYICONDATA tnid;
00103     TCHAR szLCID[CCH_LAYOUT_ID + 1];
00104     TCHAR szName[MAX_PATH];
00105 
00106     GetLayoutID(_T("1"), szLCID);
00107     GetLayoutName(_T("1"), szName);
00108 
00109     tnid.cbSize = sizeof(NOTIFYICONDATA);
00110     tnid.hWnd = hwnd;
00111     tnid.uID = 1;
00112     tnid.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
00113     tnid.uCallbackMessage = WM_NOTIFYICONMSG;
00114     tnid.hIcon = CreateTrayIcon(szLCID);
00115 
00116     lstrcpyn(tnid.szTip, szName, sizeof(tnid.szTip));
00117 
00118     Shell_NotifyIcon(NIM_ADD, &tnid);
00119 }
00120 
00121 static VOID
00122 DelTrayIcon(HWND hwnd)
00123 {
00124     NOTIFYICONDATA tnid;
00125 
00126     tnid.cbSize = sizeof(NOTIFYICONDATA);
00127     tnid.hWnd = hwnd;
00128     tnid.uID = 1;
00129 
00130     Shell_NotifyIcon(NIM_DELETE, &tnid);
00131 }
00132 
00133 static VOID
00134 UpdateTrayIcon(HWND hwnd, LPTSTR szLCID, LPTSTR szName)
00135 {
00136     NOTIFYICONDATA tnid;
00137 
00138     tnid.cbSize = sizeof(NOTIFYICONDATA);
00139     tnid.hWnd = hwnd;
00140     tnid.uID = 1;
00141     tnid.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
00142     tnid.uCallbackMessage = WM_NOTIFYICONMSG;
00143     tnid.hIcon = CreateTrayIcon(szLCID);
00144 
00145     lstrcpyn(tnid.szTip, szName, sizeof(tnid.szTip));
00146 
00147     Shell_NotifyIcon(NIM_MODIFY, &tnid);
00148 }
00149 
00150 static BOOL
00151 GetLayoutID(LPTSTR szLayoutNum, LPTSTR szLCID)
00152 {
00153     DWORD dwBufLen;
00154     DWORD dwRes;
00155     HKEY hKey;
00156     TCHAR szTempLCID[CCH_LAYOUT_ID + 1];
00157 
00158     // Get the Layout ID
00159     if (RegOpenKeyEx(HKEY_CURRENT_USER, _T("Keyboard Layout\\Preload"), 0, KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS)
00160     {
00161         dwBufLen = sizeof(szTempLCID);
00162         dwRes = RegQueryValueEx(hKey, szLayoutNum, NULL, NULL, (LPBYTE)szTempLCID, &dwBufLen);
00163 
00164         if (dwRes != ERROR_SUCCESS)
00165         {
00166             RegCloseKey(hKey);
00167             return FALSE;
00168         }
00169 
00170         RegCloseKey(hKey);
00171     }
00172 
00173     // Look for a substitude of this layout
00174     if (RegOpenKeyEx(HKEY_CURRENT_USER, _T("Keyboard Layout\\Substitutes"), 0, KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS)
00175     {
00176         dwBufLen = sizeof(szTempLCID);
00177 
00178         if (RegQueryValueEx(hKey, szTempLCID, NULL, NULL, (LPBYTE)szLCID, &dwBufLen) != ERROR_SUCCESS)
00179         {
00180             // No substitute found, then use the old LCID
00181             lstrcpy(szLCID, szTempLCID);
00182         }
00183 
00184         RegCloseKey(hKey);
00185     }
00186     else
00187     {
00188         // Substitutes key couldn't be opened, so use the old LCID
00189         lstrcpy(szLCID, szTempLCID);
00190     }
00191 
00192     return TRUE;
00193 }
00194 
00195 VOID
00196 GetLayoutIDByHkl(HKL hKl, LPTSTR szLayoutID)
00197 {
00198     /*
00199         FIXME!!! This way of getting layout ID incorrect!
00200                  This will not work correctly for 0001040a, 00010410, etc
00201     */
00202     wsprintf(szLayoutID, _T("%08x"), LOWORD(hKl));
00203 }
00204 
00205 static BOOL
00206 GetLayoutName(LPTSTR szLayoutNum, LPTSTR szName)
00207 {
00208     HKEY hKey;
00209     DWORD dwBufLen;
00210     TCHAR szBuf[MAX_PATH], szDispName[MAX_PATH], szIndex[MAX_PATH], szPath[MAX_PATH];
00211     TCHAR szLCID[CCH_LAYOUT_ID + 1];
00212     HANDLE hLib;
00213     UINT i, j, k;
00214 
00215     if(!GetLayoutID(szLayoutNum, szLCID))
00216         return FALSE;
00217 
00218     wsprintf(szBuf, _T("SYSTEM\\CurrentControlSet\\Control\\Keyboard Layouts\\%s"), szLCID);
00219 
00220     if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, (LPCTSTR)szBuf, 0, KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS)
00221     {
00222         dwBufLen = sizeof(szBuf);
00223 
00224         if (RegQueryValueEx(hKey, _T("Layout Display Name"), NULL, NULL, (LPBYTE)szDispName, &dwBufLen) == ERROR_SUCCESS)
00225         {
00226             if (szDispName[0] == '@')
00227             {
00228                 for (i = 0; i < _tcslen(szDispName); i++)
00229                 {
00230                     if ((szDispName[i] == ',') && (szDispName[i + 1] == '-'))
00231                     {
00232                         for (j = i + 2, k = 0; j < _tcslen(szDispName)+1; j++, k++)
00233                         {
00234                             szIndex[k] = szDispName[j];
00235                         }
00236                         szDispName[i - 1] = '\0';
00237                         break;
00238                     }
00239                     else szDispName[i] = szDispName[i + 1];
00240                 }
00241 
00242                 if (ExpandEnvironmentStrings(szDispName, szPath, MAX_PATH))
00243                 {
00244                     hLib = LoadLibrary(szPath);
00245                     if (hLib)
00246                     {
00247                         if (LoadString(hLib, _ttoi(szIndex), szPath, sizeof(szPath) / sizeof(TCHAR)) != 0)
00248                         {
00249                             _tcscpy(szName, szPath);
00250                             RegCloseKey(hKey);
00251                             FreeLibrary(hLib);
00252                             return TRUE;
00253                         }
00254                         FreeLibrary(hLib);
00255                     }
00256                 }
00257             }
00258         }
00259 
00260         dwBufLen = sizeof(szBuf);
00261 
00262         if (RegQueryValueEx(hKey, _T("Layout Text"), NULL, NULL, (LPBYTE)szName, &dwBufLen) == ERROR_SUCCESS)
00263         {
00264             RegCloseKey(hKey);
00265             return TRUE;
00266         }
00267 
00268         RegCloseKey(hKey);
00269     }
00270 
00271     return FALSE;
00272 }
00273 
00274 BOOL CALLBACK
00275 EnumWindowsProc(HWND hwnd, LPARAM lParam)
00276 {
00277     PostMessage(hwnd, WM_INPUTLANGCHANGEREQUEST, 0, lParam);
00278     return TRUE;
00279 }
00280 
00281 static VOID
00282 ActivateLayout(HWND hwnd, ULONG uLayoutNum)
00283 {
00284     HKL hKl;
00285     TCHAR szLayoutNum[CCH_ULONG_DEC + 1];
00286     TCHAR szLCID[CCH_LAYOUT_ID + 1];
00287     TCHAR szLangName[MAX_PATH];
00288 
00289     _ultot(uLayoutNum, szLayoutNum, 10);
00290     GetLayoutID(szLayoutNum, szLCID);
00291 
00292     // Switch to the new keyboard layout
00293     GetLocaleInfo((LANGID)_tcstoul(szLCID, NULL, 16), LOCALE_SLANGUAGE, (LPTSTR)szLangName, sizeof(szLangName) / sizeof(TCHAR));
00294     UpdateTrayIcon(hwnd, szLCID, szLangName);
00295     hKl = LoadKeyboardLayout(szLCID, KLF_ACTIVATE);
00296 
00297     EnumWindows(EnumWindowsProc, (LPARAM) hKl);
00298 
00299     ulCurrentLayoutNum = uLayoutNum;
00300 }
00301 
00302 static HMENU
00303 BuildLeftPopupMenu()
00304 {
00305     HMENU hMenu;
00306     HKEY hKey;
00307     DWORD dwIndex, dwSize;
00308     TCHAR szLayoutNum[CCH_ULONG_DEC + 1];
00309     TCHAR szName[MAX_PATH];
00310 
00311     hMenu = CreatePopupMenu();
00312 
00313     // Add the keyboard layouts to the popup menu
00314     if (RegOpenKeyEx(HKEY_CURRENT_USER, _T("Keyboard Layout\\Preload"), 0, KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS)
00315     {
00316         for(dwIndex = 0; ; dwIndex++)
00317         {
00318             dwSize = sizeof(szLayoutNum);
00319             if(RegEnumValue(hKey, dwIndex, szLayoutNum, &dwSize, NULL, NULL, NULL, NULL) != ERROR_SUCCESS)
00320                 break;
00321 
00322             if(!GetLayoutName(szLayoutNum, szName))
00323                 break;
00324 
00325             AppendMenu(hMenu, MF_STRING, _ttoi(szLayoutNum), szName);
00326         }
00327 
00328         (void)CheckMenuItem(hMenu, ulCurrentLayoutNum, MF_CHECKED);
00329 
00330         RegCloseKey(hKey);
00331     }
00332 
00333     return hMenu;
00334 }
00335 
00336 BOOL
00337 SetHooks()
00338 {
00339     hDllLib = LoadLibrary(_T("kbsdll.dll"));
00340     if (!hDllLib) return FALSE;
00341 
00342     KbSwitchSetHooks    = (PROC) GetProcAddress(hDllLib, MAKEINTRESOURCEA(1));
00343     KbSwitchDeleteHooks = (PROC) GetProcAddress(hDllLib, MAKEINTRESOURCEA(2));
00344 
00345     if ((KbSwitchSetHooks == NULL)||(KbSwitchDeleteHooks == NULL))
00346         return FALSE;
00347 
00348     return KbSwitchSetHooks();
00349 }
00350 
00351 VOID
00352 DeleteHooks()
00353 {
00354     if (KbSwitchDeleteHooks) KbSwitchDeleteHooks();
00355     if (hDllLib) FreeLibrary(hDllLib);
00356 }
00357 
00358 ULONG
00359 GetNextLayout()
00360 {
00361     TCHAR szLayoutNum[3 + 1], szLayoutID[CCH_LAYOUT_ID + 1];
00362     ULONG Ret = ulCurrentLayoutNum;
00363 
00364     _ultot(ulCurrentLayoutNum, szLayoutNum, 10);
00365     if (!GetLayoutID(szLayoutNum, szLayoutID))
00366     {
00367         return -1;
00368     }
00369 
00370     _ultot(Ret + 1, szLayoutNum, 10);
00371 
00372     if (GetLayoutID(szLayoutNum, szLayoutID))
00373     {
00374         return (Ret + 1);
00375     }
00376     else
00377     {
00378         _ultot(Ret - 1, szLayoutNum, 10);
00379         if (GetLayoutID(szLayoutNum, szLayoutID))
00380             return (Ret - 1);
00381         else
00382             return -1;
00383     }
00384 
00385     return -1;
00386 }
00387 
00388 LRESULT CALLBACK
00389 WndProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam)
00390 {
00391     static HMENU hRightPopupMenu;
00392     static TCHAR szLCID[MAX_PATH], szLangName[MAX_PATH];
00393 
00394     switch (Message)
00395     {
00396         case WM_CREATE:
00397         {
00398             SetHooks();
00399             AddTrayIcon(hwnd);
00400             hRightPopupMenu = GetSubMenu(LoadMenu(hInst, MAKEINTRESOURCE(IDR_POPUP)), 0);
00401 
00402             ActivateLayout(hwnd, ulCurrentLayoutNum);
00403 
00404             return 0;
00405         }
00406 
00407         case WM_LANG_CHANGED:
00408         {
00409             GetLayoutIDByHkl((HKL)lParam, szLCID);
00410             GetLocaleInfo((LANGID)_tcstoul(szLCID, NULL, 16), LOCALE_SLANGUAGE, (LPTSTR)szLangName, sizeof(szLangName) / sizeof(TCHAR));
00411             UpdateTrayIcon(hwnd, szLCID, szLangName);
00412 
00413             return 0;
00414         }
00415 
00416         case WM_LOAD_LAYOUT:
00417         {
00418             ActivateLayout(hwnd, GetNextLayout());
00419 
00420             return 0;
00421         }
00422 
00423         case WM_WINDOW_ACTIVATE:
00424         {
00425             GetLayoutIDByHkl(GetKeyboardLayout(GetWindowThreadProcessId((HWND)wParam, 0)), szLCID);
00426             GetLocaleInfo((LANGID)_tcstoul(szLCID, NULL, 16), LOCALE_SLANGUAGE, (LPTSTR)szLangName, sizeof(szLangName) / sizeof(TCHAR));
00427             UpdateTrayIcon(hwnd, szLCID, szLangName);
00428 
00429             return 0;
00430         }
00431 
00432         case WM_NOTIFYICONMSG:
00433             switch (lParam)
00434             {
00435                 case WM_RBUTTONDOWN:
00436                 case WM_LBUTTONDOWN:
00437                 {
00438                     POINT pt;
00439 
00440                     GetCursorPos(&pt);
00441                     SetForegroundWindow(hwnd);
00442 
00443                     if (lParam == WM_LBUTTONDOWN)
00444                     {
00445                         HMENU hLeftPopupMenu;
00446 
00447                         /* Rebuild the left popup menu on every click to take care of keyboard layout changes */
00448                         hLeftPopupMenu = BuildLeftPopupMenu();
00449                         TrackPopupMenu(hLeftPopupMenu, 0, pt.x, pt.y, 0, hwnd, NULL);
00450                         DestroyMenu(hLeftPopupMenu);
00451                     }
00452                     else
00453                     {
00454                         TrackPopupMenu(hRightPopupMenu, 0, pt.x, pt.y, 0, hwnd, NULL);
00455                     }
00456 
00457                     PostMessage(hwnd, WM_NULL, 0, 0);
00458 
00459                     return 0;
00460                 }
00461             }
00462             break;
00463 
00464         case WM_COMMAND:
00465             switch (LOWORD(wParam))
00466             {
00467                 case ID_EXIT:
00468                     SendMessage(hwnd, WM_CLOSE, 0, 0);
00469                     return 0;
00470 
00471                 case ID_PREFERENCES:
00472                 {
00473                     SHELLEXECUTEINFO shInputDll = {0};
00474 
00475                     shInputDll.cbSize = sizeof(shInputDll);
00476                     shInputDll.hwnd = hwnd;
00477                     shInputDll.lpVerb = _T("open");
00478                     shInputDll.lpFile = _T("rundll32.exe");
00479                     shInputDll.lpParameters = _T("shell32.dll,Control_RunDLL input.dll");
00480 
00481                     if (!ShellExecuteEx(&shInputDll))
00482                         MessageBox(hwnd, _T("Can't start input.dll"), NULL, MB_OK | MB_ICONERROR);
00483                 }
00484 
00485                 default:
00486                     ActivateLayout(hwnd, LOWORD(wParam));
00487                     return 0;
00488             }
00489             break;
00490 
00491         case WM_SETTINGCHANGE:
00492         {
00493             if (wParam == SPI_SETDEFAULTINPUTLANG)
00494             {
00495                 //FIXME: Should detect default language changes by CPL applet or by other tools and update UI
00496             }
00497         }
00498         break;
00499 
00500         case WM_DESTROY:
00501         {
00502             DeleteHooks();
00503             DestroyMenu(hRightPopupMenu);
00504             DelTrayIcon(hwnd);
00505             PostQuitMessage(0);
00506 
00507             return 0;
00508         }
00509     }
00510 
00511     return DefWindowProc(hwnd, Message, wParam, lParam);
00512 }
00513 
00514 INT WINAPI
00515 _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInst, LPTSTR lpCmdLine, INT nCmdShow)
00516 {
00517     WNDCLASS WndClass = {0};
00518     MSG msg;
00519     HANDLE hMutex;
00520 
00521     hMutex = CreateMutex(NULL, FALSE, szKbSwitcherName);
00522     if (!hMutex)
00523         return 1;
00524 
00525     if (GetLastError() == ERROR_ALREADY_EXISTS)
00526     {
00527         CloseHandle(hMutex);
00528         return 1;
00529     }
00530 
00531     hInst = hInstance;
00532     hProcessHeap = GetProcessHeap();
00533 
00534     WndClass.style = 0;
00535     WndClass.lpfnWndProc   = (WNDPROC)WndProc;
00536     WndClass.cbClsExtra    = 0;
00537     WndClass.cbWndExtra    = 0;
00538     WndClass.hInstance     = hInstance;
00539     WndClass.hIcon         = NULL;
00540     WndClass.hCursor       = NULL;
00541     WndClass.hbrBackground = NULL;
00542     WndClass.lpszMenuName  = NULL;
00543     WndClass.lpszClassName = szKbSwitcherName;
00544 
00545     if (!RegisterClass(&WndClass))
00546     {
00547         CloseHandle(hMutex);
00548         return 1;
00549     }
00550 
00551     CreateWindow(szKbSwitcherName, NULL, 0, 0, 0, 1, 1, HWND_DESKTOP, NULL, hInstance, NULL);
00552 
00553     while(GetMessage(&msg,NULL,0,0))
00554     {
00555         TranslateMessage(&msg);
00556         DispatchMessage(&msg);
00557     }
00558 
00559     CloseHandle(hMutex);
00560 
00561     return 0;
00562 }

Generated on Sun May 27 2012 04:16:45 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.