Category : Files from Magazines
Archive   : VOL9N08.ZIP
Filename : TYPEFAST.ASM

 
Output of file : TYPEFAST.ASM contained in archive : VOL9N08.ZIP
;-----------------------------------------------;
; TYPEFAST * PC Magazine * Michael J. Mefford ;
; Keyboard acceleration for XTs. ;
;-----------------------------------------------;

BIOS_DATA SEGMENT AT 40H
ORG 1AH
BUFFER_HEAD DW ?
BUFFER_TAIL DW ?
ORG 80H
BUFFER_START DW ?
BUFFER_END DW ?
BIOS_DATA ENDS

_TEXT SEGMENT PUBLIC 'CODE'
ASSUME CS:_TEXT
ORG 100H
START: JMP INITIALIZE

; DATA AREA
; ---------
SIGNATURE DB CR,SPACE,SPACE,SPACE,CR,LF
COPYRIGHT DB "TYPEFAST 1.0 (c) 1989 Ziff Communications Co.",CR,LF
PROGRAMMER DB "PC Magazine ",BOX," Michael J. Mefford",CR,LF,LF,"$"
DB CTRL_Z

CR EQU 13
LF EQU 10
CTRL_Z EQU 26
SPACE EQU 32
BOX EQU 254
BELL EQU 7

TRUE EQU 1
FALSE EQU 0

PORT_A EQU 60H
BREAK_CODE EQU 80H

INITIAL_MAX EQU 3
REPEAT_MAX EQU 31

BIOS_INT_9 DW ?,?
BIOS_INT_8 DW ?,?
SCAN_CHAR DW -1
SCAN_CODE DB ?
INIT_DEFAULT EQU INITIAL_MAX
INIT_DELAY DB ?
DELAY DB ?
REPEAT_DEFAULT EQU 2
REPEAT DW ?
REPEAT_CNT DW ?
REPEAT_FLAG DB FALSE
ACTIVE_FLAG DB TRUE
TYPEMATIC DB FALSE


; CODE AREA
; ---------

FASTKEY_INT_9 PROC NEAR

ASSUME DS:NOTHING

PUSH AX ;Preserve some registers.
PUSH BX
PUSH DS

IN AL,PORT_A ;Retrieve scan code.

MOV TYPEMATIC,FALSE ;No typematic while processing.

ASSUME DS:BIOS_DATA ;Point to BIOS data segment.
MOV BX,SEG BIOS_DATA
MOV DS,BX
MOV BX,BUFFER_TAIL ;Retrieve KBD buffer tail.

PUSHF ;Emulate an interrupt.
CALL DWORD PTR BIOS_INT_9 ;Let INT 9 process keystroke.

CMP ACTIVE_FLAG,TRUE ;Are we active?
JNZ INT_9_EXIT ;If no, done here.

CMP BX,BUFFER_TAIL ;Did buffer tail change?
JNZ KEY_PRESS ;If yes, process input.

;------------------------------------------------------------------------;
; Clear the keyboard buffer if key is released and we've been repeating. ;
;------------------------------------------------------------------------;

TEST AL,BREAK_CODE ;Else, was it a key release?
JZ END_TYPEMATIC ;If no, shift key;

AND AL,NOT BREAK_CODE ;Else, strip release bit.
CMP AL,SCAN_CODE ;Is it same as last press?
JNZ INT_9_EXIT ;If no, done here.

END_TYPEMATIC: MOV SCAN_CHAR,-1 ;Else, reset our scan/char code.

CMP REPEAT_FLAG,TRUE ;Have we been stuffing?
JNZ INT_9_EXIT ;If no, done here.

MOV REPEAT_FLAG,FALSE ;Else, reset repeat flag.
MOV BUFFER_HEAD,BX ;Clear keyboard buffer.
JMP SHORT INT_9_EXIT ;Exit.

;----------------------------------------------------------------;
; If key press and same key then continue typematic, else reset. ;
;----------------------------------------------------------------;

KEY_PRESS: MOV SCAN_CODE,AL ;Store the scan code.
MOV AX,[BX] ;Retrieve last scan code.
CMP AX,SCAN_CHAR ;Is it the same as last?
MOV SCAN_CHAR,AX ;Store the character.
JZ TYPEMATIC_ON ;If yes, continue typematic.

MOV BL,INIT_DELAY ;Else, reset the delay.
SHL BL,1
SHL BL,1
ADD BL,4
MOV DELAY,BL

TYPEMATIC_ON: MOV TYPEMATIC,TRUE ;Turn typematic back on.

;------------------------;

INT_9_EXIT: POP DS ;Restore registers.
POP BX
POP AX
IRET

FASTKEY_INT_9 ENDP

;**********************************************;

FASTKEY_INT_8 PROC NEAR

PUSH DS ;Preserve data segment.

ASSUME DS:_TEXT ;Point to our data.
PUSH CS
POP DS

CMP TYPEMATIC,TRUE ;Is typematic active?
JNZ INT_8_EXIT ;If no, done here.

CMP DELAY,0 ;Is delay timed-out?
JZ CK_BUFFER ;If yes, see if we should stuff.

DEC DELAY ;Else, decrement delay.
JMP SHORT INT_8_EXIT ;Exit.

;-----------------------------------------------------------;
; If there is room, stuff the keyboard with last keystroke. ;
;-----------------------------------------------------------;

CK_BUFFER: STI
PUSH AX ;Preserve some more registers.
PUSH BX
PUSH CX
PUSH DI

MOV AX,SCAN_CHAR ;Retrieve last scan/char code.
MOV CX,REPEAT_CNT ;Retrieve no. of times to repeat.
ASSUME DS:BIOS_DATA ;Point to BIOS data area.
MOV BX,SEG BIOS_DATA
MOV DS,BX
CLI ;No interrupts.

NEXT_STUFF: ROL CS:REPEAT,1 ;Rotate left one.
JNC CK_REPEAT

STUFF_KBD: MOV BX,BUFFER_TAIL ;Retrieve buffer tail.
MOV DI,BX ;Move into DI.
INC DI ;Point to next storage.
INC DI
CMP DI,BUFFER_END ;Did we pass end of buffer?
JNZ CK_FULL_KBD ;If no, continue.
MOV DI,BUFFER_START ;Else, move to buffer start.

CK_FULL_KBD: CMP DI,BUFFER_HEAD ;Is the buffer full?
JZ CK_REPEAT ;If is, skip.
MOV [BX],AX ;Else, stuff buffer repeat.
MOV BUFFER_TAIL,DI ;Move the tail up one.

MOV CS:REPEAT_FLAG,TRUE ;Flag that we stuffed buffer.

CK_REPEAT: DEC CX ;If no, continue until done.
JNS NEXT_STUFF

FULL_KBD_EXIT: STI
POP DI ;Restore registers.
POP CX
POP BX
POP AX

INT_8_EXIT: POP DS
ASSUME DS:NOTHING
JMP DWORD PTR BIOS_INT_8 ;Give the old timer its turn.

FASTKEY_INT_8 ENDP

END_RESIDENT LABEL BYTE

;**********************************************;

; DISPOSABLE DATA
; ---------------

PATTERNS DW 0000000000000000B, 1000000000000000B, 1000000010000000B
DW 1000010000100000B, 1000100010001000B, 1001001001001000B
DW 1001001001001001B, 1001001010010101B, 1010101010101010B
DW 1101010101010101B, 1101101011011010B, 1101101101101101B
DW 1110111011101110B, 1111011110111101B, 1111111011111110B
DW 1111111111111110B

SYNTAX DB "Syntax: TYPEFAST [m][,n] | [/U] | [N]",CR,LF
DB "m = typematic rate (0 - 31); larger m = faster rate"
DB CR,LF
DB "n = initial delay (0 - 3); larger n = longer delay"
DB CR,LF
DB "default: m = 2; n = 3",CR,LF
DB "N = Normal",CR,LF
DB "/U = Uninstall",CR,LF,"$"

BAD_PARAMETER DB "Invalid parameter",CR,LF,LF,BELL,"$"
UNLOAD_MSG DB "TYPEFAST can't be uninstalled.",CR,LF,BELL
DB "Uninstall resident programs in reverse order.",CR,LF
DB "TYPEFAST "
INACTIVE_MSG DB "INACTIVE",CR,LF,LF,"$"

ALLOCATE_MSG DB "Memory allocation error",CR,LF,BELL,"$"
INSTALL_MSG DB "Installed",CR,LF,LF,"$"
UNINSTALL_MSG DB "Uninstalled",CR,LF,LF,"$"

;--------------------------------------------------------------------;
; Search memory for a copy of our code, to see if already installed. ;
;--------------------------------------------------------------------;

INITIALIZE PROC NEAR

ASSUME DS:_TEXT
CLD ;All string operations forward.

MOV BX,OFFSET START ;Point to start of code.
NOT BYTE PTR [BX] ;Change a byte so no false match
; with a disk cache copy.
XOR DX,DX ;Start at segment zero.
MOV AX,CS ;Store our segment in AX.

NEXT_PARA: INC DX ;Next paragraph.
MOV ES,DX
CMP DX,AX ;Is it our segment?
JZ PARSE ;If yes, search is done.

MOV SI,BX ;Else, point to our signature.
MOV DI,BX ; and offset of possible match.
MOV CX,16 ;Check 16 bytes for match.
REP CMPSB
JNZ NEXT_PARA ;If no match, keep looking.

;-------------------------------------------------;
; Parse the command line for uninstall parameter. ;
;-------------------------------------------------;

PARSE: MOV DX,OFFSET SIGNATURE ;Display our signature.
CALL PRINT_STRING

MOV SI,81H ;Point to command line.
SEARCH_SWITCH: LODSB ;Get a byte.
CMP AL,CR ;Is it carriage return?
JZ PARAMETERS ;If yes, done here.
CMP AL,"/" ;Is there a switch character?
JNZ SEARCH_SWITCH ;If no, keep looking.
LODSB ;Else, get the switch character.
AND AL,5FH ;Capitalize.
CMP AL,"U" ;Is it uninstall?
JNZ PARAMETERS ;If no, done here.
JMP UNINSTALL ;Else, uninstall.

;--------------------------------------------------------;
; Parse command line for typematic and delay parameters. ;
;--------------------------------------------------------;

PARAMETERS: MOV SI,81H ;Point to command line.
FIND_PARA: LODSB
CMP AL,CR
JZ FOUND_PARA
CMP AL,SPACE
JBE FIND_PARA
FOUND_PARA: DEC SI
MOV AL,[SI]
AND AL,5FH
CMP AL,"N"
MOV AL,0
JZ CALC_PATTERN
CALL DECIMAL_INPUT ;Get requested typematic rate.
MOV AL,REPEAT_DEFAULT ;Assume no parameter.
JCXZ CALC_PATTERN ;If none, use default.
MOV AL,BL ;Else, rate in AL.
CMP BL,REPEAT_MAX ;Is it greater than max rate?
JA ERROR_EXIT ;If yes, exit with error msg.

CALC_PATTERN: MOV BL,AL
MOV CL,4
SHR BL,CL
XOR BH,BH
MOV ES:REPEAT_CNT,BX
AND AL,0FH
XOR AH,AH
SHL AX,1
PUSH SI
MOV SI,AX
ADD SI,OFFSET PATTERNS
LODSW
MOV ES:REPEAT,AX
POP SI

GET_DELAY: CALL DECIMAL_INPUT ;Get requested initial delay.
MOV AL,INIT_DEFAULT ;Assume no parameter.
JCXZ STORE_DELAY ;If none, use default.
MOV AL,BL ;Else, delay in AL.
CMP BL,INITIAL_MAX ;Is it greater than max delay?
JA ERROR_EXIT ;If yes, exit with error msg.

STORE_DELAY: MOV ES:INIT_DELAY,AL ;Else, store initial delay.

;-----------------------;
; Print active message. ;
;-----------------------;

CK_INSTALL: MOV ES:ACTIVE_FLAG,TRUE ;Flag as active.
MOV DX,OFFSET INACTIVE_MSG + 2 ;Display active msg.
CALL PRINT_STRING
MOV AX,ES ;Are we already installed?
MOV BX,CS
CMP AX,BX
JZ INSTALL ;If no, install.
XOR AL,AL ;Else, ERRORLEVEL of zero.
JMP SHORT EXIT ;Exit.

;-------------------------------------------------------------------;
; Exit. Return ERRORLEVEL code 0 if successful, 1 if unsuccessful. ;
;-------------------------------------------------------------------;

ERROR_EXIT: MOV DX,OFFSET BAD_PARAMETER ;Display error message.
MSG_EXIT: CALL PRINT_STRING
MOV AL,1 ;ERRORLEVEL = 1.


EXIT: PUSH AX ;Preserve ERRORLEVEL.
MOV DX,OFFSET SYNTAX ;Display syntax message.
CALL PRINT_STRING
POP AX ;Retrieve ERRORLEVEL.
MOV AH,4CH ;Terminate.
INT 21H

;--------------------------------;
; This is the install procedure. ;
;--------------------------------;

INSTALL: MOV AX,DS:[2CH] ;Get environment segment.
MOV ES,AX
MOV AH,49H ;Free up environment.
INT 21H
MOV DX,OFFSET ALLOCATE_MSG
JC MSG_EXIT ;If error, exit with message.

MOV AX,3509H ;Get keyboard interrupt.
INT 21H
MOV BIOS_INT_9[0],BX ;Save old interrupt.
MOV BIOS_INT_9[2],ES

MOV DX,OFFSET FASTKEY_INT_9 ;Install new interrupt.
MOV AX,2509H
INT 21H

MOV AX,3508H ;Get timer interrupt.
INT 21H
MOV BIOS_INT_8[0],BX ;Save old interrupt.
MOV BIOS_INT_8[2],ES

MOV DX,OFFSET FASTKEY_INT_8 ;Install new interrupt.
MOV AX,2508H
INT 21H

MOV DX,OFFSET INSTALL_MSG ;Display install message.
CALL PRINT_STRING
MOV DX,OFFSET SYNTAX ;Display syntax.
CALL PRINT_STRING

MOV DX,OFFSET END_RESIDENT ;Point to end of resident portion
ADD DX,15 ;Round up.
MOV CL,4
SHR DX,CL ;Convert to paragraphs.
MOV AX,3100H ;Return error code of zero.
INT 21H ;Terminate but stay resident.

;---------------------------------------------------;
; This subroutine uninstalls the resident TYPEFAST. ;
;---------------------------------------------------;

UNINSTALL: MOV ES:ACTIVE_FLAG,FALSE ;Flag as inactive.
MOV ES:TYPEMATIC,FALSE ;Turn off typematic.
MOV DX,OFFSET UNLOAD_MSG ;Error message if INT 9h changed.
MOV CX,ES
MOV BX,CS
CMP AX,BX ;Is segment vector same?
JZ UNINSTALL_END ;If yes, not installed; exit.

MOV AX,3509H ;Get keyboard interrupt.
INT 21H
CMP BX,OFFSET FASTKEY_INT_9 ;Has it been hooked by another?
JNZ UNINSTALL_END ;If yes, exit with error message.
MOV BX,ES
CMP BX,CX ;Is the segment vector same?
JNZ UNINSTALL_END ;If yes, exit with error message.

MOV AX,3508H ;Get timer interrupt.
INT 21H
CMP BX,OFFSET FASTKEY_INT_8 ;Has it been hooked by another?
JNZ UNINSTALL_END ;If yes, exit with error message.
MOV BX,ES
CMP BX,CX ;Is the segment vector same?
JNZ UNINSTALL_END ;If yes, exit with error message.

MOV AH,49H ;Return memory to system pool.
INT 21H
MOV DX,OFFSET ALLOCATE_MSG
JC UNINSTALL_END ;Display message if problem.

MOV DX,ES:BIOS_INT_9[0] ;Restore old INT 9.
MOV DS,ES:BIOS_INT_9[2]
MOV AX,2509H
INT 21H

MOV DX,ES:BIOS_INT_8[0] ;Restore old INT 8.
MOV DS,ES:BIOS_INT_8[2]
MOV AX,2508H
INT 21H

PUSH CS
POP DS ;Point to our data.
MOV DX,OFFSET UNINSTALL_MSG ;Display uninstall message.
UNINSTALL_END: JMP MSG_EXIT ;And exit.

INITIALIZE ENDP

;---------------------------------;
; INPUT ;
; SI points to parameter start. ;
; ;
; OUTPUT ;
; BL = number. ;
; CX = parameter length. ;
; BP preserved. ;
;---------------------------------;

DECIMAL_INPUT PROC NEAR

XOR BL,BL ;Start with zero as number.
XOR CX,CX ;Parameter length zero.

LEADING_WHITE: LODSB ;Get a byte.
CMP AL,CR ;Is it carriage return?
JZ ADJUST_DEC ;If yes, done here.
CMP AL,SPACE ;Is it leading white space?
JBE LEADING_WHITE ;If yes, parse off.

DECIMAL: DEC SI ;Adjust pointer.
NEXT_DECIMAL: LODSB ;Get a character.
CMP AL,CR ;Is it carriage return?
JZ ADJUST_DEC ;If yes, done here.
SUB AL,"0" ;ASCII to binary.
JC END_DECIMAL ;If not between 0 and 9, skip.
CMP AL,9
JA END_DECIMAL
XCHG AL,BL ;Swap old and new number.
MOV CL,10 ;Shift to left by multiplying
MUL CL ; last entry by ten.
JC DECIMAL_ERROR ;If carry, too big.
ADD BL,AL ;Add new number and store in BL.
JNC NEXT_DECIMAL ;If not carry, next number.
DECIMAL_ERROR: MOV BL,-1 ;Else, too big; return -1.

ADJUST_DEC: DEC SI ;Adjust pointer.
END_DECIMAL: RET

DECIMAL_INPUT ENDP

;--------------------------;

PRINT_STRING: MOV AH,9 ;Print string via DOS.
INT 21H
RET

_TEXT ENDS
END START


  3 Responses to “Category : Files from Magazines
Archive   : VOL9N08.ZIP
Filename : TYPEFAST.ASM

  1. Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!

  2. This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.

  3. But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/