]> git.sur5r.net Git - cc65/blob - libsrc/atari/mou/atrjoy.s
Always print the mouse cursor, even if coordinates haven't changed.
[cc65] / libsrc / atari / mou / atrjoy.s
1 ;
2 ; Driver for a "joystick mouse".
3 ;
4 ; C128 version: Ullrich von Bassewitz, 2004-04-05, 2009-09-26
5 ; Adapted to Atari: Christian Groessler, 2014-01-02
6 ;
7
8         .include        "zeropage.inc"
9         .include        "mouse-kernel.inc"
10         .include        "atari.inc"
11
12         .macpack        generic
13
14 ; ------------------------------------------------------------------------
15 ; Header. Includes jump table
16
17 .segment        "JUMPTABLE"
18
19 HEADER:
20
21 ; Driver signature
22
23         .byte   $6d, $6f, $75           ; "mou"
24         .byte   MOUSE_API_VERSION       ; Mouse driver API version number
25
26 ; Library reference
27
28         .addr   $0000
29
30 ; Jump table
31
32         .addr   INSTALL
33         .addr   UNINSTALL
34         .addr   HIDE
35         .addr   SHOW
36         .addr   SETBOX
37         .addr   GETBOX
38         .addr   MOVE
39         .addr   BUTTONS
40         .addr   POS
41         .addr   INFO
42         .addr   IOCTL
43         .addr   IRQ
44
45 ; Mouse driver flags
46
47         .byte   MOUSE_FLAG_LATE_IRQ
48
49 ; Callback table, set by the kernel before INSTALL is called
50
51 CHIDE:  jmp     $0000                   ; Hide the cursor
52 CSHOW:  jmp     $0000                   ; Show the cursor
53 CMOVEX: jmp     $0000                   ; Move the cursor to X coord
54 CMOVEY: jmp     $0000                   ; Move the cursor to Y coord
55
56
57 ;----------------------------------------------------------------------------
58 ; Constants
59
60 SCREEN_HEIGHT   = 191
61 SCREEN_WIDTH    = 319
62
63 .enum   JOY
64         UP      = $01
65         DOWN    = $02
66         LEFT    = $04
67         RIGHT   = $08
68 .endenum
69
70 ;----------------------------------------------------------------------------
71 ; Global variables. The bounding box values are sorted so that they can be
72 ; written with the least effort in the SETBOX and GETBOX routines, so don't
73 ; reorder them.
74
75 .bss
76
77 Vars:
78 YPos:           .res    2               ; Current mouse position, Y
79 XPos:           .res    2               ; Current mouse position, X
80 XMin:           .res    2               ; X1 value of bounding box
81 YMin:           .res    2               ; Y1 value of bounding box
82 XMax:           .res    2               ; X2 value of bounding box
83 YMax:           .res    2               ; Y2 value of bounding box
84 Buttons:        .res    1               ; Button mask
85
86
87 Temp:           .res    1               ; Temporary value used in the int handler
88 visible:        .res    1
89
90 ; Default values for above variables
91
92 .rodata
93
94 ; (We use ".proc" because we want to define both a label and a scope.)
95
96 .proc   DefVars
97         .word   SCREEN_HEIGHT/2         ; YPos
98         .word   SCREEN_WIDTH/2          ; XPos
99         .word   0                       ; XMin
100         .word   0                       ; YMin
101         .word   SCREEN_WIDTH            ; XMax
102         .word   SCREEN_HEIGHT           ; YMax
103         .byte   0                       ; Buttons
104 .endproc
105
106 .code
107
108 ;----------------------------------------------------------------------------
109 ; INSTALL routine. Is called after the driver is loaded into memory. If
110 ; possible, check if the hardware is present.
111 ; Must return an MOUSE_ERR_xx code in a/x.
112
113 INSTALL:
114
115 ; Initialize variables. Just copy the default stuff over
116
117         ldx     #.sizeof(DefVars)-1
118 @L1:    lda     DefVars,x
119         sta     Vars,x
120         dex
121         bpl     @L1
122
123 ; Be sure the mouse cursor is invisible and at the default location.
124
125         jsr     CHIDE
126         lda     XPos
127         ldx     XPos+1
128         jsr     CMOVEX
129         lda     YPos
130         ldx     YPos+1
131         jsr     CMOVEY
132
133 ; Done, return zero (= MOUSE_ERR_OK)
134
135         ldx     #$00
136         txa
137         rts
138
139 ;----------------------------------------------------------------------------
140 ; UNINSTALL routine. Is called before the driver is removed from memory.
141 ; No return code required (the driver is removed from memory on return).
142
143 UNINSTALL       = HIDE                  ; Hide cursor on exit
144
145 ;----------------------------------------------------------------------------
146 ; HIDE routine. Is called to hide the mouse pointer. The mouse kernel manages
147 ; a counter for calls to show/hide, and the driver entry point is only called
148 ; if the mouse is currently visible and should get hidden. For most drivers,
149 ; no special action is required besides hiding the mouse cursor.
150 ; No return code required.
151
152 HIDE:   dec     visible
153         php
154         sei
155         jsr     CHIDE
156         plp
157         rts
158
159 ;----------------------------------------------------------------------------
160 ; SHOW routine. Is called to show the mouse pointer. The mouse kernel manages
161 ; a counter for calls to show/hide, and the driver entry point is only called
162 ; if the mouse is currently hidden and should become visible. For most drivers,
163 ; no special action is required besides enabling the mouse cursor.
164 ; No return code required.
165
166 SHOW:   inc     visible
167         php
168         sei
169         jsr     CSHOW
170         plp
171         rts
172
173 ;----------------------------------------------------------------------------
174 ; SETBOX: Set the mouse bounding box. The parameters are passed as they come
175 ; from the C program, that is, a pointer to a mouse_box struct in a/x.
176 ; No checks are done if the mouse is currently inside the box, this is the job
177 ; of the caller. It is not necessary to validate the parameters, trust the
178 ; caller and save some code here. No return code required.
179
180 SETBOX: sta     ptr1
181         stx     ptr1+1                  ; Save data pointer
182
183         ldy     #.sizeof (MOUSE_BOX)-1
184         php
185         sei
186
187 @L1:    lda     (ptr1),y
188         sta     XMin,y
189         dey
190         bpl     @L1
191
192         plp
193         rts
194
195 ;----------------------------------------------------------------------------
196 ; GETBOX: Return the mouse bounding box. The parameters are passed as they
197 ; come from the C program, that is, a pointer to a mouse_box struct in a/x.
198
199 GETBOX: sta     ptr1
200         stx     ptr1+1                  ; Save data pointer
201
202         ldy     #.sizeof (MOUSE_BOX)-1
203         php
204         sei
205
206 @L1:    lda     XMin,y
207         sta     (ptr1),y
208         dey
209         bpl     @L1
210
211         plp
212         rts
213
214 ;----------------------------------------------------------------------------
215 ; MOVE: Move the mouse to a new position. The position is passed as it comes
216 ; from the C program, that is: X on the stack and Y in a/x. The C wrapper will
217 ; remove the parameter from the stack on return.
218 ; No checks are done if the new position is valid (within the bounding box or
219 ; the screen). No return code required.
220 ;
221
222 MOVE:   php
223         sei                             ; No interrupts
224
225         pha
226         txa
227         pha
228         jsr     CHIDE
229         pla
230         tax
231         pla
232
233         sta     YPos
234         stx     YPos+1                  ; New Y position
235         jsr     CMOVEY                  ; Set it
236
237         ldy     #$01
238         lda     (sp),y
239         sta     XPos+1
240         tax
241         dey
242         lda     (sp),y
243         sta     XPos                    ; New X position
244
245         jsr     CMOVEX                  ; Move the cursor
246
247         lda     visible
248         beq     @Ret
249         
250         jsr     CSHOW
251
252 @Ret:   plp                             ; Restore interrupt flag
253         rts
254
255 ;----------------------------------------------------------------------------
256 ; BUTTONS: Return the button mask in a/x.
257
258 BUTTONS:
259         lda     Buttons
260         ldx     #$00
261         rts
262
263 ;----------------------------------------------------------------------------
264 ; POS: Return the mouse position in the MOUSE_POS struct pointed to by ptr1.
265 ; No return code required.
266
267 POS:    ldy     #MOUSE_POS::XCOORD      ; Structure offset
268
269         php
270         sei                             ; Disable interrupts
271         lda     XPos                    ; Transfer the position
272         sta     (ptr1),y
273         lda     XPos+1
274         iny
275         sta     (ptr1),y
276         lda     YPos
277         iny
278         sta     (ptr1),y
279         lda     YPos+1
280         plp                             ; Restore interrupt flag
281
282         iny
283         sta     (ptr1),y                ; Store last byte
284
285         rts                             ; Done
286
287 ;----------------------------------------------------------------------------
288 ; INFO: Returns mouse position and current button mask in the MOUSE_INFO
289 ; struct pointed to by ptr1. No return code required.
290 ;
291 ; We're cheating here to keep the code smaller: The first fields of the
292 ; mouse_info struct are identical to the mouse_pos struct, so we will just
293 ; call _mouse_pos to initialize the struct pointer and fill the position
294 ; fields.
295
296 INFO:   jsr     POS
297
298 ; Fill in the button state
299
300         lda     Buttons
301         ldy     #MOUSE_INFO::BUTTONS
302         sta     (ptr1),y
303
304         rts
305
306 ;----------------------------------------------------------------------------
307 ; IOCTL: Driver defined entry point. The wrapper will pass a pointer to ioctl
308 ; specific data in ptr1, and the ioctl code in A.
309 ; Must return an error code in a/x.
310 ;
311
312 IOCTL:  lda     #<MOUSE_ERR_INV_IOCTL     ; We don't support ioclts for now
313         ldx     #>MOUSE_ERR_INV_IOCTL
314         rts
315
316 ;----------------------------------------------------------------------------
317 ; IRQ: Irq handler entry point. Called as a subroutine but in IRQ context
318 ; (so be careful). The routine MUST return carry set if the interrupt has been
319 ; 'handled' - which means that the interrupt source is gone. Otherwise it
320 ; MUST return carry clear.
321 ;
322
323 IRQ:
324
325 ; Check for a pressed button and place the result into Buttons
326
327         ldx     #0
328         lda     TRIG0                   ; joystick #0 trigger
329         bne     @L0                     ; not pressed
330         ldx     #MOUSE_BTN_LEFT
331 @L0:    stx     Buttons
332
333         lda     PORTA                   ; get joystick direction bits
334         and     #15                     ; clear joystick #1 bits
335         eor     #15
336         sta     Temp
337
338         jsr     CHIDE
339
340 ; Check left/right
341
342         lda     Temp                    ; Read joystick #0
343         and     #(JOY::LEFT | JOY::RIGHT)
344         beq     @SkipX                  ;
345
346 ; We will cheat here and rely on the fact that either the left, OR the right
347 ; bit can be active
348
349         and     #JOY::RIGHT             ; Check RIGHT bit
350         bne     @Right
351         lda     #$FF
352         tax
353         bne     @AddX                   ; Branch always
354 @Right: lda     #$01
355         ldx     #$00
356
357 ; Calculate the new X coordinate (--> a/y)
358
359 @AddX:  add     XPos
360         tay                             ; Remember low byte
361         txa
362         adc     XPos+1
363         tax
364
365 ; Limit the X coordinate to the bounding box
366
367         cpy     XMin
368         sbc     XMin+1
369         bpl     @L1
370         ldy     XMin
371         ldx     XMin+1
372         jmp     @L2
373 @L1:    txa
374
375         cpy     XMax
376         sbc     XMax+1
377         bmi     @L2
378         ldy     XMax
379         ldx     XMax+1
380 @L2:    sty     XPos
381         stx     XPos+1
382
383 ; Move the mouse pointer to the new X pos
384
385         tya
386         jsr     CMOVEX
387
388 ; Calculate the Y movement vector
389
390 @SkipX: lda     Temp                    ; Read joystick #0
391         and     #(JOY::UP | JOY::DOWN)  ; Check up/down
392         beq     @SkipY                  ;
393
394 ; We will cheat here and rely on the fact that either the up, OR the down
395 ; bit can be active
396
397         lsr     a
398         bcc     @Down
399         lda     #$FF
400         tax
401         bne     @AddY
402 @Down:  lda     #$01
403         ldx     #$00
404
405 ; Calculate the new Y coordinate (--> a/y)
406
407 @AddY:  add     YPos
408         tay                             ; Remember low byte
409         txa
410         adc     YPos+1
411         tax
412
413 ; Limit the Y coordinate to the bounding box
414
415         cpy     YMin
416         sbc     YMin+1
417         bpl     @L3
418         ldy     YMin
419         ldx     YMin+1
420         jmp     @L4
421 @L3:    txa
422
423         cpy     YMax
424         sbc     YMax+1
425         bmi     @L4
426         ldy     YMax
427         ldx     YMax+1
428 @L4:    sty     YPos
429         stx     YPos+1
430
431 ; Move the mouse pointer to the new X pos
432
433         tya
434         jsr     CMOVEY
435
436 ; Done
437
438 @SkipY: lda     visible
439         beq     @Done
440
441         jsr     CSHOW
442
443 @Done:  clc                             ; Interrupt not "handled"
444         rts
445