;
; Low level IBM/PC console keyboard/window interface routines
; for use with the DDS MICRO-C compiler.
;
; Copyright 1989-2000 Dave Dunfield
; All rights reserved.
;
; Permission granted for personal (non-commercial) use only.
;
?CBASE EQU $B800 ; Color video screen segment
?MBASE EQU $B000 ; Monochrome video screen segment
;
; Initialized variables & tables
;
W_BASE DW ?CBASE ; Mono=B000, Cga=B800
W_PAGE DB 0 ; Current video page
W_OPEN DW 0 ; Last opened window
; Special key table - General keys
?W_KEYS DW $4800 ; KUA (Up arrow)
DW $5000 ; KDA (Down arrow)
DW $4B00 ; KLA (Left arrow)
DW $4D00 ; KRA (Right arrow)
DW $4900 ; KPU (PgUp)
DW $5100 ; KPD (PgDn)
DW $4700 ; KHO (Home)
DW $4F00 ; KEN (End)
DW $4E2B ; KKP (Keypad '+')
DW $4A2D ; KKM (Keypad '-')
DW $5200 ; KIN (Ins)
DW $5300 ; KDL (Del)
DW $0E08 ; KBS (Backspace)
; Function keys
DW $3B00 ; K1 (F1)
DW $3C00 ; K2 (F2)
DW $3D00 ; K3 (F3)
DW $3E00 ; K4 (F4)
DW $3F00 ; K5 (F5)
DW $4000 ; K6 (F6)
DW $4100 ; K7 (F7)
DW $4200 ; K8 (F8)
DW $4300 ; K9 (F9)
DW $4400 ; K10 (F10)
; Special control keys
DW $8400 ; CPU (CTRL-PgUp)
DW $7600 ; CPD (CTRL-PgDn)
DW $7700 ; CHO (CTRL-Home)
DW $7500 ; CEN (CTRL-End)
DW 0
; BOX character table
?BOXTAB DB $C4,$B3,$DA,$BF,$C0,$D9
DB $CD,$BA,$C9,$BB,$C8,$BC
DB $CD,$B3,$D5,$B8,$D4,$BE
;
; Open a window: w_open(px, py, sx, sy, flags)
;
wopen PUSH BP ; Save callers stack frame
MOV BP,SP ; Address parameters
PUSH ES ; Save ES
; Set up video mode
MOV AH,#$0F ; Get video mode
INT $10 ; Call BIOS
MOV W_PAGE,BH ; Save video page
MOV BX,#?CBASE ; Assume COLOR address
CMP AL,#$07 ; Monochrome?
JNZ ?oinit1 ; No, assumption correct
MOV BX,#?MBASE ; Get MONOCHROME address
?oinit1 MOV W_BASE,BX ; Set video base address
MOV ES,BX ; Set up segment
; Allocate a window buffer
XOR AH,AH ; zero high
MOV AL,5[BP] ; Get video flags
AND AL,#$80 ; Do we save screen
JZ ?oinit2 ; No, do not
MOV AL,6[BP] ; Get 'Y' size
MOV BL,8[BP] ; Get 'X' size
MUL BL ; Calculate total size
SHL AX,1 ; X2 for attributes
?oinit2 ADD AX,#14 ; Include overhead
PUSH AX ; Pass as parameter
CALL malloc ; Allocate the buffer
MOV SI,AX ; Set up pointer
POP DX ; Clean up stack
AND SI,SI ; Did we get it?
JNZ ?oinit3 ; Yes, proceed
; Couldn't allocate, return with bad news
POP ES ; Restore extra set
POP BP ; Restore caller
RET
; Fill in window parameter block
?oinit3 MOV DL,12[BP] ; Get 'X' position
MOV DH,10[BP] ; Get 'Y' position
MOV 2[SI],DX ; Save it
MOV DL,8[BP] ; Get 'X' size
MOV DH,6[BP] ; Get 'Y' size
MOV 4[SI],DX ; Save size
MOV BX,4[BP] ; Get window flags
MOV [SI],BX ; Save attributes & flags
MOV DX,W_OPEN ; Get last opened window
MOV 8[SI],DX ; Save in buffer
XOR DX,DX ; Reset cursor position
MOV 6[SI],DX ; Save initial cursor position
; Save window contents if required
TEST BH,#$80 ; Do we save it?
JZ ?oinit5 ; No we don't
; ... Set up pointers to screen & save area
CALL ?xyaddr ; Get base address
MOV DX,4[SI] ; Get 'X' and 'Y' sizes
LEA DI,14[SI] ; Offset to data area
PUSH SI ; Save SI
MOV SI,BX ; Get base window address
; ... Save one line at a time
PUSH ES ; Stack ES
PUSH DS ; And DS
POP ES ; For swap
POP DS ; ES <> DS
?oinit4 PUSH SI ; Save source
MOV CL,DL ; Get 'X' size
XOR CH,CH ; Zero high size
REP
MOVSW ; Move one line
POP SI ; Restore it
ADD SI,#160 ; Offset to next line
DEC DH ; Reduce count
JNZ ?oinit4 ; And proceed
; ... Restore registers and continue
PUSH ES ; Stack ES
PUSH DS ; And DS
POP ES ; For swap
POP DS ; ES <> DS
POP SI ; Restore SI
XOR DX,DX ; Reset cursor position
MOV BH,5[BP] ; Get flags back
; Draw box if required
?oinit5 MOV BP,#?BOXTAB ; Point to BOX table
MOV CX,4[SI] ; Get size of box
SUB CH,#2 ; Adjust for bar
DEC CL ; Adjust for bar
AND BH,#$60 ; Draw BOX?
JZ ?oinit8 ; No we don't
; ... Select box type
CMP BH,#$40 ; Box1?
JZ ?oinit6 ; Use this one
ADD BP,#6 ; Offset to next
CMP BH,#$20 ; Box2?
JZ ?oinit6 ; Use this one
ADD BP,#6 ; Offset to next
?oinit6 PUSH CX ; Save size
CALL ?xyaddr ; Get address
; ... Draw the top (With corners)
MOV AH,[SI] ; Get attribute
MOV AL,2[BP] ; Top left corner
MOV ES:[BX],AX ; Write top corner
LEA DI,2[BX] ; Get value
XOR CH,CH ; Zero high
DEC CL ; Adjust for bar
MOV AL,0[BP] ; Horizontal line
REP
STOSW ; Draw the line
MOV AL,3[BP] ; Top right hand corner
MOV ES:[DI],AX ; Write it
POP CX ; Restore position
; ... Draw the box sides
?oinit7 INC DH ; Advance
MOV AL,1[BP] ; Box side
CALL ?xyaddr ; Get position
MOV ES:[BX],AX ; Write it
ADD DL,CL ; Offset
CALL ?xyaddr ; Get position
MOV ES:[BX],AX ; Write it
SUB DL,CL ; Backup
DEC CH ; Reduce count
JNZ ?oinit7 ; Do them all
; ... Draw the bottom (With corners)
INC DH ; Advance to bottom
CALL ?xyaddr ; get address
MOV AL,4[BP] ; Lower left corner
MOV ES:[BX],AX ; Write it
LEA DI,2[BX] ; Position to line
DEC CL ; Adjust for bar
MOV AL,0[BP] ; Horizontal line
REP
STOSW ; Write it out
MOV AL,5[BP] ; Lower right corner
MOV ES:[DI],AX ; Write it out
; ... Reduce size of active region
MOV AX,2[SI] ; Get position
INC AL ; Advance 'X'
INC AH ; Advance 'Y'
MOV 2[SI],AX ; Resave
MOV AX,4[SI] ; Get size
SUB AH,#2 ; Chop out bars
SUB AL,#2 ; Chop out bars
MOV 4[SI],AX ; And resave
XOR DX,DX ; Reset cursor position
; Clear screen if required
?oinit8 MOV BH,1[SI] ; Get flags back
TEST BH,#$10 ; Clear screen?
JZ ?oinit9 ; No, its ok
CALL ?cleos ; Clear one line
; Save cursor information
?oinit9 MOV BH,W_PAGE ; Get video page
MOV AH,#$03 ; Get cursor info
INT $10 ; Get cursor
MOV 10[SI],CX ; Save shape
MOV 12[SI],DX ; Save position
MOV AX,SI ; Get buffer address
MOV W_OPEN,AX ; Save this window pointer
POP ES ; Restore ES
POP BP ; Restore callers stack frame
RET
;
; Close current window: wclose()
;
wclose CALL ?xsetup ; Get last window
JMP <?wclos0 ; And proceed
;
; Close a window: w_close(window)
;
w_close CALL ?wsetup ; Get parameters
?wclos0 XOR DX,DX ; Zero position
MOV BH,1[SI] ; Get open flags
; If window was BOXed, adjust sizes first
TEST BH,#$60 ; Was it BOXed
JZ ?wclos1 ; No, don't adjust
MOV AX,2[SI] ; Get position
DEC AL ; Expand 'X'
DEC AH ; Expand 'Y'
MOV 2[SI],AX ; Resave
MOV AX,4[SI] ; Get size
ADD AH,#2 ; Adjust for bars
ADD AL,#2 ; Adjust for bars
MOV 4[SI],AX ; Resave
; Clear window if requested
?wclos1 TEST BH,#$08 ; Clear window?
JZ ?wclos2 ; No, try next
CALL ?cleos ; Clear the window
MOV BH,1[SI] ; Get flags back
; Restore previous contents if saved
?wclos2 TEST BH,#$80 ; Do we restore it
JZ ?wclos4 ; No, just clear
; ... Set up pointers to screen & save area
CALL ?xyaddr ; Calculate base address
MOV DX,4[SI] ; Get 'X' and 'Y' sizes
PUSH SI ; Save SI
LEA SI,14[SI] ; Offset to data area
MOV DI,BX ; Get base window address
; ... Restore one line at a time
?wclos3 PUSH DI ; Save source
MOV CL,DL ; Get 'X' size
XOR CH,CH ; Zero high size
REP
MOVSW ; Move one line
POP DI ; Restore it
ADD DI,#160 ; Offset to next line
DEC DH ; Reduce count
JNZ ?wclos3 ; And proceed
POP SI ; Restore SI
MOV BH,1[SI] ; Get flags back
; Restore the cursor
?wclos4 MOV CX,10[SI] ; Get cursor shape
MOV AH,#$01 ; Set shape
INT $10 ; Call BIOS
MOV DX,12[SI] ; Get position
MOV BH,W_PAGE ; Get display page
MOV AH,#$02 ; Set position
INT $10 ; Call BIOS
; If this is the active window, switch to previously open
CMP SI,W_OPEN ; Is this it?
JNZ ?wclos5 ; No, don't reset
MOV AX,8[SI] ; Get last free
MOV W_OPEN,AX ; Save it
; Release the buffer contents
?wclos5 PUSH SI ; Save address of buffer
CALL free ; Release it
POP SI ; Fixup stack
POP ES ; Restore ES
POP BP ; Restore BP
RET
;
; Write character into current window: wputc(int c)
;
wputc CALL ?xsetup ; Get last open window
MOV AX,4[BP] ; Get character
JMP <?tstbel ; And proceed
;
; Write a character to the video display: w_putc(int c, window)
;
w_putc CALL ?wsetup ; Set up video addresses
MOV AX,6[BP] ; Get character to display
; Handle BELL
?tstbel CMP AX,#'G'-$40 ; BELL code?
JNZ ?tstcr ; No, try next
MOV AX,#$0E07 ; Write BELL code
XOR BX,BX ; Write to page 0
INT $10 ; Call BIOS
JMP <?vedit ; and exit
; Handle CARRIAGE RETURN
?tstcr CMP AX,#'M'-$40 ; Is it carriage return
JNZ ?tstbs ; No, try next
XOR DL,DL ; Reset 'X' position
JMP <?vedit ; and proceed
; Handle BACKSPACE
?tstbs CMP AX,#'H'-$40 ; Is it backspace
JNZ ?tstnl ; No, try line-feed
AND DL,DL ; Already at first col?
JZ ?vedit ; Yes, don't backup
DEC DL ; Reduce 'X' position
JMP <?vedit ; And exit
; Handle NEWLINE
?tstnl CMP AX,#'J'-$40 ; Is it newline?
JNZ ?norchr ; Yes, advance line
MOV AL,1[SI] ; Get flags
TEST AL,#$04 ; Special case?
JNZ ?advy ; Yes, don't reset 'X'
XOR DL,DL ; Reset cursor
JMP <?advy ; And goto a new line
; Normal Character, output it
?norchr CALL ?xyaddr ; Calculate address
MOV AH,[SI] ; Get video attributes
MOV ES:[BX],AX ; Write to video display
; Advance 'X' position
?advx INC DL ; Advance 'X'
CMP DL,4[SI] ; Are we over?
JB ?vedit ; No, its ok
DEC DL ; Restore it
MOV AL,1[SI] ; Get flags
TEST AL,#$01 ; Line wrap enabled?
JZ ?vedit ; No, skip it
XOR DL,DL ; Reset 'X' position
; Advance 'Y' position
?advy INC DH ; Advance 'Y' position
CMP DH,5[SI] ; are we over?
JB ?vedit ; No, Its OK
DEC DH ; Reset it
MOV AL,1[SI] ; Get flags
TEST AL,#$02 ; Screen wrap enabled?
JZ ?vedit ; No, skip it
CALL ?scroll ; Scroll window
; Restore callers environment & exit
?vedit MOV 6[SI],DX ; Resave 'X' and 'Y'
POP ES ; Restore callers ES
POP BP ; Restore callers stack frame
RET
;
; CLEAR current window: wclwin()
;
wclwin CALL ?xsetup ; Get current window
JMP <?clscr1 ; And proceed
;
; CLEAR entire window: w_clwin(window)
;
w_clwin CALL ?wsetup ; Setup video
?clscr1 XOR DX,DX ; Reset to top of screen
MOV 6[SI],DX ; Reset cursor
CALL ?updt2 ; Position cursor
XOR DX,DX ; Reset again
JMP <?clscr2 ; And proceed
;
; CLEAR to end of current window: wcleow()
;
wcleow CALL ?xsetup ; Get current window
JMP <?clscr2 ; And proceed
;
; CLEAR to END OF WINDOW: w_cleow(window)
;
w_cleow CALL ?wsetup ; Setup video
?clscr2 CALL ?cleos ; Clear to end
POP ES ; Restore ES
POP BP ; Restore caller
RET
;
; CLEAR to end of line in current: wcleol()
;
wcleol CALL ?xsetup ; Get current window
JMP <?cleol1 ; And proceed
;
; CLEAR to END OF LINE: w_cleol(window)
;
w_cleol CALL ?wsetup ; Setup video
?cleol1 CALL ?xyaddr ; Get address
MOV DI,BX ; Set up address
MOV CL,4[SI] ; Get size of line
SUB CL,DL ; Calculate remaining
XOR CH,CH ; Zero high
MOV AH,[SI] ; Get attribute
MOV AL,#' ' ; Clear to space
REP
STOSW ; Clear a line
POP ES ; REstore ES
?cleol2 POP BP ; Restore caller
RET
;
; Position the cursor in current window: wgotoxy(int x, int y)
;
wgotoxy PUSH BP ; Save callers stack frame
MOV BP,SP ; Address parameters
MOV AL,6[BP] ; Get 'X' value
MOV AH,4[BP] ; Get 'Y' value
MOV SI,W_OPEN ; Get open window
JMP <?goto1 ; And proceed
;
; Position the cursor in window: w_gotoxy(int x, int y, window)
;
w_gotoxy PUSH BP ; Save callers stack frame
MOV BP,SP ; Address parameters
MOV AL,8[BP] ; Get 'X' value
MOV AH,6[BP] ; Get 'Y' value
MOV SI,4[BP] ; Get window buffer
?goto1 CMP AL,4[SI] ; In range?
JAE ?cleol2 ; No, error
CMP AH,5[SI] ; In range
JAE ?cleol2 ; No, error
MOV 6[SI],AX ; Save values
JMP <?updt1 ; And proceed
;
; Update the cursor in current window: wgotoxy()
;
wupdatexy MOV SI,W_OPEN ; Get open window
JMP <?updt2 ; And proceed
;
; Update the cursor position: w_updatexy(window)
;
w_updatexy PUSH BP ; Save callers stack frame
MOV BP,SP ; Address parameters
MOV SI,4[BP] ; Get caller
?updt1 POP BP ; Resture caller
?updt2 MOV DX,2[SI] ; Get starting address
ADD DX,6[SI] ; Offset into window
MOV BH,W_PAGE ; Get video page
MOV AH,#$02 ; Set cursor function
INT $10 ; Call DOS
RET
;
; Check for a key from the keyboard: c = w_tstc(window)
;
w_tstc MOV AH,#$01 ; Check for key
INT $16 ; Do we have key?
JNZ w_getc ; Yes, read it
?wtst1 XOR AX,AX ; No key today
RET
;
; Check for key with cursor in current window: c = wtstc()
;
wtstc MOV AH,#$01 ; Check for key
INT $16 ; Do we have key?
JZ ?wtst1 ; No, return zero
;
; Get in cursor in current window: c = wgetc()
;
wgetc MOV SI,W_OPEN ; Get active window
JMP <?getc1 ; And proceed
;
; Get a key from the keyboard with translations: c = w_getc(window)
;
w_getc MOV BX,SP ; Address parameters
MOV SI,2[BX] ; Get window
?getc1 CALL ?updt2 ; Update the cursor position
; Call BIOS to read key
XOR AH,AH ; Function code 0 - read key
INT $16 ; Call bios
; Lookup key for special entries
MOV CL,#$80 ; Beginning function code
MOV BX,#?W_KEYS ; Address of keys array
?lokkey MOV DX,[BX] ; Get key entry
CMP AX,DX ; Does it match?
JZ ?fndkey ; We found it
ADD BX,#2 ; Skip ahead
INC CL ; Advance key code
OR DH,DL ; End of table?
JNZ ?lokkey ; Keep looking
; Translate ENTER key to newline
CMP AX,#$1C0D ; ENTER key?
JNZ ?norkey ; Yes, we have it
MOV CL,#'J'-$40 ; Newline is LINE-FEED
; Translate special keys
?fndkey MOV AL,CL ; Set return value
?norkey CBW ; Set high bits
RET
;
; Set the CURSOR OFF: wcursor_off()
;
wcursor_off EQU *
MOV CX,#$2020 ; Value for cursor off
JMP <?setc2 ; And set it
;
; Set the CURSOR to a block: wcursor_block()
;
wcursor_block EQU *
MOV CX,#$0006 ; Color block cursor
MOV DX,#$000B ; Monochrome block cursor
JMP <?setc1 ; and proceed
;
; Set the CURSOR to a LINE: wcursor_line()
;
wcursor_line EQU *
MOV CX,#$0607 ; Color line cursor
MOV DX,#$0B0C ; Monochrome line cursor
?setc1 MOV AX,W_BASE ; Get video base
CMP AX,#?MBASE ; Monochrome?
JNZ ?setc2 ; No, do it
MOV CX,DX ; Copy for later
; Set cursor to value in CX
?setc2 MOV AH,#1 ; Set cursor type
INT $10 ; Call BIOS
RET
;
; Set up addressability to video display & stack registers
; Exit: ES = video base address
; SI = window buffer address
; DX = cursor address (X/Y)
;
?wsetup POP AX ; Get return address
PUSH BP ; Save callers stack frame
MOV BP,SP ; Address parameters
MOV SI,4[BP] ; Get window buffer
?wset1 PUSH ES ; Save callers Extra segment
PUSH AX ; Replace return address
MOV ES,W_BASE ; Point to video base
MOV DX,6[SI] ; Get 'X' and 'Y' position
RET
;
; Set up addressability to currently open window
;
?xsetup POP AX ; Get return address
PUSH BP ; Save callers stack frame
MOV BP,SP ; Address parameters
MOV SI,W_OPEN ; Get open window
JMP <?wset1 ; And proceed
;
; Scroll window forward one line
;
?scroll PUSH DS ; Save data segment
PUSH DX ; Save cursor
PUSH SI ; Save SI
; First, calculate base address of window
MOV AL,3[SI] ; Get 'Y' position
MOV BL,#160 ; Size of line
MUL BL ; Calculate 'Y' offset
MOV BL,2[SI] ; Get 'X' position
XOR BH,BH ; Zero high
SHL BX,1 ; * 2 for char & attribute bytes
ADD BX,AX ; BX = character position
MOV DI,BX ; Get base window address
; Scroll one line at a time
MOV DX,4[SI] ; Get 'X' and 'Y' sizes
DEC DH ; Don't copy to last
PUSH ES ; Stack ES
POP DS ; To place in DS
?scrol1 PUSH DI ; Save DI
MOV SI,DI ; Begin with same address
ADD SI,#160 ; Offset to next line
MOV CL,DL ; Get 'X' size
XOR CH,CH ; Zero high size
REP
MOVSW ; Move one line
POP DI ; Restore it
ADD DI,#160 ; Offset to next line
DEC DH ; Reduce count
JNZ ?scrol1 ; And proceed
; Clear bottom line of screen
MOV CL,DL ; Get 'X' size
POP SI ; Restore SI
POP DX ; Restore cursor
POP DS ; Restore data segment
MOV AH,[SI] ; Get attribute
MOV AL,#' ' ; And space
REP
STOSW ; Clear it
RET
;
; Clear from cursor(DX) to end of line
;
?cleos PUSH DX ; Save cursor
?cleos1 CALL ?xyaddr ; Get address
MOV DI,BX ; Set up address
MOV CL,4[SI] ; Get size of line
SUB CL,DL ; Calculate remaining
XOR CH,CH ; Zero high
MOV AH,[SI] ; Get attribute
MOV AL,#' ' ; Clear to space
REP
STOSW ; Clear a line
XOR DL,DL ; Zero 'X'
INC DH ; Advance 'Y'
CMP DH,5[SI] ; Are we finished
JB ?cleos1 ; Keep going
POP DX ; Restore cursor
RET
;
; Calculate screen address from X/Y position (in DX)
; On exit: BX = address
;
?xyaddr PUSH AX ; Save AX
MOV AL,DH ; Get 'Y' position
ADD AL,3[SI] ; Offset from start of screen
MOV BL,#160 ; Size of physical screen
MUL BL ; Calculate 'Y' offset
MOV BL,DL ; Get 'X' position
ADD BL,2[SI] ; Offset from start of screen
XOR BH,BH ; Zero high byte
SHL BX,1 ; * 2 for char & attribute bytes
ADD BX,AX ; BX = character position
POP AX ; Restore it
RET
$EX:malloc
$EX:free
„
file: /Techref/com/dunfield/ftp/embedpc/window_asm.htm, 56KB, , updated: 2000/5/5 09:47, local time: 2025/1/12 16:18,
|
| ©2025 These pages are served without commercial sponsorship. (No popup ads, etc...).Bandwidth abuse increases hosting cost forcing sponsorship or shutdown. This server aggressively defends against automated copying for any reason including offline viewing, duplication, etc... Please respect this requirement and DO NOT RIP THIS SITE. Questions? <A HREF="http://linistepper.com/techref/com/dunfield/ftp/embedpc/window_asm.htm"> Window.asm </A> |
Did you find what you needed?
|