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 ( jx max_x ) jx=max_x; if ( jy max_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 ); }