Консультация № 179170
20.06.2010, 21:38
42.03 руб.
0 3 1
Уважаемые эксперты! Требуется написать программу(с комментариями).Разработать резидентную программу для ОС MSDOS. Программа может быть выполнена в виде exe или com файла.При нажатии клавиши F12 программа заменяет вводимые пользователем алфавитные символы на другие (например q->w, w->e, e->r и т.д.). Ассемблер TASM. Буду очень признателен если сделаете программу.

Обсуждение

Неизвестный
24.06.2010, 21:13
общий
Такая сложная задача?
Неизвестный
24.06.2010, 21:34
общий
это ответ
Здравствуйте, Филимонов Алексей Викторович.

Эту задачу можно решить, перехватывая прерывание клавиатурное прерывание: 9 (аппаратное) или 16h (программное). Более универсальным методом является перехват int 9, но он несколько сложнее в реализации. В моей программе перехватывается int 16h.

Сначала программа проверяет, установлена ли она уже в памяти, если да, то выводится сообщение и выполнение завершается. Если программа еще не установлена, то резидентный код перемещается в младшие адреса для экономии памяти (в PSP по смещению 5Ch — это вполне безопасно), освобождается сегмент окружения, перехватывается вектор 16h и программа завершается с оставлением в памяти резидентной части. Программа занимает в памяти всего 320 байт.

Резидентный код сначала проверяет вызванную функцию прерывания 16h. Мы обрабатываем ф-и 0, 1, 10h и 11h, остальные функции передаются оригинальному обработчику. Для перечисленных функций сначала вызывается оригинальный код прерывания, а затем анализируется возвращенное значение. Небольшое отличие заключается в том, что для ф-й 1 и 11h после возврата из оригинального обработчика необходимо проверить флаг нуля — если никакая клавиша не была нажата, то перекодирование не требуется. Затем проверяется, не была ли нажата клавиша F12. Если да, то переключается режим перекодирования — вкл/выкл. Нажатие клавиши F12 "не съедается", т.е. вызвавшая программа получит код клавиши. Здесь есть такой момент: если вызывается ф-я 11h, а затем 10h, то при нажатии F12 режим перекодирования переключится дважды, т.е. не переключится вообще. Чтобы избежать этого, нужно обрабатывать F12 так, как будто никакая клавиша не была нажата вообще.

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

Программу компилировать в COM-файл.

Успехов!

Код:
locals @@
.model tiny

HOTKEY = 8600h ; расширенный код F12

; вопрос/ответ для проверки, установлен ли обработчик
MY_QUESTION = 0AFE7h
MY_ANSWER = 64D9h

; изменение адресов после перемещения резидентной части
delta EQU (offset keyTable - 5Ch)

.code
.startup

jmp Install ; переходим на код инициализации

; ---- начало резидентной части ----
; таблица перекодировки клавиш
; заменяются и скан-коды, и соответствующие им символы
keyTable label word
; скан-код нажатой клавиши
; |
; | v----- на какой заменяется
db 'E',12h ; 16 -> 18
db 'R',13h ; 17 -> 19
db 'T',14h ; 18 -> 20
db 'Y',15h ; 19 -> 21
db 'U',16h ; 20 -> 22
db 'I',17h ; 21 -> 23
db 'O',18h ; 22 -> 24
db 'P',19h ; 23 -> 25
db 'A',1eh ; 24 -> 30
db 'S',1fh ; 25 -> 31
dw 0 ; 26
dw 0 ; 27
dw 0 ; 28
dw 0 ; 29
db 'D',20h ; 30 -> 32
db 'F',21h ; 31 -> 33
db 'G',22h ; 32 -> 34
db 'H',23h ; 33 -> 35
db 'J',24h ; 34 -> 36
db 'K',25h ; 35 -> 37
db 'L',26h ; 36 -> 38
db 'Z',2ch ; 37 -> 44
db 'X',2dh ; 38 -> 45
dw 0 ; 39
dw 0 ; 40
dw 0 ; 41
dw 0 ; 42
dw 0 ; 43
db 'C',2eh ; 44 -> 46
db 'V',2fh ; 45 -> 47
db 'B',30h ; 46 -> 48
db 'N',31h ; 47 -> 49
db 'M',32h ; 48 -> 50
db 'Q',10h ; 49 -> 16
db 'W',11h ; 50 -> 17

my_int16:
cmp ax,MY_QUESTION ; проверка наличия в памяти?
jne @@1
mov ax,MY_ANSWER ; ответ: обработчик уже установлен
iret
@@1:
; обрабатываем функции 0, 1, 10h, 11h прерывания 16h
cmp ah,1
jb @@f0
je @@f1
cmp ah,10h
jb @@old
je @@f0
cmp ah,11h
je @@f1
@@old: ; иная функция, передаем управление старому обработчику
db 0EAh ; код JMP FAR
int16_ptr dd 0 ; адрес перехода

@@f0: ; функции 0 и 10h
; сначала вызовем старый обработчик прерывания
pushf
call dword ptr CS:[int16_ptr-delta]
jmp short @@common

@@f1: ; функции 1 и 11h
; сначала вызовем старый обработчик прерывания
pushf
call dword ptr CS:[int16_ptr-delta]
jz @@ret2 ; не была нажата клавиша

@@common:
pushf ; сохраняем флаги - нужно для 1, 11h

cmp ax,HOTKEY ; была нажата клавиша вкл/выкл перекодировки?
jne @@no_hotkey ; нет

cmp byte ptr CS:[@@no_hotkey+1-delta],al ; дистанция перехода = 0?
jne @@on
; выключаем перекодировку
mov byte ptr CS:[@@no_hotkey+1-delta],offset @@ret - offset @@encode
jmp short @@ret
@@on:
; включаем перекодировку
mov byte ptr CS:[@@no_hotkey+1-delta],al ; 0 - переход на следующую команду
jmp short @@ret

@@no_hotkey: ; если перекодировка выкл (начальное состояние), то выходим
jmp short @@ret ; при включении - просто переходим к следующей команде

@@encode:
test al,al
jz @@ret ; AL = 0 - расширенный код

; проверяем попадание скан-кода в диапазон буквенных латинских клавиш
cmp ah,10h
jb @@ret ; не латинская буква
cmp ah,32h
ja @@ret ; не латинская буква

push bx ; сохраняем используемый регистр
mov bl,ah
xor bh,bh
shl bx,1 ; индексируем массив слов
add bx,offset keyTable - 10h*2 - delta ; смещение таблицы перекодировки со сдвигом
cmp byte ptr CS:[bx],0
je @@no_code ; не латинская буква

cmp al,'a' ; сравнение для определения "прописная - строчная"
mov ax,CS:[bx] ; скан- и ASCII-коды клавиши
jb @@no_code ; исходный код меньше 'a' - прописная буква
or al,20h ; преобразование в строчную
@@no_code:
pop bx ; восстанавливаем измененный регист
@@ret:
popf ; восстанавливаем флаги после оригинального прерывания
@@ret2:
retf 2 ; возвращаемся с отбрасыванием старых флагов

; ---- конец резидентной части ----

Install: ; код инициализации
mov ah,9 ; AH=9 - вывод сообщения
mov dx,offset msgInfo ; DS:DX - адрес строки
int 21h

mov ax,MY_QUESTION ; проверить наличие в памяти
int 16h
cmp ax,MY_ANSWER ; сравнить с ответом
jne @@set

; программа уже установлена
mov ah,9 ; AH=9 - вывод сообщения
mov dx,offset msgAlready ; DS:DX - адрес строки
int 21h
int 20h ; выход

@@set:
; перемещаем резидентный код для экономии памяти
mov si,offset keyTable
mov di,5Ch
mov cx,(offset Install - offset keyTable + 1)/2 ; кол-во слов
cld
rep movsw

mov ah,49h ; освобождаем блок окружения (environment)
mov ES,DS:[2Ch] ; сегмент блока окружения
int 21h

; перехватываем прерывание 16h
mov ax,3516h ; AH = 35h - получить вектор, AL - прерывание
int 21h
mov word ptr DS:[int16_ptr-delta],bx ; ES:BX - адрес
mov word ptr DS:[int16_ptr-delta+2],ES

mov ah,25h ; AH = 25h - установить вектор, AL - прерывание
mov dx,offset my_int16 -delta ; DS:DX - адрес обработчика
int 21h

mov dx,offset Install - delta ; адрес конца резидентной части
int 27h ; оставляем резидентный код в памяти и выходим

msgInfo db 'Keyboard encoder',13,10
db 'Press F12 to activate/deactivate encoding',13,10,'$'
msgAlready db 'The encoder has been installed already', 13,10,'$'

end
Неизвестный
24.06.2010, 21:36
общий
спасибо буду тестировать)
Форма ответа