Доброе время суток! В связи с тем, что сам долго не мог решить и разобраться казалось бы в элементарной вещи, решил создать гид на тему: 'Как фильтровать сообщения окну? | Как подменить оконную процедуру?' # Вопрос: Как можно фильтровать системные сообщения, которые отправляются какому-либо окну? # Ответ: Существует несколько способов: - Это объявить глобальный хук 'WH_GETMESSAGE' и уже при помощи него фильтровать.
- Подменить 'оригинальную оконную процедуру' и уже через вашу 'оконную процедуру' принимать все сообщения, фильтровать и отправлять дальше. (Рекомендую)
# Вопрос: А как можно реализовать подмену оконной процедуры? # Ответ: Необходимо объявить глобальный хук на перехват клавиатуры и уже при каком-либо событие делать что-либо. # Вопрос: А какого типа глобальный хук необходимо объявить для перехвата клавиатуры: 'WH_KEYBOARD' или 'WH_KEYBOARD_LL' ? # Ответ: Необходимо использовать только 'WH_KEYBOARD'. - 'WH_KEYBOARD' - Обрабатывает в контексте потока того процесса, где была нажата клавиша.
- 'WH_KEYBOARD_LL' - Обрабатывает в контексте процесса установившего хук, и поэтому не подменяется 'Оконная процедура'.
# Вопрос: А можно реализовать подмену 'Оконной процедуры' в программе? # Ответ: Нет, подобные вещи можно реализовывать только с хуком, который лежит в '.dll'. Надо писать на 'native' языке: 'C++', 'Delphi' и т.д. (т.е. '.NET' тут не подойдёт.) # Первый шаг:| Код | // Создаём глобальную переменную для объявления глобального хука. HHOOK KeyboardHook; ...... ...... // Объявление глобального хука на клавиатуру. try{ KeyboardHook = SetWindowsHookEx(WH_KEYBOARD, (HOOKPROC)KeyboardProc, hInstance, 0); } catch(...) {;} ...... ...... // Удаление глобального хука. UnhookWindowsHookEx(KeyboardHook); ...... ......
|
| Цитата(SetWindowsHookEx) |
- WH_KEYBOARD - Тип хука.
- KeyboardProc - Имя процедуры, которая будет вызываться до всех процедур для обработки сообщений от клавиатуры.
- hInstance - Указатель на 'INSTANCE' приложения или '.dll', которое содержит данную процедуру, если стоит 'NULL', то процедура находится в текущем приложении и будет активно пока активно данное приложение или '.dll'.
- 0 - указывает в цепочку какого приложения следует вставлять процедуру перехвата, если стоит 'NULL' или '0', процедура перехвата будет выполняться для любого приложения запущенного в системе(Другими словами для любого активного потока).
|
# Второй шаг:| Код | // Объявляем глобальные переменные. HWND hWnd; static LRESULT OldWindowProc = NULL; static LRESULT NewWindowProc = NULL; ...... ...... // Функция обработки всех событий от клавиатуры. LRESULT CALLBACK KeyboardProc(int nCode, WPARAM wParam, LPARAM lParam) { bool bDown = lParam & (1<<30); // Если кнопка была нажата. (Другими словами событие: 'WM_KEYUP')
if((bDown) && (HC_ACTION == nCode)) { if(wParam >= 0x7A && wParam <= 0x7B) // Если нажатая кнопка содержит код в заданном интервале, то происходят следующие действия. (Код кнопок смотри ниже) { if(wParam == VK_F11) // Если была нажата кнопка 'F11'. { hWnd = FindWindow(NULL, "TEST"); // Ищем в системе окно с заголовком 'TEST', и присваеваем результат глобальной переменной. OldWindowProc = SetWindowLong(hWnd, GWL_WNDPROC, (long)WindowProc); // Задаём новый адрес 'оконной процедуры' и присваеваем старый адрес уже 'оконной процедуры' глобальной переменной. } if(wParam == VK_F12) // Если была нажата кнопка 'F12'. { SetWindowLong(hWnd, GWL_WNDPROC, (long)OldWindowProc); // Задаём нашему окну изначальный адрес 'оконной процедуры', т.е. все сообщения от системы уже будут направлятся напрямую окну, а не через нашу 'оконную процедуру'. } } } LRESULT RetVal = CallNextHookEx(KeyboardHook, nCode, wParam, lParam); // Вызываем слудующее системное сообщение из очереди для обработки. return RetVal; // Возвращаем результат. } ...... ...... // Функция обработки новой подмененной 'оконной процедуры'. LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch(uMsg) // Делаем выборку параметра 'uMsg'. { case WM_DESTROY: UnhookWindowsHookEx(KeyboardHook); break; // Если наше окно было разрушено, но удаляем глобальный хук. case WM_CLOSE: UnhookWindowsHookEx(KeyboardHook); break; // Если окно было закрыто, то удаляем глобальный хук. case WM_ACTIVATE: // Если окно было активировано... case WM_KILLFOCUS: // Если был убран фокус с окна... return DefWindowProc(hWnd, uMsg, wParam, lParam); // ..., то все остальные сообщения будет обрабатывать оконная процедура по умолчанию - defwindowproc(); break; default: break; // Если не одно из перечисленных событий не соответствует событию, которое произошло, то выходим из выборки. } return CallWindowProc((WNDPROC)NewWindowProc, hWnd, uMsg, wParam, lParam); // Вызываем слудующее системное сообщение из очереди для обработки. }
|
# Коды клавиш/кнопок:| Код | F1 - '0x70' или 'VK_F1' F2 - '0x71' или 'VK_F2' F3 - '0x72' или 'VK_F3' F4 - '0x73' или 'VK_F4' F5 - '0x74' или 'VK_F5' F6 - '0x75' или 'VK_F6' F7 - '0x76' или 'VK_F7' F8 - '0x77' или 'VK_F8' F9 - '0x78' или 'VK_F9' F10 - '0x79' или 'VK_F10' F11 - '0x7A' или 'VK_F11' F12 - '0x7B' или 'VK_F12' //-------------------------------------------------- Space(пробел) - '0x20' или 'VK_SPACE' BackSpace - '0x8' или 'VK_BACK' Tab - '0x9' или 'VK_TAB' Enter - '0x0D' или 'VK_RETURN' Shift - '0x10' или 'VK_SHIFT' Ctrl - '0x11' или 'VK_CONTROL' Alt - '0x12' или 'VK_MENU' CapsLock - '0x14' или 'VK_CAPITAL' Esc - '0x1B' или 'VK_ESCAPE' Insert - '0x2D' или 'VK_INSERT' PageUp - '0x21' или 'VK_PRIOR' PageDown - '0x22' или 'VK_NEXT' End - '0x23' или 'VK_END' Home - '0x24' или 'VK_HOME' //-------------------------------------------------- Стрелка влева - '0x25' или 'VK_LEFT' Стрелка вверх - '0x26' или 'VK_UP' Стрелка вправо - '0x27' или 'VK_RIGHT' Стрелка вниз - '0x28' или 'VK_DOWN' //-------------------------------------------------- PrintScreen - '0x2C' или 'VK_SNAPSHOT' Scrooll Lock - '0x91' или 'VK_SCROLL' Pause - '0x13' или 'VK_PAUSE' NumLock - '0x90' или 'VK_NUMLOCK' Windows(Левая) - '0x5B' или 'VK_LWIN' Windows(Правая) - '0X5C' или 'VK_RWIN' //-------------------------------------------------- 0 - '0x30' или '0' 1 - '0x31' или '1' 2 - '0x32' или '2' 3 - '0x33' или '3' 4 - '0x34' или '4' 5 - '0x35' или '5' 6 - '0x36' или '6' 7 - '0x37' или '7' 8 - '0x38' или '8' 9 - '0x39' или '9' //-------------------------------------------------- A - '0x41' или 'A' B - '0x42' или 'B' C - '0x43' или 'C' D - '0x44' или 'D' E - '0x45' или 'E' F - '0x46' или 'F' G - '0x47' или 'G' H - '0x48' или 'H' I - '0x49' или 'I' J - '0x4A' или 'J' K - '0x4B' или 'K' L - '0x4C' или 'L' M - '0x4D' или 'M' N - '0x4E' или 'N' O - '0x4F' или 'O' P - '0x50' или 'P' Q - '0x51' или 'Q' R - '0x52' или 'R' S - '0x53' или 'S' T - '0x54' или 'T' U - '0x55' или 'U' V - '0x56' или 'V' W - '0x57' или 'W' X - '0x58' или 'X' Y - '0x59' или 'Y' Z - '0x5A' или 'Z' //--------------------------------------------------
P.S. -> Если необходимо узнать коды других клавиш, то наберите в поиске вот такую фразу: 'Коды клавиш'.
|
# Названия событий:| Код | WM_DESTROY - WM_CLOSE - WM_ACTIVATE - WM_KILLFOCUS - WM_SETFOCUS - WM_ACTIVATEAPP - WM_MOUSEMOVE - WM_MOUSELEAVE - WM_SETCURSOR - WM_NCACTIVATE - WM_SIZE -
|
# Благодарность: 'stab' и '586' в помощи написания данной статьи. Это сообщение отредактировал(а) MuForum - 31.3.2008, 17:01
--------------------
"Чтобы правильно задать вопрос, нужно знать большую часть ответа!" (Р. Шекли)
|