Смекни!
smekni.com

Резидентный обработчик клавиатуры (перехват нажатий клавиш и запись в файл) (стр. 7 из 7)

int 21h

; Восстановим использовавшиеся регистры

pop dx

pop es

pop ds

iret ; Возврат в вызвавшую программу

new_2fh endp ; Конец процедуры обработки прерывания 2Fh

end_res=$ ; Смещение конца резидентной части программы

main endp

tail db 'off' ; Ожидаемый хвост команды

flag db 0 ; Флаг требования выгрузки

tabl db '0123456789' ; Таблица для перевода BCD кода в ASCII

time db 25 dup(?) ; Ячейка для сохранения текущей даты и времени

; Процедура создания файла

div_f proc

mov ah,3ch ; Функция создания файла

mov cx,0 ; Без атрибутов

lea dx,filename ; DS:DX ¬ ASCIIZ имени файла

int 21h

mov bx,ax ; Дескриптор в ВХ

mov ah,40h ; Функция записи в файл

mov cx,buflen ; CХ ¬ количество байт

lea dx,buf ; DS:DX ¬ адрес строки

int 21h

mov ah,3eh ; Функция закрытия файла

int 21h

ret ; Выход из процедуры

div_f endp ; Конец процедуры создания файла

; Процедура открытия файла и записи в него текущей даты и времени

div2_f proc

mov [time],0ah ; Запись в переменную time маркеров

mov [time+1],0dh ; перехода на следующую строку

mov ah,3dh ; Функция открытия файла

mov al,1 ; для записи

mov dx,offset filename ; DS:DX ¬ ASCIIZ имени файла

int 21h

mov bx,ax ; Дескриптор в ВХ

push bx ; Сохраним дескриптор

xor cx,cx ; Отчистим СХ

xor dx,dx ; и DX

mov ax,4202h ; Функция установки указателя в конец файла

int 21h

mov ah,02h ; Функция чтения времени из «постоянных» «CMOS» часов реального времени

int 1ah ; Прерывание ввода – вывода для времени

mov bx,offset tabl ; DS:DX ¬ адрес таблицы

mov si,2 ; Установим смещение для переменной time

mov ax,cx ; Часы и минуты сохраним в AX

mov cx,12 ; Установим счётчик сдвига

next: push ax ; Сохраним AX

shr ax,cl ; Сдвинем AX на CL

and al,0fh ; Получим номер ячейки в таблице прибавив маску

xlat ; Получим ASCII код числа

mov [time+si],al ; Занесём его в переменную time

inc si ; Увеличим на 1 смещение

cmp si,4 ; Смещение = 4 ?

je ras ; Да, переход на метку ras

vw: sub cl,4 ; Нет, уменьшим CL на 4

pop ax ; Восстановим AX

cmp cl,-4 ; Сравним CL с -4

jne next ; Не равно – выполним ещё раз

jmp ent1 ; Равно – переход на ent1

ras: mov [time+si],':' ; Запишем в переменную time – «:»

inc si ; Увеличим на 1 смещение

jmp vw ; Перейдём на метку vw

ent1: mov [time+si],' ' ; Запишем в переменную time – « »

inc si ; Увеличим на 1 смещение

mov ah,04h ; Функция чтения даты из «постоянных» «CMOS» часов реального времени

int 1ah ; Прерывание ввода – вывода для времени

mov ax,dx ; Дату сохраним в AX

mov cx,12 ; Установим счётчик сдвига

next1: push ax ; Сохраним AX

shr ax,cl ; Сдвинем AX на CL

and al,0fh ; Получим номер ячейки в таблице прибавив маску

xlat ; Получим ASCII код числа

mov [time+si],al ; Занесём его в переменную time

inc si ; Увеличим на 1 смещение

cmp si,10 ; Смещение = 10 ?

je ras1 ; Да, переход на метку ras1

vw1: sub cl,4 ; Нет, уменьшим CL на 4

pop ax ; Восстановим AX

cmp cl,-4 ; Сравним CL с -4

jne next1 ; Не равно – выполним ещё раз

jmp ent2 ; Равно – переход на ent2

ras1: mov [time+si],'.' ; Запишем в переменную time – «.»

inc si ; Увеличим на 1 смещение

jmp vw1 ; Перейдём на метку vw1

ent2: mov [time+si],0ah ; Запись в переменную time маркеров

mov [time+si+1],0dh ; перехода на следующую строку

pop bx ; Восстановим дескриптор

mov ah,40h ; Функция записи в файл

mov cx,20 ; CХ ¬ количество байт

mov dx,offset time ; DS:DX ¬ адрес строки

int 21h

mov ah,3eh ; Функция закрытия файла

int 21h

ret ; Выход из процедуры

div2_f endp ; Конец процедуры подготовки файла

; Процедура инициализации

init proc

mov cl,es:80h ; Получим длину хвоста PSP

cmp cl,0 ; Длина хвоста = 0 ?

je live ; Да программа запущена без параметров

xor ch,ch ; Теперь CX=CL=длина хвоста

mov di,81h ; DS:SI ® хвост в PSP

lea si,tail ; DS:SI ® поле tail

mov al,' ' ; Уберём пробелы из начала хвоста

repe scasb ; Сканируем хвост, пока пробелы

dec di ; DI ® первый символ после пробелов

mov cx,3 ; Ожидаемая длина параметра

repe cmpsb ; Сравниваем введённый хвост с ожидаемым

jne live ; Введена неизвестная команда

inc flag ; Введено «off», установим флаг запроса на выгрузку

; Проверим, не установлена ли уже данная программа

live: mov ah,0f1h ; Установим нашу функцию

mov al,0 ; и подфункцию на наличие нашей программы в оперативной памяти

int 2fh

cmp al,0ffh ; Программа установлена?

je installed ; Да, при наличии запроса на выгрузку её можно выгрузить

; Сохраним вектор 2fh

mov ax,352fh ; Функция получения вектора 2fh

int 21h

mov word ptr cs:old_2fh,bx ; Сохраним смещение системного обработчика

mov word ptr cs:old_2fh+2,es ; Сохраним сегмент системного обработчика

; Заполним вектор 2fh

mov ax,252fh ; Функция установления вектора прерывания 2fh

mov dx,offset new_2fh ; Смещение нашего обработчика

int 21h

; Сохраним вектор 09h

mov ax,3509h ; Функция получения вектора 09h

int 21h

mov word ptr cs:old_09h,bx ; Сохраним смещение системного обработчика

mov word ptr cs:old_09h+2,es ; Сохраним сегмент системного обработчика

; Заполним вектор 09h

mov ax,2509h ; Функция установления вектора прерывания 09h

mov dx,offset new_09h ; Смещение нашего обработчика

int 21h

mov ah,4eh ; Функция поиска файла

lea dx,filename ; DS:DX ¬ ASCIIZ имени файла

int 21h

cmp ax,12h ; Файл не найден?

je creat ; Да, создадим файл

call div2_f ; Нет, вызов процедуры открытия файла и записи в него текущей даты и времени

jmp by ; Переход на метку by

creat: call div_f ; Вызов процедуры создания файла

; Выведем на экран информационное сообщение

by: mov ah,09h ; Функция вывода на экран

lea dx,mes ; DS:DX ¬ адрес строки

int 21h

mov ax,3100h ; Функция «завершиться и остаться резидентным»

mov dx,(end_res-main+10fh)/16 ; Размер в параграфах

int 21h

installed:

cmp flag,1 ; Запрос на выгрузку установлен?

je unins ; Да, на выгрузку

; Выведем на экран информационное сообщение

mov ah,09h ; Функция вывода на экран

lea dx,mes1 ; DS:DX ¬ адрес строки

int 21h

; Выведем предупреждающий звуковой сигнал

mov cx,5 ; Количество гудков

mov ah,02h ; Функция вывода на экран

l: mov dl,07h ; ASCII код зуммера

int 21h

loop l ; Повторим CX раз

mov ax,4c01h ; Функция завершения с кодом возврата

int 21h

unins:

; Перешлём в первую (резидентную) копию программы запрос на выгрузку

mov ax,0f101h ; Наша функция с подфункцией выгрузки

int 2fh ; Мультиплексное прерывание

; Выведем на экран информационное сообщение

mov ah,09h ; Функция вывода на экран

lea dx,mes2 ; DS:DX ¬ адрес строки

int 21h

mov ax,4c00h ; Функция завершения программы

int 21h

buf db 'Skencode&Klav_flag file',0ah,0dh

buflen equ $-buf

mes db 'Program installed$'

mes1 db 'Program already installed$'

mes2 db 'Program is DIE$'

init endp

text ends

end main

3.4. Рекомендации по улучшению

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

– Вторым недостатком нашей программы является не всегда удобный механизм выгрузки программы из оперативной памяти. Можно предусмотреть выгрузку нашей программы специальной не стандартной комбинацией клавиш.

– Третий существенный недостаток программы состоит в том, что наш обработчик не реагирует на сочетание клавиш Clrl+Alt+Del. Так как наш обработчик перехватывает прерывания от клавиатуры раньше чем системный обработчик “int09h”, то было бы целесообразно при этом сочетании сбрасывать содержимое буфера в файл, а затем передавать управление системному обработчику.

– Можно предусмотреть запись в файл autoexec.bat либо config.sys строки с путём к нашему файлу, при запуске программы с параметром вводимым с командной строки.

– Можно предусмотреть коррекцию размеров буфера, а также задавать имя рабочего файла с помощью всё тех же параметров вводимых с командной строки.

– В зависимости от того в каких целях применяется данный обработчик, можно запретить нажатие какой либо клавиши, комбинации клавиш или последовательности.

Данная программа является шаблоном для резидентных обработчиков прерываний, в частности обработчиков прерываний от клавиатуры, и является огромным полем для творчества.

4. Список используемой литературы

1. П.И.Рудаков, К.Г.Финогенов «Программируем на языке ассемблера IBM PC», Обнинск 1997г.

2. Зубков С.В. «Assembler для DOS, Windows и UNIX», Москва 2000г.

3. Богумирский Б.С. «Руководство пользователя ПЭВМ», Санкт–Петербург 1994г.