diff --git a/reactos/base/applications/applications.rbuild b/reactos/base/applications/applications.rbuild
index 5171e945b45..d1fa08ac53c 100644
--- a/reactos/base/applications/applications.rbuild
+++ b/reactos/base/applications/applications.rbuild
@@ -25,6 +25,9 @@
+
+
+
diff --git a/reactos/base/applications/kbswitch/kbswitch.c b/reactos/base/applications/kbswitch/kbswitch.c
new file mode 100644
index 00000000000..6f7630481bc
--- /dev/null
+++ b/reactos/base/applications/kbswitch/kbswitch.c
@@ -0,0 +1,187 @@
+#include
+
+#define WM_NOTIFYICONMSG (WM_USER + 248)
+#define BUFSIZE 256
+
+HINSTANCE hInst;
+HWND hwnd;
+
+static VOID
+AddTrayIcon(HWND hwnd, HICON hIcon)
+{
+ NOTIFYICONDATA tnid;
+
+ tnid.cbSize = sizeof(NOTIFYICONDATA);
+ tnid.hWnd = hwnd;
+ tnid.uID = 1;
+ tnid.uFlags = NIF_ICON | NIF_MESSAGE;
+ tnid.uCallbackMessage = WM_NOTIFYICONMSG;
+ tnid.hIcon = hIcon;
+
+ Shell_NotifyIcon(NIM_ADD, &tnid);
+
+ if (hIcon) DestroyIcon(hIcon);
+}
+
+static VOID
+DelTrayIcon(HWND hwnd)
+{
+ NOTIFYICONDATA tnid;
+
+ tnid.cbSize = sizeof(NOTIFYICONDATA);
+ tnid.hWnd = hwnd;
+ tnid.uID = 1;
+
+ Shell_NotifyIcon(NIM_DELETE, &tnid);
+}
+
+static BOOL
+GetLayoutName(LPCTSTR lcid, LPTSTR name)
+{
+ HKEY hKey;
+ DWORD dwBufLen;
+ TCHAR szBuf[BUFSIZE];
+
+ _stprintf(szBuf, _T("SYSTEM\\CurrentControlSet\\Control\\Keyboard Layouts\\%s"),lcid);
+
+ if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, (LPCTSTR)szBuf, 0, KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS)
+ {
+ dwBufLen = BUFSIZE;
+ if (RegQueryValueEx(hKey,_T("Layout Text"),NULL,NULL,(LPBYTE)name,&dwBufLen) == ERROR_SUCCESS)
+ {
+ RegCloseKey(hKey);
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+static VOID
+ActivateLayout(INT LayoutID)
+{
+ TCHAR szLayoutID[MAX_PATH], szNewLayout[MAX_PATH];
+ HKEY hKey;
+ DWORD dwBufLen;
+
+ _stprintf(szLayoutID, _T("%d"), LayoutID);
+
+ if (RegOpenKeyEx(HKEY_CURRENT_USER, _T("Keyboard Layout\\Preload"), 0, KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS)
+ {
+ dwBufLen = MAX_PATH;
+ if (RegQueryValueEx(hKey, szLayoutID, NULL, NULL, (LPBYTE)szNewLayout, &dwBufLen) == ERROR_SUCCESS)
+ {
+ MessageBox(0, szNewLayout, _T(""), MB_OK);
+ RegCloseKey(hKey);
+ }
+ }
+}
+
+static VOID
+ShowPopupMenu(HWND hwnd, POINT pt)
+{
+ HMENU hMenu;
+ HKEY hKey;
+ DWORD dwIndex = 0, dwSize, dwType;
+ LONG Ret;
+ TCHAR szBuf[MAX_PATH], szPreload[MAX_PATH], szName[MAX_PATH];
+
+ hMenu = CreatePopupMenu();
+
+ if (RegOpenKeyEx(HKEY_CURRENT_USER, _T("Keyboard Layout\\Preload"),
+ 0, KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS)
+ {
+ dwSize = MAX_PATH;
+ Ret = RegEnumValue(hKey, dwIndex, szBuf, &dwSize, NULL, &dwType, NULL, NULL);
+ if (Ret == ERROR_SUCCESS)
+ {
+ while (Ret == ERROR_SUCCESS)
+ {
+ dwSize = MAX_PATH;
+ RegQueryValueEx(hKey, szBuf, NULL, NULL, (LPBYTE)szPreload, &dwSize);
+
+ GetLayoutName(szPreload, szName);
+ AppendMenu(hMenu, MF_STRING, _ttoi(szBuf), szName);
+
+ dwIndex++;
+
+ dwSize = MAX_PATH;
+ Ret = RegEnumValue(hKey, dwIndex, szBuf, &dwSize, NULL, &dwType, NULL, NULL);
+ }
+ }
+ }
+
+ TrackPopupMenu(hMenu, 0, pt.x, pt.y, 0, hwnd, NULL);
+ DestroyMenu(hMenu);
+ RegCloseKey(hKey);
+}
+
+LRESULT CALLBACK
+WndProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam)
+{
+ POINT pt;
+
+ switch (Message)
+ {
+ case WM_CREATE:
+ AddTrayIcon(hwnd, LoadIcon(hInst, MAKEINTRESOURCE(IDI_MAIN)));
+ break;
+
+ case WM_NOTIFYICONMSG:
+ switch (lParam)
+ {
+ case WM_LBUTTONDBLCLK:
+ case WM_LBUTTONDOWN:
+ case WM_RBUTTONDOWN:
+ {
+ GetCursorPos(&pt);
+ ShowPopupMenu(hwnd, pt);
+ }
+ break;
+ }
+ break;
+
+ case WM_COMMAND:
+ ActivateLayout(LOWORD(wParam));
+ break;
+
+ case WM_DESTROY:
+ DelTrayIcon(hwnd);
+ PostQuitMessage(0);
+ break;
+ }
+
+ return DefWindowProc(hwnd, Message, wParam, lParam);
+}
+
+INT WINAPI
+wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInst, LPTSTR lpCmdLine, INT nCmdShow)
+{
+ WNDCLASS WndClass = {0};
+ MSG msg;
+
+ hInst = hInstance;
+
+ WndClass.style = 0;
+ WndClass.lpfnWndProc = (WNDPROC)WndProc;
+ WndClass.cbClsExtra = 0;
+ WndClass.cbWndExtra = 0;
+ WndClass.hInstance = hInstance;
+ WndClass.hIcon = NULL;
+ WndClass.hCursor = NULL;
+ WndClass.hbrBackground = NULL;
+ WndClass.lpszMenuName = NULL;
+ WndClass.lpszClassName = L"kbswitch";
+
+ if (!RegisterClass(&WndClass)) return 0;
+
+ hwnd = CreateWindow(L"kbswitch", L"kbswitch", 0, 0, 0, 1, 1, HWND_DESKTOP, NULL, hInstance, NULL);
+
+ while(GetMessage(&msg,NULL,0,0))
+ {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+
+ return 0;
+}
diff --git a/reactos/base/applications/kbswitch/kbswitch.h b/reactos/base/applications/kbswitch/kbswitch.h
new file mode 100644
index 00000000000..f281629b1b8
--- /dev/null
+++ b/reactos/base/applications/kbswitch/kbswitch.h
@@ -0,0 +1,6 @@
+#include
+#include
+#include
+#include
+
+#include "resource.h"
diff --git a/reactos/base/applications/kbswitch/kbswitch.rbuild b/reactos/base/applications/kbswitch/kbswitch.rbuild
new file mode 100644
index 00000000000..7cb3ad6726c
--- /dev/null
+++ b/reactos/base/applications/kbswitch/kbswitch.rbuild
@@ -0,0 +1,20 @@
+
+
+
+ .
+ 0x600
+ 0x500
+ 0x501
+ kernel32
+ advapi32
+ ntdll
+ user32
+ gdi32
+ shell32
+ comctl32
+ msimg32
+ shlwapi
+ kbswitch.c
+ kbswitch.rc
+
+
\ No newline at end of file
diff --git a/reactos/base/applications/kbswitch/kbswitch.rc b/reactos/base/applications/kbswitch/kbswitch.rc
new file mode 100644
index 00000000000..ca5c22b6caf
--- /dev/null
+++ b/reactos/base/applications/kbswitch/kbswitch.rc
@@ -0,0 +1,6 @@
+#include "resource.h"
+#include
+
+LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
+
+IDI_MAIN ICON "res/kbswitch.ico"
diff --git a/reactos/base/applications/kbswitch/res/kbswitch.ico b/reactos/base/applications/kbswitch/res/kbswitch.ico
new file mode 100644
index 00000000000..8ec540dd2a7
Binary files /dev/null and b/reactos/base/applications/kbswitch/res/kbswitch.ico differ
diff --git a/reactos/base/applications/kbswitch/resource.h b/reactos/base/applications/kbswitch/resource.h
new file mode 100644
index 00000000000..48937260e9b
--- /dev/null
+++ b/reactos/base/applications/kbswitch/resource.h
@@ -0,0 +1,2 @@
+/* Icons */
+#define IDI_MAIN 100