This console application uses the Rich Edit Form Input procedure for which you can find the source here.
It presents the user with a dialog that has 5 input boxes and 2 buttons.
The dialog is drawn differently depending on screen width. You use TAB or SHIFTTAB to switch between fields. ENTER and ESCAPE have their usual meaning.
The program supports both input redirection and output redirection.
; A dialog using Rich Edit Form Input. Assembled with FASM 1.54 ORG 256 cld ; Fix far pointers mov ax, cs mov [InBufs+2], ax mov [InBufs+40+2], ax mov [InBufs+160+2], ax ; Program supports 'current' display page and ; adapts itself to the number of columns on screen mov ah, 0Fh ;BIOS.GetVideoMode int 10h ; -> AL=Mode AH=Cols BH=Page mov bl, ah mov [VCols], bx ;VCols and VPage ; Program supports i/o redirection xor bx, bx ;STDIN mov ax, 4400h ;DOS.GetDeviceInformation int 21h ; -> AX DX CF jc .a ;Go default to keyboard test dl, dl jns .b ;Block device, not keyboard shr dl, 1 .a: adc bl, bl ; -> BL=1 if keyboard .b: mov [IsKeyb], bl ;[0,1] ; Draw a new dialog New: call Form mov di, 200 ;Current inbox DI={160,120,80,40,0} .a: sub di, 40 mov byte [InBufs+di+7], 0 ;No preset string jnz .a ; Indicate which field has focus Cont: mov al, ":" call Focus ; Call REFI for input boxes cmp di, 4 ;5 input boxes and 2 buttons ja .a mov cx, di xor ax, ax ;No special priority key call Input ; -> AX jmp .b ; Just wait for a key for buttons .a: call Key ; -> AX ; Hide indication of focus .b: push ax mov al, " " call Focus pop ax ; Move around in dialog cmp ax, 0F00h ;<TAB> ? jne .c inc di ;Go to next field cmp di, 7 jb Cont xor di, di jmp Cont .c: cmp ax, 0F01h ;<SHIFT-TAB> ? jne .d dec di ;Go to previous field jns Cont mov di, 6 jmp Cont .d: cmp ax, 0100h ;<ESCAPE> ? je Exit cmp ax, 1C00h ;<RETURN> or <ENTER> ? jne Cont ;Ignore invalid key cmp di, 6 ;"Cancel" ? je Exit ; "OK" on an empty dialog equals "Cancel" mov si, InBufs+7 .e: or al, [si] ;Length of current ASCIIZ add si, 40 cmp si, InBufs+7+40*5 ;5 input boxes jb .e test al, al jz Exit ;End program when all boxes empty ; Re-visit all input boxes so that REFI can update their histories mov cx, 4 ;Indexes of 5 input boxes [0,4] .f: cmp cx, di ;DI is field with last focus, je .g ; then history is already updated mov ax, 1C00h ;Force update history call Input ;Returns quickly! -> AX=1C00h .g: dec cx jns .f ; Print contents as Tab Separated Values mov dx, [BaseXY] call SetCursor ; -> BH (AH) mov di, InBufs+8 ;Storage space holds an ASCIIZ jmp .i .h: mov si, TAB ;Summarize in .TSV format call WriteString .i: mov si, di call WriteString add di, 40 cmp di, InBufs+8+40*5 ;5 input boxes jb .h mov si, CRLF call WriteString ; Present a new dialog jmp New ; Remove the last (unused) dialog Exit: movzx cx, byte [VCols] ;Replication count (full row) mov di, 7 ;Lines to wipe cmp cl, 80 jnb .a mov di, 11 ;The narrow dialog is higher .a: mov dx, [BaseXY] dec dh .b: dec dh ;Move 1 row up call SetCursor ; -> BH (AH) mov ah, 08h ;BIOS.GetCharacterAndAttribute int 10h ; -> AL=Character AH=Attribute mov bl, ah mov ax, 0920h ;BIOS.WriteCharacterAndAttribute int 10h dec di jnz .b ; Program supports i/o redirection mov bx, 1 ;STDOUT mov ax, 4400h ;DOS.GetDeviceInformation int 21h ; -> AX DX CF jc .d ;Go default to screen test dl, dl jns .c ;Block device, output is redirected test dl, 00000010b jnz .d .c: mov si, CRLF ;Facilitates using redirected call WriteString ; output as next redirected input ; Exit the program .d: mov ax, 4C00h ;DOS.TerminateWithExitcode int 21h ; -------------------------------------- ; IN (ax,cx) OUT (ax) MOD () Input: push bx dx push ax ;AX is priority key imul bx, cx, 4 ;CX is index of input box [0,4] add bx, [Tags] mov dx, [BaseXY] add dx, [bx] ;dCol and dRow add dx, 00FEh ;Col-2 and Row+1 call SetCursor ; -> BH (AH) imul bx, cx, 40 lea dx, [InBufs+bx] ;DS:DX One of the 5 input buffers mov bx, ClipB ;ES:BX Clipboard pop ax ;AX Priority key call FormInput ; -> AX pop dx bx ret ; -------------------------------------- ; IN () OUT (ax) MOD () ; Most of the complexity herein is due to getting the key from DOS, ; but for now I want input redirection capability. Key: mov ah, 07h ;DOS.STDINInput int 21h ; -> AL test al, al ;Extended ASCII requires 2 calls jz .b push si ;(1) mov si, .List ;Translate ASCII into scancode mov [.Fail], al ;Sentinel .a: lodsw cmp al, [.Fail] jne .a pop si ;(1) test ah, ah jnz .c ;Got scancode we can use cmp al, 10 ;Remains an ASCII je Key ;Silently ignoring linefeed ret ; in favor of input redirection .b: mov ah, 07h ;DOS.STDINInput int 21h ; -> AL shl ax, 8 jz Key ;Don't allow embedded zeroes .c: xor al, al cmp [IsKeyb], al ;[0,1] je .d ;Input is redirected push ax ;(2) mov ah, 02h ;BIOS.GetKeyboardFlags int 16h ; -> AL test al, 00000011b ;Either SHIFT key is depressed? pop ax ;(2) setnz al .d: ret ALIGN 2 .List: dw 1C0Dh ;<RETURN> or <ENTER> dw 011Bh ;<ESCAPE> dw 0F09h ;<TAB> dw 0E08h ;<BACKSPACE> .Fail: db ?, 0 ; -------------------------------------- ; IN (ds:si) OUT () MOD () WriteString: pusha mov bx, 1 ;STDOUT mov cx, bx jmp .b .a: lea dx, [si-1] mov ah, 40h ;DOS.WriteToDevice int 21h ; -> AX CF .b: lodsb test al, al jnz .a popa ret ; -------------------------------------- ; IN (dx) OUT (bh) MOD (ah) SetCursor: mov bh, [VPage] mov ah, 02h ;BIOS.SetCursor int 10h ret ; -------------------------------------- ; IN (al,di) OUT () MOD () Focus: pusha ;AL is character imul si, di, 4 ;DI is index current field [0,6] add si, [Tags] mov dx, [BaseXY] mov cx, 1 ;Replication count mov bl, 0Eh ;YellowOnBlack call .a inc si inc si call .a popa ret .a: add dx, [si] ;dCol and dRow call SetCursor ; -> BH (AH) mov ah, 09h ;BIOS.WriteCharacterAndAttribute int 10h ret ; -------------------------------------- ; IN () OUT () MOD () Form: pusha mov si, FormA mov bx, [VCols] ;VCols and VPage cmp bl, 80 jnb .a mov si, FormB ;Form for the 40 columns screen .a: mov cx, 1 ;Replication count mov bl, 02h ;GreenOnBlack jmp .d .b: cmp al, 32 jb .c ;Non character cmp al, 255 je .c ;Indentation mov ah, 09h ;BIOS.WriteCharacterAndAttribute int 10h .c: mov ah, 0Eh ;BIOS.Teletype int 10h .d: lodsb test al, al jnz .b mov [Tags], si ;Points at field position info mov ah, 03h ;BIOS.GetCursor int 10h ; -> CX=Shape DL=Col DH=Row mov [BaseXY], dx ;Column and row of dialog base popa ret ; -------------------------------------- ALIGN 4 Hist1: times 256 db 0 Hist2: times 256 db 0 Hist5: times 256 db 0 ClipB: times 128 db 0 InBufs: dw Hist1 db ?, ?, 1, 30, 32, 0 times 32 db 0 dw Hist2 db ?, ?, 1, 20, 32, 0 times 32 db 0 dw 0 db 0, 0, 0, 17, 20, 0 times 32 db 0 dw 0 db 0, 0, 0, 11, 5, 0 times 32 db 0 dw Hist5 db ?, ?, 1, 20, 32, 0 times 32 db 0 FormA: db 13, 10 db 255, 'ÉÍÍ Rich Edit Form Input ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ»', 13, 10 db 255, 'º ÄÄ Title ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ÄÄ Author ÄÄÄÄÄÄÄÄÄÄ º', 13, 10 db 255, 'º º', 13, 10 db 255, 'º ÄÄ ISBN ÄÄÄÄÄÄÄÄÄ ÄÄ Pages ÄÄ ÄÄ Publisher ÄÄÄÄÄÄÄ º', 13, 10 db 255, 'º º', 13, 10 db 255, 'ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ OK ÍÍÍÍÍ Cancel Íͼ', 13, 10 db 10, 0 db +5, -6, +6, +0 db +37, -6, +7, +0 db +5, -4, +5, +0 db +24, -4, +6, +0 db +37, -4, +10, +0 db +37, -2, +3, +0 db +46, -2, +7, +0 FormB: db 13, 10 db 255, 'ÉÍÍ Rich Edit Form Input ÍÍÍÍÍÍÍÍÍ»', 13, 10 db 255, 'º ÄÄ Title ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ º', 13, 10 db 255, 'º º', 13, 10 db 255, 'º ÄÄ Author ÄÄÄÄÄÄÄÄÄÄ º', 13, 10 db 255, 'º º', 13, 10 db 255, 'º ÄÄ ISBN ÄÄÄÄÄÄÄÄÄ ÄÄ Pages ÄÄ º', 13, 10 db 255, 'º º', 13, 10 db 255, 'º ÄÄ Publisher ÄÄÄÄÄÄÄ º', 13, 10 db 255, 'º º', 13, 10 db 255, 'ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍ OK ÍÍÍÍÍ Cancel Íͼ', 13, 10 db 10, 0 db +5, -10, +6, +0 db +5, -8, +7, +0 db +5, -6, +5, +0 db +24, -6, +6, +0 db +5, -4, +10, +0 db +16, -2, +3, +0 db +25, -2, +7, +0 Tags: dw ? BaseXY: dw ? VCols: db ? VPage: db ? IsKeyb: db ? CRLF: db 13, 10, 0 TAB: db 9, 0 ; --------------------------------------
Screenshot 1, input in progress working on the 40×25 screen
Screenshot 2, input in progress showing some selected text
Screenshot 3, program ran with output redirection
Screenshot 4, program ran with input redirection
Screenshot 5, program ran with input redirection and output redirection