уважаемые посетители блога, если Вам понравилась, то, пожалуйста, помогите автору с лечением. Подробности тут.

В начале, как полагается, разберемся с вопросом: зачем нам нужны виртуальные и скан-коды клавиш?

Лично для меня изучить этот вопрос сподвигла небольшая проблема при тестировании одной из программ в отделе экологов. Дело в том, что встречается такой тип людей, которые почему-то страх как боятся компьютеров, несмотря на то, что без них не могут обойтись, да к тому же не могут толком объяснить, в случае проблемы, что собственно случилось.

Начинаешь тестировать программу, устанавливаешь на компьютер пользователя, объясняешь все популярно (тот, естественно, что-то помечает на обрывках бумажек), спрашиваешь «Понял?», тот — «Да, понял.» Уходишь, через день приходишь и начинается «Программа не работает», «Там что-то какое-то окошко появилось» и т.д. и т.п. Спрашиваешь «Что делал?» Показывает действие за действием — ошибок нет…Как работал человек? Не понятно. Сидеть целый день за спиной у него и наблюдать — не вариант. Заставлять записывать за собой всё, что делал — изуверство. Интерфейс упростил дальше некуда, даже не Hint’ы сделал, а в тупую подписи под каждым контролом, что куда писать. Не помогло. В итоге, родилась простая, на первый взгляд идея — установить на компьютер пользователя небольшую программку-шпиона, чтобы отслеживала все действия, которые тот творит над программой. Естественно, предупредив перед этим работника, что теперь все его действия над программой сохраняются (только не сказал куда…мало ли). Вот в процессе работы над моим псевдо-шпионом мне и потребовались дополнительные знания по работе с клавиатурой.

Вы же можете использовать полученные знания где угодно:

  • создавать клавиатурных шпионов (только учтите, что тот же «Касперский» их распознает очень хорошо)
  • использовать коды в своих программах, например, если Вам захочется, чтобы программа выполняла какое-либо действие после нажатия на дополнительную клавишу, такую как F13 на навороченных клавиатурах и пр.
  • разрабатывать приложения типа Punto Switcher и пр.

Сразу оговорюсь — в этой статье я не буду выкладывать весь исходник моего «шпиона», только ту часть, которая отвечает за перехват нажатия клавиши. Это связано с тем, что для полноценной работы моей программы мне также пришлось разобраться немного с Windows API,  чтобы отслеживать действия только с моей программой, а это уже целая отдельная статья.

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

uses crt,dos;
var xah, xal:byte;
begin
  asm
  mov ah,10h {функция чтения из клавиатуры}
  int 16h
  mov xah, ah
  mov xal, al
end;
  writeln('Symbol = ', xal, ' Scan = ', xah);
end.

То есть после нажатия какой-нибудь клавиши в регистре al окажется код символа, а в ahскан код.

Теперь про виртуальные коды.

Виртуальные коды — это то, что использует система для идентификации клавиш. То есть, зная виртуальный код клавиши, можно со 100% уверенностью хоть через неделю сказать пользователю, что он такого нажимал (и в какой последовательности). Дополнительно, зная текущую раскладку, можно также определить, что писал пользователь, но это уже немного другой вопрос.

Теперь напишем небольшую ловушку для клавиатуры, которая будет отлавливать все нажатия клавиш и писать лог-файл, в котором будет содержаться скан-код и виртуальный код нажатой клавиши.

library Spyhook;
uses Messages, Windows, Ariphm;
var HookHandle: HHOOK;
ft: TextFile;
function KeyboardProc(Code:Integer;wParam: wParam; LParam:LParam):integer; stdcall;
begin
  if code<0 then Result:=CallNextHookEx(HookHandle, code, WParam, LParam)
  else
    if byte(LParam shr 24)<$80 then
      begin
         try
           append(ft);
         except
         exit;
      end;
  writeln(ft, 'Key(wParam)=$',hexw(wParam),' LParam =$',hexlong(lParam));
closefile(ft);
end;
  CallNextHookEx(HookHandle, code, WParam, LParam)
end;
 
procedure SetHook; stdcall;
begin
  HookHandle:=SetWindowsHookEx(WH_KEYBOARD, KeyboardProc,HInstance,0);
end;
 
procedure DelHook; stdcall;
begin
  UnhookWindowsHookEx(HookHandle);
end;
 
exports
SetHook, DelHook;
 
begin
  AssignFile(ft, 'c:\keyhook.txt');
end.

Собственно, опытный глаз программиста сразу может увидеть недостаток, а именно — работа с файлом из DLL, что не рекомендуется. В идеале в DLL следует только определять коды и отсылать и в основную программу, а та в свою очередь пусть пишет их файл, но, как показала практика, может сгодиться и такой вариант.

Обратите внимание на выражение

byte(LParam shr 24)<$80

здесь определяется была ли нажата клавиша. Если да, то записываем файл. Если это условие убрать, то каждое действие на клавиатуре будет дублироваться, т.е. в файл запишется нажатая клавиша и отпущенная.

Теперь пишем основное приложение. Для демонстрации действия ловушки я сделал вот такую форму:

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

Кстати, советую поставить по-больше задержку на таймере, иначе не будете успевать просмотреть всё содержимое.

Теперь делаем ссылки на необходимые нам процедуры из DLL. Будем загружать все необходимые процедуры (а их аж 2 штуки) сразу же после запуска программы. После описания формы пишем:

....
procedure SetHook; stdcall; External 'Spyhook.dll';
procedure DelHook; stdcall; External 'Spyhook.dll';
....

На событие onCreate необходимо открыть или создать лог-файл и запустить нашу ловушку.

procedure TForm1.FormCreate(Sender: TObject);
var ft: TextFile;
begin
  AssignFile(ft, 'c:\keyhook.txt');
  try
    reset(ft);
  except
    rewrite(ft);
  end;
  CloseFile(ft);
  SetHook;  //запуск ловушки
end;

Соответственно, на закрытие приложения ловушку необходимо выгрузить:

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  DelHook;
end;

Вывод содержимого лог-файла в Memo делается проще простого:

procedure TForm1.Timer1Timer(Sender: TObject);
begin
  Memo2.Clear;
  Memo2.Lines.LoadFromFile('c:\keyhook.txt');
end;

Вот и все, что от нас требовалось. Теперь запускаем приложение (предварительно положив рядом с ним созданную DLL) и любуемся результатом:

spyhook2Как видите в wParam мы получаем необходимый виртуальный код, а в LParam — скан-код и дополнительные сведения, например, признак расширенной клавиши. Все данные сохраняются в HEX-форме и при желании вы их сможете легко расшифровать. Если возникнут трудности — обращайтесь, разберемся вместе.

Скачать исходник: Исходники —> Прочие
0 0 голоса
Рейтинг статьи
уважаемые посетители блога, если Вам понравилась, то, пожалуйста, помогите автору с лечением. Подробности тут.
Подписаться
Уведомить о
9 Комментарий
Межтекстовые Отзывы
Посмотреть все комментарии
Алексей
Алексей
28/09/2010 14:18

Здравствуйте, Влад. Возможно мой вопрос вам покажется странным и не по адресу, но на просторах интернета я себе внятного ответа не обнаружил.
Суть в следующем: требуется написать программу, одной из задач которой является выполнение процедуры по нажатию по F5 и CTRL+F5, а так же перекодировка символов в теле программы. Не могли бы вы мне подсказать, как это можно реализовать? желательно без использования ДЛЛ, на выходе предпочтительно иметь 1 экзешник.

xkeen
xkeen
27/01/2011 19:34

Если еще актуально… Горячие клавиши удобно отлавливать с помощью ActionList. Создаешь Action в свойству ShortCut присваиваешь сочетание клавиш. А на OnExecute нужную процедуру обработки.

Sasha
25/02/2011 01:51

Извините за повтор в первом сообщение не указал адрес блога. Скажите пожалуйста возможно реализовать немного иную программу, а именно : перехват нажатия на виртуальной клавиатуре и транслировать их во все приложения как нажатие обычной клавиатуры?

trackback

[…] скан коды клавиш delphi […]

Андрей
Андрей
17/10/2013 20:18

Здравствуйте, очень хорошая и полезная программа, в последней редакции она определяет буквенное значение нажатой клавиши, а нет ли у вас скомпилированного первого варианта программы которая выдает сканкоды клавиш, я не программист, попытался скомпилировать сам — не получилось , пожалуйста выложите готовлю программу, заранее благодарен!

Oleg Guzz
18/11/2013 03:56
Ответить на  Андрей

Я все откомпилировал в RAD Studio XE5 Если надо пришлю. Пиши мне на oleg.guzz@gmail.com
Разгружу автора, помогу хоть этим. Я сейчас ломаю голову над переводом кодов в символы. Зачет автору. Многое нашел в сети, но чем то не подходили. Тут же отлавливается любая клавиша. Да и как то бы избавиться от записи в текст из длл-ки — это я про следующую тему.

Oleg Guzz
18/11/2013 03:58

AssignFile(ft, ‘c:keyhook.txt’);
c:keyhook.txt это для развития мозгов слеша не хватает и еще собак кое где:)