www.pudn.com > joysrc > JOY.C


/*====================================================================*/ 
/*                                                                    */ 
/*  NOTE: Ensure this program is compiled for LARGE model.            */ 
/*        Non-ANSI stuff is pertinent to Microsoft QuickC v2.5.       */ 
/*        Porting to another compiler should not be too hard!         */ 
/*                                                                    */ 
/*====================================================================*/ 
 
#include  
#include  
#include  
#include  
#include  
 
#define FALSE         0 
#define TRUE          1 
 
#define FIRE_BUTTON1  0x01 
#define FIRE_BUTTON2  0x02 
 
#define BLACK         0         /*  Std colour for black in default palette  */ 
#define WHITE         15        /*  Std colour for white in default palette  */ 
 
typedef unsigned char BOOL; 
typedef unsigned char BYTE; 
 
/*  NB: Most of the functions below are to aid in the demonstration of the  */ 
/*  joystick routines. They are quick and simple - no effort has been made  */ 
/*  to make them efficient. Feel free to modify them as you require!        */ 
 
BYTE *pVideo=(BYTE *)0xA0000000L;       /*  Ptr to base of VGA video RAM  */ 
 
void SetVideoMode( int nMode ) 
{ 
    /*  Simple routine to set the video mode using the BIOS video interrupt  */ 
 
    _asm    mov ah, 00H 
    _asm    mov al, byte ptr nMode 
    _asm    int 10H 
} 
 
void SetPixel( int x, int y, int colour ) 
{ 
    /*  Very simple (inefficient) way of setting a pixel colour  */ 
 
    *(pVideo+(unsigned)y*320U+(unsigned)x) = (BYTE)colour; 
} 
 
void DrawCross( int cx, int cy, int colour ) 
{ 
    /*  Simple function to draw a 'cross-hair' cursor.  */ 
 
#define XWTH    4       /*  Aspect ration in 320x200 is approx 3/4  */ 
#define YHT     3 
 
    int     x, y; 
 
    if ( cx>=0 && cx<320 ) 
    { 
        for ( y=cy-YHT; y<=cy+YHT; y++ ) 
        { 
            if ( y>=0 && y<200 ) SetPixel( cx,y,colour ); 
        } 
    } 
 
    if ( cy>=0 && cy<200 ) 
    { 
        for ( x=cx-XWTH; x<=cx+XWTH; x++ ) 
        { 
            if ( x>=0 && x<320 ) SetPixel(x,cy,colour); 
        } 
    } 
} 
 
void SetCursorPos( int col, int row ) 
{ 
    /*  Even though we will be in graphics mode we can ask the video BIOS  */ 
    /*  to set our cursor position for displaying text...                  */ 
 
    _asm    mov ah, 02H 
    _asm    mov bh, 00H 
    _asm    mov dl, byte ptr col 
    _asm    mov dh, byte ptr row 
    _asm    int 10H 
} 
 
/*=========================================================================== 
 
    This text is taken from the RUTILS v2.0 manual: 
 
         These two functions allow an application to interrogate the 
         GAME port onto which up to two joysticks may be connected. 
         These two joysticks are numbered 1 and 2 and are serviced by 
         joystick_1() and joystick_2() respectively. Although these 
         functions return x and y count positions of the joystick the 
         values are NOT measured in screen or any other fixed units. In 
         fact, they are PC dependant timing values which will differ 
         from PC to PC. What this basically means is that an application 
         will need to CALIBRATE the joystick functions before any of the 
         results can be interpreted correctly. The calibration procedure 
         involves the determination of the minimum and maximum x and y 
         counts for joystick movement. This can really only be done by 
         asking the user to move the joystick to the top left and bottom 
         right respectively. In fact, some games ask the user to do this 
         and press the fire button to confirm the action. Once these 
         minimum and maximum values are known it is then a simple matter 
         of scaling the range to fit the required screen (pixel) 
         coordinates. The calibration procedure need only be performed 
         for one joystick. 
 
     Return Value: 
 
         An integer representing a bit mask comprising of FIRE_BUTTON_1 
         and/or FIRE_BUTTON_2. Each joystick has two fire buttons. If 
         neither button is pressed 0 is returned. 
 
     Example: 
 
         The following shows how to calibrate a joystick: 
 
         int  min_x,min_y,max_x,max_y; 
         ... 
         prints( "Move joystick to upper left & press FIRE\n\r",L_GREY,0 ); 
         while ( !joystick_1(&min_x,&min_y) ); 
         ... 
         prints( "Move joystick to lower right & press FIRE\n\r",L_GREY,0 ); 
         while ( !joystick_1(&max_x,&max_y) ); 
         ... 
 
 
         To scale a joystick "count" reading (j_x,j_y) to a pixel 
         position on a graphics screen the following equations can be 
         used: 
 
         pixel_x = (j_x - min_x) * (VS.mx+1) / (max_x - min_x); 
         pixel_y = (j_y - min_y) * (VS.my+1) / (max_y - min_y); 
 
==============================================================================*/ 
 
int joystick_1( int *xc, int *yc ) 
{ 
    /*  Examine joystick 1  */ 
 
    unsigned int    i, count=0; 
    unsigned char   state; 
 
    *xc=*yc=0; 
 
    _asm    mov dx, 0201H 
    _asm    mov al, 0FFH 
    _asm    out dx, al 
 
    do 
    { 
        _asm    mov dx, 0201H 
        _asm    in  al, dx 
        _asm    mov state, al 
        if ( state&0x01 ) *xc=count; 
        if ( state&0x02 ) *yc=count; 
        count++; 
    } 
    while ( state&0x03 && count<65535U ); 
 
    return( (int) ((state>>4)&0x03)^0x03 ); 
} 
 
int joystick_2( int *xc, int *yc ) 
{ 
    /*  Examine joystick 2  */ 
 
    unsigned int    i, count=0; 
    unsigned char   state; 
 
    *xc=*yc=0; 
 
    _asm    mov dx, 0201H 
    _asm    mov al, 0FFH 
    _asm    out dx, al 
 
    do 
    { 
        _asm    mov dx, 0201H 
        _asm    in  al, dx 
        _asm    mov state, al 
        if ( state&0x04 ) *xc=count; 
        if ( state&0x08 ) *yc=count; 
        count++; 
    } 
    while ( state&0x0c && count<65535U ); 
 
    return( (int) (state>>6)^0x03 ); 
} 
 
/*========================= main program ====================================*/ 
 
void main( void ) 
{ 
    int     min_x, min_y, max_x, max_y, jx, jy, lastjx=-99, lastjy=-99; 
 
    printf( "\n\nJoystick Demo\n=============\n\nPress ESCape at any time to abort\n\n" ); 
 
    /*  Calibrate the joystick by finding its lowest and highest values  */ 
 
    printf( "Calibrating:\n\nMove joystick to top left and press a fire button" ); 
 
    while ( !joystick_1(&min_x,&min_y) ) 
    { 
        if ( kbhit() && getch()==27 ) exit( 1 ); 
    } 
 
    /*  Ensure button released before we do next one. On a fast machine the  */ 
    /*  following loop will exit almost immediately 'cos the user hasn't     */ 
    /*  lifted his finger off the button yet...                              */ 
 
    while ( joystick_1(&jx,&jy) ) 
    { 
        if ( kbhit() && getch()==27 ) exit( 1 ); 
    } 
 
    printf( "\n\nMove joystick to bottom right and press a fire button" ); 
 
    while ( !joystick_1(&max_x,&max_y) ) 
    { 
        if ( kbhit() && getch()==27 ) exit( 1 ); 
    } 
 
    /*  Check for invalid range of values or idiot user(!)  */ 
 
    if ( min_x>=max_x || min_y>=max_y ) 
    { 
        printf( "\n\nWooah! Wonky joystick dude!\n" ); 
        exit( 1 ); 
    } 
 
    /*  Start the demo  */ 
 
    SetVideoMode( 0x13 );       /*  Set the magic 320x200x256 linear graphics mode  */ 
 
    while ( 1 ) 
    { 
        int     buttons=joystick_1( &jx,&jy ); 
 
        /*  Check for exit  */ 
 
        if ( kbhit() && getch()==27 ) break; 
 
        /*  Convert to pixel values  */ 
 
        if ( jxmax_x ) jx=max_x; 
        if ( jymax_y ) jy=max_y; 
 
        jx = (int)((long)(jx-min_x)*320L / (long)(max_x-min_x)); 
        jy = (int)((long)(jy-min_y)*200L / (long)(max_y-min_y)); 
 
        /*  If changed from last position, update the cross hairs  */ 
 
        if ( lastjx!=jx || lastjy!=jy ) 
        { 
            /*  Erase the original if required  */ 
 
            if ( lastjx!=-99 ) DrawCross(lastjx,lastjy,BLACK); 
 
            /*  Now draw the new position and record it for later  */ 
 
            DrawCross( lastjx=jx,lastjy=jy,WHITE ); 
        } 
 
        /*  Special POW! effect when a button pressed  */ 
 
        if ( buttons ) 
        { 
            /* Convert pixel values to character positions. In 320x200, BIOS */ 
            /* font is 8x8 pixels in size...                                 */ 
 
            int     cx=jx/8-2, cy=jy/8, tx, ty; 
 
            /*  Display POW!  */ 
 
            SetCursorPos( cx,cy ); 
            printf( "%s",(buttons&FIRE_BUTTON1?"Pow1":"Pow2") ); 
 
            /*  Wait for the button to be released  */ 
 
            while ( joystick_1(&tx,&ty) ); 
 
            /*  Remove POW! message and redraw cross hairs  */ 
 
            SetCursorPos( cx,cy ); 
            printf( "    " ); 
            DrawCross( lastjx,lastjy,WHITE ); 
        } 
    } 
 
    /*  Restore normal 80x25 text mode  */ 
 
    SetVideoMode( 0x03 ); 
 
    printf( "Joystick Demo Coded by CyberFrog 8:)\n\n" ); 
    printf( "Min Values: %u,%u\n",min_x,min_y ); 
    printf( "Max Values: %u,%u\n",max_x,max_y ); 
}