В данной статье мы рассмотрим, как перехватить ввод с клавиатуры в Delphi с использованием функции SetWindowsHookEx. Мы также обсудим причину ошибки, возникшей при попытке-duplicate кода из статьи "Intercepting Keyboard Input With Delphi".
Введение
Перехват ввода с клавиатуры может быть полезен в различных ситуациях, например, для реализации горячих клавиш, записи макросов или предотвращения нежелательного ввода. В Delphi для перехвата ввода с клавиатуры можно использовать функцию Windows API SetWindowsHookEx.
Пример кода
Давайте рассмотрим пример кода, который пытается-duplicate код из статьи "Intercepting Keyboard Input With Delphi":
type
TForm1 = class(TForm)
ListBox1: TListBox;
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
private
{ Private declarations }
KBHook: HHook; {this intercepts keyboard input}
{callback's declaration}
function KeyboardHookProc(Code: Integer; WordParam: Word;
LongParam: LongInt): LongInt; stdcall;
public
{ Public declarations }
end;
...
procedure TForm1.FormCreate(Sender: TObject);
begin
{Set the keyboard hook so we can intercept keyboard input}
KBHook := SetWindowsHookEx( WH_KEYBOARD,
{callback >} @KeyboardHookProc,
HInstance,
GetCurrentThreadId() );
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
{unhook the keyboard interception}
UnHookWindowsHookEx(KBHook) ;
end;
function TForm1.KeyboardHookProc(Code: Integer; WordParam: Word;
LongParam: LongInt): LongInt;
begin
ListBox1.Items.Add( 'Code: ' + Code.ToString);
ListBox1.Items.Add( ' -- WordParam: ' + WordParam.ToString);
ListBox1.Items.Add( ' -- LongParam: ' + LongParam.ToString);
ListBox1.Items.Add( '' );
Result := 0;
{To prevent Windows from passing the keystrokes
to the target window, the Result value must be a nonzero value.}
end;
Ошибка и решение
При попытке скомпилировать данный код возникает ошибка:
Эта ошибка происходит из-за того, что в качестве второго аргумента функции SetWindowsHookEx используется метод KeyboardHookProc, а не функция. Чтобы исправить эту ошибку, нужно либо объявить метод как статический, либо использовать свободную функцию вместо метода.
Решение 1: Использование статического метода
Можно объявить метод KeyboardHookProc как статический, чтобы удалить скрытый параметр Self. Вот как это сделать:
type
TForm1 = class(TForm)
ListBox1: TListBox;
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
private
{ Private declarations }
KBHook: HHook; {this intercepts keyboard input}
{callback's declaration}
class function KeyboardHookProc(Code: Integer; WordParam: WPARAM;
LongParam: LPARAM): LRESULT; stdcall; static;
public
{ Public declarations }
end;
var
Form1: TForm1;
...
procedure TForm1.FormCreate(Sender: TObject);
begin
{Set the keyboard hook so we can intercept keyboard input}
KBHook := SetWindowsHookEx( WH_KEYBOARD,
{callback >} @KeyboardHookProc,
HInstance,
GetCurrentThreadId() );
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
{unhook the keyboard interception}
UnHookWindowsHookEx(KBHook) ;
end;
class function TForm1.KeyboardHookProc(Code: Integer; WordParam: WPARAM;
LongParam: LPARAM): LRESULT;
begin
Form1.ListBox1.Items.Add( 'Code: ' + Code.ToString);
Form1.ListBox1.Items.Add( ' -- WordParam: ' + WordParam.ToString);
Form1.ListBox1.Items.Add( ' -- LongParam: ' + LongParam.ToString);
Form1.ListBox1.Items.Add( '' );
Result := 0;
{To prevent Windows from passing the keystrokes
to the target window, the Result value must be a nonzero value.}
end;
Решение 2: Использование свободной функции
Вместо того чтобы объявлять метод как статический, можно использовать свободную функцию для реализации обратного вызова. Вот как это сделать:
type
TForm1 = class(TForm)
ListBox1: TListBox;
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
private
{ Private declarations }
KBHook: HHook; {this intercepts keyboard input}
public
{ Public declarations }
end;
var
Form1: TForm1;
...
{callback's declaration}
function KeyboardHookProc(Code: Integer; WordParam: WPARAM;
LongParam: LPARAM): LRESULT; stdcall;
begin
Form1.ListBox1.Items.Add( 'Code: ' + Code.ToString);
Form1.ListBox1.Items.Add( ' -- WordParam: ' + WordParam.ToString);
Form1.ListBox1.Items.Add( ' -- LongParam: ' + LongParam.ToString);
Form1.ListBox1.Items.Add( '' );
Result := 0;
{To prevent Windows from passing the keystrokes
to the target window, the Result value must be a nonzero value.}
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
{Set the keyboard hook so we can intercept keyboard input}
KBHook := SetWindowsHookEx( WH_KEYBOARD,
{callback >} @KeyboardHookProc,
HInstance,
GetCurrentThreadId() );
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
{unhook the keyboard interception}
UnHookWindowsHookEx(KBHook) ;
end;
Заключение
В данной статье мы рассмотрели, как перехватить ввод с клавиатуры в Delphi с использованием функции SetWindowsHookEx. Мы также обсудили причину ошибки, возникшей при попытке-duplicate кода из статьи "Intercepting Keyboard Input With Delphi" и предложили два решения: использование статического метода или свободной функции для реализации обратного вызова. Выбор между этими решениями зависит от конкретных требований вашего проекта.
В данной статье рассматривается, как перехватить ввод с клавиатуры в Delphi с помощью функции SetWindowsHookEx и решается проблема, возникшая при попытке-duplicate кода из статьи "Intercepting Keyboard Input With Delphi".
Комментарии и вопросы
Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS
Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.