Subject: Re: Joystick and stuff
From: [email-masked] (David Empson)
Date: Thu, 16 Mar 1995 15:02:06 GMT
Newsgroups: comp.sys.apple2.programmer

In article <[email-masked]>, Stephen Carpenter  <[email-masked]> wrote:
> I am on a GS and was wondering how I can read the Joystick
> I am using Orca/c (if that helps any)

It certainly affects how you will go about reading the joystick.

There is no firmware or toolbox support provided for reading the
joystick from GS/OS.  Apart from writing your own assembly language
code to read it, the easiest way is to use the FWEntry tool call in
the Miscellaneous toolset to call the old PREAD routine in the
monitor.  This will allow one axis of the joystick to be read.  You
can then call it again with different parameters to read the other
axis.

Note: you have to ensure each axis has timed out before trying to read
it.  If you try to read the X and Y values immediately after each
other, you will probably get a false reading on the second one.  A
delay of at least three milliseconds is recommended.  One commonly
used solution is to separate the reading of the X and Y values and do
several other operations between them.

Reading the buttons is easier: it is just a matter of reading the
appropriate I/O locations directly.

Now for the details:

First, a very major warning: the FWEntry toolbox call has been
implemented incorrectly in all versions of ORCA/C: its parameters are
in a different order than they are listed in the toolbox reference.
Even worse, the parameter order varies depending on which compiler
version you have (all of them are wrong).

The official definition of FWEntry is:

   regs = FWEntry(aReg, xReg, yReg, entryPt);

With ORCA/C 1.0 to 2.0.0, you must reverse the parameters:

   regs = FWEntry(entryPt, yReg, xReg, aReg);

With ORCA/C 2.0.1 to 2.0.3, you must swap the first and last
parameters:

   regs = FWEntry(entryPt, xReg, yReg, aReg);

This will probably be fixed in a future version of the compiler (it is
actually a bug in the library code), so the correct parameter order
will be used (a, x, y, entryPt).  [Yes, Mike does know about this one.]

If you change compiler versions, make sure you check your FWEntry
calls are correct for the new version.

Having got that out of the way, here is the code required to read
either axis of the joystick from ORCA/C.  I've used inline assembly
language to read I/O ports directly, to avoid possible hickups with
ORCA/C reading the following byte as well.

#include <misctool.h>

/* Set the FWENTRY_BUG macro according to the compiler version you are using:

   1   ORCA/C 1.x, or ORCA/C 2.0.0
   2   ORCA/C 2.0.1 through 2.0.3, or future versions that still have
       the same bug.
   0   Future versions of ORCA/C that have the bug fixed.
*/

#define	FWENTRY_BUG	2       /* I'm assuming ORCA/C 2.0.1 to 2.0.3 */

#define	PRead	0xFB1E          /* Paddle read routine entry point */

Word read_paddle(Word n) {
    /* Get the current reading from a paddle.  Paddle 0 is the
       joystick X axis, paddle 1 is the joystick Y axis.  If a second
       joystick is connected, it corresponds to paddles 2 (X) and 3 (Y). */
    FWRec regs;
#if FWENTRY_BUG == 2
    regs = FWEntry(PRead, n, 0, 0);
#elif FWENTRY_BUG == 1
    regs = FWEntry(PRead, 0, n, 0);
#else
    regs = FWEntry(0, n, 0, PRead);
#endif
    return regs.yRegExit & 0xFF;
}

Boolean test_paddle(Word n) {
    /* Test if a paddle has timed out since the last read.  This routine
       can be used to check whether it is safe to call read_paddle again.
       The return value is TRUE if the specified paddle has timed out
       and can be read again, FALSE if it is still timing out (this may
       indicate that the paddle/joystick has not been connected if it
       continues long enough). */
    Byte paddle_flag;
    asm {
        sep #0x30
        lda n
        and #0x03
        tax
        lda 0xE0C064,x
        and #0x80
        sta paddle_flag
        rep #0x30
    }
    return (paddle_flag != 0);
}

Boolean read_button(Word n) {
    /* Read the state of the specified paddle/joystick button.  The return
       value will be TRUE if the button is on, FALSE if the button
       is off.  This routine supports buttons 0, 1, 2, and 3.  Button
       3 is only available on the IIgs, and only on the internal 16-pin
       game port.
       Note: holding down the Apple key will make button 0 appear to
       be on; similarly, the Option key will make button 1 appear to
       be on. */
    Byte button_state;
    asm {
        sep #0x30
        lda n
        inc a
        and #0x03
        tax
        lda 0xE0C060,x
        and #0x80
        sta button_state
        rep #0x30
    }
    return (button_state != 0);
}

-- 
David Empson
[email-masked]
Snail mail: P.O. Box 27-103, Wellington, New Zealand