1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
| ;
data segment para public 'data' ;
max_cnt EQU 10 ;Максимальное количество символов на число
a db max_cnt dup (0) ;массив для чисел
cnt db 0 ; Число уже введённых символов на экран
;num db 0
data ends ;
;
;
stk segment stack ;
db 256 dup ('?') ;
stk ends ;
;
;
code segment para public 'code' ;
assume cs:code,ds:data,ss:stk ;
start:
lea bx, a ; Адрес массива в памяти сохранить в bx; потом пригодится
mov ah, 0h ;Нулевая функция
mov al, 3h ;Номер видеорежима (текстовый, 25*80)
int 10h ; Нулевая функция 10-го прерывания, которая установит видережим
mov ah, 05h
mov al, 0 ; Нулевая видеостраница
int 10h ; Установить видеостраницу
mov ah, 3h ; Ложим в ah номер функции, который хочем выполнить
int 10h ; Вызываем третью (т.к. ah=3h) функцию 10-го прерывания (т.к. int 10h), которая в регистр dh ложит номер строки, а в dl номер колонки (столбца)
;на экране, где находится в данный момент курсор
mov cnt, 0 ;На всякий случай
again: ;метка, на которую вовзращаемся, чтобы запрашивать следующую клавишу
call Wait_key ; Вызываем НАШУ функцию Wait_key, которая ожидает нажатие клавиши пользователем,
;а затем помещает в ah ANSI-код данного символа, а в al скан-код нажатой клавиши
s_esc: ;метка для проверки на то, что нажата escape
cmp ah, 01h ; сравниваем ah с ANSI-кодом escape
jnz s_Bsp ;(Jump if Not Zero) Если они не равны (это не escape), прыгаем на метку s_Bsp, которая проверяет, не backspace ли это
jmp Quit_prog ; Если мы оказались тут, то это значит, что мы не перепрыгнули на предыдущей строке и это escape,
;а значит прыгаем на Quit_prog (jmp - JuMP - безусловный переход (прыжок)), которая производит выход из программы
s_Bsp:
cmp ah, 0EAh ;сравниваем с ANSI-кодом Backspace
jnz s_Del ; Если нет - прыгаем на проверку Delete (подробно смотри с escape)
jmp h_Bsp ;Если это оказался backspace,
;прыгаем на h_Bsp (Handler of Backspace - обработчик backspace), который занимается обработкой нажатия bsp
s_Del:
cmp ah, 053h ; Аналогично предыдыщим, только с Delete
jnz s_Ent
jmp h_Del
s_Ent:
cmp ah, 01Ch ;Enter
jnz s_left
jmp h_Ent
s_left:
cmp ah, 04Bh ;Клавиша "Влево"
jnz s_right
jmp h_left
s_right:
cmp ah, 04Dh ;"Вправо"
jnz s_dig1
jmp h_right
s_dig1:
cmp al, '0' ; Сравнить al с кодом символа нуля (30h)
jae s_dig2 ; (Jump if Above or Equals - прыгнуть, если больше или равно)
; Если ANSI-код нажатой клавиши больше '0', то переходим на проверку, а меньше или ровна ли она '9'
jmp again ;Если ANSI-код меньше '0'(39h) (подобие ветки else), то прыгаем на начало, заново запрашиваем клавишу и т.д.
s_dig2:
cmp al, '9' ; Сравнить al с кодом символа девятки (39h)
jna h_dig; (Jump if Not Above - прыгнуть, если не больше (меньше или равно))
; Нажатая клавиша между '0' и '9' включительно, прыгаем на метку, которая обработает нажатие цифр
jmp again ; В начало
h_Bsp: ;Обработка нажатия Backspace
jmp again ;По-идее должен стираться символ слева от курсора, но не сделано еще, поэтому занового запрашиваем следующую клавишу
h_Del: ; Обработчик Delete
jmp again ;Аналогично с Delete
h_Ent: ;Enter
jmp Quit_prog ; по Eneter пока выходимм из программы
h_left: ;Нажата "Влево"
;mov ah, 3h
;int 10h
cmp dl, 0 ;Мы помним, что в начале вызывали третью функцию 10-го прерывания,
;которая положила в dh номер строки, а в dl номер строки, на которой сейчас находится курсор
;сравниваем номер столбца (номер символа) в dl с 0 (первый символ, первый столбец). Если он первый, то влево двигаться некуда
jnz h_left_cont ;Если он не 0, то продолжаем обработку в h_left_cont
jmp again ;Иначе игнорируем клавишу и спрашиваем следующую
h_left_cont: ; номер символа не 0
dec dl ; уменьшить номер столбца на 1 (DECrement - уменьшение на 1)
call SetCursPos
jmp again ; Заново запрашиваем клавиши
h_right: ;"Вправо"
mov al, cnt ;Количество введённых пользователем символов
cmp dl, al
jnz h_right_cont ; не равно текущему номеру символа
jmp again
h_right_cont:
inc dl ;переместить
call SetCursPos ;курсор вправо
jmp again
h_dig: ;Была нажата цифра
mov ah, max_cnt
dec ah
cmp dl, ah
jnz h_ins ;Это не последний символ (место для вставки еще есть)
jmp again
h_ins:
mov ah, cnt
cmp dl, ah
jz h_ins_c ; Это последний введённый символ
call Off_Rt ; Если курсор где-то в середине, то смещаем всё направо, чтобы вставить в это место
h_ins_c:
call Repl_dig ; Вставляем символ в текущую позицию
mov ah, max_cnt
dec ah
dec ah
cmp dl, ah
jnz h_ins_c2 ;Если это не предпоследний символ
jmp again
h_ins_c2:
inc dl ;Смещаем курсор вправо
mov ah, cnt
inc ah ; Увеличиваем количество введённых символов
mov cnt, ah
call SetCursPos
jmp again
Quit_prog: ; Метка для выхода из программы
mov cnt, 0 ;Просто очищаем переменную (иначе при перезапуске иногда сохраняет значение)
int 20h ;Выходим из программы
; 20-ое прерывание не имеет функций, оно просто завершает программу.
; === Подпрограммы ===
; --- Wait_key --- Получение клавиши от пользователя
Wait_key proc
mov ah,10h ;Функция 10h прерывания 16h - ожидание нажатия клавиши
int 16h
ret
Wait_key endp
; --- Repl_dig --- Замена символа на символ в al в текущей позиции курсора
Repl_dig proc
; нам нужно вывести эту цифру на экран в текущую позицию курсора.
; для вывода на экран мы вызовем 9-ую функцию 10-го прерывания, но ей нужны кое-какие параметры, которые мы полижим в следующих строках
push ax
push cx
push bx
mov ah, 9 ; указываем номер функции, которая будет вызываться - 9-ая
mov cx, 1 ; количество раз, сколько выведется символ на экран, ложим в cx (1)
mov bh, 0 ;Номер видеостраницы, на которую это выводится (по умолчанию - нулевая)
mov bl, 7 ;(=00000111b). Цвет фона - черный, цвет символа - белый
; всё это будет выведено в текущую позицию курсора
int 10h ; Выполнить 9-ую фунцию 10-го прерывания с переданными ей параметрами
pop bx
pop cx
pop ax
ret
Repl_dig endp
; --- SetCursPos --- Установка позиции курсора в dh*dl (строка*столбец)
SetCursPos proc
push ax
mov ah, 2h ;Смотри, как вызываются прерывания в начале. Вызываем вторую функцию
int 10h ; 10-го прерывания (вызов происходит непосредственно на этой строке), которая установить курсор в позицию, dh*dl,
; где dh - номер строки (заполнен у нас в самом начале с помощью третьей функции), а dl - номер строки (изменен после)
; В итоге курсор просто смещается на 1
pop ax
ret
SetCursPos endp
; --- Off_Rt --- Смещение всех элементов, начиная с dl (текущего номера, текущего столбца), вправо
Off_Rt proc
push ax
push cx
push di
push es
push dx
mov ax, 0B800h
mov es, ax ; Сегмент видеобуфера
mov cx, max_cnt ;От максимального номера символа
dec cx ;dl начинается с 0, а cnt и max_cnt с 1... поправить бы...
mov di, cx
mov dh, 0
sub cx, dx
;add cx, cx
add di, di ;По 2 байта на символ на экране, поэтому удваиваем
next_off:
mov ax, es:[di-2] ; Аналогично mas[i] = mas[i-1], только на экране
mov es:[di],ax
dec di
dec di
loop next_off
pop dx
pop es
pop di
pop cx
pop ax
ret
Off_Rt endp
code ends ;
end start ; |