How to create a text editor in assembly language?
So far I have a program created to read arrow keys and move the cursor around the screen. The user must enter 0 first to start and will be able to move around during getch ()! = 27 (ESC). However, the cursor doesn't move at all.
model tiny
.code
org 100h
program:
mov cx, 10
mov ah, 7
int 21h
cmp al, 0 ; start
je clearS ; clear screen
start:
mov ah, 7 ; AL = getch()
int 21h
cmp al, 27 ; ESC
je fin
cmp al, 72
je moveUp
cmp al, 75
je moveLeft
cmp al, 77
je moveRight
cmp al, 80
je moveDown
moveRight:
mov dl, posY
inc dl ; posY ++
mov posY, dl
jmp prntCrs
jmp start
moveLeft:
mov dh, posX
mov dl, posY
dec dl ; posY --
mov posY, dh
jmp prntCrs
jmp start
moveUp:
mov dl, posY
mov dh, posX
dec dh ; posX --
mov posX, dh
jmp prntCrs ; print cursor
jmp start
moveDown:
mov dl, posY
mov dh, posX
inc dh ; posX ++
mov posX, dh
jmp prntCrs
jmp start
prntCrs: ; print cursor
mov ah, 2h
int 10h
clearS: ; clear screen
mov ah, 7
mov al, 25
mov ch, 0
mov cl, 0
mov dh, 24
mov dl, 79
int 10h
mov ah, 2
mov bh, 0
mov dh, 0
mov dl, 0
int 10h
jmp start
fin:int 20h
posX db 1 dup(0) ; dh = posX -> controls row
posY db 1 dup(0) ; dl = posY -> controls column
end program
----------------------------------------------- --- ----------------
Let's say I have this:
moveDown:
mov dl, posX
mov dh, posY
cmp dh, 9 ; limit
je stayLine
inc dh ; posY ++
mov posY, dh
add curr_line, 36 ;increment by line/string size
jmp prntCrs
goBackLine:
mov dl, posX
mov dh, posY
cmp dh, 1 ; limit
je stayLine
mov dl, 37
dec dh
mov posX, dl
mov posY, dh
sub curr_line, 36 ; go to start of last line
add curr_char, 35 ; to go to last char of last line
jmp prntCrs
nextLine:
mov dl, posX
mov dh, posY
mov dl, 1
inc dh
mov posX, dl
mov posY, dh
add curr_line, 36
mov curr_char, 0 ; or move it to whatever dl is?
jmp prntCrs
posX db 1 dup(1) ; dl = posX -> controls column
posY db 1 dup(1) ; dh = posY -> controls row
xlimit dw 38 ; number of columns (w/ border)
ylimit dw 10 ; number of rows (w/ border)
matrix db 36*8 dup(42)
curr_line dw ? ; pointer to current line
curr_char dw ? ; pointer to current char
How can I save user input?
mov si, offset ???
add si, curr_char
mov byte ptr [si], al
mov cl, dl ; to not lose value of posX
mov dl, al ; to be able to print
mov ah, 2h ; character output
int 21h ; display character in dl
mov dl, cl
inc dl ; to move right
mov posX, dl ; update posX
cmp posX, 38
je nextline
inc si
jmp writing
source to share
There are important errors in your code:
- DL for X and DH for Y. You are not using them correctly in your moveLeft, moveRight, moveUp and moveDown labels.
- Int 16h is better for special keys like arrows.
- You cleared the screen after each key, so the cursor returned to the top left corner every time.
Here is your code improved, tested with EMU8086 (arrows indicate changes):
.model tiny
.code
org 100h
program:
mov cx, 10
mov ah, 7
int 21h
cmp al, 0 ; start
je clearS ; clear screen
start:
mov ah, 0 ;<==================================
int 16h ;<==================================
cmp al, 27 ; ESC
je fin
cmp ax, 4800h ;<==================================
je moveUp
cmp ax, 4B00h ;<==================================
je moveLeft
cmp ax, 4D00H ;<==================================
je moveRight
cmp ax, 5000h ;<==================================
je moveDown
jmp start ;<==================================
moveRight:
mov dl, posX
mov dh, posY ;<==================================
inc dl ; posX ++
mov posX, dl
jmp prntCrs
jmp start
moveLeft:
mov dl, posX ;<==================================
mov dh, posY ;<==================================
dec dl ; posX -- ;<==================================
mov posX, dl ;<==================================
jmp prntCrs
jmp start
moveUp:
mov dl, posX ;<==================================
mov dh, posY ;<==================================
dec dh ; posY --
mov posY, dh ;<==================================
jmp prntCrs ; print cursor
jmp start
moveDown:
mov dl, posX ;<==================================
mov dh, posY ;<==================================
inc dh ; posY ++ ;<==================================
mov posY, dh ;<==================================
jmp prntCrs
jmp start
prntCrs: ; print cursor
mov ah, 2h
int 10h
clearS: ; clear screen
;mov ah, 7 ;<==================================
;mov al, 25 ;<==================================
;mov ch, 0 ;<==================================
;mov cl, 0 ;<==================================
;mov dh, 24 ;<==================================
;mov dl, 79 ;<==================================
;int 10h ;<==================================
;mov ah, 2 ;<==================================
;mov bh, 0 ;<==================================
;mov dh, 0 ;<==================================
;mov dl, 0 ;<==================================
;int 10h ;<==================================
jmp start
fin:int 20h
posX db 1 dup(0) ; dh = posX -> controls row
posY db 1 dup(0) ; dl = posY -> controls column
end program
Edit: it now displays symbols, adds symbols to the matrix, and updates curr_line
and curr_char
. I used colors for fun. It is still necessary that the cursor does not go out of bounds, for example, does not exceed columns 0 and 80. Next is the new code:
.model tiny
.code
org 100h
program:
mov curr_line, offset matrix
mov curr_char, 0
start:
;CAPTURE KEY.
mov ah, 0
int 16h
;EVALUATE KEY.
cmp al, 27 ; ESC
je fin
cmp ax, 4800h ; UP.
je moveUp
cmp ax, 4B00h ; LEFT.
je moveLeft
cmp ax, 4D00H ; RIGHT.
je moveRight
cmp ax, 5000h ; DOWN.
je moveDown
cmp al, 32
jae any_char
jmp start
;DISPLAY LETTER, DIGIT OR ANY OTHER ACCEPTABLE CHAR.
any_char:
mov ah, 9
mov bh, 0
mov bl, color
mov cx, 1 ; how many times display char.
int 10h ; display char in al.
;UPDATE CHAR IN MATRIX.
mov si, curr_line ; si points to the beginning of the line.
add si, curr_char ; si points to the char in the line.
mov [ si ], al ; the char is in the matrix.
;!!! EXTREMELY IMPORTANT : PREVIOUS BLOCK DISPLAYS ONE
;CHAR, AND NEXT BLOCK MOVES CURSOR TO THE RIGHT. THAT'S
;THE NORMAL BEHAVIOR FOR ALL EDITORS. DO NOT MOVE THESE
;TWO BLOCKS, THEY MUST BE THIS WAY. IF IT NECESSARY
;TO MOVE THEM, ADD A JUMP FROM ONE BLOCK TO THE OTHER.
;RIGHT.
moveRight:
inc curr_char ; update current char.
mov dl, posX
mov dh, posY
inc dl ; posX ++
mov posX, dl
jmp prntCrs
;LEFT.
moveLeft:
dec curr_char ; update current char.
mov dl, posX
mov dh, posY
dec dl ; posX --
mov posX, dl
jmp prntCrs
;UP.
moveUp:
sub curr_line, 80 ; update current line.
mov dl, posX
mov dh, posY
dec dh ; posY --
mov posY, dh
jmp prntCrs ; print cursor
;DOWN.
moveDown:
add curr_line, 80 ; update current line.
mov dl, posX
mov dh, posY
inc dh ; posY ++
mov posY, dh
jmp prntCrs
prntCrs: ; print cursor
mov ah, 2h
int 10h
jmp start
fin:
int 20h
posX db 1 dup(0) ; dh = posX -> controls row
posY db 1 dup(0) ; dl = posY -> controls column
matrix db 80*25 dup(' ') ; 25 lines of 80 chars each.
curr_line dw ?
curr_char dw ?
color db 2*16+15
;FOR COLORS USE NEXT TABLE:
;http://stackoverflow.com/questions/29460318/how-to-print-colored-string-in-assembly-language/29478158#29478158
end program
The matrix will be needed if you want to save a file or load from a file. Also, the matrix will be useful in the case of an editor with more rows than the screen size, for example, if the matrix has 100 rows (db 80 * 100 matrix), when the user presses a key, the first lines of the editor will disappear, but when the user presses the key , the first rows can be re-mapped from the matrix.
source to share
Some points of your logic flow. Four functions moveRight:
, etc., adjust the cursor position, go to prntCrs:
, which makes the BIOS call to set the cursor position, then go to a function clearS:
before going tostart:
These functions must be call
ed and have a command ret
at the end.
moveDown:
mov dl, posY
mov dh, posX
inc dh ; posX ++
mov posX, dh
call prntCrs ; call not jmp
jmp start
prntCrs: ; print cursor
mov ah, 2h
int 10h
ret ; added ret
Also you don't always process row and column in the right direction, in dh
and out dl
, and the cursor position variables are incorrectly defined
posX db 1 dup(0) ; dh = posX -> controls row
posY db 1 dup(0) ; dl = posY -> controls column
it can be one byte (fixed usage too)
posX db 0 ; dl = posX <--- swapped register names
posY db 0 ; dh = posY
Finally, you increase and decrease the position of the cursor, but you do not check its bounds. Only decrease if> 0, only increase PosX if <79, PosY if <24.
source to share