buffer .EQU TextShadow LD HL, buffer
#define BUFSIZE 48 XOR A LD B, A
LD (CurCol), A
EX DE, HL b_call(_GetCSC) EX DE, HL
OR A JR Z, KeyLoop
CP skEnter JR NZ, NotEnter LD (HL), 0 RET NotEnter:
LD C, A LD A, B CP BUFSIZE JR Z, KeyLoop LD A, C
From the scan code table, we see that all the letter keys are between $0A and $2F. We will want to reject all keys that are outside this range.
SUB skAdd JR C, KeyLoop CP skMath - skAdd + 1 JR NC, KeyLoopWe used a SUB here because of the nature of arrays. The first element in all arrays is referenced with an index of zero. Since our input domain starts with $0A, we subtract that number to "massage" the input to something more compatible. If this wasn't done, we would have to fill the first eleven entries of the look-up table with a garbage value.
Now the code to convert the character and the contents of the look-up table. We have to be careful here because the scan codes are not always sequential, and there are some keys that have no letter assigned to them. We'll make these keys result in boxes.
PUSH HL LD H, 0 LD L, A LD DE, CharTable ADD HL, DE LD A, (HL) POP HL CharTable: .DB $27, "WRMH", $FF, $FF ; + - × ÷ ^ undefined .DB "?", $5B, "VQLG", $FF, $FF ; (-) 3 6 9 ) TAN VARS undefined .DB ":ZUPKFC", $FF, $FF ; . 2 5 8 ( COS PRGM STAT .DB " YTOJEB", $FF, $FF ; 0 1 4 7 , SIN APPS XTθn undefined .DB "XSNIDA" ; STO LN LOG x2 x-1 MATH
LD (HL), A INC HL INC B
b_call(_PutC)
JR KeyLoop
#define BUFSIZE 48 buffer .EQU TextShadow GetStr: RES AppTextSave, (IY + AppFlags) LD HL, buffer ; Init pointer XOR A LD B, A ; Init character counter LD (CurCol), A KeyLoop: EX DE, HL ; Get a character b_call(_GetCSC) EX DE, HL OR A ; If no character recieved, restart JR Z, KeyLoop CP skEnter ; If [ENTER] pressed, exit JR NZ, NotEnter LD (HL), 0 ; Null-terminate buffer RET NotEnter: LD C, A ; Save input char temporarily LD A, B ; See if max number of characters input CP BUFSIZE JR Z, KeyLoop LD A, C ; Restore char SUB skAdd ; Throw out all keys below [+] JR C, KeyLoop CP skMath - skAdd + 1 ; Throw out all keys above [MATH] JR NC, KeyLoop PUSH HL ; Convert scan code into character LD H, 0 LD L, A LD DE, CharTable ADD HL, DE LD A, (HL) POP HL b_call(_PutC) ; Echo it LD (HL), A ; Write char to buffer INC HL ; Increment pointer INC B ; Increment char counter JR KeyLoop CharTable: .DB "'WRMH", 0, 0 ; + - × ÷ ^ undefined .DB "?", LTheta, "VQLG", 0, 0 ; (-) 3 6 9 ) TAN VARS undefined .DB ":ZUPKFC", 0 ; . 2 5 8 ( COS PRGM STAT .DB " YTOJEB", 0, 0 ; 0 1 4 7 , SIN APPS XTθn undefined .DB "XSNIDA" ; STO LN LOG x2 x-1 MATH
GetChar: PUSH HL LD HL, (buf_ptr) ; buf_ptr is our pointer variable LD A, (HL) OR A SCF ; Set carry to indicate error status JR Z, GetChar_Done INC HL ; Update buffer pointer LD (buf_ptr), HL OR A ; Reset carry to indicate success status GetChar_Done: POP HL RET
It would also be useful to have an inverse routine, one that "ungets" characters from the buffer. We might use such a routine in a case like inputting numbers digit-by-digit, and stopping input when the first non-digit character is read. That character might be part of subsequent data, and should be returned.
The unget routine has a very simple concept: since the characters are always in the buffer, the buffer pointer only needs to be decremented. There should also be a check to make sure we don't go past the start of the buffer.
Ungetc: PUSH HL PUSH DE LD HL, (buf_ptr) LD DE, buffer ; See that the buffer pointer is not b_call(_CpHLDE) ; at the start of the buffer SCF ; Set carry to indicate error status JR Z, Ungetc_Done DEC HL LD (buf_ptr), HL OR A ; Reset carry to indicate success status Ungetc_Done: POP DE POP HL RET
We'll allow two ways to edit the inputted string:
#define BUFSIZE 48 buffer .EQU TextShadow buf_ptr .EQU buffer + BUFSIZE + 1 GetStr: RES AppTextSave, (IY + AppFlags)LD DE, buffer ; Init pointerLD (buf_ptr), DE XOR A LD B, A ; Init character counter LD (CurCol), A KeyLoop: b_call(_GetCSC) ; Get a character. OR A ; If no character received, restart JR Z, KeyLoop CP skEnter ; If [ENTER] pressed, exit JR NZ, NotEnter XOR A ; Null-terminate bufferLD (DE), ARET NotEnter:CP skDel ; If [DEL] key pressed, backspace JR NZ, NotDel LD A, B ; See that there is a character to delete OR A JR Z, KeyLoop ; If not, restart LD HL, CurCol ; Save value of CurCol LD A, (HL) DEC (HL) ; Decrement cursor column OR A ; If original column was zero, should back up one row JR NZ, DidNotCrossLine LD (HL), 15 ; Set cursor to last column DEC HL ; Go back one row DEC (HL) DidNotCrossLine: DEC DE ; Backup one char in buffer DEC B ; Decrease char counter LD A, ' ' ; Erase char on screen b_call(_PutMap) ; without affecting position JR KeyLoop NotDel: CP skClear ; If [CLEAR] pressed, everything must die!!! JR NZ, NotClear LD C, B ; Divide characters input by 16 SRA C ; to determine how many rows the input spans SRA C SRA C SRA C LD HL, CurRow LD A, B ; See if there are any characters to clear OR A JR Z, KeyLoop LD A, (HL) ; Backup to the start of input SUB C LD C, A LD (HL), A INC HL ; Go to first column LD (HL), 0 LD A, ' ' ClearLoop: b_call(_PutC) ; Draw spaces to clear everything DJNZ ClearLoop ; Will reset char counter LD (HL), B ; Reset column to zero DEC HL ; Reset row to original value LD (HL), C LD DE, buffer ; Reset buffer pointer JR KeyLoop NotClear:LD C, A ; Save input char temporarily LD A, B ; See if at max characters input CP BUFSIZE JR Z, KeyLoop LD A, C ; Restore char SUB skAdd ; Throw out all keys below [+] JR C, KeyLoop CP skMath - skAdd + 1 ; Throw out all keys above [MATH] JR NC, KeyLoopPUSH DE ; Convert scan code into characterLD H, 0 LD L, A LD DE, CharTable ADD HL, DE LD A, (HL)POP DEb_call(_PutC) ; Echo it LD (DE), A ; Write char to bufferINC DE ; Increment pointerINC B ; Increment counter JR KeyLoop CharTable: .DB $27, "WRMH", $FF, $FF ; + - × ÷ ^ undefined .DB "?", $5B, "VQLG", $FF, $FF ; (-) 3 6 9 ) TAN VARS undefined .DB ":ZUPKFC", $FF ; . 2 5 8 ( COS PRGM STAT .DB " YTOJEB", $FF, $FF ; 0 1 4 7 , SIN APPS XTθn undefined .DB "XSNIDA" ; STO LN LOG x2 x-1 MATH
How to do this? The simplest way is to have two lookup tables, one for alpha, the other for normal. We will toggle between the two modes using the [ALPHA] key, and store the current mode in the system flag ShiftAlpha.
#define BUFSIZE 48 buffer .EQU TextShadow buf_ptr .EQU buffer + BUFSIZE + 1 GetStr: RES AppTextSave, (IY + AppFlags)RES ShiftAlpha, (IY + ShiftFlags)LD DE, buffer ; Init pointer LD (buf_ptr), DE XOR A LD B, A ; Init character counter LD (CurCol), A KeyLoop: b_call(_GetCSC) ; Get a character. OR A ; If no character received, restart JR Z, KeyLoop CP skEnter ; If [ENTER] pressed, exit JR NZ, NotEnter XOR A ; Null-terminate buffer LD (DE), A RES ShiftAlpha, (IY + ShiftFlags) RET NotEnter:CP skAlpha JR NZ, NotAlpha LD HL, Flags + ShiftFlags LD A, (HL) XOR 1 << ShiftAlpha ; Toggle state of ShiftAlpha flag LD (HL), A JR KeyLoop NotAlpha:CP skDel ; If [DEL] key pressed, backspace JR NZ, NotDel LD A, B ; See that there is a character to delete OR A JR Z, KeyLoop ; If not, restart LD HL, CurCol ; Save value of CurCol LD A, (HL) DEC (HL) ; Decrement cursor column OR A ; If original column was zero, should back up one row JR NZ, DidNotCrossLine LD (HL), 15 ; Set cursor to last column DEC HL ; Go back one row DEC (HL) DidNotCrossLine: DEC DE ; Backup one char in buffer DEC B ; Decrease char counter LD A, ' ' ; Erase char on screen b_call(_PutMap) ; without affecting position JR KeyLoop NotDel: CP skClear ; If [CLEAR] pressed, everything must die!!! JR NZ, NotClear LD C, B ; Divide characters input by 16 SRA C ; to determine how many rows the input spans SRA C SRA C SRA C LD HL, CurRow LD A, B ; See if there are any characters to clear OR A JR Z, KeyLoop LD A, (HL) ; Backup to the start of input SUB C LD C, A LD (HL), A INC HL ; Go to first column LD (HL), 0 LD A, ' ' ClearLoop: b_call(_PutC) ; Draw spaces to clear everything DJNZ ClearLoop ; Will reset char counter LD (HL), B ; Reset column to zero DEC HL ; Reset row to original value LD (HL), C LD DE, buffer ; Reset buffer pointer JR KeyLoop NotClear: LD C, A ; Save input char temporarily LD A, B ; See if at max characters input CP BUFSIZE JR Z, KeyLoop LD A, C ; Restore char SUB skAdd ; Throw out all keys below [+] JR C, KeyLoop CP skMath - skAdd + 1 ; Throw out all keys above [MATH] JR NC, KeyLoop PUSH DE ; Convert scan code into character LD DE, CharTableBIT ShiftAlpha, (IY + ShiftFlags) JR NZ, AlphaMode LD DE, NormalTable AlphaMode:LD H, 0 LD L, A LD DE, CharTable ADD HL, DE LD A, (HL) POP DE b_call(_PutC) ; Echo it LD (DE), A ; Write char to bufferINC DE ; Increment pointerINC B ; Increment counter JR KeyLoop CharTable: .DB $27, "WRMH", $FF, $FF ; + - × ÷ ^ undefined .DB "?", $5B, "VQLG", $FF, $FF ; (-) 3 6 9 ) TAN VARS undefined .DB ":ZUPKFC", $FF ; . 2 5 8 ( COS PRGM STAT .DB " YTOJEB", $FF, $FF ; 0 1 4 7 , SIN APPS XTθn undefined .DB "XSNIDA" ; STO LN LOG x2 x-1 MATHNormTable: .DB "+-*/^", $FF, $FF ; + - � � ^ CLEAR undefined .DB "_369)", $C1, "]", $FF ; (-) 3 6 9 ) TAN VARS undefined .DB ".258({};" ; . 2 5 8 ( COS PRGM STAT .DB "0147, <>|", $FF ; 0 1 4 7 , SIN APPS XTθn undefined .DB $05, "!@#%&" ; STO LN LOG x2 x-1 MATH
As for the details on each routine,
.module ConvDec8 ConvDec8: LD C, 0 _Loop: CALL GetChar CCF ; End if no more characters RET NC SUB '0' ; Throw out all characters below '0' JR C, _Check CP 10 ; Throw out all characters above '9' CCF RET C LD D, A ; Save value in D LD A, C ; Load running total CP 26 ; Halt if there would be an overflow (260+) JP NC, Ungetc ; Return gotten character LD E, C ; Save current number in case of overflow ADD A, A ; Multiply by 10 ADD A, A ADD A, C ADD A, A ADD A, D ; Add gotten character LD C, A ; Halt if overflow (256 to 259) JR NC, _Loop LD C, E JP Ungetc _Check: CP ' ' - '0' ; If a space is encountered exit without error RET Z SCF RET
.module ConvHex8 ConvHex8: LD BC, 0 _Loop: CALL GetChar JR C, _Check CP ' ' JR Z, _Check SUB '0' RET C CP 10 JR C, _Okay ; Not a hexit in the range A-F CP 'F' - '0' + 1 ; Throw out all characters above 'F' CCF RET C CP 'A' - '0' ; Throw out all characters between '9' and 'A' RET C SUB 7 ; Make A-F into 10-15 _Okay: PUSH AF LD A, C ; Multiply running total by 16 ADD A, A ADD A, A ADD A, A ADD A, A OR C ; Add in character LD C, A INC B JR _Loop _Check: LD A, B OR A RET NZ SCF RET
.module ConvDec16 ConvDec16: LD HL, 0 LD B, H _Loop: CALL GetChar CCF RET NC SUB '0' JR C, _Check CP 10 CCF RET C LD D, H LD E, L ADD HL, HL ADD HL, HL ADD HL, DE ADD HL, HL JR C, _Overflow LD C, A ADD HL, BC JR NC, _Loop _Overflow: EX DE, HL JR Ungetc _Check: CP ' ' - '0' RET Z SCF RET
.module ConvHex16 ConvHex16: LD HL, 0 LD C, H _Loop: CALL GetChar JR C, _Check CP ' ' JR Z, _Check SUB '0' RET C CP 10 JR C, _Okay CP 'F' - '0' + 1 CCF RET C CP 'A' - '0' RET C SUB 7 _Okay: ADD HL, HL ADD HL, HL ADD HL, HL ADD HL, HL OR L LD L, A INC C JR _Loop _Check: LD A, C SCF RET