From 0f37c3c8f0d859b3bc0772be4e9b50786562e292 Mon Sep 17 00:00:00 2001 From: Dmitry Chapyshev Date: Tue, 20 May 2008 12:53:31 +0000 Subject: [PATCH] - Added kbsdll to install hooks (does not work on ReactOS). To switch layouts temporarily used keys Left Alt + F10 svn path=/trunk/; revision=33607 --- .../applications/kbswitch/kbsdll/kbsdll.c | 127 ++++++++++++++++++ .../applications/kbswitch/kbsdll/kbsdll.def | 7 + .../kbswitch/kbsdll/kbsdll.rbuild | 15 +++ .../applications/kbswitch/kbsdll/kbsdll.rc | 8 ++ reactos/base/applications/kbswitch/kbswitch.c | 122 +++++++++++++++-- reactos/base/applications/kbswitch/kbswitch.h | 7 + .../applications/kbswitch/kbswitch.rbuild | 23 ++-- 7 files changed, 288 insertions(+), 21 deletions(-) create mode 100644 reactos/base/applications/kbswitch/kbsdll/kbsdll.c create mode 100644 reactos/base/applications/kbswitch/kbsdll/kbsdll.def create mode 100644 reactos/base/applications/kbswitch/kbsdll/kbsdll.rbuild create mode 100644 reactos/base/applications/kbswitch/kbsdll/kbsdll.rc diff --git a/reactos/base/applications/kbswitch/kbsdll/kbsdll.c b/reactos/base/applications/kbswitch/kbsdll/kbsdll.c new file mode 100644 index 00000000000..7933fcd0a45 --- /dev/null +++ b/reactos/base/applications/kbswitch/kbsdll/kbsdll.c @@ -0,0 +1,127 @@ +/* + * PROJECT: ReactOS Keyboard Layout Switcher + * FILE: kbswitch/kbsdll/kbsdll.c + * PROGRAMMER: Dmitry Chapyshev + * + */ + +#include "../kbswitch.h" + +HHOOK hKeyboardHook, hLangHook, hWinHook; +HINSTANCE hInstance; +HWND hKbSwitchWnd; + +static VOID +SendMessageToMainWnd(UINT Msg, WPARAM wParam, LPARAM lParam) +{ + PostMessage(hKbSwitchWnd, Msg, wParam, lParam); +} + +/* Not used yet */ +LRESULT CALLBACK +KeyboardHookProc(int code, WPARAM wParam, LPARAM lParam) +{ + return CallNextHookEx(hKeyboardHook, code, wParam, lParam); +} + +LRESULT CALLBACK +LangHookProc(int code, WPARAM wParam, LPARAM lParam) +{ + PMSG msg; + msg = (PMSG) lParam; + + switch (msg->message) + { + case WM_INPUTLANGCHANGEREQUEST: + { + SendMessageToMainWnd(WM_LANG_CHANGED, wParam, msg->lParam); + } + break; + + case WM_HOTKEY: + { + if (msg->hwnd) + { + SendMessageToMainWnd(WM_LOAD_LAYOUT, (WPARAM)msg->hwnd, msg->lParam); + } + } + break; + } + + return CallNextHookEx(hLangHook, code, wParam, lParam); +} + +LRESULT CALLBACK +WinHookProc(int code, WPARAM wParam, LPARAM lParam) +{ + int id = GlobalAddAtom(_T("KBSWITCH")); + + switch (code) + { + case HCBT_SETFOCUS: + { + if ((HWND)wParam != NULL) + { + if ((HWND)wParam != hKbSwitchWnd) + { + SendMessageToMainWnd(WM_WINDOW_ACTIVATE, wParam, lParam); + } + } + } + break; + + case HCBT_CREATEWND: + { + RegisterHotKey((HWND)wParam, id, MOD_ALT, VK_F10); + } + break; + + case HCBT_DESTROYWND: + { + UnregisterHotKey((HWND)wParam, id); + } + break; + } + + GlobalDeleteAtom(id); + + return CallNextHookEx(hWinHook, code, wParam, lParam); +} + +BOOL +KbSwitchSetHooks() +{ + hKeyboardHook = SetWindowsHookEx(WH_KEYBOARD, KeyboardHookProc, hInstance, 0); + hLangHook = SetWindowsHookEx(WH_GETMESSAGE, LangHookProc, hInstance, 0); + hWinHook = SetWindowsHookEx(WH_CBT, WinHookProc, hInstance, 0); + + if ((hKeyboardHook)&&(hLangHook)&&(hWinHook)) + return TRUE; + else + return FALSE; +} + +VOID +KbSwitchDeleteHooks() +{ + if (hKeyboardHook) UnhookWindowsHookEx(hKeyboardHook); + if (hLangHook) UnhookWindowsHookEx(hLangHook); + if (hWinHook) UnhookWindowsHookEx(hWinHook); +} + +BOOL WINAPI +DllMain(IN HINSTANCE hinstDLL, + IN DWORD dwReason, + IN LPVOID lpvReserved) +{ + switch (dwReason) + { + case DLL_PROCESS_ATTACH: + hInstance = hinstDLL; + hKbSwitchWnd = FindWindow(szKbSwitcherName, NULL); + if (!hKbSwitchWnd) return FALSE; + break; + } + + return TRUE; +} diff --git a/reactos/base/applications/kbswitch/kbsdll/kbsdll.def b/reactos/base/applications/kbswitch/kbsdll/kbsdll.def new file mode 100644 index 00000000000..99e8f342753 --- /dev/null +++ b/reactos/base/applications/kbswitch/kbsdll/kbsdll.def @@ -0,0 +1,7 @@ +LIBRARY kbsdll.dll + +EXPORTS +KbSwitchSetHooks +KbSwitchDeleteHooks + +; EOF diff --git a/reactos/base/applications/kbswitch/kbsdll/kbsdll.rbuild b/reactos/base/applications/kbswitch/kbsdll/kbsdll.rbuild new file mode 100644 index 00000000000..4e0bd705ae8 --- /dev/null +++ b/reactos/base/applications/kbswitch/kbsdll/kbsdll.rbuild @@ -0,0 +1,15 @@ + + + + + . + 0x0500 + 0x0600 + 0x0600 + ntdll + kernel32 + user32 + comctl32 + kbsdll.c + kbsdll.rc + diff --git a/reactos/base/applications/kbswitch/kbsdll/kbsdll.rc b/reactos/base/applications/kbswitch/kbsdll/kbsdll.rc new file mode 100644 index 00000000000..44b13686f03 --- /dev/null +++ b/reactos/base/applications/kbswitch/kbsdll/kbsdll.rc @@ -0,0 +1,8 @@ +#include + +#define REACTOS_VERSION_DLL +#define REACTOS_STR_FILE_DESCRIPTION "ReactOS Keyboard Layout Switcher\0" +#define REACTOS_STR_INTERNAL_NAME "kbsdll\0" +#define REACTOS_STR_ORIGINAL_FILENAME "kbsdll.dll\0" +#include + diff --git a/reactos/base/applications/kbswitch/kbswitch.c b/reactos/base/applications/kbswitch/kbswitch.c index 86801f63893..3a13c9f3a3b 100644 --- a/reactos/base/applications/kbswitch/kbswitch.c +++ b/reactos/base/applications/kbswitch/kbswitch.c @@ -10,7 +10,8 @@ #define WM_NOTIFYICONMSG (WM_USER + 248) -TCHAR szKbSwitcherName[] = _T("kbswitcher"); +PROC KbSwitchSetHooks = NULL; +PROC KbSwitchDeleteHooks = NULL; static BOOL @@ -21,6 +22,8 @@ GetLayoutName(LPTSTR szLayoutNum, LPTSTR szName); HINSTANCE hInst; HANDLE hProcessHeap; +HMODULE hDllLib; +ULONG ulCurrentLayoutNum = 1; static HICON CreateTrayIcon(LPTSTR szLCID) @@ -135,7 +138,7 @@ UpdateTrayIcon(HWND hwnd, LPTSTR szLCID, LPTSTR szName) tnid.cbSize = sizeof(NOTIFYICONDATA); tnid.hWnd = hwnd; tnid.uID = 1; - tnid.uFlags = NIF_ICON | NIF_MESSAGE |NIF_TIP; + tnid.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP; tnid.uCallbackMessage = WM_NOTIFYICONMSG; tnid.hIcon = CreateTrayIcon(szLCID); @@ -189,6 +192,16 @@ GetLayoutID(LPTSTR szLayoutNum, LPTSTR szLCID) return TRUE; } +VOID +GetLayoutIDByHkl(HKL hKl, LPTSTR szLayoutID) +{ + /* + FIXME!!! This way of getting layout ID incorrect! + This will not work correctly for 0001040a, 00010410, etc + */ + wsprintf(szLayoutID, _T("00000%x"), LOWORD(hKl)); +} + static BOOL GetLayoutName(LPTSTR szLayoutNum, LPTSTR szName) { @@ -258,7 +271,7 @@ GetLayoutName(LPTSTR szLayoutNum, LPTSTR szName) BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam) { - SendMessage(hwnd, WM_INPUTLANGCHANGEREQUEST, 0, lParam); + PostMessage(hwnd, WM_INPUTLANGCHANGEREQUEST, 0, lParam); return TRUE; } @@ -278,8 +291,10 @@ ActivateLayout(HWND hwnd, ULONG uLayoutNum) // Switch to the new keyboard layout UpdateTrayIcon(hwnd, szLCID, szName); hKl = LoadKeyboardLayout(szLCID, KLF_ACTIVATE); - SystemParametersInfo(SPI_SETDEFAULTINPUTLANG, 0, &hKl, SPIF_SENDWININICHANGE); + EnumWindows(EnumWindowsProc, (LPARAM) hKl); + + ulCurrentLayoutNum = uLayoutNum; } static HMENU @@ -360,18 +375,101 @@ BuildRightPopupMenu() return hMenu; } +BOOL +SetHooks() +{ + hDllLib = LoadLibrary(_T("kbsdll.dll")); + if (!hDllLib) return FALSE; + + KbSwitchSetHooks = (PROC) GetProcAddress(hDllLib, MAKEINTRESOURCEA(1)); + KbSwitchDeleteHooks = (PROC) GetProcAddress(hDllLib, MAKEINTRESOURCEA(2)); + + if ((KbSwitchSetHooks == NULL)||(KbSwitchDeleteHooks == NULL)) + return FALSE; + + return KbSwitchSetHooks(); +} + +VOID +DeleteHooks() +{ + if (KbSwitchDeleteHooks) KbSwitchDeleteHooks(); + if (hDllLib) FreeLibrary(hDllLib); +} + +BOOL CALLBACK +EnumChildProc(HWND hwnd, LPARAM lParam) +{ + SendMessage(hwnd, WM_INPUTLANGCHANGEREQUEST, 0, lParam); + return TRUE; +} + +ULONG +GetNextLayout() +{ + TCHAR szLayoutNum[3 + 1], szLayoutID[CCH_LAYOUT_ID + 1]; + ULONG Ret = ulCurrentLayoutNum; + + _ultot(ulCurrentLayoutNum, szLayoutNum, 10); + if (!GetLayoutID(szLayoutNum, szLayoutID)) + { + return -1; + } + + _ultot(Ret + 1, szLayoutNum, 10); + + if (GetLayoutID(szLayoutNum, szLayoutID)) + { + return (Ret + 1); + } + else + { + _ultot(Ret - 1, szLayoutNum, 10); + if (GetLayoutID(szLayoutNum, szLayoutID)) + return (Ret - 1); + else + return -1; + } + + return -1; +} + LRESULT CALLBACK WndProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam) { static HMENU hLeftPopupMenu, hRightPopupMenu; + static TCHAR szLCID[MAX_PATH]; switch (Message) { case WM_CREATE: + { + SetHooks(); AddTrayIcon(hwnd); hLeftPopupMenu = BuildLeftPopupMenu(hwnd); hRightPopupMenu = BuildRightPopupMenu(hwnd); - break; + } + break; + + case WM_LANG_CHANGED: + { + GetLayoutIDByHkl((HKL)lParam, szLCID); + UpdateTrayIcon(hwnd, szLCID, _T("")); + } + break; + + case WM_LOAD_LAYOUT: + { + ActivateLayout(hwnd, GetNextLayout()); + } + break; + + case WM_WINDOW_ACTIVATE: + { + GetLayoutIDByHkl(GetKeyboardLayout(GetWindowThreadProcessId((HWND)wParam, 0)), szLCID); + UpdateTrayIcon(hwnd, szLCID, _T("")); + } + break; case WM_NOTIFYICONMSG: switch (lParam) @@ -388,8 +486,8 @@ WndProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam) else TrackPopupMenu(hRightPopupMenu, 0, pt.x, pt.y, 0, hwnd, NULL); PostMessage(hwnd, WM_NULL, 0, 0); - break; } + break; } break; @@ -412,9 +510,8 @@ WndProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam) if (!ShellExecuteEx(&shInputDll)) MessageBox(hwnd, _T("Can't start input.dll"), NULL, MB_OK | MB_ICONERROR); - - break; } + break; default: ActivateLayout(hwnd, LOWORD(wParam)); @@ -428,15 +525,18 @@ WndProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam) { //FIXME: Should detect default language changes by CPL applet or by other tools and update UI } - } - break; + } + break; case WM_DESTROY: + { + DeleteHooks(); DestroyMenu(hLeftPopupMenu); DestroyMenu(hRightPopupMenu); DelTrayIcon(hwnd); PostQuitMessage(0); - break; + } + break; } return DefWindowProc(hwnd, Message, wParam, lParam); diff --git a/reactos/base/applications/kbswitch/kbswitch.h b/reactos/base/applications/kbswitch/kbswitch.h index d360bea3329..53db33733e1 100644 --- a/reactos/base/applications/kbswitch/kbswitch.h +++ b/reactos/base/applications/kbswitch/kbswitch.h @@ -11,3 +11,10 @@ // Maximum Character Count of a ULONG in decimal #define CCH_ULONG_DEC 10 + +#define WM_KEY_PRESSED (WM_USER + 10100) +#define WM_LANG_CHANGED (WM_USER + 10200) +#define WM_WINDOW_ACTIVATE (WM_USER + 10300) +#define WM_LOAD_LAYOUT (WM_USER + 10400) + +TCHAR szKbSwitcherName[] = _T("kbswitcher"); diff --git a/reactos/base/applications/kbswitch/kbswitch.rbuild b/reactos/base/applications/kbswitch/kbswitch.rbuild index c05484e2fe5..c107f0a6d4d 100644 --- a/reactos/base/applications/kbswitch/kbswitch.rbuild +++ b/reactos/base/applications/kbswitch/kbswitch.rbuild @@ -1,13 +1,16 @@ - - . - kernel32 - advapi32 - user32 - shell32 - gdi32 - kbswitch.c - kbswitch.rc - + + . + kernel32 + advapi32 + user32 + shell32 + gdi32 + kbswitch.c + kbswitch.rc + + + +