; ****************************************************************************
;
;                                   Keyboard
;
; ****************************************************************************

#include "include.inc"

	.text

; keyboard character map
.global KeyMap
KeyMap:
	.byte	0x6c		; CH_HOME	0x01	// key Home
	.byte	0x6b		; CH_LEFT	0x02	// key Left
	.byte	0x77+0x80	; CH_BREAK	0x03	// key Shift+Break
	.byte	0x5a+0x80	; CH_LINE	0x04	// key Shift+Enter
	.byte	0x69		; CH_END	0x05	// key End
	.byte	0x7a		; CH_PGDN	0x06	// key PageDown
	.byte	0		;		0x07
	.byte	0x66		; CH_BS		0x08	// key BackSpace
	.byte	0x0d		; CH_TB		0x09	// key Tab
	.byte	0x72		; CH_DOWN	0x0a	// key Down
	.byte	0x66+0x80	; CH_DELROW	0x0b	// key Shift+BackSpace
	.byte	0x7e+0x80	; CH_FF		0x0c	// key Shift+Scroll
	.byte	0x5a		; CH_CR		0x0d	// key Enter
	.byte	0x74		; CH_RIGHT	0x0e	// key Right
	.byte	0x0d+0x80	; CH_BACKTB	0x0f	// key Shift+Tab
	.byte	0		;		0x10
	.byte	0x7e		; CH_SCROLLUP	0x11	// key Scroll
	.byte	0x7d		; CH_PGUP	0x12	// key PageUp
	.byte	0x77		; CH_PAU	0x13	// key Pause
	.byte	0		;		0x14
	.byte	0x75		; CH_UP		0x15	// key Up
	.byte	0x70		; CH_INSERT	0x16	// key Insert
	.byte	0		;		0x17
	.byte	0		;		0x18	
	.byte	0x71		; CH_DELETE	0x19	// key Delete
	.byte	0		;		0x1a	
	.byte	0		;		0x1b	
	.byte	0		;		0x1c	
	.byte	0x12		; CH_SHIFT	0x1d	// key Shift
	.byte	0x11		; CH_ALT	0x1e	// key Alt
	.byte	0		;		0x1f	

	.byte	0x29		; CH_SPC	0x20	// space
	.byte	0x16+0x80	; CH_1000	0x21	// plot 1
	.byte	0x52+0x80	; CH_QUOT	0x22	// "
	.byte	0x1e+0x80	; CH_0100	0x23	// plot 2
	.byte	0x52		; CH_DOLLAR	0x24	// $
	.byte	0x26+0x80	; CH_1100	0x25	// plot 3
	.byte	0x29+0x80	; CH_POUND	0x26	// pound
	.byte	0x25+0x80	; CH_0010	0x27	// plot 4
	.byte	0x54		; CH_LPAR	0x28	// (
	.byte	0x5b		; CH_RPAR	0x29	// )
	.byte	0x4e+0x80	; CH_ASTER	0x2a	// *
	.byte	0x55+0x80	; CH_PLUS	0x2b	// +
	.byte	0x41		; CH_COMMA	0x2c	// ,
	.byte	0x4e		; CH_MINUS	0x2d	// -
	.byte	0x49		; CH_DOT	0x2e	// .
	.byte	0x4a		; CH_SLASH	0x2f	// /
	.byte	0x45		; CH_0		0x30	// 0
	.byte	0x16		; CH_1		0x31	// 1
	.byte	0x1e		; CH_2		0x32	// 2
	.byte	0x26		; CH_3		0x33	// 3
	.byte	0x25		; CH_4		0x34	// 4
	.byte	0x2e		; CH_5		0x35	// 5
	.byte	0x36		; CH_6		0x36	// 6
	.byte	0x3d		; CH_7		0x37	// 7
	.byte	0x3e		; CH_8		0x38	// 8
	.byte	0x46		; CH_9		0x39	// 9
	.byte	0x4c+0x80	; CH_COLON	0x3a	// :
	.byte	0x4c		; CH_SEMI	0x3b	// ;
	.byte	0x41+0x80	; CH_LT		0x3c	// <
	.byte	0x55		; CH_EQU	0x3d	// =
	.byte	0x49+0x80	; CH_GR		0x3e	// >
	.byte	0x4a+0x80	; CH_QUERY	0x3f	// ?
	.byte	0x2e+0x80	; CH_1010	0x40	// plot 5
	.byte	0x1c		; CH_A		0x41	// A
	.byte	0x32		; CH_B		0x42	// B
	.byte	0x21		; CH_C		0x43	// C
	.byte	0x23		; CH_D		0x44	// D
	.byte	0x24		; CH_E		0x45	// E
	.byte	0x2b		; CH_F		0x46	// F
	.byte	0x34		; CH_G		0x47	// G
	.byte	0x33		; CH_H		0x48	// H
	.byte	0x43		; CH_I		0x49	// I
	.byte	0x3b		; CH_J		0x4a	// J
	.byte	0x42		; CH_K		0x4b	// K
	.byte	0x4b		; CH_L		0x4c	// L
	.byte	0x3a		; CH_M		0x4d	// M
	.byte	0x31		; CH_N		0x4e	// N
	.byte	0x44		; CH_O		0x4f	// O
	.byte	0x4d		; CH_P		0x50	// P
	.byte	0x15		; CH_Q		0x51	// Q
	.byte	0x2d		; CH_R		0x52	// R
	.byte	0x1b		; CH_S		0x53	// S
	.byte	0x2c		; CH_T		0x54	// T
	.byte	0x3c		; CH_U		0x55	// U
	.byte	0x2a		; CH_V		0x56	// V
	.byte	0x1d		; CH_W		0x57	// W
	.byte	0x22		; CH_X		0x58	// X
	.byte	0x35		; CH_Y		0x59	// Y
	.byte	0x1a		; CH_Z		0x5a	// Z
	.byte	0x36+0x80	; CH_0110	0x5b	// plot 6
	.byte	0x3d+0x80	; CH_1110	0x5c	// plot 7
	.byte	0x3e+0x80	; CH_GRID	0x5d	// grid
	.byte	0x46+0x80	; CH_GRIDDN	0x5e	// grid down
	.byte	0x45+0x80	; CH_GRIDUP	0x5f	// grid up
KeyMapEnd:

	.balign 2	; to avoid linker error "warning: internal error: out of range error" must be at the end of unaligned tables

; ----------------------------------------------------------------------------
;                           Get key from keyboard buffer
; ----------------------------------------------------------------------------
; OUTPUT: R24 = key, or 0 = no key
; DESTROY: R31, R30, R25, R24, R1
; STACK: 2 bytes
; ----------------------------------------------------------------------------

.global KeyIn
KeyIn:
	; check if buffer is empty
	ldd	ZL,Y+DATA_KEYREAD
	ldd	ZH,Y+DATA_KEYWRITE
	cp	ZL,ZH
	brne	1f

	; no key
	ldi	r24,CH_NUL
	ret

	; read scan code
1:	clr	ZH
	subi	ZL,lo8(-(KeyBuf))
	sbci	ZH,hi8(-(KeyBuf))
	ld	r24,Z

	; increment read index
	subi	ZL,lo8(KeyBuf-1)
	andi	ZL,KEYBUF_MASK
	std	Y+DATA_KEYREAD,ZL

	; release prefix
	cpi	r24,0xf0
	brne	2f
	std	Y+DATA_KEYRELPREF,r24
	rjmp	KeyIn		; next scan code
	
	; key is released
2:	ldd	ZL,Y+DATA_KEYRELPREF
	std	Y+DATA_KEYRELPREF,R_ZERO ; delete release prefix
	tst	ZL
	breq	4f		; not release

	; release SHIFT
	cpi	r24,0x12	; left SHIFT
	breq	3f
	cpi	r24,0x59	; right SHIFT
	brne	2f		; ignore another released keys
3:	std	Y+DATA_KEYSHIFT,R_ZERO	; delete SHIFT prefix	

	; release ALT
2:	cpi	r24,0x11	; ALT
	brne	KeyIn		; not ALT
	std	Y+DATA_KEYALT,R_ZERO ; delete ALT prefix
	rjmp	KeyIn		; next key

	; press Shift
4:	cpi	r24,0x12	; left SHIFT
	breq	5f
	cpi	r24,0x59	; right SHIFT
	brne	6f
5:	std	Y+DATA_KEYSHIFT,r24 ; save SHIFT
	rjmp	KeyIn		; next key

	; press Alt
6:	cpi	r24,0x11	; ALT
	brne	1f		; not ALT
	std	Y+DATA_KEYALT,r24 ; save ALT
	rjmp	KeyIn		; next key

	; ignore codes >= 0x80
1:	cpi	r24,0x80
	brcc	KeyIn

	; numeric array ignores Shift (because NumLock changes this flag)
	cpi	r24,0x77	; Pause
	breq	2f
	cpi	r24,0x7e	; Scroll
	breq	2f
	cpi	r24,0x69
	brcc	7f
2:
	; prepare code - add SHIFT flag
	ldd	ZL,Y+DATA_KEYSHIFT
	tst	ZL
	breq	7f		; no SHIFT
	ori	r24,0x80	; add SHIFT flag to scan code

7:

; DEBUG - return scan code
;	ret

	; search scan code in key map table
	ldi	ZL,lo8(KeyMap)
	ldi	ZH,hi8(KeyMap)	; key map
	ldi	r25,0		; character start index - 1
8:	inc	r25		; increment character index
	lpm	r1,Z+		; load key
	cp	r1,r24		; check key
	breq	2f		; key found OK
	cpi	r25,0x5f	; check last key code
	brne	8b		; next key

	rjmp	KeyIn		; next key

	; control codes cannot have INV flag
2:	cpi	r25,0x20
	brcs	KeyIn8

	; add INV flag
	ldd	ZL,Y+DATA_KEYALT
	tst	ZL
	breq	KeyIn8		; no ALT
	ori	r25,0x80	; add INVERT flag
KeyIn8:	mov	r24,r25
	ret
