        name    capslk
        page    55,96
        title   'CAPSLK - a CapsLock unlatcher'

; This install and stay resident program releases the keyboard from
; the CapsLock state whenever a letter key is pressed while a shift
; key also depressed.  tHIS ELIMINATES A WELL KNOWN ANNOYANCE.
;
; Note that keyboards with CapsLock indicator lights may get out of
; synchronization since they have no way of knowing when the caplock bit
; in KB_FLAG is changed.
;
; This source based on a disassembly of CAPSLOCK.BAS in the Oct 15 '85
; issue of PC Magazine.  Annotation and some minor changes in code to
; shorten program and reduce the number of execution clocks, implementation
; of function call 31h vs INT 27h by Herb Shear, SVCS Librarian.

cseg    segment         para public 'CODE'

        assume          cs:cseg, ds:cseg, es:cseg

        org     100h                ;start of com program


begin:  jmp     short sta_res       ;proceed to stay resident code
vector: dd      ?                   ;storage for next code in daisychain

start   proc near
        sti                         ;enable interrupts
        push    ax                  ;save registers
        push    cx
        push    di
        push    es
        pushf
        xor     ax,ax               ;clear ax register
        mov     es,ax               ;ES =  seg 0
        mov     di,417h             ;set a pointer to KB_FLAG
        mov     ah,es:[di]          ;load KB_FLAG
        test    ah,03h              ;see if a shift key is pressed
        jz      exit                ;exit if not pressed
        in      al,60h              ;get keyboard scan code from port
        cmp     al,10h              ;compare to Q key position
        jb      exit                ;lower numbered position than Q key
        cmp     al,19h              ;compare to P key position
        jna     unlock              ;key in Q..P range
        cmp     al,1eh              ;compare to A key position
        jb      exit                ;non-alpha key position
        cmp     al,26h              ;compare to L key position
        jna     unlock              ;key in A..L range
        cmp     al,2ch              ;compare to Z key position
        jb      exit                ;non-alpha key position
        cmp     al,32h              ;compare to M key position
        ja      exit                ;key not in Z..M range
unlock: and     ah,0bfh             ;clear CapsLock bit
        mov     es:[di],ah          ;reset KB_FLAG
exit:   popf                        ;restore registers
        pop     es
        pop     di
        pop     cx
        pop     ax
        jmp     dword ptr cs:[vector]  ;follow the INT 9 daisychain

sta_res:
        xor     ax,ax               ;zero ax register
        mov     es,ax               ;zero es register
        mov     di,9h * 4h          ;interrupt 9 address
        mov     ax,es:[di]          ;get the interrupt vector
        mov     bx,es:[di+2]
        mov     si, offset vector   ;pointer to vector storage
        mov     [si],ax             ;save the interrupt vector
        mov     [si+2],bx
        mov     bx,ds               ;get seg of resident code
        cli                         ;turn off interrupts
        mov     ax,offset start     ;get offset of resident code
        mov     es:[di],ax          ;store as new INT 9 vector
        mov     es:[di+2],bx
        sti                         ;turn interrupts back on
        mov     dx,offset sta_res   ;end of resident code + 1
        mov     cl,4                ;prepare for shift
        shr     dx,cl               ;convert to paragraphs
        inc     dx                  ;roundup to full paragraph
        mov     ax,3100h            ;set exit code = zero
        int     21h                 ;terminate & stay resident
start   endp
cseg    ends
        end    begin
