/* | |
Copyright (C) 1996-1997 Id Software, Inc. | |
This program is free software; you can redistribute it and/or | |
modify it under the terms of the GNU General Public License | |
as published by the Free Software Foundation; either version 2 | |
of the License, or (at your option) any later version. | |
This program is distributed in the hope that it will be useful, | |
but WITHOUT ANY WARRANTY; without even the implied warranty of | |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | |
See the GNU General Public License for more details. | |
You should have received a copy of the GNU General Public License | |
along with this program; if not, write to the Free Software | |
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |
*/ | |
// in_mouse.c -- dos mouse code | |
#include "quakedef.h" | |
#include "dosisms.h" | |
#define AUX_FLAG_FREELOOK 0x00000001 | |
typedef struct | |
{ | |
long interruptVector; | |
char deviceName[16]; | |
long numAxes; | |
long numButtons; | |
long flags; | |
vec3_t viewangles; | |
// intended velocities | |
float forwardmove; | |
float sidemove; | |
float upmove; | |
long buttons; | |
} externControl_t; | |
/* | |
#define AUX_FLAG_FORCEFREELOOK 0x00000001 // r/o | |
#define AUX_FLAG_EXTENDED 0x00000002 // r/o | |
#define AUX_FLAG_RUN 0x00000004 // w/o | |
#define AUX_FLAG_STRAFE 0x00000008 // w/o | |
#define AUX_FLAG_FREELOOK 0x00000010 // w/o | |
#define AUX_MAP_UNDEFINED 0 | |
#define AUX_MAP_PITCH 1 | |
#define AUX_MAP_YAW 2 | |
#define AUX_MAP_ROLL 3 | |
#define AUX_MAP_FORWARD 4 | |
#define AUX_MAP_SIDE 5 | |
#define AUX_MAP_UP 6 | |
typedef struct | |
{ | |
long interruptVector; | |
// r/o | |
char deviceName[16]; | |
// r/o | |
long numAxes; | |
// r/o 1-6 | |
long numButtons; // r/o 0-32 | |
long flags; // see above | |
byte axisMapping[6]; // w/o default = p,y,r,f,s,u | |
float axisValue[6]; // r/w | |
float sensitivity[6]; // w/o default = 1.0 | |
long buttons; // r/o | |
float last_frame_time; // w/o | |
} externControl_t; | |
*/ | |
cvar_t m_filter = {"m_filter","1"}; | |
qboolean mouse_avail; | |
int mouse_buttons; | |
int mouse_oldbuttonstate; | |
int mouse_buttonstate; | |
float mouse_x, mouse_y; | |
float old_mouse_x, old_mouse_y; | |
cvar_t in_joystick = {"joystick","1"}; | |
cvar_t joy_numbuttons = {"joybuttons","4", true}; | |
qboolean joy_avail; | |
int joy_oldbuttonstate; | |
int joy_buttonstate; | |
int joyxl, joyxh, joyyl, joyyh; | |
int joystickx, joysticky; | |
qboolean need_center; | |
qboolean extern_avail; | |
int extern_buttons; | |
int extern_oldbuttonstate; | |
int extern_buttonstate; | |
cvar_t aux_look = {"auxlook","1", true}; | |
externControl_t *extern_control; | |
void IN_StartupExternal (void); | |
void IN_ExternalMove (usercmd_t *cmd); | |
void IN_StartupJoystick (void); | |
qboolean IN_ReadJoystick (void); | |
void Toggle_AuxLook_f (void) | |
{ | |
if (aux_look.value) | |
Cvar_Set ("auxlook","0"); | |
else | |
Cvar_Set ("auxlook","1"); | |
} | |
void Force_CenterView_f (void) | |
{ | |
cl.viewangles[PITCH] = 0; | |
} | |
/* | |
=========== | |
IN_StartupMouse | |
=========== | |
*/ | |
void IN_StartupMouse (void) | |
{ | |
if ( COM_CheckParm ("-nomouse") ) | |
return; | |
// check for mouse | |
regs.x.ax = 0; | |
dos_int86(0x33); | |
mouse_avail = regs.x.ax; | |
if (!mouse_avail) | |
{ | |
Con_Printf ("No mouse found\n"); | |
return; | |
} | |
mouse_buttons = regs.x.bx; | |
if (mouse_buttons > 3) | |
mouse_buttons = 3; | |
Con_Printf("%d-button mouse available\n", mouse_buttons); | |
} | |
/* | |
=========== | |
IN_Init | |
=========== | |
*/ | |
void IN_Init (void) | |
{ | |
int i; | |
Cvar_RegisterVariable (&m_filter); | |
Cvar_RegisterVariable (&in_joystick); | |
Cvar_RegisterVariable (&joy_numbuttons); | |
Cvar_RegisterVariable (&aux_look); | |
Cmd_AddCommand ("toggle_auxlook", Toggle_AuxLook_f); | |
Cmd_AddCommand ("force_centerview", Force_CenterView_f); | |
IN_StartupMouse (); | |
IN_StartupJoystick (); | |
i = COM_CheckParm ("-control"); | |
if (i) | |
{ | |
extern_control = real2ptr(Q_atoi (com_argv[i+1])); | |
IN_StartupExternal (); | |
} | |
} | |
/* | |
=========== | |
IN_Shutdown | |
=========== | |
*/ | |
void IN_Shutdown (void) | |
{ | |
} | |
/* | |
=========== | |
IN_Commands | |
=========== | |
*/ | |
void IN_Commands (void) | |
{ | |
int i; | |
if (mouse_avail) | |
{ | |
regs.x.ax = 3; // read buttons | |
dos_int86(0x33); | |
mouse_buttonstate = regs.x.bx; | |
// perform button actions | |
for (i=0 ; i<mouse_buttons ; i++) | |
{ | |
if ( (mouse_buttonstate & (1<<i)) && | |
!(mouse_oldbuttonstate & (1<<i)) ) | |
{ | |
Key_Event (K_MOUSE1 + i, true); | |
} | |
if ( !(mouse_buttonstate & (1<<i)) && | |
(mouse_oldbuttonstate & (1<<i)) ) | |
{ | |
Key_Event (K_MOUSE1 + i, false); | |
} | |
} | |
mouse_oldbuttonstate = mouse_buttonstate; | |
} | |
if (joy_avail) | |
{ | |
joy_buttonstate = ((dos_inportb(0x201) >> 4)&15)^15; | |
// perform button actions | |
for (i=0 ; i<joy_numbuttons.value ; i++) | |
{ | |
if ( (joy_buttonstate & (1<<i)) && | |
!(joy_oldbuttonstate & (1<<i)) ) | |
{ | |
Key_Event (K_JOY1 + i, true); | |
} | |
if ( !(joy_buttonstate & (1<<i)) && | |
(joy_oldbuttonstate & (1<<i)) ) | |
{ | |
Key_Event (K_JOY1 + i, false); | |
} | |
} | |
joy_oldbuttonstate = joy_buttonstate; | |
} | |
if (extern_avail) | |
{ | |
extern_buttonstate = extern_control->buttons; | |
// perform button actions | |
for (i=0 ; i<extern_buttons ; i++) | |
{ | |
if ( (extern_buttonstate & (1<<i)) && | |
!(extern_oldbuttonstate & (1<<i)) ) | |
{ | |
Key_Event (K_AUX1 + i, true); | |
} | |
if ( !(extern_buttonstate & (1<<i)) && | |
(extern_oldbuttonstate & (1<<i)) ) | |
{ | |
Key_Event (K_AUX1 + i, false); | |
} | |
} | |
extern_oldbuttonstate = extern_buttonstate; | |
} | |
} | |
/* | |
=========== | |
IN_Move | |
=========== | |
*/ | |
void IN_MouseMove (usercmd_t *cmd) | |
{ | |
int mx, my; | |
if (!mouse_avail) | |
return; | |
regs.x.ax = 11; // read move | |
dos_int86(0x33); | |
mx = (short)regs.x.cx; | |
my = (short)regs.x.dx; | |
if (m_filter.value) | |
{ | |
mouse_x = (mx + old_mouse_x) * 0.5; | |
mouse_y = (my + old_mouse_y) * 0.5; | |
} | |
else | |
{ | |
mouse_x = mx; | |
mouse_y = my; | |
} | |
old_mouse_x = mx; | |
old_mouse_y = my; | |
mouse_x *= sensitivity.value; | |
mouse_y *= sensitivity.value; | |
// add mouse X/Y movement to cmd | |
if ( (in_strafe.state & 1) || (lookstrafe.value && (in_mlook.state & 1) )) | |
cmd->sidemove += m_side.value * mouse_x; | |
else | |
cl.viewangles[YAW] -= m_yaw.value * mouse_x; | |
if (in_mlook.state & 1) | |
V_StopPitchDrift (); | |
if ( (in_mlook.state & 1) && !(in_strafe.state & 1)) | |
{ | |
cl.viewangles[PITCH] += m_pitch.value * mouse_y; | |
if (cl.viewangles[PITCH] > 80) | |
cl.viewangles[PITCH] = 80; | |
if (cl.viewangles[PITCH] < -70) | |
cl.viewangles[PITCH] = -70; | |
} | |
else | |
{ | |
if ((in_strafe.state & 1) && noclip_anglehack) | |
cmd->upmove -= m_forward.value * mouse_y; | |
else | |
cmd->forwardmove -= m_forward.value * mouse_y; | |
} | |
} | |
/* | |
=========== | |
IN_JoyMove | |
=========== | |
*/ | |
void IN_JoyMove (usercmd_t *cmd) | |
{ | |
float speed, aspeed; | |
if (!joy_avail || !in_joystick.value) | |
return; | |
IN_ReadJoystick (); | |
if (joysticky > joyyh*2 || joystickx > joyxh*2) | |
return; // assume something jumped in and messed up the joystick | |
// reading time (win 95) | |
if (in_speed.state & 1) | |
speed = cl_movespeedkey.value; | |
else | |
speed = 1; | |
aspeed = speed*host_frametime; | |
if (in_strafe.state & 1) | |
{ | |
if (joystickx < joyxl) | |
cmd->sidemove -= speed*cl_sidespeed.value; | |
else if (joystickx > joyxh) | |
cmd->sidemove += speed*cl_sidespeed.value; | |
} | |
else | |
{ | |
if (joystickx < joyxl) | |
cl.viewangles[YAW] += aspeed*cl_yawspeed.value; | |
else if (joystickx > joyxh) | |
cl.viewangles[YAW] -= aspeed*cl_yawspeed.value; | |
cl.viewangles[YAW] = anglemod(cl.viewangles[YAW]); | |
} | |
if (in_mlook.state & 1) | |
{ | |
if (m_pitch.value < 0) | |
speed *= -1; | |
if (joysticky < joyyl) | |
cl.viewangles[PITCH] += aspeed*cl_pitchspeed.value; | |
else if (joysticky > joyyh) | |
cl.viewangles[PITCH] -= aspeed*cl_pitchspeed.value; | |
} | |
else | |
{ | |
if (joysticky < joyyl) | |
cmd->forwardmove += speed*cl_forwardspeed.value; | |
else if (joysticky > joyyh) | |
cmd->forwardmove -= speed*cl_backspeed.value; | |
} | |
} | |
/* | |
=========== | |
IN_Move | |
=========== | |
*/ | |
void IN_Move (usercmd_t *cmd) | |
{ | |
IN_MouseMove (cmd); | |
IN_JoyMove (cmd); | |
IN_ExternalMove (cmd); | |
} | |
/* | |
============================================================================ | |
JOYSTICK | |
============================================================================ | |
*/ | |
qboolean IN_ReadJoystick (void) | |
{ | |
int b; | |
int count; | |
joystickx = 0; | |
joysticky = 0; | |
count = 0; | |
b = dos_inportb(0x201); | |
dos_outportb(0x201, b); | |
// clear counters | |
while (++count < 10000) | |
{ | |
b = dos_inportb(0x201); | |
joystickx += b&1; | |
joysticky += (b&2)>>1; | |
if ( !(b&3) ) | |
return true; | |
} | |
Con_Printf ("IN_ReadJoystick: no response\n"); | |
joy_avail = false; | |
return false; | |
} | |
/* | |
============= | |
WaitJoyButton | |
============= | |
*/ | |
qboolean WaitJoyButton (void) | |
{ | |
int oldbuttons, buttons; | |
oldbuttons = 0; | |
do | |
{ | |
key_count = -1; | |
Sys_SendKeyEvents (); | |
key_count = 0; | |
if (key_lastpress == K_ESCAPE) | |
{ | |
Con_Printf ("aborted.\n"); | |
return false; | |
} | |
key_lastpress = 0; | |
SCR_UpdateScreen (); | |
buttons = ((dos_inportb(0x201) >> 4)&1)^1; | |
if (buttons != oldbuttons) | |
{ | |
oldbuttons = buttons; | |
continue; | |
} | |
} while ( !buttons); | |
do | |
{ | |
key_count = -1; | |
Sys_SendKeyEvents (); | |
key_count = 0; | |
if (key_lastpress == K_ESCAPE) | |
{ | |
Con_Printf ("aborted.\n"); | |
return false; | |
} | |
key_lastpress = 0; | |
SCR_UpdateScreen (); | |
buttons = ((dos_inportb(0x201) >> 4)&1)^1; | |
if (buttons != oldbuttons) | |
{ | |
oldbuttons = buttons; | |
continue; | |
} | |
} while ( buttons); | |
return true; | |
} | |
/* | |
=============== | |
IN_StartupJoystick | |
=============== | |
*/ | |
void IN_StartupJoystick (void) | |
{ | |
int centerx, centery; | |
Con_Printf ("\n"); | |
joy_avail = false; | |
if ( COM_CheckParm ("-nojoy") ) | |
return; | |
if (!IN_ReadJoystick ()) | |
{ | |
joy_avail = false; | |
Con_Printf ("joystick not found\n"); | |
return; | |
} | |
Con_Printf ("joystick found\n"); | |
Con_Printf ("CENTER the joystick\nand press button 1 (ESC to skip):\n"); | |
if (!WaitJoyButton ()) | |
return; | |
IN_ReadJoystick (); | |
centerx = joystickx; | |
centery = joysticky; | |
Con_Printf ("Push the joystick to the UPPER LEFT\nand press button 1 (ESC to skip):\n"); | |
if (!WaitJoyButton ()) | |
return; | |
IN_ReadJoystick (); | |
joyxl = (centerx + joystickx)/2; | |
joyyl = (centerx + joysticky)/2; | |
Con_Printf ("Push the joystick to the LOWER RIGHT\nand press button 1 (ESC to skip):\n"); | |
if (!WaitJoyButton ()) | |
return; | |
IN_ReadJoystick (); | |
joyxh = (centerx + joystickx)/2; | |
joyyh = (centery + joysticky)/2; | |
joy_avail = true; | |
Con_Printf ("joystick configured.\n"); | |
Con_Printf ("\n"); | |
} | |
/* | |
============================================================================ | |
EXTERNAL | |
============================================================================ | |
*/ | |
/* | |
=============== | |
IN_StartupExternal | |
=============== | |
*/ | |
void IN_StartupExternal (void) | |
{ | |
if (extern_control->numButtons > 32) | |
extern_control->numButtons = 32; | |
Con_Printf("%s Initialized\n", extern_control->deviceName); | |
Con_Printf(" %u axes %u buttons\n", extern_control->numAxes, extern_control->numButtons); | |
extern_avail = true; | |
extern_buttons = extern_control->numButtons; | |
} | |
/* | |
=========== | |
IN_ExternalMove | |
=========== | |
*/ | |
void IN_ExternalMove (usercmd_t *cmd) | |
{ | |
qboolean freelook; | |
if (! extern_avail) | |
return; | |
extern_control->viewangles[YAW] = cl.viewangles[YAW]; | |
extern_control->viewangles[PITCH] = cl.viewangles[PITCH]; | |
extern_control->viewangles[ROLL] = cl.viewangles[ROLL]; | |
extern_control->forwardmove = cmd->forwardmove; | |
extern_control->sidemove = cmd->sidemove; | |
extern_control->upmove = cmd->upmove; | |
Con_DPrintf("IN: y:%f p:%f r:%f f:%f s:%f u:%f\n", extern_control->viewangles[YAW], extern_control->viewangles[PITCH], extern_control->viewangles[ROLL], extern_control->forwardmove, extern_control->sidemove, extern_control->upmove); | |
dos_int86(extern_control->interruptVector); | |
Con_DPrintf("OUT: y:%f p:%f r:%f f:%f s:%f u:%f\n", extern_control->viewangles[YAW], extern_control->viewangles[PITCH], extern_control->viewangles[ROLL], extern_control->forwardmove, extern_control->sidemove, extern_control->upmove); | |
cl.viewangles[YAW] = extern_control->viewangles[YAW]; | |
cl.viewangles[PITCH] = extern_control->viewangles[PITCH]; | |
cl.viewangles[ROLL] = extern_control->viewangles[ROLL]; | |
cmd->forwardmove = extern_control->forwardmove; | |
cmd->sidemove = extern_control->sidemove; | |
cmd->upmove = extern_control->upmove; | |
if (cl.viewangles[PITCH] > 80) | |
cl.viewangles[PITCH] = 80; | |
if (cl.viewangles[PITCH] < -70) | |
cl.viewangles[PITCH] = -70; | |
freelook = (extern_control->flags & AUX_FLAG_FREELOOK || aux_look.value || in_mlook.state & 1); | |
if (freelook) | |
V_StopPitchDrift (); | |
} | |