;-----------------------------
;Input.asm  - by James Vahn
; Gets a line of input from the keyboard

cseg segment
assume cs:cseg,ds:cseg
org 100h

Begin:
                mov ax,3                        ;Clear the screen
                int 10h
                mov dx,offset hello             ;Brag. ;-)
                mov ah,9
                int 21h

    Demo:       mov ah,1                        ;Turn INSert mode on.
                mov cx,0D0Ah
                int 10h

                mov bx,offset msg               ;Point to default string.
                mov cx,10                       ;Ten characters maximum
                mov dx,0500h                    ;Line 5, column 0
                call input

                cmp ax,4800h                    ;Cursor up.
                je up
                cmp ax,5000h                    ;Cursor down.
                je dn

                mov bx,cx                       ;$ terminate ASCIIZ.
                mov [msg+bx],'$'

                mov dx,offset crlf              ;Print it to the screen.
                mov ah,9
                int 21h

                int 20h                         ;Did it work??? 8-)

            up: mov dx,offset info1             ;Print cursor up message.
                mov ah,9
                int 21h
                jmp Demo

            dn: mov dx,offset info2             ;Print cursor down message.
                mov ah,9
                int 21h
                jmp Demo

crlf db 13,10
msg db 'test',0,0,0,0,0,0,0   ;Succesful input returned here.
info1 db 13,10,'up  $'
info2 db 13,10,'down$'
hello db 'Supporting left, right, up, down, backspace, insert, delete and ESC.'
db 13,10,'Up & down update the buffer, ESC aborts, Enter completes.'
db 13,10,'If the first key in the overstrike mode (small cursor), non-editing keys'
db 13,10,'will clear the line.$'

;*************************************
ASCIIZ  db 80 dup (255)                         ;Buffer, max 256(?) bytes.
IpSto   dw 0                                    ;Counter storage.
Home    dw 0                                    ;Cursor home
Char    dw 0                                    ;Character entered.
InTmp   db 0                                    ;Number of chars entered.

 Input  PROC NEAR
  ;This gets gets data from the keyboard, printing to the screen with
  ;DL,DH holding the desired cursor location. CX holds the maximum
  ;character count and BX points to the default buffer. DS=ES=CS

  ;CX returns the actual character count, the string is returned in the
  ;default buffer and AX is returns the character.
  ;
  ;Input.Asm by James Vahn 1994

                push    bx                      ;Save offset into buffer.
                stc                             ;Set carry to print default.
                pushf                           ;Save the flags.
                mov     si,bx                   ;Point SI to the default string.
                mov     IpSto,cx                ;Save 'max' counter.
                mov     di,offset ASCIIZ        ;Point DI to temp buffer.
                push    di                      ;Save it.
                inc     cx                      ;Add 1 to the counter.
                mov     al,0                    ;A null byte.
                rep stosb                       ;Clear the ASCIIZ buffer.
                mov     InTmp,al                ;Clear the counter.
                pop     di                      ;Get our pointer back.
                mov     ah,0Fh                  ;Get current page into
                int     10h                     ; BX for these BIOS calls.
                mov     Home,dx                 ;Save cursor starting point.
                mov     ah,2                    ;Position the cursor to
                int     10h                     ; location in DL,DH.
                cld                             ;Loops increment DI,SI.
          ip1:  popf                            ;Check if there is a default
                pushf                           ; string to print.
                jnc     ip5                     ;No default string.
                mov     InTmp,0                 ;No chars from keyboard yet.
                lodsb                           ;Get character from default.
                cmp     al,0                    ;Is it a terminater?
                jne     ip6                     ;Nope.
                popf                            ;Pull flags and clear the
                clc                             ; carry so we won't print
                pushf                           ; any more of the default.
          ip5:  mov     ah,0                    ;Get input from user
                int     16h                     ; via BIOS 16/0.
                mov     Char,ax
          ip6:  cmp     ax,4B00h                ;Left cursor.
                jne     ip10
                jmp     Lft
          ip10: cmp     ax,4D00h                ;Right cursor.
                jne     ip9
                jmp     Rt
          ip9:  cmp     ax,5300h                ;DEL button.
                jne     ip11
                jmp     DEL
          ip11: cmp     ax,5200h                ;Toggle INS mode.
                jne     ip12
                jmp     INSrt
          ip12: cmp     ax,4700h                ;Home key.
                jne     ip13
                jmp     HomeKey
          ip13: cmp     ax,4F00h                ;End key.
                jne     ip14
                jmp     EndKey
          ip14: cmp     al,27                   ;Escape key pressed,
                jne     ip15                    ; abort the entry and set
                stc                             ; the carry. Exit.
                jmp     ip2
          ip15: cmp     al,13                   ;Entry complete, user
                jne     ip16                    ; pressed ENTER.
                jmp     ip2
          ip16: cmp     ax,4800h                ;Cursor up. Done.
                jne     ip17
                jmp     ip2
          ip17: cmp     ax,5000h                ;Cursor down. Done.
                jne     ip18
                jmp     ip2
          ip18: cmp     al,8                    ;Was it a backspace?
                jne     ip19
                jmp     InBS                    ;Execute backspace routine.
         ip19:                                  ;Chain more key tests here.

          ip3:  cmp     al,' '                  ;Nothing less than a space.
                jnl     ip35
                jmp     ip1
          ip35: cmp     al,'~'                  ;Nothing more than a tilde.
                jng     ip36
                jmp     ip1
          ip36: mov     dx,IpSto                ;Test for max # of chars
                add     dx,offset ASCIIZ        ; by comparing DI to the
                inc     di                      ; 'max' in IpSto.
                cmp     di,dx
                jle     ip4                     ;Not yet, continue.
                dec     di                      ;Decrease ASCIIZ pointer
                mov     ax,0E07h                ; and BEEP, telling user
                int     10h                     ; the line limit has been
                jmp     ip1                     ; reached.
           ip4:
                push    ax                      ;Save the character.
                cmp     InTmp,0                 ;Test for first character.
                jne     btOkay                  ;Nope, skip this line clear.
                mov     ah,3                    ;Get cursor size via
                int     10h                     ; BIOS 10/3.
                test    cl,4                    ;Test cursor size..
                jz      btOkay                  ;If large, then jump. If
                mov     dx,Home                 ; small and this is the
                mov     ah,2                    ; first character, then
                int     10h                     ; clear the line.
                mov     ah,0Ah                  ;Erase the screen line with
                mov     al,' '                  ; the number of spaces in
                mov     cx,IpSto                ; IpSto via BIOS 10/0A.
                int     10h
                mov     dx,Home                 ;Move the cursor home
                mov     ah,2                    ; via BIOS 10/2.
                int     10h
                mov     di,offset ASCIIZ        ;Reset the pointer to
                mov     word ptr[di],0          ; ASCIIZ and zero it.
                inc     di                      ;Setup the pointer to continue.
        btOkay: pop     ax                      ;Restore the character.
                call    pushrt                  ;Push all chars right.
                dec     di                      ;Move the pointer back one.
                stosb                           ;Store character in buffer
                inc     InTmp                   ;Increment number of chars.
                mov     ah,0Ah                  ;Send the single character
                mov     cx,1                    ; to the screen via
                int     10h                     ; BIOS 10/0A.
                mov     ah,3                    ;Get current cursor position
                int     10h                     ; via BIOS 10/3.
                inc     dl                      ;Advance cursor position
                mov     ah,2                    ; via BIOS 10/2.
                int     10h
                jmp     ip1                     ;Go get more input.
          ip2:  pop     bp                      ;Clear stack.
                mov     ah,1                    ;Restore cursor size
                mov     cx,0607h                ; via BIOS 10/1.
                int     10h
                pop     di                      ;Pointer to default buffer.
                mov     si,offset ASCIIZ        ;Finish and return.
                mov     cx,0                    ;Zero CX, maintain carry.
                jc      ESCout                  ;If carry set, then abort.
          ip7:  lodsb                           ;Load AL from ASCIIZ, move to
                stosb                           ; default buffer and increment
                inc     cx                      ; CX until zero found.
                cmp     al,0                    ; CX holds character count.
                jne     ip7
                mov     ax,Char                 ;AX holds the character.
                ret                             ;End of Input, return.
        ESCout: mov     si,di                   ;SI is default buffer.
          ESC1: lodsb                           ;Load AL from buffer, increment
                inc     cx                      ; CX until zero found.
                cmp     al,0                    ; CX holds character count.
                jne     ESC1
                mov     ax,Char                 ;AX hold the character.
                ret                             ;Abort Input, return.
      ;---------------------------------------------------
      ;Destructive backspace routine. Character #8.
         InBS:  cmp     di,offset ASCIIZ        ;Test for start of line.
                je      InBS2                   ;Yes, ignore backspace.
                push    di                      ;Save current destination.
                mov     si,di                   ;Copy destination to source
                dec     di                      ; and subtract one.
                mov     ah,3                    ;Read cursor position.
                int     10h
                dec     dl                      ;Backup cursor one place
                push    dx                      ; and save new location.
                mov     ah,2                    ;Set new position via
                int     10h                     ; BIOS 10/2.
                call    DrLft                   ;Drag string to the left.
                pop     dx                      ;Put cursor at new location
                mov     ah,2                    ; via BIOS 10/2.
                int     10h
                pop     di                      ;Get original destination
                dec     di                      ; to ASCIIZ and decrement.
          InBS2:inc     InTmp                   ;Increment keystroke counter.
                jmp     ip1                     ;Backspace completed.

      ;---------------------------------------------------
      ;DEL key routine. Character #5300.
         DEL:   cmp     di,offset ASCIIZ - 1    ;Test for start of line.
                je      DEL2                    ;Yes, ignore backspace.
                push    di                      ;Save current destination.
                mov     si,di                   ;Copy destination to source
                inc     si                      ; and increase source.
                mov     ah,3                    ;Read cursor position
                int     10h                     ; and save location.
                push    dx
                call    DrLft                   ;Drag string to the left.
                pop     dx                      ;Put cursor at original
                mov     ah,2                    ; location via BIOS 10/2.
                int     10h
                pop     di                      ;Get original buffer position.
          DEL2: inc     InTmp                   ;Increment keystroke counter.
                jmp     ip1                     ;Delete completed.

      ;---------------------------------------------------
      ;Left cursor routine. Character #4B00
         Lft:   cmp     di,offset ASCIIZ        ;Test for start of line.
                je      lft1                    ;Yes, ignore.
                mov     ah,3                    ;Read cursor position
                int     10h                     ; via BIOS 10/3.
                dec     dl                      ;Move cursor back one place
                mov     ah,2                    ; via BIOS 10/2.
                int     10h
                dec     di
          lft1: inc     InTmp                   ;Increment keystroke counter.
                jmp     ip1                     ;Completed.

      ;---------------------------------------------------
      ;Right cursor routine. Character #4D00
         Rt:    mov     dx,IpSto                ;Test for max # of chars
                add     dx,offset ASCIIZ        ; by comparing DI to the
                cmp     di,dx                   ; 'max' in IpSto.
                je      rt1
                cmp     byte ptr[di],0          ;Don't move beyond data
                je      rt1                     ; in buffer.
                mov     ah,3                    ;Read cursor position
                int     10h                     ; via BIOS 10/3.
                inc     di
                inc     dl                      ;Move cursor foward one place
                mov     ah,2                    ; via BIOS 10/2.
                int     10h
           rt1: inc     InTmp                   ;Increment keystroke counter.
                jmp     ip1                     ;Completed.

      ;---------------------------------------------------
      ;Routine to drag string left.
         DrLft: lodsb                           ;Load AL from ASCIIZ and
                stosb                           ; move it back one place.
                cmp     al,0                    ;If it was a zero, exit
                je      DrLft2                  ; this loop and finish.
                mov     ah,0Ah                  ;Print it to the screen
                mov     cx,1                    ; via BIOS 10/0A.
                int     10h
                inc     dl                      ;Advance the cursor one place
                mov     ah,2                    ; for the next character
                int     10h                     ; via BIOS 10/2.
                jmp     DrLft                   ;Do the entire line.
        DrLft2: mov     al,' '                  ;Erase last character under
                mov     ah,0Ah                  ; cursor by printing a space
                mov     cx,1                    ; via BIOS 10/1.
                int     10h
                inc     InTmp                   ;Increment keystroke counter.
                ret

      ;---------------------------------------------------
      ;Routine to toggle INSert mode.
         INSrt: mov     ah,3                    ;Read cursor size
                int     10h                     ; via BIOS 10/3 and
                xor     cl,4                    ; toggle bit 4.
                mov     ah,1                    ;Set new cursor size
                int     10h                     ; via BIOS 10/1 and
                jmp     ip1                     ; jump to entry.

      ;---------------------------------------------------
      ; Routine to shift right, inserting text if required.
        PushRt:
                push    ax                      ;Save our input byte.
                push    di                      ;Save the buffer pointer.
                push    si                      ;Save another buffer pointer.
                mov     ah,3                    ;Get cursor location
                int     10h                     ; via BIOS 10/3 and
                push    dx                      ; save it.
                dec     di                      ;Point to last character
                mov     si,di                   ; and setup SI.
                sub     cx,cx                   ;Zero CX.
         pr1:   lodsb                           ;Get a character from the
                inc     cx                      ; buffer and increment CX.
                cmp     al,0                    ;Is this the end?
                jne     pr1                     ;Nope, get another.
                push    dx                      ;Save the cursor locations.
                push    cx                      ;Save the # of chars to move.
                push    si                      ;Save buffer pointer.
          pr6:  mov     ah,3                    ;Get cursor size via
                int     10h                     ; BIOS 10/3 and test bit 4
                and     cl,4                    ; to see if in insert mode.
                je      pr8                     ;Yes, shift all characters.
                pop     si                      ;No, restore registers and
                pop     cx                      ; prepare to return to caller.
                pop     dx
                jmp     pr4
         pr8:   mov     si,offset ASCIIZ        ;Point to start of buffer.
                sub     cx,cx                   ;Zero CX.
         pr5:   lodsb                           ;Get a byte from the buffer.
                inc     cx                      ;Increment our counter.
                cmp     al,0                    ;Is it a zero?
                jne     pr5                     ;Nope, try more.
                mov     dx,IpSto                ;Test for max # of chars.
                cmp     cx,dx                   ;Compare.
                jle     pr7                     ;Not yet, continue.
                mov     ax,0E07h                ;BEEP, telling user the
                int     10h                     ; line limit has been reached.
                pop     si                      ; Restore registers
                pop     cx                      ; and cleanup stack.
                pop     dx
                pop     dx
                pop     si
                pop     di
                dec     di
                pop     ax
                pop     bp                      ;Dummy to clean stack.
                jmp     ip1                     ;Re-enter input.
          pr7:  pop     si                      ;Point to buffer.
                pop     cx                      ;Restore # of chars to move.
                pop     dx                      ;Restore cursor location.
                mov     di,si                   ;DI points one place right.
                dec     si                      ;Back SI one place.
                std                             ;Decrement direction counter.
                rep movsb                       ;Move string right.
                cld                             ;Reset direction counter.
                inc     si                      ;Point SI at previous data
          pr3:                                  ; in the new location.
                lodsb                           ;Get a byte from SI into AL.
                cmp     al,0                    ;Is it a zero?
                je      pr4                     ;Yes, end of string.
                mov     ah,0Ah                  ;Print it to the screen
                mov     cx,1                    ; via BIOS 10/0A.
                int     10h
                inc     dl                      ;Advance the cursor one place
                mov     ah,2                    ; for the next character
                int     10h                     ; via BIOS 10/2.
                jmp     pr3                     ;Get another byte to print.
          pr4:
                pop     dx                      ;Restore cursor location
                mov     ah,2                    ; back to original via
                int     10h                     ; BIOS 10/2.
                pop     si                      ;Restore buffer pointer.
                pop     di                      ;Restore another buffer pointer.
                pop     ax                      ;Restore our character.
                ret                             ;Return to caller.

      ;---------------------------------------------------
      ; Routine to move to home posistion.
       HomeKey:
                mov     dx,Home                 ;Move cursor to start
                mov     ah,2                    ; of the line via
                int     10h                     ; BIOS 10/2.
                mov     di,offset ASCIIZ        ;Set pointer to start of buffer.
                inc     InTmp                   ;Increment keystroke counter.
                jmp     ip1                     ;Re-enter loop.

      ;---------------------------------------------------
      ; Routine to move to end posistion.
        EndKey:
                mov     si,offset ASCIIZ        ;Point to start of buffer.
                sub     cx,cx                   ;Zero CX.
         ek1:   lodsb                           ;Get a byte from the buffer.
                inc     cx                      ;Increment our counter.
                cmp     al,0                    ;Is it a zero?
                jne     ek1                     ;Nope, try more.
                dec     si                      ;Found end, decrease SI
                mov     di,si                   ; and move it to DI, our
                mov     dx,si                   ; current pointer.
                sub     dx,offset ASCIIZ        ;Calculate cursor location
                add     dx,Home                 ; and move it there via
                mov     ah,2                    ; BIOS 10/2.
                int     10h
                inc     InTmp                   ;Increment keystroke counter.
                jmp     ip1
 Input endp

cseg ends
end Begin
