Subversion Repositories Spectranet

[/] [branches/] [gnubinutils/] [rom/] [ui_keyscan.asm] - Blame information for rev 384

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 179 winston
;The MIT License
2
;
3
;Copyright (c) 2008 Matt Westcott
4
;
5
;Permission is hereby granted, free of charge, to any person obtaining a copy
6
;of this software and associated documentation files (the "Software"), to deal
7
;in the Software without restriction, including without limitation the rights
8
;to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
;copies of the Software, and to permit persons to whom the Software is
10
;furnished to do so, subject to the following conditions:
11
;
12
;The above copyright notice and this permission notice shall be included in
13
;all copies or substantial portions of the Software.
14
;
15
;THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
;IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
;FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
;AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
;LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
;OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
;THE SOFTWARE.
22
;
23
; This file is a slightly modified version of the ZX key scanning routines
24
; from Matt Westcott's (gasman) Open ZX ROM.
25 383 winston
.data
26
flags2:                 equ 23658
27
key_table:
28 179 winston
                        ; mapping from key codes (as returned in E by key_scan) to 'base characters'
29
                        db "BHY65TGVNJU74RFC"
30
                        db "MKI83EDX", 0x0e, "LO92WSZ"
31
                        db " ", 0x0d, "P01QA"
32
 
33
;                       block 0x8060-$,0
34
                        ; table of control codes produced by keys 0-9 in conjunction with caps shift
35 383 winston
key_table_caps_digits:
36 179 winston
                        db 0x0c,0x07,0x06,0x04,0x05,0x08,0x0a,0x0b,0x09,0x0f
37
; 0x026a
38
                        ; table of symbols / tokens produced by keys A-Z in conjunction with symbol shift
39 383 winston
key_table_sym_letters:
40 179 winston
                        db 0xe2, '*', '?', 0xcd, 0xc8, 0xcc, 0xcb, '^'
41
                        db 0xac, '-', '+', '=', '.', ',', ';', '"'
42
                        db 0xc7, '<', 0xc3, '>', 0xc5, '/', 0xc9, 0x60, 0xc6, ':'
43 383 winston
.text
44 384 winston
.globl F_key_scan
45
F_key_scan:
46 179 winston
                        ; scan keyboard, returning key code(s) in DE.
47
                        ; Numbering rows B-Sp=0, H-En=1, Y-P=2, 6-0=3, 1-5=4, Q-T=5, A-G=6, Cs-V=7,
48
                        ; key code is rownum + ((5 - bit number) << 3).
49
                        ; The first key encountered, ordering by descending row and ascending bit
50
                        ; within row, is put in E. The second key is put in D.
51
                        ; If one of the keys is caps shift, this will be placed in D.
52
                        ; Otherwise, if one of the keys is symbol shift, this will be placed in D.
53
                        ; The zero flag is returned reset if >2 keys are pressed, or 2 keys are pressed
54
                        ; and neither is a shift.
55
                        ld de,0xffff
56
                        ld b,7                                                  ; scan each of 8 rows
57
                        ld a,0xfe                                               ; with each bit in turn held low
58 383 winston
key_scan_row:
59 179 winston
                        push af
60
                        in a,(0xfe)
61
                        ld c,a                                                  ; pick apart result of IN in register C
62
                        ld a,0x20                                               ; count down bit number in A, premultiplied by 8
63 383 winston
key_scan_bit:
64 179 winston
                        push af
65
                        rr c
66
                        jr c,key_scan_bit_done                  ; if bit is nonzero (-> carry set), key not pressed; move on
67
                        add a,b                                                 ; assemble key code from bit number and row number
68
                        inc e                                                   ; check if e register is vacant
69
                        jr nz,key_scan_e_not_vacant
70
                        ld e,a
71
                        jr key_scan_bit_done
72 383 winston
key_scan_e_not_vacant:
73 179 winston
                        dec e                                                   ; e is already occupied; restore value
74
                        inc d                                                   ; check if d register is vacant
75
                        jr z,key_scan_d_vacant
76
                        pop hl                                                  ; if not, there are too many keys;
77
                        pop hl                                                  ; restore stack and exit with Z reset
78
                        ret
79 383 winston
key_scan_d_vacant:
80 179 winston
                        ld d,a
81 383 winston
key_scan_bit_done:
82 179 winston
                        pop af
83
                        sub 8                                                   ; if counter in A does not roll over,
84
                        jr nc,key_scan_bit                              ; there are bits remaining to check
85
                        pop af                                                  ; go to next row once we've checked 5 bits
86
                        dec b
87
                        rlca                                                    ; keep scanning rows for as long as the zero bit
88
                        jr c,key_scan_row                               ; doesn't fall off the end of A
89
                        ; keys collected; now handle shifts
90
                        ld a,d
91 383 winston
                        inc a                                                   ; see if d is still 0xff (i.e0. only one key)
92 179 winston
                        ret z                                                   ; if so, exit with Z set
93
                        ld a,e
94
                        cp 0x27                                                 ; check E for caps shift
95
                                                                                        ; (it's the first key we check, so it'll always
96
                                                                                        ; be in E if at all)
97
                        jr nz,key_scan_no_cs
98
                        ld e,d                                                  ; if E is caps shift, switch D and E
99
                        ld d,a                                                  ; and exit with Z set
100
                        ret
101 383 winston
key_scan_no_cs:
102 179 winston
                        cp 0x18                                                 ; check E for symbol shift
103
                        jr nz,key_scan_no_ss
104
                        ld e,d                                                  ; if E is sym shift, switch D and E
105
                        ld d,a                                                  ; and exit with Z set
106
                        ret
107 383 winston
key_scan_no_ss:
108 179 winston
                        ld a,d                                                  ; only remaining valid condition is if D is
109
                        cp 0x18                                                 ; symbol shift; check for this condition and
110
                        ret                                                             ; return with Z flag indicating the result
111
 
112 384 winston
.globl F_key_test
113
F_key_test:
114 179 winston
                        ; Test that a successful (zero flag set) response from key_scan is indeed
115 383 winston
                        ; a real key (i.e0. not just a shift key on its own). As described by Toni Baker
116 179 winston
                        ; (Mastering Machine Code on your ZX Spectrum, ch11):
117
                        ;   i) B will be made to contain the value formerly held by D
118
                        ;  ii) D will be made to contain zero
119
                        ; iii) if DE started off as FFFF, FF27 or FF18, return with low byte in A and carry reset
120
                        ;  iv) otherwise, translate the key code into its base character (capitalised ASCII code)
121
                        ;      and return that in A, with carry set
122
                        ld b,d
123
                        ld d,0
124
                        ld a,b                          ; is high byte 0xff?
125
                        inc a
126
                        ld a,e                          ; load A with low byte either way
127
                        jr nz,key_test_not_ff   ; if not, key scan result is ok
128
                        cp 0x27                         ; is low byte >= 0x27 (which can only be 0x27 or 0xff)?
129
                        ret nc                          ; return with carry reset if so
130
                        cp 0x18                         ; is low byte 0x18?
131
                        ret z                                   ; return with carry reset if so
132 383 winston
key_test_not_ff:
133 179 winston
                        ld hl,key_table
134
                        add hl,de
135
                        ld a,(hl)
136
                        scf
137
                        ret
138
; 0x0333
139 384 winston
.globl F_key_code
140
F_key_code:
141 179 winston
                        ; Convert base character to ASCII code, respecting shifts and current key mode.
142
                        ; entry: E = base character
143
                        ; B = shift code (FF, 27 or 18)
144
                        ; C = editor mode (0 = K/L/C, 1 = E, 2 = G)
145
                        ; bit 3 of D = 0 for K mode, 1 for L/C mode
146
                        ; bit 3 of FLAGS2 = 0 for L mode, 1 for C mode
147
                        ; return: A = ASCII code
148
                        ; NB: for now, we'll only consider C and L modes because the others aren't much use
149
                        ; until we have a Basic editor.
150
                        ld a,b
151
                        cp 0x18                         ; test shift code for symbol shift
152
                        jr z,key_code_sshift    ; jump ahead if symbol shift active
153
                        cp 0x27                         ; test shift code for caps shift
154
                        jr z,key_code_cshift    ; jump ahead if caps shift active
155
                        ld a,(flags2)   ; get caps lock state from flags2 system variable
156
                        and 0x08                        ; - test bit 3
157
                        ld a,e                          ; pick up base character code
158
                        ret nz                          ; return it unchanged if caps lock is set
159
                        cp 'A'                          ; also return character code unchanged if caps lock is off
160
                        ret c                                   ; but character is not a letter (= code < 'A')
161
                        add a,0x20              ; otherwise, translate to lower case by adding 0x20
162
                        ret
163
 
164 383 winston
key_code_sshift:
165 179 winston
                        ld a,e
166
                        cp '0'
167
                        ret c                                   ; return keycode unchanged if <'0' (= space or enter)
168
                        cp 'A'                          ; if it's a letter (code >= 'A'), jump ahead and look up in table
169
                        jr nc,key_code_sshift_letter
170
                        ; otherwise, deal with numbers
171
                        cp '0'                          ; 0 and 2 are special cases.
172
                        jr z,key_code_underline ; These take so many bytes to handle that we would have been
173
                        cp '2'                          ; far better off with a 10-byte lookup table. But no, we had
174
                        jr z,key_code_at                                ; to make it overly complicated...
175
                        sub 0x10                        ; for all others, just subtract 0x10 to get the resulting ASCII symbol
176
                        ret
177 383 winston
key_code_underline:
178 179 winston
                        ld a,'_'
179
                        ret
180 383 winston
key_code_at:
181 179 winston
                        ld a,'@'
182
                        ret
183
 
184 383 winston
key_code_sshift_letter:
185 179 winston
                        ld d,0                          ; look up letter in the table key_table_sym_letters
186
                        ld hl,key_table_sym_letters - 'A' ; fiddle base address of table to count from ASCII 'A'
187
                        add hl,de
188
                        ld a,(hl)
189
                        ret
190
 
191 383 winston
key_code_cshift:
192 179 winston
                        ld a,e
193
                        cp '0'                          ; return keycode unchanged if <'0' (space, enter or symbol shift);
194
                        ret c                           ; NB key code for symbol shift is 0x0E = extend mode, which is correct here
195
                        cp 'A'                          ; also return keycode unchanged if it's a letter (code >= 'A')
196
                        ret nc
197
                        ld d,0                          ; otherwise, look it up in the table key_table_caps_digits
198
                        ld hl,key_table_caps_digits - '0'       ; fiddle base address of table to start counting from ASCII '0'
199
                        add hl,de
200
                        ld a,(hl)
201
                        ret
202