📄 joystick.c
字号:
/*
** Joystick routines.
**
** This file is part of:
**
** Joystick Library for Dos.
** Version: 1.1
**
** Last modified: June 15th, 1997
**
** (C) 1997 Simone Zanella Productions.
**
** E-mail: szanella@dsi.unive.it
** zanella@prometeo.it
**
** Web: http://www.dsi.unive.it/~szanella/index.htm
** http://members.tripod.com/~szanella/index.htm
**
** Changes from version 1.0:
**
** - changed calibration to manual, to avoid incompatibilities and
** to get a faster reading;
** - added support for 4 and 6 buttons joysticks;
** - added parameter mode to function InstallJoystick, to set
** the number of buttons for joysticks;
** - added parameter skipjoy to function InstallJoystick, to skip
** installation/calibration of one joystick;
** - added parameter calibfile to function InstallJoystick, to
** allow calibration saving/reloading;
** - changed to integer parameters 'first' and 'second' in function
** ReadJoystick, to keep flags for fire buttons 5 and 6;
** - removed tolerances from function InstallJoystick.
**
** --------------------------------------------------------
**
** This is freeware: use it as you like, but ALWAYS include
** the original author's name in the docs of your program.
**
** --------------------------------------------------------
**
** Usage:
**
** - include "joystick.h" at the beginning of your program and
** compile and link the module "joystick.c"
**
** - at program startup, use:
**
** unsigned char j, mode;
**
** // Set mode to the kind of joystick requested:
** // JOY_2BUTTONS standard 2-buttons joysticks
** // JOY_4BUTTONS 4-buttons joysticks (fire 3 and 4 are other joystick's
** // fire buttons)
** // JOY_6BUTTONS 6-buttons joystick (fire 3 & 4 as above, fire 5 and 6
** // connected to joystick #2 directions)
** //
** // Set calibfile to the name of a file to be used for saving/reloading
** // calibration (NULL to force re-calibration at each run).
** //
** // Set skipjoy to:
** // JOY_NONE if all joysticks connected should be detected and calibrated;
** // JOY_SECOND if only first joystick is used and thus should be calibrated.
**
** j = InstallJoystick(mode, skipjoy, calibfile);
**
** - use the value j to determine number of joysticks connected:
**
** j & JOY_FIRST first joystick is present
** j & JOY_SECOND second joystick is present
** j & JOY_BOTH both joysticks present (or one 6-buttons joystick)
**
** - when you want to read the joystick(s), use:
**
** unsigned int fj, sj;
**
** ReadJoystick(&fj, &sj);
**
** Then, you can determine if a direction is activated by:
**
** fj & JOY_xx
**
** where "xx" can be: UP, DN (down), LT (left), RT (right)
**
** You can test the fire buttons in a similar way:
**
** fj & JOY_AF first button
** fj & JOY_BF second button
** fj & JOY_CF third button (only when mode = JOY_4BUTTONS)
** fj & JOY_DF fourth button (only when mode = JOY_4BUTTONS)
** fj & JOY_EF fifth button (only joystick 1, when mode = JOY_6BUTTONS)
** fj & JOY_FF sixth button (only joystick 1, when mode = JOY_6BUTTONS)
**
** Of course, replace "fj" above with "sj" to test second joystick.
**
** If you want to poll joystick at regular intervals, you can chain the
** system timer (int 8).
*/
#include "joystick.h"
#include <stdlib.h>
#include <dos.h>
#include <limits.h>
#include <conio.h>
#include <io.h>
#include <fcntl.h>
#include <stat.h>
#include <stdio.h>
/*
#ifndef __BORLANDC__
#include <pc.h>
#endif
*/
#define JOYPORT 0x201
/* Number of divisions, for determining thresholds */
#define SEGMENTS 2
/* Tolerance, to determine direction on 6-buttons joysticks */
#define JOY_TOL 100
/* Constant for timed joy reading */
#define JOYCOUNTER 60000
/* Pseudo-functions */
#define GetBit(c, n) ( c & ( 1 << (n) ) )
/* Static variables used for storing:
** - x and y coordinates;
** - threshold values;
** - status (ready/not ready);
** - mode (2, 4 or 6 buttons);
** - flags.
*/
static int x[2], y[2], calib[2][4];
static unsigned char jready[2], joymode = JOY_2BUTTONS;
static unsigned int jstatus[2];
/* Maps for fire buttons (internal) */
static unsigned char fire1[2] = {16, 64};
static unsigned char fire2[2] = {32, 128};
/****************************************************************************/
/************** Internal functions: should NOT be called by user ************/
/****************************************************************************/
static unsigned char _readjport(void)
{
/*
** Read joystick port, setting x and y coordinates for each joystick;
** the status of the 4 buttons is returned.
*/
register long count;
register unsigned char st, mask;
mask = 0;
if (jready[0])
mask |= 3;
if (jready[1])
mask |= 12;
count = x[0] = y[0] = x[1] = y[1] = 0;
disable();
/* Read port for JOYCOUNTER cycles */
/* Don't count previous reading (VERY FAST machines) */
do st = inportb(JOYPORT);
while (st & mask);
outportb(JOYPORT, 0xFF);
do
{
st = inportb(JOYPORT);
if (st & 1)
x[0]++;
if (st & 2)
y[0]++;
if (st & 4)
x[1]++;
if (st & 8)
y[1]++;
count++;
} while ((st & mask) && count <= JOYCOUNTER);
enable();
return st;
}
static unsigned char _readjbutton(const unsigned char j)
{
/*
** Read joystick, returning 0 if no fire button is pressed.
*/
register unsigned char st, mask, pressed;
if (j)
mask = 12;
else
mask = 3;
outportb(JOYPORT, 0xFF);
st = inportb(JOYPORT);
pressed = (j) ? (!(st & 64) || !(st & 128)) : (!(st & 16) || !(st & 32));
while (st & mask)
st = inportb(JOYPORT);
return pressed;
}
static unsigned char _readjpos(const unsigned char j)
{
/*
** Wait for the user to press a joystick button, then read joystick
** port; return 0 if user aborted calibration.
*/
delay(1000);
/* Wait for button pressed */
while (!_readjbutton(j))
if (kbhit())
if (getch() == 0x1B)
return 0;
_readjport();
/* Wait for button released */
while (_readjbutton(j));
return 1;
}
static unsigned int _manualdir(const unsigned char j)
{
/*
** Direction check for manual calibration.
*/
register unsigned int jstat = 0;
if (x[j] < calib[j][0])
jstat |= JOY_LT; /* Left */
else
jstat |= (x[j] > calib[j][1]) ? JOY_RT : 0; /* Right or center */
if (y[j] < calib[j][2])
jstat |= JOY_UP; /* Up */
else
jstat |= (y[j] > calib[j][3]) ? JOY_DN : 0; /* Down or center */
return jstat;
}
unsigned char _usercalib(const unsigned char j)
{
/*
** Print out messages for performing manual calibration for joystick j;
** set calibration values and return 1 if successfull, 0 if user aborted.
*/
unsigned char i, l;
int centx[2], centy[2], minx[2], maxx[2], miny[2], maxy[2];
int ocentx, ocenty;
char *msg[]={"Center stick and press a button (Esc abort)...",
"Move stick to upper left and press a button (Esc abort)...",
"Move stick to lower right and press a button (Esc abort)...",
"While pressing button 5, press button 1 or 2 (Esc abort)...",
"While pressing button 6, press button 1 or 2 (Esc abort)..."};
printf("Calibration of joystick %d..\n", j + 1);
for (i = 0; i < 3; i++)
{
printf(msg[i]);
#ifndef __BORLANDC__
fflush(stdout);
#endif
l = _readjpos(j);
printf("\n");
if (!l)
return 0;
/* Insert values for center, maximum, minimum variables */
switch (i)
{
case 0:
centx[j] = x[j];
centy[j] = y[j];
ocentx = x[1];
ocenty = y[1];
break;
case 1:
minx[j] = x[j];
miny[j] = y[j];
break;
default:
maxx[j] = x[j];
maxy[j] = y[j];
break;
}
}
if (joymode == JOY_6BUTTONS)
{
unsigned int jstat;
for (i = 0; i < 2; i++)
{
/* We must calibrate pseudo-directions corresponding to buttons 5 and 6 */
printf(msg[3 + i]);
#ifndef __BORLANDC__
fflush(stdout);
#endif
delay(1000);
retry:
/* Wait for button pressed */
while (!_readjbutton(j))
if (kbhit())
if (getch() == 0x1B)
return 0;
_readjport();
jstat = 0;
if (x[1] < ocentx - JOY_TOL)
jstat |= JOY_LT; /* Left */
else
jstat |= (x[1] > ocentx + JOY_TOL) ? JOY_RT : 0; /* Right or center */
if (y[1] < ocenty - JOY_TOL)
jstat |= JOY_UP; /* Up */
else
jstat |= (y[1] > ocenty + JOY_TOL) ? JOY_DN : 0; /* Down or center */
/* Wait for button released */
while (_readjbutton(j));
if (jstat & (i ? (JOY_LT | JOY_RT) : (JOY_UP | JOY_DN)))
if (i) /* Button 6: can be LEFT or RIGHT */
if (x[1] > ocentx) /* Button corresponds to RIGHT */
{
calib[1][1] = ocentx + ((x[1] - ocentx) / SEGMENTS);
calib[1][0] = INT_MIN;
}
else /* Button corresponds to LEFT */
{
calib[1][1] = INT_MAX;
calib[1][0] = ocentx - ((ocentx - x[1]) / SEGMENTS);
}
else /* Button 5: can be UP or DOWN */
if (y[1] > ocenty) /* Button corresponds to DOWN */
{
calib[1][3] = ocenty + ((y[1] - ocenty) / SEGMENTS);
calib[1][2] = INT_MIN;
}
else /* Button corresponds to UP */
{
calib[1][3] = INT_MAX;
calib[1][2] = ocenty - ((ocenty - y[1]) / SEGMENTS);
}
else
goto retry;
printf("\n");
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -