;
; BILDSCHIRMTREIBER FUER CP/M EMULATOR
;
;
; (C) 1990,1991,1993 by Jrgen Weber
;

LOCALS

INCLUDE DOS.INC

WS_KEY equ TRUE

KAYPRO_TERM_FKTS_TOO equ TRUE

EMU_SCR_PAGE EQU 0
DOS_SCR_PAGE EQU 1

HIGHLIGHT_ATTR EQU 1000b
UNDERLINE_ATTR EQU 110b
BLINK_ATTR     EQU 10000000b
; unfortunately there is no single bit that decides inverse
; on all video cards

SCRNWIDTH EQU 79
LASTLINE  EQU 24

emudata_seg segment para public 'DATA'


IF WS_KEY
after_ctrl_q db 0

CTRL_MASK EQU 111111B
ext_keys db 72, 'E' AND CTRL_MASK,0   ; up
         db 73, 'R' AND CTRL_MASK,0   ; page up
         db 75, 'S' AND CTRL_MASK,0   ; left
         db 77, 'D' AND CTRL_MASK,0   ; right
         db 80, 'X' AND CTRL_MASK,0   ; down
         db 81, 'C' AND CTRL_MASK,0   ; page down
         db 82, 'V' AND CTRL_MASK,0   ; ins
         db 83, 'G' AND CTRL_MASK,0   ; del
         db 115, 'A' AND CTRL_MASK,0  ; ctrl-left
         db 116, 'F' AND CTRL_MASK,0  ; ctrl-right
         db 71, 'Q' AND CTRL_MASK,'S' ; home
         db 79, 'Q' AND CTRL_MASK,'D' ; end
         db 117, 'Q' AND CTRL_MASK,'X' ; ctrl-end
         db 118, 'Q' AND CTRL_MASK,'C'  ; ctrl-pgdn
         db 119, 'Q' AND CTRL_MASK,'E'  ; ctrl-home
         db 132, 'Q' AND CTRL_MASK,'R'  ; ctrl-pgup
         db 0,0 ; 2. Null damit bei not found was geladen
ENDIF

tr_usa             db '#','$','@','[','\',']'
                   db '^','`','{','|','}','~'
tr_french          db '#','$','','ψ','',21
                   db '^','`','','','','~'
tr_german          db '#','$', 21,'','',''
                   db '^','`','','','','α'
tr_english         db '','$','@','[','\',']'
                   db '^','`','{','|','}','~'
tr_danish          db '#','$','@','','ι',''
                   db '^','`','','ν','','~'
tr_swedish         db '#','$','','','',''
                   db '','','','','',''
tr_italian         db '#','$','@','ψ','\',''
                   db '^','','','','',''
tr_spanish         db '','$','@','','₯','¨'
                   db '^','`','~','€','}','~'
tr_end equ this byte

tr_tab_poi         dw offset tr_usa
char_tran_flag     db FALSE


cursor_size        dw (?)
cursor_on_flag     db TRUE
cursor_pos         dw 0

txt_attribute           db 7


ESC_flag           db FALSE
ctrl_paramcount    db 0
ctrl_address       dw (?)
ctrl_buf_entries   db 0
ctrl_buf_poi       dw offset ctrl_buf
ctrl_buf           db 10 dup (?)

video_mode         db (?)

; Struktur zur Beschreibung der einzelnen Bildschirmtreiberfunktionen

termfkt  struc
         db          (?)          ; Funktionsnummer
         db          (?)          ; Paramameterzahl
         dw offset   (?)          ; Adresse des zugehoerigen UPs
termfkt  ends


;
; there are always two jump tables:
; *def_tab_poi = normal codes
; *esc_tab_poi = codes lead in by ESC
;
; each table terminated by 0ffh
;
; Note: a table should at least contain values for 13 and 10
;
; *before* *def_tab_poi table two bytes for offset to add to set cursor
; 0: for column first
; 1: for line first
; if one not needed set to 0

def_tab_poi dw offset CPC_tab
esc_tab_poi dw offset CPC_ESC_tab



; Tabelle fuer Terminalfunktionen des Schneider CPC
; (noch nicht alle Funktionen implementiert)

db 1  ; this is offset for set cursor x first
db 32 ; this is offset for set cursor y first

CPC_tab  termfkt <0,0,dummy_rout>
         termfkt <1,0,dummy_rout>
         termfkt <2,0,cursor_off>
         termfkt <3,0,cursor_on>
         termfkt <4,0,dummy_rout>
         termfkt <5,0,dummy_rout>
         termfkt <6,0,dummy_rout>
         termfkt <7,0,ringbell>
         termfkt <8,0,csr_left>
         termfkt <9,0,csr_right>
         termfkt <10,0,csr_down_scr_up>
         termfkt <11,0,csr_up>
         termfkt <12,0,clear_screen>
         termfkt <13,0,csr_to_lstart>
         termfkt <14,0,dummy_rout>
         termfkt <15,0,dummy_rout>
         termfkt <16,0,clr_chr_at_cursor>
         termfkt <17,0,del_line_to_cursor>
         termfkt <18,0,del_line_from_cursor>
         termfkt <19,0,clear_window_to_cursor>
         termfkt <20,0,clear_window_from_cursor>
         termfkt <21,0,dummy_rout>
         termfkt <22,0,dummy_rout>
         termfkt <23,0,dummy_rout>
         termfkt <24,0,txt_inverse>
         termfkt <25,0,dummy_rout>
         termfkt <26,0,dummy_rout>
         termfkt <27,0,use_esc_tab> ; this is always needed
         termfkt <28,0,dummy_rout>
         termfkt <29,0,dummy_rout>
         termfkt <30,0,cursor_home>
         termfkt <31,2,xy_set_cursor>

         db 0ffh                  ; sentinel

; Tabelle fuer Terminalfunktionen von CP/M Plus
; (noch nicht alle Funktionen implementiert)

CPC_ESC_tab   label byte

; die erste Routine stammt nicht von CP/M Plus, sondern
; ist eigendefiniert (entsprechend zu Epson Druckern)

          termfkt <'@',0,Reset_Screen>
                   
          termfkt <'0',0,dummy_rout> ; Statuszeile aus
          termfkt <'1',0,dummy_rout> ; Statuszeile an
          termfkt <'2',1,select_country>
          termfkt <'3',1,dummy_rout> ; waehle Bildschirmmodus
          termfkt <'A',0,csr_up>
          termfkt <'B',0,csr_down>
          termfkt <'C',0,csr_right_no_wrap>
          termfkt <'D',0,csr_left_no_wrap>
          termfkt <'E',0,clear_screen_no_home>
          termfkt <'H',0,cursor_home>
          termfkt <'I',0,csr_up_scr_down>
          termfkt <'J',0,clear_window_from_cursor>
          termfkt <'K',0,del_line_from_cursor>
          termfkt <'L',0,insert_line>
          termfkt <'M',0,delete_line>
          termfkt <'N',0,delete_char_at_cursor>
          termfkt <'Y',2,yx_set_cursor>
          termfkt <'b',0,dummy_rout> ; setze Zeichenhelligkeit
          termfkt <'c',0,dummy_rout> ; setze Hintergrundhelligkeit
          termfkt <'d',0,del_line_to_cursor>
          termfkt <'e',0,cursor_on>
          termfkt <'f',0,cursor_off>
          termfkt <'j',0,push_cursor_pos>
          termfkt <'k',0,pop_cursor_pos>
          termfkt <'l',0,dummy_rout> ; loesche Zeile des Cursors
          termfkt <'o',0,del_line_to_cursor>
          termfkt <'p',0,inverse_on>
          termfkt <'q',0,inverse_off>
          termfkt <'r',0,underline_on>
          termfkt <'s',0,blink_on>
          termfkt <'t',0,blink_off>
          termfkt <'u',0,underline_off>
          termfkt <'v',0,dummy_rout>
          termfkt <'w',0,dummy_rout>
          termfkt <'x',0,dummy_rout> ; setze 24x80
          termfkt <'y',0,dummy_rout> ; 24x80 wieder weg

          db 0ffh                 ; sentinel

if KAYPRO_TERM_FKTS_TOO


db 0  ; xy not needed
db 32 ; this is offset for set cursor y first

KAY_tab  termfkt <7,0,ringbell>
         termfkt <8,0,csr_left>
         termfkt <12,0,csr_right>
         termfkt <10,0,csr_down_scr_up>
         termfkt <13,0,csr_to_lstart>
         termfkt <11,0,csr_up_scr_down>
         termfkt <17h,0,clear_window_from_cursor>
         termfkt <18h,0,del_line_from_cursor>
         termfkt <1ah,0,clear_screen>
         termfkt <1eh,0,cursor_home>
         termfkt <27,0,use_esc_tab> ; this is always needed

         db 0ffh                 ; sentinel

KAY_esc_tab termfkt <'E',0,insert_line>
         termfkt <'R',0,delete_line>
         termfkt <'=',2,yx_set_cursor>
         termfkt <'B',1,kaypro_B>
         termfkt <'C',1,kaypro_C>

; the plot functions are there, but as the PC cannot display graphics
; in text mode, you first have to use the Kgraphics_on function
; e.g. mbasic: print chr$(27);"B5";
; but anyway this remains a quick hack

         termfkt <'*',2,Kset_pixel>
         termfkt <' ',2,Kres_pixel>

         db 0ffh                 ; sentinel

kaypro_B_tab equ $
         dw offset inverse_on      ; 0
         dw offset inverse_on      ; 1 (should be reduced intensity)
         dw offset blink_on        ; 2
         dw offset underline_on    ; 3
         dw offset cursor_on       ; 4
         dw offset Kgraphics_on    ; 5 (should be video on)
         dw offset push_cursor_pos ; 6
         dw offset dummy_rout      ; 7 (should be statusline on)

kaypro_C_tab equ $
         dw offset inverse_off     ; 0
         dw offset inverse_off     ; 1
         dw offset blink_off       ; 2
         dw offset underline_off   ; 3
         dw offset cursor_off      ; 4
         dw offset Kgraphics_off   ; 5
         dw offset pop_cursor_pos  ; 6
         dw offset dummy_rout      ; 7


db 0  ; xy not needed
db 32 ; yx this is offset for set cursor y first

OSB1_tab  termfkt <7,0,ringbell>
         termfkt <8,0,csr_left>
         termfkt <10,0,csr_down_scr_up>
         termfkt <11,0,csr_up_scr_down>
         termfkt <12,0,csr_right>

         termfkt <13,0,csr_to_lstart>
         termfkt <26,0,clear_screen>
         termfkt <27,0,use_esc_tab> ; this is always needed

         db 0ffh                 ; sentinel

OSB1_esc_tab termfkt <'E',0,insert_line>
         termfkt <'Q',0,insert_char_at_cursor>
         termfkt <'W',0,delete_char_at_cursor>
         termfkt <'R',0,delete_line>
         termfkt <'T',0,del_line_from_cursor>

         termfkt <'g',0,dummy_rout>  ; start graphics ?
         termfkt <'G',0,dummy_rout>  ; end graphics
         termfkt <'S',0,dummy_rout>  ; set screen ?
         termfkt <'#',0,dummy_rout>  ; lock keyboard
         termfkt <'"',0,dummy_rout>  ; unlock keyboard

         termfkt <'l',0,underline_on>
         termfkt <'m',0,underline_off>

         termfkt <'(',0,inverse_on>
         termfkt <')',0,inverse_off>
         termfkt <'=',2,yx_set_cursor>

         db 0ffh                 ; sentinel


endif ; if KAYPRO_TERM_FKTS_TOO

emudata_seg ends


emulator_seg segment para public 'CODE'

assume  cs:emulator_seg,ds:emudata_seg,es:nothing,ss:nothing

PUBLIC reset_crt,crtout,crtin,crtinstat,sel_scr_page,cursor_off,cursor_on
PUBLIC select_scr_codes,Reset_Screen

EXTRN prg_exit:far
EXTRN breakflag:byte

reset_crt proc
     mov  ctrl_buf_entries,0
     mov  ctrl_paramcount,0
     mov  ctrl_buf_poi,offset ctrl_buf
    ret
reset_crt endp

select_scr_codes proc
if KAYPRO_TERM_FKTS_TOO
      push ds
      push emudata_seg
      pop ds
      test al,1
      jz @@no_kay
      mov def_tab_poi,offset KAY_tab
      mov esc_tab_poi,offset KAY_esc_tab
@@no_kay:
      test al,2
      jz @@no_osb
      mov def_tab_poi,offset OSB1_tab
      mov esc_tab_poi,offset OSB1_esc_tab
@@no_osb:
      pop ds
endif
    ret
select_scr_codes endp

select_amstrad_codes proc
        mov def_tab_poi,offset CPC_tab
        mov esc_tab_poi,offset CPC_ESC_tab
ret
select_amstrad_codes endp


crtout proc
;
; console character output aus register c
;
       PUSHR <si,di,bp,ax>
       mov al,ctrl_paramcount
       cmp al,0
       jnz short @@not_empty
         cmp byte ptr ESC_flag,TRUE
         mov byte ptr ESC_flag,FALSE
         mov di,offset esc_tab_poi
         mov di,[di]
         jz  short @@search_entrie
         cmp cl,' '
         jnc short @@write_out
; now it is a control code < ' '
       mov di,offset def_tab_poi
         mov di,[di]
@@search_entrie:
       cmp byte ptr [di],0ffh
       jz  short @@execon         ; nicht gefunden
       cmp cl,[di]
       jz short @@entrie_found
       add di,4                   ; jeder Eintrag belegt 4 Bytes
     jmp short @@search_entrie

@@entrie_found:
       mov al,[di+1]              ; benoetigte Parameter
       cmp al,0
     jz  short @@execute
       mov ctrl_paramcount,al
       mov di,[di+2]
       mov ctrl_address,di        ; Adresse des zugehoerigen UP merken
      jmp short @@exit

@@not_empty:
       mov bx,ctrl_buf_poi
       mov [bx],cl                ; Parameter merken
       inc bx
       mov ctrl_buf_poi,bx
       inc ctrl_buf_entries
       mov al,ctrl_paramcount
       cmp al,ctrl_buf_entries    ; alle Parameter komplett ?
       jnz short @@exit
       mov di,offset ctrl_address - 2

@@execute:
       call [di+2]
@@execon:
       call reset_crt
       jmp  short @@exit

@@write_out:
       call char_out
@@exit:
       POPR <ax,bp,di,si>
       ret
crtout endp

;
; display 0 terminated string in ds:si
;

use_esc_tab proc
       mov  byte ptr ESC_flag,TRUE
       ret
use_esc_tab endp
;
dummy_rout proc
       ret
dummy_rout endp

ringbell proc
        mov cl,7
        jmp char_out
ringbell endp

Reset_Screen proc
          call clear_screen_no_home
          call cursor_home
          call inverse_off
          call cursor_on
          call underline_off
          mov  char_tran_flag,FALSE
          ret
Reset_Screen endp

push_cursor_pos proc
      call get_cursor_pos
      mov  cursor_pos,dx
      ret
push_cursor_pos endp

pop_cursor_pos proc
      mov dx,cursor_pos
      call bios_set_cursor
      ret
pop_cursor_pos endp

get_cursor_pos proc
       PUSHR <ax,si,di,bp>
         mov ah,3
         mov bh,EMU_SCR_PAGE
         int 10h
       POPR  <bp,di,si,ax>
       ret
get_cursor_pos endp

cursor_off proc
       cmp cursor_on_flag,FALSE
       jz  short @@exit
       PUSHR <ax,bx,cx,si,di,bp>
         call get_cursor_pos
         mov  cursor_size,cx
         mov ah,1                 ; define cursor
         mov cx,0ffffh            ; unmoeglicher Wert = Cursor aus
         mov bh,EMU_SCR_PAGE
         int 10h
         mov cursor_on_flag,FALSE
       POPR  <bp,di,si,cx,bx,ax>
@@exit:
       ret
cursor_off endp

cursor_on proc
       cmp cursor_on_flag,TRUE
       jz  short @@exit
       PUSHR <ax,bx,cx,si,di,bp>
         mov  cx,cursor_size
         mov ah,1                 ; define cursor
         mov bh,EMU_SCR_PAGE
         int 10h
       mov cursor_on_flag,TRUE
       POPR  <bp,di,si,cx,bx,ax>
@@exit:
       ret
cursor_on endp

insert_line proc
       PUSHR <ax,bx,cx,si,di,bp>
         call get_cursor_pos
         push dx
; scrolle den Rest des Bildschirms ab Cursorpos eine Zeile nach unten
; Cursorpos bleibt erhalten
         mov ah,7                 ; scroll down window
         mov al,1                 ; eine Zeile
         mov bh,txt_attribute
         mov ch,dh
         mov cl,0
         mov dh,LASTLINE
         mov dl,SCRNWIDTH
         int 10h
         pop dx
         call bios_set_cursor
       POPR  <bp,di,si,cx,bx,ax>
       ret
insert_line endp

delete_line proc
       PUSHR <ax,bx,cx,si,di,bp>
         call get_cursor_pos
         push dx
; scrolle den Rest des Bildschirms ab Cursorzeile+1 eine Zeile nach unten
; Cursorpos bleibt erhalten
         mov ah,6                 ; scroll up window
         mov al,1                 ; um eine Zeile
         mov bh,txt_attribute
         mov ch,dh
         mov cl,0
         mov dh,LASTLINE
         mov dl,SCRNWIDTH
         int 10h
         pop dx
         call bios_set_cursor
       POPR  <bp,di,si,cx,bx,ax>
       ret
delete_line endp

delete_char_at_cursor proc
       PUSHR <ax,bx,cx,si,di,bp>
         call get_cursor_pos
         push dx
@@while:                          ; WHILE XPos <SCRNWIDTH DO
                                  ; schlrfe Rest der Zeile ein
         inc dl
         cmp dl,SCRNWIDTH
         ja  short @@endwhile
         call bios_set_cursor
         call read_from_screen
         push ax
         dec  dl
         call bios_set_cursor
         pop  ax
         mov  bl,ah ; attribute
         mov  bh,EMU_SCR_PAGE
         mov  cx,1
         mov  ah,9 ; write char
         int  10h
         inc  dl
       jmp short @@while
@@endwhile:
         pop dx
         call bios_set_cursor
       POPR  <bp,di,si,cx,bx,ax>
       ret
delete_char_at_cursor endp


insert_char_at_cursor proc
       PUSHR <ax,bx,cx,si,di,bp>
         call get_cursor_pos
         push dx
         mov al,' '
@@while:                          ; WHILE XPos <SCRNWIDTH DO
         push ax
         call bios_set_cursor
         call read_from_screen
         pop  bx                  ; new char
         push ax
         mov  al,bl               ; old char
         mov  bl,bh ; attribute
         mov  bh,EMU_SCR_PAGE
         mov  cx,1
         mov  ah,9 ; write char
         int  10h
         pop  ax
         inc dl
         cmp dl,SCRNWIDTH
       jna short @@while
         pop dx
         call bios_set_cursor
       POPR  <bp,di,si,cx,bx,ax>
       ret
insert_char_at_cursor endp


read_from_screen proc             ; nach ax
       PUSHR <si,di,bp>
         mov ah,8                 ; bios read from screen
         mov bh,EMU_SCR_PAGE
         int 10h
       POPR  <bp,di,si>
       ret
read_from_screen endp

csr_up proc
       PUSHR <ax,bx,cx,si,di,bp>
         call get_cursor_pos
         cmp  dh,0                ; vorher schon oben ?
         jz short @@dont
           dec dh
           call bios_set_cursor
         @@dont:
       POPR  <bp,di,si,cx,bx,ax>
       ret
csr_up endp

csr_up_scr_down proc              ; ESC I
       PUSHR <ax,bx,cx,si,di,bp>
         call get_cursor_pos
         cmp  dh,0                ; vorher schon oben ?
         jz short @@is_up
           dec dh                 ; y
           call bios_set_cursor
           jmp short @@exit
   @@is_up:
         push dx
         mov ah,7                 ; scroll down window
         mov al,1                 ; um eine Zeile
         mov bh,txt_attribute
         mov cx,0
         mov dh,LASTLINE
         mov dl,SCRNWIDTH
         int 10h
         pop dx
         call bios_set_cursor
@@exit:
       POPR  <bp,di,si,cx,bx,ax>
       ret
csr_up_scr_down endp


csr_down proc ; do not scroll up if at bottom
       PUSHR <ax,bx,cx,si,di,bp>
         call get_cursor_pos
         cmp  dh,LASTLINE         ; vorher schon unten ?
         jz short @@dont
           inc dh
           call bios_set_cursor
         @@dont:
       POPR  <bp,di,si,cx,bx,ax>
       ret
csr_down endp

csr_down_scr_up proc ; scroll up if at bottom
       PUSHR <ax,bx,cx,si,di,bp>
         call get_cursor_pos
         cmp  dh,LASTLINE         ;
         jz short @@at_bottom
           inc dh                 ; y
           call bios_set_cursor
           jmp short @@exit
@@at_bottom:
         push dx
         mov ah,6                 ; scroll up window
         mov al,1                 ; one line
         mov bh,txt_attribute
         mov cx,0
         mov dh,LASTLINE
         mov dl,SCRNWIDTH
         int 10h
         pop dx
         call bios_set_cursor
@@exit:
       POPR  <bp,di,si,cx,bx,ax>
       ret
csr_down_scr_up endp


csr_right proc
       PUSHR <ax,bx,cx,si,di,bp>
         call get_cursor_pos
         cmp  dl,SCRNWIDTH
         jz short @@at_right
           inc dl
           call bios_set_cursor
           jmp short @@exit
@@at_right: ; go to first column and cursor down
           mov dl,0
           call bios_set_cursor
           call csr_down_scr_up
@@exit:
       POPR  <bp,di,si,cx,bx,ax>
       ret
csr_right endp


csr_right_no_wrap proc
       PUSHR <ax,bx,cx,si,di,bp>
         call get_cursor_pos
         cmp  dl,SCRNWIDTH
         jz short @@dont
           inc dl
           call bios_set_cursor
         @@dont:
       POPR  <bp,di,si,cx,bx,ax>
       ret
csr_right_no_wrap endp

csr_left proc
        mov cl,8
        jmp char_out
csr_left endp

csr_left_no_wrap proc
       PUSHR <ax,bx,cx,si,di,bp>
         call get_cursor_pos
         cmp  dl,0
         jz short @@dont
           dec dl
           call bios_set_cursor
         @@dont:
       POPR  <bp,di,si,cx,bx,ax>
       ret
csr_left_no_wrap endp

clear_window proc
       PUSHR <ax,bx,cx,si,di,bp>
         mov ah,6                 ; scroll window
         mov al,0                 ; clear window
         mov bh,txt_attribute
         int 10h
       POPR  <bp,di,si,cx,bx,ax>
       ret
clear_window endp

clear_screen_no_home proc
       PUSHR <cx,dx>
         mov ch,0                 ; y oben
         mov dh,25                ; y unten
         mov cl,0                 ; x links
         mov dl,SCRNWIDTH         ; x rechts
         call clear_window
       POPR  <dx,cx>
       ret
clear_screen_no_home endp

clear_screen proc
       call clear_screen_no_home
clear_screen endp                 ; und weiter mit Home

cursor_home proc
       push dx
       mov  dx,0                  ; x=y=0
       call bios_set_cursor
       pop dx
       ret
cursor_home endp

yx_set_cursor proc ; line first
       PUSHR <dx,si>
         mov si,offset ctrl_buf
         mov dx,[si]
         xchg dh,dl
         mov si,-1
        jmp short set_cur_cont
yx_set_cursor endp

xy_set_cursor proc ; column first
       PUSHR <dx,si>
         mov si,offset ctrl_buf
         mov dx,[si]
         mov si,-2
set_cur_cont:
         add si,def_tab_poi
         sub dh,[si]
         sub dl,[si]
; now check for cursor on screen range
         cmp dl,0
         jae @@xok0
         mov dl,0
@@xok0:
         cmp dh,0
         jae @@yok0
         mov dh,0
@@yok0:
         cmp dh,LASTLINE
         jna short @@yok
         mov dh,LASTLINE
@@yok:
         cmp dl,SCRNWIDTH
         jna short @@xok
         mov dl,SCRNWIDTH
@@xok:
         call bios_set_cursor
       POPR  <si,dx>
       ret
xy_set_cursor endp

ESC_set_cursor proc
       PUSHR <dx,si>
         mov si,offset ctrl_buf
         mov dx,[si]
         xchg dh,dl
         sub dh,20h
         sub dl,20h               ; offset 32 bei CP/M Plus
         cmp dl,LASTLINE
         jna short @@yok
         mov dl,LASTLINE
@@yok:
         cmp dh,SCRNWIDTH
         jna short @@xok
         mov dh,SCRNWIDTH
@@xok:
         xchg dh,dl
         call bios_set_cursor
       POPR  <si,dx>
       ret
ESC_set_cursor endp

;
; dh=y
; dl=x
;
bios_set_cursor proc
       PUSHR <ax,cx,si,di,bp>
         mov bh,EMU_SCR_PAGE
         mov ah,2
         int 10h
       POPR  <bp,di,si,cx,ax>
       ret
bios_set_cursor endp

sel_scr_page proc
       PUSHR <ax,si,di,bp>
       mov ah,5
       int 10h
       POPR  <bp,di,si,ax>
       ret
sel_scr_page endp

csr_to_lstart proc                ; Cursor an Zeilenanfang
       PUSHR <ax,bx,cx,si,di,bp>
         call get_cursor_pos
         mov bh,EMU_SCR_PAGE
         xor dl,dl                ; x:= 0
         call bios_set_cursor
       POPR  <bp,di,si,cx,bx,ax>
       ret
csr_to_lstart endp

clr_chr_at_cursor proc
       mov cx,1                   ; 1 char
       call clr_chars
       ret
clr_chr_at_cursor endp

; Zeichenzahl in cx
clr_chars proc
       PUSHR <ax,bx,cx,si,di,bp>
         mov al,' '
         mov bh,EMU_SCR_PAGE
         mov bl,txt_attribute
         mov ah,9
         int 10h
       POPR  <bp,di,si,cx,bx,ax>
       ret
clr_chars endp

del_line_to_cursor proc
       PUSHR <ax,bx,cx,si,di,bp>
         call get_cursor_pos
         push dx
           mov cl,dl              ; x
           mov dl,0
           call bios_set_cursor
           mov ch,0
           call clr_chars
         pop dx
         call bios_set_cursor
       POPR  <bp,di,si,cx,bx,ax>
       ret
del_line_to_cursor endp

del_line_from_cursor proc
       PUSHR <cx,dx>
         call get_cursor_pos
         mov cl,SCRNWIDTH
         sub cl,dl
         mov ch,0
         call clr_chars
       POPR  <dx,cx>
       ret
del_line_from_cursor endp


clear_window_to_cursor proc
       PUSHR <cx,dx>
         call get_cursor_pos

         dec dh                   ; y
         mov ch,0
         mov cl,0
         mov dl,SCRNWIDTH
         call clear_window
         call del_line_to_cursor
       POPR  <dx,cx>
       ret
clear_window_to_cursor endp

clear_window_from_cursor proc
       PUSHR <cx,dx>
         call del_line_from_cursor
         call get_cursor_pos
         inc dh                   ; y++
         mov ch,dh
         mov dh,24
         mov cl,0
         mov dl,SCRNWIDTH
         call clear_window
       POPR  <dx,cx>
       ret
clear_window_from_cursor endp

txt_inverse proc
         xor txt_attribute,HIGHLIGHT_ATTR
         ret
txt_inverse endp

inverse_on proc
         or txt_attribute,HIGHLIGHT_ATTR
         ret
inverse_on endp

inverse_off proc
         and txt_attribute,not HIGHLIGHT_ATTR
         ret
inverse_off endp

underline_on proc
         and txt_attribute,not UNDERLINE_ATTR
         ret
underline_on endp

underline_off proc
         or txt_attribute,UNDERLINE_ATTR
         ret
underline_off endp


blink_on proc
         or txt_attribute,BLINK_ATTR
         ret
blink_on  endp

blink_off proc
         and txt_attribute,not BLINK_ATTR
         ret
blink_off endp


;
; jedes Zeichen wird 2 mal ausgegeben, da Funktion 9 nicht den Cursor
; bewegt und Funktion 14 kein Attribut aendert
; dies selbst zu erledigen waere zu aufwendig
; Fkt 14 wird auf jeden Fall benoetigt, da sie u.a. piepsen kann
;
char_out proc
       PUSHR <si,di,bp,ax,cx>
       mov al,cl     ;get to accumulator
       cmp al,' '    ; Piepser oder CR ?
       jb short @@dont
       call char_tran
        push ax
         mov ah,9
         mov bl,txt_attribute
         mov bh,EMU_SCR_PAGE
         mov cx,1
         int 10h                  ; erst mal Attribut setzen
        pop ax
@@dont:
       mov ah,14                  ; character output
       mov bl,txt_attribute
       int 10h                    ; und nochmal um den Cursor weiterzusetzen

       POPR <cx,ax,bp,di,si>
       ret
char_out endp

char_tran proc
       cmp char_tran_flag,FALSE
       jz  short @@exit
       push es
       push ds
       pop  es
       mov  di,offset tr_usa
       mov  cx,tr_french-tr_usa
; muss Zeichen uebersetzt werden ?
       repnz scasb
       pop  es
       jnz  short @@exit
       sub di,offset tr_usa       ; di:= # zu uebersetzendes Zeichen
       dec di                     ; da scas eins zuviel inct
       mov bx,tr_tab_poi
       mov al,bx[di]
@@exit:
       ret
char_tran endp

select_country proc
       mov si,offset ctrl_buf
       mov al,[si]
       cmp al,7
       ja  short @@exit
       mov byte ptr char_tran_flag,FALSE
       cmp al,0
       jz  @@noflag
       mov byte ptr char_tran_flag,TRUE
@@noflag:
       mov bl,tr_french-tr_usa ; Eintraege pro Land
       mul bl
       add ax,offset tr_usa
       mov tr_tab_poi,ax
@@exit:
       ret
select_country endp


;
;
crtinstat proc
;
; console status, return 0ffh if character ready, 00h,Z_flag if not
;
; Out: al=keyboard status
;
        push bx
        mov ah,1                  ; keybord status
        int 16h
        mov al,0ffh
        jnz short @@exit
        mov al,0
@@exit:
        pop bx
        ret
crtinstat endp


crtin proc
;
; console character nach register a
;
; Out: al=ascii
;      ah zerstoert
;
IF WS_KEY
       mov al,after_ctrl_q
       mov after_ctrl_q,0
       cmp al,0
       jnz @@end_crtin
ENDIF
       mov ah,0                   ; keybord input
       push bx
       int 16h
       pop bx
       cmp breakflag,TRUE
       mov breakflag,FALSE
       jnz short @@nobreak
       call prg_exit
       jmp crtin
@@nobreak:

IF WS_KEY    ; erweiterte Codes nach WS bersetzen
       cmp al,0
       jnz short @@no_extended

       push bx

       mov bx,offset ext_keys
       mov cx,ax
@@cmp_loop:
       mov al,[bx]            ; extended code
       mov after_ctrl_q,0     ; damit es bei Aussprung richtig
       cmp al,0
       jz  short @@no_key_tr  ; z = Tabellen ende
       cmp al,ch
       pushf
       inc bx
       mov al,[bx]            ; CTRL-...
       inc bx
       mov ah,[bx]            ; CTRL-Q-...
       inc bx
       mov after_ctrl_q,ah
       popf
       jnz @@cmp_loop

@@no_key_tr:
       pop bx
@@no_extended:
ENDIF

; Umlaute werden in CP/M Form bersetzt
       push di
       push cx
       push es
        push ds
        pop  es
       mov  di,offset tr_french
       mov  cx,tr_end-tr_french
; muss Zeichen uebersetzt werden ?
       repnz scasb
       pop  es
       jnz  short @@exit
       sub di,offset tr_french    ; di:= # zu uebersetzendes Zeichen
       dec di                     ; da scas eins zuviel inct
       mov ax,di
       mov bx,tr_french-tr_usa
       mov dx,0
       div bx
       mov di,dx
       mov bx,offset tr_usa
       mov al,bx[di]
@@exit:
       pop cx
       pop di
     ;  and al,7fh                ;strip parity bit von DR vorgeschlagen
@@end_crtin:
       ret
crtin endp

if KAYPRO_TERM_FKTS_TOO


kaypro_B proc
        mov si,offset kaypro_B_tab
        jmp short kaypro_BC
kaypro_B endp

kaypro_C proc
        mov si,offset kaypro_C_tab
kaypro_BC:
        mov bl,[ctrl_buf]
        and bx,111b             ; range 0-7
        shl bx,1
        jmp BX[si]
kaypro_C endp

Kgraphics_on proc
        mov ah,0fh
        int 10h
        mov video_mode,al

        mov ah,0
        mov al,4        ; 320x200x4
        int 10h
        ret
Kgraphics_on endp

Kgraphics_off proc
        mov ah,0
        mov al,video_mode
        int 10h
        ret
Kgraphics_off endp

Kset_pixel proc
        mov al,1
        jmp short Kpixel
Kset_pixel endp

Kres_pixel proc
        mov al,0
        jmp short Kpixel
Kres_pixel endp

Kpixel proc
         mov si,offset ctrl_buf
         mov dx,[si]
         sub dx,2020h ; dl=y, dh=x


        mov cl,dh
        mov ch,0
        mov dh,ch
        add cx,cx     ; cx=2x
        add cx,cx     ; cx=4x
        add dx,dx     ; dx=2y

        mov bl,al       ; color
        mov bh,0ch      ; plot pixel

        dec cx

       rept 4          ; make each Kaypro Pixel 8 PC Pixel:  xxxx
        inc cx         ;                                     xxxx
        mov ax,bx
        int 10h
       endm

        inc dx
        mov ax,bx
        int 10h

       rept 3
        dec cx
        mov ax,bx
        int 10h
       endm

        ret
Kpixel endp

endif ; kaypro

emulator_seg ends


end

