home *** CD-ROM | disk | FTP | other *** search
/ Simtel MSDOS - Coast to Coast / simteldosarchivecoasttocoast.iso / pcmag / vol7n08.zip / STAYDOWN.ASM < prev    next >
Assembly Source File  |  1988-04-26  |  18KB  |  432 lines

  1.         PAGE    60,132
  2. ;=============================================================================
  3. ; STAYDOWN holds the CTRL, ALT, and SHIFT keys temporarily toggled on,
  4. ; allowing keystroke combinations to be entered with sequential rather
  5. ; than simultaneous keypresses.  Syntax is:
  6. ;
  7. ;    STAYDOWN [/D | /U]
  8. ;
  9. ; where /D disables the program until it is run again from the
  10. ; command line, and /U uninstalls it.
  11. ;=============================================================================
  12.  
  13. KBDATA          EQU     60H                     ;Keyboard data port
  14. KBCTRL          EQU     61H                     ;Keyboard control port
  15. ALT             EQU     38H                     ;Scan code for ALT key
  16. CTRL            EQU     1DH                     ;Scan code for CTRL key
  17. LSHIFT          EQU     2AH                     ;Scan code for left SHIFT key
  18. RSHIFT          EQU     36H                     ;Scan code for right SHIFT key
  19. CR        EQU    0DH
  20. LF        EQU    0AH
  21.  
  22. ;=============================================================================
  23. ;BIOS Data Area
  24. ;=============================================================================
  25. BIOS_DATA       SEGMENT AT 40H
  26.                 ORG     17H
  27. SHIFT_STATE_1   DB      ?                       ;Primary shift state byte
  28. SHIFT_STATE_2   DB      ?                       ;Left CTRL/ALT (bits 0, 1)
  29.                 ORG     96H
  30. SHIFT_STATE_3   DB      ?                       ;Right CTRL/ALT (bits 2, 3)
  31. BIOS_DATA       ENDS
  32.  
  33. ;=============================================================================
  34. ;Code Segment (code and data)
  35. ;=============================================================================
  36. CODE            SEGMENT PARA PUBLIC 'CODE'
  37.         ASSUME  CS:CODE, DS:CODE, ES:CODE, SS:CODE
  38.                 ORG     100H
  39. BEGIN:          JMP     INITIALIZE
  40.  
  41. PROGRAM         DB      "STAYDOWN 1.0 (c) 1988 Ziff Communications Co.",CR,LF
  42. AUTHOR          DB      "PC Magazine ",254," Jeff Prosise",CR,LF,"$",1AH
  43.  
  44. CHECKFLAG       DB      ?                       ;Enable/disable flag
  45. RESTORE_FLAG    DB      0                       ;Break code ignored flag
  46. LAST_SCAN_CODE  DB      0                       ;Last scan code
  47. EO_FLAG         DB      0                       ;80h = last code was E0h
  48. KB_VECTOR       DB      15H                     ;Vector altered to trap keys
  49.  
  50. BIOS_ISR        LABEL   DWORD
  51. OLD_VECTOR      DW      2 DUP (?)               ;Old interrupt 9/15h vector
  52.  
  53. ;-----------------------------------------------------------------------------
  54. ;INT9H handles interrupt 9 on machines that lack interrupt 15h keyboard
  55. ;processing facilities.
  56. ;-----------------------------------------------------------------------------
  57. INT9H           PROC    FAR
  58.     ASSUME    CS:CODE, DS:NOTHING, ES:NOTHING, SS:NOTHING
  59.  
  60.                 CMP     CS:CHECKFLAG,0          ;Exit to BIOS if program
  61.                 JE      PASS_TO_BIOS            ;  isn't currently enabled
  62.  
  63.         STI                ;Interrupts on
  64.                 PUSH    AX
  65.                 IN      AL,KBDATA               ;Read scan code from keyboard
  66.                 CALL    MAIN                    ;Perform internal processing
  67.                 JNC     RESET_KEYBOARD          ;Ignore scan code if CF = 0
  68.                 POP     AX
  69. PASS_TO_BIOS:   JMP     CS:BIOS_ISR             ;Jump to BIOS int handler
  70.  
  71. RESET_KEYBOARD: IN      AL,KBCTRL               ;Reset the keyboard
  72.                 MOV     AH,AL
  73.                 OR      AL,80H
  74.                 OUT     KBCTRL,AL
  75.                 MOV     AL,AH
  76.                 OUT     KBCTRL,AL
  77.                 CLI
  78.                 MOV     AL,20H                  ;Signal EOI to interrupt
  79.                 OUT     20H,AL                  ;  controller
  80.                 STI
  81.                 POP     AX
  82.                 IRET                            ;Exit without processing
  83.  
  84. INT9H           ENDP
  85.  
  86. ;-----------------------------------------------------------------------------
  87. ;INT15H handles interrupt 15h on machines with an extended BIOS.
  88. ;-----------------------------------------------------------------------------
  89. INT15H          PROC    FAR
  90.     ASSUME    CS:CODE, DS:NOTHING, ES:NOTHING, SS:NOTHING
  91.  
  92.                 CMP     AH,4FH                  ;Exit to BIOS handler if
  93.                 JNE     EXIT_TO_BIOS            ;  function code <> 4Fh
  94.  
  95.         STI                ;Interrupt on
  96.                 CMP     CS:CHECKFLAG,0          ;Process scan code as normal
  97.                 JE      PROCESS_SCAN_CODE       ;  if program is disabled
  98.  
  99.                 CMP     AL,0E0H                 ;Set flag and terminate if
  100.                 JNE     NOT_EO                  ;  scan code = E0h
  101.                 MOV     CS:EO_FLAG,80H
  102.                 JMP     SHORT PROCESS_SCAN_CODE
  103.  
  104. NOT_EO:        CMP    CS:EO_FLAG,0        ;Branch if E0 flag not set
  105.         JE    CHECK_CODE
  106.         CMP    AL,2AH            ;If this scan code is part of
  107.         JE    RESET_EO_FLAG        ;  a 4-code sequence, then
  108.         CMP    AL,0AAH            ;  reset E0 flag and process
  109.         JE    RESET_EO_FLAG        ;  the scan code
  110.         CMP    AL,36H
  111.         JE    RESET_EO_FLAG
  112.         CMP    AL,0B6H
  113.         JNE    CHECK_CODE
  114.  
  115. RESET_EO_FLAG:    MOV    CS:EO_FLAG,0        ;Reset flag
  116.         JMP    SHORT PROCESS_SCAN_CODE    ;Process the scan code
  117.  
  118. CHECK_CODE:     PUSH    AX
  119.                 CALL    MAIN                    ;Perform internal processing
  120.                 MOV     CS:EO_FLAG,0
  121.                 POP     AX
  122.                 RET    2                       ;Return with flags intact
  123.  
  124. PROCESS_SCAN_CODE:
  125.                 STC                             ;Set CF for BIOS processing
  126.                 RET    2                       ;Return with flags intact
  127. EXIT_TO_BIOS:   JMP     CS:BIOS_ISR             ;Pass to BIOS for processing
  128.  
  129. INT15H          ENDP
  130.  
  131. ;-----------------------------------------------------------------------------
  132. ;MAIN is called by the two interrupt handling routines to process a keystroke.
  133. ;Entry:  AL - scan code
  134. ;-----------------------------------------------------------------------------
  135. MAIN            PROC    NEAR
  136.     ASSUME    CS:CODE, DS:NOTHING, ES:NOTHING, SS:NOTHING
  137.  
  138.                 TEST    AL,80H                  ;Branch on break code
  139.                 JNZ     BREAK_CODE
  140. ;
  141. ;Process a make code by simply saving the scan code.
  142. ;
  143.                 OR      AL,CS:EO_FLAG           ;Save E0h indicator
  144.                 MOV     CS:LAST_SCAN_CODE,AL    ;Save make code
  145.                 STC                             ;Exit with CF = 1
  146.                 RET
  147. ;
  148. ;A break code was received.
  149. ;
  150. BREAK_CODE:     CMP     CS:RESTORE_FLAG,0       ;Branch if shift bits are
  151.                 JNE     RESTORE_SHIFT_BYTES     ;  out of sync
  152.                 AND     AL,7FH                  ;Strip break bit
  153.                 OR      AL,CS:EO_FLAG           ;Add E0h indicator
  154.                 CMP     AL,CS:LAST_SCAN_CODE    ;Branch if the key released
  155.                 JE      CHECK_FOR_SHIFT         ;  was the last one pressed
  156. PROCESS_BREAK:  MOV     LAST_SCAN_CODE,0        ;Process break code as normal
  157.                 STC
  158.                 RET
  159. ;
  160. ;Ignore the break if the key just released was a shift key.
  161. ;
  162. CHECK_FOR_SHIFT:
  163.                 CMP     AL,ALT                  ;Check codes for ALT, CTRL,
  164.                 JE      IGNORE_BREAK            ;  and SHIFT keys
  165.                 CMP     AL,ALT+80H
  166.                 JE      IGNORE_BREAK
  167.                 CMP     AL,CTRL
  168.                 JE      IGNORE_BREAK
  169.                 CMP     AL,CTRL+80H
  170.                 JE      IGNORE_BREAK
  171.                 CMP     AL,LSHIFT
  172.                 JE      IGNORE_BREAK
  173.                 CMP     AL,RSHIFT
  174.                 JNE     PROCESS_BREAK
  175. IGNORE_BREAK:   MOV     CS:RESTORE_FLAG,AL      ;Ignore the break code
  176.                 MOV     CS:LAST_SCAN_CODE,0
  177.                 CLC                             ;Return with CF = 0
  178.                 RET
  179. ;
  180. ;Reset the BIOS shift bit(s) corresponding to the last key release ignored.
  181. ;
  182. RESTORE_SHIFT_BYTES:
  183.                 MOV     AL,CS:RESTORE_FLAG      ;Recover ignored scan code
  184.                 MOV     CS:RESTORE_FLAG,0       ;Reset flag
  185.                 PUSH    ES                      ;Point ES to BIOS data area
  186.                 PUSH    AX
  187.                 MOV     AX,40H
  188.                 MOV     ES,AX
  189.                 POP     AX
  190.  
  191.                 CMP     AL,RSHIFT               ;Reset a single bit if
  192.                 JNE     NOT_RSHIFT              ;  right SHIFT key was
  193.                 AND     ES:[SHIFT_STATE_1],0FEH ;  released
  194.                 JMP     SHORT END_RESTORE
  195.  
  196. NOT_RSHIFT:     CMP     AL,LSHIFT               ;Likewise for left SHIFT
  197.                 JNE     NOT_LSHIFT
  198.                 AND     ES:[SHIFT_STATE_1],0FDH
  199.                 JMP     SHORT END_RESTORE
  200.  
  201. NOT_LSHIFT:     CMP     AL,CTRL+80H             ;Reset right CTRL key bit
  202.                 JNE     NOT_RCTRL
  203.                 AND     ES:[SHIFT_STATE_3],0FBH
  204.                 JMP     SHORT FIX_PRIMARY_SHIFT
  205.  
  206. NOT_RCTRL:      CMP     AL,CTRL                 ;Reset two left CTRL bits
  207.                 JNE     NOT_LCTRL
  208.                 AND     ES:[SHIFT_STATE_1],0FBH
  209.                 AND     ES:[SHIFT_STATE_2],0FEH
  210.                 TEST    ES:[SHIFT_STATE_3],10H  ;Branch for further processing
  211.                 JZ      END_RESTORE             ;  if this is a 101-key
  212.                 JMP     SHORT FIX_PRIMARY_SHIFT ;  keyboard
  213.  
  214. NOT_LCTRL:      CMP     AL,ALT+80H              ;Reset right ALT bit
  215.                 JNE     NOT_RALT
  216.                 AND     ES:[SHIFT_STATE_3],0F7H
  217.                 JMP     SHORT FIX_PRIMARY_SHIFT
  218.  
  219. NOT_RALT:       AND     ES:[SHIFT_STATE_1],0F7H ;Reset two left ALT bits
  220.                 AND     ES:[SHIFT_STATE_2],0FDH
  221.                 TEST    ES:[SHIFT_STATE_3],10H  ;Test for 101-key keyboard
  222.                 JZ      END_RESTORE             ;Branch if it's not
  223.  
  224. FIX_PRIMARY_SHIFT:
  225.                 MOV     AH,ES:[SHIFT_STATE_2]   ;Set CTRL/ALT bits in primary
  226.                 SHL     AH,1                    ;  shift state byte if either
  227.                 SHL     AH,1                    ;  left or right CTRL/ALT is
  228.                 OR      AH,ES:[SHIFT_STATE_3]   ;  pressed
  229.                 AND     AH,0CH
  230.                 AND     ES:[SHIFT_STATE_1],0F3H
  231.                 OR      ES:[SHIFT_STATE_1],AH
  232. END_RESTORE:    POP     ES
  233.                 JMP     PROCESS_BREAK           ;Process the break code
  234. MAIN            ENDP
  235.  
  236. ;-----------------------------------------------------------------------------
  237. ;INITIALIZE installs the program into memory.
  238. ;-----------------------------------------------------------------------------
  239. HEADMSG        DB    CR,LF,"STAYDOWN: $"
  240. ERRMSG1         DB      "Usage: STAYDOWN [/D][/U]",CR,LF,"$"
  241. ERRMSG2         DB      "Not Installed",CR,LF,"$"
  242. ERRMSG3         DB      "Cannot Uninstall",CR,LF,"$"
  243. ERRMSG4         DB      "Uninstall Error",CR,LF,"$"
  244. CONFIRM_MSG1    DB      "Disabled",CR,LF,"$"
  245. CONFIRM_MSG2    DB      "Uninstalled",CR,LF,"$"
  246. CONFIRM_MSG3    DB      "Activated",CR,LF,"$"
  247.  
  248. INSTALL_FLAG    DB      0
  249.  
  250. INITIALIZE      PROC    NEAR
  251.                 ASSUME  CS:CODE,DS:CODE,ES:CODE,SS:CODE
  252. ;
  253. ;See if STAYDOWN is already installed.
  254. ;
  255.                 CLD                             ;Clear DF
  256.                 NOT     WORD PTR [BEGIN]        ;Initialize fingerprint
  257.                 XOR     BX,BX                   ;Initialize segment values
  258.                 MOV     AX,CS
  259.     ASSUME    ES:NOTHING
  260.  
  261. INIT1:          INC     BX                      ;Advance to next segment
  262.                 MOV     ES,BX
  263.                 CMP     AX,BX                   ;End search if we loop back
  264.                 JE      PARSE                   ;  to the current segment
  265.                 MOV     SI,OFFSET BEGIN         ;Check for ASCII fingerprint
  266.                 MOV     DI,SI
  267.                 MOV     CX,16
  268.                 REPE    CMPSB
  269.                 JNE     INIT1                   ;Loop if not found
  270.                 MOV     INSTALL_FLAG,1          ;Program is already installed
  271. ;
  272. ;Parse the command line for a /D or /U parameter.
  273. ;
  274. PARSE:          MOV     SI,81H                  ;Point DS:SI to command line
  275. PARSE1:         CMP     BYTE PTR [SI],32        ;Advance to first non-space
  276.                 JNE     PARSE2
  277.                 INC     SI
  278.                 JMP     SHORT PARSE1
  279.  
  280. PARSE2:         CMP     BYTE PTR [SI],CR        ;End-of-line?
  281.                 JE      INSTALL                 ;Yes, then install/enable
  282.                 AND     BYTE PTR [SI+1],0DFH    ;Capitalize entry
  283.                 CMP     WORD PTR [SI],442FH     ;Qualifier /D?
  284.                 JE      DISABLE                 ;Yes, then disable program
  285.                 CMP     WORD PTR [SI],552FH     ;Qualifier /U?
  286.                 JE      UNINSTALL               ;Yes, then uninstall program
  287.  
  288.         MOV    AL,1            ;Error code
  289.                 MOV     DX,OFFSET ERRMSG1       ;Error message address
  290. ERROR_EXIT:
  291.         PUSH    AX            ;Save registers
  292.         PUSH    DX
  293.  
  294.         MOV    DX,OFFSET HEADMSG    ;Display prologue
  295.                 MOV     AH,9
  296.                 INT     21H
  297.  
  298.         POP    DX            ;Display error
  299.                 MOV     AH,9
  300.                 INT     21H
  301.  
  302.         POP    AX            ;Error code
  303.                 MOV     AH,4CH                  ;Terminate with ERRORLEVEL set
  304.                 INT     21H
  305. ;
  306. ;Disable STAYDOWN if a copy is present in memory.
  307. ;
  308. DISABLE:
  309.                 CMP     INSTALL_FLAG,1          ;Error if not installed
  310.         JE    DISABLE2
  311.  
  312.         MOV    AL,2
  313.                 MOV     DX,OFFSET ERRMSG2       ;Initialize error pointer
  314.                 JMP     ERROR_EXIT
  315. DISABLE2:
  316.                 MOV     ES:[CHECKFLAG],0        ;Clear CHECKFLAG byte
  317.                 MOV     DX,OFFSET CONFIRM_MSG1  ;Print confirmation message
  318. CONFIRM_AND_EXIT:
  319.         PUSH    DX
  320.  
  321.         MOV    DX,OFFSET HEADMSG
  322.                 MOV     AH,9
  323.                 INT     21H
  324.  
  325.         POP    DX
  326.                 MOV     AH,9
  327.                 INT     21H
  328.  
  329.                 MOV     AX,4C00H                ;Exit with ERRORLEVEL = 0
  330.                 INT     21H
  331. ;
  332. ;Uninstall STAYDOWN if a copy is present in memory.
  333. ;
  334. UNINSTALL:
  335.  
  336.                 CMP     INSTALL_FLAG,1          ;Error if not installed
  337.                 JE      UNINSTALL2
  338.  
  339.         MOV    AL,3
  340.                 MOV     DX,OFFSET ERRMSG2       ;Initialize error pointer
  341.         JMP    ERROR_EXIT
  342. UNINSTALL2:
  343.                 CALL    REMOVE                  ;Uninstall the program
  344.                 JNC     UNINSTALL3
  345.  
  346.         MOV    AL,4
  347.         JMP    ERROR_EXIT
  348. UNINSTALL3:
  349.                 MOV     DX,OFFSET CONFIRM_MSG2  ;Print confirmation message
  350.                 JMP     SHORT CONFIRM_AND_EXIT  ;And exit
  351. ;
  352. ;Install the program if it isn't already installed, or enable it if it is.
  353. ;
  354. INSTALL:        MOV     ES:[CHECKFLAG],1        ;Set enable byte
  355.                 CMP     INSTALL_FLAG,1          ;Branch if not installed
  356.                 JNE     INSTALL1
  357.                 MOV     DX,OFFSET CONFIRM_MSG3  ;Print confirmation message
  358.                 JMP     SHORT CONFIRM_AND_EXIT  ;And exit
  359.  
  360. INSTALL1:       MOV     AH,0C0H                 ;Check for BIOS support of
  361.                 INT     15H                     ;  extended functions
  362.                 MOV     DX,OFFSET INT15H
  363.                 JNC     INSTALL2                ;Branch if support is there
  364.                 MOV     KB_VECTOR,9             ;Use int 9 rather than 15h
  365.                 MOV     DX,OFFSET INT9H         ;Point DX to int 9 routine
  366.  
  367. INSTALL2:       MOV     AH,35H                  ;Save current vector
  368.                 MOV     AL,KB_VECTOR
  369.                 INT     21H
  370.                 MOV     OLD_VECTOR,BX
  371.                 MOV     OLD_VECTOR[2],ES
  372.                 MOV     AH,25H                  ;Then point it to internal
  373.                 MOV     AL,KB_VECTOR            ;  interrupt handler
  374.                 INT     21H
  375.  
  376.                 MOV     AX,DS:[2CH]             ;Get environment segment
  377.                 MOV     ES,AX                   ;  address from PSP
  378.                 MOV     AH,49H                  ;Then deallocate environment
  379.                 INT     21H                     ;  space reserved by DOS
  380.  
  381.                 MOV     AH,9                    ;Print installation message
  382.                 MOV     DX,OFFSET PROGRAM
  383.                 INT     21H
  384.  
  385.                 MOV     AX,3100H                ;Terminate but remain resident
  386.                 MOV     DX,(OFFSET INITIALIZE-OFFSET CODE+15) SHR 4
  387.                 INT     21H
  388.  
  389. INITIALIZE      ENDP
  390.  
  391. ;-----------------------------------------------------------------------------
  392. ;REMOVE deallocates the memory block addressed by ES and restores the
  393. ;Interrupt vector displaced on installation.
  394. ;-----------------------------------------------------------------------------
  395. REMOVE          PROC    NEAR
  396.  
  397.                 PUSH    ES                      ;Get current interrupt 9/15h
  398.                 MOV     AH,35H                  ;  vector and see if STAYDOWN
  399.                 MOV     AL,ES:[KB_VECTOR]       ;  still owns it
  400.                 INT     21H
  401.  
  402.                 MOV     BX,ES
  403.                 POP     ES
  404.         MOV    AX,ES
  405.                 CMP     BX,AX            ;Program cannot be uninstalled
  406.                 JE      RESTORE_VECTOR          ;  if interrupt 9/15h vector
  407.                 MOV     DX,OFFSET ERRMSG3       ;  has been grabbed away
  408.                 STC                             ;Return with CF = 1 for error
  409.                 RET
  410. RESTORE_VECTOR:
  411.         PUSH    DS                      ;Restore displaced interrupt
  412.         ASSUME  DS:NOTHING                      ;  vector
  413.  
  414.                 LDS     DX,ES:[BIOS_ISR]
  415.                 MOV     AH,25H
  416.                 MOV     AL,ES:[KB_VECTOR]
  417.                 INT     21H
  418.                 POP     DS
  419.         ASSUME  DS:CODE
  420.  
  421.                 NOT     WORD PTR ES:[BEGIN]     ;Remove fingerprint
  422.  
  423.                 MOV     AH,49H                  ;Free memory given to
  424.                 INT     21H                     ;  original program block
  425.                 MOV     DX,OFFSET ERRMSG4       ;Initialize error pointer
  426.                 RET                             ;Exit with CF intact
  427.  
  428. REMOVE          ENDP
  429.  
  430. CODE            ENDS
  431.                 END     BEGIN
  432.