Given that you can either use the BIOS or direct access to read joystick coordinates, which method would you choose? Well, I prefer to have both methods available so that my programs can switch between them on the fly. I can choose either method by simply using a flag that allows me to switch between using the BIOS extensions or using direct access input via the same function calls in C. It isn't the most efficient method for accessing joystick input because the functions themselves will always have to check the status of the flags whenever they are called, but it is the most flexible. Oftentimes, there are advantages of one method over another given the circumstances, and this method allows me (or someone running my programs) to choose which one to employ without having to recompile any code. That said, here are the source and header files for my library functions.
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\ * JOYSTICK.C -- by Gary Neal, Jr. * * * * Source code for our functions that access the joystick controls. * \* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "joystick.h" /* Joystick potentiometer values */ unsigned short joyPotVal[4]; /* Flags if using BIOS or direct access for joystick interface */ char joystickDirectAccess = 0; /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\ * Joyin * * * * Samples all four joystick pots and stores their values in * * joyPotVal[0] through joyPotVal[3]. * * * * For Joystick's X-axis, the minimum value is LEFT. * * For Joystick's Y-axis, the minimum value is UP. * \* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ void Joyin(int joyTest) { union REGS regs; /* Declare register variable, BIOS call */ unsigned int limit; /* Limit for direct access timing */ unsigned char joyState; /* Current state for direct access */ static char joyMask; /* Joystick direct access mask enabler */ if (joystickDirectAccess) { /* Clear the joystick potentiometer values */ joyPotVal[0] = joyPotVal[1] = joyPotVal[2] = joyPotVal[3] = limit = 0; /* Enable all joystick pots if in test mode */ if (joyTest) joyMask = 0x0F; disable(); /* Disable interrupts for direct access */ outp(0x201, 0); /* Discharge joystick caps */ /* While limit > 0 and joystick caps not fully charged */ while (joyState = (inp(0x201) & joyMask)) { /* Test and increment joystick pot values */ joyPotVal[JsA_Xaxis] += joyState & 1; joyState >>= 1; joyPotVal[JsA_Yaxis] += joyState & 1; joyState >>= 1; joyPotVal[JsB_Xaxis] += joyState & 1; joyState >>= 1; joyPotVal[JsB_Yaxis] += joyState & 1; /* Count the loop limit, break if limit reached */ if (!(++limit)) break; } enable(); /* Re-enable interrupts */ if (joyTest) { /* Mask off caps with no corresponding pot values */ joyMask = (joyPotVal[JsA_Xaxis] != 0) << JsA_Xaxis | /* Bit 0 */ (joyPotVal[JsA_Yaxis] != 0) << JsA_Yaxis | /* Bit 1 */ (joyPotVal[JsB_Xaxis] != 0) << JsB_Xaxis | /* Bit 2 */ (joyPotVal[JsB_Yaxis] != 0) << JsB_Yaxis; /* Bit 3 */ } } else { regs.h.ah = 0x84; /* Joystick BIOS functions */ regs.x.dx = 0x01; /* Get joystick pot values */ /* Call BIOS to get the pot values */ int86(0x15, ®s, ®s); /* Store the registers returned as our pot values */ joyPotVal[JsA_Xaxis] = regs.x.ax; joyPotVal[JsA_Yaxis] = regs.x.bx; joyPotVal[JsB_Xaxis] = regs.x.cx; joyPotVal[JsB_Yaxis] = regs.x.dx; } } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\ * JoystickButtonPressed * * * * Samples the joystick buttons state and returns the desired bits * * determined by the bit mask (buttonMask). * * * * If you want to return the bits for all buttons, pass (JsAllButtons) * * to this function. * * * * The state of the desired bits is 1 if button is pressed, 0 if not. * \* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ int JoystickButtonPressed(int buttonMask) { union REGS regs; /* Declare register variable for BIOS call */ if (joystickDirectAccess) { /* Return the buttons state */ return ((~inp(0x201)) & buttonMask); } else { regs.h.ah = 0x84; /* Joystick BIOS functions */ regs.x.dx = 0x00; /* Read joystick buttons state */ /* Call BIOS to get the buttons state */ int86(0x15, ®s, ®s); /* Return the buttons state */ return ((~regs.h.al) & buttonMask); } }
The header file, JOYSTICK.H
, defines some useful constants for using these two
functions. When using the Joyin
function, you can identify the proper
joystick coordinates with the JsA_Xaxis
, JsA_Yaxis
, JsB_Xaxis
, and JsB_Yaxis
constants.
The constants used for the buttons allow you to specify and button of interest when using the
JoystickButtonPressed
function.
/* JOYSTICK.H -- by Gary Neal, Jr. (garyneal@oocities.com) * * Header file for our functions that provide joystick support. */ #ifndef __JOYSTICK_H /* Prevent multiple inclusions */ #define __JOYSTICK_H #include <dos.h> /* Needed for int86 functionality */ #include <conio.h> /* Needed for inp and outp functions */ /* Useful Joystick constants */ #define JsA_Xaxis 0 #define JsA_Yaxis 1 #define JsB_Xaxis 2 #define JsB_Yaxis 3 #define JsAbutton1 0x10 #define JsAbutton2 0x20 #define JsBbutton1 0x40 #define JsBbutton2 0x80 #define JsAllButtons 0xF0 /* Joystick potentiometer values */ extern unsigned short joyPotVal[4]; /* Flags if using BIOS or direct access for joystick interface */ extern char joystickDirectAccess; #ifdef __cplusplus /* Must be compiled C style */ extern "C" { #endif void Joyin(int joyTest); int JoystickButtonPressed(int buttonMask); #ifdef __cplusplus } #endif #endif /* __JOYSTICK_H */
This code allows you to wire the joystick control into your programs.
If you decide to use these functions, a few words of advice are in order.
First off, you should do an initial test of the joystick pots to see if the
joysticks are present. This is especially true if you plan to use
direct access to the joystick hardware itself
(joystickDirectAccess = 1
). If you plan to use the BIOS
interface to the joystick, then this initial test isn't necessary.
By performing the initial test, the Joyin
function can determine
which joysticks are present and which aren't and mask off those that are not
present. To perform the test, pass 1 to the 'Joyin
'
function like so:
Joyin(1); /* Test for the presence of the joysticks */
After that, you can immediately check to see if a joystick is present or
not by checking their pot values. If the joystick pot values are zero,
you can be almost certain that a joystick is not plugged in. Be careful,
if you decide to use the BIOS interface for accessing the joystick hardware
because some computers do not provide joystick BIOS extensions. This is
especially true on newer computers that rely on Windows to provide an
interface to the joysticks. If you are using the BIOS to get the
joystick pot values on a computer that does not provide the BIOS extensions
for accessing the joystick hardware, the pot values returned by Joyin
will be undefined.
Send your questions, comments, or ideas here.