%TITLE          "WorkStation I/O - CHiPS bv 1997"
;**********************************************************************
;**                                                                  **
;**  Program   : WSIO                                                **
;**  Purpose   : WorkStation Input/Output                            **
;**                                                                  **
;**  Author    : B.F. Schreurs                                       **
;**              Computer High Performance Software (CHiPS) bv       **
;**  Date      : November 20th, 1997                                 **
;**                                                                  **
;**  Calls     : [None]                                              **
;**                                                                  **
;**  Language  : Turbo Assembler                                     **
;**                                                                  **
;**********************************************************************
        IDEAL
        JUMPS

;----------------------------------------------------------------------
;--  Functions which can be called                                   --
;----------------------------------------------------------------------
        PUBLIC  WSIO



;----------------------------------------------------------------------
;--  Equates                                                         --
;----------------------------------------------------------------------
include ".\equ\dos.equ"
include ".\equ\keyboard.equ"
include ".\equ\mouse.equ"
include ".\equ\sysdep.equ"
include ".\equ\video.equ"
include ".\equ\wsio.equ"

SCREEN_SAVE_TABLE_MAX       EQU  10
SCREEN_SAVE_STRUCTURE_SIZE  EQU  14
SCREEN_NAME_SIZE            EQU   8

KEY_ALPHA                   EQU  "ABCDEFGHIJKLMNOPQRSTUVWXYZ "
KEY_NUMERIC                 EQU  "0123456789.,+- "
KEY_SPECIAL                 EQU  "@#$"
KEY_FILEMASK                EQU  "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ*\:!#$%&_()'?~^³ñ`ø÷@.- "

;**********************************************************************
SEGMENT SSeg Para Stack 'STACK'
;**********************************************************************

        db        64 dup (0)            ; Stack

ENDS    SSeg

;**********************************************************************
SEGMENT DSeg Word Public 'DATA'
;**********************************************************************

;----------------------------------------------------------------------
;--  Structures                                                      --
;----------------------------------------------------------------------
include ".\str\position.str"
include ".\str\wsio.str"

Struc   Screen_Save
  Screen_Name                   DB    8 dup (NULL)
  Save_Address_Hi               DW    ?         ; Save Area Memory Address HIGH
  Save_Address_Lo               DW    ?         ; Save Area Memory Address LOW
  Cursor_Position_Org           Position <>     ; Location of Cursor of prev screen
ends                                            ; Screen_Save

;----------------------------------------------------------------------
;--  Working Storage                                                 --
;----------------------------------------------------------------------
Return_Code                     DW    NULL

Allocation_Strategy_Old         DW    NULL
Allocation_Strategy_New         DW    NULL

;--------------------------------
; Saved screen information/tables
;--------------------------------
Screen_Save_Table               Screen_Save SCREEN_SAVE_TABLE_MAX dup (<>)

Screen_Save_ptr_es              DW    NULL
Screen_Save_ptr_di              DW    NULL

Screen_Name_Last_Used_Wsio_Hi   DW    ?
Screen_Name_Last_Used_Wsio_Lo   DW    ?

;-----------
; Mouse info
;-----------
Pixels_Per_Row                  DW    0
Pixels_Per_Col                  DW    0

;------------
; Screen info
;------------
Wsio_Initialize                 DB    LOGIC_NO
Wsio_No_Input                   DB    LOGIC_NO
Wsio_Mouse_Visible              DB    LOGIC_NO
Wsio_Mouse_Present              DB    LOGIC_NO
Wsio_Mouse_Left_Button_Pressed  DB    LOGIC_NO

Wsio_Area_ptr_es                DW    NULL
Wsio_Area_ptr_di                DW    NULL
Wsio_Rows                       DW    NULL
Wsio_Cols                       DW    NULL
Wsio_Field_Nr_Max               DW    NULL
Wsio_Field_Nr_Mod_Max           DW    NULL
Temp_Wsio_Field_Modifiable      DB    0
Temp_Wsio_Field_Mouse_Sensitive DB    0
Save_Wsio_Field_Modifiable      DB    0
Save_Wsio_Input_Select_Attrib   DB    0
Save_Wsio_Select_Field_Nr       DB    0
Save_Wsio_Select_Field_Occur_Nr DB    0
Save_Wsio_Select_Field_Attrib   DB    0

;
; Fields below have the same layout and size as the Wsio structure!!!
; Structure size is WSIO_STRUCTURE_SIZE
;
Wsio_Command                    DB    WSIO_OPEN
Wsio_Start_Row                  DB    1         ; Start of screen ROW
Wsio_Start_Col                  DB    1         ; Start of screen COLUMN
Wsio_End_Row                    DB   24         ; End of screen   ROW
Wsio_End_Col                    DB   80         ; End of screen   COLUMN
Wsio_Screen_Attrib              DB    0         ; Screen attribute, 0=don't change it
Wsio_Field_Attrib               DB    0         ; Field attribute, 0=don't change it
Wsio_Input_Select_Attrib        DB    0         ; Input/Select attribute, input or selected
Wsio_Error_Attrib               DB    0         ; Input error attribute
Wsio_Mouse_Support              DB    LOGIC_NO  ; No Mouse Support
Wsio_Select_Field_Nr            DB    1         ; Cursor positioned at Active Window field nr
Wsio_Select_Field_Occur_Nr      DB    1         ; Cursor positioned at Active Window field occurrence
Wsio_Select_Field_Position      DB    1         ; Cursor positioned at Active Window field position
Wsio_Screen_Changed             DB    LOGIC_NO  ; Screen changed, No=LOGIC_NO, Yes=LOGIC_YES
Wsio_Cursor_Row                 DB    1         ; Position at screen location row
Wsio_Cursor_Col                 DB    1         ; Position at screen location col
Wsio_Name_Address_Hi            DW    ?         ; Screen Name      Address HIGH
Wsio_Name_Address_Lo            DW    ?         ; Screen Name      Address LOW
Wsio_Text_Address_Hi            DW    ?         ; Text             Address HIGH
Wsio_Text_Address_Lo            DW    ?         ; Text             Address LOW
Wsio_Attrib_Address_Hi          DW    ?         ; Attribute  Table Address HIGH
Wsio_Attrib_Address_Lo          DW    ?         ; Attribute  Table Address LOW
Wsio_Keys_Address_Hi            DW    ?         ; Valid Keys       Address HIGH
Wsio_Keys_Address_Lo            DW    ?         ; Valid Keys       Address LOW
Wsio_Enter_Address_Hi           DW    ?         ; Enter Emul Keys  Address HIGH
Wsio_Enter_Address_Lo           DW    ?         ; Enter Emul Keys  Address LOW
Wsio_Field_Address_Hi           DW    ?         ; Field Area Table Address HIGH
Wsio_Field_Address_Lo           DW    ?         ; Field Area Table Address LOW

;------------------
; Active field info
;------------------
Wsio_Field_Curr_Char            DB    SPACE
Wsio_Field_Curr_Occur           DB    0
Wsio_Field_Data_Save            DB    MAX_COL dup (SPACE)
Wsio_Field_Change               DB    LOGIC_NO

;
; Fields below have the same layout and size as the Wsio_Field structure!!!
; Structure size is WSIO_FIELD_STRUCTURE_SIZE
;
Wsio_Field_Start_Row            DB    1         ; Rel. Start of field ROW, NULL=End
Wsio_Field_Start_Col            DB    1         ; Rel. Start of field COLUMN
Wsio_Field_Size                 DB    1         ; Field size
Wsio_Field_Occurs               DB    1         ; Nr of occurrences
Wsio_Field_Offset               DW    0         ; Add this value to the field size to get to the next element, if this element is part of a table
Wsio_Field_Modifiable           DB    0         ; 0=Protected 1=Modifiable
Wsio_Field_Mouse_Sensitive      DB    0         ; 0=No, Any other key is the value to be emulated
Wsio_Field_Edit                 DB    0         ; 0=External 1=Any 2=Nrs 3=Letters 4=Nrs+Letters 5=Nrs+Letters+@#$ 6=Filemask 7=Hexadecimal
Wsio_Field_Blank                DB    0         ; 0=Anywhere 1=Trailing 2=None
Wsio_Field_Uppercase            DB    0         ; 0=Upper 1=Upper+Lower
Wsio_Field_Backspace            DB    0         ; Backspace mode, 0=Destructive backspace, 1=Restore character from source data field
Wsio_Field_Digits_Before        DB    0         ; Digits before dot, max. 15
Wsio_Field_Digits_After         DB    0         ; Digits after  dot, max   3
Wsio_Field_Negative             DB    LOGIC_NO  ; Can the number be negative
Wsio_Field_Decimal_Point        DB    DECIMAL_SEPERATOR
Wsio_Field_Date_Time_Format     DB    0         ; Date Format, 0=dd, 1=mm 2=yy, 3=ccyy, 4=yymm, 5=yymmdd, 6=ccyymmdd, 7=ddmmyy, 8=ddmmccyy, 9=hh, 10=mm, 11=ss, 12=tt, 13=hhmm, 14=hhmmss, 15=hhmmsstt, 16=ccyymmddhhmmsstt
Wsio_Field_Changed              DB    LOGIC_NO  ; Field changed, LOGIC_NO=No, LOGIC_YES=Yes
Wsio_Field_Data_Src_ptr_es      DW    ?         ; Field Data Source Address HIGH
Wsio_Field_Data_Src_ptr_di      DW    ?         ; Field Data Source Address LOW
Wsio_Field_Data_Obj_ptr_es      DW    ?         ; Field Data Object Address HIGH
Wsio_Field_Data_Obj_ptr_di      DW    ?         ; Field Data Object Address LOW
Wsio_Field_Video_ptr_es         DW    ?         ; Attribute         Address HIGH
Wsio_Field_Video_ptr_di         DW    ?         ; Attribute         Address LOW
Wsio_Field_Keys_ptr_es          DW    ?         ; Valid Keys        Address HIGH
Wsio_Field_Keys_ptr_di          DW    ?         ; Valid Keys        Address LOW

;-----------
; Edit Masks
;-----------
Edit_Mask_1_Any                 DB    ?

Edit_Mask_2_Nrs                 DB    KEY_NUMERIC
                                DB    NULL

Edit_Mask_3_Letters             DB    KEY_ALPHA
                                DB    NULL

Edit_Mask_4_Nrs_Letters         DB    KEY_ALPHA
                                DB    KEY_NUMERIC
                                DB    NULL

Edit_Mask_5_Nrs_Let_Spc         DB    KEY_ALPHA
                                DB    KEY_NUMERIC
                                DB    KEY_SPECIAL
                                DB    NULL

Edit_Mask_6_Filemask            DB    KEY_FILEMASK
                                DB    NULL

Edit_Mask_7_Hexadecimal         DB    "0123456789ABCDEF"
                                DB    NULL

Edit_Mask_8_Tabable             DB    NULL

;-----------------------
; Video memory addresses
;-----------------------
Video_Address_Base              DW    VIDEO_MODE_COLOR_BASE
Video_Address_Offset            DW    0
Video_Address_ptr_es            DW    1 dup (NULL)
Video_Address_ptr_di            DW    1 dup (NULL)

;----------------
; M e s s a g e s
;----------------
Msg_Ok                          DW    000       ; Screen I/O ok
Msg_Screen_Not_Altered          DW    001       ; Screen has not been altered
Msg_Err_Wsio_Open               DW    002       ; Screen already open
Msg_Err_No_Empty_Slot           DW    003       ; No empty screen slot, all slots in use
Msg_Err_Memory_Alloc            DW    004       ; Memory Allocation Error
Msg_Err_Wsio_Not_Found          DW    005       ; Screen save area somehow disappeared

ENDS    DSeg



;**********************************************************************
SEGMENT CSeg Word Public 'CODE'
;**********************************************************************



;**********************************************************************
PROC    WSIO
;**********************************************************************
        ASSUME  cs:CSeg
        ASSUME  ds:DSeg
        mov     ax, DSeg                        ; Initialize DS to address
        mov     ds, ax                          ; of data segment

        mov     bx, sp
        mov     ax, [ss:bx+2]                   ; si
        mov     bx, [ss:bx+4]                   ; ds

        mov     [Wsio_Area_ptr_es], bx
        mov     [Wsio_Area_ptr_di], ax

        push    ds si es di

        mov     si, offset Wsio_Command
        push    ds si
        pop     di es
        mov     si, ax
        mov     ds, bx
        mov     cx, WSIO_STRUCTURE_SIZE
        rep     movsb

        pop     di es si ds

        call    Process_Initialize
        call    Process_Passed_Parameters
        call    Process_Wsio_Command

        mov     ah, [byte Return_Code]

        ret

ENDP    WSIO



;**********************************************************************
PROC    Process_Initialize
;**********************************************************************
        cmp     [Wsio_Initialize], LOGIC_YES    ; Initialize executed?
        je      @@99                            ; Yes
                                                ; No, so
        mov     [Wsio_Initialize], LOGIC_YES
        mov     [Wsio_Mouse_Present], LOGIC_NO

;------------------------
; Determine Video Address
;------------------------
        mov     [Video_Address_Base], VIDEO_MODE_COLOR_BASE
        xor     ax, ax
        mov     ah, VIDEO_GET_MODE
        int     VIDEO_SERVICE                   ; Get Video Mode
        cmp     al, VIDEO_MODE_MONO             ; Monochrome Mode?
        jne     @@10                            ; No
                                                ; Yes, so
        mov     [Video_Address_Base], VIDEO_MODE_MONO_BASE

;--------------
; Mouse support
;--------------
@@10:
        mov     ax, MOUSE_RESET_MOUSE
        int     MOUSE_SERVICE
        cmp     ax, NULL                        ; Mouse available?
        je      @@99                            ; No
                                                ; Yes, so
        mov     [Wsio_Mouse_Present], LOGIC_YES
        mov     [Wsio_Mouse_Visible], LOGIC_NO
;
; Get pixel sizes
;
        mov     ax, MOUSE_GET_MAXIMUM_COORDINATES
        int     MOUSE_SERVICE

        inc     cx                              ; Column size in pixels
        inc     dx                              ; Row size in pixels
        mov     ax, 8                           ; Assume 8 pixels per char horizontal
        mov     bx, 8                           ; Assume 8 pixels per char vertical
        cmp     cx, 640                         ; 640 pixels horizontal?
        je      @@20                            ; Yes
                                                ; No, so
@@20:
        mov     [Pixels_Per_Col], ax

        cmp     dx, 192                         ; 192 pixels vertical?
        je      @@30                            ; Yes
                                                ; No, so
@@30:
        mov     [Pixels_Per_Row], bx

@@99:
        ret

ENDP    Process_Initialize



;**********************************************************************
PROC    Process_Passed_Parameters
;**********************************************************************
        mov     ax, NULL
        mov     [Return_Code], ax

        xor     cx, cx
        xor     dx, dx

        mov     cl, [Wsio_End_Row]
        inc     cl
        mov     dl, [Wsio_Start_Row]
        sub     cl, dl
        mov     [Wsio_Rows], cx

        mov     dl, [Wsio_End_Col]
        inc     dl
        mov     cl, [Wsio_Start_Col]
        sub     dl, cl
        mov     [Wsio_Cols], dx

        mov     cl, [Wsio_Start_Row]
        mov     dl, [Wsio_Start_Col]

        mov     [Save_Wsio_Select_Field_Nr], 0
        mov     [Save_Wsio_Select_Field_Occur_Nr], 0
        mov     al, [Wsio_Input_Select_Attrib]
        mov     [Save_Wsio_Input_Select_Attrib], al

        mov     di, [Video_Address_Offset]      ; Videomap Offset
        mov     es, [Video_Address_Base]        ; Videomap Base

@@10:
        add     di, (MAX_COL * 2)
        loop    @@10

        sub     di, (MAX_COL * 2)
        add     di, dx
        add     di, dx
        sub     di, 2                           ; Correct video location reached

        mov     [Video_Address_ptr_es], es
        mov     [Video_Address_ptr_di], di

;--------------------------------------
; Check cursor row/col for location 0,0
;--------------------------------------
        cmp     [Wsio_Cursor_Row], 0            ; Jump to pre-specified or first modifiable field?
        jne     @@80                            ; No
                                                ; Yes, so
        xor     cx, cx                          ; Reset cx
;
; Assume top left cursor position
;
        mov     ah, [Wsio_Start_Row]            ; Assume top left first
        mov     al, [Wsio_Start_Col]            ; of current window
                                                ; in case of no (modifiable) field
        mov     [Wsio_Cursor_Row], ah
        mov     [Wsio_Cursor_Col], al

;
; Check Field Table
;
        mov     bx, [Wsio_Field_Address_Hi]
        mov     di, [Wsio_Field_Address_Lo]
        mov     es, bx

        cmp     bx, NULL                        ; Address specified?
        je      @@80                            ; No,
                                                ; Yes, so
;
; Check (Next) Field
;
@@30:
        cmp     [byte es:di], NULL              ; Fields left to check?
        je      @@80                            ; No
                                                ; Yes, so
        cmp     [Wsio_Select_Field_Nr], 0       ; Field nr specified?
        je      @@40                            ; No
                                                ; Yes, so
        inc     cl                              ; Field counter
        cmp     cl, [Wsio_Select_Field_Nr]      ; Specified Field nr reached?
        je      @@60                            ; Yes
                                                ; No, so
        jmp     @@50                            ; Check next field

@@40:
        cmp     [(Wsio_Field ptr di).Modifiable], 1     ; Modifiable?
        je      @@60                            ; Yes
                                                ; No, so
@@50:
        add     di, WSIO_FIELD_STRUCTURE_SIZE   ; Point to next field
        jmp     @@30                            ; Check next field

@@60:
;
; Field found to point the cursor at
;
        mov     ah, [Wsio_Start_Row]
        add     ah, [(Wsio_Field ptr di).Start_Row]
        dec     ah

        mov     al, [Wsio_Start_Col]
        add     al, [(Wsio_Field ptr di).Start_Col]
        dec     al

;
; Position at selected occurrence (if any)
;
        cmp     [Wsio_Select_Field_Occur_Nr], 0 ; Occurrence nr specified?
        je      @@70                            ; No
                                                ; Yes, so
        add     ah, [Wsio_Select_Field_Occur_Nr]
        dec     ah                              ; Occurrence reached

;
; Position at selected position (if any)
;
        cmp     [Wsio_Select_Field_Position], 0 ; Position specified?
        je      @@70                            ; No
                                                ; Yes, so
        add     al, [Wsio_Select_Field_Position]
        dec     al                              ; Position reached

@@70:
;
; Set cursor to selected field
;
        mov     [Wsio_Cursor_Row], ah
        mov     [Wsio_Cursor_Col], al

@@80:
;
; Check for cursor off screen
;
        mov     [Wsio_No_Input], LOGIC_NO
        cmp     [Wsio_Cursor_Row], CURSOR_OFF_SCREEN
        jne     @@99
        mov     [Wsio_No_Input], LOGIC_YES

@@99:
        ret

ENDP    Process_Passed_Parameters



;**********************************************************************
PROC    Process_Wsio_Command
;**********************************************************************
        cmp     [Wsio_Command], WSIO_OPEN
        je      @@10

        cmp     [Wsio_Command], WSIO_DISPLAY_ONLY
        je      @@20

        cmp     [Wsio_Command], WSIO_DISPLAY_TEXT_ONLY
        je      @@23

        cmp     [Wsio_Command], WSIO_DISPLAY_FIELDS_ONLY
        je      @@25

        cmp     [Wsio_Command], WSIO_READ_ONLY
        je      @@30

        cmp     [Wsio_Command], WSIO_DISPLAY_AND_READ
        je      @@40

        cmp     [Wsio_Command], WSIO_SELECT_DESELECT
        je      @@50

        cmp     [Wsio_Command], WSIO_KEY_CHECK
        je      @@60

        cmp     [Wsio_Command], WSIO_CLOSE
        je      @@70

;
; Command Error
;
        jmp     @@99

@@10:
;--------
; O P E N
;--------
        call    Wsio_Command_Open
        jmp     @@99

@@20:
;------------------------
; D I S P L A Y   O N L Y
;------------------------
        call    Wsio_Command_Display_Only
        jmp     @@99

@@23:
;----------------------------------
; D I S P L A Y   T E X T   O N L Y
;----------------------------------
        call    Wsio_Command_Display_Text_Only
        jmp     @@99

@@25:
;--------------------------------------
; D I S P L A Y   F I E L D S   O N L Y
;--------------------------------------
        call    Wsio_Command_Display_Fields_Only
        jmp     @@99

@@30:
;------------------
; R E A D   O N L Y
;------------------
        call    Wsio_Command_Read_Only
        jmp     @@99

@@40:
;--------------------------------
; D I S P L A Y   A N D   R E A D
;--------------------------------
        call    Wsio_Command_Display_And_Read
        jmp     @@99

@@50:
;------------
; S E L E C T
;------------
        call    Wsio_Command_Select_Deselect
        jmp     @@99

@@60:
;---------------
; KEY CHECK ONLY
;---------------
        call    Wsio_Command_Key_Check
        jmp     @@99

@@70:
;----------
; C L O S E
;----------
        call    Wsio_Command_Close
        jmp     @@99

@@99:
        ret

ENDP    Process_Wsio_Command



;**********************************************************************
PROC    Wsio_Command_Open
;**********************************************************************
;
; Check on screen name
;
        mov     bx, [Wsio_Name_Address_Hi]
        mov     di, [Wsio_Name_Address_Lo]
        mov     es, bx

        mov     si, offset Screen_Save_Table.Screen_Name
        mov     bx, HIGH_VALUES
        mov     cx, SCREEN_SAVE_TABLE_MAX

@@20:
        push    cx
        cmp     [byte ds:si], NULL              ; Empty entry found?
        jne     @@30                            ; No
                                                ; Yes, so
        cmp     bx, HIGH_VALUES                 ; Was there an empty already?
        jnz     @@40                            ; Yes
                                                ; No, so
        mov     bx, SCREEN_SAVE_TABLE_MAX
        sub     bx, cx                          ; Store free entry nr
        jmp     @@40

@@30:
        push    ds si es di
        mov     cx, SCREEN_NAME_SIZE            ; Compare Size
        rep     cmpsb                           ; Screen already exist?
        pop     di es si ds
        jne     @@40                            ; No
                                                ; Yes, so
;
; Error, Screen already exist or open
;
        pop     cx
        mov     ax, [Msg_Err_Wsio_Open]
        mov     [Return_Code], ax
        jmp     @@99

@@40:
        pop     cx
        add     si, SCREEN_SAVE_STRUCTURE_SIZE
        loop    @@20

;
; Check for empty slot to store the screen info
;
        cmp     bx, HIGH_VALUES                 ; Is there an empty slot?
        jne     @@50                            ; Yes
                                                ; No, so
        mov     ax, [Msg_Err_No_Empty_Slot]
        mov     [Return_Code], ax
        jmp     @@99

@@50:
;
; Save Screen Name
;
        mov     si, offset Screen_Save_Table.Screen_Name
        mov     cx, bx
        mov     ax, SCREEN_SAVE_STRUCTURE_SIZE
        mul     cx
        add     si, ax

        mov     [Screen_Save_ptr_es], ds
        mov     [Screen_Save_ptr_di], si

        push    ds si es di

        push    ds si es di
        pop     si ds di es

        mov     cx, SCREEN_NAME_SIZE            ; Copy Size
        rep     movsb                           ; Copy Screen Name

        pop     di es si ds                

;
; Determine Memory Strategy
;
        mov     ax, DOS_GET_ALLOCATION_STRATEGY
        int     DOS_SERVICE

        mov     [Allocation_Strategy_Old], ax
        mov     [Allocation_Strategy_New], ax

        mov     bx, [Allocation_Strategy_New]
        or      bx, DOS_STRATEGY_MEM_UMB_CONV
        or      bx, DOS_STRATEGY_MEM_BEST_FIT
        mov     [Allocation_Strategy_New], bx

        mov     ax, DOS_SET_ALLOCATION_STRATEGY
        mov     bx, [Allocation_Strategy_New]
        int     DOS_SERVICE                     ; Set new strategy
        jnc     @@60                            ; Failed?
                                                ; Yes, so
        mov     ax, DOS_SET_ALLOCATION_STRATEGY
        mov     bx, [Allocation_Strategy_Old]
        int     DOS_SERVICE                     ; Reset to old strategy

@@60:
;
; Allocate Memory for Save Screen Area
;
        mov     ax, [Wsio_Rows]
        mov     cx, [Wsio_Cols]

        mul     cx
        mov     cx, 2                           ; Because of video structure
        mul     cx                              ; being character + attribute

        mov     bx, PARAGRAPH
        xor     dx, dx
        div     bx                              ; dx:ax / bx
        mov     bx, ax
        inc     bx
        xor     cx, cx

        xor     ax, ax                          ; Reset ax
        mov     ah, DOS_ALLOCATE_MEMORY
        int     DOS_SERVICE                     ; Allocate Memory in paragraphs
        mov     cx, ax
        jnc     @@70

;
; Error, Memory Allocation
;
        mov     ax, DOS_SET_ALLOCATION_STRATEGY
        mov     bx, [Allocation_Strategy_Old]
        int     DOS_SERVICE                     ; Reset to old strategy

        mov     ax, [Msg_Err_Memory_Alloc]
        mov     [Return_Code], ax
        jmp     @@99

@@70:
        mov     ax, DOS_SET_ALLOCATION_STRATEGY
        mov     bx, [Allocation_Strategy_Old]
        int     DOS_SERVICE                     ; Reset to old strategy

;
; Save Screen Area Pointers
;
        mov     es, [Screen_Save_ptr_es]
        mov     di, [Screen_Save_ptr_di]

        mov     [(Screen_Save ptr di).Save_Address_Hi], cx
        mov     [(Screen_Save ptr di).Save_Address_Lo], NULL

;
; Save Original Cursor Position
;
        mov     ah, VIDEO_GET_CURSOR
        int     VIDEO_SERVICE                   ; Get Cursor

        mov     [(Screen_Save ptr di).Cursor_Position_Org.Row], dh
        mov     [(Screen_Save ptr di).Cursor_Position_Org.Col], dl

;
; Set cursor position to requested position
;
        mov     dh, [Wsio_Cursor_Row]
        dec     dh
        mov     dl, [Wsio_Cursor_Col]
        dec     dl

        xor     ax, ax
        xor     bx, bx
        xor     cx, cx
        mov     ah, VIDEO_SET_CURSOR
        int     VIDEO_SERVICE                   ; Set Cursor

;
; Save Screen Area
;
        mov     bx, [Wsio_Rows]
        mov     dx, [Wsio_Cols]

        mov     ax, [Video_Address_ptr_es]
        mov     cx, [Video_Address_ptr_di]

        mov     es, [Screen_Save_ptr_es]
        mov     di, [Screen_Save_ptr_di]

        push    ds si

        mov     es, [(Screen_Save ptr di).Save_Address_Hi]
        mov     di, [(Screen_Save ptr di).Save_Address_Lo]

        push    ax cx
        pop     si ds

@@80:
        mov     cx, dx
        rep     movsw
        mov     cx, MAX_COL
        sub     cx, dx
        shl     cx, 1
        add     si, cx
        dec     bx
        jnz     @@80

        pop     si ds

@@99:
        ret

ENDP    Wsio_Command_Open



;**********************************************************************
PROC    Wsio_Command_Display_And_Read
;**********************************************************************
        call    Wsio_Command_Display_Only
        call    Wsio_Command_Read_Only
        ret

ENDP    Wsio_Command_Display_And_Read



;**********************************************************************
PROC    Wsio_Command_Display_Only
;**********************************************************************
        call    Show_Screen_Text
        call    Show_Screen_Attributes
        call    Show_Screen_Fields
        ret

ENDP    Wsio_Command_Display_Only



;**********************************************************************
PROC    Wsio_Command_Display_Text_Only
;**********************************************************************
        call    Show_Screen_Text
        call    Show_Screen_Attributes
        ret

ENDP    Wsio_Command_Display_Text_Only



;**********************************************************************
PROC    Wsio_Command_Display_Fields_Only
;**********************************************************************
        call    Show_Screen_Fields

        ret

ENDP    Wsio_Command_Display_Fields_Only



;**********************************************************************
PROC    Wsio_Command_Read_Only
;**********************************************************************
;------------------------
; Determine Mouse Support
;------------------------
        cmp     [Wsio_Mouse_Support], LOGIC_NO  ; Support mouse?
        je      @@04                            ; No
                                                ; Yes, so
        mov     cx, [Wsio_Name_Address_Hi]      ; Same screen?
        cmp     cx, [Screen_Name_Last_Used_Wsio_Hi]
        jne     @@02                            ; No
                                                ; Maybe
        mov     cx, [Wsio_Name_Address_Lo]      ; Same screen?
        cmp     cx, [Screen_Name_Last_Used_Wsio_Lo]
        je      @@04                            ; Yes
                                                ; No
@@02:
;
; Set mouse boundaries
;
        mov     ax, [Wsio_Name_Address_Hi]
        mov     [Screen_Name_Last_Used_Wsio_Hi], ax
        mov     ax, [Wsio_Name_Address_Lo]
        mov     [Screen_Name_Last_Used_Wsio_Lo], ax
       
;
; Define border limits mouse column, minimum <-> maximum
;
        xor     ax, ax
        mov     al, [Wsio_End_Col]
        dec     ax
        mov     cx, [Pixels_Per_Col]
        mul     cx
        mov     bx, ax

        xor     ax, ax
        mov     al, [Wsio_Start_Col]
        dec     ax
        mov     cx, [Pixels_Per_Col]
        mul     cx

        mov     cx, ax                          ; Left border
        mov     dx, bx                          ; Right border
        mov     ax, MOUSE_DEFINE_HOR_CURSOR_RANGE
        int     MOUSE_SERVICE

;
; Define border limits mouse row, minimum <-> maximum
;
        xor     ax, ax
        mov     al, [Wsio_End_Row]
        dec     ax
        mov     cx, [Pixels_Per_Row]
        mul     cx
        mov     bx, ax

        xor     ax, ax
        mov     al, [Wsio_Start_Row]
        dec     ax
        mov     cx, [Pixels_Per_Row]
        mul     cx

        mov     cx, ax                          ; Top border
        mov     dx, bx                          ; Bottom border
        mov     ax, MOUSE_DEFINE_VER_CURSOR_RANGE
        int     MOUSE_SERVICE

        xor     ax, ax
        mov     al, [Wsio_End_Col]
        mov     cx, [Pixels_Per_Col]
        mul     cx

        xor     cx, ax
        xor     dx, dx

        mov     ax, MOUSE_POSITION_MOUSE_CURSOR
        int     MOUSE_SERVICE

@@04:
;-----------------------------
; Determine field under cursor
;-----------------------------
        call    Determine_Field_Under_Cursor

        mov     ah, [Wsio_Select_Field_Nr]
        mov     al, [Wsio_Select_Field_Occur_Nr]

        cmp     ah, [Save_Wsio_Select_Field_Nr]         ; Active Field changed?
        jne     @@06                                    ; Yes
                                                        ; No, so
        cmp     al, [Save_Wsio_Select_Field_Occur_Nr]   ; Active Field occurrence changed?
        je      @@10                                    ; No
                                                        ; Yes, so
;----------------------
; Deselect old field nr
;----------------------
@@06:
        mov     bh, [Wsio_Input_Select_Attrib]          ; Save attrib of new field
        cmp     [Save_Wsio_Select_Field_Nr], 0          ; Something to deselect?
        je      @@08                                    ; No
                                                        ; Yes, so
        mov     bl, [Save_Wsio_Select_Field_Nr]
        mov     [Wsio_Select_Field_Nr], bl
        mov     bl, [Save_Wsio_Select_Field_Occur_Nr]
        mov     [Wsio_Select_Field_Occur_Nr], bl

        mov     bl, [Save_Wsio_Select_Field_Attrib]
        cmp     bl, [Save_Wsio_Input_Select_Attrib]     ; Input/Select <-> Field attrib changed?
        je      @@08                                    ; No
                                                        ; Yes, so
        mov     [Wsio_Input_Select_Attrib], bl

        cmp     [Save_Wsio_Field_Modifiable], 0         ; Protected field?
        je      @@08                                    ; Yes
                                                        ; No, so
        push    ax

        call    Wsio_Command_Select_Deselect

        pop     ax

;--------------------
; Select new field nr
;--------------------
@@08:
        mov     [Save_Wsio_Select_Field_Nr], ah
        mov     [Save_Wsio_Select_Field_Occur_Nr], al
        mov     [Wsio_Select_Field_Nr], ah
        mov     [Wsio_Select_Field_Occur_Nr], al
        cmp     ah, 0                                   ; Something to select?
        je      @@10                                    ; No
                                                        ; Yes, so
        cmp     [Wsio_Field_Modifiable], 0              ; Protected field?
        je      @@10                                    ; Yes
                                                        ; No, so
        mov     [Save_Wsio_Select_Field_Attrib], bh     ; Save new field attrib
        mov     al, [Save_Wsio_Input_Select_Attrib]     ; Input/Select attrib
        mov     [Wsio_Input_Select_Attrib], al          ; Set it
        cmp     al, bh                                  ; Will the attribute change?
        je      @@10                                    ; No
                                                        ; Yes, so
        call    Wsio_Command_Select_Deselect

@@10:
;--------------------------
; Set cursor position first
;--------------------------
        mov     dh, [Wsio_Cursor_Row]
        dec     dh
        mov     dl, [Wsio_Cursor_Col]
        dec     dl

        cmp     [Wsio_No_Input], LOGIC_YES      ; Disable cursor?
        jne     @@12                            ; No
                                                ; Yes, so
        mov     dh, CURSOR_OFF_SCREEN
        mov     dl, CURSOR_OFF_SCREEN

@@12:
        xor     ax, ax
        xor     bx, bx
        xor     cx, cx
        mov     ah, VIDEO_SET_CURSOR
        int     VIDEO_SERVICE                   ; Set Cursor

;-------------
; Keyboard I/O
;-------------
        mov     [Wsio_Mouse_Left_Button_Pressed], LOGIC_NO

        call    Wsio_Show_Mouse_Cursor

        call    Keyboard_IO

        call    Wsio_Hide_Mouse_Cursor

;----------------
; Valid Key Table
;----------------
        mov     es, [Wsio_Keys_Address_Hi]
        mov     di, [Wsio_Keys_Address_Lo]

;------------------------
; Check for the "any" key
;------------------------
        cmp     [byte es:di], KEY_ANY                   ; "Any" key allowed?
        je      @@93                                    ; Yes
                                                        ; No, so
;---------------------
; Check Mouse activity
;---------------------
        cmp     [Wsio_Mouse_Left_Button_Pressed], LOGIC_YES     ; Left button pressed?
        je      @@04                            ; Yes
                                                ; No, so
;------------------------
; Check valid Window keys
;------------------------
        cmp     ah, 1                           ; Special key (Alt+something)
        je      @@18

@@16:
;-----------------------------------------
; Check key press against Valid Keys Table
;-----------------------------------------
        cmp     [byte es:di], NULL              ; End of valid keys found?
        je      @@18                            ; Yes
                                                ; No, so
        cmp     al, [byte es:di]                ; Valid key pressed?
        je      @@93                            ; Yes
                                                ; No, so
        inc     di                              ; Try next key frm valid key table
        jmp     @@16

;------------------------------------------------
; Check if we have modifable fields on the screen
;------------------------------------------------
@@18:
        cmp     [Wsio_Field_Nr_Mod_Max], 0      ; Are there modifiable fields?
        je      @@10                            ; No
                                                ; Yes, so
;---------------------------------
; Check if the user disabled input
;---------------------------------
        cmp     [Wsio_No_Input], LOGIC_YES
        je      @@10

;-----------------------------------------------------------
; Determine "internal" key press, and process it accordingly
;-----------------------------------------------------------
        cmp     ah, NULL                        ; Special character pressed?
        jne     @@90                            ; No
                                                ; Yes, so
        cmp     al, KEY_ARROW_LEFT
        je      @@20
        cmp     al, KEY_ARROW_RIGHT
        je      @@20
        cmp     al, KEY_ARROW_UP
        je      @@20
        cmp     al, KEY_ARROW_DOWN
        je      @@20
        cmp     al, KEY_HOME
        je      @@20
        cmp     al, KEY_END
        je      @@20
        cmp     al, KEY_PAGE_UP
        je      @@20
        cmp     al, KEY_PAGE_DOWN
        je      @@20
        cmp     al, KEY_TAB
        je      @@20
        cmp     al, KEY_BACKTAB
        je      @@20
        cmp     al, KEY_BACKSPACE
        je      @@20
        cmp     al, KEY_DELETE
        je      @@20
        cmp     al, KEY_INSERT
        je      @@20

; Other key pressed
        jmp     @@90

@@20:
;
; Interpret special character key press
;
        cmp     al, KEY_ARROW_LEFT
        je      @@25
        cmp     al, KEY_ARROW_RIGHT
        je      @@30
        cmp     al, KEY_ARROW_UP
        je      @@35
        cmp     al, KEY_ARROW_DOWN
        je      @@40
        cmp     al, KEY_HOME
        je      @@45
        cmp     al, KEY_END
        je      @@50
        cmp     al, KEY_PAGE_UP
        je      @@55
        cmp     al, KEY_PAGE_DOWN
        je      @@60
        cmp     al, KEY_TAB
        je      @@65
        cmp     al, KEY_BACKTAB
        je      @@70
        cmp     al, KEY_DELETE
        je      @@75
        cmp     al, KEY_INSERT
        je      @@80
        cmp     al, KEY_BACKSPACE
        je      @@85

@@25:
;---------------
; KEY ARROW LEFT
;---------------
        call    Wsio_Key_Arrow_Left
        jmp     @@04

@@30:
;----------------
; KEY ARROW RIGHT
;----------------
        call    Wsio_Key_Arrow_Right
        jmp     @@04

@@35:
;-------------
; KEY ARROW UP
;-------------
        call    Wsio_Key_Arrow_Up
        jmp     @@04

@@40:
;---------------
; KEY ARROW DOWN
;---------------
        call    Wsio_Key_Arrow_Down
        jmp     @@04

@@45:
;---------
; KEY HOME
;---------
        call    Wsio_Key_Home
        jmp     @@04

@@50:
;--------
; KEY END
;--------
        call    Wsio_Key_End
        jmp     @@04

@@55:
;------------
; KEY PAGE UP
;------------
        call    Wsio_Key_Page_Up
        jmp     @@04

@@60:
;--------------
; KEY PAGE DOWN
;--------------
        call    Wsio_Key_Page_Down
        jmp     @@04

@@65:
;--------
; KEY TAB
;--------
        call    Wsio_Key_Tab
        jmp     @@04

@@70:
;------------
; KEY BACKTAB
;------------
        call    Wsio_Key_Backtab
        jmp     @@04

@@75:
;-----------
; KEY DELETE
;-----------
        call    Wsio_Key_Delete
        jmp     @@04

@@80:
;-----------
; KEY INSERT
;-----------
        call    Wsio_Key_Insert
        jmp     @@04

@@85:
;--------------
; KEY BACKSPACE
;--------------
        call    Wsio_Key_Backspace
        jmp     @@04

@@90:
;----------
; OTHER KEY
;----------
        call    Wsio_Key_Other

        cmp     ax, 0                           ; Invalid key?
        je      @@10                            ; Yes
                                                ; No, so
        jmp     @@04

;-----------------------------------------------------
; Interpret special key (and see if ENTER was pressed)
;-----------------------------------------------------
@@93:
;
; On the "ENTER" key, we process the entered fields
;
        mov     es, [Wsio_Enter_Address_Hi]
        mov     di, [Wsio_Enter_Address_Lo]

@@94:
        cmp     [byte es:di], NULL              ; End of valid enter keys found?
        je      @@95                            ; Yes
                                                ; No, so
        cmp     al, [byte es:di]                ; Enter emulation found
        je      @@96                            ; Yes
                                                ; No, so
        inc     di                              ; Try next key frm valid enter key table
        jmp     @@94

@@95:
        cmp     al, KEY_ENTER
        jne     @@97

;----------------------------------------
; "ENTER" pressed, process entered fields
;----------------------------------------
@@96:
        call    Process_Entered_Screen_Fields

@@97:
;
; Update Wsio Command Block
;
        mov     es, [Wsio_Area_ptr_es]
        mov     di, [Wsio_Area_ptr_di]

        mov     bl, [Wsio_Screen_Changed]
        mov     [(Wsio_Area ptr di).Screen_Changed], bl
        mov     bl, [Wsio_Cursor_Row]
        mov     [(Wsio_Area ptr di).Cursor_Position_Row], bl
        mov     bl, [Wsio_Cursor_Col]
        mov     [(Wsio_Area ptr di).Cursor_Position_Col], bl

@@99:
        ret

ENDP    Wsio_Command_Read_Only



;**********************************************************************
PROC    Wsio_Show_Mouse_Cursor
;**********************************************************************
        cmp     [Wsio_Mouse_Support], LOGIC_NO  ; Support mouse?
        je      @@99                            ; No
                                                ; Yes, so
        cmp     [Wsio_Mouse_Visible], LOGIC_YES ; Mouse_Visible?
        je      @@99                            ; Yes
                                                ; No, so
;
; Show mouse cursor
;
        mov     ax, MOUSE_SHOW_MOUSE_CURSOR
        int     MOUSE_SERVICE
        mov     [Wsio_Mouse_Visible], LOGIC_YES

@@99:
        ret

ENDP    Wsio_Show_Mouse_Cursor



;**********************************************************************
PROC    Wsio_Hide_Mouse_Cursor
;**********************************************************************
        cmp     [Wsio_Mouse_Present], LOGIC_NO  ; Mouse present?
        je      @@99                            ; No
                                                ; Yes, so
        push    ax                              ; Save pressed key
        cmp     [Wsio_Mouse_Visible], LOGIC_NO  ; Mouse visible
        je      @@98                            ; No
                                                ; Yes, so
        mov     ax, MOUSE_HIDE_MOUSE_CURSOR
        int     MOUSE_SERVICE                   ; Kill mouse
        mov     [Wsio_Mouse_Visible], LOGIC_NO

@@98:
        pop     ax                              ; Restore pressed key

@@99:
        ret

ENDP    Wsio_Hide_Mouse_Cursor



;**********************************************************************
PROC    Wsio_Key_Arrow_Left
;**********************************************************************
;
; Get current cursor position
;
        mov     ah, [Wsio_Cursor_Row]
        mov     al, [Wsio_Cursor_Col]

;
; Move to the left
;
        cmp     al, [Wsio_Start_Col]            ; Left edge reached?
        je      @@10                            ; Yes
                                                ; No, so
        dec     [Wsio_Cursor_Col]               ; Move cursor left
        jmp     @@99                            ; Show cursor

@@10:
;
; Move to previous row, and wrap to the end of the row
;
        cmp     ah, [Wsio_Start_Row]            ; Top edge reached?
        jnle    @@20                            ; No
                                                ; Yes, so
        mov     ah, [Wsio_End_Row]              ; Go to bottom edge
        inc     ah                              ; Because of subtraction below

@@20:
        dec     ah                              ; Move to previous row
        mov     [Wsio_Cursor_Row], ah           ; Done
        mov     al, [Wsio_End_Col]              ; Go to right edge
        mov     [Wsio_Cursor_Col], al           ; Done

@@99:
        ret

ENDP    Wsio_Key_Arrow_Left



;**********************************************************************
PROC    Wsio_Key_Arrow_Right
;**********************************************************************
;
; Get current cursor position
;
        mov     ah, [Wsio_Cursor_Row]
        mov     al, [Wsio_Cursor_Col]

;
; Move to the right
;
        cmp     al, [Wsio_End_Col]              ; Right edge reached?
        je      @@10                            ; Yes
                                                ; No, so
        inc     [Wsio_Cursor_Col]               ; Move cursor right
        jmp     @@99                            ; Show cursor

@@10:
;
; Move to next row, and wrap to the begin of the row
;
        cmp     ah, [Wsio_End_Row]              ; Bottom edge reached?
        jl      @@20                            ; No
                                                ; Yes, so
        mov     ah, [Wsio_Start_Row]            ; Go to top edge
        dec     ah                              ; Because of addition below

@@20:
        inc     ah                              ; Move to next row
        mov     [Wsio_Cursor_Row], ah           ; Done
        mov     al, [Wsio_Start_Col]            ; Go to left edge
        mov     [Wsio_Cursor_Col], al           ; Done

@@99:
        ret

ENDP    Wsio_Key_Arrow_Right



;**********************************************************************
PROC    Wsio_Key_Arrow_Up
;**********************************************************************
;
; Get current cursor position
;
        mov     ah, [Wsio_Cursor_Row]
        mov     al, [Wsio_Cursor_Col]

;
; Move up
;
        cmp     ah, [Wsio_Start_Row]            ; Top edge reached?
        je      @@10                            ; Yes
                                                ; No, so
        dec     [Wsio_Cursor_Row]               ; Move cursor up
        jmp     @@99                            ; Show cursor

@@10:
;
; Move to bottom edge
;
        mov     ah, [Wsio_End_Row]              ; Bottom edge
        mov     [Wsio_Cursor_Row], ah           ; Done

@@99:
        ret

ENDP    Wsio_Key_Arrow_Up



;**********************************************************************
PROC    Wsio_Key_Arrow_Down
;**********************************************************************
;
; Get current cursor position
;
        mov     ah, [Wsio_Cursor_Row]
        mov     al, [Wsio_Cursor_Col]

;
; Move down
;
        cmp     ah, [Wsio_End_Row]              ; Bottom edge reached?
        je      @@10                            ; Yes
                                                ; No, so
        inc     [Wsio_Cursor_Row]               ; Move cursor down
        jmp     @@99

@@10:
;
; Move to top edge
;
        mov     ah, [Wsio_Start_Row]            ; Top edge
        mov     [Wsio_Cursor_Row], ah           ; Done

@@99:
        ret

ENDP    Wsio_Key_Arrow_Down



;**********************************************************************
PROC    Wsio_Key_Home
;**********************************************************************
;
; Check if we are in a modifiable field
;
        cmp     [Wsio_Select_Field_Nr], 0
        je      @@99                            ; No
                                                ; Yes, so
;
; Check if we are at the first position of the field
;
        cmp     [Wsio_Select_Field_Position], 1 ; First position?
        je      @@99                            ; Yes
                                                ; No, so
;
; Determine new cursor position
;
        mov     al, [Wsio_Select_Field_Position]
        dec     al
        sub     [Wsio_Cursor_Col], al

@@99:
        ret

ENDP    Wsio_Key_Home



;**********************************************************************
PROC    Wsio_Key_End
;**********************************************************************
;
; Check if we are in a modifiable field
;
        cmp     [Wsio_Select_Field_Nr], 0
        je      @@99                            ; No
                                                ; Yes, so
;
; Determine new cursor position
;
        mov     al, [Wsio_Field_Size]           ; Get field size
        sub     al, [Wsio_Select_Field_Position]  ; Subtract current position
        add     [Wsio_Cursor_Col], al           ; Add to cursor position

;
; Determine last video screen position
;
        mov     es, [Wsio_Field_Video_ptr_es]
        mov     di, [Wsio_Field_Video_ptr_di]
        xor     ax, ax
        mov     al, [Wsio_Field_Size]
        mov     cx, ax                          ; For searching non space
        dec     ax                              ; Because of offset 0
        add     di, ax
        add     di, ax                          ; To skip attributes

;
; Field completely filled?
;
        cmp     [byte es:di], SPACE             ; Space found?
        jne     @@99                            ; No, show cursor
                                                ; Yes, so
@@10:
;
; Search non space character from end to beginning
;
        cmp     [byte es:di], SPACE             ; Space found?
        jne     @@20                            ; No
                                                ; Yes, so
        dec     di                              ; Move 1 character to the left
        dec     di                              ; Including the attribute
        dec     [Wsio_Cursor_Col]               ; Move cursor 1 to the left too
        loop    @@10                            ; Check next character
                                                ; Field is completely blank
@@20:
        inc     [Wsio_Cursor_Col]               ; Move to space character

@@99:
        ret

ENDP    Wsio_Key_End



;**********************************************************************
PROC    Wsio_Key_Page_Up
;**********************************************************************
;
; Pointer to Field Table
;
        mov     bx, [Wsio_Field_Address_Hi]
        mov     di, [Wsio_Field_Address_Lo]
        mov     es, bx

@@10:
;
; Only check modifiable fields
;
        cmp     [(Wsio_Field ptr di).Modifiable], 1     ; Modifiable?
        je      @@20                            ; Yes
                                                ; No, so
        add     di, WSIO_FIELD_STRUCTURE_SIZE   ; Point to next field
        jmp     @@10                            ; Check next field

@@20:
;
; Determine Field cursor location
;
        mov     ah, [Wsio_Start_Row]
        add     ah, [(Wsio_Field ptr di).Start_Row]
        dec     ah

        mov     al, [Wsio_Start_Col]
        add     al, [(Wsio_Field ptr di).Start_Col]
        dec     al

        mov     [Wsio_Cursor_Row], ah           ; New cursor row
        mov     [Wsio_Cursor_Col], al           ;            col

@@99:
        ret

ENDP    Wsio_Key_Page_Up



;**********************************************************************
PROC    Wsio_Key_Page_Down
;**********************************************************************
;
; Pointer to Field Table
;
        mov     bx, [Wsio_Field_Address_Hi]
        mov     di, [Wsio_Field_Address_Lo]
        mov     es, bx

        mov     dh, 0                           ; Possible candidate for row
        mov     dl, 0                           ; Possible candidate for col

@@10:
;
; Check (Next) Field
;
        cmp     [byte es:di], NULL              ; Fields left to check?
        je      @@50                            ; No
                                                ; Yes, so
        mov     cx, 1                           ; Assume occurrence of 1
;
; Only check modifiable fields
;
        cmp     [(Wsio_Field ptr di).Modifiable], 1     ; Modifiable?
        jne     @@40                            ; No
                                                ; Yes, so
;
; Determine location of this field
;
        mov     ah, [Wsio_Start_Row]
        add     ah, [(Wsio_Field ptr di).Start_Row]
        dec     ah

        mov     al, [Wsio_Start_Col]
        add     al, [(Wsio_Field ptr di).Start_Col]
        dec     al

        xor     cx, cx                          ; Reset cx
        mov     cl, [(Wsio_Field ptr di).Occurs]

@@20:
        cmp     ah, dh                          ; This modifiable field further down the road?
        jl      @@40                            ; No
                                                ; Maybe, so
        cmp     ah, dh                          ; This modifiable field further down the road?
        jne     @@30                            ; Yes
                                                ; Maybe, so
        cmp     al, dl                          ; This modifiable field further down the road?
        jle     @@40                            ; No
                                                ; Yes, so
;
; Remember this location
;
@@30:
        mov     dx, ax

@@40:
;
; Check next occurrence
;
        inc     ah                              ; Get next occurrence
        loop    @@20

;
; Check next field
;
        add     di, WSIO_FIELD_STRUCTURE_SIZE   ; Point to next field
        jmp     @@10                            ; Check next field

@@50:
        mov     [Wsio_Cursor_Row], dh
        mov     [Wsio_Cursor_Col], dl

@@99:
        ret

ENDP    Wsio_Key_Page_Down



;**********************************************************************
PROC    Wsio_Key_Tab
;**********************************************************************
;
; Pointer to Field Table
;
        mov     bx, [Wsio_Field_Address_Hi]
        mov     di, [Wsio_Field_Address_Lo]
        mov     es, bx

        mov     dh, 0                           ; Possible candidate for row
        mov     dl, 0                           ; Possible candidate for col

@@10:
;
; Check (Next) Field
;
        cmp     [byte es:di], NULL              ; Fields left to check?
        je      @@70                            ; No
                                                ; Yes, so
;
; Only check modifiable fields
;
        cmp     [(Wsio_Field ptr di).Modifiable], 1     ; Modifiable?
        jne     @@60                            ; No
                                                ; Yes, so
;
; Determine if we could tab to this field
;
        mov     ah, [Wsio_Start_Row]
        add     ah, [(Wsio_Field ptr di).Start_Row]
        dec     ah

        mov     al, [Wsio_Start_Col]
        add     al, [(Wsio_Field ptr di).Start_Col]
        dec     al

        xor     cx, cx                          ; Reset cx
        mov     cl, [(Wsio_Field ptr di).Occurs]

@@20:
;
; Check if cursor lies before tabable field
;
        cmp     [Wsio_Cursor_Row], ah           ; Cursor before field row?
        jl      @@30                            ; Yes
                                                ; No, so
        cmp     [Wsio_Cursor_Row], ah           ; Cursor on field row?
        jne     @@50                            ; No
                                                ; Yes, so
        cmp     [Wsio_Cursor_Col], al           ; Column before field column?
        jnl     @@50                            ; No
                                                ; Yes, so
;
; Compare to location to be
;
@@30:
        cmp     dx, 0                           ; Something to compare?
        je      @@40                            ; No
                                                ; Yes, so
        cmp     ah, dh                          ; Row closer to cursor?
        jnle    @@60                            ; No
                                                ; Maybe, so
        cmp     al, dl                          ; Column closer to cursor?
        jnl     @@60                            ; No
                                                ; Yes, so
;
; Remember this location
;
@@40:
        mov     dx, ax
        jmp     @@60

@@50:
;
; Check next occurrence
;
        inc     ah                              ; Get next occurrence
        loop    @@20

@@60:
;
; Check next field
;
        add     di, WSIO_FIELD_STRUCTURE_SIZE   ; Point to next field
        jmp     @@10                            ; Check next field

@@70:
        cmp     dx, 0                           ; Tabable field found?
        jne     @@80                            ; Yes,
                                                ; No, so
        call    Wsio_Key_Page_Up                ; Go to first field
        jmp     @@99

@@80:
        mov     [Wsio_Cursor_Row], dh
        mov     [Wsio_Cursor_Col], dl

@@99:
        ret

ENDP    Wsio_Key_Tab



;**********************************************************************
PROC    Wsio_Key_Backtab
;**********************************************************************
;
; Pointer to Field Table
;
        mov     bx, [Wsio_Field_Address_Hi]
        mov     di, [Wsio_Field_Address_Lo]
        mov     es, bx

        mov     dh, 0                           ; Possible candidate for row
        mov     dl, 0                           ; Possible candidate for col

@@10:
;
; Check (Next) Field
;
        cmp     [byte es:di], NULL              ; Fields left to check?
        je      @@70                            ; No
                                                ; Yes, so
;
; Only check modifiable fields
;
        cmp     [(Wsio_Field ptr di).Modifiable], 1     ; Modifiable?
        jne     @@60                            ; No
                                                ; Yes, so
;
; Determine if we could backtab to this field
;
        mov     ah, [Wsio_Start_Row]
        add     ah, [(Wsio_Field ptr di).Start_Row]
        dec     ah

        mov     al, [Wsio_Start_Col]
        add     al, [(Wsio_Field ptr di).Start_Col]
        add     al, [(Wsio_Field ptr di).Size]
        dec     al

        xor     cx, cx                          ; Reset cx
        mov     cl, [(Wsio_Field ptr di).Occurs]

@@20:
;
; Check if cursor lies after tabable field
;
        cmp     [Wsio_Cursor_Row], ah           ; Cursor after field row?
        jnle    @@30                            ; Yes
                                                ; No, so
        cmp     [Wsio_Cursor_Row], ah           ; Cursor on field row?
        jne     @@50                            ; No
                                                ; Yes, so
        cmp     [Wsio_Cursor_Col], al           ; Column after field column?
        jle     @@50                            ; No
                                                ; Yes, so
;
; Compare to location to be
;
@@30:
        cmp     dx, 0                           ; Something to compare?
        je      @@40                            ; No
                                                ; Yes, so
        cmp     ah, dh                          ; Row closer to cursor?
        jl      @@50                            ; No
                                                ; Maybe, so
        cmp     al, dl                          ; Column closer to cursor?
        jl      @@50                            ; No
                                                ; Yes, so
;
; Remember this location
;
@@40:
        sub     al, [(Wsio_Field ptr di).Size]
        mov     dx, ax
        add     al, [(Wsio_Field ptr di).Size]

@@50:
;
; Check next occurrence
;
        inc     ah                              ; Get next occurrence
        loop    @@20

@@60:
;
; Check next field
;
        add     di, WSIO_FIELD_STRUCTURE_SIZE   ; Point to next field
        jmp     @@10                            ; Check next field

@@70:
        cmp     dx, 0                           ; Tabable field found?
        jne     @@80                            ; Yes,
                                                ; No, so
        call    Wsio_Key_Page_Down              ; Go to last field
        jmp     @@99

@@80:
        mov     [Wsio_Cursor_Row], dh
        mov     [Wsio_Cursor_Col], dl

@@99:
        ret

ENDP    Wsio_Key_Backtab



;**********************************************************************
PROC    Wsio_Key_Delete
;**********************************************************************
;
; Check if we are in a modifiable field
;
        cmp     [Wsio_Select_Field_Nr], 0
        je      @@99                            ; No
                                                ; Yes, so
;
; Determine current video location
;
        mov     es, [Wsio_Field_Video_ptr_es]
        mov     di, [Wsio_Field_Video_ptr_di]
        xor     bx, bx
        mov     bl, [Wsio_Select_Field_Position]
        dec     bx                              ; Because of offset 0
        add     di, bx
        add     di, bx                          ; To skip attributes

;
; Determine number of characters to move
;
        xor     cx, cx
        mov     cl, [Wsio_Field_Size]
        sub     cl, [Wsio_Select_Field_Position]

;-----------------------------------
; Check for "Trailing Spaces" option
;-----------------------------------
        cmp     [Wsio_Field_Blank], 2           ; Blanks allowed?
        je      @@99                            ; No
                                                ; Yes, so
        cmp     cx, 0                           ; Something to move?
        je      @@95                            ; No
                                                ; Yes, so
;----------------------------------------------------------------------------
; Move all characters from next location thru the end, 1 position to the left
;----------------------------------------------------------------------------
@@90:
        push    ds si                           ; Save pointer

        push    es di                           ; Receiving pointer
        pop     si ds                           ; Sending pointer

;
; Go to the next position
;
        inc     si                              ; Character and
        inc     si                              ; Attribute to add
                                                ; to go to the next position
@@91:
        movsb
        inc     di                              ; Moved to next receiving char
        inc     si                              ; Moved to next sending char
        loop    @@91                            ; Move next character

        pop     si ds                           ; Restore pointer

@@95:
        mov     [byte es:di], SPACE             ; Insert SPACE character

@@99:
        ret

ENDP    Wsio_Key_Delete



;**********************************************************************
PROC    Wsio_Key_Insert
;**********************************************************************
;
; Check if we are in a modifiable field
;
        cmp     [Wsio_Select_Field_Nr], 0
        je      @@99                            ; No
                                                ; Yes, so
;---------------------------------------
; Determine if we may insert a character
;---------------------------------------
;
; Determine current video location
;
        mov     es, [Wsio_Field_Video_ptr_es]
        mov     di, [Wsio_Field_Video_ptr_di]
        xor     bx, bx
        mov     bl, [Wsio_Select_Field_Position]
        dec     bx                              ; Because of offset 0
        add     di, bx
        add     di, bx                          ; To skip attributes

;
; Determine number of characters to move/check
;
        xor     cx, cx
        mov     cl, [Wsio_Field_Size]
        sub     cl, [Wsio_Select_Field_Position]

;-----------------------------------
; Check for "Trailing Spaces" option
;-----------------------------------
        cmp     [Wsio_Field_Blank], 0           ; Blanks anywhere?
        je      @@90                            ; Yes
                                                ; No, so
;
; Character to be inserted is a SPACE, check if that is allowed
;
        cmp     [Wsio_Field_Blank], 2           ; No blanks allowed at all?
        je      @@99                            ; Yes
                                                ; Trailing only
        cmp     cx, 0                           ; Something to check?
        je      @@95                            ; No
                                                ; Yes, so        
        push    es di cx
        inc     cx                              ; Check under cursor too
        jmp     @@30

@@10:
        cmp     [byte es:di], SPACE             ; Character is space?
        je      @@20                            ; Yes
                                                ; No, so
        pop     cx di es
        jmp     @@99                            ; Error

@@20:
        inc     di
        inc     di                              ; (Next) character to check

@@30:
        loop    @@10

        pop     cx di es

;-----------------------------------------------------------------------------
; Move all characters from this location thru the end, 1 position to the right
;-----------------------------------------------------------------------------
@@90:
        push    ds si                           ; Save pointer

;
; Go to the end of the field
;
        add     di, cx                          ; Characters and
        add     di, cx                          ; Attributes to add
                                                ; to go to the end of the field
        push    es di                           ; Receiving pointer
        pop     si ds                           ; Sending pointer
        dec     si                              ; is one character to the left
        dec     si                              ; of the receiving pointer
@@91:
        movsb
        dec     di
        dec     di
        dec     di                              ; Moved to prev receiving char
        dec     si
        dec     si
        dec     si                              ; Moved to prev sending char
        loop    @@91                            ; Move next character

        pop     si ds                           ; Restore pointer

@@95:
        mov     [byte es:di], SPACE             ; Insert SPACE character

@@99:
        ret

ENDP    Wsio_Key_Insert



;**********************************************************************
PROC    Wsio_Key_Backspace
;**********************************************************************
;
; Check if we are in a modifiable field
;
        cmp     [Wsio_Select_Field_Nr], 0
        je      @@99                            ; No
                                                ; Yes, so
;
; Backspace from position 1 is not possible
;
        cmp     [Wsio_Select_Field_Position], 1 ; Position 1?
        je      @@99                            ; Yes
                                                ; No, so
;-----------------------------------
; Check for "Trailing Spaces" option
;-----------------------------------
        cmp     [Wsio_Field_Blank], 2           ; Blanks allowed?
        je      @@99                            ; No
                                                ; Yes, so
;
; Determine current video location
;
        mov     es, [Wsio_Field_Video_ptr_es]
        mov     di, [Wsio_Field_Video_ptr_di]
        xor     bx, bx
        mov     bl, [Wsio_Select_Field_Position]
        dec     bx                              ; Because of offset 0
        add     di, bx
        add     di, bx                          ; To skip attributes

;
; Determine number of characters to move
;
        xor     cx, cx
        mov     cl, [Wsio_Field_Size]
        sub     cl, [Wsio_Select_Field_Position]
        inc     cx                              ; Move current character too

;-------------------------------------------------------------------------------
; Move all characters from current location thru the end, 1 position to the left
;-------------------------------------------------------------------------------
@@90:
        push    ds si                           ; Save pointer

        push    es di                           ; Receiving pointer
        pop     si ds                           ; Sending pointer

;
; Go to the previous position
;
        dec     di                              ; Character and
        dec     di                              ; Attribute to add
                                                ; to go to the next position
@@91:
        movsb
        inc     di                              ; Moved to next receiving char
        inc     si                              ; Moved to next sending char
        loop    @@91                            ; Move next character

        pop     si ds                           ; Restore pointer

@@95:
        mov     [byte es:di], SPACE             ; Insert SPACE character

;
; After backspacing, we move 1 position to the left
;
        call    Wsio_Key_Arrow_Left

@@99:
        ret

ENDP    Wsio_Key_Backspace



;**********************************************************************
PROC    Wsio_Key_Other
;**********************************************************************
;
; Check if we are in a field (modifiable or protected)
;
        cmp     [Wsio_Select_Field_Nr], 0
        je      @@02                                    ; No
                                                        ; Yes, so
;
; Check if we are in a protected field
;
        cmp     [Wsio_Field_Modifiable], 0              ; Protected field?
        jne     @@10                                    ; No
                                                        ; Yes, so
@@02:
        push    ax
        call    Wsio_Key_Tab                            ; Jump to first modifiable field
        call    Determine_Field_Under_Cursor

        mov     ah, [Wsio_Select_Field_Nr]
        mov     al, [Wsio_Select_Field_Occur_Nr]

        mov     [Save_Wsio_Select_Field_Nr], ah
        mov     [Save_Wsio_Select_Field_Occur_Nr], al

        mov     bh, [Wsio_Input_Select_Attrib]          ; Save attrib of tab-ed field
        mov     [Save_Wsio_Select_Field_Attrib], bh

        mov     al, [Save_Wsio_Input_Select_Attrib]     ; Input/Select attrib
        mov     [Wsio_Input_Select_Attrib], al          ; Set it
        cmp     al, bh                                  ; Will the attribute change?
        je      @@04                                    ; No
                                                        ; Yes, so
        call    Wsio_Command_Select_Deselect

@@04:
        pop     ax

@@10:
;----------------------------
; Valid keys for active field
;----------------------------
        mov     es, [Wsio_Field_Keys_ptr_es]
        mov     di, [Wsio_Field_Keys_ptr_di]

;-------------------------------------------------------------
; Check if a we have to do an uppercase translation of the key
;-------------------------------------------------------------
        mov     ah, al
        cmp     al, "a"                         ; Key lowercase (min)?
        jl      @@20                            ; No
                                                ; Maybe, so
        cmp     al, "z"                         ; Key lowercase (max)?
        jnle    @@20                            ; No
                                                ; Yes, so
        sub     ah, " "                         ; "a" -> "A", etc.
        cmp     [Wsio_Field_Uppercase], 1       ; Lowercase ok?
        je      @@20                            ; Yes
                                                ; No, so
        mov     al, ah                          ; Only uppercase allowed

;------------------------------------------------
; Check if a valid key for this Field was pressed
;------------------------------------------------
@@20:
        push    es
        pop     cx
        cmp     cx, NULL                        ; Any key allowed?
        je      @@40                            ; Yes
                                                ; No, so
@@30:
        cmp     [byte es:di], NULL              ; End of valid keys found?
        je      @@98                            ; Yes
                                                ; No, so
        cmp     ah, [byte es:di]                ; Valid key pressed?
        je      @@40                            ; Yes
                                                ; No, so
        inc     di                              ; Try next key
        jmp     @@30

;-----------------------------------------------------------------
; Determine "internal" field key press, and process it accordingly
;-----------------------------------------------------------------
@@40:
;
; Determine current video location
;
        mov     es, [Wsio_Field_Video_ptr_es]
        mov     di, [Wsio_Field_Video_ptr_di]
        xor     bx, bx
        mov     bl, [Wsio_Select_Field_Position]
        dec     bx                              ; Because of offset 0
        add     di, bx
        add     di, bx                          ; To skip attributes

;----------------------------
; Check for decimal seperator
;----------------------------
        cmp     al, [Wsio_Field_Decimal_Point]  ; Character is decimal point?
        jne     @@45                            ; No
                                                ; Yes, so
        cmp     [Wsio_Field_Digits_After], 0    ; Digits after allowed?
        je      @@98                            ; No
                                                ; Yes, so
@@45:
;-----------------------------------
; Check for "Trailing Spaces" option
;-----------------------------------
        cmp     [Wsio_Field_Blank], 0           ; Blanks anywhere?
        je      @@90                            ; Yes
                                                ; No, so
;-----------------------------------
; Check if the SPACE key was pressed
;-----------------------------------
        cmp     al, SPACE                       ; Character is space?
        jne     @@60                            ; No
                                                ; Yes, so
        cmp     [Wsio_Field_Blank], 2           ; No blanks allowed at all?
        je      @@98                            ; Yes
                                                ; Trailing only
;----------------------------
; Check if a SPACE is allowed
;----------------------------
;
; Determine number of characters to check
;
        xor     cx, cx
        mov     cl, [Wsio_Field_Size]
        sub     cl, [Wsio_Select_Field_Position]

        cmp     cx, 0                           ; Something to check?
        je      @@90                            ; No
                                                ; Yes, so        
        push    es di

@@50:
        inc     di
        inc     di                              ; (Next) character to check
        cmp     [byte es:di], SPACE             ; Character is space?
        je      @@55                            ; Yes
                                                ; No, so
        pop     di es
        jmp     @@98                            ; Error

@@55:
        loop    @@50

        pop     di es

        jmp     @@90

@@60:
;--------------------------------
; Check if a non SPACE is allowed
;--------------------------------
        push    es di

;
; Determine number of characters to check
;
        xor     cx, cx
        mov     cl, [Wsio_Select_Field_Position]
        jmp     @@75

@@70:
        dec     di
        dec     di                              ; (Previous) character to check
        cmp     [byte es:di], SPACE             ; Character is space?
        jne     @@75                            ; No
                                                ; Yes, so
        pop     di es
        jmp     @@98                            ; Error
                                                ; No, so
@@75:
        loop    @@70

        pop     di es

;------------------------------
; Place character on the screen
;------------------------------
@@90:
        mov     [byte es:di], al

;
; After "inserting" a character, we move 1 position to the right
;
        call    Wsio_Key_Arrow_Right
        jmp     @@99

;------------------
; Error encountered
;------------------
@@98:
        xor     ax, ax                          ; Indicate invalid key

@@99:
        ret

ENDP    Wsio_Key_Other



;**********************************************************************
PROC    Wsio_Command_Select_Deselect
;**********************************************************************
@@00:
;------------------
; Check Field Table
;------------------
        mov     bx, [Wsio_Field_Address_Hi]
        mov     di, [Wsio_Field_Address_Lo]
        mov     es, bx

        cmp     bx, NULL                        ; Fields present?
        je      @@99                            ; No
                                                ; Yes, so
        xor     cx, cx                          ; Reset cx
        mov     cl, [Wsio_Select_Field_Nr]
        jmp     @@20

;-------------------
; Check (Next) Field
;-------------------
@@10:
        cmp     [byte es:di], NULL              ; Fields left to check?
        je      @@99                            ; No
                                                ; Yes, so
;----------------------------------
; Remember Field Information
;----------------------------------
        add     di, WSIO_FIELD_STRUCTURE_SIZE   ; Point to next field already

@@20:
        loop    @@10

;
; Field to Select/Deselect found
;
        xor     cx, cx
        mov     cl, [(Wsio_Field ptr di).Size]
        push    cx

        mov     cl, [(Wsio_Field ptr di).Start_Row]
        add     cl, [Wsio_Select_Field_Occur_Nr]  ; Jump to right occurrence
        dec     cx
        xor     dx, dx                          ; Reset dx
        mov     dl, [(Wsio_Field ptr di).Start_Col]

        mov     es, [Video_Address_ptr_es]
        mov     di, [Video_Address_ptr_di]

@@30:
        add     di, (MAX_COL * 2)
        loop    @@30

        sub     di, (MAX_COL * 2)
        add     di, dx
        add     di, dx
        sub     di, 1                           ; Correct video location reached

        pop     cx

        mov     dl, [byte es:di]
        mov     [Save_Wsio_Select_Field_Attrib], dl
        mov     dl, [Wsio_Input_Select_Attrib]

@@40:
        mov     [byte es:di], dl
        inc     di
        inc     di
        loop    @@40

@@99:
        ret

ENDP    Wsio_Command_Select_Deselect



;**********************************************************************
PROC    Wsio_Command_Key_Check
;**********************************************************************
        xor     ax, ax                          ; Reset ax
        mov     ah, KEYBOARD_KBD_STATUS         ; Check buffer
        int     KEYBOARD_SERVICE
                                                ; Key waiting?
        jnz     @@10                            ; Yes
                                                ; No, so
        xor     ax, ax                          ; No key pressed
        jmp     @@99                            ; Exit

@@10:
        mov     ah, KEYBOARD_READ_CHAR          ; Retrieve Key press
        int     KEYBOARD_SERVICE
        or      al, al                          ; Special Key pressed?
        jnz     @@20                            ; No
                                                ; Yes, so
        xchg    ah, al                          ; ah<-0, al<-scan code
        add     al, 32                          ; Adjust scan code to >= 32
        jmp     @@30

@@20:
        xor     ah, ah                          ; Assume Special Key
        cmp     al, 32                          ; Special Key pressed?
        jb      @@30                            ; Yes
                                                ; No, so
        inc     ah                              ; It's an ASCII key

@@30:
        or      ah, ah                          ; Set or clear zf result flag

@@99:
        ret

ENDP    Wsio_Command_Key_Check



;**********************************************************************
PROC    Wsio_Command_Close
;**********************************************************************
;
; Check on screen name
;
        mov     cx, SCREEN_SAVE_TABLE_MAX

        mov     bx, [Wsio_Name_Address_Hi]
        mov     di, [Wsio_Name_Address_Lo]
        mov     es, bx

        mov     si, offset Screen_Save_Table.Screen_Name

@@20:
        push    cx
        cmp     [byte ds:si], NULL              ; Table entry empty?
        je      @@40                            ; Yes
                                                ; No, so
        push    ds si es di
        mov     cx, SCREEN_NAME_SIZE            ; Compare Size
        rep     cmpsb                           ; Screen found?
        pop     di es si ds
        jne     @@40                            ; No
                                                ; Yes, so
;
; Screen to close found
;
        pop     cx
        mov     bx, SCREEN_SAVE_TABLE_MAX
        sub     bx, cx                          ; Store free entry nr
        jmp     @@50

@@40:
        pop     cx
        add     si, SCREEN_SAVE_STRUCTURE_SIZE
        loop    @@20

;
; Error, screen name somehow disappeared!
;
        mov     ax, [Msg_Err_Wsio_Not_Found]
        mov     [Return_Code], ax
        jmp     @@99

@@50:
;
; Restore Screen Area
;
        push    ds si
        pop     di es

        mov     dh, [(Screen_Save ptr di).Cursor_Position_Org.Row]
        mov     dl, [(Screen_Save ptr di).Cursor_Position_Org.Col]

        push    dx                              ; Save cursor position

        mov     bx, [(Screen_Save ptr di).Save_Address_Hi]
        mov     dx, [(Screen_Save ptr di).Save_Address_Lo]

;
; Reset entry
;
        mov     cx, SCREEN_SAVE_STRUCTURE_SIZE
        mov     ax, NULL
        rep     stosb

        mov     ax, bx
        mov     cx, dx

        mov     bx, [Wsio_Rows]
        mov     dx, [Wsio_Cols]

        mov     es, [Video_Address_ptr_es]
        mov     di, [Video_Address_ptr_di]

        push    ds si

        push    ax cx
        pop     si ds

@@60:
        mov     cx, dx
        rep     movsw
        mov     cx, MAX_COL
        sub     cx, dx
        shl     cx, 1
        add     di, cx
        dec     bx
        jnz     @@60

        pop     si ds

;
; Release Allocated Memory
;
        mov     es, ax
        xor     ax, ax
        mov     ah, DOS_FREE_ALLOCATED_MEMORY
        int     DOS_SERVICE                     ; Release Allocated Memory

;
; Restore cursor
;
        pop     dx                              ; Restore curosr position

        xor     ax, ax
        xor     bx, bx
        xor     cx, cx

        mov     ah, VIDEO_SET_CURSOR
        int     VIDEO_SERVICE                   ; Set Cursor

@@99:
        ret

ENDP    Wsio_Command_Close



;**********************************************************************
PROC    Determine_Field_Under_Cursor
;**********************************************************************
;---------------------
; Initialize variables
;---------------------
        mov     [Wsio_Select_Field_Nr], 0       ; We start from the beginning
        mov     [Wsio_Select_Field_Occur_Nr], 0
        mov     [Wsio_Select_Field_Position], 0
        mov     [Wsio_Input_Select_Attrib], 0

;------------------
; Check Field Table
;------------------
        mov     bx, [Wsio_Field_Address_Hi]
        mov     di, [Wsio_Field_Address_Lo]
        mov     es, bx

        cmp     bx, NULL                        ; Fields to check?
        je      @@99                            ; No
                                                ; Yes, so
;-------------------
; Check (Next) Field
;-------------------
@@10:
        cmp     [byte es:di], NULL              ; Fields left to check?
        je      @@90                            ; No
                                                ; Yes, so
        inc     [Wsio_Select_Field_Nr]

;----------------------------------
; Remember Field Information
;----------------------------------
        push    ds si es di                     ; Save pointers

        mov     si, offset Wsio_Field_Start_Row ; Beginning of Field structure

        push    ds si es di                     ; Copy Wsio Field info
        pop     si ds di es                     ; from table to active info

        mov     cx, WSIO_FIELD_STRUCTURE_SIZE   ; Field structure size
        rep     movsb                           ; Structure copied

        pop     di es si ds                     ; Restore pointers

        add     di, WSIO_FIELD_STRUCTURE_SIZE   ; Point to next field already

;-----------------------------
; Only check modifiable fields
;-----------------------------
        cmp     [Wsio_Field_Modifiable], 1      ; Modifiable?
        je      @@15                            ; Yes
                                                ; No, so
        cmp     [Wsio_Field_Mouse_Sensitive], 0 ; Mouse_Sensitive?
        je      @@10                            ; No
                                                ; Yes, so
@@15:
;---------------------------------------------------
; Determine Field cursor location start/end of field
;---------------------------------------------------
        mov     ah, [Wsio_Start_Row]
        add     ah, [Wsio_Field_Start_Row]
        dec     ah

        mov     al, [Wsio_Start_Col]
        add     al, [Wsio_Field_Start_Col]
        dec     al

        mov     bx, ax
        add     bl, [Wsio_Field_Size]
        dec     bl

        xor     cx, cx                          ; Reset cx
        mov     cl, [Wsio_Field_Occurs]
        mov     [Wsio_Select_Field_Occur_Nr], 0

@@20:
;---------------------------------------------------
; Check if cursor lies within field row/column range
;---------------------------------------------------
        inc     [Wsio_Select_Field_Occur_Nr]    ; Current occurrence

        cmp     ah, [Wsio_Cursor_Row]           ; Cursor on this field row?
        je      @@30                            ; Yes
                                                ; No, so
        inc     ah                              ; Get next occurrence
        loop    @@20
        jmp     @@10                            ; Check next field

@@30:
        cmp     al, [Wsio_Cursor_Col]           ; Cursor > field col start?
        jnle    @@10                            ; No
                                                ; Yes, so
        cmp     bl, [Wsio_Cursor_Col]           ; Cursor > field col end
        jl      @@10                            ; Yes
                                                ; No, so
;-------------------------
; Determine field position
;-------------------------
        mov     [Wsio_Select_Field_Position], 0
        mov     bl, [Wsio_Cursor_Col]           ; Current column
        sub     bl, al                          ; Subtract begin of field
        inc     bl                              ; For correct position
        mov     [Wsio_Select_Field_Position], bl

        cmp     [Wsio_Field_Modifiable], 0      ; Protected field?
        je      @@99                            ; Yes
                                                ; No, so
;----------------------------------------
; Determine video address of active field
;----------------------------------------
        mov     es, [Video_Address_Base]
        mov     di, [Video_Address_Offset]

        xor     cx, cx                          ; Reset cx
        mov     cl, ah                          ; Field row
        mov     ah, NULL                        ; Reset upper part of ax

@@40:
        add     di, (MAX_COL * 2)
        loop    @@40

        sub     di, (MAX_COL * 2)
        add     di, ax
        add     di, ax
        sub     di, 2                           ; Correct video location reached

        mov     [Wsio_Field_Video_ptr_es], es
        mov     [Wsio_Field_Video_ptr_di], di

;--------------------------
; Remember active attribute
;--------------------------
        mov     al, [es:di + 1]
        mov     [Wsio_Input_Select_Attrib], al

;--------------------------------
; Remember character under cursor
;--------------------------------
        mov     al, [Wsio_Select_Field_Position]
        dec     ax                              ; Because of offset 0
        add     di, ax
        add     di, ax                          ; To skip attributes
        mov     al, [byte es:di]                ; Get character
        mov     [Wsio_Field_Curr_Char], al      ; Remember character under cursor

@@50:
;---------------------------------------------------
; Valid keys of active field depend on the edit mask
;---------------------------------------------------
;
; Check edit mask 0 = External key map
;
        cmp     [Wsio_Field_Edit], 0
        je      @@99
;
; Check edit mask 1 = Any
;
        mov     [Wsio_Field_Keys_ptr_es], NULL
        mov     [Wsio_Field_Keys_ptr_di], NULL
        cmp     [Wsio_Field_Edit], 1
        je      @@99
;
; Check edit mask 2 = Nrs
;
        mov     si, offset Edit_Mask_2_Nrs
        mov     [Wsio_Field_Keys_ptr_es], ds
        mov     [Wsio_Field_Keys_ptr_di], si
        cmp     [Wsio_Field_Edit], 2
        je      @@99
;
; Check edit mask 3 = Letters 4=Nrs+Letters 5=Nrs+Letters+@#$ 6=Filemask1 = External key map
;
        mov     si, offset Edit_Mask_3_Letters
        mov     [Wsio_Field_Keys_ptr_es], ds
        mov     [Wsio_Field_Keys_ptr_di], si
        cmp     [Wsio_Field_Edit], 3
        je      @@99
;
; Check edit mask 4 = Nrs and Letters
;
        mov     si, offset Edit_Mask_4_Nrs_Letters
        mov     [Wsio_Field_Keys_ptr_es], ds
        mov     [Wsio_Field_Keys_ptr_di], si
        cmp     [Wsio_Field_Edit], 4
        je      @@99
;
; Check edit mask 5 = Nrs and Letters and @#$
;
        mov     si, offset Edit_Mask_5_Nrs_Let_Spc
        mov     [Wsio_Field_Keys_ptr_es], ds
        mov     [Wsio_Field_Keys_ptr_di], si
        cmp     [Wsio_Field_Edit], 5
        je      @@99
;
; Check edit mask 6 = Filemask
;
        mov     si, offset Edit_Mask_6_Filemask
        mov     [Wsio_Field_Keys_ptr_es], ds
        mov     [Wsio_Field_Keys_ptr_di], si
        cmp     [Wsio_Field_Edit], 6
        je      @@99
;
; Check edit mask 7 = Hexadecimal
;
        mov     si, offset Edit_Mask_7_Hexadecimal
        mov     [Wsio_Field_Keys_ptr_es], ds
        mov     [Wsio_Field_Keys_ptr_di], si
        cmp     [Wsio_Field_Edit], 7
        je      @@99
;
; Check edit mask 8 = Tabable
;
        mov     si, offset Edit_Mask_8_Tabable
        mov     [Wsio_Field_Keys_ptr_es], ds
        mov     [Wsio_Field_Keys_ptr_di], si
        cmp     [Wsio_Field_Edit], 8
        je      @@99
;
; Invalid edit mask specified, assume any key is valid
;
        mov     [Wsio_Field_Keys_ptr_es], NULL
        mov     [Wsio_Field_Keys_ptr_di], NULL

        jmp     @@99

@@90:
;----------------------------------
; Cursor outside a modifiable field
;----------------------------------
        mov     [Wsio_Select_Field_Nr], 0
        mov     [Wsio_Select_Field_Occur_Nr], 0
        mov     [Wsio_Select_Field_Position], 0
        mov     [Wsio_Input_Select_Attrib], 0

@@99:
        ret

ENDP    Determine_Field_Under_Cursor



;**********************************************************************
PROC    Process_Entered_Screen_Fields
;**********************************************************************
        mov     [Wsio_Screen_Changed], LOGIC_NO

        mov     bx, [Wsio_Field_Address_Hi]
        mov     di, [Wsio_Field_Address_Lo]
        mov     es, bx

        cmp     bx, NULL                        ; Any fields to update?
        je      @@99                            ; No
                                                ; Yes, so
@@10:
        push    ds si es di

        cmp     [byte es:di], NULL              ; Are there (still) any fields?
        je      @@99                            ; No
                                                ; Yes, so
;
; Assume nothing happened
;
        mov     [(Wsio_Field ptr di).Field_Changed], LOGIC_NO   ; Nothing changed

;
; Only process modifiable fields
;
        cmp     [(Wsio_Field ptr di).Modifiable], 1     ; Modifiable?
        jne     @@70                            ; No
                                                ; Yes, so
;
; Copy field info to active info
;
        push    ds si                           ; Save pointers

        mov     si, offset Wsio_Field_Start_Row ; Beginning of Field structure

        push    ds si es di                     ; Copy Wsio Field info
        pop     si ds di es                     ; from table to active info

        mov     cx, WSIO_FIELD_STRUCTURE_SIZE   ; Field structure size
        rep     movsb                           ; Structure copied

        pop     si ds                           ; Restore pointers

        mov     [Wsio_Field_Curr_Occur], 1      ; Current occurrence

@@20:
;-------------------------------------------------------------
; Copy screen input to save area first of (current) occurrence
;-------------------------------------------------------------
        push    ds si

        mov     [Wsio_Field_Change], LOGIC_NO

        xor     cx, cx
        mov     cl, [Wsio_Field_Start_Row]
        add     cl, [Wsio_Field_Curr_Occur]
        dec     cx                              ; For offset reasons
        xor     dx, dx
        mov     dl, [Wsio_Field_Start_Col]
        xor     bx, bx
        mov     bl, [Wsio_Field_Size]

        mov     si, offset Wsio_Field_Data_Save
        mov     es, [Video_Address_ptr_es]
        mov     di, [Video_Address_ptr_di]

        push    ds si es di
        pop     si ds di es                     ; Video -> Save copy direction

@@30:
        add     si, (MAX_COL * 2)
        loop    @@30                            ; Go to correct row

        sub     si, (MAX_COL * 2)               ; Done

        add     si, dx                          ; Go to correct column
        add     si, dx
        sub     si, 2                           ; Done
                                                ; Correct video location reached
        mov     cx, bx                          ; Field size

@@40:
        movsb
        inc     si
        loop    @@40

        pop     si ds

;--------------------
; Field changed check
;--------------------
        mov     si, offset Wsio_Field_Data_Save
        cmp     [Wsio_Field_Data_Src_ptr_es], NULL  ; Any source data?
        jne     @@41                            ; Yes
                                                ; Maybe
        cmp     [Wsio_Field_Data_Src_ptr_di], NULL  ; Any source data?
        je      @@70                            ; No
                                                ; Yes
@@41:
        mov     es, [Wsio_Field_Data_Src_ptr_es]
        mov     di, [Wsio_Field_Data_Src_ptr_di]
        xor     dx, dx                          ; Reset dx
        mov     dl, [Wsio_Field_Size]           ; Field size
        xor     cx, cx                          ; Reset cx
        mov     cl, [Wsio_Field_Curr_Occur]
        jmp     @@43

@@42:
        add     di, dx                          ; Next source occurrence

@@43:
        loop    @@42

        mov     cx, dx
        rep     cmpsb                           ; Field changed?
        je      @@50                            ; No
                                                ; Yes, so
        mov     [Wsio_Screen_Changed], LOGIC_YES
        mov     [Wsio_Field_Change], LOGIC_YES

@@50:
;-------------------------------------------------------------------
; Check if we should copy screen input to the source or object field
;-------------------------------------------------------------------
        mov     bx, [Wsio_Field_Data_Obj_ptr_es]
        mov     di, [Wsio_Field_Data_Obj_ptr_di]

        cmp     bx, NULL                        ; Copy to Object field?
        jne     @@60                            ; Yes
                                                ; No, so
        mov     bx, [Wsio_Field_Data_Src_ptr_es]
        mov     di, [Wsio_Field_Data_Src_ptr_di]

;---------------------
; Update field content
;---------------------
@@60:
        mov     es, bx
        mov     si, offset Wsio_Field_Data_Save
        xor     cx, cx                          ; Reset cx
        mov     cl, [Wsio_Field_Curr_Occur]
        jmp     @@62

@@61:
        add     di, dx                          ; Next source/object occurrence

@@62:
        loop    @@61

        mov     cx, dx                          ; Field size
        rep     movsb                           ; Field updated

;--------------------
; Get next occurrence
;--------------------
        inc     [Wsio_Field_Curr_Occur]         ; Assume next occurrence
        cmp     [Wsio_Field_Occurs], 0          ; Insanity check first
        je      @@70                            ; User supplied an occ of 0
                                                ; User specified an occ of 1 or more
        dec     [Wsio_Field_Occurs]             ; More occurrences?
        jnz     @@20                            ; Yes
                                                ; No, so
;---------------
; Get next field
;---------------
@@70:
        pop     di es si ds

;
; Update field status
;
        mov     bl, [Wsio_Field_Change]
        mov     [(Wsio_Field ptr di).Field_Changed], bl

        add     di, WSIO_FIELD_STRUCTURE_SIZE
        jmp     @@10

@@99:
        pop     di es si ds

        ret

ENDP    Process_Entered_Screen_Fields



;**********************************************************************
PROC    Keyboard_IO
;**********************************************************************
@@00:
        xor     ax, ax                          ; Reset ax
        mov     ah, KEYBOARD_KBD_STATUS         ; Check buffer
        int     KEYBOARD_SERVICE
                                                ; Key waiting?
        jnz     @@10                            ; Yes
                                                ; No, so
;
; Check mouse I/O
;        
        cmp     [Wsio_Mouse_Present], LOGIC_NO  ; Mouse present?
        je      @@00                            ; No
                                                ; Yes, so
        cmp     [Wsio_Mouse_Support], LOGIC_NO  ; Support mouse?
        je      @@00                            ; No
                                                ; Yes, so
;
; Check mouse press
;        
        mov     ax, MOUSE_GET_MOUSE_BUTTON_STATUS
        mov     bx, 0                           ; Status of left button
        int     MOUSE_SERVICE

        cmp     ax, 1                           ; Left button pressed?
        jne     @@00                            ; No
                                                ; Yes, so
        cmp     bx, 0                           ; Nr of left button presses > 0?
        je      @@00                            ; No
                                                ; Yes, so
;
; Left mouse button pressed, position cursor on requested position
;
        mov     [Wsio_Mouse_Left_Button_Pressed], LOGIC_YES
        mov     ax, dx
        xor     dx, dx
        mov     bx, [Pixels_Per_Row]
        div     bx                              ; dx:ax / bx = cursor Row
        inc     ax
        mov     [Wsio_Cursor_Row], al

        mov     ax, cx
        xor     dx, dx
        mov     bx, [Pixels_Per_Col]
        div     bx                              ; dx:ax / bx = cursor col
        inc     ax
        mov     [Wsio_Cursor_Col], al

        mov     dh, [Wsio_Cursor_Row]
        dec     dh
        mov     dl, [Wsio_Cursor_Col]
        dec     dl

        xor     ax, ax
        xor     bx, bx
        xor     cx, cx
        mov     ah, VIDEO_SET_CURSOR
        int     VIDEO_SERVICE                   ; Set Cursor

        call    Determine_Field_Under_Cursor

        cmp     [Wsio_Select_Field_Nr], 0       ; Outside a field?
        je      @@99                            ; Yes
                                                ; No, so
        cmp     [Wsio_Field_Mouse_Sensitive], 0 ; Mouse sensitive field?
        je      @@99                            ; No
                                                ; Yes, so
;
; Mouse sensitive field encountered, emulate specified key
; Cursor location specifies which "key" was pressed
;
        mov     [Wsio_Mouse_Left_Button_Pressed], LOGIC_NO
        xor     ax, ax
        mov     al, [Wsio_Field_Mouse_Sensitive]
        mov     [Return_Code], WSIO_MOUSE_PRESSED       ; Indicate mouse pressed
        jmp     @@99

@@10:
        mov     ah, KEYBOARD_READ_CHAR          ; Retrieve Key press
        int     KEYBOARD_SERVICE
        or      al, al                          ; Special Key pressed?
        jnz     @@20                            ; No
                                                ; Yes, so
        xchg    ah, al                          ; ah<-0, al<-scan code
        add     al, 32                          ; Adjust scan code to >= 32
        jmp     @@30

@@20:
        xor     ah, ah                          ; Assume Special Key
        cmp     al, 32                          ; Special Key pressed?
        jb      @@30                            ; Yes
                                                ; No, so
        inc     ah                              ; It's an ASCII key

@@30:
        or      ah, ah                          ; Set or clear zf result flag

@@99:
        ret

ENDP    Keyboard_IO



;**********************************************************************
PROC    Show_Screen_Text
;**********************************************************************
        push    ds si

        mov     bx, [Wsio_Rows]
        mov     dx, [Wsio_Cols]

        mov     ax, [Wsio_Text_Address_Hi]
        mov     cx, [Wsio_Text_Address_Lo]

        mov     es, [Video_Address_ptr_es]
        mov     di, [Video_Address_ptr_di]

        push    ax cx
        pop     si ds

@@10:
        mov     cx, dx

@@20:
        movsb
        inc     di
        loop    @@20

        mov     cx, MAX_COL
        sub     cx, dx
        shl     cx, 1
        add     di, cx
        dec     bx
        jnz     @@10

@@99:
        pop     si ds

        ret

ENDP    Show_Screen_Text



;**********************************************************************
PROC    Show_Screen_Attributes
;**********************************************************************
        push    ds si

        mov     bx, [Wsio_Rows]
        mov     dx, [Wsio_Cols]

        mov     ax, [Wsio_Attrib_Address_Hi]
        mov     cx, [Wsio_Attrib_Address_Lo]

        mov     es, [Video_Address_ptr_es]
        mov     di, [Video_Address_ptr_di]
        inc     di

        cmp     ax, NULL                        ; Use screen attributes table?
        je      @@30                            ; No
                                                ; Yes, so
        push    ax cx
        pop     si ds

;-------------------------------------
; Use specified screen attribute table
;-------------------------------------
@@10:
        mov     cx, dx

@@20:
        movsb
        inc     di
        loop    @@20

        mov     cx, MAX_COL
        sub     cx, dx
        shl     cx, 1
        add     di, cx
        dec     bx
        jnz     @@10
        jmp     @@99

@@30:
;-------------------------------
; Use specified screen attribute
;-------------------------------
        mov     al, [Wsio_Screen_Attrib]        ; Specified screen attribute
        cmp     al, 0                           ; Change screen's attribute?
        je      @@99                            ; No
                                                ; Yes, so
        mov     cx, dx

@@40:
        mov     [byte es:di], al                ; Use screen attribute
        inc     si
        inc     di
        inc     di
        loop    @@40

        mov     cx, MAX_COL
        sub     cx, dx
        shl     cx, 1
        add     di, cx
        dec     bx
        jnz     @@30

@@99:
        pop     si ds

        ret

ENDP    Show_Screen_Attributes



;**********************************************************************
PROC    Show_Screen_Fields
;**********************************************************************
        push    ds si

;--------------------------
; Determine Fields location
;--------------------------
        mov     bx, [Wsio_Field_Address_Hi]
        mov     di, [Wsio_Field_Address_Lo]
        mov     es, bx

;
; Number of fields on the screen
;
        mov     [Wsio_Field_Nr_Max], 0

;
; Number of modifiable fields on the screen
;
        mov     [Wsio_Field_Nr_Mod_Max], 0

        cmp     bx, NULL                        ; Any fields to update?
        je      @@99                            ; No
                                                ; Yes, so
@@10:
        push    ds si es di

        cmp     [byte es:di], NULL              ; Are there (still) any fields?
        je      @@80                            ; No
                                                ; Yes, so
;
; Determine number of fields (w/o their occurrences) on the screen
;
        inc     [Wsio_Field_Nr_Max]

;
; Determine number of modifiable fields (w/o their occurrences) on the screen
;

        cmp     [(Wsio_Field ptr di).Modifiable], 1     ; Modifiable?
        jne     @@15                                    ; No
                                                        ; Yes, so
        inc     [Wsio_Field_Nr_Mod_Max]

@@15:
        mov     ax, [(Wsio_Field ptr di).Offset]
        mov     [Wsio_Field_Offset], ax

        xor     ax, ax
        xor     cx, cx
        xor     dx, dx

        mov     al, [(Wsio_Field ptr di).Size]
        mov     [Wsio_Field_Size], al

        mov     dl, [(Wsio_Field ptr di).Occurs]
        mov     [Wsio_Field_Occurs], dl

        mov     cl, [(Wsio_Field ptr di).Start_Row]
        mov     [byte Wsio_Field_Start_Row], cl

        mov     dl, [(Wsio_Field ptr di).Start_Col]
        mov     [byte Wsio_Field_Start_Col], dl

;-----------
; Field DATA
;-----------
        mov     bx, [(Wsio_Field ptr di).Data_Address_Src_Hi]
        mov     di, [(Wsio_Field ptr di).Data_Address_Src_Lo]
        cmp     bx, NULL
        jne     @@16
        cmp     di, NULL
        je      @@70

@@16:
        mov     es, bx

        push    es di

        mov     es, [Video_Address_ptr_es]
        mov     di, [Video_Address_ptr_di]

@@20:
        add     di, (MAX_COL * 2)
        loop    @@20

        sub     di, (MAX_COL * 2)
        add     di, dx
        add     di, dx
        sub     di, 2                           ; Correct video location reached

        xor     cx, cx
        mov     cl, [Wsio_Field_Size]
        mov     ah, [Wsio_Field_Occurs]
        mov     bx, [Wsio_Field_Offset]
        pop     si ds

@@25:
        movsb
        inc     di
        loop    @@25

        dec     ah                              ; Nr of occurrences
        jz      @@30

        mov     cx, (MAX_COL * 2)               ; Move to location of next occurrence

        push    ax

        xor     ah, ah                          ; Reset hi part

        sub     cx, ax                          ; Subtract Field size
        sub     cx, ax                          ; Subtract Field size
        add     di, cx                          ; Location reached
        mov     cx, ax                          ; Get Field size

        pop     ax

        add     si, bx                          ; In case this field is just part of a table
        jmp     @@25                            ; Show next occurrence

@@30:
        pop     di es si ds
        push    ds si es di

;-----------------------
; Temporary fields setup
;-----------------------
        mov     al, [(Wsio_Field ptr di).Modifiable]
        mov     [Temp_Wsio_Field_Modifiable], al
        mov     al, [(Wsio_Field ptr di).Mouse_Sensitive]
        mov     [Temp_Wsio_Field_Mouse_Sensitive], al

;-----------------
; Field ATTRIBUTES
;-----------------
        mov     ax, [(Wsio_Field ptr di).Attrib_Address_Hi]
        mov     bx, [(Wsio_Field ptr di).Attrib_Address_Lo]

        mov     es, [Video_Address_ptr_es]
        mov     di, [Video_Address_ptr_di]

        mov     cl, [Wsio_Field_Start_Row]
        mov     dl, [Wsio_Field_Start_Col]

@@40:
        add     di, (MAX_COL * 2)
        loop    @@40

        sub     di, (MAX_COL * 2)
        add     di, dx
        add     di, dx
        sub     di, 1                           ; Correct video location reached

        mov     cx, bx                          ; High portion of attrib address
        xor     bx, bx
        mov     bl, [Wsio_Field_Size]
        xor     dx, dx
        mov     dl, [Wsio_Field_Occurs]

@@50:
;-------------------------------------------
; Field ATTRIBUTES using an attributes table
;-------------------------------------------
        cmp     ax, NULL                        ; Attribute table present?
        je      @@60                            ; No
                                                ; Yes, so
        push    ax cx
        pop     si ds                           ; Attrib table -> Video

@@53:
        push    ds si                           ; Occurrence attribute pointer

        mov     cx, bx                          ; Field size
        mov     al, [byte ds:si]                ; Get field attribute of occurr.

@@55:
        mov     [byte es:di], al
        inc     di
        inc     di
        loop    @@55

        dec     dx                              ; More occurrences?
        jz      @@59                            ; No
                                                ; Yes, so
        mov     ax, (MAX_COL * 2)               ; Move to location of next occurrence
        sub     ax, bx                          ; Subtract Field size
        sub     ax, bx                          ; Subtract Field size
        add     di, ax                          ; Location reached

        pop     si ds                           ; Occurrence attribute pointer

        inc     si                              ; Get next occurrence
        jmp     @@53                            ; Show next occurrence

@@59:
        pop     si ds
        jmp     @@70

@@60:
;-------------------------------------------
; Field ATTRIBUTES using the field attribute
;-------------------------------------------
;
; Normally protected fields are displayed as fields as well,
; however when they are mouse sensitive, it is probably a special field,
; i.e. a Function Selection Key field, i.e. Enter, Cancel, Help
; Special fields will retain their "background" attribute and will
; not be displayed as fields
;
        cmp     [Temp_Wsio_Field_Modifiable], 1         ; Modifiable?
        je      @@62                                    ; Yes
                                                        ; No, so
        cmp     [Temp_Wsio_Field_Mouse_Sensitive], 0    ; Mouse sensitive?
        jne     @@70                                    ; Yes
                                                        ; No, so
@@62:
        mov     al, [Wsio_Field_Attrib]
        cmp     al, 0                                   ; Field attribute specified?
        je      @@70                                    ; No
                                                        ; Yes, so
@@63:
        mov     cx, bx                                  ; Field size
        mov     al, [Wsio_Field_Attrib]

@@65:
        mov     [byte es:di], al
        inc     di
        inc     di
        loop    @@65

        dec     dx                              ; More occurrences?
        jz      @@70                            ; No
                                                ; Yes, so
        mov     ax, (MAX_COL * 2)               ; Move to location of next occurrence
        sub     ax, bx                          ; Subtract Field size
        sub     ax, bx                          ; Subtract Field size
        add     di, ax                          ; Location reached
        jmp     @@63                            ; Show next occurrence

@@70:
;---------------
; Get next field
;---------------
        pop     di es si ds

        add     di, WSIO_FIELD_STRUCTURE_SIZE
        jmp     @@10

@@80:
        pop     di es si ds

@@99:
        pop     si ds

        ret

ENDP    Show_Screen_Fields



ENDS    CSeg                                    ; End of Code segment

END                                             ; End of WSIO
