title     DOORS2.ASM
comment ~
      άάάάάάάάάάάάάάάάάάάάάάάάάάάάάάάάάάάάάάάάάάάάάάάάάά
     ΙΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝ»Ϋ
     Ί               PCMagizine ASseMbler             ΊΫ
     Ί                                                ΊΫ
     Ί     The following program began its life in    ΊΫ
     Ί     PC Magazine. A detailed description of     ΊΫ
     Ί     the program can be found in the issue      ΊΫ
     Ί     referenced below.                          ΊΫ
     Ί                                                ΊΫ
     ΘΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΝΌί

     DOORS.ASM     John Dickinson, "Try a Door, Not a Window"
               Vol. 4, No. 3 (February  5, 1985)
               Coordinating your color and monochrome
               displays

The program becomes memory resident when run, and scans the
keycodes of any keys pressed.  In its original version, if the
Alt - Right Shift keys were pressed together, the routine would
copy all screen information to the monitor not being used, and
would switch to that monitor.

The program has been modified slightly.  Now, the Alt - Left Shift
keys will switch monitors.  The Alt - Right Shift keys will copy
all text information to the other screen, but leave you where you
were on the original monitor.  (I use this function to put a
"snapshot" of text on the other screen for reference while I work).

If the program is switching to the graphics board, it does so in
the BW80 mode -- which can be changed to the CO80 mode (see the
comments below) if you have a color monitor.

Modified January 1986.

Please let me know about any bugs/comments that you have via
Gene Plantz' IBBS, 312-882-4227.
                                                     Mike Pechnyo
                                                     ID1206
  ~
;
ROM_BIOS_DATA     segment at 40h          ; Low Memory "BIOS" Parameters
;
     org     10h             ; Location of EQUIP_FLAG
EQUIP_FLAG   dw     ?        ; Contains video settings
                             ; in bits 4 and 5
;
     org     17h             ; Location of KB_FLAG
KB_FLAG      db     ?        ; Contains Alt (bit 3) &
                             ; Right Shift (bit 0) States
ROM_BIOS_DATA     ends
;
; Initialization Routine
;
CODE_SEG     segment
     assume  cs:CODE_SEG
     org     100h            ; COM program format
BEGIN:     jmp     SWAP_VECTORS      ; Initialize vectors and attach to DOS
;
ROM_KB_INT     dd     ?      ; Double word to save address of
                             ; ROM-BIOS keyboard interrupt
video_hold  dw 2000 dup(?)   ; storage to hold the old screen
old_mode    db ?

; DOORS_INT intercepts the keyboard interrupt and switches
;  screens if [Alt]-[Shift] combination is pressed
;

DOORS_INT     proc     near
     assume     ds:nothing
     push     ds             ; Push all affected registers
     push     es
     push     ax
     push     bx
     push     cx
     push     dx
     push     si
     push     di
;
     pushf                   ; Push Flags for fake interrupt call
     call     ROM_KB_INT     ; to BIOS program to read keyboard
;
     assume   ds:ROM_BIOS_DATA        ; Define data segment to read
     mov      ax,ROM_BIOS_DATA        ; keyboard flag & equipment flag
     mov      ds,ax
     mov      cx,2            ; times to go through the loop
     mov      al,KB_FLAG      ; Get keyboard flag
     and      al,11           ; Isolate [Alt] + [Shift keys]
     cmp      al,09           ; is [Alt] + [Right Shift] pressed ?
     je       go_ahead
     cmp      al,10           ; is [Alt] + [Left Shift] pressed ?
     jne      RETURN          ; No, quit
     mov      cx,1            ; set cx to 1 if Left Shift, 2 if Right Shift
                              ; do 2 passes through the code if Right Shift
                              ; (copy info to opposite screen), 1 pass if
                              ; Left Shift (switch monitors)
;
; [Alt] + [Right Shift] are pressed -- Continue processing
; Check on video mode - quit if not monochrome, color 80x25 or BW 80x25
;
go_ahead:
                              ; first check the original screen mode
     mov      ah,15           ; Call Func 15 of Int 10h to
     int      10h             ; get video state of the PC
     cmp      al,7            ; Is screen monochrome?
     je       SCREEN_OKAY     ; Yes, go switch screens
     cmp      al,3            ; Is screen color text?
     jbe      CHECK_40_OR_80         ; Yes, go check for 80 or 40 char
     jmp      RETURN          ; Screen is in graphics mode, quit
CHECK_40_or_80:
     cmp      al,1            ; Is screen 40-character?
     jbe      RETURN          ; Yes, quit
;
SCREEN_OKAY:
     push     cx              ; save the number of times to do the work

;
; Save the current cursor position
;
     mov      ah,3            ; Call Func 3 of Int 10H
     mov      bh,0            ; to read cursor position
     int      10h             ; (page zero for color screen)
;
; Screen switch routine - Establish calling argument (AL) for Int 10h
;
     mov      bx,EQUIP_FLAG   ; Current equipment flag to BX
     mov      cx,bx           ; Make a copy of it in CX
     and      cx,30h          ; Extract screen information
     xor      bx,cx           ; Erase current screen information in BX
     or       bx,20h          ; Set BX to color 80x25
     mov      al,2            ; Set AL for B&W 80x25 in Int 10h
                              ; change to 3 for color 80x25
     cmp      cx,30h          ; Is current mono?
     je       SET_MODE        ; Yes, switch to color
     or       bx,30h          ; No, set BX for monochrome
     mov      al,7            ; Set AL for monochrome in Int 10h
SET_MODE:
     mov      EQUIP_FLAG,bx   ; Write BX to equipment flag
     xor      ah,ah           ; Use Func 0 of Int 10h to
     int      10h             ; change screen parameters
;
; Restore Cursor
;
     mov      ah,2            ; Use Func 2 of Int 10h to restore
     mov      bh,0            ; cursor on new screen (position in DX)
     int      10h
;
; After screens are switched, set DS and ES registers to move screen data
;
     push     ds              ; save the data segment
     mov      ax,0b000h       ; Load ES with Mono Segment
     mov      es,ax
     mov      ax,0b800h       ; Load DS with Color Segment
     mov      ds,ax
     cmp      cx,30h          ; Did we switch from mono?
     jne      COPY_THE_SCREEN ; NO, move data from mono to color
     push     ds              ; YES, swap ES and DS to move data
     push     es              ; from mono to color
     pop      ds
     pop      es
COPY_THE_SCREEN:
     xor      di,di           ; Start at zero offsets
     xor      si,si
     mov      cx,2000         ; 2000 chars + attrs per screen
     cld                      ; Make sure move is 'forward'
rep     movsw                 ; Move Words with string instruction
                              ; from DS:[SI] to ES:[DI]
     pop      ds              ; restore the data segment

     pop      cx              ; restore the count value
     loop     SCREEN_OKAY     ; and go back if CX>0
;
RETURN:
     pop      di              ; Restore saved registers
     pop      si
     pop      dx
     pop      cx
     pop      bx
     pop      ax
     pop      es
     pop      ds
     iret                     ; Return to system

DOORS_INT      endp
;
; This procedure initializes the new keyboard interupt vectors
;
SWAP_VECTORS  proc     near
;     push     ds              ; Save Data Segment
                              ; for DOS return
comment |
     mov     ax,VECTORS       ; Set up the data
     mov     ds,ax             ; segment for vectors
     cli                         ; Disable interrupts
     mov     ax,word ptr KB_INT_VECTOR          ; Store addresses
     mov     word ptr ROM_KB_INT,ax               ; of BIOS program
     mov     ax,word ptr KB_INT_VECTOR[2]
     mov     word ptr ROM_KB_INT[2],ax
     mov     word ptr KB_INT_VECTOR, offset DOORS_INT ; Substitute Our
     mov     word ptr KB_INT_VECTOR[2],cs          ; Program
     sti                         ; Enable interrupts

     ; the old code (commented out) has been replaced by the
     ; more kosher DOS 2.0 Get and Set interrupt calls -- of course,
     ; this DOES require using DOS 2.0 or above  --  and the routine
     ; does NOT check the DOS version
  |
     mov      ah,35h
     mov      al,9                      ; keyboard function
     int      21h                       ; get interrupt vector
     mov      word ptr ROM_KB_INT,bx    ; offset
     mov      word ptr ROM_KB_INT[2],es ; segment

     mov      ah,25h
     mov      al,9
     push     cs
     pop      ds                        ; DS:DX point to this routine
     mov      dx,offset DOORS_INT
     int      21h                       ; set interrupt vector

     mov      dx,offset SWAP_VECTORS    ; End of new resident
                                        ; program
     int      27h                       ; Terminate resident
SWAP_VECTORS     endp
CODE_SEG     ends
     end     BEGIN
;
