Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > Низкоуровневое программирование > Win Api
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 13.10.2017, 11:47   #1
mxustin
Пользователь
 
Аватар для mxustin
 
Регистрация: 02.10.2015
Сообщений: 20
Вопрос Нестабильная работа клавиатурного хука

Приветствую, уважаемые программисты!

Уж много раз этот форум спасал меня. Вся надежда только на него и теперь. Развлекаюсь с хуками клавиатуры. Установка и снятие хука происходит без проблем. Беда в другом. Я не могу понять, при каких именно обстоятельствах, но... иногда в некоторых программах перехват не работает. А в некоторых работает не так, как я ожидаю...

Возьмем «простенькие» программки (Блокнот, Проводник, Калькулятор, PowerShell, TeamViewer и т.д.) — с ними проблем не возникает. Перехватывается сообщение нажатия клавиши, перехватывается сообщения отпускания клавиши. Все ок.

С браузерами дело хуже... у меня их не так много: IE (браузер, который нужен для скачивания нормального браузера) и Chrome.

В IE (v.11) происходит перехват только в том случае, если ввод осуществляется в адресную строку. Тут все ок. Перехватывается нажатие, перехватывается отпускание. Но... если открыта какая-то страница, содержащая поля ввода — то при вводе текста в эти поля перехват не происходит совсем.

В Хроме — еще веселее. Что при вводе в адресную строку, что при вводе в любое текстовое поле внутри какой-либо страницы, я получаю не два, а три перехвата (один раз — нажатие клавиши и два раза — ее отпускание).

И совсем беда с продуктами из пакета MS-Office: что таблички, что текст, что БД - куда бы я что ни вводил (хоть в документ, хоть в служебные поля (например поиск по документу) — ничего не перехватывается совсем.

А самая жесть — кнопка поиска рядом с кнопкой пуск: при попытке ввода текста в поле поискового запроса там творится вообще что-то непонятное: сначала (при вводе первой буквы) перехват происходит только нажатия (хотя в реальности я клавишу отпустил), а при попытке ввода второй буквы - сыплется штук 10 сообщений подряд..

Подскажите, пожалуйста, направление поиска куда копать... И, вообще, сталкивался ли кто-нибудь с чем-то подобным?

Код dll-ки:

Код:
library KBDHook;

uses
  SysUtils,
  Windows;

var
  CurHook: HWND;

function KeyboardProc(Code, WParam, LParam: DWord): DWord; stdcall;
Begin
  SendMessage(FindWindow(nil, PChar('Перехватчик')), $0400 + $125, WParam, LParam);
  Result := CallNextHookEx(CurHook, Code, WParam, LParam)
end;

procedure Hook(Switch: Boolean; HandleProg: HWND) export; stdcall;
begin
  if Switch = true then CurHook := SetWindowsHookEx(WH_KEYBOARD, @KeyboardProc, HInstance, 0) else UnhookWindowsHookEx(CurHook)
end;

exports
  Hook;

begin

end.
З.Ы. Потестировал на самой Delphi (у меня XE10): если программа (моя) запущена из-под среды, то перехват ввода текста в окне редактора происходит "в двойном размере" (ну, ладно, это, как бы, еще можно считать понятным и ожидаемым), а вот, если программа (моя) запущена сама по себе (отдельно от среды), то при вводе текста в окне редактора среды — перехват не происходит совсем (как и в Word, Excell etc.)

З.З.Ы. Перезагрузил ПК... теперь при вводе в Excell у меня происходит 10 перехватов (5 нажатий подряд и 5 отпусканий)... при вводе в скайп - 14 перехватов... а вот в веб-содержимом IE по-прежнему ничего перехватить не удается (хотя ввод в адресную строку перехватывается успешно)...

Короче, взорвался моск....

Последний раз редактировалось mxustin; 13.10.2017 в 12:09.
mxustin вне форума Ответить с цитированием
Старый 13.10.2017, 12:10   #2
eoln
Старожил
 
Аватар для eoln
 
Регистрация: 26.04.2008
Сообщений: 2,689
По умолчанию

Вместо WH_KEYBOARD нужен WH_KEYBOARD_LL
Соответственно, нужно менять процедуру обработки данных, т.к. в параметрах https://msdn.microsoft.com/ru-ru/lib...(v=vs.85).aspx хранятся не коды, а адрес структуры https://msdn.microsoft.com/ru-ru/lib...(v=vs.85).aspx

Ну и посылать каждое перехваченное нажатие по отдельности неэффективно, плюс ещё каждый раз приходится искать окно, да ещё и ожидать отклика (send - не post). Конечно, человек не так быстро печатает, но всё равно нехорошо.
eoln вне форума Ответить с цитированием
Старый 13.10.2017, 12:30   #3
mxustin
Пользователь
 
Аватар для mxustin
 
Регистрация: 02.10.2015
Сообщений: 20
По умолчанию

Цитата:
Сообщение от eoln Посмотреть сообщение
Вместо WH_KEYBOARD нужен WH_KEYBOARD_LL
Соответственно, нужно менять процедуру обработки данных, т.к. в параметрах https://msdn.microsoft.com/ru-ru/lib...(v=vs.85).aspx хранятся не коды, а адрес структуры https://msdn.microsoft.com/ru-ru/lib...(v=vs.85).aspx
Спасибо большое. Буду ковыряться. Потом, по итогу сообщу, что стало...

Цитата:
Сообщение от eoln Посмотреть сообщение
Ну и посылать каждое перехваченное нажатие по отдельности неэффективно, плюс ещё каждый раз приходится искать окно, да ещё и ожидать отклика (send - не post). Конечно, человек не так быстро печатает, но всё равно нехорошо.
Ну, пока демо-пример же... потом я весь шлак уберу и с поиском окна - тоже оптимизирую дело. Тоже, кстати, спасибо за указание!

---

От себя еще хочу одно маленькое наблюдение: когда тимвьювер активен - то по многим приложениям перехват не идет. Если его вырубить - то лучше становится, но, все равно, не идеально. Возможно, еще что-то там с тимвьюверовскими хуками какой-то конфликт возникает... Хотя при вводе на удаленную машину (через сам тимвьювер) — все норм...

В общем, буду рыть в сторону low level

Спасибо за наводку!


---
Upd.: Дружище, ты — лучший!!! Огромное спасибо! Все заработало кажись, как по маслу. Еще буду тестить, конечно, но, вроде бы, все работает! Спасибо!
Всё работает во всех программах, независимо от того, как давно был перезагружен компьютер, включен ли тимвьювер, и в какую сторону дует ветер! ))))) Причем, во всех программах по каждому нажатию приходит строго одинаковое количество сообщений, сколько их и должно быть, то есть - два (клавиша нажата/клавиша отпущена).

Последний раз редактировалось mxustin; 13.10.2017 в 14:52. Причина: Еще раз отблагодарить коллегу
mxustin вне форума Ответить с цитированием
Старый 13.10.2017, 16:59   #4
mxustin
Пользователь
 
Аватар для mxustin
 
Регистрация: 02.10.2015
Сообщений: 20
По умолчанию

Upd.: По поводу разных значений виртуальных клавиш в разных источниках — все вопросы, соответственно, тоже отпали...
mxustin вне форума Ответить с цитированием
Старый 14.10.2017, 22:04   #5
mxustin
Пользователь
 
Аватар для mxustin
 
Регистрация: 02.10.2015
Сообщений: 20
Лампочка Клавиатурный хук WH_KEYBOARD_LL (Delphi)

Частенько на форумах, когда хотелось найти решение какой-то проблемы, я встречал ветки, заканчивающиеся постом типа «Все ничтяк: я нашел решение!! Все работает!». В такие моменты я всегда немного недоумевал, почему же ТС не счел нужным поделиться решением с остальными...

Вот, чтобы не быть таким неблагодарным человеком, я выкладываю демо-пример. Преследуется только эта цель! Я прошу не пинать за код (это демо-пример, и не более того).

Итак,

Перехват клавиатуры

Общие сведения сводятся к следующему:
- если мы хотим глобально перехватывать нажатия клавиш в целом в системе, то перехват необходимо реализовывать в DLL;
- чтобы не иметь проблем, в отличие от примеров, на которые даны ссылки в конце поста, нужно пользоваться хуком WH_KEYBOARD_LL, а не WH_KEYBOARD, как там (у меня наблюдались странности, когда я пытался реализовать через WH_KEYBOARD: см. начало ветки);
- по скорости обработки — важно, чтобы процедура обработки была хорошо оптимизирована и укладывалась бы в отведенное время (это время может варьироваться в зависимости от настроек системы), потому что при перехвате "низкоуровневых" нажатий, система ждать не будет, пока вы там обработаете: она будет слать и слать сообщения;
- теоретические сведения можно почерпнуть по ссылкам ниже (см. конец поста).

Реализация DLL

Код:
library KBDHook;

uses
  SysUtils,
  Windows;

var
  Hk: HWND;
  Wn: HWND;

function KbdProc(Code: integer;  WParam: WPARAM;  LParam: LPARAM): LRESULT; stdcall;
Begin
  SendMessage(Wn, $555, WParam, LParam);
  Result := CallNextHookEx(Hk, Code, WParam, LParam)
end;

procedure Hook(Switch: Boolean; HandleProg: HWND) export; stdcall;
begin
  if Switch = true then Hk := SetWindowsHookEx(WH_KEYBOARD_LL, @KbdProc, HInstance, 0) else UnhookWindowsHookEx(Hk)
end;

exports
  Hook;

begin
  Wn := FindWindow(nil, PChar('Перехватчик'))
end.
Пояснения:
- KbdProc обрабатывает нажатия — в моем примере она ловит все нажатия (и "отжатия") подряд, без разбору и посылает соответствующие сообщения в мою программу-перехватчик (Wn), а после этого (безусловно) вызывает следующий хук.

Здесь больше всего нужно пояснений. Во-первых, ловить все подряд нажатия (и "отжатия"), вероятно, не потребуется (если только не пишется какой-нибудь клавиатурный шпион). Так что в этой процедуре могут быть какие-то условия, а может быть, потребуются только нажатия (без "отжатий"): это существенно повлияет на быстродействие (см. выше замечание о критичности времени обработки нажатий).

Второй момент касается условий, которые, вероятно, вы поставите на вызов следующего хука. Возможно, в каких-то случаях нужно будет "подменить" стандартное действие по той или иной клавише, и, соответственно, следующий хук вообще не вызывать (о том, что хуки образуют стек, если их несколько - можно почитать тут. Если пишется "шпион", присутствие которого должно быть незаметным, то, соответственно, вызываем следующий хук обязательно, чтобы пользователь получил бы то, что ожидает получить.

- Hook — устанавливает/снимает хук (тут особо пояснять нечего).

Реализация программы-перехватчика

В моем примере эта программа получает сообщения от DLL и показывает (в Memo), какая именно информация пришла.

Скриншот

Пояснения:

- при создании формы загружаем DLL и устанавливаем хук, а при закрытии программы - снимаем хук.

Код:
procedure TFormMain.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  Hook(False, FormMain.Handle);
end;

procedure TFormMain.FormCreate(Sender: TObject);
begin
  HDLL := LoadLibrary(PChar('KBDHook.dll'));
  @Hook := GetProcAddress(HDLL, 'Hook');
  Hook(True, FormMain.Handle);
end;
- объявляем procedure WndProc(var Msg: TMessage); override; и добавляем свою реализацию (за код этой процедуры мне особенно стыдно, потому что я поленился ее "причесывать", поэтому добавлю ее в архивчик )

Ну, собственно, в этой процедуре мы получаем Msg, и дальше делаем с этим что хотим (пишем в лог, смотрим, что именно нажато или "отжато", как долго было нажато... и т.д. и т.п.). В моем примере - просто выводится пришедшая инфа в Мемо.

Несколько ссылок по теме

Полезные ссылки по теме хуков на клавиатуру

Пример разработки клавиатурного шпиона
http://www.cyberguru.ru/programming/...oks-page2.html
http://www.webdelphi.ru/2009/10/prim...ona-na-delphi/

Хуки в Windows
https://rsdn.org/article/baseserv/winhooks.xml#ENJAE

MSDN о хуках на клавиатуру
https://msdn.microsoft.com/ru-ru/lib...(v=vs.85).aspx
https://msdn.microsoft.com/ru-ru/lib...(v=vs.85).aspx
https://msdn.microsoft.com/ru-ru/lib...(v=vs.85).aspx
https://msdn.microsoft.com/ru-ru/lib...(v=vs.85).aspx
https://msdn.microsoft.com/ru-ru/lib...(v=vs.85).aspx
https://msdn.microsoft.com/ru-ru/lib...(v=vs.85).aspx

Виртуальные коды клавиш
http://delphi-box.ru/kodi-klavish-delphi.html

Скан-коды клавиш
https://ru.wikipedia.org/wiki/%D0%A1...BA%D0%BE%D0%B4

Как обрабатывать WParam и LParam при низкоуровневом перехвате сообщений клавиатуры
http://www.delphimaster.ru/cgi-bin/f...1283707527&n=5
Вложения
Тип файла: rar 0001.rar (2.87 Мб, 33 просмотров)
mxustin вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц

Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск


Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
C++. Программа закрывается после клавиатурного ввода переменных Ruko! Помощь студентам 3 27.09.2012 06:41
Защита от хука Zombie_Killer Win Api 1 16.03.2012 08:23
Нестабильная работа ОС webstream Операционные системы общие вопросы 1 17.08.2010 16:10
правильное снятие хука majestic Win Api 1 11.01.2010 02:52
Структура клавиатурного шпиона. Altera Win Api 3 02.03.2009 10:53