© Иван Рощин, Москва
| ZXNet | : 500:95/462.53 |
| : bestview@mtu-net.ru | |
| WWW | : http://www.ivr.da.ru |
(«Радиомир. Ваш
компьютер» 1/2003)
Дата последнего редактирования: 13.04.2003.
Введение
Постановка задачи
Начнём с простого
Взаимодействие резидента с программой
Листаем справочник: прерывание BIOS 10h
Листаем справочник: прерывание BIOS 16h
Текст резидентной программы
Комментарии
«Бонусы» резидента
Литература
Когда приходится набирать текст, содержащий и русские, и латинские буквы, иногда забываешь переключить режим Рус/Lat, и набираемый текст становится бессмысленным. Бывает, что так же забываешь переключить режим Caps Lock, и вместо прописных букв вводятся строчные и наоборот. Приходится стирать неправильно набранный участок текста и вводить его заново.
Я предлагаю способ решения этой проблемы для
Сначала определимся с терминами. Разрабатываемую программу я буду в дальнейшем называть «резидент», а термин «программа» буду использовать для обозначения программы, в которой вы набираете и исправляете текст. Клавиша (или комбинация с Shift, Alt, Ctrl), предназначенная для активизации резидента, будет в дальнейшем называться «горячей клавишей».
Итак, что нам надо? Пусть мы забыли переключить режим Рус/Lat, и в результате неправильно набрали определённый участок текста. Когда ошибка замечена, хотелось бы нажать определённую «горячую клавишу» (пусть это будет, скажем, F12), после чего неправильно набранный участок текста окажется исправленным. Точно так же, когда мы забыли включить (или наоборот, выключить) режим Caps Lock, хотелось бы нажать другую «горячую клавишу» (скажем, F11) для исправления неправильно набранного текста.
Возможно, в такой постановке решить задачу и не удастся, придётся идти на
Пусть у нас имеется строка символов, и известно, что при её наборе был неправильно установлен режим Caps Lock. Как исправить такую строку?
Если режим Caps Lock выключен, то при нажатии клавиш без Shift вводятся строчные буквы, а с Shift прописные. Если же этот режим включён, то наоборот: без Shift вводятся прописные буквы, а с Shift строчные. Таким образом, для исправления строки достаточно заменить в ней прописные буквы на строчные и наоборот.
Идём дальше. Теперь пусть у нас имеется строка символов, и известно, что при её наборе был ошибочно включён русский (или латинский) режим. Как исправить такую строку?
При нажатии одних и тех же клавиш в русском и латинском режиме вводятся различные символы. Их соответствие приведено в табл. 1 (для русификатора KeyRus с раскладкой клавиатуры «по умолчанию»).
| N строки таблицы | Режим Caps Lock | Режим работы клавиатуры | Вводимые символы |
|---|---|---|---|
| 1 | выключен | РУС | абвгдежзийклмнопрстуфхцчшщъыьэюяАБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ"/':,.; |
| 2 | выключен | LAT | f,dult;pbqrkvyjghcnea[wxio]sm'.zF<DULT:PBQRKVYJGHCNEA{WXIO}SM">Z@#$%^&* |
| 3 | включён | РУС | АБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыьэюя"/':,.; |
| 4 | включён | LAT | F,DULT;PBQRKVYJGHCNEA[WXIO]SM'.Zf<dult:pbqrkvyjghcnea{wxio}sm">z@#$%^&* |
Отсюда непосредственно следует алгоритм исправления строки. Возможны четыре различных случая.
1. Если при наборе строки был ошибочно включён русский режим, и режим Caps Lock был выключен, то отыскиваем в строке все символы, имеющиеся в строке 1 табл. 1, и заменяем их на соответствующие символы из строки 2 табл. 1.
2. Если был ошибочно включён латинский режим, и режим Caps Lock был выключен, то отыскиваем в строке все символы, имеющиеся в строке 2 табл. 1, и заменяем их на соответствующие символы из строки 1 табл. 1.
3. Если был ошибочно включён русский режим, и режим Caps Lock был включён, то отыскиваем в строке все символы, имеющиеся в строке 3 табл. 1, и заменяем их на соответствующие символы из строки 4 табл. 1.
4. Если был ошибочно включён латинский режим, и режим Caps Lock был включён, то отыскиваем в строке все символы, имеющиеся в строке 4 табл. 1, и заменяем их на соответствующие символы из строки 3 табл. 1.
Как видим, для исправления строки, набранной в неправильном режиме Рус/Lat, надо ещё знать, включён или выключен был режим Caps Lock при её вводе. Если считать, что с момента ввода строки и до её исправления состояние Caps Lock не изменилось, то достаточно узнать текущее состояние Caps Lock. Как это сделать, мы рассмотрим позднее.
Можно заметить, что строка 1 в табл. 1 отличается от строки 3 только тем, что прописные буквы заменены на строчные и наоборот. То же самое относится к строкам 2 и 4. Тогда выгоднее для экономии места хранить не все четыре строки, а, например, только первую и вторую, а третью и четвёртую получать из них, меняя регистр букв на противоположный. Процедура для изменения регистра букв всё равно понадобится для исправления текста, набранного при неправильном состоянии Caps Lock.
Набираемый в программе текст хранится в некоторой области памяти. Где именно «знает» только сама программа. И вот пользователь нажимает «горячую клавишу» для исправления текста. Как резидент «узнает», какой именно текст ему надо исправить?
В самом деле, не выводить же окошко с просьбой пользователю, чтобы он ввёл ещё раз неправильно набранный текст. Очевидно, что тогда использование резидента потеряет всякий смысл: проще будет исправить текст вручную.
Заметим, что набранный текст также отображается на экране! То есть он находится в видеопамяти. И непосредственно после неправильно набранной строки текста стоит курсор! Тогда можно, обращаясь к функциям прерывания BIOS 10h, определить координаты курсора, а затем узнать, какие символы находятся слева от курсора, это и будет исправляемый текст.
Но надо ещё определить длину исправляемого участка текста. Не обязательно это будет вся расположенная слева от курсора часть строки. Может быть, пользователь набрал в неправильном режиме только последние несколько символов. Как быть? Не запрашивать же у пользователя длину неправильно введённой строки?
Определять длину автоматически? А как? Это вопрос непростой. Можно
предложить разные способы, но ни один не может обеспечить 100% надёжности.
Поэтому я решил, что одно нажатие «горячей клавиши» будет
исправлять только один символ текста, находящийся слева от курсора, после чего
курсор передвинется на символ влево. (Если
При нажатии «горячей клавиши» для исправления текста,
набранного в неправильном режиме Рус/Lat, резидент должен ещё определить,
какой режим был ошибочно включён при наборе текста: русский или латинский. Как
это сделать? Если считать, что с момента ввода строки и до её исправления
режим Рус/Lat не переключался, то достаточно знать его текущее состояние. Но
сведения о том, какой режим в данный момент включён, хранятся
Тогда поступим так: будем просматривать строку от позиции курсора до левого края экрана, пока не попадётся буква. Если эта буква русская, значит, при наборе текста был ошибочно включён русский режим; если латинская соответственно, латинский режим. Если в строке не оказалось буквы, то считаем, что ошибочно включённым был тот же режим, который был определён при нажатии «горячей клавиши» в прошлый раз.
Обратим внимание на следующее. Если пользователь исправляет строку текста, набранную в неправильном режиме Рус/Lat, нажимая для этого нужное число раз соответствующую «горячую клавишу», то определять, какой режим был ошибочно включён при наборе строки, надо только при первом нажатии «горячей клавиши». Дело в том, что если остались неисправленными только небуквенные символы, а слева остался участок строки, не нуждающийся в исправлении и с другими буквами, то определение режима произойдёт неверно.
Например, на экране такая строка:
Это первый участок "nj dnjhjq exfcnjr
^курсор
|
При первом нажатии «горячей клавиши» первый же символ слева от курсора оказывается латинской буквой. Значит, при наборе был ошибочно включён латинский режим. Последовательные нажатия «горячей клавиши» приводят к исправлению строки:
Это первый участок "то второй участок
^курсор
|
Осталось исправить только первый символ строки. Если сейчас попробовать снова определить, какой режим был неправильно включён при наборе текста, то первой встреченной буквой окажется русская, и будет сделан вывод, что был неправильно включён русский режим. Это неверно, и дальнейшее исправление будет неправильным:
Это первый участок @то второй участок
^курсор
|
Перейдём к рассмотрению следующего вопроса. Пусть после нажатия «горячей клавиши» резидент уже определил, какой символ текста должен быть исправлен и на какой символ его надо заменить. А что он должен сделать дальше? Выше уже упоминалось, что набираемый в программе текст хранится в некоторой области памяти, известной только самой программе. Так что резидент не может сам исправить текст, а может только передать программе указания по его исправлению.
Как это сделать? А как передаёт указания по исправлению текста пользователь? С помощью нажатия клавиш, конечно. Как вы стали бы исправлять неправильно набранный символ текста? Сначала нажали бы клавишу BackSpace для стирания этого символа, а затем ввели бы правильный.
Значит, резидент должен «подсунуть» программе информацию о нажимаемых клавишах, как будто их нажимает пользователь. А как это сделать?
В подавляющем большинстве случаев программы используют для опроса клавиатуры прерывание BIOS 16h (может быть, и не обращаясь к нему непосредственно). Следовательно, чтобы «подсовывать» программе нужные коды клавиш, нужно перехватить обработку этого прерывания. Помимо этого, перехват прерывания BIOS 16h нужен ещё и для того, чтобы отслеживать факт нажатия пользователем «горячих клавиш».
Рассмотрим функции прерывания BIOS 10h, которые понадобятся нам для определения положения курсора и определения кодов символов, отображённых на экране.
При вызове функции её номер указывается в регистре AH. В [3] упоминается, что после окончания работы вызванной функции содержимое регистров BX, CX, DX, SI и BP остаётся неизменённым (очевидно, если эти регистры не используются для возвращения результата).
Для определения координат курсора служит функция 3. Перед её вызовом в регистре BH надо указать номер текущей страницы видеопамяти. После вызова в DH будет номер строки, а в DL номер столбца, где расположен курсор. В регистре CX возвращается размер курсора (он нам не понадобится, но знать, что содержимое CX изменится после вызова функции, необходимо).
Для использования этой функции надо знать номер текущей страницы видеопамяти. Чтобы его узнать, используется функция F. После её вызова нужный нам номер страницы будет в регистре BH.
Теперь о том, как определить код символа, если известны его координаты на экране. Для этого можно использовать функцию 8. Перед вызовом в регистре BH надо указать номер текущей страницы видеопамяти. После вызова код символа, находящегося в позиции курсора, будет в регистре AL.
Понятно, что перед вызовом этой функции надо установить курсор в нужную позицию, а после вызова вернуть курсор на прежнее место. Для задания нового положения курсора служит функция 2. Перед её вызовом в регистре BH надо указать номер текущей страницы видеопамяти, а в DX новые координаты курсора (DH номер строки, DL номер столбца).
Как видим, использование одной функции влечёт за собой необходимость использования другой функции, и так далее. Хотя было бы достаточно всего двух функций «определить координаты курсора в текущей странице видеопамяти» и «определить код символа с заданными координатами в текущей странице видеопамяти».
Функции этого прерывания предназначены для работы с клавиатурой. Даже если программа пользуется более высокоуровневыми функциями DOS, они в итоге всё равно обращаются к этому прерыванию.
Вообще работа с клавиатурой организована так: при нажатии или отпускании
Здесь мы рассмотрим те из функций прерывания BIOS 16h, которые нам придётся использовать и/или перехватывать в резиденте.
При вызове функции её номер указывается в регистре AH.
Функция 0 чтение кода клавиши. Берёт из клавиатурного буфера
значение
Функция 1 чтение кода клавиши без удаления его из клавиатурного
буфера. Если буфер не пуст, флаг Z сбрасывается, а прочитанные
Функция 2 опрос состояния служебных клавиш. Результат
возвращается в регистре AL. Эта функция понадобится нам, чтобы узнать, включён
или выключен режим Caps Lock. Если
Функции 10h и 11h то же самое, что функции 0 и 1, но с их
помощью можно также получить коды дополнительных клавиш, имеющихся на
Функции 0, 1, 10h, 11h должны быть перехвачены резидентом, чтобы «подсовывать» программе нужные коды клавиш. За одно обращение к функции можно передать программе только один код клавиши, а для исправления неправильно введённого символа надо передать несколько кодов. Следовательно, надо организовать в резиденте специальный буфер (далее внутренний буфер), помещать оставшиеся коды туда, а при следующих обращениях программы к функциям INT 16h для опроса клавиатуры возвращать коды из этого буфера.
Как уже упоминалось выше, эти функции должны возвращать в AH
KEY_1 equ 8600h ;Скан-код и ASCII-код "горячей клавиши" RUS <-> LAT.
KEY_2 equ 8500h ;Скан-код и ASCII-код "горячей клавиши" txt <-> TXT.
codesg segment
assume cs:codesg
assume ds:codesg
org 100h
begin: jmp init ;Переход к инициализации
;Определение переменных:
buf_inside dw ?,?,? ;Внутренний буфер.
buf_len db 0 ;Текущее количество элементов в нём.
page_num db ? ;Номер текущей страницы видеопамяти.
next_corr db 0 ;Прошлой нажатой клавишей была KEY_1?
way_l2r db 1 ;0 - RUS -> LAT, 1 - LAT -> RUS.
cursor_xy dw ? ;Координаты курсора.
rus_chars db "абвгдежзийклмнопрстуфхцчшщъыьэюя"
db "АБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ"
db '"',"/':,.;"
lat_chars db "f,dult;pbqrkvyjghcnea[wxio]sm'.z"
db 'F<DULT:PBQRKVYJGHCNEA{WXIO}SM">Z'
db "@#$%^&*"
len_chars equ offset lat_chars - offset rus_chars
;Новый обработчик прерывания 16h.
new_16h: test ah,0eeh ;Проверка номера вызванной функции.
jz main_1
;Если вызвана не одна из функций 0,1,10h,11h, передаём управление
;на старый обработчик:
db 0eah ;Код межсегментного JMP.
old_16h dd ? ;Адрес старого обработчика.
;Иначе обрабатываем сами:
main_1: push ax
push bx
push cx
push dx
push es
push ds
push si
push di
push bp
mov bp,sp
;Теперь исходное (и возвращаемое) значение AX находится по адресу [BP+16],
;а исходное (и возвращаемое) значение регистра флагов - по адресу [BP+22].
push cs
pop ds
;Проверка номера вызванной функции:
test ah,0efh
jnz main_3
;Функция 0 или 10h - "чтение кода клавиши":
cmp buf_len,0 ;Если буфер пуст, заполняем.
jne main_2
call append_buf
main_2: mov ax,buf_inside ;Берём пару "скан-код, символ"
mov [bp+16],ax ;из буфера.
mov ax,buf_inside+2 ;Сдвигаем оставшиеся
mov buf_inside,ax ;элементы буфера.
mov ax,buf_inside+4
mov buf_inside+2,ax
dec buf_len
jmp short return
;Функция 1 или 11h - "проверить наличие кода клавиши":
main_3: cmp buf_len,0
jne main_7
;Во внутреннем буфере пусто, проверяем клавиатурный буфер
;(с помощью функции 11h, чтобы отследить коды "горячих клавиш"):
mov ah,11h ;!!!
pushf
call old_16h
mov buf_inside,ax
jnz main_4
;Если там тоже пусто, выходим, установив флаг Z=1:
or word ptr [bp+22],40h
jmp short return
;В клавиатурном буфере что-то есть.
;Проверяем: это код "горячей клавиши"?
main_4: cmp ax,KEY_1
je main_5
cmp ax,KEY_2
jne main_6
;Обработка "горячей клавиши":
main_5: call act_hotkey
jmp main_3
;В клавиатурном буфере не код "горячей клавиши".
;Возвращаем ответ, вызывая старый обработчик INT 16h:
main_6: or word ptr [bp+22],40h ;Сначала устанавливаем флаг Z.
mov ax,[bp+16]
pushf
call old_16h
jnz return_1 ;Переход, если флаг Z надо сбросить.
jmp short return_2
;Внутренний буфер не пуст. Берём оттуда значение и выходим, сбросив флаг Z:
main_7: mov ax,buf_inside
return_1: and word ptr [bp+22],0bfh
return_2: mov [bp+16],ax
return: pop bp
pop di
pop si
pop ds
pop es
pop dx
pop cx
pop bx
pop ax
iret
;----------------------------------------------------------------------------
;Процедура append_buf - пополнение внутреннего буфера кодов клавиш.
;Вызывается, если буфер пуст (т.е. buf_len=0).
append_buf proc near
;Чтобы иметь возможность определить нажатие "горячей клавиши", опрашиваем
;клавиатуру как 101-клавишную и ждём нажатия, не забирая символ из
;клавиатурного буфера:
append_1: mov ah,11h ;!!!
pushf
call old_16h
mov buf_inside,ax
jz append_1
;Проверяем: в клавиатурном буфере код "горячей клавиши"?
cmp ax,KEY_1
jz append_2
cmp ax,KEY_2
jnz append_3
;Обработка "горячей клавиши":
append_2: call act_hotkey
cmp buf_len,0
jne append_4
;В клавиатурном буфере не код "горячей клавиши" либо её код, но при обработке
;во внутренний буфер ничего не было помещено. Тогда просто запрашиваем код
;клавиши, обращаясь к старому обработчику:
append_3: mov ax,[bp+16]
pushf
call old_16h
mov buf_inside,ax
inc buf_len ;= mov buf_len,1
mov next_corr,0
append_4: ret
append_buf endp
;----------------------------------------------------------------------------
;Процедура act_hotkey - обработка "горячей клавиши".
;
;Вход: в клавиатурном буфере - код "горячей клавиши", во внутреннем буфере -
; он же (но buf_len=0).
;Выход: если нажатие надо обрабатывать, в буфер помещаются три кода или один
; код, иначе - ничего. Длина буфера соответственно будет 3, 1 или 0.
act_hotkey proc near
;Извлекаем код "горячей клавиши" из клавиатурного буфера:
mov ah,10h ;!!!
pushf
call old_16h
;Определяем текущую страницу видеопамяти:
mov ah,15
int 10h
mov page_num,bh
;Определяем координаты курсора:
mov ah,3
int 10h
mov cursor_xy,dx
;Если курсор на левой границе экрана, выходим:
and dl,dl
jz act_exit
;Иначе переходим на символ влево:
dec dl
;Определяем, какая именно "горячая клавиша" нажата:
cmp buf_inside,KEY_1
jnz act_2
;Выполняем преобразование Рус/Lat.
cmp next_corr,0
jnz act_1
;Определяем направление преобразования:
push dx
call def_rl
pop dx
inc next_corr ;=mov next_corr,1
act_1: call char_xy
call corr_rl
cmp al,0
je act_4
jmp short act_3
;Выполняем преобразование прописные/строчные:
act_2: mov next_corr,0
call char_xy
call corr_caps
;Сейчас, если AH=2, то символ не надо преобразовывать, иначе
;в AL преобразованный символ.
cmp ah,2
je act_4
;Символ надо преобразовывать.
;Заносим в буфер код Backspace:
act_3: mov buf_inside,0e08h
;Заносим в буфер скан-код (=0) и ASCII-код преобразованного символа:
mov ah,0
mov buf_inside+2,ax
;Заносим в буфер код "<-":
mov buf_inside+4,4b00h
mov buf_len,3
ret
;Символ не надо преобразовывать - заносим в буфер только код "<-":
act_4: mov buf_inside,4b00h
inc buf_len ;= mov buf_len,1
act_exit: ret
act_hotkey endp
;----------------------------------------------------------------------------
;Процедура def_rl определяет направление преобразования строки: 0, если
;строка была неправильно набрана в русском режиме, и 1, если строка была
;неправильно набрана в латинском режиме.
;
;Вход: DX - координаты последнего символа строки.
;Выход: way_l2r - направление.
def_rl proc near
call char_xy ;Берем текущий символ строки.
call corr_caps ;Проверяем: это буква, и если да, то какая?
cmp ah,2
jne def_rl_2
;Это не буква - тогда переходим к предыдущему символу. Если строка кончилась,
;выходим, при этом way_l2r сохраняет старое значение.
def_rl_1: and dl,dl
jz def_rl_3
dec dl
jmp def_rl
;Это буква - тогда в AH сейчас 0, если буква русская, и 1 - если латинская.
;Это значение и присваиваем way_l2r.
def_rl_2: mov way_l2r,ah
def_rl_3: ret
def_rl endp
;----------------------------------------------------------------------------
;Процедура char_xy возвращает код символа с заданными координатами.
;
;Вход: DX - координаты символа.
;Выход: AL - код символа;
; DX - без изменений.
char_xy proc near
push dx
mov ah,2 ;Устанавливаем курсор
mov bh,page_num ;в заданную позицию.
int 10h
mov ah,8 ;Определяем код символа
int 10h ;в позиции курсора.
push ax
mov ah,2 ;Восстанавливаем
mov dx,cursor_xy ;координаты курсора.
int 10h
pop ax
pop dx
ret
char_xy endp
;----------------------------------------------------------------------------
;Процедура corr_rl исправляет один символ строки.
;
;Вход: AL - исходный символ,
; way_l2r - направление преобразования.
;Выход: AL - исправленный символ или 0, если исправлять не надо.
corr_rl_a dw ? ;Адрес вызываемой подпрограммы: addr_ret при
;не нажатой Caps Lock и corr_caps - при нажатой.
corr_rl proc near
push ax
;Определяем, нажата ли клавиша Caps Lock:
mov ah,2
pushf
call old_16h
;Если нажата, то при чтении из массивов rus_chars и lat_chars кодов букв
;надо изменять регистр этих букв на противоположный. Для этого в corr_rl_a
;записывается адрес процедуры corr_caps. Если клавиша Caps Lock не нажата,
;в corr_rl_a записывается адрес команды RET.
mov corr_rl_a,offset addr_ret
and al,40h
jz corr_rl_1
mov corr_rl_a,offset corr_caps
corr_rl_1: mov di,offset rus_chars
mov si,offset lat_chars
cmp way_l2r,0
je corr_rl_2
xchg di,si
corr_rl_2: pop cx ;CL - исходный символ
;Сейчас DI указывает на строку с "неправильными" символами, а SI - на строку
;с "правильными".
xor bx,bx ;Обнулили счётчик.
corr_rl_3: mov al,[bx+di]
call corr_rl_a
cmp cl,al ;Исходный символ совпал с "неправильным"?
jnz corr_rl_4
mov al,[bx+si] ;Если совпал, заменяем его на "правильный".
jmp corr_rl_a ;= CALL/RET
corr_rl_4: inc bx ;Если не совпал, надо проверить на совпадение
cmp bx,len_chars ;со следующим "неправильным" символом.
jnz corr_rl_3
mov al,0 ;Если не совпал ни с одним, возвращаем 0.
addr_ret: ret
corr_rl endp
;----------------------------------------------------------------------------
;Процедура corr_caps.
;
;Вход: AL - код символа.
;Выход: если символ не является буквой, то AH=2, AL не изменяется;
; если символ - русская буква, то AH=0, регистр буквы изменяется;
; если символ - латинская буква, то AH=1, регистр буквы изменяется.
data_corr db 1,97,122,-20h ;a-z
db 1,65,90,20h ;A-Z
db 0,160,175,-20h ;а-п
db 0,224,239,-50h ;р-я
db 0,128,143,20h ;А-П
db 0,144,159,50h ;Р-Я
db 0,240,240,1 ;Ё
db 0,241,241,-1 ;ё
db 2,0 ;Второе число, равное 0 - признак конца.
corr_caps proc near
push bx
mov bx,offset data_corr-4
corr_c_1: add bx,4
mov ah,[bx] ;AH = 0, 1 или 2.
cmp byte ptr [bx+1],0 ;Конец таблицы?
je corr_c_2
cmp al,[bx+1] ;Проверка левой границы диапазона.
jb corr_c_1
cmp al,[bx+2] ;Проверка правой границы диапазона.
ja corr_c_1
add al,[bx+3] ;Изменяем регистр буквы на противоположный.
corr_c_2: pop bx
ret
corr_caps endp
;----------------------------------------------------------------------------
;Инициализация:
init: mov ah,9 ;Печать
mov dx,offset info ;сведений
int 21h ;о программе.
mov ax,3516h ;Получаем и запоминаем
int 21h ;адрес старого
mov word ptr old_16h,bx ;обработчика INT 16h.
mov word ptr old_16h+2,es
mov dx,offset new_16h ;Устанавливаем
mov ax,2516h ;адрес нового
int 21h ;обработчика INT 16h.
mov dx,offset init ;Завершить и остаться
int 27h ;резидентом.
info db 13,10
db 'Text corrector by Ivan Roshin, Moscow, 29 Apr 2002.'
db 13,10
db 'Use F11 to correct TEXT -> text, text -> TEXT.'
db 13,10
db 'Use F12 to correct RUS/LAT.'
db 13,10
db 'Welcome to http://www.ivr.da.ru!'
db 13,10,13,10,'$'
codesg ends
end begin
Скачать программу
(1 КБ ZIP)
Скачать листинг программы в текстовом виде
(4 КБ ZIP)
Резидентная часть программы занимает в памяти меньше килобайта (912 байтов, если быть точным).
Если в используемом вами русификаторе другая раскладка клавиатуры (обычно различие в том, какие клавиши используются для ввода знаков препинания в русском режиме), то следует соответствующим образом изменить строки rus_chars и lat_chars, определяющие взаимное соответствие символов, вводимых в русском и латинском режимах.
Если BIOS вашего компьютера не поддерживает
Как уже упоминалось выше, для исправления текста, набранного при
неправильном состоянии Caps Lock, я выбрал клавишу F11, а для исправления
текста, набранного при неправильном режиме Рус/Lat, клавишу F12.
Вы можете выбрать другие «горячие клавиши», изменив значения
констант KEY_1 и KEY_2. Старший байт константы содержит
Полный список пар
codesg segment
assume cs:codesg
assume ds:codesg
org 100h
main proc near
mov ah,10h ;Или mov ah,0 для старого BIOS.
int 16h ;Ждём нажатия клавиши.
cmp ax,011bh ;Если нажата Esc - выходим.
je exit
mov bx,offset string
push bx
mov cl,4 ;Подготавливаем
mov ch,ah ;выводимую строку
shr ch,cl ;в буфере.
call one_digit
mov ch,ah
call one_digit
mov ch,al
shr ch,cl
call one_digit
mov ch,al
call one_digit
pop dx ;Печать строки.
mov ah,9
int 21h
jmp main
exit: ret
main endp
one_digit proc near
push ax
and ch,0fh
add ch,'0'
cmp ch,'9'
jna m1
add ch,'a'-'0'-10
m1: mov [bx],ch
inc bx
pop ax
ret
one_digit endp
string db '0000',13,10,'$'
codesg ends
end main
Скачать программу
(1 КБ ZIP)
Скачать листинг программы в текстовом виде
(1 КБ ZIP)
Это возможности резидента, которые изначально при его разработке не задумывались, а получились «сами собой».
Если текущий режим русский, а надо ввести одну латинскую букву (или наоборот, текущий режим латинский, а надо ввести одну русскую букву), то может оказаться проще ввести букву, не переключая режим, а затем исправить её нажатием соответствующей «горячей клавиши».
Точно так же можно поступить, и когда текущий режим русский, а надо ввести один из символов <, >, [, ], {, }, которые вводятся только в латинском режиме, или когда надо ввести один из символов, вместо которых в русском режиме вводятся знаки препинания (для русификатора KeyRus с раскладкой клавиатуры «по умолчанию» это символы @, #, $, %, ^, &, *). (В последнем случае для правильного исправления символа последняя буква в части строки слева от этого символа должна быть русской.)
Большое неудобство при наборе текста доставляет то, что знаки препинания
вводятся
«Горячую клавишу» для исправления текста, набранного при
неправильном состоянии Caps Lock, можно использовать не только для исправления
ошибок, но и просто, чтобы заменить в
Можно, разумеется, изменять таким образом не строку, а лишь одну букву. При редактировании текста довольно часто приходится заменять прописную букву на строчную и наоборот например, при добавлении слова в начало предложения и при удалении первого слова предложения; при разбиении одного предложения на два и при объединении двух предложений в одно.
|
Другие мои статьи о резидентных программах для DOS:
|