home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / basic / library / qb_pds / ansi / pansi.bas next >
Encoding:
BASIC Source File  |  1992-07-24  |  20.6 KB  |  670 lines

  1. 'PANSI.BAS v1.50
  2. 'ANSI emulator for QuickBASIC 4.5 and PDS
  3. 'By Richard Geldreich July 24, 1992
  4. 'Don't forget that "CALL INTERRUPT" is used- load QB with "QB/l"
  5.  
  6. 'I have fixed up & improved the ANSI escape sequence state machine. It
  7. 'now works faster. I still don't know why I'm releasing this driver,
  8. 'because I'm going to release my all-assembly version very soon...
  9. '(the assembly version of this driver is light years ahead of this program!)
  10. 'See the PrintANSI procedure for a list of bug fixes.
  11.  
  12. '!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  13. '! Don't forget to modify the "SendStatus" procedure for your !
  14. '!                       comm package!                        !
  15. '!    You also should modify PrintString for QB4.5 or PDS     !
  16. '!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  17.  
  18. 'I welcome any suggestions or ideas about this program... It _should_
  19. 'emulate DOS's ANSI.SYS device driver... This program is in the public
  20. 'domain; do what you want with it! Have a ball!! Just try and give
  21. 'me some credit. Thanks. I have tested this driver out with many BBS's
  22. 'and door programs and it works fine. Please test this driver out before
  23. 'you release it in a program!!!
  24.  
  25. 'NOTE: This program assumes that the current segment is always
  26. 'pointing twards the video buffer!! If you change the current
  27. 'segment don't forget to change it back or sparks will fly when you
  28. 'write to the screen! (see GetVSeg)
  29.  
  30. 'Info:
  31. 'ClearScreen- used internally by the PrintAnsi procedure- you may
  32. 'use it to clear the current window(the current background color
  33. 'is used in the clear). The cursor is set to the upper left hand corner
  34. 'of the window after the window is cleared.
  35.  
  36. 'CursorControl A- if A is non-zero then the SetCursor routine(which
  37. 'is called by PrintAnsi) will update the cursor whenever it is moved.
  38. 'If it is zero then SetCursor won't touch the cursor's position.
  39.  
  40. 'GetVSeg- Returns the current video segment.
  41.  
  42. 'Init- Initializes the driver. This should be called before any other
  43. 'procedure. Completly resets the entire driver, sets the window to the
  44. 'current screen page & size and moves the cursor to the upper left hand
  45. 'corner of the screen.
  46.  
  47. 'Music A- if A is not zero, then ANSI music is enabled.
  48.  
  49. 'PrintAnsi Char- where Char is an ASCII code from 0-255. Recognizes
  50. 'ANSI escape sequences(of course!). Processes the character and
  51. 'updates the display, if needed
  52.  
  53. 'PrintString A$- prints a string to the display. Calls PrintAnsi for
  54. 'each character. Don't forget to modify this for PDS/QuickBASIC.
  55.  
  56. 'ScrollUpScreen- scrolls up the current window. Uses a BIOS call.
  57. 'Normally used internally by PrintAnsi.
  58.  
  59. 'SendStatus- sends a CPR sequence to the receiver.
  60. 'In other words, SendStatus will output the current X and Y coordinates
  61. 'of the cursor to the remote terminal. Used by some BBS's and doors
  62. 'to see if the user's terminal has ANSI capibilities. You must modify
  63. 'this procedure to output the status string to your comm package!
  64. '(this is used internally by PrintAnsi)
  65.  
  66. 'SetCursor- moves the cursor to its correct position(it doesn't turn
  67. 'it on however- use the LOCATE , , 1 command to do that). This procedure
  68. 'should work on all adapters, but I haven't tested it out on many
  69. 'cards yet... Use this to restore the cursor to where it should be
  70. 'after you move it. If you want, change this procedure to use QB's
  71. 'LOCATE command instead of the OUT's.
  72.  
  73. 'SetWindow WorkPage, Lx,Ly,Hx,Hy- defines a window where all text
  74. 'is printed. if WorkPage is -1, then the BIOS data area is examined for
  75. 'the current screen page, otherwise WorkPage must indicate which page to
  76. 'write to. If Lx is -1, the the window will take up the entire screen
  77. 'otherwise Lx and Ly are the upper-left lines of the window(where
  78. '1,1 is the upper corner of the screen) and Hx and Hy are the lower-right
  79. 'coordinates of the window.
  80. '   The current cursor position is moved to the upper left corner of the
  81. 'new window. If the coordinates passed are invalid, the window is not
  82. 'modified.
  83.  
  84. '   That's all! You can add more functions if you need them; I've
  85. 'documented the PrintAnsi procedure enough for you to get
  86. 'a good idea of how it works.
  87.  
  88. '   The assembly version of this driver very close to completion and I will
  89. 'be posting it very soon...
  90.  
  91. DEFINT A-Z
  92.  
  93. DECLARE SUB ClearScreen ()
  94. DECLARE SUB CursorControl (A%)
  95. DECLARE FUNCTION GetVSeg% ()
  96. DECLARE SUB Init ()
  97. DECLARE SUB Music (A%)
  98. DECLARE SUB PrintANSI (Char%)
  99. DECLARE SUB PrintString (B$)
  100. DECLARE SUB ScrollUpScreen ()
  101. DECLARE SUB SendStatus (X%, Y%)
  102. DECLARE SUB SetCursor ()
  103. DECLARE SUB SetWindow (WorkPage%, Lx%, Ly%, Hx%, Hy%)
  104.  
  105. DECLARE SUB playme (A$)
  106.  
  107. TYPE RegType
  108.      Ax    AS INTEGER
  109.      Bx    AS INTEGER
  110.      Cx    AS INTEGER
  111.      Dx    AS INTEGER
  112.      bp    AS INTEGER
  113.      si    AS INTEGER
  114.      di    AS INTEGER
  115.      flags AS INTEGER
  116. END TYPE
  117.  
  118. DIM SHARED Xpos, Ypos               'cursor's position
  119. DIM SHARED MinX, MinY, MaxX, MaxY   'current window
  120. DIM SHARED SaveX, SaveY             'used by SCR and RCP
  121. DIM SHARED Colors(7), Attribute
  122. DIM SHARED CursorOn, VideoSegment, VideoOffset, CursorAddress, BytesPerLine
  123. DIM SHARED Monochrome, CRT          'monochrome adapter flag
  124. DIM SHARED ANSIMusic, MusicLevel
  125. DIM SHARED Level
  126.  
  127. CONST True = -1, False = NOT True   'usefull stuff
  128.  
  129. 'The color translation table is used to translate an ANSI color
  130. 'to a screen color.
  131. ColorTable:
  132.     DATA 0,4,2,6,1,5,3,7
  133.  
  134. '******START OF TEST PROGRAM
  135. 'The following code is not needed... It's only for testing!
  136.  
  137. SCREEN 0
  138. WIDTH 80, 25
  139. CLS
  140. LOCATE , , 1            'turn cursor on
  141.  
  142. Init
  143. ClearScreen             'clear the window
  144. SetWindow -1, 1, 1, 80, 25 'set window at (1,2)-(80,25)
  145.  
  146. 'DO
  147. '    A$ = INKEY$: IF A$ <> "" THEN PrintString A$
  148. 'LOOP
  149.  
  150. 'test ANSI music
  151. PrintString CHR$(27) + "[MFO1CDEFGABC" + CHR$(14)
  152.  
  153. 'A! = TIMER
  154. 'PrintString STRING$(5000, 65)
  155. 'B! = TIMER
  156. 'PRINT 5000 / (B! - A!)
  157. 'END
  158.  
  159. 'a lame test
  160. Esc$ = CHR$(27)
  161. Up$ = CHR$(27) + "[A"
  162. Down$ = CHR$(27) + "[B"
  163. Lft$ = CHR$(27) + "[D"
  164. Rgt$ = CHR$(27) + "[C"
  165. Foreground = 31: Background = 40: Bold = 0
  166. X = 1: Y = 1
  167. DO
  168.     A$ = CHR$(27) + "["
  169.     IF NOT Bold THEN A$ = A$ + "0;" ELSE A$ = A$ + "1;"
  170.     PrintString A$ + MID$(STR$(Foreground), 2) + ";" + MID$(STR$(Background), 2) + "m"
  171.     
  172.     Bold = NOT Bold
  173.     Foreground = Foreground + 1
  174.     IF Foreground > 37 THEN
  175.         Foreground = 31
  176.         Background = Background + 1
  177.         IF Background > 47 THEN Background = 40
  178.     END IF
  179.     PrintString CHR$(27) + "[s" + CHR$(219) + CHR$(27) + "[u"
  180.     IF Xdirect THEN
  181.         X = X - 1
  182.         PrintString Lft$
  183.         IF X = 1 THEN Xdirect = 0
  184.     ELSE
  185.         X = X + 1
  186.         PrintString Rgt$
  187.         IF X = 80 THEN Xdirect = 1
  188.     END IF
  189.     IF Ydirect THEN
  190.         Y = Y - 1
  191.         PrintString Up$
  192.         IF Y = 1 THEN Ydirect = 0
  193.     ELSE
  194.         Y = Y + 1
  195.         PrintString Down$
  196.         IF Y = 24 THEN Ydirect = 1
  197.     END IF
  198.  
  199. LOOP UNTIL INKEY$ <> ""
  200.  
  201. END
  202. '******END OF TEST PROGRAM
  203.  
  204. 'Clears the current window. The cursor is also set to the upper-left hand
  205. 'corner of the window.
  206. SUB ClearScreen
  207.     DIM Regs AS RegType
  208.     Regs.Ax = &H600
  209.     A& = Attribute * 256&
  210.     IF A& > 32767 THEN A = A& - 65536 ELSE A = A&
  211.     Regs.Bx = A
  212.     Regs.Cx = (MinY * 256&) + MinX - 257
  213.     Regs.Dx = (MaxY * 256&) + MaxX - 257
  214.     CALL interrupt(&H10, Regs, Regs)
  215.  
  216.     Xpos = MinX: Ypos = MinY
  217.     SetCursor
  218.  
  219.  
  220. END SUB
  221.  
  222. 'Enables or disables cursor updating.
  223. SUB CursorControl (A)
  224.     IF A THEN
  225.         CursorOn = True
  226.     ELSE
  227.         CursorOn = False
  228.     END IF
  229. END SUB
  230.  
  231. 'Returns the current video segment.
  232. FUNCTION GetVSeg
  233.     GetVSeg = VideoSegment
  234. END FUNCTION
  235.  
  236. 'Initializes everything.
  237. SUB Init
  238.     DIM Regs AS RegType
  239.  
  240.     'default color, white on black (or black on white??)
  241.     Attribute = 7
  242.  
  243.     Level = 0: MusicLevel = 0   'reset levels
  244.     ANSIMusic = True            'ANSI music enabled
  245.     CursorOn = True             'cursor movement enabled
  246.  
  247.     'read in color translation table
  248.     RESTORE ColorTable
  249.     FOR A = 0 TO 7: READ Colors(A): NEXT
  250.    
  251.     Regs.Ax = 15 * 256
  252.     CALL interrupt(&H10, Regs, Regs)
  253.     'if AL=7 then card is monochrome.
  254.     IF (Regs.Ax AND 255) = 7 THEN
  255.         VideoSegment = &HB000
  256.         Monochrome = True
  257.     ELSE
  258.         VideoSegment = &HB800
  259.         Monochrome = False
  260.     END IF
  261.     DEF SEG = &H40
  262.     CRT = PEEK(&H63) + PEEK(&H64) * 256&
  263.  
  264.     'Set segment to the screen.
  265.     DEF SEG = VideoSegment
  266.  
  267.     'window defaults to screen's page & size
  268.     'Xpos, Ypos, SaveX, SaveY, MinX, MinY, MaxX, MaxY, VideoOffset and the
  269.     'cursor are set up within this procedure
  270.     SetWindow -1, -1, 0, 0, 0
  271.  
  272. END SUB
  273.  
  274. 'Enables/Disables ANSI music...
  275. SUB Music (A)
  276.     ANSIMusic = A
  277. END SUB
  278.  
  279. 'Prints an ASCII character on the screen; filters out
  280. 'ANSI escape sequences and parses them.
  281. 'Fixups from last version(howcome nobody told me about these errors?!):
  282. ' A chr$(27) would not be processed correctly if received from within
  283. '   another escape sequence. This has been fixed.
  284. ' SetCursor now uses a BIOS variable to get the correct OUT address... It
  285. '   should now work on monochrome and color monitors.
  286. ' The cursor set, up & down commands are now not ignored if the cursor is
  287. '  set to a position that is invalid.
  288. ' The entire parameter table is set to 1 so special case tests do not
  289. '  have to be performed. Parameters will now be interpeted as 1 if they
  290. '  are zero in the cursor set commands(these two aren't bugs, just
  291. '  improvements!)
  292. ' ESC[m now resets the attribute to 7. The new page command, CHR$(12), now
  293. '  resets the screen to attribute 7 before clearing(not really a bug, but...)
  294. ' OOPS!! The cursor position command, ESC[H, was processed as an absolute
  295. '  coordinate relative to the upper-left hand of the screen... It should of
  296. '  been processed relative to the upper-left hand corner of the window! DUMB!
  297. '  So if the window was set to (1,2)-(80,25), and an ESC[H was received, the
  298. '  cursor would not move anywhere.... This of course has been fixed.
  299. '
  300. ' I discovered almost all of these little bugs while coding the assembly
  301. ' version of the driver...
  302. SUB PrintANSI (Char) STATIC
  303.     DIM Parameters(10)
  304.     
  305.     SELECT CASE Level
  306.     CASE 0
  307.         'normal mode
  308.         GOSUB ProcessChar
  309.     CASE 1
  310.         'Level=1 after a chr$(27) is received.
  311.         'valid escape sequence?
  312.  
  313.         IF Char <> 91 THEN
  314.             Level = 0
  315.             GOSUB ProcessChar
  316.         ELSE
  317.             'a valid escape sequence has been received
  318.             Level = 2
  319.             CurrentParameter = 0
  320.             NumParameters = 0
  321.             ValidParameter = False
  322.             FOR A = 0 TO 10: Parameters(A) = 1: NEXT
  323.         END IF
  324.     CASE 2
  325.  
  326.         'inside an escape sequence
  327.         GOSUB ProcessCode
  328.     END SELECT
  329. EXIT SUB
  330.  
  331. ProcessChar:
  332.     'processes a non-ANSI code
  333.     SELECT CASE Char
  334.     'process new page code
  335.     CASE 12
  336.         Attribute = 7
  337.         ClearScreen
  338.     'process escape character
  339.     CASE 27
  340.         Level = 1
  341.     'process enter
  342.     CASE 13
  343.         Xpos = MinX
  344.         SetCursor
  345.     'process line feed
  346.     CASE 10
  347.         Ypos = Ypos + 1
  348.         IF Ypos > MaxY THEN Ypos = MaxY: ScrollUpScreen
  349.         SetCursor
  350.     'process backspace(non-destructive)
  351.     CASE 8
  352.         IF Xpos > MinX THEN
  353.             Xpos = Xpos - 1
  354.             SetCursor
  355.         END IF
  356.     'process tab key(tab stops=8)
  357.     CASE 9
  358.         Xpos = ((Xpos \ 8) + 1) * 8
  359.         IF Xpos > MaxX THEN Xpos = MaxX
  360.         SetCursor
  361.     'process bell
  362.     CASE 7
  363.         'don't substitute a "BEEP" statement here!
  364.         'BEEP resets the cursor to where QB thinks it is!
  365.         SOUND 3140, 1.25
  366.     'any other character is sent to the screen
  367.     CASE ELSE
  368.  
  369.         'prints a character to the screen
  370.         POKE CursorAddress, Char: POKE CursorAddress + 1, Attribute
  371.         CursorAddress = CursorAddress + 2
  372.         Xpos = Xpos + 1
  373.  
  374.         IF Xpos > MaxX THEN
  375.  
  376.             Xpos = MinX
  377.             Ypos = Ypos + 1
  378.             IF Ypos > MaxY THEN
  379.                 Ypos = MaxY
  380.                 ScrollUpScreen
  381.             END IF
  382.             SetCursor
  383.         ELSE
  384.             IF CursorOn THEN
  385.                 Address = CursorAddress \ 2
  386.                 OUT CRT, &HE
  387.                 OUT CRT + 1, Address \ 256
  388.                 OUT CRT, &HF
  389.                 OUT CRT + 1, Address AND 255
  390.             END IF
  391.         END IF
  392.     END SELECT
  393. RETURN
  394. 'processes a character within an ansi escape sequence
  395. 'non-valid characters are sent to the screen
  396. ProcessCode:
  397. 'handles ANSI music...
  398. IF MusicLevel > 0 THEN
  399.     SELECT CASE MusicLevel
  400.     'see if the "F" in "ESC[MF" is received...
  401.     CASE 1
  402.         IF Char <> 70 THEN          '"F"
  403.             MusicLevel = 0
  404.             Level = 0
  405.             GOSUB ProcessChar
  406.         ELSE
  407.             MusicLevel = 2
  408.             MusicString$ = ""
  409.         END IF
  410.         'Either add a char to the music string or play it...
  411.     CASE 2
  412.         IF Char <> 14 THEN
  413.             'fall out if an escape character is received...
  414.             IF Char = 27 THEN
  415.                 MusicString$ = ""
  416.                 MusicLevel = 0
  417.                 Level = 0
  418.                 GOSUB ProcessChar
  419.             'assume the character received to be part of the
  420.             'PLAY string
  421.             ELSE
  422.                 MusicString$ = MusicString$ + CHR$(Char)
  423.             END IF
  424.         ELSE
  425.             IF ANSIMusic THEN
  426.                 'play the string- the PLAY command is in a seperate
  427.                 'module to keep error checking out of this module
  428.                 playme MusicString$
  429.             END IF
  430.             MusicString$ = ""
  431.             MusicLevel = 0
  432.             Level = 0
  433.         END IF
  434.     END SELECT
  435. ELSE
  436.     SELECT CASE Char
  437.     CASE 77                             '"M"
  438.         MusicLevel = 1
  439.     CASE 48 TO 57                       '0-9
  440.         'all parameters should be lower than 199...
  441.         IF CurrentParameter < 199 THEN
  442.             CurrentParameter = CurrentParameter * 10 + (Char - 48)
  443.             ValidParameter = True
  444.         ELSE
  445.             Level = 0
  446.             GOSUB ProcessChar
  447.         END IF
  448.     CASE 59
  449.         GOSUB MakeParameter             '";"
  450.     'CUP-set cursor's position
  451.     CASE 72, 102                        'H or f
  452.         GOSUB MakeParameter
  453.         Ypos = MinY + A - 1
  454.         A = Parameters(1): IF A = 0 THEN A = 1
  455.         Xpos = MinX + A - 1
  456.         IF Xpos > MaxX THEN Xpos = MaxX
  457.         IF Ypos > MaxY THEN Ypos = MaxY
  458.         SetCursor
  459.         Level = 0
  460.     'CUU- cursor up
  461.     CASE 65                             'A
  462.         GOSUB MakeParameter
  463.         Ypos = Ypos - A
  464.         IF Ypos < MinY THEN Ypos = MinY
  465.         SetCursor
  466.         Level = 0
  467.     'CUD-cursor down
  468.     CASE 66                             'B
  469.         GOSUB MakeParameter
  470.         Ypos = Ypos + A
  471.         IF Ypos > MaxY THEN Ypos = MaxY
  472.         SetCursor
  473.         Level = 0
  474.     'CUF-cursor forward
  475.     CASE 67                             'C
  476.         GOSUB MakeParameter
  477.         Xpos = Xpos + A
  478.         IF Xpos > MaxX THEN Xpos = MaxX
  479.         SetCursor
  480.         Level = 0
  481.     'CUB-cursor backward
  482.     CASE 68                              'D
  483.         GOSUB MakeParameter
  484.         Xpos = Xpos - A
  485.  
  486.         IF Xpos < MinX THEN Xpos = MinX
  487.         SetCursor
  488.         Level = 0
  489.     'SCR-save cursor position
  490.     CASE 115                            's
  491.         SaveX = Xpos: SaveY = Ypos
  492.         Level = 0
  493.     'RCP-restore cursor position
  494.     CASE 117                            'u
  495.         Xpos = SaveX: Ypos = SaveY
  496.         Level = 0
  497.         SetCursor
  498.     'ED-erase display(ESC[2J and ESC[J work
  499.     'both work)
  500.     CASE 74                             'J
  501.         ClearScreen
  502.         Level = 0
  503.     'EL-erase in line
  504.     CASE 75                             'K
  505.         A = CursorAddress
  506.         FOR X = Xpos TO MaxX
  507.             POKE A, 32: POKE A + 1, Attribute: A = A + 2
  508.         NEXT
  509.         Level = 0
  510.     'SGR-sets new color
  511.     CASE 109                            'm
  512.         GOSUB MakeParameter
  513.         'if no color codes then stuff 0 into the table
  514.         IF NumParameters = 0 THEN Parameters(0) = 0: NumParameters = 1
  515.         FOR A = 0 TO NumParameters - 1
  516.             P = Parameters(A)
  517.             SELECT CASE P
  518.             CASE IS <= 8
  519.                 SELECT CASE P
  520.                 'all attributes off
  521.                 CASE 0
  522.                     Attribute = 7
  523.                 'high-intensity
  524.                 CASE 1
  525.                     Attribute = Attribute OR 8
  526.                 'blinking
  527.                 CASE 5
  528.                     Attribute = Attribute OR 128
  529.                 'inverse
  530.                 CASE 7
  531.                     Attribute = (Attribute AND 136) OR (Attribute AND 7) * 16 OR (Attribute AND 112) \ 16
  532.                 END SELECT
  533.                 'set foreground
  534.             CASE 30 TO 37
  535.                 IF NOT Monochrome THEN
  536.                     Attribute = (Attribute AND 248) OR Colors(P - 30)
  537.                 END IF
  538.                 'set background
  539.             CASE 40 TO 47
  540.                 IF NOT Monochrome THEN
  541.                     Attribute = (Attribute AND 143)
  542.                     Attribute = Attribute OR Colors(P - 40) * 16
  543.                 END IF
  544.             END SELECT
  545.         NEXT
  546.         Level = 0
  547.     'DSR-outputs a CPR sequence
  548.     'This function outputs the string "ESC[#;#R" where
  549.     '#;# is the current Y and current X coordinate
  550.     'to the receiver.
  551.     'Calls SendStatus to do its dirty work...
  552.     CASE 110
  553.         SendStatus Xpos, Ypos
  554.         Level = 0
  555.     'any other code is assumed to be invalid;it's just sent to the
  556.     'screen
  557.     CASE ELSE
  558.         Level = 0
  559.         GOSUB ProcessChar
  560.     END SELECT
  561. END IF
  562. RETURN
  563. 'stores a numeric parameter into the parameter table
  564. MakeParameter:
  565.     'check to see if a least one digit has been received
  566.     'for this parameter and there's room left in the table
  567.     IF ValidParameter AND NumParameters < 10 THEN
  568.         'add parameter to table
  569.         Parameters(NumParameters) = CurrentParameter
  570.         NumParameters = NumParameters + 1
  571.         CurrentParameter = 0
  572.         ValidParameter = False
  573.     END IF
  574.  
  575.     'Set A equal to the first parameter and make it 1 if it's 0
  576.     A = Parameters(0)
  577.     IF A = 0 THEN A = 1
  578.  
  579. RETURN
  580. END SUB
  581.  
  582. 'Prints a string to the display.
  583. SUB PrintString (B$)
  584.     A& = SADD(B$)
  585.     IF A& < 0 THEN A& = A& + 65536
  586.  
  587.     STOP' You must change the next line if you're using QB4.5!
  588.     'It is currently coded for PDS.
  589.  
  590.     'Segment = VARSEG(B$) + A& \ 16
  591.  
  592.     Segment = SSEG(B$) + A& \ 16    'change to VARSEG(B$) for QB4.5 & QBASIC
  593.     
  594.     Address = A& MOD 16
  595.     FOR B = Address TO Address + LEN(B$) - 1
  596.         DEF SEG = Segment
  597.         A1 = PEEK(B)
  598.         DEF SEG = VideoSegment
  599.         PrintANSI A1
  600.     NEXT
  601. END SUB
  602.  
  603. SUB ScrollUpScreen
  604.     DIM Regs AS RegType
  605.     Regs.Ax = &H601
  606.    
  607.     A& = Attribute * 256&
  608.     IF A& > 32767 THEN A = A& - 65536 ELSE A = A&
  609.     Regs.Bx = A
  610.    
  611.     Regs.Cx = (MinY * 256&) + MinX - 257
  612.     Regs.Dx = (MaxY * 256&) + MaxX - 257
  613.     CALL interrupt(&H10, Regs, Regs)
  614. END SUB
  615.  
  616. 'Sends the screen's status to the receiver. You must modify the
  617. '"PRINT #1, A$;" command to print to your comm package.
  618. 'Sends "ESC[##;##R" where ##;## is Y;X.
  619. SUB SendStatus (X, Y)
  620.     A$ = CHR$(27) + "[" + RIGHT$("0" + MID$(STR$(Y), 2), 2)
  621.     A$ = A$ + ";" + RIGHT$("0" + MID$(STR$(X), 2), 2) + "R"
  622.  
  623. '*****Change the next line to print this string out to your comm package!!****
  624.     PRINT A$;           'DON'T insert a line feed!!
  625.     
  626. END SUB
  627.  
  628. 'Sets the cursor- uses OUT's for speed
  629. SUB SetCursor
  630.     'Must do this...
  631.  
  632.     CursorAddress = (Xpos - 1) * 2 + (Ypos - 1) * BytesPerLine + VideoOffset
  633.     IF CursorOn THEN
  634.         Address = CursorAddress \ 2
  635.         OUT CRT, &HE
  636.         OUT CRT + 1, Address \ 256
  637.         OUT CRT, &HF
  638.         OUT CRT + 1, Address AND 255
  639.     END IF
  640. END SUB
  641.  
  642. 'Sets a new printing window.
  643. SUB SetWindow (WorkPage, Lx, Ly, Hx, Hy)
  644.     DEF SEG = &H40
  645.     IF WorkPage = -1 THEN
  646.         VideoOffset = PEEK(&H4E) + PEEK(&H4F) * 256&
  647.     ELSE
  648.         VideoOffset = (PEEK(&H4C) + PEEK(&H4D) * 256&) * WorkPage
  649.     END IF
  650.  
  651.     ScreenX = PEEK(&H4A)
  652.     ScreenY = PEEK(&H84) + 1
  653.  
  654.     IF Lx = -1 THEN
  655.         MinX = 1: MinY = 1
  656.         MaxX = ScreenX: MaxY = ScreenY
  657.         BytesPerLine = MaxX * 2
  658.     ELSE
  659.         'change window size if coordinates are valid
  660.         IF Lx <= Hx AND Ly <= Hy AND Hx <= ScreenX AND Hy <= ScreenY THEN
  661.             MinX = Lx: MaxX = Hx: MinY = Ly: MaxY = Hy
  662.         END IF
  663.     END IF
  664.     DEF SEG = VideoSegment
  665.     Xpos = MinX: Ypos = MinY
  666.     SaveX = MinX: SaveY = MinY
  667.     SetCursor
  668. END SUB
  669.  
  670.