.386
.MODEL flat, stdcall

Beep PROTO STDCALL :DWORD,:DWORD

GetStdHandle PROTO STDCALL :DWORD

WriteConsoleA PROTO STDCALL :DWORD,:DWORD,:DWORD,:DWORD,:DWORD
	;_In_             HANDLE  hConsoleOutput,
	;_In_       const VOID    *lpBuffer,
	;_In_             DWORD   nNumberOfCharsToWrite,
	;_Out_opt_        LPDWORD lpNumberOfCharsWritten,
	;_Reserved_       LPVOID  lpReserved

ReadConsoleInputA PROTO STDCALL :DWORD,:DWORD,:DWORD,:DWORD
	;_In_  HANDLE        hConsoleInput,
	;_Out_ PINPUT_RECORD lpBuffer,
	;_In_  DWORD         nLength,
	;_Out_ LPDWORD       lpNumberOfEventsRead

GetNumberOfConsoleInputEvents PROTO STDCALL :DWORD,:DWORD
	;_In_  HANDLE  hConsoleInput,
	;_Out_ LPDWORD lpcNumberOfEvents

SetConsoleMode PROTO STDCALL :DWORD,:DWORD
	;_In_ HANDLE hConsoleHandle,
	;_In_ DWORD  dwMode

TIMEOFNOTE EQU 48

.DATA
	HANDLE DWORD ?
	HANDLEIN DWORD ?
	LEN DWORD ?
	BUFFER BYTE 32 DUP(?)
	READLEN DWORD ?
	
	TITLEVAR BYTE 1BH, "]0;PIANO", 07H, 1BH, "[1;96m"	;TITLE + SET TO BLUE
	SCALE DWORD 33, 37, 41, 44, 49, 55, 62, 66
	KEYS BYTE "Z", "X", "C", "V", "B", "N", "M", "L"
	SHIFT BYTE 04

.CODE
START:
	;GET CONSOLE (OUT):
	PUSH -11	;get STD_OUTPUT_HANDLE 
	CALL GetStdHandle	;RETURNS IN EAX
	MOV HANDLE, EAX
	;GET CONSOLE (IN):
	PUSH -10	;get STD_INPUT_HANDLE 
	CALL GetStdHandle	;RETURNS IN EAX
	MOV HANDLEIN, EAX

	;SET CONSOLE MODE ENSURING ANSI INPUT IS ALLOWED
	MOV EAX, 05H	;ENABLE VIRTUAL TERMINAL
	PUSH EAX
	PUSH HANDLE
	CALL SetConsoleMode

	;SET CONSOLE TITLE & CURSOR OFF WITHT ANSI STRING
	LEA EAX, [TITLEVAR]
	MOV LEN, 17
	CALL WRITEBUFFER

	MOV BUFFER, 40H
	LEA EAX, [BUFFER]
	MOV LEN, 1
	CALL WRITEBUFFER
	
	;READ
	WAITFORKEY:
	CALL READKEY
	CMP AL, 00H	;NO KEYS DOWN
	JE WAITFORKEY

	MOV EBX, OFFSET KEYS
	MOV ECX, SIZEOF KEYS
	CMPKEY:
		CMP AL, [EBX]
		JNZ NOHIT
	HIT:
		MOV [BUFFER], AL
		LEA EAX, [BUFFER]
			PUSH EBX
		CALL WRITEBUFFER
			POP EBX
		SUB EBX, OFFSET KEYS
		SHL EBX, 02H
		MOV EDX, OFFSET SCALE
		ADD EDX, EBX
		JMP NOTE
	NOHIT:
		;CHECK UP DOWN SCALE
			CMP AL, 38	;UP ARROW
			JNE CHECKDOWN
			INC SHIFT
			JMP WAITFORKEY
		CHECKDOWN:
			CMP AL, 40	;DOWN ARROW
			JNE NEXT
			DEC SHIFT
			JMP WAITFORKEY
	NEXT:
		INC EBX
		LOOP CMPKEY
	JMP WAITFORKEY

	NOTE:
		MOV EAX, [EDX]
		MOV CL, SHIFT
		SHL EAX, CL
		PUSH TIMEOFNOTE
		PUSH EAX
		CALL Beep	
	JMP WAITFORKEY

;KERNEL32 FUNCTIONS:
WRITEBUFFER PROC	;STRING PNTR STORED IN EAX AND LENGTH TO WRITE IN LEN
	PUSH 0
	PUSH 0
	PUSH LEN
	PUSH EAX
	PUSH HANDLE
	CALL WriteConsoleA
	RET
WRITEBUFFER ENDP

READKEY PROC
	;CHECK IF THERE ARE EVENTS TO BE READ:
	LEA EAX, [READLEN]
	PUSH EAX
	PUSH HANDLEIN
	CALL GetNumberOfConsoleInputEvents
	MOV EAX, READLEN
	CMP EAX, 00H
	JE ENDREADKEY

	;READ EVENTS:
	LEA EBX, [BUFFER]
	LEA EAX, [READLEN]
	PUSH EAX
	PUSH 1
	PUSH EBX
	PUSH HANDLEIN
	CALL ReadConsoleInputA
	MOV EAX, READLEN
	CMP EAX, 00H
	JE ENDREADKEY
	MOV AL, BUFFER
		;EVENT TYPE:
		CMP AL, 01H	;KEY_EVENT_RECORD
		JE CHECKKEYDOWN
		XOR EAX, EAX
		JMP ENDREADKEY
			CHECKKEYDOWN:
			;LOAD KEY:
			;CHECK IF HELD DOWN
			MOV AL, [BUFFER+4]
			CMP AL, 00
			JE ENDREADKEY
			;GET KEY CODE
			MOV AL, BUFFER+10
	ENDREADKEY:
	RET
READKEY ENDP

END START