chiark / gitweb /
JPEG support and other fixes from Nick Clark
[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