Форум программистов  
Контакты: о проблемах с регистрацией, почтой и по другим вопросам пишите сюда - alarforum@yandex.ru, проверяйте папку спам! Обязательно пройдите активизацию e-mail.

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

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

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

skype: mxustin
Вопрос Нестабильная работа клавиатурного хука

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

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

Возьмем «простенькие» программки (Блокнот, Проводник, Калькулятор, 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 в 13:09.
mxustin вне форума   Ответить с цитированием
Старый 13.10.2017, 13:10   #2
eoln
Профессионал
 
Аватар для eoln
 
Регистрация: 26.04.2008
Сообщений: 2,628
Репутация: 2191

icq: 421277094
По умолчанию

Вместо 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, 13:30   #3
mxustin
Пользователь
 
Аватар для mxustin
 
Регистрация: 02.10.2015
Адрес: Россия, Ростовская область
Сообщений: 18
Репутация: 24

skype: mxustin
По умолчанию

Цитата:
Сообщение от 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 в 15:52. Причина: Еще раз отблагодарить коллегу
mxustin вне форума   Ответить с цитированием
Старый 13.10.2017, 17:59   #4
mxustin
Пользователь
 
Аватар для mxustin
 
Регистрация: 02.10.2015
Адрес: Россия, Ростовская область
Сообщений: 18
Репутация: 24

skype: mxustin
По умолчанию

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

skype: mxustin
Лампочка Клавиатурный хук 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 Мб, 2 просмотров)
mxustin вне форума   Ответить с цитированием
Ответ



Опции темы

Ваши права в разделе
Вы не можете создавать новые темы
Вы не можете отвечать в темах
Вы не можете прикреплять вложения
Вы не можете редактировать свои сообщения

BB коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.

Быстрый переход

Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
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 03:52
Структура клавиатурного шпиона. Altera Win Api 3 02.03.2009 11:53




14:27.


Powered by vBulletin® Version 3.8.8 Beta 2
Copyright ©2000 - 2017, Jelsoft Enterprises Ltd.

купить трафик


как улучшить посещаемость, а также решения по монетизации сайтов, видео и приложений

RusProfile.ru


Справочник российских юридических лиц и организаций.
Проекты отопления, пеллетные котлы, бойлеры, радиаторы
интернет магазин respective.ru