📄 joystick.c
字号:
}
printf("\n");
/* line BEFORE WHICH left is stuffed */
calib[j][0] = centx[j] - ((centx[j] - minx[j]) / SEGMENTS);
/* line AFTER WHICH right is stuffed */
calib[j][1] = centx[j] + ((maxx[j] - centx[j]) / SEGMENTS);
/* line BEFORE WHICH up is stuffed */
calib[j][2] = centy[j] - ((centy[j] - miny[j]) / SEGMENTS);
/* line AFTER WHICH down is stuffed */
calib[j][3] = centy[j] + ((maxy[j] - centy[j]) / SEGMENTS);
return 1;
}
static void _readjoy(void)
{
/* Set flags for each joystick (directions and fire buttons) */
register int v;
register unsigned char st, j;
st = _readjport();
for (j = 0; j < 2; j++)
if (jready[j])
{
jstatus[j] = 0;
if (!(st & fire1[j]))
jstatus[j] |= JOY_AF;
if (!(st & fire2[j]))
jstatus[j] |= JOY_BF;
jstatus[j] |= _manualdir(j);
if (joymode) /* 4 buttons or 6 buttons */
{
v = j ? 0 : 1;
if (!(st & fire1[v]))
jstatus[j] |= JOY_CF;
if (!(st & fire2[v]))
jstatus[j] |= JOY_DF;
/*
** Buttons 5 and 6 are connected to directions on second joystick.
** Only one 6-button joystick can be connected, so we use jstatus[0]
** instead of jstatus[j].
*/
if (joymode == JOY_6BUTTONS)
{
v = _manualdir(1);
if (v & (JOY_UP | JOY_DN))
jstatus[0] |= JOY_EF;
if (v & (JOY_LT | JOY_RT))
jstatus[0] |= JOY_FF;
j = 2;
}
}
}
}
static unsigned char _joyready(const unsigned char j)
{
/*
** Probe joystick, returning 1 if it is present, 0 otherwise.
** Presence is determined in this way:
** - if position (x and y) and both fire buttons read through bios are 0,
** joystick is absent;
** - otherwise, it is present.
**
** If 'j' is 0, probes the first joystick; if 'j' is 1, probes the second.
*/
union REGS regs;
register int x, y, fa, fb;
/* Read position */
regs.h.ah = 0x84;
regs.x.dx = 1;
int86(0x15, ®s, ®s);
if (regs.x.cflag)
return 0; /* Error: joystick not found */
if (j)
{
x = regs.x.cx;
y = regs.x.dx;
}
else
{
x = regs.x.ax;
y = regs.x.bx;
}
/* Read fire buttons */
regs.h.ah = 0x84;
regs.x.dx = 0;
int86(0x15, ®s, ®s);
if (regs.x.cflag)
return 0; /* Error: joystick not found */
if (j)
{
fa = !GetBit(regs.x.ax, 6);
fb = !GetBit(regs.x.ax, 7);
}
else
{
fa = !GetBit(regs.x.ax, 4);
fb = !GetBit(regs.x.ax, 5);
}
if (x + y + fa + fb == 0)
return 0;
else
return 1;
}
static void _savecalib(const char *filename, const unsigned char njoy)
{
/*
** Store number of joysticks connected, joystick mode and
** calibration informations into filename (which is created
** or overwritten). No errors are reported; if filename is NULL,
** calibration is not saved.
*/
if (filename != NULL)
{
register int i, l;
int h;
struct calibrecord {
unsigned char njoy;
unsigned char joymode;
int calib[2][4];
} cr;
cr.njoy = njoy;
cr.joymode = joymode;
for (i = 0; i < 2; i++)
for (l = 0; l < 4; l++)
cr.calib[i][l] = calib[i][l];
h = open(filename, O_WRONLY | O_BINARY | O_CREAT | O_TRUNC, S_IWRITE);
if (h != -1)
{
write(h, (void *) &cr, sizeof(cr));
close(h);
}
}
}
static unsigned char _checkcalib(const unsigned char j)
{
/*
** Check if joystick j is centered, according to current calibration;
** returns JOY_FIRST or JOY_SECOND (according to j) if it needs to
** be re-calibrated, JOY_NONE otherwise.
** This routine does two checks, at one-second interval each:
** if both return joystick off-centered, the program assumes that
** calibration is needed.
*/
int try = 0;
unsigned int jstat;
retry:
_readjport();
jstat = _manualdir(j);
if (jstat)
if (try)
return j + 1;
else
{
delay(1000);
goto retry;
}
return JOY_NONE;
}
static unsigned char _loadcalib(const char *filename, const unsigned char njoy)
{
/*
** Load calibration and returns:
**
** JOY_NONE if mode and joy # are correct and joys appear centered
** JOY_FIRST if joy #1 must be re-calibrated
** JOY_SECOND if joy #2 must be re-calibrated
** JOY_BOTH if both joys need to be re-calibrated
*/
if (filename != NULL)
{
int h, i, l;
unsigned char oldnjoy;
struct calibrecord {
unsigned char njoy;
unsigned char joymode;
int calib[2][4];
} cr;
h = open(filename, O_RDONLY | O_BINARY, S_IREAD);
/* File not found: re-calibration */
if (h == -1)
return njoy;
/* Wrong size: remove file and force re-calibration */
if (filelength(h) != sizeof(cr))
{
close(h);
remove(filename);
return njoy;
}
l = read(h, (void *) &cr, sizeof(cr)) != sizeof(cr);
close(h);
/* Error reading: re-calibration */
if (l)
return njoy;
/* Mode incompatibility: re-calibration */
if ((joymode == JOY_6BUTTONS && cr.joymode != JOY_6BUTTONS) ||
(cr.joymode == JOY_6BUTTONS && joymode != JOY_6BUTTONS))
return njoy;
/* Different number of joysticks: re-calibration for only the new joystick */
oldnjoy = njoy;
for (i = 0; i < 2; i++)
for (l = 0; l < 4; l++)
calib[i][l] = cr.calib[i][l];
if (oldnjoy != cr.njoy)
{
unsigned char t = 0;
for (i = 1; i < 3; i++)
if ((oldnjoy & i) && (cr.njoy & i))
t |= _checkcalib(i - 1);
else
if (oldnjoy & i)
t |= i;
return t;
}
return JOY_NONE;
}
else
return njoy; /* NULL file specified: re-calibration */
}
/****************************************************************************/
/******************* External functions: joystick interface *****************/
/****************************************************************************/
unsigned char InstallJoystick(const unsigned char mode, const unsigned char skipjoy, const char *calibfile)
{
/*
** This function checks and returns the number of installed joysticks.
**
** 'mode' can be:
**
** JOY_2BUTTONS 2-buttons joysticks (one or two)
** JOY_4BUTTONS 4-buttons joysticks (one or two)
** JOY_6BUTTONS 6-buttons joystick (only one)
**
** 'skipjoy' can be:
**
** JOY_NONE all joysticks present are installed and calibrated
** JOY_FIRST skip installation/calibration for first joystick
** JOY_SECOND skip installation/calibration for second joystick
**
** Most of the times, skipjoy will be JOY_NONE (all joysticks installed
** and calibrated) or JOY_SECOND (only first joystick is installed and
** calibrated, e.g. when your program uses just one joystick).
**
** 'calibfile' is the name of the file from which calibration must be
** loaded (if exists) or to which it will be saved (if does NOT exist).
** If 'calibfile' is NULL, calibration won't be saved, i.e. the user will
** have to calibrate joystick(s) at each run.
** If 'mode' is JOY_2BUTTONS or JOY_4BUTTONS and mode determined from
** configuration file is JOY_6BUTTONS (or viceversa), calibration will be
** forced; the same will happen if number of joysticks connected is
** different or if the calibration appears incorrect.
** If calibration is aborted for one joystick, that joystick will be
** reported as not connected (it will be re-calibrated the next time you
** run the program).
**
** Values returned
** JOY_NONE if no joystick is installed
** JOY_FIRST if only joystick 1 is installed
** JOY_SECOND if only joystick 2 is installed
** JOY_BOTH if both joysticks (or one 6-buttons joystick) are installed
**
** Central values are set at current position.
*/
register unsigned char retval = 0, j;
unsigned char j2calib;
joymode = mode;
/* Determine joysticks attached */
for (j = 0; j < 2; j++)
if ((jready[j] = _joyready(j)) != 0)
retval += j + 1;
/* Revert to 4-buttons mode if 6-buttons joystick not found */
if (joymode == JOY_6BUTTONS && retval < JOY_BOTH)
joymode = JOY_4BUTTONS;
/* Prompt the user to calibrate joystick(s) */
j2calib = _loadcalib(calibfile, retval);
for (j = 0; j < 2; j++)
{
if ((skipjoy & (j + 1)) || (jready[j] && (j2calib & (j + 1)) && !_usercalib(j)))
{
jready[j] = 0;
retval -= j + 1;
}
/* No need to calibrate second (virtual) joystick when in 6-buttons mode */
if (joymode == JOY_6BUTTONS)
j = 2;
}
if (retval)
_savecalib(calibfile, retval);
return retval;
}
void ReadJoystick(unsigned int *first, unsigned int *second)
{
/*
** Read both joysticks, returning into "first" and "second" an
** unsigned integer with the following flags set:
**
** JOY_UP Joystick moved up
** JOY_DN Joystick moved down
** JOY_LT Joystick moved to left
** JOY_RT Joystick moved to right
** JOY_AF Button 1 pressed
** JOY_BF Button 2 pressed
** JOY_CF Button 3 pressed (joymode = JOY_4BUTTONS or JOY_6BUTTONS)
** JOY_DF Button 4 pressed (joymode = JOY_4BUTTONS or JOY_6BUTTONS)
** JOY_EF Button 5 pressed (joymode = JOY_6BUTTONS)
** JOY_FF Button 6 pressed (joymode = JOY_6BUTTONS)
**
** If a NULL pointer is passed, no data is stored (useful if data
** for only one joystick are needed).
*/
_readjoy();
if (first)
*first = jstatus[0];
if (second)
*second = jstatus[1];
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -