code	segment	byte	public
	assume	cs:code

	public	SetKeyVector,RestoreKeyVector,Ext_Keyboard_Present

;_______________________________________________________________

SetKeyVector	proc	far
; Install new interrupt vector
;First get old INT 16h vector
	mov	ah,35h		; get interrupt vector into ES:BX
	mov	al,16h		; vector to get
	int	21h			; DOS call

; now store the old vector

	mov	ax,es		; vector segment
	mov	cs:vectseg,ax	; store it
	mov	cs:vectofs,bx	; store vector offset

; get address of the new interrupt handler and set the INT 16h vector

	push	ds			; save data segment
	mov	ax,cs
	mov	ds,ax			; set current segment
	mov	dx,offset newkey
	mov	ah,25h			; set interrupt vector
	mov	al,16h			; vector to set
	int	21h
	pop	ds

; Temporary storage for old interrupt vector in the code segment

vectofs	dw	0
vectseg	dw	0
; First check the function number to see if its one of the ones we want
; to operate on i.e. functions 0, 1 and 2. The function no is in AH. If
; not we pass control to the old INT 16h vector.

newkey:
	push	ds			; store data segment
	push	ax			; keep function params

	sti					; restart interrupts

	cmp	ah,03h			; check function
	jae	oldvect			; if ah>=3 then call the old vector

; Function must be one of 0, 1 or 2 so we use the new routine below. First
; test for enhanced keyboard by checking the flag in the BIOS data area.

	mov	ax,0040h		; BIOS data segment
	mov	ds,ax
	mov	al,byte ptr ds:[0096h]	; get keyboard state flags
	and	al,10h			; must be old keyboard so transfer
	jz	oldvect			; control to old routine

; If we get here the machine has probably got an enhanced keyboard
; so add 10h to the BIOS function number and call the old vector

newcall:	pop	ax		; get old function no
	add	ah,10h			; modify function no
	cmp	ah,12h			; function 12h ?
	je	ovect2			; use enhanced function

; At this point the function must have been 0 or 1 so start by calling
; the old INT 16h routine with the modified function no. We simulate an
; INT intstruction a long call to the original vector.

	cli
	pushf				; simulate interrupt
	call	dword ptr cs:[vectofs]	; do INT 16h !

; Set up a stack frame using BP so we can access the flags that were pushed
; on to the stack by the calling INT instruction.

	push	bp			; save base pointer
	mov	bp,sp			; set up stack frame
	push ax				; save AX temporarily
	pushf				; save result flags

	pop	ax				; get flags into AX
	mov	word ptr [bp+8],ax		; replace stacked interrupt flags

	pop	ax				; restore AX
	pop	bp				; restore base pointer

; If the extended function returns the value 244 decimal in AL then a special
; function key has been pressed (like PgUp etc) so we must modify this result
; appropriately by returning zero in AL if neccessary.

	cmp	al,224			; special key ?
	jne	exit			; no so quit
	cmp	ah,0			; fix for special keys
	je	exit
	mov	al,0
exit:
	pop	ds				; restore from stack

	sti					; restart interrupts
	iret				; end of interrupt

oldvect:	pop	ax		; pop function number

ovect2:	cli				; disable interrupts
	pop	ds				; restore data segment
	jmp	dword ptr cs:[vectofs]	; jump to old vector

SetKeyVector	endp
;_____________________________________________________________________________
RestoreKeyVector	proc	far

; procedure to restore original interrupt vector

	push	ds
	mov	ax,seg SetKeyVector
	mov	ds,ax
	mov	dx,vectofs
	mov	ax,vectseg		; get old vector
	mov	ds,ax
	mov	ah,25h			; set interrupt vector
	mov	al,16h			; interrupt number
	int	21h				; DOS call
	pop	ds

	ret

RestoreKeyVector	endp
;______________________________________________________________________________
Ext_Keyboard_Present	proc	far
; Returns boolean flag to indicate presence on enhanced keyboard. If Al=0
; on return then the enhanced keyboard is not present. If Al=1, it is.

	push	es
	mov	ax,0040h		; BIOS data segment
	mov	es,ax
	mov	al,byte ptr es:[0096h]	; get keyboard state flags
	pop	es
	and	al,10h			; mask enhanced flag
	jz	fin				; must be old keyboard
	mov	al,1
fin:	ret

Ext_Keyboard_Present	endp

code	ends

	end
