Initial revision
[ssr] / StraySrc / Libraries / Sapphire / s / akbd
1 ;
2 ; akbd.s
3 ;
4 ; Keyboard handling (MDW)
5 ;
6 ; © 1994-1998 Straylight
7 ;
8
9 ;----- Licensing note -------------------------------------------------------
10 ;
11 ; This file is part of Straylight's Sapphire library.
12 ;
13 ; Sapphire is free software; you can redistribute it and/or modify
14 ; it under the terms of the GNU General Public License as published by
15 ; the Free Software Foundation; either version 2, or (at your option)
16 ; any later version.
17 ;
18 ; Sapphire is distributed in the hope that it will be useful,
19 ; but WITHOUT ANY WARRANTY; without even the implied warranty of
20 ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 ; GNU General Public License for more details.
22 ;
23 ; You should have received a copy of the GNU General Public License
24 ; along with Sapphire. If not, write to the Free Software Foundation,
25 ; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
26
27 ;----- Standard header ------------------------------------------------------
28
29 GET libs:header
30 GET libs:swis
31
32 ;----- External dependencies ------------------------------------------------
33
34 GET sapphire:keyMap
35 GET sapphire:intKeys
36
37 ;----- Macros ---------------------------------------------------------------
38
39 MACRO
40 $label KEYCMP $reg,$key
41
42 [ $key > &100
43 CMP $reg,# ( $key - &100 ) << 8
44 |
45 CMP $reg,# $key
46 ]
47
48 MEND
49
50 MACRO
51 $label KEYRNG $reg,$low,$high
52
53 [ $low > &100
54 SUB R14,$reg,# ( $low - &100 ) << 8
55 CMP R14,# ( $high - $low - &100 ) << 8
56 |
57 SUB R14,$reg,# $low
58 CMP R14,# $high-$low
59 ]
60
61 MEND
62
63 ;----- Main code ------------------------------------------------------------
64
65 AREA |Sapphire$$Code|,CODE,READONLY
66
67 ; --- akbd_test ---
68 ;
69 ; On entry: R0 == internal key number to test
70 ;
71 ; On exit: CS if key was pressed, CC otherwise
72 ;
73 ; Use: Informs you whether a given key is currently being pressed.
74
75 EXPORT akbd_test
76 akbd_test ROUT
77
78 STMFD R13!,{R0-R2,R14} ;Save some registers
79 MOV R2,#&FF ;Test internal key number
80 EOR R1,R0,#&FF ;Wierd translation for key
81 MOV R0,#&81 ;Test for key pressed
82 SWI OS_Byte ;Do the test nicely
83 CMP R1,#0 ;Is it pressed down?
84 LDMFD R13!,{R0-R2,R14} ;Restore registers anyhow
85 ORRNES PC,R14,#C_flag ;Yes -- set C on exit
86 BICEQS PC,R14,#C_flag ;No -- clear C on exit
87
88 LTORG
89
90 ; --- akbd_translate ---
91 ;
92 ; On entry: R0 == Wimp key number
93 ;
94 ; On exit: R0 == Straylight extended keyset key number
95 ;
96 ; Use: Translates a Wimp key number into one of the more specific
97 ; Straylight key numbers.
98
99 akbd__s EQU (1<<0)
100 akbd__c EQU (1<<1)
101
102 EXPORT akbd_translate
103 akbd_translate ROUT
104
105 ; --- Deep magic warning ---
106 ;
107 ; This routine is really not very pleasant. If you can,
108 ; avoid messing about with it. It contains several `clever'
109 ; tricks to try and reduce the code size and time taken,
110 ; which will probably end up being utterly incomprehensible.
111
112 STMFD R13!,{R6-R10,R14} ;Save some registers away
113 MOV R10,R0 ;Look after the keynumber
114 MOV R9,R10 ;Keep another copy
115
116 ; --- Do a clever translation on the Wimp key ---
117 ;
118 ; The idea is that instead of distinguishing the two keymap
119 ; halves by whether but 8 is set, we distinuguish by which
120 ; byte the value is in -- byte 0 for bottom-half values and
121 ; byte 1 for top-half values. This has an advantage in that
122 ; *all* key values are now available as immediate constants.
123 ;
124 ; There is in fact a slight problem with this: &100 and &000
125 ; become indistinguishable. This is OK, though, since the
126 ; value &100 cannot be returned by the Wimp.
127
128 CMP R10,#&100 ;Is it in the top half?
129 MOVGE R10,R10,LSL #8 ;Yes -- move it into byte 2
130 ANDGE R10,R10,#&FF00 ;And clear the top bit
131
132 ; --- Handle PageUp/PageDown nicely ---
133
134 BIC R14,R10,#&3100 ;Clear Shift and Control bits
135 CMP R14,#&8E00 ;Is it PageUp/PageDown?
136 BEQ %50 ;Yes -- handle it specially
137
138 ; --- Remove some immediate no-hopers ---
139
140 KEYCMP R10,&180 ;Is it really big?
141 BGE %99 ;Yes -- skip everything
142 KEYRNG R10,'a','z' ;Is it a simple character?
143 BLS %99 ;Yes -- skip everything
144 KEYRNG R10,'A','Z' ;Check upper case too
145 BLS %99 ;Yes -- skip everything
146 KEYRNG R10,'[',']' ;Go for the brackets too
147 BLS %99 ;Skip if in there
148
149 ; --- Work out the modifiers now ---
150
151 MOV R8,#0 ;No modifiers found yet
152 MOV R0,#intk_Shift ;Check for shift held down
153 BL akbd_test ;Is Shift being pressed?
154 ORRCS R8,R8,#akbd__s ;Yes -- set the bit then
155 MOV R0,#intk_Ctrl ;Check for ctrl too
156 BL akbd_test ;Is Ctrl being pressed?
157 ORRCS R8,R8,#akbd__c ;Yes -- set that bit
158
159 ; --- Various key checks ---
160
161 KEYCMP R10,key_Delete ;Check for Delete key
162 BEQ akbd__del ;Yes -- handle it
163
164 KEYCMP R10,' ' ;Check for Space key
165 BEQ akbd__space ;Yes -- handle it
166
167 ; --- Handle the mappings to `Return' ---
168
169 KEYCMP R10,&0D ;Check for Return key
170 BNE %10 ;No -- skip ahead a little
171 MOV R0,#intk_kEnter ;Check for Enter key
172 BL akbd_test ;Scan the keyboard again
173 BCS akbd__enter ;Yes -- handle it
174 MOV R0,#intk_M ;Check for the M key
175 BL akbd_test ;Scan the keyboard again
176 BCS %10 ;If so, skip to ctrl keys
177
178 ADD R9,PC,#0 ;Point to the table
179 B %90 ;And sort that out nicely
180 DCW key_Return,key_sReturn
181 DCW key_cReturn,key_scReturn
182
183 akbd__enter ADD R9,PC,#0 ;Point to the table
184 B %90 ;And sort that out nicely
185 DCW key_kEnter,key_skEnter
186 DCW key_ckEnter,key_sckEnter
187
188 akbd__space ADD R9,PC,#0 ;Point to the table
189 B %90 ;And sort that out nicely
190 DCW key_Space,key_sSpace
191 DCW key_cSpace,key_scSpace
192
193 akbd__del ADD R9,PC,#0 ;Point to the table
194 B %90 ;And sort that out nicely
195 DCW key_Delete,key_sDelete
196 DCW key_cDelete,key_scDelete
197
198 ; --- Handle control keys now (at last!) ---
199
200 10 CMP R10,#&1B ;Is it a control key?
201 BGE %20 ;No -- skip forwards then
202
203 MOV R14,#&00BB ;Part of the weird key mask
204 ORR R14,R14,#&0300 ;Rest of the mask
205 MOV R7,#1 ;Will be shifted about
206 TST R14,R7,LSL R10 ;Check the weirdness bit then
207 BEQ %15 ;If not *very* strange, skip
208
209 CMP R10,#8 ;Is it a backspace?
210 BNE %11 ;No -- skip ahead
211 MOV R0,#intk_H ;Could be a ctrl-H
212 BL akbd_test ;So check for that then
213 MOVCC R0,#intk_8 ;Or a ctrl-8
214 BLCC akbd_test ;So check for that too
215 BCS %11 ;Either -- skip ahead
216
217 ADD R9,PC,#0 ;Point to table
218 B %90 ;Handle table nicely
219 DCW key_Backspace,key_sBackspace
220 DCW key_cBackspace,key_scBackspace
221
222 ; --- Now handle keys which could be numbers ---
223
224 akbd__numKeys DCB 0,intk_1,0,intk_3,intk_4
225 DCB intk_5,0,intk_7,intk_8,intk_9
226
227 11 CMP R10,#0 ;Is it a null code?
228 BEQ %13 ;Yes -- it could be anything!
229
230 ADR R14,akbd__numKeys ;Point to internal key table
231 LDRB R0,[R14,R10] ;Load the correct number
232 BL akbd_test ;Test the key's state
233 BCC %15 ;It's not that weird then
234 12 TST R8,#akbd__s ;Was Shift being pressed?
235 ADDNE R9,R9,#&150 ;Yes -- add in offset
236 ADDEQ R9,R9,#&130 ;No -- add different offset
237 B %99 ;And come right out of this
238
239 ; --- Handle a 0 key number ---
240
241 13 MOV R0,#intk_0 ;Is it control-0?
242 BL akbd_test ;Check the keyboard
243 MOVCC R9,#2 ;No -- then it's really 2
244 B %12 ;Now handle Shift status
245
246 ; --- It's a sensible control key ---
247
248 15 TST R8,#akbd__s ;Is shift held down?
249 ADDNE R9,R9,#&100 ;Yes -- add the offset nicely
250 B %99 ;And return the key number
251
252 ; --- Try to handle number key presses ---
253
254 akbd__padTab DCB intk_k0,intk_k1,intk_k2,intk_k3,intk_k4
255 DCB intk_k5,intk_k6,intk_k7,intk_k8,intk_k9
256
257 20 SUB R0,R10,#'0' ;Chop off bottom limit
258 CMP R0,#9 ;Is it a numeric key?
259 BHI %30 ;No -- skip ahead then
260 ADR R14,akbd__padTab ;Point to key number table
261 LDRB R0,[R14,R0] ;Load the correct key number
262 BL akbd_test ;Check the key number nicely
263 ADDCS R9,R9,#&1C0 - '0' ;If on keypad, add offset
264 ADDCS R9,R9,R8,LSL #4 ;And add in the modifiers
265 B %99 ;Return this value to caller
266
267 ; --- Handle other keypad bits ---
268 ;
269 ; This is somewhat clever in places, so watch out. Rather
270 ; than branching on a match, or having an unconditional
271 ; CMP for each case, and a further CMP at the end, we
272 ; drop through to *all* subsequent comparisons, and take
273 ; this into account.
274 ;
275 ; Skeptics may say that this actually wastes an instruction.
276 ; Not true -- the setting up requires one value to be
277 ; initialised to an invalid value spotted at the end anyway,
278 ; and the base values are not valid immediate constants
279 ; anyway. Oddly enough, &168 == &5A >> 2, which is valid!
280
281 30 MOV R7,#&168 ;Initial value for base
282 MOV R0,#0 ;Initial value for icode
283
284 CMP R10,#'/'
285 SUBEQ R7,R7,#1
286 ADDEQ R0,R0,#intk_kSlash-intk_kStar
287 CMPNE R10,#'*'
288 SUBEQ R7,R7,#1
289 ADDEQ R0,R0,#intk_kStar-intk_kHash
290 CMPNE R10,#'#'
291 SUBEQ R7,R7,#1
292 ADDEQ R0,R0,#intk_kHash-intk_kMinus
293 CMPNE R10,#'-'
294 SUBEQ R7,R7,#1
295 ADDEQ R0,R0,#intk_kMinus-intk_kPlus
296 CMPNE R10,#'+'
297 SUBEQ R7,R7,#2
298 ADDEQ R0,R0,#intk_kPlus-intk_kDot
299 CMPNE R10,#'.'
300 SUBEQ R7,R7,#1
301 ADDEQ R0,R0,#intk_kDot
302
303 BNE %40 ;If no match above, skip
304
305 BL akbd_test ;Test the key's state
306 BCC %40 ;If not pressed, skip
307
308 ; --- Now return the correct value ---
309 ;
310 ; We use the barrel shifter to copy the modifier key states
311 ; to the ARM flags.
312
313 MOV R9,R7
314 MOVS R14,R8,LSR #1 ;Copy ctrl to !Z, sh to C
315 SUBNE R9,R9,#64 ;If ctrl, subtract 64
316 ADDCS R9,R9,#16 ;If shift, add 16
317 ADDHI R9,R9,#16 ;If both, subtract only 32
318 B %99 ;Return this value
319
320 ; --- Now tidy up any other weirdnesses ---
321
322 40 CMP R10,#&01E ;Is it a home lookalike?
323 BEQ akbd__home ;Yes -- handle it nicely
324 CMP R10,#&01B ;Is it an escape press?
325 BEQ akbd__esc ;Yes -- handle that
326 KEYRNG R10,&1C,&1F ;Is it one of the others?
327 BHI %99 ;No -- nothing else for it
328
329 TST R8,#akbd__s ;Is Shift being pressed?
330 ADDNE R9,R9,#&130 ;Yes -- offset correctly
331 ADDEQ R9,R9,#&110 ;No -- use different offset
332 B %99 ;Return this value
333
334 akbd__home MOV R0,#intk_6 ;It could be control-6
335 BL akbd_test ;Check this possibility
336 ADRCC R9,akbd__homeMods ;No -- point to home table
337 BCC %90 ;And process it as normal
338 TST R8,#akbd__s ;Is Shift being pressed?
339 ADDNE R9,R9,#key_sc6-&1E ;Yes -- handle this nicely
340 ADDEQ R9,R9,#key_c6-&1E ;No -- return other value
341 B %99 ;And return to caller
342
343 akbd__homeMods DCW key_Home,key_sHome
344 DCW key_cHome,key_scHome
345
346 akbd__esc MOV R0,#intk_LSquare ;It could be control-[
347 BL akbd_test ;Check this possibility
348 ADRCC R9,akbd__escMods ;No -- point to escape table
349 BCC %90 ;And process it as normal
350 TST R8,#akbd__s ;Is Shift being pressed?
351 ADDNE R9,R9,#key_scLSquare-&1B ;Yes -- handle this nicely
352 ADDEQ R9,R9,#key_cLSquare-&1B ;No -- return other value
353 B %99 ;And return to caller
354
355 akbd__escMods DCW key_Esc,key_sEsc
356 DCW key_cEsc,key_scEsc
357
358 ; --- Distinguish Page keys from Shift+Up/Down ---
359
360 50 TST R10,#&0100 ;Is it up or down?
361 MOVNE R0,#intk_PageUp ;If up, check PageUp key
362 MOVEQ R0,#intk_PageDown ;Otherwise, check PageDown
363 BL akbd_test ;Check the key's pressedness
364 MOVNE R0,#intk_k9 ;Can use keypad with NumLock!
365 MOVEQ R0,#intk_k3 ;So check for this as well
366 BLCC akbd_test ;Check the key's pressedness
367 EORCS R9,R9,#&050 ;If it is, mangle correctly
368 B %99 ;Return this value to caller
369
370 ; --- R9 points to a modifier table ---
371 ;
372 ; Entries in the table are held in halfwords, to save space
373
374 90 TST R8,#akbd__s ;Is shift set?
375 BIC R8,R8,#akbd__s ;Clear shift bit anyway
376 LDR R9,[R9,R8,LSL #1] ;Load word from address
377 MOVNE R9,R9,LSR #16 ;If set, shift word down
378 BIC R9,R9,#&ff000000 ;Clear top byte of key value
379 BIC R9,R9,#&00ff0000 ;Clear next byte of key too
380
381 ; --- Standard return-to-caller code ---
382
383 99 MOV R0,R9 ;Return the key number
384 LDMFD R13!,{R6-R10,PC}^ ;Return all registers
385
386 LTORG
387
388 ; --- akbd_pollKey ---
389 ;
390 ; On entry: --
391 ;
392 ; On exit: CC if a key was in the buffer and
393 ; R0 == wimp translated key code
394 ; else CS and
395 ; R0 corrupted
396 ;
397 ; Use: Reports whether the user has typed ahead, and if so what the ; keypress. Note that the keypresses returned are WIMP-type,
398 ; not Straylight extended ones so you will have to use
399 ; akbd_translate if you need the extended type.
400 ;
401 ; This call could be used to allow buffering of keypresses:
402 ; on a Key_Pressed event you would call this routine until
403 ; it returns FALSE and store the codes it returns in a buffer
404 ; along with the code from the event.
405
406 EXPORT akbd_pollKey
407 akbd_pollKey ROUT
408
409 STMFD R13!,{R1,R2,R14} ;Stack some registers
410
411 ; --- Find out if there is a key waiting ---
412
413 MOV R0,#129 ;Scan for a key
414 MOV R1,#0 ;No time limit
415 MOV R2,#0
416 SWI OS_Byte ;Read it then
417 CMP R2,#&FF ;Was there a time out
418 BEQ %95akbd_pollKey ;Yes -- return
419
420 ; --- Check for extended key codes ---
421
422 CMP R1,#0 ;Was 0 returned?
423 BNE %90akbd_pollKey ;No -- return happily
424
425 MOV R0,#129 ;Scan for a key
426 MOV R1,#0 ;No time limit
427 MOV R2,#0
428 SWI OS_Byte ;Read it then
429
430 CMP R1,#0 ;Is it still 0?
431 ADDNE R1,R1,#&100 ;No -- return extended no.
432
433 90akbd_pollKey MOV R0,R1 ;No -- get the character code
434 LDMFD R13!,{R1,R2,R14} ;Load back registers
435 BICS PC,R14,#C_flag ;Return with C clear
436
437 95akbd_pollKey LDMFD R13!,{R1,R2,R14} ;Load back registers
438 ORRS PC,R14,#C_flag ;Return with C set
439
440 LTORG
441
442 ;----- That's all, folks ----------------------------------------------------
443
444 END