/* in_dos.c @description@ 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: Free Software Foundation, Inc. 59 Temple Place - Suite 330 Boston, MA 02111-1307, USA $Id$ */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #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; 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; cvar_t *joy_numbuttons; 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; 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->int_val) 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; m_filter = Cvar_Get ("m_filter", "0", CVAR_ARCHIVE, 0, "None"); in_joystick = Cvar_Get ("joystick", "0", CVAR_ARCHIVE, 0, "None"); joy_numbuttons = Cvar_Get ("joybuttons", "4", CVAR_ARCHIVE, 0, "None"); aux_look = Cvar_Get ("auxlook", "1", CVAR_ARCHIVE, 0, "None"); Cmd_AddCommand ("toggle_auxlook", Toggle_AuxLook_f, "No Description"); Cmd_AddCommand ("force_centerview", Force_CenterView_f, "No Description"); 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->int_val; 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->int_val) { 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->int_val && (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->int_val) 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; IN_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; IN_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->int_val || in_mlook.state & 1); if (freelook) V_StopPitchDrift (); } void IN_HandlePause (qboolean pause) { }