;
; scancode.asm - display key scan codes.
;
; Jason Hood, 4 & 5 June, 1998.
; Public Domain.
;
; 13 July, 1998: rewrote using the Int15 intercept function;
;		 used LeftShift-LeftCtrl-Esc to exit.
; 30 November, 1998: "b" option to display break codes as well.
;
; 14 October, 2003, v1.00:
;   just use either Shift with Esc to exit.
;


	.model tiny
	.code
	org 100h


LEFTSHIFT  equ	2ah
RIGHTSHIFT equ	36h
ESCAPE	   equ	01h
RELEASED   equ	

esc_on	   equ	01b
shift_on   equ	10b
esc_off    equ	
shift_off  equ	
exit_state equ	esc_on or shift_on


begin:
	jmp	start
	db	8, 8, 8
helpmsg db	'Scancode by Jason Hood .',13,10
	db	'Version 1.00 (14 October, 2003). Public Domain.',13,10
	db	'http://misc.adoxa.cjb.net/',13,10
	db	13,10
	db	'Display the hexadecimal scancode of each key pressed.',13,10
	db	'Add a "b" argument to display the release (break) code.',13,10
	db	26, 8, ' $'

help:
	mov	dx, offset helpmsg
	mov	ah, 9
	int	21h
	ret

start:
	cmp	word ptr [ds:81h],'?/'
	je	help
	cmp	word ptr [ds:82h],'?/'  ;Assume a space before it
	je	help

	mov	dx,offset intro		;Display an introductory message
	mov	ah,9
	int	21h

	mov	ax,3515h		;Get the original Int15
	int	21h
	mov	word ptr int15,bx	;Preserve it
	mov	word ptr int15+2,es

	mov	dx,offset scancode	;Point to my new one
	mov	ax,2515h		;Set it
	int	21h

	cmp	word ptr ds:[81h], 'b ' ;Scancodes only? (include space to
	jne	continue		; prevent garbage from previous
	inc	break			; execution)

continue:				;Wait for termination
	cmp	done,exit_state
	jne	continue

	lds	dx,int15		;Point to the original Int15
	mov	ax,2515h		;Restore it
	int	21h

	mov	dl,10			;Add a blank line (DOS does the CR)
	call	print_char

	ret				;Finished


intro	db	'Press Shift+Esc to exit.'
	db	13, 10, 10, '$'

int15	dd	0			;Original Int15 vector
done	db	0			;Termination flag
break	db	0			;1 to display break codes

prefix	 db	0			;For the E0 and E1 prefixed codes
old_code dw	0			;Prevent repeat


scancode proc far
	pushf
	sti				;Okay to interrupt
	cmp	ah,4fh			;Intercept function?
	je	okay
	popf
	jmp	cs:[int15]
okay:
	push	ax dx
	xor	ah,ah
	xchg	cs:prefix,ah
	or	ah,ah			;Have we seen a prefix?
	jne	prefixed_code		;Yes
	cmp	al,0e0h 		;Test for prefix
	je	prefix_found
	cmp	al,0e1h 		;Second prefix (Pause only)
	jne	no_prefix
prefix_found:
	mov	cs:prefix,al		;Remember the prefix
	jmp	short exit		; and get out
no_prefix:
prefixed_code:
	cmp	ax,cs:old_code		;Same as the previous key?
	je	exit			;Yep, get out
	mov	cs:old_code,ax
test_escape:				;Test for certain keys
	cmp	ax,ESCAPE
	jne	test_shift
	or	cs:done,esc_on
	jmp	short print_code
test_shift:
	cmp	ax,LEFTSHIFT
	je	shift_pressed
	cmp	ax,RIGHTSHIFT
	jne	test_esc_release
shift_pressed:
	or	cs:done,shift_on
	jmp	short print_code
test_esc_release:
	cmp	ax,ESCAPE RELEASED
	jne	test_shift_release
	and	cs:done,esc_off
	jmp	short print_code
test_shift_release:
	cmp	ax,LEFTSHIFT RELEASED
	je	shift_released
	cmp	ax,RIGHTSHIFT RELEASED
	jne	print_code
shift_released:
	and	cs:done,shift_off

print_code:
	cmp	cs:break,0
	jne	display_all
	test	al,80h			;Is it a break code?
	jnz	exit			;Yes, don't display it
display_all:
	call	ax2hex			;Display the scancode
	mov	dl,' '                  ; and separate codes with a space
	call	print_char
exit:
	pop	dx ax
	popf
	clc				;Ignore the key
	ret	2			; and the interrupted flags
scancode endp


ax2hex proc near
	or	ah,ah			;If there's no prefix...
	jnz	ah2hex
	push	ax
	mov	dl,' '                  ;...just display spaces
	call	print_char
	int	21h
	pop	ax
	jmp	short al2hex
ah2hex:
	push	ax
	mov	al,ah
	call	al2hex
	pop	ax

al2hex:
	push	ax
	shr	al,4			;High nibble first
	call	nibble
	pop	ax
	and	al,0fh			;Low nibble second

nibble:
	cmp	al,0ah			;From Programming Tips & Tricks
	sbb	al,69h			; Issue 1, "Binary to Hex Conversion"
	das				; by Tenie Remmel
	mov	dl,al

print_char label near
	mov	ah,2			;DOS service display char in DL
	int	21h
	ret
ax2hex endp


end	begin

    Source: geocities.com/jadoxa/misc

               ( geocities.com/jadoxa)