Тема: LangMF 8.0: отслеживание клавиатурных нажатий, хук WH_KEYBOARD
Без гарантий. Используете на свой страх и риск.
Пример постановки глобального клавиатурного хука WH_KEYBOARD. После запуска скрипта в окне формы отображается текущая нажатая клавиша из буквенно цифрового диапазона [A-Z А-Я 0-9 Space] в верхнем регистре с учетом языковой раскладки текущего окна. Чтобы закрыть форму дважды щелкните по ней любой кнопкой мыши.
Потребуется установленный LangMF 8.0
ОС Win Me/XP
Проект состоит из двух файлов расположенных в одном каталоге:
1) Скрипт Khook.mf - установщик хука который надо запустить.
2) Библиотека процедуры хука CALLBACK.DLL
Содержимое Khook.mf
'Пример постановки клавиатурного хука WH_KEYBOARD. После запуска скрипта в окне формы
'отображается текущая нажатая клавиша из буквенно цифрового диапазона [A-Z А-Я 0-9 Space]
'в верхнем регистре с учетом языковой раскладки текущего окна. Чтобы закрыть форму
'дважды щелкните по ней любой кнопкой мыши.
'Потребуется установленный LangMF 8.0
'ОС Win 98/XP
<#Module=KBRD_HOOK>
Const WH_KEYBOARD =2
Const WM_COMMNOTIFY =&H0044
Const LY_RU =&H419
Const LY_EN =&H409
Public hHook
Public hLib
Sub Load(cmdstr)
'[Загрузка библиотеки хука]
'----------------------------------------------------------------------------------
hLib =Sys.API.LoadLibrary("CALLBACK.DLL")
If hLib=0 Then
MsgBox "Требуется CALLBACK.DLL",vbSystemModal+vbExclamation,"Error"
EndMF
End If
hCBack =Sys.DynApi.CallFunction("KERNEL32.DLL","GetProcAddress",hLib,"HookCallBack")
'[Установка параметров формы]
'----------------------------------------------------------------------------------
With form
.Caption ="kbrdhook"
.BackColor =vbYellow
.Style.ToolWindow =True
.Style.TaskBar =False
'------------------------------------------------------------------------
.Add "label",1, "Left=5","Top=5","Width=80","Height=40", _
"Alignment=2","Caption= ","FontSize=20"
'------------------------------------------------------------------------
.AttachMsg WM_COMMNOTIFY
.Show
End With
DoEvents
'----------------------------------------------------------------------------------
Sys.API.SetWindowPosA form.hWnd, _
-1, _
0, _
0, _
100, _
100, _
0
'[Установка клавиатурного хука]
'----------------------------------------------------------------------------------
hHook =Sys.DynApi.CallFunction( _
"USER32.DLL", _
"SetWindowsHookExA", _
WH_KEYBOARD, _
hCBack, _
hLib, _
0)
'----------------------------------------------------------------------------------
DoEvents
End Sub
Function UnhookKbrd()
'[Освобождение клавиатурного хука]
'----------------------------------------------------------------------------------
Sys.DynApi.CallFunction _
"USER32.DLL", _
"UnhookWindowsHookEx", _
hHook
'----------------------------------------------------------------------------------
Sys.DynApi.CallFunction _
"KERNEL32.DLL", _
"FreeLibrary", _
hLib
'----------------------------------------------------------------------------------
End Function
<#Module>
<#Form=form>
Function ISubclass_MsgResponse()
ISubclass_MsgResponse=1
End Function
Function ISubclass_WindowProc(hwnd,iMsg,wParam,lParam)
'[Получение языковой раскладки текущего окна]
'----------------------------------------------------------------------------------
hHookWnd=Sys.DynApi.CallFunction( _
"USER32.DLL", _
"GetForegroundWindow")
hThread =Sys.DynApi.CallFunction( _
"USER32.DLL", _
"GetWindowThreadProcessId", _
hHookWnd, _
0)
hLY =Sys.DynApi.CallFunction( _
"USER32.DLL", _
"GetKeyboardLayout", _
hThread)
'[Отображение нажатой клавиши]
'----------------------------------------------------------------------------------
hLY=CLng("&H" & Sys.RightS(CStr(Hex(hLY)),4))
'----------------------------------------------------------------------------------
If hLY=LY_RU Then
data=Sys.Conv.LKey_RKey(Chr(wParam))
Else
data=Chr(wParam)
End If
'--------------------------------------------------------------------------
if data =~ /([A-ZА-Я0-9\s]+)// then form.Label(1).Caption=data
'--------------------------------------------------------------------------
ISubclass_WindowProc=True
End Function
Sub Form_DblClick()
form.UnloadForm()
End Sub
Sub Form_Unload()
Form.DetachMsg WM_COMMNOTIFY
DoEvents
UnhookKbrd()
DoEvents
EndMF
DoEvents
End Sub
'pltrgst
<#Form>
2) Вынос процедуры хука в библиотеку CALLBACK.DLL позволяет поставить глобальный хук для всех уже существующих и вновь запущенных оконных процессов.
Запуск n новых процессов порождает n хуков, каждый из которых принадлежит своему процессу. Процедура хука автоматически подключается в процесс текущего рабочего окна, и отслеживает клавиатурные нажатия. К сожалению хуки встроенные во вновь запущенные процессы удаляются только закрытием самих процессов. Библиотека CALLBACK.DLL собрана на макроассемблере HLA 1.103.
Код CALLBACK.DLL
unit DllCallBack;
//------------------------------------------------------------------------
// Обработка хука WH_KEYBOARD
//------------------------------------------------------------------------
#include( "w.hhf" );
//------------------------------------------------------------------------
procedure dll( instance:dword; reason:dword; reserved:dword );
@stdcall;
@external( "_dll@12" );
//------------------------------------------------------------------------
procedure HookCallBack(nCode:int32; wParam:dword; lParam:dword);
@stdcall;
@external( "_HookCallBack@12" );
//------------------------------------------------------------------------
static
ThisInstance: dword:= 0;
storage
hHook: dword;
//------------------------------------------------------------------------
procedure dll( instance:dword; reason:dword; reserved:dword ); @nodisplay;
begin dll;
mov( instance, eax );
mov( eax, ThisInstance );
if( reason = w.DLL_PROCESS_ATTACH ) then
endif;
mov( true, eax );
end dll;
//------------------------------------------------------------------------
procedure HookCallBack(nCode:int32; wParam:dword; lParam:dword);
var
hwnd: dword;
begin HookCallBack;
if ( nCode < 0 ) then
mov(0,eax);
else
w.FindWindow(NULL,"kbrdhook");
mov(eax,hwnd);
w.SendMessage(hwnd,w.WM_COMMNOTIFY,wParam,lParam);
endif;
w.CallNextHookEx( hHook,nCode,wParam,lParam );
end HookCallBack;
//------------------------------------------------------------------------
end DllCallBack;
Библиотека экспортирует единственную полезную функцию HookCallBack, которая обрабатывает нажатия клавиатуры и не видя внутренние глобальные переменные, отсылает входной параметр отвечающий за виртуальный код нажатой клавиши окну LangMF скрипта,который обрабатывает сообщение с помощью возможностей сабклассинга.
Существенный недостаток HLA - работа с 128 символьной кодировкой, что сокращает возможности скрипта по корректному определению ASCII кода нажатой клавиши. Тем не менее данный вариант вполне применим для дополнительной обработки нажатия произвольной клавиши даже при скрытой форме LangMF, в независимости от текущего активного окна.