This procedure is the natural continuation of the Example 4 that I wrote for How buffered input works, a Stack Overflow Q/A.
Features include:
- freely positioning the cursor.
- Left Moves cursor left.
- Right Moves cursor right.
- Home Moves cursor to the far left.
- End Moves cursor to the far right.
- CtrlLeft Move cursor to word on the left.
- CtrlRight Move cursor to word on the right.
- deleting text in numerous ways.
- Delete Removes the current character or the selected text.
- Backspace Removes the character to the left of the cursor or the selected text.
- CtrlHome Removes all characters to the left.
- CtrlEnd Removes all characters to the right.
- cutting, copying and pasting on a clipboard.
- ShiftLeft Extend selection to the left.
- ShiftRight Extend selection to the right.
- ShiftHome Extend selection to the far left.
- ShiftEnd Extend selection to the far right.
- ShiftCtrlLeft Extend selection to word on the left.
- ShiftCtrlRight Extend selection to word on the right.
- CtrlX Cut to clipboard.
- CtrlC Copy to clipboard.
- CtrlV Paste from clipboard.
- undo/redo of the most recently deleted text.
- CtrlZ Undo deleted text.
- easy character case flipping.
- CtrlO Other case of selection.
- using an optional input history.
- Up Fetch previous history item.
- Down Fetch next history item.
- ending input in several manners allowing for complex dialogs.
- Return Ends input altering the input buffer and the history.
- Escape Ends input altering the input buffer.
- Tab Ends input altering the input buffer.
- ShiftTab Ends input altering the input buffer.
If the 8th byte of the input buffer holds a non-zero value then the storage space is supposed to contain an old string (perhaps from a previous input). The old string is not required to be zero terminated and is immediately shown on screen.
While the input is in progress, the input is confined to staying within the
user specified input box on the current row. Longer texts will scroll
horizontally.
When the input is finally done, either the complete text or at least the right
hand part of it is shown in the input box, leaving the cursor beyond the last
character.
The first key to process and the last key processed are of particular interest
in building complex dialogs. They are passed through the AX
register.
This procedure does no ctrlC checking.
This procedure supports input redirection.
; Example 5, Rich Edit Form Input. (FASM 1.54)
; IN (ds:dx,es:bx,ax) OUT (ax)
FormInput:
; Silently quits on parameter errors, just like DOS
; Entry DS:DX Buffer of max 8+128 bytes
; 1st dword is far pointer to optional history
; (History is collection of ASCIIZ strings plus a final zero)
; 5th byte is size of history in 256 bytes pages
; 6th byte is size of input box
; 7th byte is size of storage space starting at 9th byte
; 8th byte is size of old ASCII(Z) string, 0 if none
; Storage space can contain old ASCII(Z) string
; ES:BX Clipboard (minimum 128 bytes)
; AX First key to process, 0 if none
; Exit DS:DX Nothing changed if any parameter was invalid
; 8th byte is size of new ASCIIZ string
; Storage space contains new ASCIIZ string
; New ASCIIZ string uniquely appended to history
; AX Last key processed
; Local [bp-1] PAGE Display page
; [bp-2] STORE Size of storage space
; [bp-3] ROW Row of input box
; [bp-4] COL Column of input box
; [bp-5] SHIFT Number of characters shifted out on leftside
; [bp-6] INBOX Size of input box
; [bp-7] LIX Number of characters in current input string
; [bp-8] CIX Position of cursor in current input string
; [bp-10] FLAGS Bit[0] is ON for normal keyboard input
; Bit[1] is ON if selection exists
; [bp-11] HISEL Position of high end of selection
; [bp-12] LOSEL Position of low end of selection
; [bp-14] HISLIX Number of strings in history
; [bp-16] HISCIX Index of current string in history
; [bp-18] OLDKEY Key previously processed
pusha
sub sp, 268 ;EditBuffer (128) and
mov bp, sp ; UndeleteBuffer (12+128)
pusha ;'sub sp, 16' Local variables
push 0 ;OLDKEY
mov si, dx
add si, 6
lodsw ; -> SI points at storage space
dec al ;AL is size of storage space
js .Quit ;Storage space not in [1,128]!
inc al
cmp ah, al ;AH is size of old string
jnb .Quit ;Old string too long!
xor di, di
push es ;(1)
les bx, [si-8] ;FarPtrOfHistory
mov ch, [si-4] ;SizeOfHistory (in pages)
xor cl, cl
jcxz .c ;It's fine to not use an history
.a: cmp byte [es:bx], 0
je .c ;Found final zero
inc di ;Counts strings
.b: inc bx
dec cx ;Room for terminating zero ?
jz .Quit_ ;No
cmp byte [es:bx], 0
jne .b
inc bx
dec cx ;Room left for final zero ?
jnz .a ;Yes, go check
.Quit_: pop es ;(1a)
.Quit: lea sp, [bp+268] ;Free Locals, EditBuffer,
popa ; and UndeleteBuffer
ret
.c: pop es ;(1b)
mov [bp-14], di ;HISLIX
mov [bp-16], di ;HISCIX
mov bl, al
mov ah, 0Fh ;BIOS.GetVideoMode
int 10h ; -> AL=Mode AH=Cols BH=Page
mov [bp-2], bx ;STORE and PAGE
mov bl, ah
mov ah, 03h ;BIOS.GetCursor
int 10h ; -> CX=Shape DL=Col DH=Row
mov [bp-4], dx ;COL and ROW
sub bl, dl ;Size of the widest inbox
movzx cx, byte [si-3] ;Requested size inbox
jcxz .d ;It's fine to not want to set the
cmp bl, cl ; size for the input box
jb .d
mov bl, cl
.d: mov [bp-6], bl ;INBOX
call .Wipe ; -> CIX=0 LIX=0 SHIFT=0
xor bx, bx ;STDIN
mov ax, 4400h ;DOS.GetDeviceInformation
int 21h ; -> AX DX CF
jc .e ;Go default to keyboard
test dl, dl
jns .f ;Block device, not keyboard
shr dl, 1
.e: adc bx, bx ; -> BX=1 if Keyboard
.f: mov [bp-10], bx ;FLAGS
mov cl, [si-1] ;CH=0 Size of old string
jmp .h
.g: lodsb ;Storage space gives old string
push cx si ;(2)
call .Asc ; -> CF Input old string
pop si cx ;(2)
jc .i
.h: dec cx
jns .g
.i: mov ax, [bp+268+14] ;pusha.AX is NEWKEY
test ax, ax
jnz .Main_
.Main: call .Show
mov ax, [bp+268+14] ;pusha.AX is NEWKEY
mov [bp-18], ax ;OLDKEY
call .Key ; -> AX (DL SI)
mov [bp+268+14], ax ;pusha.AX is NEWKEY
.Main_: mov bx, .Scan
test ah, ah
jz .l ;Not an extended ASCII
mov [cs:.Fail], ax ;Sentinel
.j: lea bx, [bx+4]
mov cx, [cs:bx-2]
mov dx, cx
and cx, 0FF01h ;Strip flag bits
cmp ax, cx
jne .j
mov [bp+268+14], dx ;pusha.AX is NEWKEY Update with
shl dl, 1 ;Flag bit 7 extra flags
jc .k ;Don't undo selection
call .NoSel
.k: shl dl, 1 ;Flag bit 6
jnc .l ;Current key is not a deletion key
call .Backup
.l: call word [cs:bx]
jmp .Main
; - - - - - - - - - - - - - - - - - - -
; Bit[0] is ON if <SHIFT> has to be pressed
; Bit[6] is ON if this is a deletion key
; Bit[7] is ON if selection should not be un-done automatically
.Scan: dw .Asc
dw 4B00h, .s4B ;<LEFT>
dw 4D00h, .s4D ;<RIGHT>
dw 4700h, .s47 ;<HOME>
dw 4F00h, .s4F ;<END>
dw 7740h, .s77 ;<CTRL-HOME>
dw 7540h, .s75 ;<CTRL-END>
dw 7300h, .s73 ;<CTRL-LEFT>
dw 7400h, .s74 ;<CTRL-RIGHT>
dw 4800h, .s48 ;<UP>
dw 5000h, .s50 ;<DOWN>
dw 1C00h, .s1C ;<RETURN> or <ENTER>
dw 0100h, .s1C ;<ESCAPE>
dw 0F00h, .s1C ;<TAB>
dw 0F01h, .s1C ;<SHIFT-TAB>
dw 1100h, .s11 ;<CTRL-Z> undo/redo
dw 53C0h, .s53 ;<DELETE>
dw 0EC0h, .s0E ;<BACKSPACE>
dw 4B81h, .s4Bs ;<SHIFT-LEFT>
dw 4D81h, .s4Ds ;<SHIFT-RIGHT>
dw 4781h, .s47s ;<SHIFT-HOME>
dw 4F81h, .s4Fs ;<SHIFT-END>
dw 7381h, .s73s ;<SHIFT-CTRL-LEFT>
dw 7481h, .s74s ;<SHIFT-CTRL-RIGHT>
dw 1880h, .s18 ;<CTRL-O> other case of selection
dw 2DC0h, .s2D ;<CTRL-X> cut to clipboard
dw 2E80h, .s2E ;<CTRL-C> copy to clipboard
dw 2F80h, .s2F ;<CTRL-V> paste from clipboard
.Fail: dw ?, .STC
; - - - - - - - - - - - - - - - - - - -
; 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 .Key_2
mov si, .Key_List ;Translate ASCII into scancode
mov [cs:.Key_Fail], al ;Sentinel
mov dl, al
.Key_1: lods word [cs:si]
cmp al, dl
jne .Key_1
test ah, ah
jnz .Key_3 ;Got scancode we can use
cmp al, 10 ;Remains an ASCII
je .Key ;Silently ignoring linefeed
ret ; in favor of input redirection
.Key_2: mov ah, 07h ;DOS.STDINInput
int 21h ; -> AL
shl ax, 8
jz .Key ;Don't allow embedded zeroes
.Key_3: xor al, al
test word [bp-10], 1 ;FLAGS.Keyboard ?
jz .Key_4 ;No, input is redirected
push ax ;(3)
mov ah, 02h ;BIOS.GetKeyboardFlags
int 16h ; -> AL
test al, 00000011b ;Either SHIFT key is depressed?
pop ax ;(3)
setnz al
.Key_4: ret
.Key_List:
dw 1C0Dh ;<RETURN> or <ENTER>
dw 011Bh ;<ESCAPE>
dw 0F09h ;<TAB>
dw 0E08h ;<BACKSPACE>
dw 180Fh ;<CTRL-O> other case of selection
dw 2D18h ;<CTRL-X> cut to clipboard
dw 2E03h ;<CTRL-C> copy to clipboard
dw 2F16h ;<CTRL-V> paste from clipboard
dw 111Ah ;<CTRL-Z> undo/redo
.Key_Fail:
db ?, 0
; - - - - - - - - - - - - - - - - - - -
.Show: test word [bp-10], 1 ;FLAGS.Keyboard ?
jz .Show_Ready ;No, input is redirected
movzx di, byte [bp-6] ;INBOX
movzx si, byte [bp-5] ;SHIFT
mov dx, [bp-4] ;COL and ROW
mov cx, 1 ;Replication count
mov bh, [bp-1] ;PAGE
.Show_Next:
mov ah, 02h ;BIOS.SetCursor
int 10h
mov bl, 07h ;WhiteOnBlack for normal text
test word [bp-10], 2 ;FLAGS.Selection ?
jz .Show_None
mov ax, si ;Current position
cmp al, [bp-12] ;LOSEL
jb .Show_None
cmp al, [bp-11] ;HISEL
jae .Show_None
mov bl, 1Fh ;BrightWhiteOnBlue for selection
.Show_None:
mov al, [bp+si] ;Current character
mov ah, 09h ;BIOS.WriteCharacterAndAttribute
int 10h
inc dl ;Next column
inc si ;Next character
dec di
jnz .Show_Next ;Process all of the input box
mov dx, [bp-4] ;COL and ROW
add dl, [bp-8] ;CIX
sub dl, [bp-5] ;SHIFT
mov ah, 02h ;BIOS.SetCursor
int 10h
.Show_Ready:
ret
; - - - - - - - - - - - - - - - - - - -
; Will backup only once for a series of deletion keys
.Backup:mov dx, [bp-18] ;OLDKEY
test dh, dh ;DH is zero for a character key
jz .Backup_First ;Previous key is not a deletion key
test dl, 64 ;DL has flags for an action key
jnz .Backup_Once ;Previous key was also deletion key
.Backup_First:
mov si, 128 ;Undelete buffer is at BP+128
@@: sub si, 2
mov dx, [bp+si]
mov [bp+128+12+si], dx
cmp si, -12
jg @b
.Backup_Once:
ret
; - - - - - - - - - - - - - - - - - - -
; <CTRL-Z>
.s11: mov ax, [bp-18] ;OLDKEY
cmp ax, 1100h
je .s11_Undo ;Previous key was also <CTRL-Z>
test ah, ah ;AH is zero for a character key
jz .s11_Bad ;Previous key is not a deletion key
test al, 64 ;AL has flags for an action key
jz .s11_Bad ;Previous key is not a deletion key
.s11_Undo:
mov si, 128 ;Undelete buffer is at BP+128
@@: sub si, 2
mov ax, [bp+si]
mov dx, [bp+128+12+si]
mov [bp+128+12+si], ax
mov [bp+si], dx
cmp si, -12
jg @b
ret
.s11_Bad:
mov word [bp+268+14], 0 ;pusha.AX is NEWKEY Throw away
ret ; invalid key
; - - - - - - - - - - - - - - - - - - -
; AH=01h <ESCAPE>
; AH=0Fh <TAB> or <SHIFT-TAB>
; AH=1Ch <RETURN> or <ENTER>
.s1C: xor si, si
mov bx, [bp+268+10] ;pusha.DX -> DS:BX
mov al, [bp-7] ;LIX
mov [bx+7], al ;8th byte is size of new string
add bx, 8
jmp .s1C_2
.s1C_1: mov dl, [bp+si]
mov [bx+si], dl ;Storage space receives new string
inc si
.s1C_2: sub al, 1
jnb .s1C_1
mov byte [bx+si], 0 ;Terminating zero
cmp ah, 1Ch ;Don't touch history for
jne .s1C_12 ; <TAB> or <ESCAPE>
mov dh, [bx-4] ;Size of history (in pages)
xor dl, dl
test dx, dx
jz .s1C_12 ;No history
movzx cx, byte [bp-7] ;LIX
jcxz .s1C_12 ;Don't add empty item
push es ;(4)
les di, [bx-8] ; -> ES:DI History
mov si, di
jmp .s1C_7
.s1C_3: cmp al, [bx] ;DS:BX points at storage space
jne .s1C_6 ;Not same first character
push bx si ;(5)
inc si ;Don't re-test first characters
.s1C_4: inc bx
lods byte [es:si] ;Compare following characters
cmp al, [bx]
jne .s1C_5
test al, al
jnz .s1C_4
pop bx bx ;(5a) Duplicate found
jmp .s1C_7 ;Don't keep it
.s1C_5: pop si bx ;(5b) Not a duplicate
.s1C_6: lods byte [es:si] ;Keep this item
stosb
test al, al
jnz .s1C_6
.s1C_7: mov al, [es:si] ;Next byte in history
test al, al
jnz .s1C_3 ;Not yet the final zero
mov [es:di], al ;Temporary final zero
inc cx ;Space needed for new item
mov ax, di ;DI points beyond last item
sub ax, [bx-8] ;[BX-8] points at first item
sub dx, ax ;Free=Size-(Last-First)
cmp cx, dx
jb .s1C_11 ;Plenty space available
mov di, [bx-8] ; -> ES:DI History
mov si, di
.s1C_8: lods byte [es:si] ;Discard oldest item
inc dx ;One more free byte
test al, al
jnz .s1C_8
cmp cx, dx
jnb .s1C_8 ;Not enough, go discard another one
jmp .s1C_10 ;Go keep all remaining items
.s1C_9: lods byte [es:si] ;Keep this item
stosb
test al, al
jnz .s1C_9
.s1C_10:cmp [es:si], al ;AL=0
jne .s1C_9 ;More items to keep
.s1C_11:mov al, [bx] ;Copy new ASCIIZ item
stosb
inc bx
test al, al
jnz .s1C_11
stosb ;New final zero
pop es ;(4)
.s1C_12:call .s47 ;<HOME>
call .s4F ;<END>
or word [bp-10], 1 ;FLAGS.Keyboard, Force display
call .Show ;Show all or last part of result
jmp .Quit
; - - - - - - - - - - - - - - - - - - -
; <BACKSPACE>
.s0E: call .DelSel ; -> CF
jc .s0E_1
cmp byte [bp-8], 0 ;CIX
jne .s0E_2
.s0E_1: ret
.s0E_2: call .s4B ;<LEFT>
; --- --- --- --- --- --- --
.Del: movzx di, byte [bp-8] ;CIX
movzx cx, byte [bp-7] ;LIX
sub cx, di
jz .Del_No ;Cursor behind the current input
@@: mov dl, [bp+di+1] ;Move down in edit buffer
mov [bp+di], dl
inc di
dec cx
jnz @b
dec byte [bp-7] ;LIX
.Del_No:ret
; - - - - - - - - - - - - - - - - - - -
; <DELETE>
.s53: call .DelSel ; -> CF
jnc .Del
ret
; - - - - - - - - - - - - - - - - - - -
.Beep: mov ax, 0E07h ;BIOS.TeletypeBeep
int 10h
.STC: stc
ret
; - - - - - - - - - - - - - - - - - - -
.Asc: cmp al, 32
jb .STC
call .DelSel ; -> CF
movzx di, byte [bp-8] ;CIX
movzx si, byte [bp-7] ;LIX
lea dx, [si+1]
cmp dl, [bp-2] ;STORE
jnb .Beep ;Not enough storage capacity
jmp .Asc_2
.Asc_1: mov dl, [bp+si-1] ;Move up in edit buffer
mov [bp+si], dl
dec si
.Asc_2: cmp si, di
ja .Asc_1
mov [bp+si], al ;Add newest character
inc byte [bp-7] ;LIX
; --- --- --- --- --- --- --
; <RIGHT>
.s4D: inc byte [bp-8] ;CIX
mov al, [bp-7] ;LIX
cmp [bp-8], al ;CIX
jbe .Shift
; --- --- --- --- --- --- --
; <LEFT>
.s4B: sub byte [bp-8], 1 ;CIX
jnb .Shift
; --- --- --- --- --- --- --
; <HOME>
.s47: xor bl, bl
jmp .Shift_
; - - - - - - - - - - - - - - - - - - -
; <END>
.s4F: mov bl, [bp-7] ;LIX
; --- --- --- --- --- --- --
.Shift_:mov [bp-8], bl ;CIX
.Shift: mov dl, [bp-5] ;SHIFT
mov dh, [bp-8] ;CIX
cmp dh, dl
jb .Shi_1
add dl, [bp-6] ;INBOX
sub dh, dl
jb .Shi_2
inc dh
add dh, [bp-5] ;SHIFT
.Shi_1: mov [bp-5], dh ;SHIFT
.Shi_2: clc
ret
; - - - - - - - - - - - - - - - - - - -
; <CTRL-HOME>
.s77: call .s0E ;<BACKSPACE>
cmp byte [bp-8], 0 ;CIX
ja .s77
ret
; - - - - - - - - - - - - - - - - - - -
; <CTRL-END>
.s75: call .Del
mov al, [bp-8] ;CIX
cmp al, [bp-7] ;LIX
jb .s75
ret
; - - - - - - - - - - - - - - - - - - -
; <CTRL-LEFT>
.s73: movzx bx, byte [bp-8] ;CIX
dec bx
call .wChar_ ; -> AL
@@: shr al, 1 ;Make room for 2nd leftside signal
dec bx
call .wChar ; -> AL
inc bx
and al, 11000000b ;Only keep both left signals
cmp al, 01000000b ;Found the start of a word ?
je .Shift_ ;Yes
dec bx
jns @b
ret
; - - - - - - - - - - - - - - - - - - -
; <CTRL-RIGHT>
.s74: movzx bx, byte [bp-8] ;CIX
call .wChar_ ; -> AL
@@: shl al, 1 ;Make room for 2nd rightside signal
inc bx
call .wChar ; -> AL
and al, 00000011b ;Only keep both right signals
cmp al, 00000010b ;Found the end of a word ?
je .Shift_ ;Yes
cmp bl, [bp-7] ;LIX
jb @b
ret
; - - - - - - - - - - - - - - - - - - -
.wChar_:xor al, al
.wChar: test bx, bx
js @f
cmp bl, [bp-7] ;LIX
jae @f
mov si, bx
cmp byte [bp+si], " " ;Current character
je @f ;Whitespace
or al, 10000001b ;Signal at both sides
@@: ret
; - - - - - - - - - - - - - - - - - - -
; <UP>
.s48: mov cx, [bp-16] ;HISCIX
dec cx
jns .s48_
ret
.s48_: mov [bp-16], cx ;HISCIX
mov bx, [bp+268+10] ;pusha.DX points at InputBuffer
push es ;(6)
les bx, [bx] ;FarPtrOfHistory
jmp .s48_2
.s48_1: inc bx ;Skip an item in the history
cmp byte [es:bx-1], 0
jne .s48_1
.s48_2: dec cx
jns .s48_1
call .Wipe ; -> CIX=0 LIX=0 SHIFT=0
jmp .s48_4
.s48_3: push bx ;(7)
call .Asc ; -> CF Input an history string
pop bx ;(7)
jc .s48_5
inc bx
.s48_4: mov al, [es:bx]
test al, al
jnz .s48_3
.s48_5: pop es ;(6)
ret
; - - - - - - - - - - - - - - - - - - -
; <DOWN>
.s50: mov cx, [bp-16] ;HISCIX
inc cx
cmp cx, [bp-14] ;HISLIX
jbe .s48_
; --- --- --- --- --- --- --
.Wipe: mov di, 128 ;Fill edit buffer with spaces
@@: sub di, 2
mov word [bp+di], " "
jnz @b
mov [bp-8], di ;DI=0 -> CIX=0 LIX=0
mov byte [bp-5], 0 ;SHIFT=0
ret
; - - - - - - - - - - - - - - - - - - -
; Other case of selection
; <CTRL-O>
.s18: bt word [bp-10], 1 ;FLAGS.Selection ?
jnc .s18_None
mov cx, [bp-12] ;LOSEL and HISEL
.s18_1: movzx si, cl
mov al, [bp+si] ;From edit buffer
cmp al, "A"
jb .s18_3
cmp al, "Z"
jbe .s18_2
cmp al, "a"
jb .s18_3
cmp al, "z"
ja .s18_3
.s18_2: xor al, 32 ;Change the case
mov [bp+si], al
.s18_3: inc cl
cmp cl, ch
jb .s18_1
.s18_None:
ret
; - - - - - - - - - - - - - - - - - - -
; <SHIFT-LEFT>
.s4Bs: mov ax, .s4B ;<LEFT>
jmp .Sel
; - - - - - - - - - - - - - - - - - - -
; <SHIFT-RIGHT>
.s4Ds: mov ax, .s4D ;<RIGHT>
jmp .Sel
; - - - - - - - - - - - - - - - - - - -
; <SHIFT-HOME>
.s47s: mov ax, .s47 ;<HOME>
jmp .Sel
; - - - - - - - - - - - - - - - - - - -
; <SHIFT-END>
.s4Fs: mov ax, .s4F ;<END>
jmp .Sel
; - - - - - - - - - - - - - - - - - - -
; <SHIFT-CTRL-LEFT>
.s73s: mov ax, .s73 ;<CTRL-LEFT>
jmp .Sel
; - - - - - - - - - - - - - - - - - - -
; <SHIFT-CTRL-RIGHT>
.s74s: mov ax, .s74 ;<CTRL-RIGHT>
; --- --- --- --- --- --- --
.Sel: mov ch, [bp-8] ;CIX
call ax ;One of the cursor movement ops
mov cl, [bp-8] ;CIX
cmp cl, ch ;Current vs previous position
je .Sel_Nop ;Cursor didn't move at all
bts word [bp-10], 1 ;FLAGS.Selection ?
jc .Sel_Old
.Sel_New:
cmp cl, ch ;Normalize the indexes
jb @f
xchg cl, ch
@@: mov [bp-12], cx ;LOSEL and HISEL
.Sel_Nop:
ret
.Sel_Old:
mov dx, [bp-12] ;LOSEL and HISEL
cmp ch, dl ;Previous cursor was
je @f ; either at LOSEL or at HISEL
mov dh, cl ;Update HISEL
mov cl, dl ;Replaces a 'jmp'
@@: mov dl, cl ;Update LOSEL
mov cx, dx
cmp dl, dh ;Compare new borders
jne .Sel_New ;Selection continues to exist
mov [bp-12], cx ;Selection dies with LOSEL=HISEL
; --- --- --- --- --- --- --
.NoSel: and word [bp-10], -3 ;FLAGS.Selection OFF
ret
; - - - - - - - - - - - - - - - - - - -
; Cut to clipboard
; <CTRL-X>
.s2D: call .s2E ;<CTRL-C>
; --- --- --- --- --- --- --
.DelSel:btr word [bp-10], 1 ;FLAGS.Selection ?
jnc .DelSel_None
mov bx, [bp-12] ;LOSEL and HISEL
call .Shift_
@@: call .Del
dec bh
cmp bh, bl
ja @b
mov [bp-12], bx ;LOSEL and HISEL
stc ;CF=1 if selection existed
.DelSel_None:
ret
; - - - - - - - - - - - - - - - - - - -
; Copy to clipboard
; <CTRL-C>
.s2E: bt word [bp-10], 1 ;FLAGS.Selection ?
jnc .s2E_None
mov di, [bp+268+8] ;pusha.BX -> ES:DI is Clipboard
mov cx, [bp-12] ;LOSEL and HISEL
@@: movzx si, cl
mov al, [bp+si] ;From edit buffer
stosb ; to clipboard
inc cl
cmp cl, ch
jb @b
xor al, al
stosb
.s2E_None:
ret
; - - - - - - - - - - - - - - - - - - -
; Paste from clipboard
; <CTRL-V>
.s2F: call .DelSel ; -> CF
mov si, [bp+268+8] ;pusha.BX -> ES:SI is Clipboard
jmp .s2F_2
.s2F_1: push si ;(8)
call .Asc ; -> CF Input the clipboard string
pop si ;(8)
jc .s2F_3
.s2F_2: lods byte [es:si] ;From clipboard
test al, al
jnz .s2F_1
.s2F_3: ret
; --------------------------------------
The idea behind this all new input procedure (input as in a dialog window) is to pimp my DOS programs with input capabilities that rival those found on Windows. It's possible that my observations on what Windows has to offer is missing a thing or two. Hence my question:
Did I include enough (Windows style) features to rightfully call this procedure "Rich Edit" ?
Since I program for DOS, I can't afford to waste memory. I tried to write the shortest code possible, but perhaps someone else could suggest additional code size reductions?
The current code uses a lot of memory transfers (buffer to buffer). I would like these to be as fast as possible, but I don't want the code size to increase. Kind of a dilemma but maybe a seasoned programmer can find a way out?
x86-16
anddos
- is that the case here? Consider additional tags. \$\endgroup\$Buffered input
example. In that case, it is over capable, but for text like word processing, it could use some other functionality. \$\endgroup\$