1 /* 2 Copyright (C) 1996-1997 Id Software, Inc. 3 4 This program is free software; you can redistribute it and/or 5 modify it under the terms of the GNU General Public License 6 as published by the Free Software Foundation; either version 2 7 of the License, or (at your option) any later version. 8 9 This program is distributed in the hope that it will be useful, 10 but WITHOUT ANY WARRANTY; without even the implied warranty of 11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 12 13 See the GNU General Public License for more details. 14 15 You should have received a copy of the GNU General Public License 16 along with this program; if not, write to the Free Software 17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 18 19 */ 20 // in_mouse.c -- dos mouse code 21 22 #include "quakedef.h" 23 #include "dosisms.h" 24 25 #define AUX_FLAG_FREELOOK 0x00000001 26 27 typedef struct 28 { 29 long interruptVector; 30 char deviceName[16]; 31 long numAxes; 32 long numButtons; 33 long flags; 34 35 vec3_t viewangles; 36 37 // intended velocities 38 float forwardmove; 39 float sidemove; 40 float upmove; 41 42 long buttons; 43 } externControl_t; 44 45 /* 46 #define AUX_FLAG_FORCEFREELOOK 0x00000001 // r/o 47 #define AUX_FLAG_EXTENDED 0x00000002 // r/o 48 #define AUX_FLAG_RUN 0x00000004 // w/o 49 #define AUX_FLAG_STRAFE 0x00000008 // w/o 50 #define AUX_FLAG_FREELOOK 0x00000010 // w/o 51 52 #define AUX_MAP_UNDEFINED 0 53 #define AUX_MAP_PITCH 1 54 #define AUX_MAP_YAW 2 55 #define AUX_MAP_ROLL 3 56 #define AUX_MAP_FORWARD 4 57 #define AUX_MAP_SIDE 5 58 #define AUX_MAP_UP 6 59 60 typedef struct 61 { 62 long interruptVector; 63 // r/o 64 char deviceName[16]; 65 // r/o 66 long numAxes; 67 // r/o 1-6 68 long numButtons; // r/o 0-32 69 long flags; // see above 70 byte axisMapping[6]; // w/o default = p,y,r,f,s,u 71 float axisValue[6]; // r/w 72 float sensitivity[6]; // w/o default = 1.0 73 long buttons; // r/o 74 float last_frame_time; // w/o 75 } externControl_t; 76 */ 77 78 cvar_t m_filter = {"m_filter","1"}; 79 80 qboolean mouse_avail; 81 int mouse_buttons; 82 int mouse_oldbuttonstate; 83 int mouse_buttonstate; 84 float mouse_x, mouse_y; 85 float old_mouse_x, old_mouse_y; 86 87 88 cvar_t in_joystick = {"joystick","1"}; 89 cvar_t joy_numbuttons = {"joybuttons","4", true}; 90 91 qboolean joy_avail; 92 int joy_oldbuttonstate; 93 int joy_buttonstate; 94 95 int joyxl, joyxh, joyyl, joyyh; 96 int joystickx, joysticky; 97 98 qboolean need_center; 99 100 qboolean extern_avail; 101 int extern_buttons; 102 int extern_oldbuttonstate; 103 int extern_buttonstate; 104 cvar_t aux_look = {"auxlook","1", true}; 105 externControl_t *extern_control; 106 void IN_StartupExternal (void); 107 void IN_ExternalMove (usercmd_t *cmd); 108 109 void IN_StartupJoystick (void); 110 qboolean IN_ReadJoystick (void); 111 112 113 void Toggle_AuxLook_f (void) 114 { 115 if (aux_look.value) 116 Cvar_Set ("auxlook","0"); 117 else 118 Cvar_Set ("auxlook","1"); 119 } 120 121 122 void Force_CenterView_f (void) 123 { 124 cl.viewangles[PITCH] = 0; 125 } 126 127 128 /* 129 =========== 130 IN_StartupMouse 131 =========== 132 */ 133 void IN_StartupMouse (void) 134 { 135 if ( COM_CheckParm ("-nomouse") ) 136 return; 137 138 // check for mouse 139 regs.x.ax = 0; 140 dos_int86(0x33); 141 mouse_avail = regs.x.ax; 142 if (!mouse_avail) 143 { 144 Con_Printf ("No mouse found\n"); 145 return; 146 } 147 148 mouse_buttons = regs.x.bx; 149 if (mouse_buttons > 3) 150 mouse_buttons = 3; 151 Con_Printf("%d-button mouse available\n", mouse_buttons); 152 } 153 154 /* 155 =========== 156 IN_Init 157 =========== 158 */ 159 void IN_Init (void) 160 { 161 int i; 162 163 Cvar_RegisterVariable (&m_filter); 164 Cvar_RegisterVariable (&in_joystick); 165 Cvar_RegisterVariable (&joy_numbuttons); 166 Cvar_RegisterVariable (&aux_look); 167 Cmd_AddCommand ("toggle_auxlook", Toggle_AuxLook_f); 168 Cmd_AddCommand ("force_centerview", Force_CenterView_f); 169 170 IN_StartupMouse (); 171 IN_StartupJoystick (); 172 173 i = COM_CheckParm ("-control"); 174 if (i) 175 { 176 extern_control = real2ptr(Q_atoi (com_argv[i+1])); 177 IN_StartupExternal (); 178 } 179 } 180 181 /* 182 =========== 183 IN_Shutdown 184 =========== 185 */ 186 void IN_Shutdown (void) 187 { 188 189 } 190 191 192 /* 193 =========== 194 IN_Commands 195 =========== 196 */ 197 void IN_Commands (void) 198 { 199 int i; 200 201 if (mouse_avail) 202 { 203 regs.x.ax = 3; // read buttons 204 dos_int86(0x33); 205 mouse_buttonstate = regs.x.bx; 206 207 // perform button actions 208 for (i=0 ; i<mouse_buttons ; i++) 209 { 210 if ( (mouse_buttonstate & (1<<i)) && 211 !(mouse_oldbuttonstate & (1<<i)) ) 212 { 213 Key_Event (K_MOUSE1 + i, true); 214 } 215 if ( !(mouse_buttonstate & (1<<i)) && 216 (mouse_oldbuttonstate & (1<<i)) ) 217 { 218 Key_Event (K_MOUSE1 + i, false); 219 } 220 } 221 222 mouse_oldbuttonstate = mouse_buttonstate; 223 } 224 225 if (joy_avail) 226 { 227 joy_buttonstate = ((dos_inportb(0x201) >> 4)&15)^15; 228 // perform button actions 229 for (i=0 ; i<joy_numbuttons.value ; i++) 230 { 231 if ( (joy_buttonstate & (1<<i)) && 232 !(joy_oldbuttonstate & (1<<i)) ) 233 { 234 Key_Event (K_JOY1 + i, true); 235 } 236 if ( !(joy_buttonstate & (1<<i)) && 237 (joy_oldbuttonstate & (1<<i)) ) 238 { 239 Key_Event (K_JOY1 + i, false); 240 } 241 } 242 243 joy_oldbuttonstate = joy_buttonstate; 244 } 245 246 if (extern_avail) 247 { 248 extern_buttonstate = extern_control->buttons; 249 250 // perform button actions 251 for (i=0 ; i<extern_buttons ; i++) 252 { 253 if ( (extern_buttonstate & (1<<i)) && 254 !(extern_oldbuttonstate & (1<<i)) ) 255 { 256 Key_Event (K_AUX1 + i, true); 257 } 258 if ( !(extern_buttonstate & (1<<i)) && 259 (extern_oldbuttonstate & (1<<i)) ) 260 { 261 Key_Event (K_AUX1 + i, false); 262 } 263 } 264 265 extern_oldbuttonstate = extern_buttonstate; 266 } 267 268 } 269 270 271 /* 272 =========== 273 IN_Move 274 =========== 275 */ 276 void IN_MouseMove (usercmd_t *cmd) 277 { 278 int mx, my; 279 280 if (!mouse_avail) 281 return; 282 283 regs.x.ax = 11; // read move 284 dos_int86(0x33); 285 mx = (short)regs.x.cx; 286 my = (short)regs.x.dx; 287 288 if (m_filter.value) 289 { 290 mouse_x = (mx + old_mouse_x) * 0.5; 291 mouse_y = (my + old_mouse_y) * 0.5; 292 } 293 else 294 { 295 mouse_x = mx; 296 mouse_y = my; 297 } 298 old_mouse_x = mx; 299 old_mouse_y = my; 300 301 mouse_x *= sensitivity.value; 302 mouse_y *= sensitivity.value; 303 304 // add mouse X/Y movement to cmd 305 if ( (in_strafe.state & 1) || (lookstrafe.value && (in_mlook.state & 1) )) 306 cmd->sidemove += m_side.value * mouse_x; 307 else 308 cl.viewangles[YAW] -= m_yaw.value * mouse_x; 309 310 if (in_mlook.state & 1) 311 V_StopPitchDrift (); 312 313 if ( (in_mlook.state & 1) && !(in_strafe.state & 1)) 314 { 315 cl.viewangles[PITCH] += m_pitch.value * mouse_y; 316 if (cl.viewangles[PITCH] > 80) 317 cl.viewangles[PITCH] = 80; 318 if (cl.viewangles[PITCH] < -70) 319 cl.viewangles[PITCH] = -70; 320 } 321 else 322 { 323 if ((in_strafe.state & 1) && noclip_anglehack) 324 cmd->upmove -= m_forward.value * mouse_y; 325 else 326 cmd->forwardmove -= m_forward.value * mouse_y; 327 } 328 } 329 330 /* 331 =========== 332 IN_JoyMove 333 =========== 334 */ 335 void IN_JoyMove (usercmd_t *cmd) 336 { 337 float speed, aspeed; 338 339 if (!joy_avail || !in_joystick.value) 340 return; 341 342 IN_ReadJoystick (); 343 if (joysticky > joyyh*2 || joystickx > joyxh*2) 344 return; // assume something jumped in and messed up the joystick 345 // reading time (win 95) 346 347 if (in_speed.state & 1) 348 speed = cl_movespeedkey.value; 349 else 350 speed = 1; 351 aspeed = speed*host_frametime; 352 353 if (in_strafe.state & 1) 354 { 355 if (joystickx < joyxl) 356 cmd->sidemove -= speed*cl_sidespeed.value; 357 else if (joystickx > joyxh) 358 cmd->sidemove += speed*cl_sidespeed.value; 359 } 360 else 361 { 362 if (joystickx < joyxl) 363 cl.viewangles[YAW] += aspeed*cl_yawspeed.value; 364 else if (joystickx > joyxh) 365 cl.viewangles[YAW] -= aspeed*cl_yawspeed.value; 366 cl.viewangles[YAW] = anglemod(cl.viewangles[YAW]); 367 } 368 369 if (in_mlook.state & 1) 370 { 371 if (m_pitch.value < 0) 372 speed *= -1; 373 374 if (joysticky < joyyl) 375 cl.viewangles[PITCH] += aspeed*cl_pitchspeed.value; 376 else if (joysticky > joyyh) 377 cl.viewangles[PITCH] -= aspeed*cl_pitchspeed.value; 378 } 379 else 380 { 381 if (joysticky < joyyl) 382 cmd->forwardmove += speed*cl_forwardspeed.value; 383 else if (joysticky > joyyh) 384 cmd->forwardmove -= speed*cl_backspeed.value; 385 } 386 } 387 388 /* 389 =========== 390 IN_Move 391 =========== 392 */ 393 void IN_Move (usercmd_t *cmd) 394 { 395 IN_MouseMove (cmd); 396 IN_JoyMove (cmd); 397 IN_ExternalMove (cmd); 398 } 399 400 /* 401 ============================================================================ 402 403 JOYSTICK 404 405 ============================================================================ 406 */ 407 408 409 410 qboolean IN_ReadJoystick (void) 411 { 412 int b; 413 int count; 414 415 joystickx = 0; 416 joysticky = 0; 417 418 count = 0; 419 420 b = dos_inportb(0x201); 421 dos_outportb(0x201, b); 422 423 // clear counters 424 while (++count < 10000) 425 { 426 b = dos_inportb(0x201); 427 428 joystickx += b&1; 429 joysticky += (b&2)>>1; 430 if ( !(b&3) ) 431 return true; 432 } 433 434 Con_Printf ("IN_ReadJoystick: no response\n"); 435 joy_avail = false; 436 return false; 437 } 438 439 /* 440 ============= 441 WaitJoyButton 442 ============= 443 */ 444 qboolean WaitJoyButton (void) 445 { 446 int oldbuttons, buttons; 447 448 oldbuttons = 0; 449 do 450 { 451 key_count = -1; 452 Sys_SendKeyEvents (); 453 key_count = 0; 454 if (key_lastpress == K_ESCAPE) 455 { 456 Con_Printf ("aborted.\n"); 457 return false; 458 } 459 key_lastpress = 0; 460 SCR_UpdateScreen (); 461 buttons = ((dos_inportb(0x201) >> 4)&1)^1; 462 if (buttons != oldbuttons) 463 { 464 oldbuttons = buttons; 465 continue; 466 } 467 } while ( !buttons); 468 469 do 470 { 471 key_count = -1; 472 Sys_SendKeyEvents (); 473 key_count = 0; 474 if (key_lastpress == K_ESCAPE) 475 { 476 Con_Printf ("aborted.\n"); 477 return false; 478 } 479 key_lastpress = 0; 480 SCR_UpdateScreen (); 481 buttons = ((dos_inportb(0x201) >> 4)&1)^1; 482 if (buttons != oldbuttons) 483 { 484 oldbuttons = buttons; 485 continue; 486 } 487 } while ( buttons); 488 489 return true; 490 } 491 492 493 494 /* 495 =============== 496 IN_StartupJoystick 497 =============== 498 */ 499 void IN_StartupJoystick (void) 500 { 501 int centerx, centery; 502 503 Con_Printf ("\n"); 504 505 joy_avail = false; 506 if ( COM_CheckParm ("-nojoy") ) 507 return; 508 509 if (!IN_ReadJoystick ()) 510 { 511 joy_avail = false; 512 Con_Printf ("joystick not found\n"); 513 return; 514 } 515 516 Con_Printf ("joystick found\n"); 517 518 Con_Printf ("CENTER the joystick\nand press button 1 (ESC to skip):\n"); 519 if (!WaitJoyButton ()) 520 return; 521 IN_ReadJoystick (); 522 centerx = joystickx; 523 centery = joysticky; 524 525 Con_Printf ("Push the joystick to the UPPER LEFT\nand press button 1 (ESC to skip):\n"); 526 if (!WaitJoyButton ()) 527 return; 528 IN_ReadJoystick (); 529 joyxl = (centerx + joystickx)/2; 530 joyyl = (centerx + joysticky)/2; 531 532 Con_Printf ("Push the joystick to the LOWER RIGHT\nand press button 1 (ESC to skip):\n"); 533 if (!WaitJoyButton ()) 534 return; 535 IN_ReadJoystick (); 536 joyxh = (centerx + joystickx)/2; 537 joyyh = (centery + joysticky)/2; 538 539 joy_avail = true; 540 Con_Printf ("joystick configured.\n"); 541 542 Con_Printf ("\n"); 543 } 544 545 546 /* 547 ============================================================================ 548 549 EXTERNAL 550 551 ============================================================================ 552 */ 553 554 555 /* 556 =============== 557 IN_StartupExternal 558 =============== 559 */ 560 void IN_StartupExternal (void) 561 { 562 if (extern_control->numButtons > 32) 563 extern_control->numButtons = 32; 564 565 Con_Printf("%s Initialized\n", extern_control->deviceName); 566 Con_Printf(" %u axes %u buttons\n", extern_control->numAxes, extern_control->numButtons); 567 568 extern_avail = true; 569 extern_buttons = extern_control->numButtons; 570 } 571 572 573 /* 574 =========== 575 IN_ExternalMove 576 =========== 577 */ 578 void IN_ExternalMove (usercmd_t *cmd) 579 { 580 qboolean freelook; 581 582 if (! extern_avail) 583 return; 584 585 extern_control->viewangles[YAW] = cl.viewangles[YAW]; 586 extern_control->viewangles[PITCH] = cl.viewangles[PITCH]; 587 extern_control->viewangles[ROLL] = cl.viewangles[ROLL]; 588 extern_control->forwardmove = cmd->forwardmove; 589 extern_control->sidemove = cmd->sidemove; 590 extern_control->upmove = cmd->upmove; 591 592 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); 593 594 dos_int86(extern_control->interruptVector); 595 596 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); 597 598 cl.viewangles[YAW] = extern_control->viewangles[YAW]; 599 cl.viewangles[PITCH] = extern_control->viewangles[PITCH]; 600 cl.viewangles[ROLL] = extern_control->viewangles[ROLL]; 601 cmd->forwardmove = extern_control->forwardmove; 602 cmd->sidemove = extern_control->sidemove; 603 cmd->upmove = extern_control->upmove; 604 605 if (cl.viewangles[PITCH] > 80) 606 cl.viewangles[PITCH] = 80; 607 if (cl.viewangles[PITCH] < -70) 608 cl.viewangles[PITCH] = -70; 609 610 freelook = (extern_control->flags & AUX_FLAG_FREELOOK || aux_look.value || in_mlook.state & 1); 611 612 if (freelook) 613 V_StopPitchDrift (); 614 } 615 616