home *** CD-ROM | disk | FTP | other *** search
/ Simtel MSDOS 1992 June / SIMTEL_0692.cdr / msdos / printer / lq15tsr.arc / SETP1524.ASM < prev    next >
Assembly Source File  |  1988-02-05  |  28KB  |  585 lines

  1. ;
  2. interrupts    segment at 0h                      ;interrupt table segment
  3.               org 9h*4
  4. keyboard_int  dw 2 dup (?)                       ;interrupt 9 vector
  5. interrupts    ends
  6. ;
  7. rom_bios_data segment at 40h                     ;ROM BIOS data area segment
  8.               org 60h
  9. ;
  10. cursor_mode   dw ?                      ;starting and ending cursor scan lines
  11. rom_bios_data ends
  12. ;
  13. rom           segment at 0F000h                  ;ROM segment
  14.               org 0FFFEh
  15. ;
  16. machine_id    db ?                ;ID byte identifies machine as PCjr or other
  17. rom           ends
  18. ;
  19. code          segment para public 'code'         ;code segment
  20.               assume cs:code
  21.               org 100h
  22. ;
  23. begin:        jmp initialize                     ;goto initialization routine
  24. ;
  25.               db '(C) Copyright 1986, Ziff-Davis Publishing Company ', 1Ah
  26.  
  27. shift_right   equ  1h
  28. shift_left    equ  2h
  29. shift_ctrl    equ  4h
  30. shift_alt     equ  8h 
  31. shift_trigger equ  shift_right+shift_left ; 
  32.  
  33. column_count  dw ?              ;width of window in columns 
  34. cursor_type   dw ?              ;cursor scan line definition 
  35. setup_status  db 0              ;indicator if printer window is already active
  36. display_mode  dw ?              ;current crt display mode 
  37. page_no       dw ?              ;current displayed page 
  38. attribute1    db 4Fh            ;window attribute bytes 
  39. attribute2    db 70h ; 
  40. display_table db 2Dh,29h        ;display re-enable values for modes 2 and 3 
  41. video         dw 0B800h,0B900h,0BA00h,0BB00h     ;starting addresses of video 
  42.                                                  ;memory for CGA pages 0 - 3
  43. ;
  44. mono_video    dw 0B000h                          ;video segment address for
  45.                                                  ;monochrome adapter
  46. ;
  47. old_kb_int              label dword
  48. old_keyboard_int        dw 2 dup (?)             ;storage for old keyboard
  49.                                                  ;interrupt vector
  50. ;
  51. ;----------------------------------------------------------------------------
  52. ;Text of the Printer Setup Menu window.
  53. ;After initialization, text and attribute bytes are combined and stored
  54. ;in the WINDOW_TEXT area, and this area is used to store the contents of
  55. ;the screen that underlie the window when the window is called up.
  56. ;----------------------------------------------------------------------------
  57. ;
  58. window_buffer           label word
  59. buffer_text             db 201,26 dup (205),187
  60.                         db 186,'    PRINTER SETUP MENU    ',186
  61.                         db 186,'    PANASONIC KXP-1524    ',186
  62.                         db 199,26 dup (196),182
  63.                         db 186,' F1    Compressed Mode    ',186
  64.                         db 186,' F2    Expanded Mode      ',186
  65.                         db 186,' F3    Emphasized Mode    ',186
  66.                         db 186,' F4    Quality Mode       ',186
  67.                         db 186,' F5    Elite/Pica Mode    ',186
  68.                         db 186,' F6    Miniature Mode     ',186
  69.                         db 186,' F7    Skip Perforation   ',186
  70.                         db 186,' F8    Form Feed/Line Feed',186
  71.                         db 186,' F9    Reset Top-of-Form  ',186
  72.                         db 186,' F10   Reset Print Modes  ',186
  73.                         db 186,' ESC   Exit               ',186
  74.                         db 199,26 dup (196),182
  75.                         db 186,' Unshifted:   Toggle ON   ',186
  76.                         db 186,' Shifted:     Toggle OFF  ',186
  77.                         db 200,26 dup (205),188
  78.                         db 532 dup (?)
  79. ;
  80. ;Storage area for the combination of text and attribute bytes that
  81. ;form the window image.
  82. ;
  83. window_bytes  label byte
  84. window_text   dw 532 dup (?)
  85. ;
  86. ;Control code strings for all of the printer setup options.
  87. ;
  88. code_table:   db 15,255,14 dup (0)                      ;compressed mode on .
  89.               db 27,87,31,255,12 dup (0)                ;expanded mode on   .
  90.               db 27,69,255,13 dup (0)                   ;emphasized mode on .
  91.               db 27,120,1,255,27,85,49,9 dup (0)        ;quality mode on    .
  92.               db 27,77,255,13 dup (0)                   ;elite mode on      .
  93.               db 15,27,83,0,27,65,6,255,8 dup (0)       ;miniature mode on  .
  94.               db 27,78,6,255,12 dup (0)                 ;perfskip on        .
  95.               db 12,255,14 dup (0)                      ;Form Feed          .
  96.  
  97.               db 27,64,255,13 dup (0)                   ;reset top-of-form  .
  98.               db 27,64,255,13 dup (0)                   ;reset print modes  .
  99. ;
  100.               db 18,255,14 dup (0)                      ;compress off       .
  101.               db 27,87,30,255,12 dup (0)                ;expand off         .
  102.               db 27,70,255,13 dup (0)                   ;emphasize off      .
  103.               db 27,120,0,255,27,85,48,9 dup (0)        ;quality mode  off  .
  104.               db 27,80,255,13 dup (0)                   ;pica  on           .
  105.               db 18,27,84,27,50,255,10 dup (0)          ;miniature off      .
  106.               db 27,79,255,13 dup (0)                   ;perfskip off       .
  107.               db 13,10,255,13 dup (0)                   ;line feed          .
  108. ;
  109. ;---------------------------------------------------------------------------
  110. ;Execution comes here, to the main body of the program, when an interrupt 9
  111. ;is generated from the keyboard.  Registers are saved, then the keypress is
  112. ;checked and compared to the key combination that activates the menu window.
  113. ;---------------------------------------------------------------------------
  114. ;
  115. main          proc near
  116.               sti                                ;enable software interrupts
  117.               push ax                            ;save all registers
  118.               push bx
  119.               push cx
  120.               push dx
  121.               push si
  122.               push di
  123.               push ds
  124.               push es
  125.               push ax                   ;save ax for call to old routine
  126.               in al,0A0h                         ;re-enable NMI on PCjr
  127.               pop ax                             ;restore ax
  128.               pushf          ;simulate interrupt call to old keyboard routine
  129.               call old_kb_int                    ;call old routine
  130.               mov ah,2                   ;check status of the shift keys
  131.               int 16h
  132.               and al,shift_trigger               ;trigger keys depressed?
  133.               cmp al,shift_trigger
  134.               je do_program                      ;yes, then skip exit routine
  135. ;
  136. ;Exit routine is the common point of exit for all routines in the program.
  137. ;
  138. exit:         pop es
  139.               pop ds
  140.               pop di
  141.               pop si
  142.               pop dx
  143.               pop cx
  144.               pop bx
  145.               pop ax
  146.               iret
  147. ;
  148. ;Execution comes here when the proper key combination, Ctrl/Rt-Shift, is
  149. ;pressed.  First task is to check whether or not the window is already open.
  150. ;
  151. do_program:   push cs                   ;set es and ds to the code segment
  152.               pop ds
  153.               push cs
  154.               pop es
  155.               cmp setup_status,0                 ;is the window already open?
  156.               jne exit                           ;yes, then ignore request
  157. ;
  158. ;----------------------------------------------------------------------------
  159. ;Check current video mode.  If it's mode 2, 3, or 7, then set the window
  160. ;status flag, store the mode number and page number, save the cursor type,
  161. ;and hide the cursor.  If any other display mode is active instead, ignore
  162. ;the request and exit.
  163. ;----------------------------------------------------------------------------
  164. ;
  165.               mov ah,15                          ;get page and mode numbers
  166.               int 10h                            ;al=mode, bh=page
  167.               cmp al,2                  ;is crt now in an acceptable mode?
  168.               je prog0                           ;yes, then continue
  169.               cmp al,3
  170.               je prog0
  171.               cmp al,7
  172.               je prog0
  173.               jmp exit                           ;no, then ignore reques
  174.  
  175. prog0:        mov setup_status,1                 ;set status flag tmZdicate
  176.                                                  ;that window is active
  177.               mov ah,0                           ;save mode number
  178.               mov display_mode,ax
  179.               push bx
  180.               mov bl,bh                 ;save page number for color displays
  181.               mov bh,0
  182.               mov page_no,bx
  183.               pop bx
  184.               mov ah,3                           ;get cursor type
  185.               int 10h
  186.               mov cursor_type,cx                 ;save it
  187.               mov ah,1                           ;hide the cursor until later
  188.               mov ch,20h
  189.               int 10h
  190. ;
  191. ;Preparatory routines are completed.  Now open the window by first saving the
  192. ;contents of video memory beneath the window and then writing the window text
  193. ;directly to memory.
  194. ;
  195.               mov bx,page_no             ;use bx as index into video segment
  196.                                          ;address table
  197.               cmp display_mode,7         ;manually adjust index for monochrome
  198.                                          ;adapter
  199.               jne prog1
  200.               mov bx,4
  201. prog1:        shl bx,1                           ;multiply bx by two since
  202.                                                  ;table is made up of words
  203.               mov ax,video[bx]                   ;read segment from table
  204.               mov ds,ax                          ;ds set to video memory
  205.               cmp display_mode,7                 ;skip disable if in mode 7
  206.               je prog2
  207.               call video_disable      ;turn display off for snow-free writing
  208. prog2:        lea di,window_buffer         ;set di to buffer area to save
  209.                                            ;screen contents
  210.               mov ch,28               ;define window dimensions and location
  211.               mov cl,19
  212.               mov dh,2
  213.               mov dl,26
  214.               call video2mem          ;then transfer screen contents to buffer
  215.               push ds                            ;set es to video memory
  216.               pop es
  217.               push cs                            ;reset ds to code segment
  218.               pop ds
  219.               lea si,window_text                 ;point si to window image
  220. prog3:        mov ch,28                          ;define window region
  221.               mov cl,19
  222.               mov dh,2
  223.               mov dl,26
  224.               call mem2video            ;and write the window to the display
  225.               cmp display_mode,7                 ;skip enable if in mode 7
  226.               je getkey
  227.               call video_enable                  ;re-enable the video display
  228. ;
  229. ;Window is now present on the screen, so wait for a keypress.
  230. ;
  231. getkey:       mov ah,0                           ;get a keypress
  232.               int 16h
  233.               cmp al,0                           ;is it an extended code?
  234.               je extended_code                   ;yes, go interpret it
  235.               cmp al,'a'                         ;make some more ways
  236.               jb  tryesc                         ; out
  237.               cmp al,'z'
  238.               ja  getkey1
  239. tryesc:
  240.               cmp al,27                          ;is it the ESC key?
  241.               jne getkey1               ;no, then signal illegal keypress
  242. ;
  243. ;----------------------------------------------------------------------------
  244. ;Execution comes here when the ESC key is pressed.  The window is refilled
  245. ;with its original contents, the cursor is restored, and control is handed
  246. ;back to the application program.
  247. ;----------------------------------------------------------------------------
  248. ;
  249. esc:          
  250.               cmp display_mode,7                 ;skip disable if in mode 7
  251.               je prog4
  252.               call video_disable                 ;turn off the display
  253. prog4:        lea si,window_buffer               ;point si to the buffer area
  254.               mov ch,28                          ;define the window
  255.               mov cl,19
  256.               mov dh,2
  257.               mov dl,26
  258.               call mem2video     ;and write the buffer contents to the display
  259.               cmp display_mode,7                 ;skip enable if in mode 7
  260.               je prog5
  261.               call video_enable                  ;turn display back on
  262. prog5:        mov ah,1                           ;restore cursor
  263.               mov cx,cursor_type
  264.               int 10h
  265.               mov setup_status,0                 ;reset window status
  266.               jmp exit                           ;and exit
  267. ;
  268. ;Getkey1 routine handles an illegal keypress by beeping and returning
  269. ;for another.
  270. ;
  271. getkey1:      call beep                 ;beep and return for another keypress
  272.               jmp getkey
  273. ;
  274. ;An extended code has been entered...check its validity and goto the
  275. ;appropriate routine.
  276. ;
  277. extended_code:
  278.               cmp ah,59                          ;less than F1?
  279.               jb getkey1                         ;yes, then don't accept it
  280.               cmp ah,91                          ;greater than Shft-F8?
  281.               ja getkey1                         ;yes, then don't accept it
  282.               cmp ah,68                          ;between F1 and F10?
  283.               jbe unshifted                      ;yes
  284.               cmp ah,84                          ;between Shft-F1 and Shft-F9?
  285.               jae shifted                        ;yes
  286.               jmp getkey1     ;if all tests failed, then keypress was illegal
  287. ;
  288. ;----------------------------------------------------------------------------
  289. ;If a legal function key was pressed, its scan code is translated here to the
  290. ;starting address of the string of bytes to be sent to the printer.  The
  291. ;string is then sent to LPT1: provided it's powered on and on-line.
  292. ;----------------------------------------------------------------------------
  293. ;
  294. shifted:      sub ah,15                ;adjustment for shifted function keys
  295. unshifted:    sub ah,59                ;adjustment for unshifted function keys
  296.               mov al,ah                          ;convert index to word in ax
  297.               xor ah,ah
  298.               mov cl,4                           ;multiply ax by 16
  299.               shl ax,cl
  300.               add ax,offset code_table     ;convert ax to full offset address
  301.               mov si,ax                          ;and transfer it to si
  302.               call lpt1stat                      ;check for printer ready
  303.               jc getkey1                         ;beep if printer not ready
  304.               mov bl,255               ;specify delimiter for call to LPRINTZ
  305.               call lprintz             ;send control code string to printer
  306.               jmp getkey                         ;return for another keypress
  307. ;
  308. main          endp                               ;end of main body of program
  309. ;
  310. ;---------------------------------------------------------------------------
  311. ;VIDEO_ENABLE and VIDEO_DISABLE routines manipulate bit 3 of port 3D8h,
  312. ;the CGA Mode Control Register, to temporarily turn the display on or off.
  313. ;Since these routines write directly to hardware, they have no effect on
  314. ;other video adapters.
  315. ;---------------------------------------------------------------------------
  316. ;
  317. video_disable proc near
  318.               mov dx,3DAh                        ;read CGA status port
  319. disable1:     in al,dx                  ;wait for vertical retrace to occur
  320.               test al,8                          ;is bit 3 set?
  321.               je disable1                        ;no, wait until it is
  322.               mov dx,3D8h                        ;now disable the display
  323.               mov al,25h      ;by clearing bit 3 of the Mode Control Register
  324.               out dx,al
  325.               ret
  326. video_disable endp
  327. ;
  328. video_enable  proc near
  329.               mov dx,3D8h                        ;CGA Mode Control Register
  330.               mov bx,display_mode        ;get value to re-enable display
  331.               sub bx,2
  332.               mov al,display_table[bx]
  333.               out dx,al                          ;and send it to the port
  334.               ret
  335. video_enable  endp
  336. ;
  337. ;---------------------------------------------------------------------------
  338. ;VIDEO2MEM routine transfers the contents of a portion of video memory
  339. ;to memory buffer for storage.
  340. ;Entry:       DS    - video segment
  341. ;             ES:DI - memory buffer
  342. ;             DH,DL - row and column of upper left corner of window
  343. ;             CH    - width of window in columns
  344. ;             CL    - number of lines in window
  345. ;---------------------------------------------------------------------------
  346. ;
  347. video2mem     proc near
  348.               mov al,ch                          ;store number of columns
  349.               mov ah,0
  350.               mov column_count,ax
  351.               mov ch,0                           ;cx = number of lines
  352.               push di                            ;save di
  353.               call video_offset         ;get cell address of first character
  354.               mov si,di                          ;put it in si
  355.               pop di                             ;restore di
  356. v2mem1:       push si                            ;save si for next line
  357.               push cx                            ;save line count
  358.               mov cx,column_count                ;set cx for call to WRITELN
  359.               call writeln                       ;transfer one line
  360.               pop cx                             ;restore saved registers
  361.               pop si
  362.               add si,160                         ;set si for next line address
  363.               loop v2mem1               ;loop until all lines are done
  364.               ret
  365. video2mem     endp
  366. ;
  367. ;---------------------------------------------------------------------------
  368. ;MEM2VIDEO writes a selected area of memory to the video display.
  369. ;Entry:       DS:SI - memory buffer
  370. ;             ES    - video segment
  371. ;             DH,DL - row and column of upper left corner of window
  372. ;             CH    - width of window in columns
  373. ;             CL    - number of lines in window
  374. ;------------------------------------------m-$------------------------------
  375. ;
  376. mem2video     proc near
  377.               mov al,ch                          ;save number of columns
  378.               mov ah,0
  379.               mov column_count,ax
  380.               mov ch,0                           ;cx = number of lines
  381.               call video_offset                  ;get offset into video memory
  382. mem2v1:       push di                            ;save video starting address
  383.               push cx                            ;save line count
  384.               mov cx,column_count                ;set cx for call to WRITELN
  385.               call writeln                       ;transfer one line
  386.               pop cx                             ;restore registers
  387.               pop di
  388.               add di,160                         ;set di for next display line
  389.               loop mem2v1                        ;loop until done
  390.               ret
  391. mem2video     endp
  392. ;
  393. ;---------------------------------------------------------------------------
  394. ;VIDEO_OFFSET calculates the offset into video memory of a character cell.
  395. ;Entry:       DH,DL - row and column of cell (0-24,0-79)
  396. ;Exit:        DI    - offset address
  397. ;---------------------------------------------------------------------------
  398. ;
  399. video_offset  proc near
  400.               mov al,160
  401.               mul dh                             ;row * 160
  402.               shl dl,1                           ;column * 2
  403.               mov dh,0                           ;byte to word
  404.               add ax,dx                          ;(row *160)+(column*2)
  405.               mov di,ax                          ;set offset in di
  406.               ret
  407. video_offset  endp
  408. ;
  409. ;---------------------------------------------------------------------------
  410. ;WRITELN subroutine copies a string of words from one memory location to
  411. ;another.  The CGA status port is not checked for vertical retrace status
  412. ;before transfer.
  413. ;Entry:       DS:SI - source
  414. ;             ES:DI - destination
  415. ;             CX    - number of words
  416. ;---------------------------------------------------------------------------
  417. ;
  418. writeln       proc near
  419.               cld                       ;clear for string instructions
  420. write1:       movsw                              ;move one word
  421.               loop write1                        ;loop until done
  422.               ret
  423. writeln       endp
  424. ;
  425. ;---------------------------------------------------------------------------
  426. ;LPRINTZ routine sends a string of bytes delimited by a user-specified byte to
  427. ;LPT1: thru INT 17h.
  428. ;Entry:       DS:SI - string address
  429. ;             BL    - delimiter (0-255)
  430. ;---------------------------------------------------------------------------
  431. ;
  432. lprintz       proc near
  433.               cld                                ;for 8088 string instructions
  434. lprintz1:     lodsb                              ;get one byte
  435.               cmp al,bl                          ;is it the delimiter?
  436.               je lprintz2                        ;yes, then exit
  437.               mov dx,0                           ;printer no. 0 (LPT1:)
  438.               mov ah,0
  439.               int 17h                            ;send byte to printer
  440.               jmp lprintz1                       ;return for next byte
  441. lprintz2:     ret
  442. lprintz       endp
  443. ;
  444. ;---------------------------------------------------------------------------
  445. ;LPT1STAT checks the current status of printer LPT1:.  If it's either
  446. ;powered off or off-line, then an error condition is signalled upon return
  447. ;thru the carry flag.
  448. ;Exit:        Carry clear - no error
  449. ;             Carry set   - error
  450. ;---------------------------------------------------------------------------
  451. ;
  452. lpt1stat      proc near
  453.               mov dx,0                  ;printer no. 0
  454.               mov ah,2                  ;use ROM BIOS 'get status' function
  455.               int 17h
  456.               test ah,8                 ;test bit 3, I/O error indicator
  457.               je stat1                  ;if clear, then no error
  458.               stc                       ;raise error flag
  459.               ret
  460. stat1:        clc                       ;clear error flag
  461.               ret
  462. lpt1stat      endp
  463. ;
  464. ;---------------------------------------------------------------------------
  465. ;BEEP uses the 8253 timer chip to emit a short beep thru the PC's speaker.
  466. ;---------------------------------------------------------------------------
  467. ;
  468. beep          proc near
  469.               mov al,182          ;notify 8253 that frequency data is coming
  470.               out 67,al
  471.               mov al,0                           ;send frequency (776.8 Hz)
  472.               out 66,al
  473.               mov al,6
  474.               out 66,al
  475.               in al,97                           ;activate speaker
  476.               or al,3
  477.               out 97,al
  478.               mov cx,6000h                  ;time delay for sound duration
  479. beep1:        loop beep1
  480.               in al,97                           ;deactivate speaker
  481.               and al,252
  482.               out 97,al
  483.               ret
  484. beep          endp
  485. ;
  486. ;---------------------------------------------------------------------------
  487. ;MEM2MEM subroutine transfers a non-overlapping block of memory one byte
  488. ;at a time.
  489. ;Entry:       DS:SI - source
  490. ;             ES:DI - destination
  491. ;             CX    - number of bytes
  492. ;---------------------------------------------------------------------------
  493. ;
  494. mem2mem       proc near
  495.               cld
  496. mem1:         movsb                              ;transfer one byte
  497.               loop mem1                          ;and loop until done
  498.               ret
  499. mem2mem       endp
  500. ;
  501. ;---------------------------------------------------------------------------
  502. ;Initialization routine sets up the window image in the WINDOW_TEXT area,
  503. ;resets the CURSOR_MODE word if this is a PCjr, and saves and replaces the
  504. ;old keyboard interrupt vector.
  505. ;---------------------------------------------------------------------------
  506. ;
  507. initialize    proc near
  508. ;
  509. ;Initialize the window text area by combining the text data with the attribute
  510. ;bytes and placing the conglomeration in the WINDOW_TEXT area.
  511. ;
  512.               assume ds:code,es:code
  513.               mov ah,15                          ;check the current video mode
  514.               int 10h
  515.               cmp al,7          ;if it's mode 7, then replace the attribute
  516.               jne init0          ;bytes with ones appropriate for mono adapter
  517.               mov attribute1,70h
  518.               mov attribute2,07h
  519. init0:        cld                  ;now combine the text and attribute bytes
  520.               lea si,buffer_text                 ;point si to table of text
  521.               lea di,window_bytes                ;and di to storage area
  522.               mov cx,112           ;create first four lines by combining
  523.               mov al,attribute1          ;text with attribute1 (112 words)
  524. init1:        movsb                              ;text byte
  525.               stosb                              ;attribute byte
  526.               loop init1                 ;loop until all 112 words are done
  527.               mov cx,11                          ;now do the next 11 lines
  528. init2:        push cx              ;first attribute in each line is attribute1
  529.               movsb
  530.               stosb
  531.               mov cx,26            ;next 26 attributes are attribute2
  532.               mov al,attribute2
  533. init3:        movsb
  534.               stosb
  535.               loop init3
  536.               movsb
  537.               mov al,attribute1     ;and the last in each line is attribute1
  538.               stosb
  539.               pop cx
  540.               loop init2            ;loop until all 11 lines are done
  541.               mov cx,112            ;create the last four lines just like
  542. init4:        movsb                 ;the first four
  543.               stosb
  544.               loop init4
  545. ;
  546. ;Check the machine ID byte in ROM and if this is a PCjr, then reset the
  547. ;cursor and correct the CURSOR_MODE word at 0040:0060.
  548. ;
  549.               mov ax,rom                         ;set ds to rom
  550.               mov ds,ax
  551.               assume ds:rom
  552.               cmp machine_id,0FDh                ;is this a PCjr?
  553.               jne init5                          ;no, then skip this routine
  554.               mov ax,rom_bios_data               ;set ds to ROM BIOS data area
  555.               mov ds,ax
  556.               assume ds:rom_bios_data
  557.               mov cursor_mode,0607h          ;reset the cursor mode indicator
  558.               mov ah,1                       ;then physically reset the cursor
  559.               mov cx,0607h
  560.               int 10h
  561. ;
  562. ;Now save the old keyboard interrupt vector and replace it with the new one.
  563. ;
  564. init5:        mov ax,interrupts          ;set ds to the interrupt vector area
  565.               mov ds,ax
  566.               assume ds:interrupts
  567.               mov ax,keyboard_int                ;save old vector
  568.               mov old_keyboard_int,ax
  569.               mov ax,keyboard_int[2]
  570.               mov old_keyboard_int[2],ax
  571.               cli                        ;disable all interrupts but NMI
  572.               mov keyboard_int,offset main       ;and install new vector
  573.               mov keyboard_int[2],cs
  574.               sti                                ;re-enable interrupts
  575.               mov dx,offset initialize   ;point dx to end of resident section
  576.               int 27h                            ;terminate-but-stay-resident
  577. initialize    endp
  578. ;
  579. code          ends
  580.               end begin
  581.  
  582.  
  583. Press any key to continue...
  584. 
  585.