Joystick Unit

[From Bruce Abbott (950329.1425 EST)]

Below are JOYSTICK.PAS, a program for reading the status of the joysticks
and joystick buttons on a PC equipped with an IBM-style game port, and
a Turbo Pascal Unit called GAMEPORT.PAS that supplies the necessary
functions to JOYSTICK. You can add joystick support to any program by
compiling GAMEPORT as a TPU unit and adding GamePort to the USES statement
of the program.

I adapted the unit from a program that appeared in BYTE magazine a few years
ago and tested it on (believe it or not) an IBM PCjr. PCjrs came equipped
with game ports. In my tests I found that the PCjr.'s joysticks would
return values only up to 65-70 using this unit, although you can get values
up to around 104 from the joysticks from the STICK statement in BASICA as
supplied on the PCjr. This had me puzzled until I remembered reading
somewhere that the PCjr.'s clock is reprogrammed by BASICA in order to give
better timing resolution. The present unit depends simply on the speed with
which the central loop of the assembler code executes, and the PCjr. is
S-L-O-W. Faster computers should give much better results. If on testing
you find that the MINIMUM value returned by each joystick axis is zero, you
can increase the range of output by increasing the constant MAXCOUNT in the
STICK function (it's currently set to 200).

Because of the low range when used with the PCjr., I had to multiply the
output values (after centering) to get a useful range on the CTRACK1
program. The handle curves took on a decidedly discrete look. (However,
this problem should not arise with a faster computer.) My obtained k values
are not much different from those obtained using the mouse on my 386.

Regards,

Bruce

program JoyStick;

{ Program to demonstrate the use of the GamePort unit. The
  program reads the status of the two buttons and the X- and Y-axis
  values of each of the two joysticks on an IBM-style game port,
  and displays these values on the screen.

  Bruce Abbott
  950329
}

uses DOS, CRT, GamePort;

begin
  clrscr;
  gotoxy(23, 3); write('Joystick / Game Port Test Program');
  gotoxy(36, 8); write('BUTTONS');
  gotoxy(28, 9); write('A1 A2 B1 B2');
  gotoxy(35, 12); write('JOYSTICKS');
  gotoxy(28, 13); write('AX AY BX BY');
  while not keypressed do
    begin
      gotoxy(25, 10);
      write(Button(0):7, Button(1):7, Button(2):7, Button(3):7);
      gotoxy(23, 14);
      write(Stick(0):7, Stick(1):7, Stick(2):7, Stick(3):7);
    end;
end.

···

******************************************************************
The GamePort Unit follows. Separate this from the above and compile
as a TPU unit.

Unit GamePort;

{ Functions for reading the joystick buttons and joystick positions
  from the IBM PC game port.

  The Button function is called with parameter N set to the button
  number as follows:
                       0 = Joystick A, Button A
                       1 = Joystick A, Button B
                       2 = Joystick B, Button A
                       3 = Joystick B, Button B

  Button returns True if the button is pressed, false otherwise.

  The Stick function is called with parameter N set to the stick
  axis number as follows:

                       0 = Joystick A, X-axis
                       1 = Joystick A, Y-axis
                       2 = Joystick B, X-axis
                       3 = Joystick B, Y-axis

  Stick returns a value between 0 and (at most) maxcount; if no
  joystick is present a value of 0 is returned. If your computer
  is fast enough, you may be able to increase the range of numbers
  returned by increasing maxcount. You want the value returned to
  be just larger than 0 when the stick resistance is smallest.

  This unit was modified from a program by James P. McAdams which
  appeared in BYTE magazine, October 1985, Pp. 143-145.

  Bruce Abbott
  Psychological Sciences
  Indiana U. - Purdue U.
  Fort Wayne IN 46815

  950329
}

interface

uses DOS;

function Button(N: byte): boolean;

function Stick(N: byte): integer;

implementation

function Button(N: byte): boolean;
const
  joyport = $201;
var
  mask: byte;
begin
  case N of
    0: mask := 16;
    1: mask := 32;
    2: mask := 64;
    3: mask := 128;
    else mask := 16;
  end;
  Button := (port[joyport] and mask) = 0;
end;

function Stick(N: byte): integer;
const
  maxcount = 200;
  joyport = $201;
var
  counter: integer;
  mask: byte;
begin
  case N of
    0: mask := 1;
    1: mask := 2;
    2: mask := 4;
    3: mask := 8;
    else mask := 1;
  end;
  asm
        MOV CX,maxcount
        MOV DX,joyport
        MOV AH,mask
        OUT DX,AL
        CLI
    @A: IN AL,DX
        TEST AL,AH
        LOOPNZ @A
        STI
        MOV counter, CX;
  end;
  if counter = 0 then Stick := 0
  else Stick := maxcount - counter;
end;

begin
end.