From: tony@microware.co.uk (Tony Mountifield)
Newsgroups: comp.sys.atari.st
Subject: Re: Accessing joystick from 'C'
Date: 19 Nov 92 13:10:23 GMT
Organization: Microware Systems (UK) Ltd., Winchester, UK.

In article <1992Nov18.093245.8277@ccsun.strath.ac.uk> cabp09@ccsun.strath.ac.uk ("David McNicol") writes:
> 
> Hi there,
> 	 Does ANYONE out there know how to read the joystick ports
> of an atari ST in C/Assembly ?? I presume there must be tonnes of
> people out there.

I never saw it properly documented, so about 4 years ago, using
information from the old Abacus/DataBecker internals book, I set about
investigating the Keyboard vector routines, using a packet handler which
I could patch into the vectors I wanted to investigate. The C program I
used is given below. As written, it hooks into the status and joystick
vectors. For just the joystick information, it is not necessary to use
the status vector. Obviously, the program could be cut dow to just bare
bones for joystick handling, but I thought the complete thing might be
of interest.

It was compiled using Lattice C 3.0.4.  UBYTE is just a typedef of
unsigned char.  You won't need <portab.h> if you define this by hand. 
cprintf() is just printf() directly to the console. The include file
<fctype.h> is just a variant of <ctype.h>, which itself would do fine.

It should be compiled to a .TOS executable.

------------------------------------------------------------------------
#include <portab.h>
#include <osbind.h>
#include <fctype.h>

typedef struct {
   void (*midivec)();
   void (*vkbderr)();
   void (*vmiderr)();
   void (*statvec)();
   void (*mousevec)();
   void (*clockvec)();
   void (*joyvec)();
   void (*midisys)();
   void (*ikbdsys)();
}  KBVEC;

UBYTE joy0,joy1;
UBYTE list[10];
int got=FALSE;

void dopkt(packet)
UBYTE packet[];
{
   register int i;

   for(i=0;i<10;i++)
      list[i]=packet[i];
   got=TRUE;

   if (packet[0]>=0xFE) {
      joy0=packet[1];
      joy1=packet[2];
   }
}

void main()
{
   KBVEC *p,save;
   UBYTE old0,old1;
   char buf[128];
   int cmd;
   char c;

   p = (KBVEC *)Kbdvbase();
   save.joyvec = p->joyvec;
   p->joyvec = dopkt;
   save.statvec = p->statvec;
   p->statvec = dopkt;

   Ikbdws(0,"\x12");                   /* Turn mouse off */

   old0=old1=0xFF;
   cmd = 0;

   for(;;) {

      if (Cconis()) {
         c=toupper((short)Crawcin());
         if (c=='\x03') {
            Ikbdws(0,"\x08");          /* Restore mouse operation */
            p->joyvec = save.joyvec;
            p->statvec = save.statvec;
            Pterm0();
         }
         else if (c=='\r') {
            buf[0]=cmd;
            Ikbdws(0,buf);
            cmd = 0;
         }
         else if (c>='0' && c<='9') {
            cmd = ((cmd & 0xF) << 4) | (c-'0');
            cprintf("cmd = %X\r\n",cmd);
         }
         else if (c>='A' && c<='F') {
            cmd = ((cmd & 0xF) << 4) | (c-'A'+10);
            cprintf("cmd = %X\r\n",cmd);
         }
      }

      if (got) {
         cprintf("Packet = %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X\r\n",
                  list[0],list[1],list[2],list[3],list[4],
                  list[5],list[6],list[7],list[8],list[9]);
         got=FALSE;
      }

      if (old0 != joy0) {
         old0 = joy0;
         cprintf("Joy0 = %02X\r\n",old0);
      }

      if (old1 != joy1) {
         old1 = joy1;
         cprintf("Joy1 = %02X\r\n",old1);
      }
   }
}
------------------------------------------------------------------------

Armed with the information gleaned by this program, it was possible to
write assembler routines to setup, use and unsetup the joystick. JOYINI
and JOYEND should be callable from ASM or C, and the global variables
JOY0 and JOY1 will be updated automatically whenever a joystick state
changes.

I can't remember what bit means what, but that is easily determined by
trial and error.

------------------------------------------------------------------------
;
JOYINI  MOVEM.L A0-A1/D0,-(SP)          ; Save registers
        MOVE.W  #34,-(SP)               ; Kbdvbase()
        TRAP    #14                     ; Xbios
        LEA     2(SP),SP                ; Better than ADDQ, as it
                                        ; doesn't set any flags.
;       Now D0 points to the table of longword vectors. The
;       joystick vector is at offset 24 from this.
;
        MOVEA.L D0,A0                   ; Must be in an addr reg
        MOVE.L  A0,ADRSAV               ; Save table address
        MOVE.L  24(A0),JOYSAV           ; Save current joy value
        LEA     OURJOY(PC),A1           ; Position independent
        MOVE.L  A1,24(A0)               ; Point vector to our code
        PEA     MOUSOF(PC)              ; Command to turn off mouse
        MOVE.W  #MOUSOFL-1,-(SP)        ; Length-1
        MOVE.W  #25,-(SP)               ; Ikbdws()
        TRAP    #14                     ; Xbios
        LEA     8(SP),SP                ; Tidy stack
        MOVEM.L (SP)+,A0-A1/D0          ; Restore registers
        RTS
;
JOYEND  MOVEM.L A0,-(SP)                ; Save registers
        MOVEA.L ADRSAV,A0               ; Point to table
        MOVE.L  JOYSAV,24(A0)           ; Restore old value
        PEA     MOUSON(PC)              ; Command to restore mouse
        MOVE.W  #MOUSONL-1,-(SP)        ; Length-1
        MOVE.W  #25,-(SP)               ; Ikbdws()
        TRAP    #14                     ; Xbios
        LEA     8(SP),SP                ; Tidy stack
        MOVEM.L (SP)+,A0                ; Restore registers
        RTS
;
MOUSOF  DC.B    $12
MOUSOFL EQU     *-MOUSOF
MOUSON  DC.B    $08
MOUSONL EQU     *-MOUSON
;
;       This next is our joystick interrupt routine. We may use
;       registers A0-A2 and D0-D2 without having to save them.
;
OURJOY  MOVEA.L 4(SP),A0                ; Pointer to packet
        CMPI.B  #$FE,(A0)               ; Joystick packet?
        BLO.S   NOJOY                   ; Ignore if not
YESJOY  MOVE.B  1(A0),JOY0              ; Copy joystick 0.
        MOVE.B  2(A0),JOY1              ; Copy joystick 1.
NOJOY   RTS
;
        DATA
;
        BSS
;
ADRSAV  DS.L    1                       ; 4 bytes for table addr
JOYSAV  DS.L    1                       ; 4 bytes for old vector
JOY0    DS.B    1                       ; Joystick 0 state.
JOY1    DS.B    1                       ; Joystick 1 state.
;
        END
------------------------------------------------------------------------

Hope this is of help to people. Please feel free to add the contents of
this article to any FAQs, etc.

Tony

-- 
Tony Mountifield     (G4CJO)       | Microware Systems (UK) Ltd.
-----------------------------------| Leylands Farm, Nobs Crook,
Email:  tony@microware.co.uk       | Colden Common, WINCHESTER, SO21 1TH.
(or:  ...!uknet!mwuk!tony)         | Tel: 0703 601990   Fax: 0703 601991
------------------------------------------------------------------------
** Any opinions are mine, not Microware's - but you knew that anyway. **
------------------------------------------------------------------------