Клавиатурная снифалка на C++

Николай "GorluM" Андреев

Xakep, номер #055, стр. 055-070-2


int code, // hook code

WPARAM wParam, // virtual-key code

LPARAM lParam // keystroke-message information

);

То есть наша функция должна принимать три параметра, описанных так же, как в документации мелкомягких. Плюс надо сделать ее экспортируемой - она будет запихиваться в отдельный модуль. В итоге получилось вот что:

__declspec(dllexport) LRESULT CALLBACK KeyboardProc(int code, WPARAM wParam, LPARAM lParam);

При срабатывании события в эту функцию передаются некоторые параметры. В code будет содержаться либо значение HC_ACTION, либо HC_NOREMOVE, но нас интересует только первое. Мы ведь обрабатываем именно нажатия клавиш. Кстати, определить, нажата ли клавиша, можно при помощи вот такого выражения:

(!(HIWORD(lParam) & KF_DOWN))

Оно будет истинно, если клавиша нажата, и ложно, если клавиша отпущена. Так как нам не надо писать каждую клавишу по два раза (для нажатия и отпускания), то при запуске функции поставим условие, чтобы запись производилась только при нажатии:

(code == HC_ACTION)&&(!(HIWORD(lParam) & KF_UP))

Если параметры удовлетворяют условию, то можно приступить к обработке кода нажатой клавиши, который будет содержаться в параметре wParam в виде значения типа char. Как ты понимаешь, можно сразу записать это значение в лог и без обработки, но тогда мы никогда не узнаем, была ли это русская буква или латинская, и вместо нажатых ctrl и alt мы увидим просто квадратики. Нет, так дело не пойдет. Мы грамотно обработаем полученную клавишу и запишем в лог и название клавиши и, если был включен русский язык, букву в кириллице.

А сделаем это следующим образом. Когда условия параметров нас удовлетворяют, создадим блок switch, в котором проверим значение wParam на сходство с системными клавишами. Если клавиша не системная, значит это буква.

switch ((char)wParam){

case VK_ESCAPE:

strcpy(buffer,"<ESC>");

break;

case VK_RETURN:

strcpy(buffer,"<RETURN>\r\n");

break;

}

buffer - строковая переменная. В нее записываются данные, которые впоследствии будут занесены в лог. По аналогии с примером описываются все возможные значения wParam для ctrl, alt, tab и т.п. Все они определены в файле winuser.h.

Далее, если значение wParam не подпадает ни под одно из описанных выше, значит, это буква, и данное условие требует отдельного рассмотрения. Так как мы не знаем, какой был включен языковой режим, соответственно, и не сможем определить, что же записывать в файл. Для определения текущей раскладки и записи необходимого символа относительно этой раскладки мы воспользуемся двумя функциями. Первая - GetKeyboardState получает массив из 256 элементов со всеми статусами виртуальных клавиш. Вторая, ToAscii, занимается тем, что относительно текущей раскладки, полученной при помощи первой функции, вычисляет, какой символ должен соответствовать нажатой клавише, и записывает этот символ в первый элемент нашей переменной. Вот так выглядит код:

default:

BYTE keyarray[256] ;

if(GetKeyboardState(keyarray))

if(!ToAscii(wParam,(HIWORD(lParam)&(0x0000FFFF)), keyarray,(WORD*)&buffer[0],NULL))

Назад на стр. 055-070-1  Содержание  Вперед на стр. 055-070-3