;-----------------------------------------------------------------------
; Alternate Multiplex Interrupt Specification Library
; AMISHOTK.ASM	Public Domain 1992,1995 Ralf Brown
;		You may do with this software whatever you want, but
;		common courtesy dictates that you not remove my name
;		from it.
;
; Version 0.92
; LastEdit: 9/24/95
;-----------------------------------------------------------------------

	INCLUDE AMIS.MAC

_TEXT SEGMENT PUBLIC BYTE 'CODE'
	ASSUME	CS:_TEXT

;-----------------------------------------------------------------------
; entry: AX,CX = required shift states for two TSRs
; exit:	 AX,CX adjusted
;
fix_multishifts proc near
	xchg	cx,ax
	call	fix_multishifts_0
	xchg	cx,ax
	;; fall through
fix_multishifts_0:
	test	ax,HK_ANYSHIFT
	jz	fms_1
	test	cx,HK_LSHIFT or HK_RSHIFT
	jz	fms_1
	and	ax,not HK_ANYSHIFT
fms_1:
	test	ax,HK_ANYCTRL
	jz	fms_2
	test	cx,HK_LCTRL or HK_RCTRL
	jz	fms_2
	and	ax,not HK_ANYCTRL
fms_2:
	test	ax,HK_ANYALT
	jz	fms_3
	test	cx,HK_LALT or HK_RALT
	jz	fms_3
	and	ax,not HK_ANYALT
fms_3:
	ret
fix_multishifts endp

;-----------------------------------------------------------------------
; entry: DS:SI -> hotkey list of already-installed TSR
;	 ES:DI -> hotkey list of current TSR
; exit:	 AX = conflict flags (see below)
;
check_hotkey_conflict proc near
	push	bp
	push	si
	xor	bp,bp			; no conflicts yet
	cld				; string operations move up in memory
	inc	si
	mov	cl,[si]			; number of hotkeys to check
	or	cl,cl			; any hotkeys?
	jz	chc_done
	inc	si			; skip list header
chc_loop:
	push	di
	inc	di
	mov	ch,es:[di]		; number of hotkeys in list
					; we already know this number is nonzero
	inc	di			; skip list header
chc_inner_loop:
	push	cx
	cmpsb				; check if scan codes the same
	jne	chc_inner_next		; skip if scan codes different
	mov	ax,[si]
	mov	bx,[si+2]
	mov	cx,es:[di]		; get required shift states
	mov	dx,es:[di+2]		; get disallowed shift states
	;
	; first, check for an exact match
	;
	cmp	cx,ax
	jne	chc_maybe_superset
	cmp	dx,bx
	jne	chc_maybe_superset
	mov	ax,HC_EXACT
	jmp short chc_set_conflict_flag
chc_maybe_superset:
	; superset if we require more shift states than the other one does
	; or if the other one has more disallowed shift states
	;
	; need special cases for either-shift vs one-shift, same for Ctrl,Alt
	;
	call	fix_multishifts
	;
	; after the preceding adjustments, check the bits
	;
	push	ax			; preserve AX
	not	ax
	test	ax,cx			; states not present in other?
	pop	ax			; restore AX
	jz	chc_maybe_superset_2
	push	dx			; preserve DX
	not	dx
	test	dx,bx			; states not present in ours?
	pop	dx			; restore DX
	jz	chc_maybe_subset
	;
	; now make sure it is a superset by doing the test the other way around
	;
chc_maybe_superset_2:
	not	cx
	test	cx,ax			; states not present in ours?
	jnz	chc_inner_next		; if yes, not a superset
	not	bx
	test	bx,dx			; states not present in other?
	jnz	chc_inner_next		; if yes, not a superset
	mov	ax,HC_SUPERSET
	jmp short chc_set_conflict_flag
chc_maybe_subset:
	; subset if we require fewer shift states than the other one does
	; or if we have more disallowed shift states
	;
	not	cx
	test	cx,ax			; states not present in ours?
	jz	chc_is_subset
	not	bx
	test	bx,dx			; states not present in other?
	jz	chc_inner_next
chc_is_subset:
	mov	ax,HC_SUBSET
chc_set_conflict_flag:
	test	byte ptr [si+4],HK_MONITOR
	jz	chc_set_flag
	test	byte ptr es:[di+4],HK_CHAINBEFORE or HK_CHAINAFTER
	jz	chc_set_flag
	mov	ax,HC_MONITOR		; no actual conflict, but let caller know
chc_set_flag:
	or	bp,ax
chc_inner_next:
	pop	cx
	add	di,5			; move to next hotkey record
	dec	ch
	jnz	chc_inner_loop
	pop	di
	add	si,5			; move to next hotkey record
	dec	cl
	jnz	chc_loop
chc_done:
	mov	ax,bp			; AX <- conflict flags
	pop	si
	pop	bp
	ret
check_hotkey_conflict endp

;-----------------------------------------------------------------------
; entry: DX:AX -> hotkey list
; exit:  ZF set if no hotkey conflicts
;	 ZF clear if hotkey conflict
;	 AX = type of conflicts
;		bit 0: one or more exact keys already in use
;		bit 1: one or more superset keys already in use
;		bit 2: one or more subset keys already in use
;		bit 7: some other TSR is monitors one of our passed-thru keys
;
public check_if_hotkeys_used
check_if_hotkeys_used proc DIST
	push	bp
	xor	bp,bp			; conflict flags; no conflicts yet
	push	es
	push	di
	mov	es,dx
	mov	di,ax
	cmp	byte ptr es:[di+1],0	; does this TSR have any hotkeys?
	je	cihu_done		; if not, no conflicts
	push	ds
	push	si
	mov	ah,0
check_hotkeys_loop:
	push	ax			; save multiplex number
	mov	al,0
	push	di
	int	2Dh
	pop	di
	cmp	al,AMIS_SUCCESSFUL
	jne	cihu_next
	pop	ax
	push	ax
	mov	al,5			; function "get hotkeys"
	int	2Dh
	cmp	al,AMIS_SUCCESSFUL
	jne	cihu_next
	mov	ds,dx
	mov	si,bx
	call	check_hotkey_conflict
	or	bp,ax			; add any conflicts to conflict flags
cihu_next:
	pop	ax			; get back multiplex number
	inc	ah
	jne	check_hotkeys_loop
	pop	si
	pop	ds
cihu_done:
	pop	di
	pop	es
	mov	ax,bp			; AX <- conflict flags
	pop	bp
	test	ax,HC_IS_CONFLICT	; set ZF if no conflicts
	ret
check_if_hotkeys_used endp


_TEXT ENDS
	END
