Initial revision
[ssr] / StraySrc / Libraries / Sapphire / s / repeater
1 ;
2 ; repeater.s
3 ;
4 ; Handles things that should auto-repeat
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 GET libs:stream
33
34 ;----- External dependencies ------------------------------------------------
35
36 GET sapphire:divide
37 GET sapphire:idle
38 GET sapphire:sapphire
39 GET sapphire:win
40
41 ;----- Main code ------------------------------------------------------------
42
43 AREA |Sapphire$$Code|,CODE,READONLY
44
45 ; --- repeater ---
46 ;
47 ; On entry: R0 == pointer to routine to call
48 ; R1 == R10 value to pass to routine
49 ; R2 == R12 value to pass to routine
50 ;
51 ; On exit: --
52 ;
53 ; Use: Calls a routine (a) immediately, (b) after the configured
54 ; keyboard delay rate and (c) repeatedly after the configured
55 ; keyboard repeat rate. Calls stop when the user stops
56 ; pressing the mouse button.
57 ;
58 ; The routine is called with R0 containing either the number
59 ; of missed calls since the last one (normally this is 1) --
60 ; this is intended to be used to implement a kind of buffering
61 ; of repeats if the operation being performed is a lengthy one
62 ; -- and with 0 to indicate that the operation is now
63 ; completed.
64
65 EXPORT repeater
66 repeater ROUT
67
68 STMFD R13!,{R0-R4,R12,R14} ;Save some registers
69 WSPACE rpt__wSpace ;Locate my workspace nicely
70
71 ; --- Set up the workspace ---
72
73 STMIA R12,{R0-R2} ;Save the call information
74 MOV R0,#1 ;This is the first call
75 BL rpt__call ;Call the user's routine
76
77 ; --- Now we have to work out the repeat times ---
78
79 MOV R0,#196 ;Read keybd repeat and delay
80 MOV R1,#0 ;Set up registers to read...
81 MOV R2,#255 ;... without corrupting
82 SWI OS_Byte ;Read the autorepeat info
83 STR R2,rpt__repeat ;Save repeat rate in wspace
84 MOVS R4,R1 ;Look after delay time
85
86 MOVEQ R0,#0 ;If no delay, end op now
87 BLEQ rpt__call ;Tell client it's over
88 BEQ %90repeater ;And exit nicely
89
90 ; --- Set up the drag box ---
91 ;
92 ; We do this for several reasons:
93 ;
94 ; * It informs us when the mouse button is finally released.
95 ;
96 ; * It keeps the mouse pointer bounded for the duration.
97 ;
98 ; * It stops things going wrong if for some reason the mouse
99 ; gets unbounded (e.g. by doing a Wimp_SetMode).
100
101 SUB R13,R13,#56 ;Get a drag box block
102 MOV R1,R13 ;Point to the block
103 SWI Wimp_GetPointerInfo ;Get the current mouse state
104 LDMIA R13,{R2,R3} ;Read mouse position
105 MOV R1,#7 ;This drag is a user type
106 STMIA R13,{R0,R1} ;Save them in the block
107 ADD R14,R13,#24 ;Point to parent rectangle
108 STMIA R14!,{R2,R3} ;Save the current mouse...
109 STMIA R14!,{R2,R3} ;... posn to lock in place
110 MOV R1,R13 ;Point to the block
111 SWI Wimp_DragBox ;Start the drag operation
112 ADD R13,R13,#56 ;Restore the stack now
113
114 ; --- Now set up the unknown handler to catch the drag ---
115
116 ADR R0,rpt__ukEvents ;Point to my handler routine
117 MOV R1,#0 ;Don't care about R4
118 MOV R2,#0 ;Nothing to pass in R10
119 MOV R3,R12 ;Pass workspace in R12
120 BL win_unknownHandler ;Add the handler
121 BVS %90repeater ;If it failed, skip to end
122
123 ; --- Set up the alarm for the first repeat ---
124
125 SWI OS_ReadMonotonicTime ;Read the current time
126 ADD R0,R4,R0 ;Add time to keyboard delay
127 STR R0,rpt__alarm ;Store the time of the alarm
128 STR R0,rpt__last ;And this is correct time
129 ADR R1,rpt__alarms ;Point to my alarm handler
130 MOV R2,#0 ;Nothing to pass in R10
131 MOV R3,R12 ;Pass workspace in R12
132 BL idle_setAlarm ;Set the alarm call then
133
134 90repeater LDMFD R13!,{R0-R4,R12,PC}^ ;Return to caller if all OK
135
136 LTORG
137
138 ; --- rpt__call ---
139 ;
140 ; On entry: R0 == value to pass client in R0
141 ;
142 ; On exit: --
143 ;
144 ; Use: Calls client routine.
145
146 rpt__call ROUT
147
148 STMFD R13!,{R1,R10,R12,R14} ;Save some registers
149 LDMIA R12,{R1,R10,R12} ;Load client's routine data
150 MOV R14,PC ;Set up return address
151 MOV PC,R1 ;And call the routine
152 LDMFD R13!,{R1,R10,R12,PC}^ ;And return to caller
153
154 LTORG
155
156 ; --- rpt__alarms ---
157 ;
158 ; On entry: --
159 ;
160 ; On exit: --
161 ;
162 ; Use: Handles alarms while a repeater is in operation.
163
164 rpt__alarms ROUT
165
166 STMFD R13!,{R0-R4,R14} ;Save some registers
167
168 LDR R0,rpt__routine ;Load the current addr
169 CMP R0,#-1 ;Have we ended?
170 BEQ %70rpt__alarms ;Yes -- do special things
171
172 ; --- Things go odd if zero repeat rate set up ---
173
174 LDR R2,rpt__repeat ;Load current repeat rate
175 CMP R2,#0 ;Is it currently zero?
176 BEQ %50rpt__alarms ;Yes -- handle specially
177
178 ; --- Work out how many we missed ---
179 ;
180 ; We also add in the next alarm, and resynch to the
181 ; expected time.
182
183 SWI OS_ReadMonotonicTime ;Get the current time
184 MOV R4,R0 ;Look after this value
185 LDR R3,rpt__last ;Get the time I was expecting
186 SUB R0,R4,R3 ;Find how late I was called
187 MOV R1,R2 ;Get the repeat rate ready
188 BL divide ;Find out how many I missed
189 ADD R0,R0,#1 ;Add in one extra repeat
190 BL rpt__call ;Call client code again
191 SUB R14,R2,R1 ;Work out next repeat time
192 ADD R0,R4,R14 ;Add that to current time
193 STR R0,rpt__last ;This is the new alarm time
194
195 SWI OS_ReadMonotonicTime ;Get the current time
196 MOV R4,R0 ;Look after this now
197 SUB R0,R4,R3 ;Find how late I was called
198 MOV R1,R2 ;Get the repeat rate ready
199 BL divide ;Find out how many I missed
200 SUB R14,R2,R1 ;Work out next repeat time
201 ADD R0,R4,R14 ;Add that to current time
202 STR R0,rpt__alarm ;This is the new alarm time
203
204 ADR R1,rpt__alarms ;Point to me again
205 MOV R2,R10 ;Pass the dialogue handle
206 MOV R3,R12 ;And my workspace pointer
207 BL idle_setAlarm ;Add in next alarm handler
208
209 LDMFD R13!,{R0-R4,PC}^ ;And return to caller
210
211 ; --- If no repeat rate, stop the whole operation ---
212
213 50rpt__alarms MOV R0,#1 ;Just send one call
214 BL rpt__call ;Send that off to the client
215 MOV R1,#-1 ;Tell Wimp to stop dragging
216 SWI Wimp_DragBox ;Send that off nicely
217 ADR R0,rpt__ukEvents ;Point to the unknown handler
218 MOV R1,#0 ;I'm passing 0 in R4
219 MOV R2,#0 ;And 0 in R10 too
220 MOV R3,R12 ;But R12 is my workspace
221 BL win_removeUnknownHandler ;Remove it from the list
222 MOV R0,#0 ;Tell client it's all over
223 BL rpt__call ;Finish that off nicely
224 LDMFD R13!,{R0-R4,PC}^ ;And return to caller
225
226 ; --- The repeater was ended before its time ---
227
228 70rpt__alarms MOV R1,#-1 ;Tell Wimp to stop dragging
229 SWI Wimp_DragBox ;Send that off nicely
230 ADR R0,rpt__ukEvents ;Point to the unknown handler
231 MOV R1,#0 ;I'm passing 0 in R4
232 MOV R2,#0 ;And 0 in R10 too
233 MOV R3,R12 ;But R12 is my workspace
234 BL win_removeUnknownHandler ;Remove it from the list
235 LDMFD R13!,{R0-R4,PC}^ ;And return to caller
236
237 LTORG
238
239 ; --- rpt_end ---
240 ;
241 ; On entry: --
242 ;
243 ; On exit: --
244 ;
245 ; Use: Ends a repeater before the drag is released. No final
246 ; 0 is sent to the handler.
247
248 EXPORT rpt_end
249 rpt_end ROUT
250
251 STMFD R13!,{R12,R14} ;Stack registers
252 WSPACE rpt__wSpace ;Locate my workspace nicely
253 MOV R14,#-1 ;Get a silly routine value
254 STR R14,rpt__routine ;Store in routine address
255 LDMFD R13!,{R12,PC}^ ;Return to caller
256
257 LTORG
258
259 ; --- rpt__ukEvents ---
260 ;
261 ; On entry: R0 == event code
262 ; R1 == pointer to event information
263 ;
264 ; On exit: --
265 ;
266 ; Use: Picks up end-of-drag events from the WindowMangler and
267 ; diables the alarm for the repeat op.
268
269 rpt__ukEvents ROUT
270
271 CMP R0,#7 ;Is this a drag event?
272 MOVNES PC,R14 ;No -- return right away
273 STMFD R13!,{R0-R3,R14} ;Save some registers away
274
275 ; --- Remove the alarm and unknown handlers ---
276
277 LDR R0,rpt__alarm ;Get the time it's due for
278 ADR R1,rpt__alarms ;Point to my alarms routine
279 MOV R2,#0 ;I passed 0 as it's R10
280 MOV R3,R12 ;Get its R12 value
281 BL idle_removeAlarm ;And remove it from the list
282 ADR R0,rpt__ukEvents ;Point to the unknown handler
283 MOV R1,#0 ;I'm passing 0 in R4
284 BL win_removeUnknownHandler ;Remove it from the list
285
286 ; --- Tell the client it's over ---
287
288 MOV R0,#0 ;Say this is it then
289 BL rpt__call ;Send the event over
290 LDMFD R13!,{R0-R3,PC}^ ;Return to caller
291
292 LTORG
293
294 rpt__wSpace DCD 0
295
296 ;----- Workspace ------------------------------------------------------------
297
298 ^ 0,R12
299 rpt__wStart # 0
300
301 rpt__routine # 4 ;Client routine to call
302 rpt__R10 # 4 ;R10 value to pass routine
303 rpt__R12 # 4 ;R12 value to pass routine
304 rpt__repeat # 4 ;Current autorepeat rate
305 rpt__alarm # 4 ;Time for next alarm pop
306 rpt__last # 4 ;When last pop expected
307
308 rpt__wSize EQU {VAR}-rpt__wStart
309
310 AREA |Sapphire$$LibData|,CODE,READONLY
311
312 DCD rpt__wSize
313 DCD rpt__wSpace
314 DCD 0
315 DCD 0
316
317 ;----- That's all, folks ----------------------------------------------------
318
319 END