Вопрос № 179170: Уважаемые эксперты! Требуется написать программу(с комментариями).Разработать резидентную программу для ОС MSDOS. Программа может быть выполнена в виде exe или com файла.При нажатии клавиши F12 программа заменяет вводимые пользователем алфавитные сим...
Вопрос № 179170:
Уважаемые эксперты! Требуется написать программу(с комментариями).Разработать резидентную программу для ОС MSDOS. Программа может быть выполнена в виде exe или com файла.При нажатии клавиши F12 программа заменяет вводимые пользователем алфавитные символы на другие (например q->w, w->e, e->r и т.д.). Ассемблер TASM. Буду очень признателен если сделаете программу.
Отвечает amnick, Профессионал :
Здравствуйте, Филимонов Алексей Викторович.
Эту задачу можно решить, перехватывая прерывание клавиатурное прерывание: 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 -> 1
7
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
Ответ отправил: amnick, Профессионал
Ответ отправлен: 24.06.2010, 21:34
Номер ответа: 262272
Вам помог ответ? Пожалуйста, поблагодарите эксперта за это! Как сказать этому эксперту "спасибо"?
Отправить SMS#thank 262272
на номер 1151 (Россия) |
Еще номера »
Оценить выпуск »
Нам очень важно Ваше мнение об этом выпуске рассылки!
* Стоимость одного СМС-сообщения от 7.15 руб. и зависит от оператора сотовой связи.
(полный список тарифов)
** При ошибочном вводе номера ответа или текста #thank услуга считается оказанной, денежные средства не возвращаются.
*** Сумма выплаты эксперту-автору ответа расчитывается из суммы перечислений на портал от биллинговой компании.