Использование ловушек, блокировка мышки, клавиатуры и т.д.

=== Использование ловушек, блокировка мышки, клавиатуры и т.д. ===
Возможные вариации: Любые вопросы, связанные с постановкой хука. Например "Как отследить [что-то]", "Как подменить [какое-то действие]", "Как заблокировать комбинации клавиш, как заблокировать определённые действия", "Как не дать запускаться определённым приложениям, не дать открываться определённым окнам?", "Как получить список запущенных оконных приложений?" и т.д.
Рабочий пример глобальной блокировки правой кнопки мыши:
==== DLL ====
library Project2;
uses
 Windows,
 Messages;
var
 SysHook: HHook = 0;
function SysMsgProc(Code: Integer; WParam: LongInt; LParam: LongInt): LongInt; stdcall;
var
 Msg: TMessage;
begin
 if Code = HC_ACTION then
 begin
 case TMsg(Pointer(LParam)^).Message of
 WM_RBUTTONDOWN,
 WM_RBUTTONUP,
 WM_RBUTTONDBLCLK:
 TMsg(Pointer(LParam)^).Message := WM_NULL
 else
 Result := CallNextHookEx(SysHook, Code, WParam, LParam);
 end;
 end;
end;
procedure Hook(Flag: boolean); export; stdcall;
begin
 if Flag then
 SysHook := SetWindowsHookEx(WH_GETMESSAGE, @SysMsgProc, HInstance, 0)
 else
 begin
 UnhookWindowsHookEx(SysHook);
 SysHook := 0;
 end;
end;
exports Hook;
{$R *.res}
begin
end.
----
==== Project ====
unit Unit1;
interface
uses
 Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
 Dialogs, Menus, StdCtrls;
type
 MyProcType = procedure (Flag: Boolean); stdcall;
type
 TForm1 = class(TForm)
 Button1: TButton;
 Button2: TButton;
 procedure FormMouseDown(Sender: TObject; Button: TMouseButton;
 Shift: TShiftState; X, Y: Integer);
 procedure Button1Click(Sender: TObject);
 procedure Button2Click(Sender: TObject);
 procedure FormDestroy(Sender: TObject);
 private
 { Private declarations }
 public
 { Public declarations }
 end;
var
 Form1: TForm1;
 HDLL: HWND;
implementation
{$R *.dfm}
procedure TForm1.FormMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
 if Button = mbRight then
 ShowMessage('Right mouse key pressed');
end;
procedure TForm1.Button1Click(Sender: TObject);
var
 Hook: MyProcType;
begin
 @Hook := nil;
 HDLL := LoadLibrary(PChar('project2.dll'));
 if HDLL > HINSTANCE_ERROR then
 begin
 @Hook := GetProcAddress(HDLL, 'Hook');
 Hook(True);
 end
 else
 MessageDlg('Ошибка загрузки DLL.', mtError, [mbIgnore], 0);
end;
procedure TForm1.Button2Click(Sender: TObject);
var
 Hook: MyProcType;
begin
 @Hook := nil;
 if HDLL > HINSTANCE_ERROR then
 begin
 @Hook := GetProcAddress(HDLL, 'Hook');
 Hook(False);
 end;
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
 Button2.Click;
end;
end.
Файлы для демонстрации можно взять здесь: http://coolsong.narod.ru/hook.rar
Работает так: при неустановленном хуке правая кнопка работает (о чём свидетельствует нажатие правой кнопки мыши - событие TForm.onMouseDown и сообщение). После установки хука кнопкой "Install", события от мыши перестают обрабатываться (сообщение "Right mouse key pressed" не выдаётся). после снятия хука (кнопка "Remove") - всё возвращается к первоначальному состоянию.
Если требуется перехватывать клавиши, тогда из вышеобозначенной теории нам известны варианты: WH_KEYBOARD, WH_KEYBOARD_LL или WH_GETMESSAGE+WM_CHAR/WM_KEYDOWN/UP
Однако, если требуется перехватить всего лишь отдельную клавишу, будь то одну либо с нажатым Ctrl, Alt, Shift, рациональней для этого воспользоваться назначением горячей клавиши, через RegisterHotKey().
Рабочий пример такого приёма:
type
 TForm1 = class(TForm)
 procedure FormCreate(Sender: TObject);
 procedure FormDestroy(Sender: TObject);
 protected
 procedure hotykey(var msg: TMessage); message WM_HOTKEY;
 end;
var
 Form1: TForm1;
 id, id2: Integer;
implementation
{$R *.DFM}
procedure TForm1.hotykey(var msg: TMessage);
begin
 if (msg.LParamLo = MOD_CONTROL) and (msg.LParamHi = 81) then
 begin
 ShowMessage('Ctrl + Q wurde gedruckt !');
 end;
 if (msg.LParamLo = MOD_CONTROL) and (msg.LParamHi = 82) then
 begin
 ShowMessage('Ctrl + R wurde gedruckt !');
 end;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
 id := GlobalAddAtom('hotkey');
 RegisterHotKey(handle, id, mod_control, 81);
 id2 := GlobalAddAtom('hotkey2');
 RegisterHotKey(handle, id2, mod_control, 82);
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
 UnRegisterHotKey(handle, id);
 UnRegisterHotKey(handle, id2);
end;
==== Блокировка клавиатуры/мыши. ====
Родственная тема, поэтому помещена в этот же вопрос.
Итак, заблокировать можно хуком. Но в некоторых случаях можно обойтись и "малой кровью".
Вы можете использовать функцию BlockInput. Она живёт в user32.dll Также она блокирует одновременно и мышь.
 procedure BlockInput(ABlockInput: Boolean); stdcall; external 'USER32.DLL';
 
 BlockInput(True); - заблокировать
 BlockInput(False); - разблокировать
Однако имейте ввиду, что BlockInput() не заблокирует CAD. Кроме того, её работа блокируется по нажатию трёх пальцев. Для блокировки CAD в w9x, мы можем использовать режим скринсэйвера, в NT, увы никак.
Функция BlockInput() явилась продолжением функции EnableHardwareInput(), которая как мы знаем использовалась в 16-разрядных приложениях.
Кроме того, для блокировки, мы можем использовать некоторые недокументированные возможности, однако их недостаток в том, что обратно клавиатуру/мышь уже включить нельзя:
 "rundll32 keyboard,disable" - заблокировать клавиатуру
 "rundll32 mouse,disable" - заблокировать мышь
Запустить эти команды мы можем самое простое через ShellExecute() или WinExec():
 ShellExecute(Application.Handle, 'open', 'C:\Windows\Rundll32.exe', 'команда', 'C:\Windows', SW_HIDE);
Author: Song
ID: 02218