home *** CD-ROM | disk | FTP | other *** search
- TITLE STACKKEY
-
- ;INITIAL VALUES : CS:IP 0000:0100
- ; SS:SP 0000:FFFE
-
- com_segment SEGMENT
- ASSUME cs:com_segment, es:com_segment
- assume ss:com_segment, ds:com_segment
-
- org $+80h
- keybuffer equ $
- parmbuffer equ $
- ORG $+80h
-
- bufptr equ $
- maxkeys equ 255
- keybuflen equ (2*maxkeys)
-
- ; WARNING: the code and data below is EXACTLY the right length to
- ; be consumed by the keybuffer starting at 080h
-
- epoint:
- MOV SI, parmbuffer
- LODSB
- CBW
- MOV BX, AX
- MOV BYTE PTR [BX+SI], 0 ; null terminate cmd line
- look_for_slash:
- LODSB
- OR AL, AL
- JZ no_more_parms
- CMP AL, '/'
- jz found_slash
- cmp al, ' '
- JZ look_for_slash
- jmp do_parms
- found_slash:
- LODSB
- CMP AL, 'I'
- JZ do_install
- CMP AL, 'i'
- JZ do_install
- cmp al, 'f'
- jz do_file_parms
- cmp al, 'F'
- jz do_file_parms
- JMP look_for_slash
-
- ; if no parms, print installation check results
- no_more_parms:
- MOV AX, 0D44Fh
- XOR BX, BX
- INT 2Fh ; install check
- CMP AX, 44DDh
- JNZ not_installed
- MOV DX, offset fdosalready
- jz print_and_exit
- not_installed:
- mov dx, offset fdosnoload
- print_and_exit:
- MOV AH, 9
- INT 21h
- MOV AX, 4C01h
- INT 21h ; exit normally, exit code 1
-
- fdosinstalled db 'KEYS installed.', 0dh, 0ah, '$'
- fdosnoload db 'KEYS not installed.', 0dh, 0ah, '$'
-
- ; WARNING: the above code and data is EXACTLY the right length to
- ; be consumed by the keybuffer starting at 080h
-
- terminator dw -1
-
- ; betcha $ is at 0100h right here !!!
-
- skeycnt dw 0
- curkeyp dw 0
- delaydur dw 0
- startticks dw 0
-
- oldint16 dw 0
- dw 0
-
- oldint2f dw 0
- dw 0
-
- resident proc near
- assume cs:com_segment
- assume ds:nothing, es:nothing, ss:nothing
- fwdint16:
- JMP dword ptr [oldint16]
- newint16:
- sti
- CMP [skeycnt], 0
- jz fwdint16 ; if no stacked keys, get out quick
- test ah, 0eeh ; this weirdness is a quick check for
- ; 0h, 1h, 10h, and 11h.
- ; All other calls are always forwarded.
- jnz fwdint16
-
- int16around:
- PUSH SI
- PUSH DS
- push ax
-
- PUSH CS
- POP DS
- assume ds:com_segment
-
- mov si, [curkeyp]
-
- CLD
- test ah, 1 ; check vs. get
- jnz just_checking
-
- must_get_key:
- cmp [delaydur], 0
- jz get_key_now
- call delay_check
- jmp short must_get_key
-
- just_checking:
- cmp [delaydur], 0
- jz check_now
- call delay_check
- check_now:
- xor ax, ax
- cmp [delaydur], ax
- jnz check_exit
- lodsw
- cmp ax, -1
- jnz is_key
- call delay_setup
- xor ax, ax
- jmp short check_exit
- is_key:
- or ax, ax
- jnz check_exit
- dec [skeycnt] ; zero means fake out the check
- mov [curkeyp], si ; but consume the fake out indicator
- check_exit:
- or ax, ax
- pop si ; old ax value
- pop ds
- pop si
- retf 2
-
- get_key_now:
- lodsw
- cmp ax, -1
- jnz not_a_delay
- call delay_setup
- jmp must_get_key
- not_a_delay:
- dec [skeycnt]
- or ax, ax
- jz get_key_now
-
- mov [curkeyp], si
- pop si ; old ax value
- pop ds
- assume ds:nothing
- pop si
- iret
- assume ds:com_segment
-
- ; set up new delay if appropriate
- delay_setup:
- DEC [skeycnt] ; adjust for the -1 flag
- LODSW ; fetch the delay parameter
- MOV [delaydur], AX
- CALL getticks
- MOV [startticks], AX
-
- DEC [skeycnt] ; adjust for the delay parameter
- mov [curkeyp], si
- cmp [skeycnt], 0
- jl found_terminator ; negative count remaining
-
- ret
-
- found_terminator:
- pop ax ; throw away return IP from call to delay_setup
- mov [skeycnt], 0
- pop ax
- pop ds
- assume ds:nothing
- pop si
- jmp fwdint16
- assume ds:com_segment
-
- getticks:
- PUSH ES
- MOV AX, 40h
- MOV ES, AX
- MOV AX, es:[6Ch] ; low word of ticks since midnight
- POP ES
- RET
-
- delay_check:
- CALL getticks
- SUB AX, [startticks]
- CMP AX, [delaydur]
- JB moredelay
- MOV [delaydur], 0
- moredelay:
- RET
-
- assume ds:nothing, es:nothing, ss:nothing
- fwdint2f: JMP dword ptr [oldint2f]
-
- newint2f: CMP AX, 0D44Fh
- JNZ fwdint2f ; we only recognize 1 op-code
- MOV AX, 44DDh ; we always do this for grins
- OR BX, BX ; here's the real op-code
- JZ done2f
-
- ; here's the code to load in the new keystrokes
- STI
- PUSH DI
- PUSH SI
- CLD
-
- PUSH CS
- POP ES
- assume es:com_segment
- MOV DI, keybuffer
- MOV [curkeyp], DI
- xor ch, ch ; bounds check cx
- MOV [skeycnt], cx
- MOV [delaydur], 0
- MOV SI, DX
-
- REPZ MOVSW
- dec cx
- mov word ptr es:[di], cx ; end with -1
-
- POP SI
- POP DI
- XOR AX, AX
-
- done2f: IRET
- assume es:nothing
-
- endres equ $
- resident endp
-
- nonres proc near
- ASSUME cs:com_segment, es:com_segment
- assume ss:com_segment, ds:com_segment
-
- do_install: MOV AX, cs:[2Ch] ; get environment segment
- OR AX, AX
- JZ noenvironment
- assume es:nothing
- MOV ES, AX
- MOV AH, 49h
- INT 21h ; return environment block
- noenvironment:
- MOV AX, 3516h
- INT 21h ; get vector for INT 16h
- MOV [oldint16], BX
- MOV [oldint16+2], ES
- MOV AX, 2516h
- MOV DX, newint16
- INT 21h
- MOV AX, 352Fh
- INT 21h ; get vector for INT 2fh
- MOV [oldint2f], BX
- MOV [oldint2f+2], ES
- MOV AX, 252Fh
- MOV DX, newint2f
- INT 21h
- MOV AH, 9
- MOV DX, offset fdosinstalled
- INT 21h
- MOV DX, offset endres + 15
- MOV CX, 4
- SHR DX, CL
- MOV AX, 3100h
- INT 21h
-
- ASSUME cs:com_segment, es:com_segment
- assume ss:com_segment, ds:com_segment
- do_parms:
- MOV SI, offset parmbuffer
- LODSB
- CBW
- jmp do_common
- do_file_parms:
- mov ah, 3fh
- mov bx, 1
- mov cx, 32767
- mov dx, offset filebuf
- int 21h
- mov si, dx
- do_common:
- ; at this point, si points to buffer, ax is count
- MOV BP, AX ; save count
- mov bx, ax
- mov ax, 0d44fh
- add bx, si
- CLD
- mov byte ptr [bx], 0 ; null terminate the input
- mov bx, 0h
- int 2fh ; check if KEYS is installed
- cmp ax, 044ddh
- je installed
- exitpoint:
- ret ; not installed, exit quietly
-
- installed:
- MOV DI, OFFSET bufptr
- xor cx, cx
- dec cl ; initialize initial scan code value
- or bp, bp ; any buffer to process ?
- jz exitpoint
- call parsemain
- mov ax, 0d44fh
- mov bx, 1h
- mov cx, [numentries]
- mov dx, offset bufptr
- int 2fh
- ret
- nonres endp
-
- align 2
-
- numentries dw 0
- SOFAR dw 0
- BASEVAL dw 0AH
-
- parse proc near
- ; in remainder of code, the following register assignments are generally used
- ; BP count of command line bytes remaining (yes, this usage is unusual)
- ; BX is used as a temporary scratch register; often to a lookup table
- ; DH is quoted string delimiter during quoted string operations
- ; DL is a temporary save register during scan code lookup, and putchar ops
- ; AH generally contains the scan code of interest
- ; AL generally contains the ASCII code of interest, or the current input byte
- ; DS:SI points to the input stream
- ; ES:DI points to the output stream
- ; CL contains the global scan code (initially 255)
-
- parsemain:
- XOR AX, AX
- call obtchar
- call chkspace
- OR BP, BP
- JnZ parsemain ; loop until all characters used
- ret
-
- chkspace: ; ' ' and all control characters are ignored
- cmp al, ' '
- jg chkpound
- ret
-
- CHKPOUND: ; '#' introduces a scancode value. Once set, it is
- ; used for all subsequent keystrokes. Initially 255.
- ; The value of 255 causes a lookup of the "real" scancode.
- CMP AL, '#'
- JNZ CHKAT
- CALL GETNUM
- MOV CL, AL
- ret
-
- CHKAT: ; '@' introduces a number used as an Extended ASCII code.
- ; Hence, the ASCII value is set to zero, and the number
- ; specified is used as the scancode. This is independent
- ; of the scancode used for subsequent ASCII codes, however.
- CMP AL, '@'
- JNZ CHKPCT
- CALL GETNUM
- MOV AH, AL
- MOV AL, 0
- CALL PUTCHAR
- ret
-
- CHKPCT: ; '%' introduces a number used as an Enhanced keyboard
- ; Extended ASCII code. Hence, the ASCII value is set to
- ; E0, and the number specified is used as the scancode.
- ; This is independent of the scancode used for subsequent
- ; ASCII codes, however.
- cmp al, '%'
- jnz chkhat
- call getnum
- mov ah, al
- mov al, 0e0h
- call putchar
- ret
-
- chkhat: ; '^' introduces a letter used for a control code.
- ; It must be an uppercase letter, or one of '@[\]^_'.
- ; Also acceptable, are lowercase letters, or one of '`{|}~'.
- ; Actually, any character is acceptable, and only the low
- ; 5 bits of the character code are used.
- cmp al, '^'
- jnz chkbang
- call obtchar
- and al, 1fh
- call xlatchar
- call putchar
- ret
-
- chkbang: cmp al, '!'
- jnz chkamp
- mov ax, 0d44fh
- mov bx, 1h
- xor cx, cx
- mov dx, offset bufptr
- int 2fh
- jmp short startflush
-
- flushloop:
- mov ah, 0
- int 16h ; eat a character
- startflush:
- mov ah, 01h
- int 16h ; is there a character
- jnz flushloop
- ret
-
- chkamp: ; '&' introduces a letter used for an ALT code.
- ; It must be a letter.
- ; Actually, any character is acceptable, that letter's
- ; scan code is determined from the table, and used as
- ; and extended code.
- cmp al, '&'
- jnz chkstr
- call obtchar
- call xlatspec
- mov al, 0
- call putchar
- doret:
- ret
-
- CHKSTR:
- CMP AL, '"'
- JZ ISSTR
- CMP AL, "'"
- JZ ISSTR
- CMP AL, '~'
- JNZ CHKDASH
- ISSTR:
- MOV DH, AL
- MORESTR:
- xor ax, ax
- CALL OBTCHAR
- CMP AL, DH
- JZ doret
- CALL xlatchar
- CALL PUTCHAR
- JMP SHORT MORESTR
-
- CHKDASH:
- CMP AL, '-'
- JNZ CHKR
- MOV AX, 0
- CALL PUTCHAR
- ret
-
- CHKR:
- CMP AL, 'r'
- JZ DOENTER
- CMP AL, 'R'
- JZ DOENTER
- CMP AL, 'e'
- JZ DOENTER
- CMP AL, 'E'
- JNZ CHKF
- DOENTER:
- MOV AL, 0DH
- CALL XLATCHAR
- CALL PUTCHAR
- ret
-
- nochkw:
- call unobtchar
- ret
-
- CHKSLASH:
- CMP AL, '/'
- JNZ CHKDIGIT
- CHKW:
- CALL OBTCHAR
- CMP AL, 'w'
- JZ DOWAIT
- CMP AL, 'W'
- JNZ nochkw
-
- DOWAIT:
- CALL GETNUM
- push ax
- mov ax, -1
- call putchar
- pop ax
- shl ax, 1
- call putchar
- ret
-
- CHKF:
- CMP AL, 'f'
- JZ DOFUNC
- CMP AL, 'F'
- JNZ CHKSLASH
-
- DOFUNC:
- CALL OBTCHAR
- mov bx, offset afunckey
- CMP AL, 'A'
- JZ DOFUNCNUM
- CMP AL, 'a'
- JZ DOFUNCNUM
- mov bx, offset cfunckey
- CMP AL, 'C'
- JZ DOFUNCNUM
- CMP AL, 'c'
- JZ DOFUNCNUM
- mov bx, offset sfunckey
- CMP AL, 'S'
- JZ DOFUNCNUM
- CMP AL, 's'
- JZ DOFUNCNUM
- mov bx, offset rfunckey
- CALL UNOBTCHAR
- DOFUNCNUM:
- CALL GETNUM ; should be in range of 1-12
- sub ax, 1 ; put in range of 1-11
- cmp ax, 11 ; compare to the max
- JA nofunc ; bad number
- xlat
- mov ah, al
- MOV AL, 0
- CALL PUTCHAR
- nofunc:
- ret
-
- CHKDIGIT:
- CMP AL, '0'
- JB nochkdigit
- CMP AL, '9'
- JA nochkdigit
- CALL UNOBTCHAR
- CALL GETNUM
- CALL XLATCHAR
- CALL PUTCHAR
- nochkdigit:
- ret
-
- fdosalready db 'KEYS already installed.', 0dh, 0ah, '$'
-
- parse endp
-
- xlatchar PROC NEAR
- cmp ah, 0
- jnz regnoxlat ; fastest way out, if scan code pre-set
- MOV AH, CL
- cmp ah, 255
- jnz regnoxlat ; 2nd fastest way out, if scan code pre-spec
- cmp dh, '~' ; what kind of scan code do you want
- jnz xlatspec
- mov bx, offset numscan
- jmp short xlatact
- xlatspec:
- mov bx, offset regscan
- xlatact:
- MOV DL, AL
- XLAT
- MOV AH, AL
- MOV AL, DL
- regnoxlat:
- RET
- xlatchar ENDP
-
- OBTCHAR PROC NEAR
- LODSB
- DEC BP
- RET
- OBTCHAR ENDP
-
- UNOBTCHAR PROC
- INC BP
- DEC SI
- RET
- UNOBTCHAR ENDP
-
- GETNUM PROC NEAR
- PUSH AX
- MOV BYTE PTR SOFAR, 0
- CHKCHAR:
- CALL OBTCHAR
- CMP AL, '0'
- JB BADCHAR
- CMP AL, '9'
- JA BADCHAR
- SUB AL, '0'
- xor ah, ah
- XCHG ax, SOFAR
- MUL BYTE PTR BASEVAL
- ADD SOFAR, ax
- JMP SHORT CHKCHAR
-
- BADCHAR:
- CALL UNOBTCHAR
- POP AX
- MOV AX, SOFAR
- RET
- GETNUM ENDP
-
- PUTCHAR PROC NEAR
- mov bx, [numentries]
- cmp bx, maxkeys
- ja noputchar
- STOSW
- INC bx
- mov [numentries], bx
- noputchar:
- RET
- PUTCHAR ENDP
-
- DB 'Function Key Lookup Table'
- ; F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12
- RFUNCKEY DB 3bh, 3ch, 3dh, 3eh, 3fh, 40h, 41h, 42h, 43h, 44h, 91h, 92h
- SFUNCKEY DB 54h, 55h, 56h, 57h, 58h, 59h, 5ah, 5bh, 5ch, 5dh, 93h, 94h
- CFUNCKEY DB 5eh, 5fh, 60h, 61h, 62h, 63h, 64h, 65h, 66h, 67h, 95h, 96h
- AFUNCKEY DB 68h, 69h, 6ah, 6bh, 6ch, 6dh, 6eh, 6fh, 70h, 71h, 97h, 98h
-
- DB 'Scancode Lookup Table'
- regscan DB 03H ; zero (control @)
- ; control A-Z
- DB 1EH, 30H, 2EH, 20H, 12H, 21H, 22H, 0EH, 0FH
- DB 24H, 25H, 26H, 1CH, 31H, 18H, 19H, 10H, 13H
- DB 1FH, 14H, 16H, 2FH, 11H, 2DH, 15H, 2CH
- ; control [ | ] ^ _
- DB 01H, 2BH, 1BH, 07H, 0CH, 39H
- ; special characters ! " # $ % & ' ( ) * +, - . /
- DB 02H, 28H, 04H, 05H, 06H, 08H, 28H, 0AH, 0BH, 09H, 0DH
- DB 33H, 0CH, 34H, 35H
- ; digits 0-9
- DB 0BH, 02H, 03H, 04H, 05H, 06H, 07H, 08H, 09H, 0AH
- ; special characters : ; < = > ? @
- DB 27H, 27H, 33H, 0DH, 34H, 35H, 03H
- ; A-Z
- DB 1EH, 30H, 2EH, 20H, 12H, 21H, 22H, 23H, 17H
- DB 24H, 25H, 26H, 32H, 31H, 18H, 19H, 10H, 13H
- DB 1FH, 14H, 16H, 2FH, 11H, 2DH, 15H, 2CH
- ; special characters [ \ ] ^ _ `
- DB 1AH, 2BH, 1BH, 07H, 0CH, 39H, 29H
- ; a-z
- DB 1EH, 30H, 2EH, 20H, 12H, 21H, 22H, 23H, 17H
- DB 24H, 25H, 26H, 32H, 31H, 18H, 19H, 10H, 13H
- DB 1FH, 14H, 16H, 2FH, 11H, 2DH, 15H, 2CH
- ; special characters { | } ~
- DB 1AH, 2BH, 1BH, 29H
- ; Alt numeric key entry only
- DB 129 DUP(0)
- numscan DB 03H ; zero
- ; control A-Z
- DB 1EH, 30H, 2EH, 20H, 12H, 21H, 22H, 0EH, 0FH
- DB 24H, 25H, 26H, 1CH, 31H, 18H, 19H, 10H, 13H
- DB 1FH, 14H, 16H, 2FH, 11H, 2DH, 15H, 2CH
- ; control [ | ] ^ _
- DB 01H, 2BH, 1BH, 07H, 0CH, 39H
- ; special characters ! " # $ % & ' ( ) * +, - . /
- DB 02H, 28H, 04H, 05H, 06H, 08H, 28H, 0AH, 0BH, 37H, 4EH
- DB 33H, 4AH, 53H, 35H
- ; digits 0-9
- DB 52H, 4FH, 50H, 51H, 4BH, 4CH, 4DH, 47H, 48H, 49H
- ; special characters : ; < = > ? @
- DB 27H, 27H, 33H, 0DH, 34H, 35H, 03H
- ; A-Z
- DB 1EH, 30H, 2EH, 20H, 12H, 21H, 22H, 23H, 17H
- DB 24H, 25H, 26H, 32H, 31H, 18H, 19H, 10H, 13H
- DB 1FH, 14H, 16H, 2FH, 11H, 2DH, 15H, 2CH
- ; special characters [ \ ] ^ _ `
- DB 1AH, 2BH, 1BH, 07H, 0CH, 39H, 29H
- ; a-z
- DB 1EH, 30H, 2EH, 20H, 12H, 21H, 22H, 23H, 17H
- DB 24H, 25H, 26H, 32H, 31H, 18H, 19H, 10H, 13H
- DB 1FH, 14H, 16H, 2FH, 11H, 2DH, 15H, 2CH
- ; special characters { | } ~
- DB 1AH, 2BH, 1BH, 29H
- ; Alt numeric key entry only
- DB 129 DUP(0)
-
- align 2
-
- filebuf equ $
-
- com_segment ends
- end epoint
-