;
; keyboard.inc: handles the "cell phone" style quick
;               text input
;
; author: Marko Kanala, raato ]a t[ mulletronic.com

; enters the naming mode - step keys are used in the
;  same way as the sms writing in cell phones ie.
;  step key 1 == abc
;  step key 2 == def
;  ...
;  step key 9 == number
;  step key 14 == delete char
;  step key 15 == previous char
;  step key 16 == next char
;  enter == done
;
; LICENSE
; Creative Commons Attribution-NonCommercial-ShareALike 2.5
;
; You are free:
;
; * to copy, distribute, display, and perform the work
; * to make derivative works
;
; Under the following conditions:
;	
; 1. Attribution. You must attribute the work in the manner specified by the 
;    author or licensor.
; 2. Noncommercial. You may not use this work for commercial purposes.
; 3. Share Alike. If you alter, transform, or build upon this work, you may 
;    distribute the resulting work only under a license identical to this one.
;
; * For any reuse or distribution, you must make clear to others the license 
;   terms of this work.
; * Any of these conditions can be waived if you get permission from the 
;   copyright holder.
;
; Your fair use and other rights are in no way affected by the above.
;
; This is a human-readable summary of the Legal Code.
; See full license at http://creativecommons.org/licenses/by-nc-sa/2.5/legalcode
;
; Copyright: Marko Kanala (raato@mulletronic.com).
;

; load FSR1 for destination addr
keyboard:
	clrf	cursorpos
	clrf	keyboardbuf
	call	lcd_cursor_on		; enable cursor
keyboard_loop:
	; refresh screen
	movff	FSR1L, temp2		; backup FSR1
	FORCEDISPLAYREFRESH
	call	lcd_refresh
	movff	temp2, FSR1L		; restore FSR1
	; refresh cursor position
	movf	cursorpos, W
	addlw	LCD_LINE1 + 4
	call	lcd_set_cursor
	CLEAREVENT	EVENT_KEY
	; wait for "roll presses"
	clrf	temp
keyboard_waitkey:
	IFEVENT	EVENT_KEY, keyboard_gotkey	
	; if no key event delay
	call	lcd_delay2ms
	decfsz	temp
	bra		keyboard_waitkey
	; delay passed without key
	; if keyboardbuf has a value we need to advance
	;  to the next position
	clrf	WREG
	cpfsgt	keyboardbuf
	bra		keyboard_loop
	; advance
	call	keyboard_advance
	; and clear keyboardbuf
	clrf	keyboardbuf
	bra		keyboard_loop
keyboard_gotkey:
	KEYEVENT	KEY_ENTER, keyboard_done
	; decode only step keys
	KEYEVENT	KEY_S14, keyboard_delete
	KEYEVENT	KEY_S15, keyboard_prev
	KEYEVENT	KEY_S16, keyboard_next
	KEYEVENT	KEY_S10, keyboard_space
	; decode keys 1 - 9
	movff	keypress, temp
	movlw	KEY_NONE
	cpfsgt	temp
	bra		keyboard_loop
	; > KEY_NONE
	movlw	KEY_S10
	cpfslt	temp
	bra		keyboard_loop
	; key 1 - 9 (key 9 == number)
	; check if keyboardbuf matches with the keypress
	movf	keyboardbuf, W
	cpfseq	temp
	bra		keyboard_insertnew
	; current keypress == previous keypress, roll key characters
	; W == keypress
	call	get_keyboard_char
	; W == upper limit for character roll
	movwf	temp2
	incf	INDF1, W				; curr pos char + 1
	cpfseq	temp2
	bra		keyboard_setchar
	; upper limit reached, roll over
	movlw	"9" + 1
	cpfseq	temp2
	bra		keyboard_normalcharroll
	; a number, reset to "0"
	movlw	"0"
	bra		keyboard_setchar
keyboard_normalcharroll:
	decf	temp, W					; keypress - 1
	call	get_keyboard_char
keyboard_setchar:
	; just set the new char without insertion
	movwf	INDF1
	bra		keyboard_handled
keyboard_insertnew:
	; if keyboardbuf != 0 we need to advance before inserting
	tstfsz	keyboardbuf
	call	keyboard_advance
	; insert at current position
	movff	temp, keyboardbuf		; store keypress to keyboardbuf
	movlw	KEY_S9
	cpfseq	temp
	bra		keyboard_insertnormal
	; a number, insert "0"
	movlw	"0"
	bra		keyboard_doinsert
keyboard_insertnormal:
	decf	temp, W					; keypress - 1
	call	get_keyboard_char
keyboard_doinsert:
	call	keyboard_insert	
keyboard_handled:
	; loop until enter pressed
	CLEAREVENT	EVENT_KEY
	bra		keyboard_loop

; advances to cursor to the next position
keyboard_advance:
	movlw	11					; 12 chars in max
	cpfslt	cursorpos
	return
	incf	cursorpos
	incf	FSR1L
	return	

; insert a char from WREG to the current position
;  note: keyboardbuf gets cleared if there is no space
;        for the character
keyboard_insert:
	movwf	temp2				; temp2 == char
	movff	FSR1L, temp
	; advance to the last char
	movf	cursorpos, W
	subwf	FSR1L, W
	addlw	11
	movwf	FSR1L				; FSR1L + 11 - cursorpos
	movlw	" "
	cpfseq	POSTINC1			; "pat_name + 12"
	bra		keyboard_insnospace
	; shift chars after the insertion position
keyboard_insloop:
	decf	FSR1L
	movf	temp, W
	cpfseq	FSR1L
	bra		keyboard_contins
	; shift done, insert char
	movff	temp2, INDF1
	return
keyboard_contins:
	decf	FSR1L
	movf	POSTINC1, W
	movwf	INDF1
	bra		keyboard_insloop
keyboard_insnospace:
	; restore FSR1L
	movff	temp, FSR1L
	clrf	keyboardbuf
	return

; deletes a character at the previous position
keyboard_delete:
	clrf	keyboardbuf
	clrf	WREG
	cpfsgt	cursorpos
	bra		keyboard_deletedone
	movff	FSR1L, temp		; backup FSR1L
	movff	cursorpos, temp2
	; pos > 0, delete ok
	; shift chars from this position to the left and
	;  pad right side with " "
keyboard_delloop:
	movlw	12				; are we done yet ?
	cpfslt	cursorpos
	bra		keyboard_delloopdone
	movf	POSTDEC1, W		; no, move from current to prev
	movwf	POSTINC1
	incf	FSR1L			; advance to next
	incf	cursorpos
	bra		keyboard_delloop 
keyboard_delloopdone:
	; shift done, insert " " at the end
	decf	FSR1L
	movlw	" "
	movwf	INDF1
	decf	temp, W
	movwf	FSR1L			; restore FSR1L
	decf	temp2, W
	movwf	cursorpos
keyboard_deletedone:
	CLEAREVENT	EVENT_KEY
	bra		keyboard_loop

; moves cursor to previous position
keyboard_prev:
	clrf	keyboardbuf
	CLEAREVENT	EVENT_KEY
	; cursorpos from 0 to 12
	clrf	WREG
	cpfsgt	cursorpos
	bra		keyboard_loop
	decf	FSR1L
	decf	cursorpos
	bra		keyboard_loop

; moves cursor to next position
keyboard_next:
	clrf	keyboardbuf
	CLEAREVENT	EVENT_KEY
	call	keyboard_advance
	bra		keyboard_loop

; enters a space to the current position
keyboard_space:
	clrf	keyboardbuf
	movlw	" "
	call	keyboard_insert
	call	keyboard_advance
	CLEAREVENT	EVENT_KEY
	bra		keyboard_loop

; name enter done!
keyboard_done:
	call	lcd_cursor_off
	return

External Labels :

lcd_cursor_on
lcd_refresh
lcd_set_cursor
lcd_delay2ms
keyboard_advance
get_keyboard_char
keyboard_insert
lcd_cursor_off