ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

【DOS 6.0模块】handicap.asm

2021-09-30 23:33:37  阅读:140  来源: 互联网

标签:handicap mov al int kybd ax DOS asm cmp


;************************************************************************
;									*
;	Copyright (C) 1991 by Trace Center (just kidding)		*
;									*
;	HANDICAP.ASM							*
;									*
;************************************************************************
;----------------------------------------------------------------------------
; HANDICAP.ASM
;
; FilterKeys  = Adjustment of typematic rate, key acceptance, debounce time and recovery times
; StickyKeys = One finger typing feature
; MouseKeys   = Complete mouse function from the numeric keypad
; ToggleKeys  = Audible feedback of indicator light states of keyboard
;
; The way this is done is to chain together the routines that implement 
; these features.  The routine below, keybd_int, actually reads the keyboard 
; port and then builds up the extended scan code which consists of the 
; "hidden" byte and then the scan byte.  It then passes it in AX to the first 
; routine in line (FilterKeys).  Each successive routine then continues to 
; pass it on or inhibits it.  Note, that if the scan code is an "e0", "e1", or 
; a response to a keyboard command, (>"f0"), then this routine passes the
; code to the original keyboard int. while also saving it to use as a scan code
; identification as the real scan code is later passed along between the routines.
; There may be a few exceptions to this, like if a control break is being trapped.
;
; The routine keybd_int does all the hardware management, unless one of the 
; routines (namely the BIOS in the computer ROM ) resets the hardware, in which case 
; keybd_int does not.  The variable fbios_called_direct is used to flag this condition.


print	MACRO	string
	mov	dx,OFFSET string
	mov	ah,9
	int	21h
	ENDM

INCLUDE	keyboard.inc

IFDEF	BUG

	PUBLIC	portid,portout
	EXTRN	HexCharsOut:PROC

ENDIF; BUG

	EXTRN	_end:ABS

	EXTRN	flatch:byte				; in Stickeys.asm
	EXTRN	shift_flg:byte

	EXTRN	FilterKeys:NEAR				; in FilterKeys.asm
	EXTRN	FilterKeys_timer:PROC
	EXTRN	FilterKeys_dialog:PROC
	EXTRN	fshift_click:byte

	EXTRN	MouseKeys_timer:PROC			; in  MouseKeys.asm
	EXTRN	InjectMouse:PROC			
	EXTRN	button_click:PROC			
;;	EXTRN	Put_Mouse_Data:PROC
	EXTRN	fMoving:byte
	EXTRN	Mouse_Status:word
	EXTRN	Delta_X:word
	EXTRN	Delta_Y:word
	EXTRN	Last_Direction:byte
	EXTRN	Status:byte
	EXTRN	mouse_data:word
	EXTRN	mouse_data_head:word
	EXTRN	mouse_data_tail:word
	EXTRN	mouse_data_end:word
	EXTRN	fbutton_up:byte
	EXTRN	fbutton_down:byte
	EXTRN	MouseKeys_dialog:PROC
	EXTRN	Button_Status:byte
	EXTRN	mouse_cnt:byte
	EXTRN	fnum_lock_was_off:byte
	EXTRN	fserial_stop:byte

	EXTRN	ToggleKeys_timer:PROC			; in ToggleKeys.asm
	EXTRN	ToggleKeys_dialog:PROC

	EXTRN	TimeOut_Reset:PROC			; in TimeOut.asm
	EXTRN	TimeOut_dialog:PROC
	EXTRN	last_address:word

	EXTRN	key_cnt:byte				; in StickeyKeys.asm
	EXTRN	StickeyKeys_dialog:PROC
	EXTRN	fkeys_injected:byte
	EXTRN	set_shift_states:PROC

;	EXTRN	_serialKeysInit:PROC			; in SerialKeys
	EXTRN	_kickStartSerialKeys:PROC
;	EXTRN	_initCommPort:PROC
;	EXTRN	_serialKeysStartupInit:PROC
	EXTRN	_forcedInt9Flag:byte
	EXTRN	_injectByte:byte
	EXTRN	_skWindowCompatible:byte
	EXTRN	_serialKeysEnableFar:FAR
	EXTRN	_serialKeysDisableFar:FAR

	EXTRN	fFilterKeysOn:byte			; from Param.asm
	EXTRN	fMouseKeysOn:byte	
	EXTRN	fcomp_dialog:byte
	EXTRN	fcomp_dialog_id:byte
	EXTRN	fDialog_Filter_off:byte
	EXTRN	fDialog_Stickeys_off:byte
	EXTRN	fDialog_Mouse_off:byte
	EXTRN	fDialog_Toggle_off:byte
	EXTRN	fDialog_TimeOut_off:byte
	EXTRN	fDialog_Action:byte
	EXTRN	fmkeys_override:byte
	EXTRN	fspace_saver:byte
	EXTRN	fhearing_on:byte
	EXTRN	fvideo_flash:byte
	EXTRN	fcomputer_not_found:byte
	EXTRN	fSticKeysOn:byte   
	EXTRN	fclick_on:byte
	EXTRN	_serialKeysOn:byte
	EXTRN	fslow_baud_mouse:byte

	EXTRN	_comp_id:byte
	EXTRN   _combase:word
	EXTRN	fmouse_driver:byte
	EXTRN	_finject_keys:byte
	EXTRN	_vector:byte
	EXTRN	comp_flag:byte
	EXTRN	ExtendedSeg:word
	EXTRN	_fmouse_id:byte
        EXTRN   comp_flag:byte
        EXTRN   btn_1:byte
        EXTRN   btn_2:byte
        EXTRN   Current_Button:byte
        EXTRN   fmouse_driver:byte
        EXTRN   fvideo_type:byte
	EXTRN	fserial_keys_loaded:byte


	PUBLIC	beep_low				; in Handicap.asm
	PUBLIC	pass_to_computer
	PUBLIC	beep_high
	PUBLIC	click
	PUBLIC	no_beep
	PUBLIC	beep_turn_on
	PUBLIC	beep_turn_off
	PUBLIC	InjectKeys
	PUBLIC	Get_Mouse_Data
	PUBLIC  Put_Key_Data
	PUBLIC	shift_tbl
	PUBLIC	shift_tbl_len
	PUBLIC	real_states
	PUBLIC	prev_real_states
	PUBLIC	current_shift
	PUBLIC	fpause_being_sent
	PUBLIC	fmouse_button
	PUBLIC	fwindows_st_re
	PUBLIC	fsilent_click
	PUBLIC	key_data_tail
	PUBLIC	key_data_head
	PUBLIC	key_data
	PUBLIC	key_data_end
	PUBLIC	faccess_sound
	PUBLIC	fswitching_video

	PUBLIC	fbios_called_timing
	PUBLIC	Enable
	PUBLIC	fsecond_cue
	PUBLIC	fkey_not_passed
	PUBLIC	ftimer_1C_active 
	PUBLIC	fserial_key_recieved
	PUBLIC	fmousetrapping
;	PUBLIC  fwindows_enh				; DEBUGGING

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

_TEXT	segment	word public 'CODE'

	assume CS:_TEXT
	assume DS:_TEXT
	assume ES:_TEXT
	assume SS:NOTHING

;;PUBLIC	timer_Stack_top

PUBLIC	kybd_Stack_top


;		even
;timer_sp_save		dw 0
;timer_ss_save		dw 0
;		db 'tstacke'
;		even
;timer_Stack		dw 150 dup(0)
;timer_Stack_top	dw $-2
;		db 'tstacks'

		even
kybd_sp_save		dw 0
kybd_ss_save		dw 0
		db 'kstacke'
		even
kybd_Stack		dw 75 dup(0)
kybd_Stack_top	dw $-2
		db 'kstacks'


;;	ORG	100h
;;
;;begin:
;;
;;	jmp	_enable		  
;----------------------------------------------------------------------------
;			R E S I D E N T   D A T A   A R E A
;

;  The below area defines the resident data area.
;
;----------------------------------------------------------------------------

fserial_key_recieved	db	false		; flag used to tell my code modules that they are processing a serial key input
fkey_not_passed		db	false		; flag used to signal that a key didn't pass yet in int 9 w/stickeys on

ftimer_1C_active	db	false		; flag to signal me when I am in a timer 1C interrupt
fint9_active_temp	db	false		; flag used by int 9 to prevent double pushing of stack
;;fint1C_active_temp	db	false		; flag used by int 1C to prevent double pushing of stack

fdonnot_hook_address	db	false		; flag used by int 33 routine to hook or unhook address's
fslow_mouse		db	false		; flag used in slow serial mice to tell timer to write every other clock tic

fvideo_flash_cnt	db	0		; reset counter at start
fvideo_flash_on		db	false		; reset flag at start
video_cnst		db	4		; 4 for wait between toggling screen

shift_tbl	label	byte
	dw	RAlt,RCtrl,Alt,Ctrl,LShift,RShift
shift_tbl_len	equ	6

ctrl_break_buf	label	byte
	db	0e0h,046h,0e0h,0c6h
ctrl_break_buf_len	equ	4


ctrl_break_buf_cnt	DB	false			; counter into buffer when keys are being Injected

prev_real_states	DB	0			; previous state of real shift keys
real_states		DB	0			; current state of real shift keys

current_shift		DB	0			; holds flag of current shift if there is one

video_state		DB	0			; hold current video state for comparison checking
old_char_1		DB	0			; hold the char, which gets over written by hearing impaired symbol
old_char_2		DB	0			; hold the char, which gets over written by hearing impaired symbol
old_char_1_attr		db	0			; hold attribute of char 1
old_char_2_attr		db	0			; hold attribute of char 2
fsecond_cue		db	0			; holds second character if needed for visual cue

old_row			DB	0			; temp storage of cursor row position if hearing flag set
old_col			DB	0			; temp storage of cursor column position if hearing flag set
old_cursor_1		DB	0			; temp save of cursor type
old_cursor_2		DB	0			; temp save of cursor type
txt_or_grph		DB	0			; temp save of current video state, text or graphics mode

video_count		DB	false			; counter used if hearing flag set
faccess_sound		DB	false			; flag which will cause video output for AccesDos beeps 
							; since some of them are too short in length to be trapped by the timer int.
fswitching_video	DB	false			; flag to inform ADOS that video is switching when true	
fint9_by_timer		DB	false			; flag to our int15 routine that timer inititated an int9h
							; and that we should get scan code out of the key_data_buffer

floop_back     		db	false			; flag to let me know if I need to grab byte/replace byte
							; to prevent keyboard int from getting between timer injected codes

count_down_ticks	label	word			; counter used during tone setup
no_tone			DW	014h			; soft tone sound
low_tone		DW	06c0h			; 500 hz FilterKeys tones
high_tone		DW	0120h			; 2.0 khz
click_tone		DW	06c0h			;  hz ??????
turn_on_start_beep	DW	0360h			; 1.0 khz
turn_off_start_beep	DW	0120h			; 2.0 khz
on_off_change		DW	6			; for 100 steps

fbios_called_direct	DB	false			; flag for if BIOS routine called
fbios_called_timing	DB	false			; flag for when timer function calls BIOS routine

fpause_being_sent	DB	false			; flag to tell MouseKeys that a real PAUSE key is passing, so don't 
							; turn off on the "45h" part of it
fmouse_or_kybd		DB	false			; flag to tell us if the int. routine called the keybd or mouse int. vector
frehook_mouse		DB	false			; flag to during int33h
fmouse_button		DB	false			; flag to tell int 33 or timer when mousekeys has a mouse button down for polled mice
fFake_mouse		DB	false			; flag to tell sub int33h, when mask has been set for Int. driven mice
fsilent_click		DB	false			; flag to call click but silently
							; so we should convert to control break on computers which support it

fmousetrapping		DB	false			; if this flag is false, we allow MouseKeys to hook int 33h (added 4/92)
fctrl_break_on		DB	false			; same as above,used in Handicap.asm to eat keystrokes

fsysreq	   	  	DB	false			; flag to tell us the alternate key is down and a print screen key was pressed
							; so we should convert to system request on computers which support it
							; keyboard buffer
fscroll_changed		DB	false			; flag to tell us we detected shift+numlock on space saver keyboard
fvideo_flash_save	DB	false			; temp storage flag for fvideo_flash when Windows takes over
fhearing_on_save	DB	false			; "" "" ""

call_mask		DW	0			; mask sent by applications to mouse driver

;------------------------------------------------------------------------------------------------------------------------------
fwindows		DB	false			; flag to tell us if we started program inside of or under windows
							; anytime we exit Windows, this TSR program will have to terminate if started
							; after Windows was already running.
fwindows_st_re		DB	false			; flag to tell us which mode of Windows we are running in
fwindows_enh		DB	false			; flag to tell us which mode of Windows we are running in
;------------------------------------------------------------------------------------------------------------------------------

fwindows_after		DB	false 			; flag to tell us that Windows was loaded after ADOS was already started
fwindows_after_st	DB	false			; flag that says Windows started after ADOS in standard mode
fwindows_after_re	DB	false			; flag that says Windows started after ADOS in real mode
fwinfows_after_enh 	DB	false			; flag that says Windows started after ADOS in enhanced mode

fDOS_box		DB	false			; flag to Windows and serial keys that Windows is either DOS boxing
							; int2f w/ax=1680 =true first fime, or alt/ctrl+esc from DSO box back to Windows
							; and fDOS_box=false
;-------------------------------------------------------------------------------------------------------------------------------

falt_esc		DB	false			; flag to tell us that an alt+esc make was sent
falt_esc_send		DB	false			; flag that alt+esc break was sent and we can now safely inject Windows Alt+esc

fctrl_esc		DB	false			; flag to tell us that an ctrl+esc make was sent
fctrl_esc_send		DB	false			; flag that ctrl+esc break was sent and we can now safely inject Windows Ctrl+esc


mouse_x_temp		DB	false			; byte used to keep semi track of mouse x coordinate, to tell if it moved 
							; during int. 33 polling
mouse_y_temp		DB	false			; byte used to keep semi track of mouse y coordinate, to tell if it moved 
							; during int. 33 polling

hidden_code		DB	0			; holds either E0 or E1 or 00

key_data_tail		DW	?			; pointer into key_data
key_data_head		DW	?			; pointer into key_data
key_data		DW	20 DUP (?)		; array of (20 words) for circular buffer of keyboard scan code data
key_data_end	label	word

IFDEF	BUG
	portid		DB	0
	portout		DB	0

fserial_debugging	DB	0

	PUBLIC	old_row,old_col
	PUBLIC	fserial_debugging

; Message data area for the various routines used during initialization

	mesg41		DB	"Program started while running Windows in Enhanced Mode", 13, 10, "$"
	mesg42		DB	"Program started while running Windows in Real/Standard Mode", 13, 10, "$"

	mesg45		DB	"Your version of DOS (pre 3.0) does not support all Access DOS features", 13, 10, "$"
	mesg46		DB	"Your computer is running DOS version 3.0 or higher", 13, 10, "$"

ENDIF;	BUG

	mesg22		DB	"Computer was not identifiable and will be treated as a PC/XT/AT with an 84 key keyboard.", 13, 10, "$"
	mesg22A		DB	"Please restart AccesDOS menu, type access,  to change this selection if your ", 13, 10, "$"
	mesg22B		DB	"computer is NOT a PC/XT/AT with an 84 key keyboard.", 13, 10, "$"

	mesg43		DB	"Windows loading aborted, DO NOT run Enhanced Mode after AccessDOS is started", 13, 10, "$"
	mesg44		DB	"Unload Access DOS or run Windows in Standard Mode (win /s) ", 13, 10, "$"
	mesg60		DB	"Please wait, AccessDOS is loading...", 13, 10, "$"

; store these old vector variables here such that they always get addressed correcly


old_1C_int		label	word			; holds far call vector to previous timer int
old_1C_int_off		DW	0			; holds old timer routine offset address
old_1C_int_seg		DW	0			; holds old timer routine segment address

old_kybd_int		label	word			; holds far call vector to previous keyboard int
old_kybd_int_off	DW	0
old_kybd_int_seg	DW	0

old_2f_int		label	word			; holds far call vector to previous int 2f service routine
old_2f_int_off		DW	0		    	; we watch this int solely to know if windows is loaded after
old_2f_int_seg		DW	0		    	; ADOS has been started

old_33_int		label	word			; holds far call vector to previous int 33 service routine
old_33_int_off		DW	0
old_33_int_seg		DW	0

old_ps2mou_int		label	word			; holds far call vector to previous int
old_ps2mou_int_off	DW	0
old_ps2mou_int_seg	DW	0

;testpattern		db	'markstart'
sub_int33_ptr		label	word
sub_int33_ptr_off	DW	0			; holds far call vector to an address if an application trys
sub_int33_ptr_seg	DW	0			; holds far call vector to an address if an application trys

;sub_int33_ptr_2		label	word
;sub_int33_ptr_off_2	DW	0			; holds far call vector to an address if an application trys
;sub_int33_ptr_seg_2	DW	0			; holds far call vector to an address if an application trys
;
;sub_int33_ptr_3		label	word
;sub_int33_ptr_off_3	DW	0			; holds far call vector to an address if an application trys
;sub_int33_ptr_seg_3	DW	0			; holds far call vector to an address if an application trys

;---------------------------------------------------------------------------
; ship_it
;
; Routine to disable and enable the keyboard.  Works for IBM AT, NAT, 50,60 70,80
; according to Tech Ref. manual.  Send what is in al register to status port of 
; keyboard.  We only need to use this routine for int 9 computers of AT class
;
; expects	al register to contain code to send to the keyboard control chip


ship_it	proc

	push	cx
	push	ax
	xor	cx,cx				; zero cx register

ship_it_5:

	in	al,status_port			; read keyboard status port
	test	al,inpt_buf_full		; wait till we are allowed to write to port
	loopnz	ship_it_5
	pop	ax				; char to send is in al register
	out	status_port,al			; may have gotten an  enable or disable code for keyboard in "al" register
	pop	cx				; clean up stack
	ret

ship_it	endp

;----------------------------------------------------------------------------
; pass_to_computer 
;
; This routine passes the scan code to the original keyboard device driver when 
; called on a computer using keyboard interrupt 9h in byte form in al.
;
; In reality, the original keyboard int. reads the kb_data
; in port, and places the result in "al" register, which is the same scan code
; which this routine is passing along
;
; If this computer supports int 15h, then the only thing this routine does is set the 
; fbios_called_direct flag to true, telling the return code that this key should get
; passed to the computer



pass_to_computer	proc

	assume	DS:_TEXT

;;	push	ax
;;	push	ds

	cmp	_vector,15h				; are we running under int 15h
	je	pass_to_computer_100			; if yes, life as usual

; int 9h computers will get ot this code

	cmp	fFilterKeysOn,false			; is FilterKeys On ???
	je	pass_to_computer_25			; if FilterKeys is off, safe to pass key in this int 9 pass

	cmp	ftimer_1C_active,true			; is the timerr trying to pass a key
	jne	pass_to_computer_25			; if not, allow key to pass

; if stickeys is on, we need to flag that we didn't pass the key as yet

	cmp	fSticKeysOn,true
	jne	pass_to_computer_10
	mov	fkey_not_passed,true			; flag that timed key has not yet passed

pass_to_computer_10:

	jmp	pass_to_computer_end

;**************
;	cmp	_comp_id,1				; is this an IBM PC or original PC/XT ??
;	jne	pass_to_computer_25			; if not, don't need to bother with the following check
;
;	mov	ah,al					; save al, the scan code we are supposed to pass on
;	in	al,kb_data				; read in data from keyboard port
;	cmp	al,0					; was bit 0 a 0??
;	je	pass_to_computer_110			; yes, no data in buffer, skip call to orig. kybd int.
;
;	cmp	al,ah					; was the data at the keybd port, the same as what is supposed to be passed ?
;	jne	pass_to_computer_110			; if not, don't send it
;**************

pass_to_computer_25:
  	
	mov	fkey_not_passed,false			; reset this flag
	push	ds

	pushf
	call	dword ptr cs:old_kybd_int

	pop	ds
	assume	ds:_TEXT

pass_to_computer_100:
  	
	mov	fbios_called_direct,true


;************
;	jmp	short pass_to_computer_120
;
;pass_to_computer_110:
;
;	mov	fsilent_click,true			; set true if didn't send anything
;
;pass_to_computer_120:
;
;	pop	ds
;	pop	ax
;************

pass_to_computer_end:

	ret

pass_to_computer	endp
;----------------------------------------------------------------------------
; 
; InjectKeys
; 
; This procedure is used on computers which support the Injection of key scan codes 
; into the hardware buffer to inject either a control break scan code or an alternate
; print screen (SYSREQ) scan code if the user tries to do so with StickeyKeys.
;
; This routine is also used to inject StickeyKeys modifier break codes.
; This routine should never be called if the computer type is determined not capable of 
; handling scan codes injected into the hardware buffer.  Currently, the only computers
; which support hardware injections are PS/1 and all PS/2 except the 25/30-86 models.
;
; Expects 	al=code to inject


InjectKeys	proc

	assume	DS:_TEXT

;	push	cx				; DO NOT need to save any registers, called from inside timer int. only..
	mov	cx,995				; approx. 15msec/15.086*10-6/sec

IK_5:

	in	al,status_port			; read keyboard status port
	test	al,inpt_buf_full		; wait till we are allowed to write to port
	jz	IK_8				; yes buffers are empty, okay to do inject so far


	in	al,kb_ctl			; buffer not empty, check time
	and	al,10h				; mask to check refresh bit = 10h
	cmp	al,ah				; did it change? or first time thru
	jz	short IK_5    			; no wait for change, else cont.
	mov	ah,al
	loop	IK_5	      			; have we timed out ?
	jmp	short IK_20			; can't write this time thru, exit inject 

IK_8:
	mov	cx,995				; approx. 15msec/15.086*10-6/sec
	mov	al,0d2h				; code to tell keyboard output buffer that next byte
	out	status_port,al			; written is to I/O address hex 060 (kb_data) 	
IK_10:

	in	al,status_port			; read keyboard status port
	test	al,inpt_buf_full		; wait till we are allowed to write to port
	jz	IK_15				; yes buffers are empty, okay to do inject so far

	in	al,kb_ctl			; buffer not empty, check time
	and	al,10h				; mask to check refresh bit = 10h
	cmp	al,ah				; did it change? or first time thru
	jz	short IK_10    			; no wait for change, else cont.
	mov	ah,al
	loop	IK_10	      			; have we timed out ?
	jmp	short IK_20			; can't write this time thru, exit inject 

IK_15:
	call	Get_Key_Data		       	; ax has the data upon return
	out	kb_data,al			; send our char. which will generate an int. as if sent by kybd.

;IFDEF	BUG
;;	mov	fserial_debugging,true
;	mov	portid,06
;	mov	portout,al
;	call	HexCharsOut
;;	mov	fserial_debugging,false
;ENDIF;	BUG

	mov	floop_back,true			; flag that we sent a byte
IK_20:
;	pop	cx				; clean up stack
	ret

InjectKeys	endp

;----------------DEBUGGING------------------------------------------------
;
;Inject_Mouse_Low	proc
;
;	assume	DS:_TEXT
;	call	click	       
;	mov	cx,995				; approx. 15msec/15.086*10-6/sec
;
;IKM_5:
;
;	in	al,status_port			; read keyboard status port
;	test	al,inpt_buf_full		; wait till we are allowed to write to port
;	jz	IKM_8				; yes buffers are empty, okay to do inject so far
;
;
;	in	al,kb_ctl			; buffer not empty, check time
;	and	al,10h				; mask to check refresh bit = 10h
;	cmp	al,ah				; did it change? or first time thru
;	jz	short IKM_5    			; no wait for change, else cont.
;	mov	ah,al
;	loop	IKM_5	      			; have we timed out ?
;	jmp	short IKM_20			; can't write this time thru, exit inject 
;
;IKM_8:
;	mov	cx,995				; approx. 15msec/15.086*10-6/sec
;	mov	al,0d3h				; code to tell mouse output buffer that next byte
;	out	status_port,al			; written is to I/O address hex 060 (kb_data) 	
;IKM_10:
;
;	in	al,status_port			; read keyboard status port
;	test	al,inpt_buf_full		; wait till we are allowed to write to port
;	jz	IKM_15				; yes buffers are empty, okay to do inject so far
;
;	in	al,kb_ctl			; buffer not empty, check time
;	and	al,10h				; mask to check refresh bit = 10h
;	cmp	al,ah				; did it change? or first time thru
;	jz	short IKM_10    			; no wait for change, else cont.
;	mov	ah,al
;	loop	IKM_10	      			; have we timed out ?
;	jmp	short IKM_20			; can't write this time thru, exit inject 
;
;IKM_15:
;	call	Get_Mouse_Data		 	; ax has the data upon return
;	out	kb_data,al			; send our char. which will generate an int. as if sent by kybd.
;
;IKM_20:
;	ret
;
;Inject_Mouse_Low	endp
;----------------DEBUGGING------------------------------------------------

;----------------------------------------------------------------------------
; 
; kybd_echo
; 
; This routine is used on computers which DO NOT support hardware injection of scan codes but
; do support int 15h, to cause an int9h to occur, such that when int15 is called, we can trap for
; it and inject our scan code.  For IBM's, we will do this by using an undocumented call to 8042, which will
; cause it to do an interrupt with our data loaded into port 60h.  For non IBM's, we will write to status port
; which caused the 8042 to return a byte, which we then trapped.

kybd_echo	proc

	assume	DS:_TEXT

	cmp	_comp_id,5Ah			; is this an IBM product (Old AT, AT239, AT339)?
	je	kybd_echo_10			; if yes, do 2nd half of kybd_echo
						; if not, do the first half
 	cmp	_comp_id,2			; is this a New XT (1/10-5/9/86) running 
	je	kybd_echo_10			; if yes, do 2nd half of kybd_echo

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

kybd_echo_5:

	xor	cx,cx				; zero cx

kybd_echo_5A:

	in	al,status_port			; read keyboard status port
	test	al,both_buf_full		; check to be sure we can write to the port
	jz	kybd_echo_6
	loop	kybd_echo_5A
	jmp	short kybd_echo_8		; if cannot write this time, exit out


kybd_echo_6:

	mov	al,020h
	out	status_port,al			; a write to the keyboard status port (ctrl port) generates an interrupt

; if succesful in generating an interrupt, set a flag for myself to watch for when int 9 calls int 15h

	mov	fint9_by_timer,true 		; set flag so I know when int 9 occur, to disregard
				    		; the scan code int 9 has, and to read the key_data_buffer
				    		; for the scan code I want to insert
kybd_echo_8:

	jmp	kybd_echo_end			; exit

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

kybd_echo_10:

;	push	cx
	xor	cx,cx				; zero cx

kybd_echo_10A:

	in	al,status_port			; read keyboard status port
	test	al,inpt_buf_full		; check to be sure we can we can write buffer
	jz	kybd_echo_15
	loop	kybd_echo_10A
	jmp	kybd_echo_end			; if can't write this time, exit

kybd_echo_15:

	mov	al,7fh				; write command for 8042
	out	status_port,al			; write to port 64h
	jmp	$+2				; delay
	xor	cx,cx				; reset cx to 0

kybd_echo_20:

	in	al,status_port			; read keyboard status port
	test	al,inpt_buf_full		; check to be sure we can we can write buffer
	jz	kybd_echo_25
	loop	kybd_echo_20
	jmp	short kybd_echo_end		; if can't write this time, exit

kybd_echo_25:

	call	Get_Key_Data		       	; ax has the data upon return
	mov	floop_back,true			; flag to be sure we get our keystroke on the way back thru int 15h

	out	kb_data,al			; write "al"register to port 60h
	jmp	$+2				; delay
	xor	cx,cx				; reset cx to 0
	
kybd_echo_30:

	in	al,status_port			; read keyboard status port
	test	al,inpt_buf_full		; check to be sure we can we can write buffer
	jz	kybd_echo_35
	loop	kybd_echo_30
	jmp	short kybd_echo_end		; if can't write this time, exit

kybd_echo_35:

	mov	al,3fh				; read command to 8042
	out	status_port,al			; write to port 64h
	jmp	$+2				; delay
	xor	cx,cx				; reset cx to 0

kybd_echo_40:

	in	al,status_port			; read keyboard status port
	test	al,inpt_buf_full		; check to be sure input buffer empties
	jz	kybd_echo_45
	loop	kybd_echo_40
	jmp	short kybd_echo_end		; if can't write this time, exit

kybd_echo_45:

	xor	cx,cx				; reset cx to 0

kybd_echo_50:

	in	al,status_port			; read keyboard status port
	test	al,out_buf_full			; check to be sure output buffer filled
	jnz	kybd_echo_end
	loop	kybd_echo_50			; wait till not zero, (i.e. buffer is filled)

;	pop	cx				; clean up stack

kybd_echo_end:

	ret

kybd_echo	endp


;----------------------------------------------------------------------------
;	Put_Key_Data
; 
; This procedure loads keyboard key data into a buffer where the timer will later
; retrieve it and send it to the InjectKeys.  
;
; Key scan codes may be retrieved by computers which support int 15h also.  If they 
; do, the fbios_called_timer flag will be set.
;
;	Expects   Ax= keyboard data to be stored, order is
;			
;		  ah = 0
;		  al = hidden code and scan code if called twice, scan code if called once 

Put_Key_Data	proc

	assume	DS:_TEXT

	push	bx				; temp store of bx register
	push	si				; temp store of si register

	mov	bx,key_data_tail		; get tail pointer of key_data buffer
	mov	si,bx				; save pointer value
	add	bx,2				; move to next word address in buffer
	cmp	bx,OFFSET key_data_end		; are we at the end of the buffer ?
	jne	PKD_5				; no
	mov	bx,OFFSET key_data		; yes we are, so reset to the buffer beginning

PKD_5:
	cmp	bx,key_data_head		; has the buffer wrapped around ?
	jne	PKD_10

; if equal, buffer is full, beep high to inform user, and exit

	jmp	Put_Key_Data_End		; if full, error beep and leave routine

PKD_10:
	mov	[si],ax				; move whats in ax into address pointed to by si
	mov	key_data_tail,bx		; update tail pointer

Put_Key_Data_End:

	pop	si
	pop	bx
	ret

Put_Key_Data	endp

;----------------------------------------------------------------------------
;	Get_Key_Data
; 
; This procedure retrieves keyboard keystroke info. from a buffer for the timer 
; to send it to InjectKeys or for int15h to retrieve.
;
;	Returns   ax = keyboard keystroke data stored
;
;		  ah = 0
;		  al = hidden code and scan code if called twice, scan code if called once 


Get_Key_Data	proc

	assume	DS:_TEXT

	push	bx				; temp store of bx register

	mov	bx,key_data_head		; get head pointer of key_data buffer
	cmp	bx,key_data_tail		; test to see if head = tail, i.e. no data to send
	je	Get_Key_Data_End

	mov	ax,[bx]				; move whats in address pointed to by bx into ax
	add	bx,2				; move to next word in list
	cmp	bx,OFFSET key_data_end		; are we at the end of the buffer
	jne	GKD_5				; no, then we are done, except update the pointer
	mov	bx,OFFSET key_data		; if yes, then reset to the beginning of the buffer
GKD_5:
	mov	key_data_head,bx   		; move the head pointer to the start also

Get_Key_Data_End:

	pop	bx
	ret

Get_Key_Data	endp

;----------------------------------------------------------------------------
; beep
;
; Expects:	bx = length (number of cycles)
;		cx = tone (length of cycle)
;
; Changes:	bx

beep	proc

	push	ds
	push	cs
	pop	ds
	assume DS:_TEXT

	push	ax			; save ax
	IN	al,kb_ctl		; get keyboard control

	push	ax			; save
	push	cx			; save cx=wave length
b_1:	
	and	al,0fch			; set speaker bits
	OUT	kb_ctl,al		; send out to speaker
	pop	cx			; get cx=wave length
	push	cx			; save cx
b_2:	
	loop	b_2			; keep on for wave length of time
	cmp	fsilent_click,true	; should this be a silent click
	je	b_2A
	or	al,2			; set speaker bit
	jmp	short b_2B
b_2A:
	or	al,0			; NO SOUND 
b_2B:
	OUT	kb_ctl,al		; send out to speaker
	pop	cx			; get cx
	push	cx			; save cx
b_3:	
	loop	b_3			; keep off for wave length of time
	dec	bx			; decrement length of tone
	jnz	b_1			; loop if not zero

	pop	cx			; restore cx
	pop	ax			; get old keyboard control
	OUT	kb_ctl,al		; send out
	pop	ax			; restore old ax

	pop	ds

	ret
beep	endp

;----------------------------------------------------------------------------
; beep_high
; beep_low
; beep_turn_on
; beep_turn_off
; no_beep
; click
;
; The following routines provide the sound feedback.
;
; Expects:	Nothing
;
; Changes:	Nothing
;


beep_high	proc	

	push	ds
	push	cs
	pop	ds
	assume DS:_TEXT

	push	cx			; save registers
	push	bx
	mov	bx,high_tone_len	; give low tone
	mov	cx,high_tone
beep_high_20:
	call	beep
	pop	bx			; restore registers
	pop	cx

	pop	ds
;	assume	DS:NOTHING

	ret
beep_high	endp



beep_low	proc	

	push	ds
	push	cs
	pop	ds
	assume DS:_TEXT

	push	cx			; save registers
	push	bx
	mov	bx,low_tone_len		; give low tone
	mov	cx,low_tone
	call	beep
	pop	bx			; restore registers
	pop	cx

	pop	ds
;	assume	DS:NOTHING

	ret
beep_low	endp



no_beep		proc	

	push	ds
	push	cs
	pop	ds
	assume DS:_TEXT

	push	cx			; save registers
	push	bx
	mov	bx,no_tone_len		; give no tone
	mov	cx,no_tone
no_beep_20:
	call	beep
	pop	bx			; restore registers
	pop	cx

	pop	ds
;	assume	DS:NOTHING

	ret
no_beep		endp

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

beep_turn_on	proc	

	push	ds
	push	cs
	pop	ds
	assume DS:_TEXT

	push	cx			; save registers
	push	bx
	mov	cx,turn_on_start_beep	; low frequency
bon_20:	
	mov	bx,02h
	call	beep
	sub	cx,on_off_change	; rate of change
	cmp	cx,turn_off_start_beep	; high frequency
	jg	bon_20

	pop	bx			; restore registers
	pop	cx

	pop	ds
;	assume	DS:NOTHING

	ret
beep_turn_on	endp
;---------------------------------------------------------------
	
beep_turn_off	proc   

	push	ds
	push	cs
	pop	ds
	assume DS:_TEXT

	push	cx			; save registers
	push	bx
	mov	cx,turn_off_start_beep	; high frequency
bof_20:	
	mov	bx,02h
	call	beep
	add	cx,on_off_change	; rate of change
	cmp	cx,turn_on_start_beep	; low frequency
	jl	bof_20

	pop	bx			; restore registers
	pop	cx

	pop	ds
;	assume	DS:NOTHING

	ret
beep_turn_off	endp

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

click 	proc

	push	ds
	push	cs
	pop	ds
	assume DS:_TEXT

	push	cx			; save registers
	push	bx
	mov	bx,click_tone_len      	; give click tone
	mov	cx,click_tone
	call	beep
	mov	fsilent_click,false	; reset to clear for PC or XT
	pop	bx			; restore registers
	pop	cx

	pop	ds
;	assume	DS:NOTHING

	ret
click	endp

;----------------------------------------------------------------------------
;	Get_Mouse_Data
; 
; This procedure retrieves mouse button info. from a buffer for the timer 
; to send it to the appropriate mouse input mechanism.
;
;	Returns   Ax= mouse data stored
;
;		  1st Mouse_Status
;		  2nd Delta_X
;		  3rd Delta_Y

Get_Mouse_Data	proc

	assume	DS:_TEXT

	push	bx				; temp store of bx register

	mov	bx,mouse_data_head		; get head pointer of mouse_data buffer
	cmp	bx,mouse_data_tail		; test to see if head = tail, i.e. no data to send
	je	Get_Mouse_Data_End

	mov	ax,[bx]				; move whats in address pointed to by bx into ax
	dec	mouse_cnt			; derease counter since we took a word out of the buffer

	add	bx,2				; move to next word in list
	cmp	bx,OFFSET mouse_data_end	; are we at the end of the buffer
	jne	GMD_5				; no, then we are done, except update the pointer
	mov	bx,OFFSET mouse_data		; if yes, then reset to the beginning of the buffer
GMD_5:
	mov	mouse_data_head,bx   		; move the head pointer to the start also

Get_Mouse_Data_End:

	pop	bx
	ret

Get_Mouse_Data	endp

;---------------------------------------------------------------------------
; _int2f
;
; We hook int2fh, to monitor if Windows is ever loaded after Access Dos is already 
; loaded.  To test, we will abort Enhanced loading and put up a message.
; AccessDOS version 1.1 allows enhanced mode windows.


_int2f	proc	far

	cmp	ax,01605h				; watch for Windows to load after us
	jne	int2f_50				; this is what Windows broadcasts when it loads

	push	dx
	and	dx,001h					; mask off bit 0
	cmp	dx,0					; is this Windows 3 in enhanced mode ?
	pop	dx   
	jne	int2f_45				; if not, exit to next int 2fh handler

; If we find enhanced mode, flag it accordingly instead of aborting as AccessDOS v1.00 did
;
;	mov	cx,1					; return cx=1, will cause windows to abort
;	pop	dx					; 
;	jmp	int2f_100

	push	ds
	push	cs
	pop	ds
	assume DS:_TEXT

	mov	fwindows_after,true			; general flag for Windows standard mode loading after ADOS
	mov	fwindows_enh,true			; flag that we are in Windows enhanced mode

	push	ax
	mov	al,fhearing_on				; save state of hearing impaired flag(s)
	mov	fhearing_on_save,al
	mov	fhearing_on,false
	mov	al,fvideo_flash				; ""
	mov	fvideo_flash_save,al
	mov	fvideo_flash,false
	pop	ax
	jmp	int2f_90


int2f_45:

	push	ds
	push	cs
	pop	ds
	assume DS:_TEXT

	mov	fwindows_after,true			; general flag for Windows standard mode loading after ADOS
	mov	fwindows_after_st,true			; flag that Windows stand. mode is starting after ADOS

	push	ax
	mov	al,fhearing_on				; save state of hearing impaired flag(s)
	mov	fhearing_on_save,al
	mov	fhearing_on,false
	mov	al,fvideo_flash				; ""
	mov	fvideo_flash_save,al
	mov	fvideo_flash,false
	pop	ax

;	call	serialKeysDisableFar

	jmp	int2f_90

int2f_50:

	cmp	ax,01606h				; watch for Windows to unload after us
	jne	int2f_75				; this is what Windows broadcasts when it unloads
 
; right now don't need to check if unloading from enhanced or stand./real  -- change for 1.1

	push	ds
	push	cs
	pop	ds
	assume DS:_TEXT

;;	cmp	fwindows_after_st,true			; this would have been set true by a successful Windows loading
;;	je	int2f_70				; if not, operator tried enhanced windows, so give error messasge
;;
;;	print	mesg43					; print message to abort
;;	print	mesg44					; instruct user to try Windows in Real/Standard Mode

int2f_70:
; reset flags upon exit

	mov	fwindows_after,false			; general flag for Windows real mode running after ADOS
	mov	fwindows_after_st,false			; flag that Windows stand. mode is running after ADOS
	mov	fwindows_enh,false
	mov	video_count,07fh			; reset such that it will take 5 seconds to start video 

	push	ax
	mov	al,fhearing_on_save			; restore upon exit
	mov	fhearing_on,al
	mov	al,fvideo_flash_save
	mov	fvideo_flash,al
	pop	ax

;	cmp	fserial_keys_loaded,true		; is serial keys loaded ?
;	jne	int2f_72
;	cmp	_serialKeysOn,true			; is SerialKeys code on ?
;	jne	int2f_72
;
;	call	_serialKeysEnableFar
;	call	_initCommPort				; reset 
;	call	_serialKeysStartupInit			; clear serialkeys buffers

int2f_72:

	jmp	short int2f_90


int2f_75:

	cmp	ax,01684h				; watch for Windows to load after us
	jne	int2f_80				; this is what Windows broadcasts when it loads Real Mode
							; NOTE, Windows doesn't broadcast REAL mode exit of 01606h !@!

	push	ds
	push	cs
	pop	ds
	assume DS:_TEXT

	mov	fwindows_after,true			; general flag for Windows loading after ADOS
	mov	fwindows_after_re,true			; flag that Windows real mode is starting after ADOS

	push	ax
	mov	al,fhearing_on				; save state of hearing impaired flag(s)
	mov	fhearing_on_save,al
	mov	fhearing_on,false
	mov	al,fvideo_flash				; ""
	mov	fvideo_flash_save,al
	mov	fvideo_flash,false
	pop	ax
							; and no way to tell when we exit, use timer to find out if we exitted
;	call	_serialKeysDisableFar

	mov	video_count,07fh			; reset such that it will take 5 seconds to start video 
	jmp	short int2f_90

								   
int2f_80:

	cmp	ax,04680h				; watch for Windows 3.0 to DOS box
	je	int2f_85

	cmp	ax,04810h				; watch for Windows 3.1 to DOS box
	jne	int2f_100

int2f_85:

	push	ds
	push	cs
	pop	ds
	assume DS:_TEXT

	cmp	fwindows_after_st,true			; are we DOS boxing after Windows standard was started ?
	jne	int2f_86 
	jmp	short int2f_88

int2f_86:
	cmp	fwindows_enh,true			; are we DOS boxing after Windows enhanced mode was started ?
	jne	int2f_87 
;	jmp	short int2f_88
	jmp	short int2f_90				; if running in enhanced mode, allow Access Utility SerialKeys
							; to run as is, do not attempt tp take back the port in a DOS box
int2f_87:
	cmp	fwindows_after_re,true			; are we DOS boxing after Windows real was started ?
	jne	int2f_90				; if not, exit as some one is asking if Windows is loaded
int2f_88:

;	call	click					; DEBUGGING
	cmp	fserial_keys_loaded,true		; is serial keys loaded ?
	jne	int2f_90

	cmp	_skWindowCompatible,true
	je	int2f_89

	cmp	_serialKeysOn,true			; is SerialKeys code on ?
	jne	int2f_90

int2f_89:

	cmp	_serialKeysOn,true
	je	int2f_90

	call	_serialKeysEnableFar
;	call	_initCommPort				; reset 
;;	call	_serialKeysStartupInit			; clear serialkeys buffers

int2f_90:

	pop	ds
	assume	DS:NOTHING

int2f_100:

	jmp	dword ptr cs:old_2f_int	    		; jump to original interrupt 2fh handler

_int2f	endp

;---------------------------------------------------------------------------
; _int71/74
; 
; All we are doing is hooking the input of the mouse to be able to reset the 
; StickeyKeys count (key_cnt) if we get real mouse activity.  Turns out for the the PS/2 Model
; 25..30/86, the keyboard int9h, is shared by the keyboard and the pointing device.  Therefore,
; we don't necessarily know if the interrupt was generated by the mouse or the keyboard, unless
; we do some further investigation.  After looking at the new PS/2 BIOS, (or what DOS adds to it)the 
; original keybd. int. has a pre-amble attached which decifers whether or not the interrupt was a 
; keystroke or the pointing device.  After review, I decided to set my own flag, such that if the 
; keyboard int 9h routine is called by the original int ? device(mouse or keyboard), then I will 
; not reset the key_cnt variable of StickeyKeys, since it was not mouse activity.
;

_intps2mou	proc
		  
	push	ds
	push	cs
	pop	ds
	assume DS:_TEXT

	mov	fmouse_or_kybd,false 			; set flag to false at entry

	pushf
	call	dword ptr cs:old_ps2mou_int	    	; call original interrupt 71 or 74h

	cmp	fmouse_or_kybd,false			; if keybd int 9h. was called, this would have been set true
	jne	_intps2mou_25				; if false, then it was mouse activity, and we need to reset key_cnt
	mov	key_cnt,false

_intps2mou_25:

	pop	ds
	assume	DS:NOTHING

	iret

_intps2mou	endp


;---------------------------------------------------------------------------
; sub_int33 
;
;	If this suroutine is called, it's because an application passed the mouse driver
; a new address to send data when ever the mouse int. occurs.  If this is called, we are really only 
; interested in maintaining the button status connection between MouseKeys and the real mouse.
;
; This routine is called with ax=mask=bit1=left but. pressed, bit2=left button released
; bit3=right button pressed, bit4=right button released

sub_int33	proc	far

	push	ds
	push	cs
	pop	ds
	assume DS:_TEXT

; if this routine gets called, then there was mouse activity, a mouse int. was generated, so reset StickeyKey count

	mov	key_cnt,0				; reset key_cnt to 0
	cmp	fMouseKeysOn,true			; check to see if MouseKeys is even On ?
	je	sub_int33_2
	jmp  	sub_int33_65
  
sub_int33_2:

	cmp	fmouse_button,true			; using a MouseKeys button ?
	je	sub_int33_4				; if yes, then the int. was initiated by kybd, follow thru

; If not a MouseKeys int. (i.e. from the kybd), then the real mouse was moved or a real mouse button was pushed while
; MouseKeys is on, so if we want to allow the MouseKeys mouse button to override the real mouse button, then we better
; check that they agree, and if not, alter the real mouse button info accordingly. 


	cmp	fbutton_down,true			; is the MouseKeys button down ???
	jne	sub_int33_3A				; if no, MouseKeys button is down, then don't need to compare status'

;********************************************************************************************************************************
; REAL MOUSE HANDLING
;
; Real mouse input while the MouseKeys mouse button is being held down, so we must act on it
; If we see that the REAL mouse depresses a button, we will assume it is a mouse capable users, 
; and reset allow the real mouse to release the depressed MouseKeys button.  However, do not
; let only button up information reset the MouseKeys mouse button so check to see if the real 
; mouse is sending any mouse button up info ??(ax=0001 0100 ?)
;
; ax = mask passed back to application from mouse driver to inform application why mouse driver is sending data
;
; mouse moved           ax = 0000 0001 (01h)
; mouse r/l button down ax = 0000 1010 (0Ah)
; mouse r/l button up	ax = 0001 0100 (14h)
;
;********************************************************************************************************************************

	push	bx
	push	ax

; check if button down info

	mov	bx,ax					; get button info into ax
	and	ax,0ah					; mask ax for either right/left/both buttons down
	jz	sub_int33_2A				; if zero, then there was not any button pressed down
	pop	ax

	mov	fbutton_down,false			; reset MouseKeys button down flag
	mov	Button_Status,0				; reset since we let MouseKeys mouse button up

	cmp	_fmouse_id,4				; check if a PS/2 mouse ?
	jne	sub_int33_2B
	mov	Mouse_Status,08h			; reset Mouse_Status to button up also for PS2 mouse
	jmp	short sub_int33_3			; exit

sub_int33_2B:
	mov	Mouse_Status,040h			; reset Mouse_Status to button up also for serial mouse
	jmp	short sub_int33_3			; exit

sub_int33_2A:

	mov	ax,bx					; get button info into ax
	and	ax,014h					; mask ax for either right/left/both buttons up
	pop	ax					; pop has no affect on the flags status
	jz	sub_int33_3				; if zero, there was no button release info, so pass along as is

; If we get here, then we have Real mouse button up info, and we want to suppress it
; Some applications need to see mouse button dowm to remain in sync, so we will try to fool them also


	xor	ax,ax					; zero ax mask, causing real mouse info to not pass on the fact that real mouse 
							; button is actually up, since we want MouseKeys mouse button to override
	mov	ax,01					; first bit is set in real codes
;	shr	bx,1					; move whatever up mask bit right 1 bit to a down mask bit
;	or	ax,bx					; logical -or- them to ax, so it looks like mouse button is down


sub_int33_3:
	pop	bx

sub_int33_3A:

	jmp	sub_int33_50				; we can exit

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

sub_int33_4:

; if we get a MouseKeys button_up key, we want to EAT the down portion of the button_click
; and not pass that along to the application.  Remember, we added the button_click to a standard
; button_up to fool the mouse driver for those occassions when the user operates both MouseKeys
; and the real mouse

	cmp	fbutton_up,true				; did we have a button up ?
	jne	sub_int33_50
	mov	bx,0					; clear button down mask before the application gets it
	xor	ax,ax					; clear ax
	mov	ax,14h					; mask to release both buttons
	mov	fbutton_up,false			; reset flag to false since we ate the button down code as designed

sub_int33_50:

	push	ax
	mov	ax,mouse_data_head			; get head pointer of mouse_data buffer
	cmp	ax,mouse_data_tail			; test to see if head = tail, i.e. no data to send
	jne	sub_int33_60			   	; if not equal, data in mouse_data buffer, so don't reset this flag yet
	mov	fmouse_button,false			; after we have sent the ALL THE mouse info, reset this flag

sub_int33_60:
	pop	ax

sub_int33_65:

	call	dword ptr cs:sub_int33_ptr

	pop	ds
	assume	ds:NOTHING
	ret

sub_int33	endp

;----------------------------------------------------------------------------
; int33h hook
; 
; Hooked int33h in an attempt to watch mouse activity and to keep mousekeys in 
; sync with real mouse activity, i.e. if mousekeys locks a button down, movement 
; real mouse will alter this, so if we monitor for this condition, we can correct
; or keep the two mice in sync
;----------------------------------------------------------------------------

PUBLIC	_int33

_int33	proc

	push	ds					; save registers used

	push	cs
	pop	ds
	assume DS:_TEXT

	cmp	fmousetrapping,false			; is mouse address hooking allowed
	je	i33_2
	jmp	i33_A_50  				; if not,call original int 33h

i33_2:
;-------------
; AX=0 or 33 decimal (21h)
;-------------
	cmp	ax,0					; did we get a call to mouse reset and status
	je	i33_3
	cmp	ax,21h					; did we do a software reset ?, if so, only clear mask
	je	i33_4
	jmp	short i33_5

i33_3:
	mov	sub_int33_ptr_off,0
	mov	sub_int33_ptr_seg,0
i33_4:
	mov	call_mask,0				; reset call mask with 0 or 21h calls
	jmp	i33_A_50

;-------------
; AX= 12 decimal (0Ch) or 20 decimal (14h)
;-------------
;
; If we get here, someone is using int 33 vector with function 12 decimal, which will be
; passed an address for the mouse driver to send mouse data when a mouse int. occurs, based 
; upon a mouse mask which gets set.  We have to trap for this address, if we want to monitor
; what the real mouse might be doing, to keep it in sync with MouseKeys.  This situation occurs
; for example, if MouseKeys has a mouse button down, and then I move the real mouse, normally the 
; real mouse movement would cancel the mouse button down of MouseKeys, and we didn't want it to.
; Therefore, we need to be able to trap such conditions, and alter them to the desired condition, 
; before the application actually gets the mouse info.

i33_5:

	cmp	ax,0Ch					; is int 33h being called with ax=12, i.e. reseting an address
	je	i33_5_A
	cmp	ax,014h
	je	i33_5_A
	jmp	short i33_8

i33_5_A:
	mov	call_mask,cx
	
i33_5_D:

	pushf
	call	dword ptr cs:old_33_int			; call original interrupt 33h

	push	es
	push	ax
	push	bx
	push	cx
	push	dx

	mov	ax,cs
	mov	bx,ax
	mov	es,ax
assume es:_TEXT
	mov	dx,OFFSET sub_int33			; our routine that gets executed if an application repoints the 
							; now int 33h, called with ax=12, will load our sub_int33h address 
							; as es:dx instead of the application's es:dx
	mov	cx,call_mask
	mov	ax,0014h				; call to swap int. routines

	pushf
	call	dword ptr cs:old_33_int			; call original interrupt 33h

i33_5_G:
	mov	word ptr [sub_int33_ptr_off],dx 	; save address our call returned as new sub_int33_ptr
	mov	word ptr [sub_int33_ptr_seg],es	 	

	pop	dx
	pop	cx
	pop	bx
	pop	ax
	pop	es
assume es:nothing

	jmp	i33_B_50


;-------------
; AX=22 decimal (16h)
;-------------
; If we get here, application is exitting for some reason, and wants to save the state of the mouse.
; We need to put back the address the application may have originally passed to the mouse driver, to 
; tell the mouse driver where to send data, so when the application resatarts, we will have an address
; we can use to rehook ourselves.

i33_8:

	cmp	ax,016h
	je	i33_8_A
	jmp	short i33_10

i33_8_A:

	push	es
	push	ax
	push	bx
	push	cx
	push	dx

	mov	dx,word ptr [sub_int33_ptr_off]
	mov	es,word ptr [sub_int33_ptr_seg]
	mov	bx,es
	mov	cx,call_mask
	mov	ax,0014h				; call to swap int. routines

	pushf
	call	dword ptr cs:old_33_int			; call original interrupt 33h

	pop	dx
	pop	cx
	pop	bx
	pop	ax
	pop	es

	jmp	i33_3

;------------------------------------
; AX = 23 decimal (17h) 
;------------------------------------

i33_10:
	cmp	ax,017h
	je	i33_10_A
	jmp	short i33_A_50

i33_10_A:

	pushf
	call	dword ptr cs:old_33_int			; call original interrupt 33h

	push	es
	push	ax
	push	bx
	push	cx
	push	dx

	mov	ax,cs
	mov	bx,ax
	mov	es,ax
assume es:_TEXT
	mov	dx,OFFSET sub_int33			; our routine that gets executed if an application repoints the 
							; now int 33h, called with ax=12, will load our sub_int33h address 
							; as es:dx instead of the application's es:dx
	mov	cx,01fh
	mov	ax,0014h				; call to swap int. routines

	pushf
	call	dword ptr cs:old_33_int			; call original interrupt 33h

; check call_mask returned, to see if this is an active mouse application

	cmp	cx,0   
	jne	i33_10_G

; we did get back a zero for call_mask
; so call back with ax = 0014h, es:dx are the address we received
; leave CX alone, as we want to pass back the original call_mask

	mov	ax,0014h				; call to swap int. routines
	pushf
	call	dword ptr cs:old_33_int			; call original interrupt 33h	

	mov	ax,0
	mov	cx,ax					; to rezero call mask coming up if was zero
;	mov	es,ax
;	mov	dx,ax					; clear our sub_int33_ptr upon return

i33_10_G:

	mov	call_mask,cx				; get new call mask
	mov	word ptr [sub_int33_ptr_off],dx 	; save address our call returned as new sub_int33_ptr
	mov	word ptr [sub_int33_ptr_seg],es	 	

	pop	dx
	pop	cx
	pop	bx
	pop	ax
	pop	es
assume es:nothing

	jmp	short i33_B_50

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

i33_A_50:

	pushf
	call	dword ptr cs:old_33_int			; call original interrupt 33h

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

i33_B_50:

; at this point, we don't know if this is a MouseKeys or real mouse entry, using int. 33 or polled, so we need to 
; check if button status or x,y coordinate info was requested, so we can decide if we should reset key_cnt of 
; StickeyKeys.

	cmp	ax,03					; request for button status and mouse postion ?
	je	i33_26A
	jmp	i33_50

; is requesting mouse button or movement info, unfortunately, this may be a polled mouse, which would do this
; request several times each second, even if no mouse activity occurred, or this may be from an int. mouse
; which didn' use int.33 to repoint the mouse vector like seen in sub_int33 routine, so we have to check if any mouse
; data is being returned, before we can judge to reset the key_cnt variable of StickeyKeys
; Not setting mouse_x/y_temp first time thru, so may miss a StickeyKeys count, but unlikely, since polling is so fast

i33_26A:
	cmp	bx,0					; if bx=0, the mouse button(s) is/are up
	jne	i33_26B					; if not zero, then we had mouse button activity, so reset key_cnt

	cmp	mouse_x_temp,cl				; did mouse x data change from last poll ??
	jne	i33_26B					

	cmp	mouse_y_temp,dl				; did mouse y data change from last poll ??
	je	i33_27					; no change, so jump to cont

i33_26B:
	mov	mouse_x_temp,cl				; update mouse_x_temp position	
	mov	mouse_y_temp,dl				; update mouse_y_temp position
	mov	key_cnt,0				; reset key_cnt to 0


i33_27:
; now we can continue as normal, by first checking to see if MouseKeys is even on ???

	cmp	fMouseKeysOn,true
	je	int33_27
	jmp	i33_50

int33_27:

;; Okay, MouseKeys is On and Int33h, requested button info.  Is there a MouseKeys keys down???
;

	cmp	fbutton_up,true				; did we have a button up ?
	jne	int33_27B
	mov	bx,0					; clear the extra button down mask that MouseKeys sends, before the 
							; application gets it

	mov	fbutton_up,false			; reset flag to false since we ate the button down code as designed
	jmp	i33_50					; then jump around all this checking

int33_27B:

; if no MouseKeys keys are currently down, look out for real mouse info, if get any real mouse info, and we want to 
; keep the MouseKeys mouse button down if it was down, then we must alter the real mouse button info if it tries to
; let the mouse buttons up

	cmp	fbutton_down,true			; is the MouseKeys button down ???
	je	int33_28				; if yes, then a MouseKeys button is down, and we need to check on REAL mouse status
	jmp	i33_50					; if not, jump around all this checking

int33_28:

;********************************************************************************************************************************
; REAL MOUSE HANDLING
;
; Real mouse input while the MouseKeys mouse button is being held down, so we must act on it
; If the REAL mouse button is pushed, allow it to release the MouseKeys mouse button.
; Problem with a "polled" mouse routine, is that it constantly asks for mouse status updates, and MouseKeys
; buttons are one time things.  If this routine gets asked for mouse status info, we have no way of
; knowing if it is MouseKeys mouse button down, or REAL mouse buttons down, since the asking is continous
; which is alot different than asking only when an action occurs (interrupt driven) as in the 
; mouse routines above which handle the interrupt driven mouse.  We can figure one thing out however,
; and that is that we should never see mouse button up information, as long as the fbutton_down flag
; is set within MouseKeys, unless the REAL mouse sent it.  

; Next check to see if the real mouse is sending any mouse button up info ??(bx=0000 0000 ?)
; We could get REAL mouse button up info. from moving the REAL mouse or from clicking the REAL mouse button ?
; Problem is, we want to override a button up if it was from moving, and allow a button up if it was a click

	cmp	bx,0					; if zero, real mouse is sending all buttons are up info.
	jz	int33_29				; if zero, there is button up info, so we must alter
	jmp	i33_50					; if not, jump around all this checking

int33_29:
	
; If we get here, then we have Real mouse button up info, and we want to suppress it, so we have to check and see what
; MouseKeys mouse button is down, and echo this condition

	cmp	_fmouse_id,4				; check if a PS/2 mouse ?
	jne	int33_37

;-------------------------------------------------------------------------------------------------
; PS/2 Mouse

	push	ax					; temp store
	mov	ax,Mouse_Status
	and	al,03h					; mask off lowest bits
	cmp	al,01					; is the left MouseKeys button down ?
	jne	int33_30
	xor	bx,bx					; clear what ever was in bx
	or	bx,01h					; or the left button pressed in bx mask
	pop	ax
	jmp	i33_50	  				; exit to normal address called

int33_30:
	cmp	al,02h
	jne	int33_32
	xor	bx,bx					; clear what ever was in bx
	or	bx,02h					; or the right button pressed
	pop	ax
	jmp	i33_50

int33_32:

	cmp	al,03h
	jne	int33_34				; if we do this jump, no buttons were down
	xor	bx,bx					; clear what ever was in bx
	or	bx,03h					; or both the left and right buttons pressed
	pop	ax
	jmp	i33_50

int33_34:
	pop	ax
	jmp	i33_50					; if we already called int33h, jump around doing it again
;----------------------------------------------------------------------------------------------------------------------------
; serial mouse

int33_37:

	cmp	_fmouse_id,2				; check if a serial mouse ?
	jne	i33_50

	push	ax					; temp store
	mov	ax,Mouse_Status
	and	al,030h					; mask off high byte low bits
	cmp	al,00h					; any MouseKeys buttons down
	je	int33_44				; no
	cmp	al,020h
	jne	int33_40
	xor	bx,bx					; clear what ever was in bx
	or	bx,01h					; or the left button pressed in bx mask
	pop	ax
	jmp	i33_50					; exit to normal address called

int33_40:
	cmp	al,010h
	jne	int33_42
	xor	bx,bx					; clear what ever was in bx
	or	bx,02h					; or the right button pressed
	pop	ax
	jmp	i33_50

int33_42:

	cmp	al,030h
	jne	int33_44				; if we do this jump, we had an error ?
	xor	bx,bx					; clear what ever was in bx
	or	bx,03h					; or both the left and right buttons pressed
	pop	ax
	jmp	i33_50

int33_44:
	pop	ax

i33_50:

	pop	ds
	assume	DS:NOTHING

	iret

_int33	endp
									    
;----------------------------------------------------------------------------
;----------------------------------------------------------------------------
;----------------------------------------------------------------------------
;----------------------------------------------------------------------------
;----------------------------------------------------------------------------
; new_timer_int 
;
; Calls various procedures to handle time dependent function of the different
; features.  Also calls the original timer 1Ch interrupt

_new_timer_int	proc

	push	ds					; save registers used
	push	es
	push	si
	push	di
	push	dx
	push	cx
	push	bx
	push	ax

	push	cs
	pop	ds
	assume DS:_TEXT
	push	cs
	pop	es
	assume ES:_TEXT

;	cmp	ftimer_1C_active,true 			; check to see if we got re-interrupted ?
;	jne	NT_5
;	call	click
;	jmp	NT_END_5
;NT_5:

	mov	ftimer_1C_active,true

; TimeOut_timer is currently called from the Togglekeys_timer routine and seems to work there ????

	call	FilterKeys_timer			; service FilterKeys
	call	ToggleKeys_timer			; service ToggleKeys

	cmp	fMouseKeysOn,true			; is MouseKeys On, if not don't call MouseKey_timer
	jne	NT_8					; if MouseKeys is Off, make sure buffer got emptied on turn off

	call	MouseKeys_timer				; yes, so call the timer

NT_8:

	mov	bx,mouse_data_head			; get head pointer of mouse_data buffer
	cmp	bx,mouse_data_tail			; test to see if head = tail, i.e. no data to send
	jne	NT_10					; if not equal, we have mouse data in the buffer
	jmp	NT_105 					; nothing to send from mouse buffer so jump to here

;---------------------------------------------------------------------------------------------
; if not equal, we have mouse_data to send, after we call, ax will have the data to send
; at this point, we should also disable the real mouse from int. and messing up mousekey 
; data from the buffer.  Quick and dirty way to do this would be to force the mouse clock
; line low, so the mouse would think that the host computer is inhibiting, but we have a serial
; mouse here, not the PS/2 mouse.   Since we again are not inside the mouse driver, we have
; a problem of knowing when it is safe to disable the real mouse (serial this time), since we
; have no way of knowing which data byte might currently be being sent. (i.e. 1st, 2nd or 
; 3rd)  Therefore, we can not truely disable the real mouse safely, so we will NOT currently
; inhibit the real mouse, but inform the user that both mice are active (real serial mouse 
; and MouseKeys) but that the user should not try to input data from both at the same instant 
; of time......
;---------------------------------------------------------------------------------------------
; If we get here,we have mouse data in buffer, so we need to check if PS/2 mouse check

NT_10:

	cmp	_fmouse_id,4				; do we have a PS/2 mouse ?
	jne	NT_50

;-----DEBUGGING------------------------------------------------------
;;;	cmp	fwindows_enh,true			; DEBUGGING
;;;	jne	NT_20
;	call	Inject_Mouse_Low
;	jmp	NT_110	
;
;-----DEBUGGING------------------------------------------------------

NT_20:
	call	Get_Mouse_Data				; ax has the data upon return
	mov	Mouse_Status,ax
	call	Get_Mouse_Data				; ax has the data upon return
	mov	Delta_X,ax
	call	Get_Mouse_Data				; ax has the data upon return
	mov	Delta_Y,ax

	call	InjectMouse
	jmp	short NT_110

;----------------------------------------------------------------------------------------------
; If we get here,we have mouse data in buffer, and we must have a Serial Mouse 

NT_50:

	cmp	_fmouse_id,2				; do we have a serial mouse ?
	jne	NT_110


	cmp	_comp_id,1				; are we on a PC/XT
	je	NT_60
	cmp	_comp_id,1Ah				; are we on a PC/XT with int 15h
	je	NT_60

NT_55:
	cmp	fslow_baud_mouse,true			; do we have a slow mouse
	jne	NT_65

NT_60:

	cmp	fslow_mouse,true			; is this first pass at slow mouse or second ?
	je	NT_65					; second pas, so cont. on
	mov	fslow_mouse,true			; first pass, set flag and exit
	jmp	short NT_110

NT_65:
	mov	fslow_mouse,false			; reset on second pass or every pass if not a slow mouse
	mov	dx,_combase				; put address of combase in dx

; first check to be sure the byte we may have transmitted previously has been sent out

	add	dx,5
	in	al,dx
	test	al,00100000b				; bit 5, transmit buffer should be clear if okay to write
	jz	NT_110					; if zero, register is not empty, jump around

; next check to be sure we are not suppossed to stop sending serial mouse data

	cmp	fserial_stop,true			; if set true, we should stop sending serial mouse data and flush th buffer
	jne	NT_70					; if not set, okay to send so cont

; if we get here, we are suppossed to stop sending serial mouse data, but we need to be sure we have sent a complete packet (3 bytes)
; before we quit.  The easiest way to do this, will be to get a byte from the buffer, and if bit 6 is set, then it is the first byte
; of another three byte packet, and then it is safe to stop sending serial mouse data

	call	Get_Mouse_Data				; get the next mouse data if it exists
	test	al,01000000b				; is bit 6 set high
	jz	NT_80					; if bit 6 is 0, not forst byte, cont. on

; if we get here, bit 6 was set, it is a first byte of a packet, and it is safe to flush the mouse data buffer

	mov	bx,OFFSET mouse_data			; get address of mouse_data buffer
	mov	mouse_data_head,bx			; reset head pointer to start of buffer
	mov	mouse_data_tail,bx			; reset tail pointer to start of buffer
	mov	mouse_cnt,false				; 
	mov	fserial_stop,false
	jmp	short NT_105


NT_70:
	call	Get_Mouse_Data				; get the next mouse data if it exists
NT_80:

	mov	dx,_combase				; put address of combase in dx
	out	dx,al		

NT_90:
	jmp	short NT_110

NT_105:
;--------------------------------------------------------------------------------------------------------------------
; call original timer, If jump was to NT_105, then mouse data buffer is empty, and we can reset fmouse_button flag

	mov	fmouse_button,false			; if buffer is empty reset flag for a serial mouse

NT_110:

; ************ later setup that if this is called and serial port has input, we won't do stuff after orig. int *****************

	cmp	fserial_keys_loaded,true		; is serial keys loaded ?
	jne	NT_112
	cmp	_serialKeysOn,true			; is SerialKeys code on ?
	jne	NT_112

	push	ds
	push	es
	call	_kickStartSerialKeys			; check if SerialKeys needs anything
	pop	es
	pop	ds

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

NT_112:

; If jump was to NT_110, then there was mouse data in the buffer buffer is empty, and after we call orig. int, we should 
; exit the timer int. since we have been inside the timer interrupt extra long doing something with mouse buffer data

	pushf
	call	dword ptr cs:old_1C_int			; call original timer 1Ch interrupt in case any one else chained in

	cmp	fmouse_button,false			; is mouse data buffer empty, (i.e. we didn't do any mouse activity)


	je	NT_115					; if the mouse data buffer was empty, we have the time to cont.
							; inside the timer interrupt


	jmp	NT_END					; since we had mouse activity, exit timer interrupt

;--------------------------------------------------------------------------------------------------------------------
; check to see if we need to call InjectKeys or just fake an interrupt 9h
; because we are running on a computer which supports int 15h and not hardware injection
;--------------------------------------------------------------------------------------------------------------------

NT_115:

; We will never inject if it is not a computer which supports int 15 intercept method of some kind...

	cmp	_vector,15h				; does this computer support int 15 h ?
							; this check should be REDUNDANT !!!!!
	je	NT_118					; cont. on and do an injection method if int 15h computer
	jmp	NT_200					; if not an int 15h computer, buffer should never get data and we should 
							; NEVER attempt to inject in any fashion

NT_118:

	mov	bx,key_data_head			; get head pointer of key_data buffer
	cmp	bx,key_data_tail			; test to see if head = tail, i.e. no data to send
	jne	NT_120					; if not equal, then we may need to empty buffer
	mov	fint9_by_timer,false			; if equal, reset this flag
	jmp	NT_200


NT_120:

; We will never try to inject if keyboard and system are talking...check mode indicator flag at 40:97 in BIOS...

	push	es
	mov	ax,RAMBIOS
	mov	es,ax
	assume	es:RAMBIOS
	mov	al,es:[97h]
	test	al,01000000b				; look at keyboard mode indicator update
	pop	es
	assume	es:_TEXT
	jz	NT_122					; if this flag is zero, safe to talke with keyboard since system is not
	jmp	NT_200					; if this flag is set, system is talking with keyboard, jump around and 
							; wait tilll that interaction is complete before trying to inject

NT_122:

; We will never try to inject if we are simultaneously filling our own keystroke buffer...

	cmp	fkeys_injected,true			; when this is true, something is filling the buffer, so we wait
	jne	NT_123					; when this is false, we can check the buffer for emptying
	jmp	short NT_200				


NT_123:

; Need to check 8259 interrupt controller to be sure that nothing other than the timer interrupt
; which we are currently in is pending before we fake a keyboard int using software int 9h.  We do this to avoid
; unwanted and dangerous extra EOI's being generated. We check "al" register upon return, and if it doesn't 
; equal 1, then we have other pending interrupts and we don't do an inject method now..

	call	controller_check			; check if 8259 controller has any other pending interrupts 
						     	

	cmp	al,01h					; is the timer and only the timer int. pending ?
	jne	NT_200					; if not, don't insert a key just yet
							; if yes, disable interrupts 

	cli						; disable interrupts, leaving timer int. will re-enable 

NT_125:

; Buffer HAS data, and we want to empty it, but need to check which method to use.

	cmp	_finject_keys,true			; can we inject into the hardware ?
	je	NT_150					; if yes, jump to here to do that routine


NT_130:

; If we get here, we do have a computer which supports int 15, but NOT hardware injection
; we must check for the two exception comnputers to the int15, 8042 insert of keys, they are the PS/2 Model 25/30-8086
; and the old PC or PX/XT running DOS 4+/5 with keyb.com loaded simulating int15 services
       
; Exception 1
; if _comp_id = 6, then we have the PS/2 Model 25/30-8086 and we must handle it by checking to see that
; that the timer didn't interrupt a keyboard interrupt, if not, cli, write to port 60h, and do and software int9h

; Exception 2
; if _comp_id = 1A, then we have the PC or PC/XT running DOS 4+/5 with keyb.com loaded and we must handle it by checking to see that
; that the timer didn't interrupt a keyboard interrupt, if not, do software int9h, and insert our code via int15h when it comes by
; since we cannot write a byte to keyboard port 60h on this computer.

	cmp	_comp_id,6
	jne	NT_142

	cmp	fnum_lock_was_off,true			; if we have a space saver kybd, wait till numlock kybd codes have passed
	je	NT_200					; before injecting StickyKey breaks
	jmp	short NT_145

NT_142:
	cmp	_comp_id,1Ah
	jne	NT_148

NT_145:
	cmp	_comp_id,1Ah				; is is the PC or PC/XT ?
	jne	NT_146
	mov	fint9_by_timer,true			; if PC or PC/XT signal to catch in int15h on the way back
	jmp	short NT_147

NT_146:

	call	Get_Key_Data				; ax has the data upon return when doing PS/2 Model 25/20-8086
	out	kb_data,al				; write to kybd data port
	mov	floop_back,true

NT_147:

	int	9h					; do a software int 9h
	jmp	NT_END

NT_148:

; I we get here, it was not one of the exception type computers form the abocve list, so cont. on with the kybd_echo routines...

	call	kybd_echo				; call our routine to insert a keystroke via 8042 undocumented feature
	jmp	NT_END

NT_150:

	cmp	fnum_lock_was_off,true			; if we have a space saver kybd, wait till numlock kybd codes have passed
	je	NT_200					; before injecting StickyKey breaks

	call	InjectKeys				; inject buffer data, keystrokes, into keyboard hardware buffer
	jmp	NT_END

NT_200:

;-----------------------------------------------------------------------------------------------------------------------
; Need to check our dialog flags here.  If fDialog_Action flag is false, (=0), then no action occurred and we can ignore
; any call to the respective turn on or turn off function.  If fDdialog_Action flag is true (1 ), then we need to call the
; respective routine to handle turning on or off of the feature.
;-----------------------------------------------------------------------------------------------------------------------

	cmp	fDialog_Action,true			; any action occur in Dialog or Menu's ?
	jne	NT_300					; if not, skip to next major check

	cmp	fDialog_Filter_off,false		; is filterkeys off ?
	je	NT_220					; yes
	call	FilterKeys_dialog
	jmp	NT_END					; exit timer int. any time we do a routine

NT_220:
	cmp	fDialog_Stickeys_off,false		; is stickeys off ?
	je	NT_240					; yes
	call	StickeyKeys_dialog
	jmp	NT_END					; exit timer int. any time we do a routine


NT_240:
	cmp	fDialog_Mouse_off,false			; is mousekeys off ?
	je	NT_260					; yes
	call	MouseKeys_dialog
	jmp	NT_END					; exit timer int. any time we do a routine

NT_260:
	cmp	fDialog_Toggle_off,false		; is togglekeys off ?
	je	NT_280
	call	ToggleKeys_dialog
	jmp	NT_END					; exit timer int. any time we do a routine
	
NT_280:	
	cmp	fDialog_TimeOut_off,false		; is timeout off ?
	je	NT_300
	call	TimeOut_dialog
	jmp	NT_END					; exit timer int. any time we do a routine

NT_300:
	mov	fDialog_Action,false			; reset this flag upon exit the above routines

;-------------------------------------------------------------------------------------------------------
; Hearing impaired attempt to display to screen a character for sound on/off
; check only 2 times a second otherwise cursor blinking is too annoying
; and also programs which take over the video like Microsoft Works will not
; start if we check the speaker port too often
;-------------------------------------------------------------------------------------------------------

	cmp	fhearing_on,true			; is hearing inpaired viaual cue flag set on ?
	je	video_1
	cmp	fvideo_flash,true			; is hearing impaired video flashing flag set on ?
	je	video_0
	mov	faccess_sound,false			; reset flag and
video_0:
	jmp	video_end				; if hearing impaired flag is not on, jump to here

; Go get the current video state and save it.  If it changes from the previous video state, we
; will prevent writes to video for a short period of time in hopes of not messing up the switched
; video state.
;
; Before we do anything, we will get current video state and check it with the old. Since we asssign
; video state a ZERO to start, it will alway pause when ADOS is first enabled.  We could try to read
; the video state in _Enable Proc and avoid this, if it seems to miss any beeps.

video_1:

	push	es
	mov	ax,RAMBIOS
	mov	es,ax
	assume	es:RAMBIOS
	mov	al,es:[49h]				; read same area int 10h would, but cause less video trouble if not
	pop	es					; going to write visual cue this time thru
	assume	es:_TEXT

;	mov	ah,0fh					; read current video state
;	int	10h					; int 10

	cmp	al,video_state				; is the read video state the same as previous video state ?
	je	video_3					; if yes, cont. on here
	mov	video_state,al				; if not, save current video state
							; and set the video_count such that a 5 second delay will 
							; take palce while the video state is changing

	mov	video_count,07fh			; reset such that it will take 5 seconds to start video 
							; for hearing impaired if on
	mov	faccess_sound,false			; if ADOS produced a sound during a switch, reset that flag also
	mov	fswitching_video,true			; inform myself (ADOS) that video mode is switching
	jmp	video_end				; if switching video , jump out

video_3:

	inc	video_count				; increment counter each time through
	cmp	video_count,9				; have we reach 1/2 second ?
	je	video_4
	jmp	video_end				; if not at 9 yet, jump around

video_4:
	mov	video_count,0				; reset count to 0
	mov	fswitching_video,false			; inform myself (ADOS) that safe to do video

; any reason to produce a video que for some kind of sound which happened or is happening ?

	cmp	faccess_sound,true			; did AccesDos produce a beep
	je	video_20				; yes or speaker did 

video_10:	

	in	al,kb_ctl				; read speaker control port
	and	al,02					; test speaker bit on/off
	jnz	video_18				; speaker bit is high, do video
	jmp	video_end

video_18:
	mov	faccess_sound,true			; use our variable to flag speaker bit toggling also

video_20:

	cmp	video_state,7				; is this mode 7, Mono text
	je	video_22
	cmp	video_state,3				; is this any of the Text video modes below 3
	jle	video_22
		       					; if not, must be in a graphics mode, so 
	mov	txt_or_grph,09h	     			; write a character to video graphically
	jmp	short video_23

video_22:
	mov	txt_or_grph,0ah	 			; write a character to video as text

video_23:

	cmp	fvideo_type,3				; check if we have a CGA monitor
	jne	video_25				; if not, continue

; if yes, don't write to video memory until horizontal retrace is in progress

	mov	dx,3dah
	in	al,dx					; read CGA status byte
	test	al,1					; test bit 1
	jnz	video_25				; if bit is set, in retrace, semi safe to write
	jmp	video_end

video_25:

; if not true, not a CGA monitor and we can write to video directly

	mov	ah,3					; read current cursor position
	mov	bh,0					; page 0
	int	10h					; video interrupt
	mov	old_row,dh				; save current row
	mov	old_col,dl				; save current column
	mov	old_cursor_1,cl				; save current cursor type
	mov	old_cursor_2,ch				; save current cursor type

	mov	ah,2					; prepare to set current position
	mov	dh,0					; row 0
	mov	dl,0					; column 0
	mov	bh,0					; page 0
	int	10h					; video int
			     
video_30:

	mov	ah,08h					; read character and attribute at cursor
	int 	10h
	mov	old_char_1_attr,ah	 		; put attributes into variable

	cmp	al,14					; did we just read back the hearing impaired sysbol ?
	je	video_50

	mov	old_char_1,al				; save orig. char. to rewrite

	mov	ah,2					; prepare to set current position
	mov	dh,0					; row 0
	mov	dl,1					; column 1
	mov	bh,0					; page 0
	int	10h					; video int

	mov	ah,08h					; read character and attribute at cursor
	int 	10h
	mov	old_char_2_attr,ah	  		; put attributes into variable
	mov	old_char_2,al				; save orig. char. to rewrite

	mov	ah,txt_or_grph				; set video mode to write in
video_40:

	cmp	fsecond_cue,false
	je	video_45

	mov	cx,1					; write 1 character			
	mov	al,fsecond_cue				; 
	mov	bl,old_char_2_attr
	int	10h

video_45:

	mov	ah,2					; prepare to set current position
	mov	dh,0					; row 0
	mov	dl,0					; column 0
	mov	bh,0					; page 0
	int	10h					; video int

	mov	cx,1					; write 1 character			
	mov	ah,txt_or_grph				; set video mode to write in
	mov	bl,old_char_1_attr
	mov	al,14					; send ASCII character 14 to video for sounds on
	int	10h

	jmp	video_70				; jump to restore cursor

video_50:

	mov	ah,txt_or_grph				; set video mode to write in
video_66:

	mov	cx,1					; write 1 character			
	mov	faccess_sound,false
	mov	bl,old_char_1_attr
	mov	al,old_char_1				; replace original character
	int	10h

	cmp	fsecond_cue,false
	je	video_70

	mov	ah,2					; prepare to set current position
	mov	dh,0					; row 0
	mov	dl,1					; column 1
	mov	bh,0					; page 0
	int	10h					; video int

	mov	ah,txt_or_grph				; set video mode to write in
	mov	bl,old_char_2_attr
	mov	al,old_char_2				; replace original character
	mov	fsecond_cue,false			; reset fsecond_cue flag
	int	10h

video_70:

	mov	ah,2					; restore current cursor position
	mov	ch,old_cursor_2
	mov	cl,old_cursor_1
	mov	dh,old_row
	mov	dl,old_col
	mov	bh,0
	int	10h

	jmp	NT_END					; exit timer int. any time we do a routine

video_end:

;-------------------------------------------------------------------------------------------------------
; video flash routines


	cmp	fvideo_flash,true			; is hearing impaired video flashing flag set on ?
	je	flash_10
	jmp	flash_end_out

flash_10:

	cmp	fvideo_flash_on,true			; did we already flash
	je	flash_40				; if yes, jump to routine to turn video back on

	cmp	faccess_sound,true			; did AccesDos produce a beep
	jne	flash_15				
	mov	video_cnst,4				; yes  
	jmp	short flash_30

flash_15:	

	in	al,kb_ctl				; read speaker control port
	and	al,02					; test speaker bit on/off
	jnz	flash_20				; speaker bit is high, do video
	jmp	flash_end_out

flash_20:
	mov	faccess_sound,true			; use our variable to flag speaker bit toggling also
	mov	video_cnst,4				; speaker did, keep seperateincase we change system flash length

flash_30:

;;	cmp	fvideo_flash_on,true			; did we already flash
;;	je	flash_40				; if yes, jump to routine to turn video back on

	mov	fvideo_flash_on,true
	call	video_flash_on				; subroutine to do borderflash on
	jmp	short flash_end

flash_40:


	inc	fvideo_flash_cnt
	mov	al,video_cnst
	cmp	al,fvideo_flash_cnt
	jne	flash_end_out

	call	video_flash_off				; subroutine to do borderflash off
	mov	faccess_sound,false
	mov	fvideo_flash_cnt,0
	mov	fvideo_flash_on,false

flash_end:

	jmp	NT_END					; exit timer int. any time we do a routine

flash_end_out:

;--------------------------------- End of Video for Hearing Impaired flag ------------------------------

	cmp	_finject_keys,true			; if flag isn't true, donot check any further
	jne	NT_END

	cmp	fwindows_enh,true			; are we in enhanced mode ?
	jne	NT_END

	cmp	falt_esc_send,true			; safe to send codes ?
	jne	sound_100

	mov	al,038h					; put ALT make into buffer
	call	Put_Key_Data
	mov	al,001h					; put ESC make into buffer
	call	Put_Key_Data
	mov	al,081h					; put ESC break into buffer
	call	Put_Key_Data
	mov	al,0b8h					; put ALT break into buffer
	call	Put_Key_Data

sound_90:

	mov	falt_esc,false
	mov	falt_esc_send,false
	jmp	short NT_END

sound_100:

;--------------------------------- check if we ever loaded Windows Real mode, and if we did, did we exit

	cmp	fwindows_after_re,true			; was Windows ever startec in REAL mode ?
	jne	NT_500

	mov	ax,04680h				; use int2f to see if still loaded
	int	2fh
	cmp	al,00					; al = 00, if REAL mode still running
	je	NT_500
							; if al <> 00, then REAL mode exitted, reset flags

	mov	video_count,07fh			; reset such that it will take 5 seconds to start video 
	mov	fwindows_after_re,false
	mov	fwindows_after,false
	mov	al,fhearing_on_save			; restore upon exit
	mov	fhearing_on,al
	mov	al,fvideo_flash_save
	mov	fvideo_flash,al


NT_500:

;----------------------------------- run if and only if ADOS started after windows in enhanced mode-----------------

	cmp	fctrl_esc_send,true			; safe to send codes ?
	jne	NT_END

	mov	al,01dh					; put CTRL make into buffer
	call	Put_Key_Data
	mov	al,001h					; put ESC make into buffer
	call	Put_Key_Data
	mov	al,081h					; put ESC break into buffer
	call	Put_Key_Data
	mov	al,09dh					; put CTRL break into buffer
	call	Put_Key_Data

	mov	fctrl_esc,false
	mov	fctrl_esc_send,false

NT_END:

	mov	ftimer_1C_active,false

;NT_END_5:

	pop	ax
	pop	bx					; restore registers
	pop	cx
	pop	dx
	pop	di
	pop	si
	pop	es
	assume	ES:NOTHING
	pop	ds
	assume	DS:NOTHING

	iret

_new_timer_int	endp

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

controller_check	proc	near

	assume DS:_TEXT

	mov	al,0Bh
	out	ack_port,al				; write operation command byte 3, to get ISR 
	jmp	$+2

	in	al,ack_port				; read the 8259 controller port
	jmp	$+2

	mov	ah,al
	mov	al,08h
	out	ack_port,al				; write operation to rese controller

	mov	al,ah
	ret

	controller_check	endp
;--------------------------------------------------------------------------------------------------------

video_flash_on	proc	near

	assume DS:_TEXT
	assume	es:NOTHING

	mov	ax,RAMBIOS
	mov	es,ax

	assume	es:RAMBIOS
	mov	al,es:vid_flag
	and	al,0f7h

	cmp	fvideo_type,1
	jne	von_10
	
        mov     dx,3b8h
        out     dx,al
	mov	es:vid_flag,al
	jmp	short von_end

von_10:

	cmp	fvideo_type,3
	jne	von_30

        mov     dx,3d8h
        out     dx,al
	mov	es:vid_flag,al
	jmp	short von_end

von_30:	

	cmp	fvideo_type,4
	jne	von_40

        mov     dx,3bah
        in      al,dx
        mov     dx,3c0h
        xor     al,al
        out     dx,al
	jmp	short von_end

von_40:

	cmp	fvideo_type,5
	jne	von_50
        mov     dx,3dah
        in      al,dx
        mov     dx,3c0h
        xor     al,al
        out     dx,al
	jmp	short von_end


von_50:

	cmp	fvideo_type,6
	jne	von_60
        mov     dx,3d8h
        in      al,dx
        and     al,0f7h
        out     dx,al
	mov	es:vid_flag,al
	jmp	short von_end

von_60:
	cmp	fvideo_type,7
	jne	von_end
        mov     ax,1201h
        mov     bx,0036h
        int     10h

von_end:
	assume	es:NOTHING
	ret

video_flash_on	endp

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

video_flash_off proc	near

	assume DS:_TEXT
	assume	es:NOTHING

	mov	ax,RAMBIOS
	mov	es,ax

	assume	es:RAMBIOS
	mov	al,es:vid_flag
	or	al,08h

	cmp	fvideo_type,1
	jne	voff_10

        mov     dx,3b8h
        out     dx,al
	mov	es:vid_flag,al
	jmp	short voff_end

voff_10:

	cmp	fvideo_type,3
	jne	voff_30

        mov     dx,3d8h
        out     dx,al
	mov	es:vid_flag,al
	jmp	short voff_end

voff_30:	

	cmp	fvideo_type,4
	jne	voff_40
        mov     dx,3bah
        in      al,dx
        mov     dx,3c0h
        mov     al,20h
        out     dx,al
	jmp	short voff_end


voff_40:

	cmp	fvideo_type,5
	jne	voff_50
        mov     dx,3dah
        in      al,dx
        mov     dx,3c0h
        mov     al,20h
        out     dx,al
	jmp	short voff_end


voff_50:

	cmp	fvideo_type,6
	jne	voff_60
        mov     dx,3d8h
        in      al,dx
        or      al,08h
        out     dx,al
	mov	es:vid_flag,al
	jmp	short voff_end

voff_60:
	cmp	fvideo_type,7
	jne	voff_end

        mov     ax,1200h
        mov     bx,0036h
        int     10h

voff_end:

	assume	es:NOTHING
	ret

video_flash_off	endp

;-----------------------------------------------------------------------------------------------------------------
;*****************************************************************************************************************
; This is the beginning of the resident code of the routine which receives
; the keyboard scan code via int 15h from the keyboard interrupt, int 9h.  It builds up 
; the extended scan code while also passing the scan code along back to interrupt 9, most of the time.
; If after passing thru the keyboard features, it is detemined that the scan code should not pass along,
; the software returns to int. 9h with the carry flag cleared.  
;
; The flags fbios_called_direct or fbios_called_timing are used to tell if the scan code should get
; passed back to interrupt 9h, or should be eaten upon passing back to interrrpt 9h.
;
; The scan code is in Al when int 15h is called with Ah = 4f
;*****************************************************************************************************************
;-----------------------------------------------------------------------------------------------------------------


_keybd_int_15  PROC	far

	cmp	ah,4fh					; is this an int15 for the keyboard ?
	je	kybd_int_15_5

	jmp	not_kybd_int_15

kybd_int_15_5:

	push	ds					; save the ds and ax
	push	es
	push	bx
	push	ax

	push	cs
	pop	ds
	assume DS:_TEXT
	push	cs
	pop	es
	assume ES:_TEXT

;---------------------------------------------------------------------------------------------------------------------------
; difference here to standard int 9h routine *******************************************************************************
;---------------------------------------------------------------------------------------------------------------------------

	mov	fmouse_or_kybd,true			; flag any int. callers, that kybd int. 9h executed
	call	TimeOut_Reset				; reset the time out count
	mov	fbios_called_direct,false 		; reset to false upon entry

;----------------------------------------------------------------------------
; we do not want to have any of the routines that process key input have to
; deal with any of the commands that are specifc to the operation of the 
; keyboard, so we will pass them on directly to the BIOS routine since the
; original device driver routine also passed commands to the BIOS routine.
; See original BIOS of Tech. Ref. manuals for PC/PCXT/PCAT
;
	pop	ax

	cmp	al,kybd_Command				; is it a command (0EDh)?
	jb	not_command_15				; no -->

kybd_command_50:

	jmp	kybd_int_15_exit	  		; done -->

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

not_command_15:

;	cmp	fserial_keys_loaded,true		; is serial keys loaded ?
;	jne	kybd_int_15_5A
	cmp	_serialKeysOn,true			; is SerialKeys code on ?
	jne	kybd_int_15_5A

;---------------------------- serial port keyboard emulation ----------
; if we get here, we need to first look and see if SerialKeys injected a code

 	test	cs:_forcedInt9Flag,true			; if flag is true, SerialKeys injected a scan code
	jz	kybd_int_15_5A

	mov	cs:_forcedInt9Flag,false   		; reset flag
	mov	fserial_key_recieved,true		; set flag for my code modules
	mov	ah,04fh					; fill in the rest of a fake int 15h AX 
	mov	al,cs:_injectByte   			; inject new scan code

;IFDEF	BUG
;	mov	portid,9
;	mov	portout,al
;	call	HexCharsOut
;ENDIF;	BUG			

;	call	click
	jmp	short kybd_int_15_7


kybd_int_15_5A:
;---------------------------- keyboard emulation-----------------------
; When we get here, we need to check if this is a real int9 or did the timer simulate an int9 when int 15h was called ?

	cmp	fint9_by_timer,true			; if the timer simulated an int9, this flag will be true
	jne	kybd_int_15_6				; if false, it is a real int 9 and call to int 15
	call	Get_Key_Data				; if true, this is a fake int9, and we want to get 
							; the scan code to pass out of the key_data_buffer
							; the scan code we want to pass is now in AL register
	mov	ah,04fh					; fill in the rest of a fake int 15h AX 
	jmp	short kybd_int_15_7

kybd_int_15_6:


;IFDEF	BUG
;;	mov	fserial_debugging,true
;	mov	portid,0
;	mov	portout,al
;	call	HexCharsOut
;;	mov	fserial_debugging,false
;ENDIF;	BUG

	cmp	fkeys_injected,false
	jne	kybd_int_15_6C
	push	bx
	mov	bx,key_data_head			; get head pointer of key_data buffer
	cmp	bx,key_data_tail			; test to see if head = tail, i.e. no data to send

	je	kybd_int_15_6B				; if equal, then we may need to empty buffer
	cmp	floop_back,true
	je	kybd_int_15_6B

	push	es
	push	ax
	mov	ax,RAMBIOS
	mov	es,ax
	assume	es:RAMBIOS
	mov	al,es:[97h]
	test	al,01000000b				; look at keyboard mode indicator update
	pop	ax
	pop	es
	assume	es:_TEXT
	jz	kybd_int_15_6A				; if clear, comp. and kybd are not talking, okay to in-line inject
	jmp	short kybd_int_15_6B

kybd_int_15_6A:

	call	Put_Key_Data				; save current al
	call	Get_Key_Data				; get my code
	mov	ah,04fh					; fill in the rest of a fake int 15h AX 

kybd_int_15_6B:
	mov	floop_back,false	 		; reset
	pop	bx


kybd_int_15_6C:


;IFDEF	BUG
;;	mov	fserial_debugging,true
;	mov	portid,1
;	mov	portout,al
;	call	HexCharsOut
;;	mov	fserial_debugging,false
;ENDIF;	BUG

kybd_int_15_7:
;---------------------------------------------------------
; first check to see if the space saver keyboard is in use
;---------------------------------------------------------

	cmp	fspace_saver,true			; is flag set to indicate space saver ?
	jne	kybd_space_saver_end			; if not, exit to next check

kybd_space_saver_15_3:

	cmp	al,046h					; is space saver kybd, so check is this SCROLL LOCK make key ?
	jne	kybd_space_saver_15_5
	jmp	short kybd_space_saver_15_15

kybd_space_saver_15_5:

	cmp	al,0C6h					; is this SCROLL LOCK break key ?
	jne	kybd_space_saver_end			; if not, exit
	cmp	fscroll_changed,true			; did we previously detect shift+numlock ?
	jne	kybd_space_saver_end			; if not, exit
	mov	fscroll_changed,false			; reset flag
	mov	al,0C5h					; insert NUM LOCK break into "al" register instead of scroll lock break
	jmp	short kybd_space_saver_end

kybd_space_saver_15_15:

	cmp	fscroll_changed,true			; did we already change scroll lock to num lock and this is typematic
	jne	kybd_space_saver_15_25			; because if it is, it will also need to be changed, as StickyKeys would have cleared
							; the shift flag by now...If a person hold both keys down, we don't have a problem, since the
							; keyboard will then send a "45,C5", not a "46,C6" code

	jmp	short kybd_space_saver_15_30		; fscroill was set, so keep changing makes until we get a break


kybd_space_saver_15_25:

	push	es
	push	ax
	push	bx
	assume	ES:NOTHING
	mov	bx,RAMBIOS
	mov	es,bx
	ASSUME	ES:RAMBIOS
	mov	al,es:kb_flag
	test	al,03h					; is a shift key also down with the scroll lock ?
	jz	kybd_space_saver_15_50			; if not, cont
	mov	fscroll_changed,true			; if yes, set htis flag to catch on the scroll break
	pop	bx
	pop	ax
	pop	es
	assume ES:_TEXT

kybd_space_saver_15_30:

	mov	al,045h				      	; change al to NUM LOCK make
	jmp	short kybd_space_saver_end

kybd_space_saver_15_50:

	pop	bx
	pop	ax
	pop	es
	assume ES:_TEXT

kybd_space_saver_end:

;-----------------------------------------------------
; Next, need to check if we are in a control break condition
;-----------------------------------------------------

	cmp	fctrl_break_on,true			; was ctrl break flagged on previous int ?
	jne	kybd_int_15_13
	cmp	al,0c5h					; control break condition on, wait for "C5h" to clear
	jne	kybd_int_15_12				; if not "C5h" yet, jump to end

kybd_int_15_10:
; if we get here, we are looking for the "C5h" scan code only-last part of PAUSE key
; what ever is in "ax" register doesn't need to be saved, since we are throwing it away
	
	push	cx
	push	si
	push	ax
	xor	cx,cx
	xor	ax,ax
	mov	fkeys_injected,true			; set flag since we are going to put keys in the buffer

kybd_int_15_11:

	mov	cl,ctrl_break_buf_cnt
	mov	bx,offset ctrl_break_buf
	mov	si,cx
	mov	al,[bx+si]
	call	Put_Key_Data
	inc	ctrl_break_buf_cnt

	mov	al,ctrl_break_buf_cnt
	mov	bl,ctrl_break_buf_len
	cmp	al,bl
	jne	kybd_int_15_11

	mov	ctrl_break_buf_cnt,false		; reset buffer count
	mov	fkeys_injected,false			; buffer stuffed, turn off flag so timer can inject
	mov	fctrl_break_on,false			; if it is "C5h" jump to end

	pop	ax
	pop	si
	pop	cx

kybd_int_15_12:

	jmp	keybd_int_15_end     			; jump to end, since we ate a code

kybd_int_15_13:

;;----------------------------------------------------------------------------------------------------------------------
;; For this next routine, we need to check if we support Inject keys routine

	cmp	_finject_keys,true			; first check if we can inject ?
	je	kybd_win_15_5				; if we can inject, do next code which is based on the ability to INJECT

	jmp	kybd_win_end				; if we CAN NOT inject, cont. at _13

;-------------------------------------------------------------------------------------------
; THIS CODE ASSUMES THE KEYBOARD AND COMPUTER ACCEPT DIRECT INJECTION OF MOUSE AND KYBD CODES
;-------------------------------------------------------------------------------------------
;-------------------------------------------------------------------------------------------
; next check to see if we are running under Windows 3.0 in the enhanced mode only
;-------------------------------------------------------------------------------------------

kybd_win_15_5:


	cmp	fwindows_enh,true			; is windows running ?
	jne	kybd_win_end


kybd_win_15_7:

	cmp	al,01h					; did we read in an "ESC" key ?
	jne	kybd_win_15_10
 	jmp	short kybd_win_15_30			; was an "ESC" key make , check if "ALT" key down ?

kybd_win_15_10:

	cmp	al,081h					; is this the "ESC" break ?
	jne	kybd_win_end

kybd_win_15_20:						; was an "ESC" key break

	cmp	falt_esc,true
	jne	kybd_win_15_25
	mov	falt_esc_send,true
	mov	falt_esc,false
	jmp	short kybd_win_end

kybd_win_15_25:

	cmp	fctrl_esc,true
	jne	kybd_win_end
	mov	fctrl_esc_send,true
	mov	fctrl_esc,false
	jmp	short kybd_win_end

kybd_win_15_30:

	push	es
	push	ax
	push	bx
	assume	ES:NOTHING
	mov	bx,RAMBIOS
	mov	es,bx
	assume	ES:RAMBIOS
	mov	al,es:kb_flag
	test	al,08h
	jz	kybd_win_15_50

	mov	falt_esc,true
	jmp	short kybd_win_15_95

kybd_win_15_50:
	mov	falt_esc,false
	test	al,04h
	jz	kybd_win_15_60

	mov	fctrl_esc,true
	jmp	short kybd_win_15_95

kybd_win_15_60:

	mov	fctrl_esc,false

kybd_win_15_95:

	pop	bx
	pop	ax
	pop	es
	assume ES:_TEXT

kybd_win_end:

;;;----------------------------------------------------------------------------
;;; we do not want to have any of the routines that process key input have to
;;; deal with any of the commands that are specifc to the operation of the 
;;; keyboard, so we will pass them on directly to the BIOS routine since the
;;; original device driver routine also passed commands to the BIOS routine.
;;; See original BIOS of Tech. Ref. manuals for PC/PCXT/PCAT
;;;
;;	cmp	al,kybd_Command				; is it a command (0F0h)?
;;	jb	not_command_15				; no -->
;;	jmp	kybd_int_15_exit	  		; done -->
;;
;----------------------------------------------------------------------------
; we need to build up the two byte key codes if appropriate.

	cmp	al,kb_ext_code1				; is it a hidden code prefix e0?
	je	is_hidden_code_15			; yes, save -->
	cmp	al,kb_ext_code2				; is it a hidden code prefix e1?
	jne	not_hidden_code_15			; no, -->

is_hidden_code_15:

	mov	hidden_code,al				; yes, save

; at this point, we know we had a hidden code, so check for ctrl-break
; or alt-print screen for sysreq.

	push	es					; save es
	push	ax
	assume	ES:NOTHING
	mov	bx, RAMBIOS				; BIOS RAM segment at 40h
	mov	es,bx					;  .. point ES to that!
	assume	ES:RAMBIOS
	mov	al,es:kb_flag				; 

	cmp	hidden_code,0E1h			; is it "E1h" ?
	jne	kybd_int_15_20				; if not jump to check the "E0h" code

	test	al,04h
	jz	kybd_int_15_30				; if zero, the control key isn't pressed
	mov	fctrl_break_on,true			; set flag to tell us we have ctrl break condition
	mov	fpause_being_sent,false			; if control break, not a PAUSE
	jmp	short kybd_int_15_30


kybd_int_15_20:
; if it jumps here, we know we have a hidden code, and it must be "E0h" only, and all we want to check is if an alt. key is down

	test	al,08h
	jz	kybd_int_15_25				; if not set, jump out
	mov	fsysreq,true				; alt. key is down with "E0h" code, MAY have sys req. in progress
	jmp	short kybd_int_15_30

kybd_int_15_25:
	mov	fsysreq,false				; alt key not down with "E0h" code
kybd_int_15_30:

	pop	ax
	pop	es
	assume ES:_TEXT

kybd_int_15_35:

	cmp	fctrl_break_on,true			; are we in a ctrl break condition ???
	jne	kybd_int_15_45
	jmp	keybd_int_15_end 			; reset without any call to original BIOS

kybd_int_15_45:
	cmp	al,0E1h					; is this an E1h hidden code ?
	jne	kybd_int_15_46

	mov	fpause_being_sent,true			; if "E1h" unaltered, then PAUSE key is being sent, flag this so MouseKeys
							; doesn't turn off on the "45h" part of the scan code
							; will alway stay on unless MouseKeys is on, detects this, and clears it
							; or it is a computer which Injects, then it is turned off above kybd_int_20
kybd_int_15_46:	   

	jmp	kybd_int_15_exit 			; pass the E0 or E1 code

;------------------------------------------------------------
; now build up the code and pass to first one of the routines
;------------------------------------------------------------
; last check for alt-print screen for sysreq done here
;------------------------------------------------------------

not_hidden_code_15:

; int 15h with ah = 4fh will get burnt here, since ah is replaced with hidden code and passed thru AccessDos features
; appears not to bother int 15h, 4fh, unless DOS keyb.com is running, so I reworked this 
; code to maintain the "ah"=4fh ..........

	push	ax					; save al, ah =4fh 

	mov	ah,hidden_code				; get current hidden code value
	mov	hidden_code,0				; reset hidden code

; for passing thru keyboard features only

	cmp	fsysreq,true				; did we previously set this flag due to alt.+"E0h" code ?
	jne	kybd_int_15_48				; if not, cont.
; if yes, then we must watch for the "B7h" scan code which is PrtSc make code

	cmp	al,0B7h					; is this the "37h" key  scan code ?
	jne	kybd_int_15_48				; cont. on if not

; if we get here, it was "B7h" scan code, so we pass the last code and inject the SysReq codes (54/D4)

	push	ax
	mov	fkeys_injected,true			; set this flag to inject
	mov	al,054h					; SysReq make code
	call	Put_Key_Data
	mov	al,0D4h					; SysReq break code
	call	Put_Key_Data
	mov	fsysreq,false				; we've inject sysreq, so clear htis falg 
	pop	ax

;;	mov	fkeys_injected,false			; we are done stuffing buffer, so reset this flag to allow timer to inject
;;	jmp	short kybd_int_15_exit      		; exit

kybd_int_15_48:

; Now call Handicap routines.  We do not expect any registers to be
; the same.  So the routine does not need to save any.


	call	FilterKeys				; pass on extended code in AX

	pop	ax					; restore ah, and al, to code to be passed or eaten

	test	al,break_bit				; was this code a break code ?
	jz	kybd_int_15_48A				; it was a make scan code, check other condition 

	mov	fkeys_injected,false			; reset this flag if a break upon return
	jmp	short kybd_int_15_49			; 

kybd_int_15_48A:

	cmp	fSticKeysOn,true			; is StickeyKeys On ?
	je	kybd_int_15_48C				; 

	cmp	fint9_by_timer,true			; is this an injected scan code by the timer ?
	je	kybd_int_15_48C				; 
	cmp	al,46h
	je	kybd_int_15_48C				; 
	cmp	al,54h
	je	kybd_int_15_48C				; 
	jmp	short kybd_int_15_49			; if flag gets reset on a break, okay

kybd_int_15_48C:

	mov	fkeys_injected,false			; if yes, reset this flag also so buffer will empty makes/breaks

kybd_int_15_49:

	cmp	fbios_called_timing,true		; Does the timer want to let a key pass ? (FROM FILTERKEYS ONLY)
	jne	kybd_int_15_50

	cmp	fclick_on,true
	jne	kybd_int_15_49A

	cmp	fshift_click,true
	je	kybd_int_15_49A

	cmp	current_shift,0
	je	kybd_int_15_49B				; if not a modifier key, call click
	mov	fshift_click,true			; if we clicked once, set, as non-modifier will clear

kybd_int_15_49B:

	call	click

kybd_int_15_49A:

	mov	fbios_called_timing,false		; reset flag
	jmp	short kybd_int_15_exit			; and allow code to pass

kybd_int_15_50:

	cmp	fbios_called_direct,true  		; do we want to pass on the code ?
	jne	keybd_int_15_end 			; no, so end and eat the code
		
;-----------------------------------------
; jumps to here, if passing scan code on as is or what ever has been stored in the AL register

kybd_int_15_exit:

	mov	fserial_key_recieved,false		; reset flag for my code modules

;IFDEF	BUG
;;	mov	fserial_debugging,true
;	mov	portid,2
;	mov	portout,al
;	call	HexCharsOut
;;	mov	fserial_debugging,false
;ENDIF;	BUG

	pop	bx
	pop	es
	pop	ds
	assume	DS:NOTHING
	assume	ES:NOTHING

	stc
	jmp	dword ptr cs:old_kybd_int			; call old int 15 routine

;-----------------------------------------
; jumps to here if ate a code, if we eat code, return to int15 caller
; with ret 2, which in effect, through away flags on stack and allows
; our carry flag clear to return as it should

keybd_int_15_end:


	mov	fserial_key_recieved,false		; reset flag for my code modules

;;IFDEF	BUG
;;	mov	fserial_debugging,true
;;	mov	portid,3
;;	mov	portout,al
;;	call	HexCharsOut
;;	mov	fserial_debugging,false
;;ENDIF;	BUG

	pop	bx
	pop	es
	pop	ds

	assume	DS:NOTHING
	assume	ES:NOTHING

	clc
	ret	2

;-----------------------------------------
; jumps to here, if not int15h with Ah=4fh

not_kybd_int_15:

	jmp	dword ptr cs:old_kybd_int			; call old int 15 routine

_keybd_int_15	endp

;----------------------------------------------------------------------------
; keybd_int
;
; This is the beginning of the resident code of the routine which intercepts 
; the keyboard interrupt, int 9h.  This keyboard interrput routine should only load
; and run for IBM PC /PCXT/ PCAT Original 1/10/84 (i.e. 84 key keyboard) computers.
; Non of these computer should ever see a hidden code (i.e E0/E1), and non of these 
; computers support the Extended BIOS or kb_flags1/3 or hardware keyboard injection.  
;
; Since I know some PC/PCXT/PCAT users prefer 101 keyboard, and that these keyboards
; typically cheat by sending hidden codes for the extra keys expecting the BIOS 
; to straighten the situation out, I can easily send on any hidden codes straight to BIOS
; where the computer will ignore them, and this may allow our code to work on 
; these NASTY keyboards.
;-----------------------------------------------------------------------------
; NOTE: IF I get codes for 101 cursor keys like 2A 4D AA 2A CD AA for the --> key, 
; we will still have trouble since the extra 2A and AA look like shift keys to PC/PCXT/PCAT
; Original, since it never had cursor keys, and if it did have cursor keys, they should 
; send E0 2A E0 4D E0 CD E0 AA for the --> key, which would distinguish it correctly,
; and this code should handle by passing along to BIOS where the hidden codes would be ignored.
;-----------------------------------------------------------------------------

_keybd_int  PROC	


	push	ax
	mov	ax,1					; watch for myself to be re-entrant
	xchg	cs:fint9_active_temp,al			; flag that I'm in interrupt

	cmp	al,1					; which time are we ???
	je	kybd_int_3
	
	mov	cs:kybd_ss_save,ss
	mov	cs:kybd_sp_save,sp
	push	cs
	pop	ss
	mov	sp,offset kybd_Stack_top

kybd_int_3:

	push	ax					; save value of ax

	push	ds					; save the ds and ax
	push	ax
	push	bx
	push	es

	push	cs
	pop	ds
	assume DS:_TEXT
	push	cs
	pop	es
	assume ES:_TEXT

	call	TimeOut_Reset				; reset the time out count
	mov	fbios_called_direct,false
	mov	fmouse_or_kybd,true			; flag any int. callers, that kybd int. 9h executed

kybd_int_5:

	cmp	_comp_id,5				; do we have an AT class machine
	jne	kybd_int_8				; if not, cont.

	mov	al,dis_kbd				; if yes, disable keyboard
	call 	ship_it


kybd_int_8:
	
	in	al,kb_data				; read in data from keyboard port

;IFDEF	BUG
;	mov	portid,0
;	mov	portout,al
;	call	HexCharsOut
;ENDIF;	BUG

;----------------------------------------------------------------------------
; we do not want to have any of the routines that process key input have to
; deal with any of the commands that are specifc to the operation of the 
; keyboard, so we will pass them on directly to the BIOS routine since the
; original device driver routine also passed commands to the BIOS routine.
; See original BIOS of Tech. Ref. manuals for PC/PCXT/PCAT
;
	cmp	al,kybd_Command				; is it a command (0EDh)?
	jb	not_command				; no -->

kybd_int_10:

	pushf						; yes, call bios routine
	call	dword ptr cs:old_kybd_int
	jmp	keybd_int_ret				; done -->

not_command:
;----------------------------------------------------------------------------
; we need to pass on hidden key codes if appropriate.

	cmp	al,kb_ext_code1				; is it a hidden code prefix e0?
	je	is_hidden_code				; yes, eat-->
	cmp	al,kb_ext_code2				; is it a hidden code prefix e1?
	jne	not_hidden_code				; no, -->

is_hidden_code:

	mov	hidden_code,al	
	jmp	short kybd_int_10			; allow BIOS to deal with any hidden codes we may get


not_hidden_code:

; if the hidden code is not zero, then the previous scan code was either E0/E1 and something, which
; should not exist on these computers, so I will pass them along to the original BIOS and let it
; sort them out.

	mov	ah,hidden_code				; get previous hidden code if any ?
	mov	hidden_code,0				; reset for next key

	cmp	ah,0					; was there a previous hidden code ?
	je	kybd_int_20				; if not, we can cont.----else goto BIOS

; Before we send all E0 /E1 codes to BIOS, ....
; check for right alt. and ctrl. as these older computers shouldn't have these keys, but someone may
; use a 101 key keyboard on tis type of computer as the BIOS just treat the right alt. and ctrl. keys
; as the left alt. and ctrl. keys, as should I

	push	ax
	and	al,not break_bit			; be sure al is the make version of a make/break code
	cmp	al,38h					; an right alt. key ?
	jne	kybd_int_11
	jmp	short kybd_int_18

kybd_int_11:

	cmp	al,1dh					; an right ctrl. key ?
	jne	kybd_int_12
	jmp	short kybd_int_18

kybd_int_12:

	cmp	al,1ch					; an right enter key ?
	jne	kybd_int_15
	jmp	short kybd_int_18

kybd_int_15:
	pop	ax
	jmp	short kybd_int_10			; allow BIOS to deal with any codes

kybd_int_18:
	pop	ax

kybd_int_20:

; Now call Handicap routines.  We do not expect any registers to be
; the same.  So the routine does not need to save any.

;	sti

;IFDEF	BUG
;	mov	portid,0
;	mov	portout,ah
;	call	HexCharsOut
;	mov	portid,1
;	mov	portout,al
;	call	HexCharsOut
;ENDIF;	BUG

	call	FilterKeys				; pass on code in Al

; Disable int. and then re-enable keyboard INTs at the interrupt controller

	cli						; Ints off again. NOTE: don't need
							; to turn them back on because we are
							; going to to an IRET when we finish.

	cmp	fbios_called_direct,true  		; did we pass on to ROM routine?
	je	keybd_int_ret				; yes, so no need to reset it again
							; and no need to re-enable jeyboard as original
							; BIOS routine already did if it was supposed to

	cmp	fFilterKeysOn,true			; is FilterKeys on ???
	jne	keybd_int_end				; if not, this must have been a stickeys eat or something

	cmp	fbios_called_timing,true		; Does the timer want to let a key pass ? (FROM FILTERKEYS ONLY)
	jne	keybd_int_end				; if not, exit w/o out calling old int 9 kybd routine

kybd_int_25:

	cmp	fclick_on,true
	jne	kybd_int_40

	cmp	fshift_click,true
	je	kybd_int_40

	cmp	current_shift,0
	jne	kybd_int_40				; if not a modifier key, call click
	mov	fshift_click,true			; if we clicked once, set, as non-modifier will clear
	call	click

kybd_int_40:

	mov	fbios_called_timing,false		; reset flag
	mov	fkey_not_passed,false			; reset flag

	push	ds
	pushf
	call	dword ptr cs:old_kybd_int
	pop	ds

; any other clean up to do,like reset stickey flags ???

	cmp	fSticKeysOn,true
	jne	kybd_int_50
	cmp	flatch,true
	jne	kybd_int_50

	call	set_shift_states			; clear latched key(s) states
	mov	shift_flg,0				; clear shifted states

kybd_int_50:

	assume	ds:_TEXT
	jmp	keybd_int_ret		

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


keybd_int_end:

; If we get here, then we did a call to FilterKeys, StickeyKeys,.....and we DID NOT want to
; call the Original BIOS, so we need to reset the kybd hardware ourselves to allow 
; any other key strokes to generate interrupts.


;IFDEF	BUG
;	mov	portid,3
;	mov	portout,al
;	call	HexCharsOut
;ENDIF;	BUG


	in	al,kb_ctl				; reset interface chip (8042)
	mov	ah,al
	or	al,80h
	jmp	$ + 2					; jump delay for fast computers
	out	kb_ctl,al
	xchg	ah,al
	jmp	$ + 2					; jump delay for fast computers
	out	kb_ctl,al

	mov	al,020h					; acknowledge interrupt  (8259)
	jmp	$ + 2					; jump delay for fast computers
	out	ack_port,al

	cmp	_comp_id,5				; do we have an AT class machine
	jne	keybd_int_ret				; if not, cont.

	mov	al,ena_kbd				; if yes, disable keyboard
	call 	ship_it

keybd_int_ret:

;IFDEF	BUG
;	mov	portid,2
;	mov	portout,al
;	call	HexCharsOut
;ENDIF;	BUG

	pop	es

	assume	ES:NOTHING
	pop	bx
	pop	ax					; restore the world
	pop	ds

	assume	DS:NOTHING

	pop	ax					; save value of ax
	cmp	al,1					; which time are we ???
	je	kybd_int_ret_3

	mov	ss,cs:kybd_ss_save
	mov	sp,cs:kybd_sp_save
	mov	cs:fint9_active_temp,0			; clear my flag since I'm out finally

kybd_int_ret_3:

	pop	ax
	iret						; also clears any int. which were set

_keybd_int	endp

;;----------------------------------------------------------------------------
; speed_timer_int 
;
; increments the counts used in the time out and key delay repeat options for setting up
; the beep sounds on the various computers.  This routine is called during initialization only.


speed_timer_int	PROC

	push	ds
	push	cs
	pop	ds
	assume DS:_TEXT

	dec	count_down_ticks	; decrement the count

	pushf
	call	dword ptr cs:old_1C_int	; call original interrupt

	pop	ds
	assume	DS:NOTHING

	iret

speed_timer_int	endp

;----------------------------------------------------------------------------
;****************************************************************************
;----------------------------------------------------------------------------
; Enable_Handicap
;----------------------------------------------------------------------------
;****************************************************************************
;----------------------------------------------------------------------------

Enable	PROC	NEAR

	push	ds					; save registers used
	push	es
	push	si
	push	di
	push	dx
	push	cx
	push	bx
	push	ax

	assume DS:_TEXT

; reset key_data buffer to empty, i.e. point head and tail to the start of the buffer

	mov	bx,OFFSET key_data			; get address of key_data buffer
	mov	key_data_head,bx			; reset head pointer to start of buffer
	mov	key_data_tail,bx			; reset tail pointer to start of buffer

; reset mouse_data buffer to empty, i.e. point head and tail to the start of the buffer

	mov	bx,OFFSET mouse_data			; get address of mouse_data buffer
	mov	mouse_data_head,bx			; reset head pointer to start of buffer
	mov	mouse_data_tail,bx			; reset tail pointer to start of buffer
	mov	mouse_cnt,false				; 

	print	mesg60					; tell user we are loading


ena_2:

;------------------------------------------------------------------------------
; Enable serial port COMM 1/2 at 9600, n, 8, 1 if DEBUG is On
IFDEF	BUG

	cli
;	cmp	_comp_id,8				; am I on the PS2 Model 70 ?
;	je	com_set_20
	mov	dx,0   					; com1
	mov	ah,0					; init com port
	jmp	short com_set_30
;
;com_set_20:
;
;	mov	dx,1   					; com2
;	mov	ah,0					; init com port
;
com_set_30:

	mov	al,0e3h					; 9600 baud, 1 stop bit, no parity, 8 data bits
;	mov	al,043h					; 300 baud, 1 stop bit, no parity, 8 data bits

	int	14h

;	mov	fserial_debugging,true
	mov	al,_vector
	mov	portid,0fh
	mov	portout,al
	call	HexCharsOut
;	mov	fserial_debugging,false

	sti
ENDIF;BUG


;---------------------------------------------------------------------------
; Check if DOS version 3.0 or higher, so we know if we have support for DOS int2f

	mov	ah,30h					; call int21h with al=30h
	int	21h					; major version # in al, minor version # in ah
	cmp	al,3					; if 3 or higher, then int2f supported
	jge	ena_4
IFDEF	BUG
	print 	mesg45					; message that pre 3.0 version of DOS is running
ENDIF;	BUG
	jmp	short ena_10


ena_4:
;IFDEF	BUG
;	print	mesg46					; running DOS 3.0 or higher
;ENDIF;	BUG

;---------------------------------------------------------------------------
; check if AccesDos was started under Windows 3.0 in real, standard or enhanced mode ?

	mov	ax,1600h				; code to ask Windows if running enhanced ?
	int	2fh					; DOS int call
	test	al,7fh					; if al=0 or 80h, then Windows enhanced in NOT running
	jz	ena_5					; if jump, enhanced not running, go check if real or standard ?

	assume	DS:_TEXT

	mov	fwindows,true				; flag set true if we are in Windows
	mov	fwindows_enh,true			; flag that we are in Windows enhanced mode
	mov	fwindows_st_re,false

;IFDEF	BUG
;	print	mesg41					; tell users program started under Windows Enhanced
;ENDIF;	BUG

	jmp	short ena_10				; no need to hook int2f if ADOS started after Windows

ena_5:

	mov	ax,4680h				; code to ask Windows if real or standard
	int	2fh					; DOS int call
	cmp	ax,0					; if ax=0, then real or standard Windows is running
	jne	ena_8					; if not, running Windows, hook int 2fh incase 

	assume	DS:_TEXT							; Windows is started after us

	mov	fwindows,true				; if ax=0, then we are in real or standard mode
	mov	fwindows_st_re,true			; flag that we are in Windows standard or real mode
	mov	fwindows_enh,false


;IFDEF	BUG
;	print	mesg42					; tell user
;ENDIF;	BUG
	jmp	short ena_10				; no need to hook int2f if ADOS started after Windows
ena_8:

;-----------------------------------------------------------------------------
; get INT 2Fh vector and save away
; Need to hook into int2Fh to watch if Windows is loaded after Access Dos
    				
	assume ES:NOTHING
	mov	ax,352fh
	int	21h
	mov	word ptr [old_2f_int_off],bx
	mov	word ptr [old_2f_int_seg],es

;-----------------------------------------------------------------------------
; get INT 2fh vector and save away

	push	ds					; SAVE DS for restore
	mov	ax,cs
	mov	ds,ax
	mov	dx,OFFSET _int2f			; hook int. 2fh also
	mov	ax,252fh
	int	21h
	pop	ds

ena_10:

;-----------------------------------------------------------------------------
	cmp	_vector,09				; do we hook int 9 or int 15
	jne	ena_10A

	mov	ax,3509h				; get INT 09h vector and save away
	jmp	short ena_10B

ena_10A:

	mov	ax,3515h				; get INT 15h vector and save away
ena_10B:
	
	int	21h
	mov	word ptr [old_kybd_int_off],bx
	mov	word ptr [old_kybd_int_seg],es

;----------------------------------------------------------------------------
; Setup timer interrupt vector to point to our interrupt routine
; get INT 1Ch vector and save away in old_timer_int this time
; NOTE: Original timer 08h must have been previously restored above.

	assume ES:NOTHING
	mov	ax,351Ch
	int	21h
	mov	word ptr [old_1C_int_off],bx
	mov	word ptr [old_1C_int_seg],es

;----------------------------------------------------------------------------
; Setup timer interrupt vector to point to our speed timer interrupt routine

	push	ds				; SAVE DS for restore
	mov	ax,cs
	mov	ds,ax
	mov	dx,OFFSET speed_timer_int
	mov	ax,251Ch
	int	21h				; set the vector
	pop	ds

	xor	ax,ax
	mov	count_down_ticks,2
;
; The way we will do this is to simulate the exact same set of code that
; is our beep routine.  There will be some overhead, but hopefully it will
; not factor into the accuracy that much.  We will keep track of how many
; times we will be able to get through the beep routine before we
; get through 1 tick of the real time timer.

ena11:

	cmp	count_down_ticks,1
	jg	ena11
;
; 46h is the value for a 2000hz square wave running on a PC.  Therefore,
; there would be about 110 cycles within the 18.2 clock (54.95ms).
; If we do 5 cycles, then the count in AX would be 22.  Assume that a fast
; 386 machine running at 25Mhz is about 15 times faster than a PC so AX
; in the upper range would be 330.
;

	cmp	fwindows,true
	jne	ena12			; if Windows isn't running, don't need cli
	cli

ena12:
	mov	cx,46h			; test tone, length of square cycle
	mov	bx,5			; length of test tone

	push	ax			; save ax, count
	IN	al,kb_ctl		; get keyboard control
	push	ax			; save
	push	cx			; save cx=wave length
ena13:	
	and	al,0ffh			; set speaker bits, really don't
	OUT	kb_ctl,al		; send out to speaker
	pop	cx			; get cx=wave length
	push	cx			; save cx
ena14:	
	loop	ena14			; keep on for wave length of time
	or	al,0			; set speaker bit, really don't
	OUT	kb_ctl,al		; send out to speaker
	pop	cx			; get cx
	push	cx			; save cx
ena15:	
	loop	ena15			; keep off for wave length of time
	dec	bx			; decrement length of tone
	jnz	ena13			; loop if not zero

	pop	cx			; restore cx
	pop	ax			; get old keyboard control
	OUT	kb_ctl,al		; send out
	pop	ax			; restore old ax


	sti
;
; Now keep track of count
;

	inc	ax			; increment count

	cmp	count_down_ticks,0	; are we done?
;;	ja	ena12			; no
	jg	ena12			; if count_down_ticks is >= to zero,loop again
					; make this a signed check so if we miss it, FFFF
					; is -1, and we will pass
;--------------------------------------------------------------------------------
; for some unknown reason, if running under Windows, especially enhanced mode, the DOS
; timer doesn't seem to handle the speed timer routine correctly all the time, so we will
; check the "ax" register value here to see if it messed up

	cmp	fwindows,true		; did we find out earlier that Window is running ?
	jne	ena_20
	cmp	ax,80			; Low end 8/10 Mhz Model 50/60 value we might expect for Windows
	jg	ena_20			; if ax from speed loop is higher, don't change
	mov	ax,150			; otherwise override Windows loop to 150 decimal

ena_20:
; for a 4.77 MHz PC, the count in ax should be about 22
; for a 16   MHz PC, the count in ax should be about 165
; for a 25   MHz PC, the count in ax should be about 330

	mov	cx,ax			; save a copy in cx
	mov	ax,46h			; put tone value in ax
	mul	cx			; multiply by number of times through
	mov	bx,22			; normalize to standard pc
	div	bx

	mov	high_tone,ax

	mov	turn_off_start_beep,ax

	shl	ax,1			; multiply by 2 to get 1000hz
	mov	turn_on_start_beep,ax

	shl	ax,1			; multiply by 2 to get 500hz
	mov	low_tone,ax

	mov	ax,turn_on_start_beep		; get 1000hz back
	sub	ax,turn_off_start_beep		; get difference

	mov	bx,100				; 100 steps
	xor	dx,dx
	div	bx

	mov	on_off_change,ax

	cmp	ax,00				; did on_off_change crank out to be ZERO ??
	jne	ena25				; if not, things should be okay, so cont

	mov	on_off_change,1			; if it was ZERO, very slow computer, so override prev. calc.

ena25:

;-----------------------------------------------------------------------------
	cmp	fmouse_driver,false
	je	ena_100				; if we didn't find a mouse, do not need to hook into any of these

;-----------------------------------------------------------------------------
; get INT 33h vector and save away
; Need to hook into int33h for either serial or PS/2 mouse

	assume ES:NOTHING
	mov	ax,3533h
	int	21h
	mov	word ptr [old_33_int_off],bx
	mov	word ptr [old_33_int_seg],es

;-----------------------------------------------------------------------------
; PS/2 MOUSE
;
; If we get here, we found a PS/2 mouse, so we need to check which computer we are on

	assume ES:NOTHING

	cmp	_comp_id,6			; Int 71h is for computer id=6, 25..30/86
	jne	ena_70				; if not equal, jump to other PS/2 mouse int

	mov	ax,3571h			; get INT 71h vector and save away
	jmp	short ena_75
ena_70:
						; If we get here, then we should have computer id = 7 or 8
	mov	ax,3574h			; get INT 74h vector and save away
ena_75:

	int	21h
	mov	word ptr [old_ps2mou_int_off],bx
	mov	word ptr [old_ps2mou_int_seg],es

ena_100:

;-------------------------------------------------------------------------------------
; Setup kybd interrupt vector to point to our interrupt routine

	cmp	_vector,09h				; do we hook int9 or int 15 ?
	jne	ena_102

	push	ds					; SAVE DS for restore
	mov	ax,cs
	mov	ds,ax
	mov	dx,OFFSET _keybd_int			; hook into int. 09h, keyboard
	mov	ax,2509h
	int	21h					; set the vector
	pop	ds
	jmp	short ena_103

ena_102:
	push	ds					; SAVE DS for restore
	mov	ax,cs
	mov	ds,ax
	mov	dx,OFFSET _keybd_int_15			; hook into int. 15h of the keyboard interrupt
	mov	ax,2515h
	int	21h					; set the vector
	pop	ds

ena_103:

; if not on during a call to Enable, serialkeys will not be loaded, so we don'y have to check the other flags

	cmp	_serialKeysOn,true			; is SerialKeys code on ?
	jne	ena_104

	push	ds
;	call	_serialKeysInit     			; initialize serial keys
	call	_serialKeysEnableFar
	pop	ds


ena_104:
;-------------------------------------------------------------------------------------
; Setup 1C timer interrupt vector to point to our interrupt routine

	push	ds					; SAVE DS for restore
	mov	ax,cs
	mov	ds,ax
	mov	dx,OFFSET _new_timer_int		; hook into int. 1Ch, timer
	mov	ax,251Ch
	int	21h					; set the vector
	pop	ds

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

	cmp	fmouse_driver,false			; did we load a mouse driver ???
	je	ena_200					; if not, quit

;---------------------------------------------------------------------------------------
; Setup interrupt 33h vector to point to our interrupt routine. we need int33h for either serial or PS/2 mouse

	push	ds					; SAVE DS for restore
	mov	ax,cs
	mov	ds,ax
	mov	dx,OFFSET _int33			; hook int. 33h also
	mov	ax,2533h
	int	21h
	pop	ds

;-----------------------------------------------------------------------------
; get INT 71h vector and save away
; If we get here, we found a PS/2 mouse, so we need to check which computer we are on

	cmp	_comp_id,6				; Int 71h is for computer id=6, 25..30/86
	jne	ena_140					; if not equal, jump to other PS/2 int

	push	ds					; SAVE DS for restore
	mov	ax,cs
	mov	ds,ax
	mov	dx,OFFSET _intps2mou			; hook int. 71h also
	mov	ax,2571h
	int	21h
	pop	ds
	jmp	ena_200				

ena_140:
;-----------------------------------------------------------------------------
; get INT 74h vector and save away
; If we get here, then we should have computer id = 7 or 8

	push	ds					; SAVE DS for restore
	mov	ax,cs
	mov	ds,ax
	mov	dx,OFFSET _intps2mou			; hook int. 74h also
	mov	ax,2574h
	int	21h
	pop	ds

ena_200:

	pop	ax
	pop	bx					; restore registers
	pop	cx
	pop	dx
	pop	di
	pop	si
	pop	es
	pop	ds

	ret	


Enable	endp

_TEXT	ends

	end




标签:handicap,mov,al,int,kybd,ax,DOS,asm,cmp
来源: https://blog.csdn.net/u25th_engineer/article/details/120573656

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有