win_input.c (26325B)
1 /* 2 =========================================================================== 3 Copyright (C) 1999-2005 Id Software, Inc. 4 5 This file is part of Quake III Arena source code. 6 7 Quake III Arena source code is free software; you can redistribute it 8 and/or modify it under the terms of the GNU General Public License as 9 published by the Free Software Foundation; either version 2 of the License, 10 or (at your option) any later version. 11 12 Quake III Arena source code is distributed in the hope that it will be 13 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 GNU General Public License for more details. 16 17 You should have received a copy of the GNU General Public License 18 along with Foobar; if not, write to the Free Software 19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 20 =========================================================================== 21 */ 22 // win_input.c -- win32 mouse and joystick code 23 // 02/21/97 JCB Added extended DirectInput code to support external controllers. 24 25 #include "../client/client.h" 26 #include "win_local.h" 27 28 29 typedef struct { 30 int oldButtonState; 31 32 qboolean mouseActive; 33 qboolean mouseInitialized; 34 qboolean mouseStartupDelayed; // delay mouse init to try DI again when we have a window 35 } WinMouseVars_t; 36 37 static WinMouseVars_t s_wmv; 38 39 static int window_center_x, window_center_y; 40 41 // 42 // MIDI definitions 43 // 44 static void IN_StartupMIDI( void ); 45 static void IN_ShutdownMIDI( void ); 46 47 #define MAX_MIDIIN_DEVICES 8 48 49 typedef struct { 50 int numDevices; 51 MIDIINCAPS caps[MAX_MIDIIN_DEVICES]; 52 53 HMIDIIN hMidiIn; 54 } MidiInfo_t; 55 56 static MidiInfo_t s_midiInfo; 57 58 // 59 // Joystick definitions 60 // 61 #define JOY_MAX_AXES 6 // X, Y, Z, R, U, V 62 63 typedef struct { 64 qboolean avail; 65 int id; // joystick number 66 JOYCAPS jc; 67 68 int oldbuttonstate; 69 int oldpovstate; 70 71 JOYINFOEX ji; 72 } joystickInfo_t; 73 74 static joystickInfo_t joy; 75 76 77 78 cvar_t *in_midi; 79 cvar_t *in_midiport; 80 cvar_t *in_midichannel; 81 cvar_t *in_mididevice; 82 83 cvar_t *in_mouse; 84 cvar_t *in_logitechbug; 85 cvar_t *in_joystick; 86 cvar_t *in_joyBallScale; 87 cvar_t *in_debugJoystick; 88 cvar_t *joy_threshold; 89 90 qboolean in_appactive; 91 92 // forward-referenced functions 93 void IN_StartupJoystick (void); 94 void IN_JoyMove(void); 95 96 static void MidiInfo_f( void ); 97 98 /* 99 ============================================================ 100 101 WIN32 MOUSE CONTROL 102 103 ============================================================ 104 */ 105 106 /* 107 ================ 108 IN_InitWin32Mouse 109 ================ 110 */ 111 void IN_InitWin32Mouse( void ) 112 { 113 } 114 115 /* 116 ================ 117 IN_ShutdownWin32Mouse 118 ================ 119 */ 120 void IN_ShutdownWin32Mouse( void ) { 121 } 122 123 /* 124 ================ 125 IN_ActivateWin32Mouse 126 ================ 127 */ 128 void IN_ActivateWin32Mouse( void ) { 129 int width, height; 130 RECT window_rect; 131 132 width = GetSystemMetrics (SM_CXSCREEN); 133 height = GetSystemMetrics (SM_CYSCREEN); 134 135 GetWindowRect ( g_wv.hWnd, &window_rect); 136 if (window_rect.left < 0) 137 window_rect.left = 0; 138 if (window_rect.top < 0) 139 window_rect.top = 0; 140 if (window_rect.right >= width) 141 window_rect.right = width-1; 142 if (window_rect.bottom >= height-1) 143 window_rect.bottom = height-1; 144 window_center_x = (window_rect.right + window_rect.left)/2; 145 window_center_y = (window_rect.top + window_rect.bottom)/2; 146 147 SetCursorPos (window_center_x, window_center_y); 148 149 SetCapture ( g_wv.hWnd ); 150 ClipCursor (&window_rect); 151 while (ShowCursor (FALSE) >= 0) 152 ; 153 } 154 155 /* 156 ================ 157 IN_DeactivateWin32Mouse 158 ================ 159 */ 160 void IN_DeactivateWin32Mouse( void ) 161 { 162 ClipCursor (NULL); 163 ReleaseCapture (); 164 while (ShowCursor (TRUE) < 0) 165 ; 166 } 167 168 /* 169 ================ 170 IN_Win32Mouse 171 ================ 172 */ 173 void IN_Win32Mouse( int *mx, int *my ) { 174 POINT current_pos; 175 176 // find mouse movement 177 GetCursorPos (¤t_pos); 178 179 // force the mouse to the center, so there's room to move 180 SetCursorPos (window_center_x, window_center_y); 181 182 *mx = current_pos.x - window_center_x; 183 *my = current_pos.y - window_center_y; 184 } 185 186 187 /* 188 ============================================================ 189 190 DIRECT INPUT MOUSE CONTROL 191 192 ============================================================ 193 */ 194 195 #undef DEFINE_GUID 196 197 #define DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \ 198 EXTERN_C const GUID name \ 199 = { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } } 200 201 DEFINE_GUID(GUID_SysMouse, 0x6F1D2B60,0xD5A0,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00); 202 DEFINE_GUID(GUID_XAxis, 0xA36D02E0,0xC9F3,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00); 203 DEFINE_GUID(GUID_YAxis, 0xA36D02E1,0xC9F3,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00); 204 DEFINE_GUID(GUID_ZAxis, 0xA36D02E2,0xC9F3,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00); 205 206 207 #define DINPUT_BUFFERSIZE 16 208 #define iDirectInputCreate(a,b,c,d) pDirectInputCreate(a,b,c,d) 209 210 HRESULT (WINAPI *pDirectInputCreate)(HINSTANCE hinst, DWORD dwVersion, 211 LPDIRECTINPUT * lplpDirectInput, LPUNKNOWN punkOuter); 212 213 static HINSTANCE hInstDI; 214 215 typedef struct MYDATA { 216 LONG lX; // X axis goes here 217 LONG lY; // Y axis goes here 218 LONG lZ; // Z axis goes here 219 BYTE bButtonA; // One button goes here 220 BYTE bButtonB; // Another button goes here 221 BYTE bButtonC; // Another button goes here 222 BYTE bButtonD; // Another button goes here 223 } MYDATA; 224 225 static DIOBJECTDATAFORMAT rgodf[] = { 226 { &GUID_XAxis, FIELD_OFFSET(MYDATA, lX), DIDFT_AXIS | DIDFT_ANYINSTANCE, 0,}, 227 { &GUID_YAxis, FIELD_OFFSET(MYDATA, lY), DIDFT_AXIS | DIDFT_ANYINSTANCE, 0,}, 228 { &GUID_ZAxis, FIELD_OFFSET(MYDATA, lZ), 0x80000000 | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0,}, 229 { 0, FIELD_OFFSET(MYDATA, bButtonA), DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0,}, 230 { 0, FIELD_OFFSET(MYDATA, bButtonB), DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0,}, 231 { 0, FIELD_OFFSET(MYDATA, bButtonC), 0x80000000 | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0,}, 232 { 0, FIELD_OFFSET(MYDATA, bButtonD), 0x80000000 | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0,}, 233 }; 234 235 #define NUM_OBJECTS (sizeof(rgodf) / sizeof(rgodf[0])) 236 237 // NOTE TTimo: would be easier using c_dfDIMouse or c_dfDIMouse2 238 static DIDATAFORMAT df = { 239 sizeof(DIDATAFORMAT), // this structure 240 sizeof(DIOBJECTDATAFORMAT), // size of object data format 241 DIDF_RELAXIS, // absolute axis coordinates 242 sizeof(MYDATA), // device data size 243 NUM_OBJECTS, // number of objects 244 rgodf, // and here they are 245 }; 246 247 static LPDIRECTINPUT g_pdi; 248 static LPDIRECTINPUTDEVICE g_pMouse; 249 250 void IN_DIMouse( int *mx, int *my ); 251 252 /* 253 ======================== 254 IN_InitDIMouse 255 ======================== 256 */ 257 qboolean IN_InitDIMouse( void ) { 258 HRESULT hr; 259 int x, y; 260 DIPROPDWORD dipdw = { 261 { 262 sizeof(DIPROPDWORD), // diph.dwSize 263 sizeof(DIPROPHEADER), // diph.dwHeaderSize 264 0, // diph.dwObj 265 DIPH_DEVICE, // diph.dwHow 266 }, 267 DINPUT_BUFFERSIZE, // dwData 268 }; 269 270 Com_Printf( "Initializing DirectInput...\n"); 271 272 if (!hInstDI) { 273 hInstDI = LoadLibrary("dinput.dll"); 274 275 if (hInstDI == NULL) { 276 Com_Printf ("Couldn't load dinput.dll\n"); 277 return qfalse; 278 } 279 } 280 281 if (!pDirectInputCreate) { 282 pDirectInputCreate = (long (__stdcall *)(void *,unsigned long ,struct IDirectInputA ** ,struct IUnknown *)) 283 GetProcAddress(hInstDI,"DirectInputCreateA"); 284 285 if (!pDirectInputCreate) { 286 Com_Printf ("Couldn't get DI proc addr\n"); 287 return qfalse; 288 } 289 } 290 291 // register with DirectInput and get an IDirectInput to play with. 292 hr = iDirectInputCreate( g_wv.hInstance, DIRECTINPUT_VERSION, &g_pdi, NULL); 293 294 if (FAILED(hr)) { 295 Com_Printf ("iDirectInputCreate failed\n"); 296 return qfalse; 297 } 298 299 // obtain an interface to the system mouse device. 300 hr = IDirectInput_CreateDevice(g_pdi, &GUID_SysMouse, &g_pMouse, NULL); 301 302 if (FAILED(hr)) { 303 Com_Printf ("Couldn't open DI mouse device\n"); 304 return qfalse; 305 } 306 307 // set the data format to "mouse format". 308 hr = IDirectInputDevice_SetDataFormat(g_pMouse, &df); 309 310 if (FAILED(hr)) { 311 Com_Printf ("Couldn't set DI mouse format\n"); 312 return qfalse; 313 } 314 315 // set the cooperativity level. 316 hr = IDirectInputDevice_SetCooperativeLevel(g_pMouse, g_wv.hWnd, 317 DISCL_EXCLUSIVE | DISCL_FOREGROUND); 318 319 // https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=50 320 if (FAILED(hr)) { 321 Com_Printf ("Couldn't set DI coop level\n"); 322 return qfalse; 323 } 324 325 326 // set the buffer size to DINPUT_BUFFERSIZE elements. 327 // the buffer size is a DWORD property associated with the device 328 hr = IDirectInputDevice_SetProperty(g_pMouse, DIPROP_BUFFERSIZE, &dipdw.diph); 329 330 if (FAILED(hr)) { 331 Com_Printf ("Couldn't set DI buffersize\n"); 332 return qfalse; 333 } 334 335 // clear any pending samples 336 IN_DIMouse( &x, &y ); 337 IN_DIMouse( &x, &y ); 338 339 Com_Printf( "DirectInput initialized.\n"); 340 return qtrue; 341 } 342 343 /* 344 ========================== 345 IN_ShutdownDIMouse 346 ========================== 347 */ 348 void IN_ShutdownDIMouse( void ) { 349 if (g_pMouse) { 350 IDirectInputDevice_Release(g_pMouse); 351 g_pMouse = NULL; 352 } 353 354 if (g_pdi) { 355 IDirectInput_Release(g_pdi); 356 g_pdi = NULL; 357 } 358 } 359 360 /* 361 ========================== 362 IN_ActivateDIMouse 363 ========================== 364 */ 365 void IN_ActivateDIMouse( void ) { 366 HRESULT hr; 367 368 if (!g_pMouse) { 369 return; 370 } 371 372 // we may fail to reacquire if the window has been recreated 373 hr = IDirectInputDevice_Acquire( g_pMouse ); 374 if (FAILED(hr)) { 375 if ( !IN_InitDIMouse() ) { 376 Com_Printf ("Falling back to Win32 mouse support...\n"); 377 Cvar_Set( "in_mouse", "-1" ); 378 } 379 } 380 } 381 382 /* 383 ========================== 384 IN_DeactivateDIMouse 385 ========================== 386 */ 387 void IN_DeactivateDIMouse( void ) { 388 if (!g_pMouse) { 389 return; 390 } 391 IDirectInputDevice_Unacquire( g_pMouse ); 392 } 393 394 395 /* 396 =================== 397 IN_DIMouse 398 =================== 399 */ 400 void IN_DIMouse( int *mx, int *my ) { 401 DIDEVICEOBJECTDATA od; 402 DIMOUSESTATE state; 403 DWORD dwElements; 404 HRESULT hr; 405 int value; 406 static float oldSysTime; 407 408 if ( !g_pMouse ) { 409 return; 410 } 411 412 // fetch new events 413 for (;;) 414 { 415 dwElements = 1; 416 417 hr = IDirectInputDevice_GetDeviceData(g_pMouse, 418 sizeof(DIDEVICEOBJECTDATA), &od, &dwElements, 0); 419 if ((hr == DIERR_INPUTLOST) || (hr == DIERR_NOTACQUIRED)) { 420 IDirectInputDevice_Acquire(g_pMouse); 421 return; 422 } 423 424 /* Unable to read data or no data available */ 425 if ( FAILED(hr) ) { 426 break; 427 } 428 429 if ( dwElements == 0 ) { 430 break; 431 } 432 433 switch (od.dwOfs) { 434 case DIMOFS_BUTTON0: 435 if (od.dwData & 0x80) 436 Sys_QueEvent( od.dwTimeStamp, SE_KEY, K_MOUSE1, qtrue, 0, NULL ); 437 else 438 Sys_QueEvent( od.dwTimeStamp, SE_KEY, K_MOUSE1, qfalse, 0, NULL ); 439 break; 440 441 case DIMOFS_BUTTON1: 442 if (od.dwData & 0x80) 443 Sys_QueEvent( od.dwTimeStamp, SE_KEY, K_MOUSE2, qtrue, 0, NULL ); 444 else 445 Sys_QueEvent( od.dwTimeStamp, SE_KEY, K_MOUSE2, qfalse, 0, NULL ); 446 break; 447 448 case DIMOFS_BUTTON2: 449 if (od.dwData & 0x80) 450 Sys_QueEvent( od.dwTimeStamp, SE_KEY, K_MOUSE3, qtrue, 0, NULL ); 451 else 452 Sys_QueEvent( od.dwTimeStamp, SE_KEY, K_MOUSE3, qfalse, 0, NULL ); 453 break; 454 455 case DIMOFS_BUTTON3: 456 if (od.dwData & 0x80) 457 Sys_QueEvent( od.dwTimeStamp, SE_KEY, K_MOUSE4, qtrue, 0, NULL ); 458 else 459 Sys_QueEvent( od.dwTimeStamp, SE_KEY, K_MOUSE4, qfalse, 0, NULL ); 460 break; 461 // https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=50 462 case DIMOFS_Z: 463 value = od.dwData; 464 if (value == 0) { 465 466 } else if (value < 0) { 467 Sys_QueEvent( od.dwTimeStamp, SE_KEY, K_MWHEELDOWN, qtrue, 0, NULL ); 468 Sys_QueEvent( od.dwTimeStamp, SE_KEY, K_MWHEELDOWN, qfalse, 0, NULL ); 469 } else { 470 Sys_QueEvent( od.dwTimeStamp, SE_KEY, K_MWHEELUP, qtrue, 0, NULL ); 471 Sys_QueEvent( od.dwTimeStamp, SE_KEY, K_MWHEELUP, qfalse, 0, NULL ); 472 } 473 break; 474 } 475 } 476 477 // read the raw delta counter and ignore 478 // the individual sample time / values 479 hr = IDirectInputDevice_GetDeviceState(g_pMouse, 480 sizeof(DIDEVICEOBJECTDATA), &state); 481 if ( FAILED(hr) ) { 482 *mx = *my = 0; 483 return; 484 } 485 *mx = state.lX; 486 *my = state.lY; 487 } 488 489 /* 490 ============================================================ 491 492 MOUSE CONTROL 493 494 ============================================================ 495 */ 496 497 /* 498 =========== 499 IN_ActivateMouse 500 501 Called when the window gains focus or changes in some way 502 =========== 503 */ 504 void IN_ActivateMouse( void ) 505 { 506 if (!s_wmv.mouseInitialized ) { 507 return; 508 } 509 if ( !in_mouse->integer ) 510 { 511 s_wmv.mouseActive = qfalse; 512 return; 513 } 514 if ( s_wmv.mouseActive ) 515 { 516 return; 517 } 518 519 s_wmv.mouseActive = qtrue; 520 521 if ( in_mouse->integer != -1 ) { 522 IN_ActivateDIMouse(); 523 } 524 IN_ActivateWin32Mouse(); 525 } 526 527 528 /* 529 =========== 530 IN_DeactivateMouse 531 532 Called when the window loses focus 533 =========== 534 */ 535 void IN_DeactivateMouse( void ) { 536 if (!s_wmv.mouseInitialized ) { 537 return; 538 } 539 if (!s_wmv.mouseActive ) { 540 return; 541 } 542 s_wmv.mouseActive = qfalse; 543 544 IN_DeactivateDIMouse(); 545 IN_DeactivateWin32Mouse(); 546 } 547 548 549 550 /* 551 =========== 552 IN_StartupMouse 553 =========== 554 */ 555 void IN_StartupMouse( void ) 556 { 557 s_wmv.mouseInitialized = qfalse; 558 s_wmv.mouseStartupDelayed = qfalse; 559 560 if ( in_mouse->integer == 0 ) { 561 Com_Printf ("Mouse control not active.\n"); 562 return; 563 } 564 565 // nt4.0 direct input is screwed up 566 if ( ( g_wv.osversion.dwPlatformId == VER_PLATFORM_WIN32_NT ) && 567 ( g_wv.osversion.dwMajorVersion == 4 ) ) 568 { 569 Com_Printf ("Disallowing DirectInput on NT 4.0\n"); 570 Cvar_Set( "in_mouse", "-1" ); 571 } 572 573 if ( in_mouse->integer == -1 ) { 574 Com_Printf ("Skipping check for DirectInput\n"); 575 } else { 576 if (!g_wv.hWnd) 577 { 578 Com_Printf ("No window for DirectInput mouse init, delaying\n"); 579 s_wmv.mouseStartupDelayed = qtrue; 580 return; 581 } 582 if ( IN_InitDIMouse() ) { 583 s_wmv.mouseInitialized = qtrue; 584 return; 585 } 586 Com_Printf ("Falling back to Win32 mouse support...\n"); 587 } 588 s_wmv.mouseInitialized = qtrue; 589 IN_InitWin32Mouse(); 590 } 591 592 /* 593 =========== 594 IN_MouseEvent 595 =========== 596 */ 597 void IN_MouseEvent (int mstate) 598 { 599 int i; 600 601 if ( !s_wmv.mouseInitialized ) 602 return; 603 604 // perform button actions 605 for (i = 0 ; i < 3 ; i++ ) 606 { 607 if ( (mstate & (1<<i)) && 608 !(s_wmv.oldButtonState & (1<<i)) ) 609 { 610 Sys_QueEvent( g_wv.sysMsgTime, SE_KEY, K_MOUSE1 + i, qtrue, 0, NULL ); 611 } 612 613 if ( !(mstate & (1<<i)) && 614 (s_wmv.oldButtonState & (1<<i)) ) 615 { 616 Sys_QueEvent( g_wv.sysMsgTime, SE_KEY, K_MOUSE1 + i, qfalse, 0, NULL ); 617 } 618 } 619 620 s_wmv.oldButtonState = mstate; 621 } 622 623 624 /* 625 =========== 626 IN_MouseMove 627 =========== 628 */ 629 void IN_MouseMove ( void ) { 630 int mx, my; 631 632 if ( g_pMouse ) { 633 IN_DIMouse( &mx, &my ); 634 } else { 635 IN_Win32Mouse( &mx, &my ); 636 } 637 638 if ( !mx && !my ) { 639 return; 640 } 641 642 Sys_QueEvent( 0, SE_MOUSE, mx, my, 0, NULL ); 643 } 644 645 646 /* 647 ========================================================================= 648 649 ========================================================================= 650 */ 651 652 /* 653 =========== 654 IN_Startup 655 =========== 656 */ 657 void IN_Startup( void ) { 658 Com_Printf ("\n------- Input Initialization -------\n"); 659 IN_StartupMouse (); 660 IN_StartupJoystick (); 661 IN_StartupMIDI(); 662 Com_Printf ("------------------------------------\n"); 663 664 in_mouse->modified = qfalse; 665 in_joystick->modified = qfalse; 666 } 667 668 /* 669 =========== 670 IN_Shutdown 671 =========== 672 */ 673 void IN_Shutdown( void ) { 674 IN_DeactivateMouse(); 675 IN_ShutdownDIMouse(); 676 IN_ShutdownMIDI(); 677 Cmd_RemoveCommand("midiinfo" ); 678 } 679 680 681 /* 682 =========== 683 IN_Init 684 =========== 685 */ 686 void IN_Init( void ) { 687 // MIDI input controler variables 688 in_midi = Cvar_Get ("in_midi", "0", CVAR_ARCHIVE); 689 in_midiport = Cvar_Get ("in_midiport", "1", CVAR_ARCHIVE); 690 in_midichannel = Cvar_Get ("in_midichannel", "1", CVAR_ARCHIVE); 691 in_mididevice = Cvar_Get ("in_mididevice", "0", CVAR_ARCHIVE); 692 693 Cmd_AddCommand( "midiinfo", MidiInfo_f ); 694 695 // mouse variables 696 in_mouse = Cvar_Get ("in_mouse", "1", CVAR_ARCHIVE|CVAR_LATCH); 697 in_logitechbug = Cvar_Get ("in_logitechbug", "0", CVAR_ARCHIVE); 698 699 // joystick variables 700 in_joystick = Cvar_Get ("in_joystick", "0", CVAR_ARCHIVE|CVAR_LATCH); 701 in_joyBallScale = Cvar_Get ("in_joyBallScale", "0.02", CVAR_ARCHIVE); 702 in_debugJoystick = Cvar_Get ("in_debugjoystick", "0", CVAR_TEMP); 703 704 joy_threshold = Cvar_Get ("joy_threshold", "0.15", CVAR_ARCHIVE); 705 706 IN_Startup(); 707 } 708 709 710 /* 711 =========== 712 IN_Activate 713 714 Called when the main window gains or loses focus. 715 The window may have been destroyed and recreated 716 between a deactivate and an activate. 717 =========== 718 */ 719 void IN_Activate (qboolean active) { 720 in_appactive = active; 721 722 if ( !active ) 723 { 724 IN_DeactivateMouse(); 725 } 726 } 727 728 729 /* 730 ================== 731 IN_Frame 732 733 Called every frame, even if not generating commands 734 ================== 735 */ 736 void IN_Frame (void) { 737 // post joystick events 738 IN_JoyMove(); 739 740 if ( !s_wmv.mouseInitialized ) { 741 if (s_wmv.mouseStartupDelayed && g_wv.hWnd) 742 { 743 Com_Printf("Proceeding with delayed mouse init\n"); 744 IN_StartupMouse(); 745 s_wmv.mouseStartupDelayed = qfalse; 746 } 747 return; 748 } 749 750 if ( cls.keyCatchers & KEYCATCH_CONSOLE ) { 751 // temporarily deactivate if not in the game and 752 // running on the desktop 753 // voodoo always counts as full screen 754 if (Cvar_VariableValue ("r_fullscreen") == 0 755 && strcmp( Cvar_VariableString("r_glDriver"), _3DFX_DRIVER_NAME) ) { 756 IN_DeactivateMouse (); 757 return; 758 } 759 } 760 761 if ( !in_appactive ) { 762 IN_DeactivateMouse (); 763 return; 764 } 765 766 IN_ActivateMouse(); 767 768 // post events to the system que 769 IN_MouseMove(); 770 771 } 772 773 774 /* 775 =================== 776 IN_ClearStates 777 =================== 778 */ 779 void IN_ClearStates (void) 780 { 781 s_wmv.oldButtonState = 0; 782 } 783 784 785 /* 786 ========================================================================= 787 788 JOYSTICK 789 790 ========================================================================= 791 */ 792 793 /* 794 =============== 795 IN_StartupJoystick 796 =============== 797 */ 798 void IN_StartupJoystick (void) { 799 int numdevs; 800 MMRESULT mmr; 801 802 // assume no joystick 803 joy.avail = qfalse; 804 805 if (! in_joystick->integer ) { 806 Com_Printf ("Joystick is not active.\n"); 807 return; 808 } 809 810 // verify joystick driver is present 811 if ((numdevs = joyGetNumDevs ()) == 0) 812 { 813 Com_Printf ("joystick not found -- driver not present\n"); 814 return; 815 } 816 817 // cycle through the joystick ids for the first valid one 818 mmr = 0; 819 for (joy.id=0 ; joy.id<numdevs ; joy.id++) 820 { 821 Com_Memset (&joy.ji, 0, sizeof(joy.ji)); 822 joy.ji.dwSize = sizeof(joy.ji); 823 joy.ji.dwFlags = JOY_RETURNCENTERED; 824 825 if ((mmr = joyGetPosEx (joy.id, &joy.ji)) == JOYERR_NOERROR) 826 break; 827 } 828 829 // abort startup if we didn't find a valid joystick 830 if (mmr != JOYERR_NOERROR) 831 { 832 Com_Printf ("joystick not found -- no valid joysticks (%x)\n", mmr); 833 return; 834 } 835 836 // get the capabilities of the selected joystick 837 // abort startup if command fails 838 Com_Memset (&joy.jc, 0, sizeof(joy.jc)); 839 if ((mmr = joyGetDevCaps (joy.id, &joy.jc, sizeof(joy.jc))) != JOYERR_NOERROR) 840 { 841 Com_Printf ("joystick not found -- invalid joystick capabilities (%x)\n", mmr); 842 return; 843 } 844 845 Com_Printf( "Joystick found.\n" ); 846 Com_Printf( "Pname: %s\n", joy.jc.szPname ); 847 Com_Printf( "OemVxD: %s\n", joy.jc.szOEMVxD ); 848 Com_Printf( "RegKey: %s\n", joy.jc.szRegKey ); 849 850 Com_Printf( "Numbuttons: %i / %i\n", joy.jc.wNumButtons, joy.jc.wMaxButtons ); 851 Com_Printf( "Axis: %i / %i\n", joy.jc.wNumAxes, joy.jc.wMaxAxes ); 852 Com_Printf( "Caps: 0x%x\n", joy.jc.wCaps ); 853 if ( joy.jc.wCaps & JOYCAPS_HASPOV ) { 854 Com_Printf( "HASPOV\n" ); 855 } else { 856 Com_Printf( "no POV\n" ); 857 } 858 859 // old button and POV states default to no buttons pressed 860 joy.oldbuttonstate = 0; 861 joy.oldpovstate = 0; 862 863 // mark the joystick as available 864 joy.avail = qtrue; 865 } 866 867 /* 868 =========== 869 JoyToF 870 =========== 871 */ 872 float JoyToF( int value ) { 873 float fValue; 874 875 // move centerpoint to zero 876 value -= 32768; 877 878 // convert range from -32768..32767 to -1..1 879 fValue = (float)value / 32768.0; 880 881 if ( fValue < -1 ) { 882 fValue = -1; 883 } 884 if ( fValue > 1 ) { 885 fValue = 1; 886 } 887 return fValue; 888 } 889 890 int JoyToI( int value ) { 891 // move centerpoint to zero 892 value -= 32768; 893 894 return value; 895 } 896 897 int joyDirectionKeys[16] = { 898 K_LEFTARROW, K_RIGHTARROW, 899 K_UPARROW, K_DOWNARROW, 900 K_JOY16, K_JOY17, 901 K_JOY18, K_JOY19, 902 K_JOY20, K_JOY21, 903 K_JOY22, K_JOY23, 904 905 K_JOY24, K_JOY25, 906 K_JOY26, K_JOY27 907 }; 908 909 /* 910 =========== 911 IN_JoyMove 912 =========== 913 */ 914 void IN_JoyMove( void ) { 915 float fAxisValue; 916 int i; 917 DWORD buttonstate, povstate; 918 int x, y; 919 920 // verify joystick is available and that the user wants to use it 921 if ( !joy.avail ) { 922 return; 923 } 924 925 // collect the joystick data, if possible 926 Com_Memset (&joy.ji, 0, sizeof(joy.ji)); 927 joy.ji.dwSize = sizeof(joy.ji); 928 joy.ji.dwFlags = JOY_RETURNALL; 929 930 if ( joyGetPosEx (joy.id, &joy.ji) != JOYERR_NOERROR ) { 931 // read error occurred 932 // turning off the joystick seems too harsh for 1 read error,\ 933 // but what should be done? 934 // Com_Printf ("IN_ReadJoystick: no response\n"); 935 // joy.avail = false; 936 return; 937 } 938 939 if ( in_debugJoystick->integer ) { 940 Com_Printf( "%8x %5i %5.2f %5.2f %5.2f %5.2f %6i %6i\n", 941 joy.ji.dwButtons, 942 joy.ji.dwPOV, 943 JoyToF( joy.ji.dwXpos ), JoyToF( joy.ji.dwYpos ), 944 JoyToF( joy.ji.dwZpos ), JoyToF( joy.ji.dwRpos ), 945 JoyToI( joy.ji.dwUpos ), JoyToI( joy.ji.dwVpos ) ); 946 } 947 948 // loop through the joystick buttons 949 // key a joystick event or auxillary event for higher number buttons for each state change 950 buttonstate = joy.ji.dwButtons; 951 for ( i=0 ; i < joy.jc.wNumButtons ; i++ ) { 952 if ( (buttonstate & (1<<i)) && !(joy.oldbuttonstate & (1<<i)) ) { 953 Sys_QueEvent( g_wv.sysMsgTime, SE_KEY, K_JOY1 + i, qtrue, 0, NULL ); 954 } 955 if ( !(buttonstate & (1<<i)) && (joy.oldbuttonstate & (1<<i)) ) { 956 Sys_QueEvent( g_wv.sysMsgTime, SE_KEY, K_JOY1 + i, qfalse, 0, NULL ); 957 } 958 } 959 joy.oldbuttonstate = buttonstate; 960 961 povstate = 0; 962 963 // convert main joystick motion into 6 direction button bits 964 for (i = 0; i < joy.jc.wNumAxes && i < 4 ; i++) { 965 // get the floating point zero-centered, potentially-inverted data for the current axis 966 fAxisValue = JoyToF( (&joy.ji.dwXpos)[i] ); 967 968 if ( fAxisValue < -joy_threshold->value ) { 969 povstate |= (1<<(i*2)); 970 } else if ( fAxisValue > joy_threshold->value ) { 971 povstate |= (1<<(i*2+1)); 972 } 973 } 974 975 // convert POV information from a direction into 4 button bits 976 if ( joy.jc.wCaps & JOYCAPS_HASPOV ) { 977 if ( joy.ji.dwPOV != JOY_POVCENTERED ) { 978 if (joy.ji.dwPOV == JOY_POVFORWARD) 979 povstate |= 1<<12; 980 if (joy.ji.dwPOV == JOY_POVBACKWARD) 981 povstate |= 1<<13; 982 if (joy.ji.dwPOV == JOY_POVRIGHT) 983 povstate |= 1<<14; 984 if (joy.ji.dwPOV == JOY_POVLEFT) 985 povstate |= 1<<15; 986 } 987 } 988 989 // determine which bits have changed and key an auxillary event for each change 990 for (i=0 ; i < 16 ; i++) { 991 if ( (povstate & (1<<i)) && !(joy.oldpovstate & (1<<i)) ) { 992 Sys_QueEvent( g_wv.sysMsgTime, SE_KEY, joyDirectionKeys[i], qtrue, 0, NULL ); 993 } 994 995 if ( !(povstate & (1<<i)) && (joy.oldpovstate & (1<<i)) ) { 996 Sys_QueEvent( g_wv.sysMsgTime, SE_KEY, joyDirectionKeys[i], qfalse, 0, NULL ); 997 } 998 } 999 joy.oldpovstate = povstate; 1000 1001 // if there is a trackball like interface, simulate mouse moves 1002 if ( joy.jc.wNumAxes >= 6 ) { 1003 x = JoyToI( joy.ji.dwUpos ) * in_joyBallScale->value; 1004 y = JoyToI( joy.ji.dwVpos ) * in_joyBallScale->value; 1005 if ( x || y ) { 1006 Sys_QueEvent( g_wv.sysMsgTime, SE_MOUSE, x, y, 0, NULL ); 1007 } 1008 } 1009 } 1010 1011 /* 1012 ========================================================================= 1013 1014 MIDI 1015 1016 ========================================================================= 1017 */ 1018 1019 static void MIDI_NoteOff( int note ) 1020 { 1021 int qkey; 1022 1023 qkey = note - 60 + K_AUX1; 1024 1025 if ( qkey > 255 || qkey < K_AUX1 ) 1026 return; 1027 1028 Sys_QueEvent( g_wv.sysMsgTime, SE_KEY, qkey, qfalse, 0, NULL ); 1029 } 1030 1031 static void MIDI_NoteOn( int note, int velocity ) 1032 { 1033 int qkey; 1034 1035 if ( velocity == 0 ) 1036 MIDI_NoteOff( note ); 1037 1038 qkey = note - 60 + K_AUX1; 1039 1040 if ( qkey > 255 || qkey < K_AUX1 ) 1041 return; 1042 1043 Sys_QueEvent( g_wv.sysMsgTime, SE_KEY, qkey, qtrue, 0, NULL ); 1044 } 1045 1046 static void CALLBACK MidiInProc( HMIDIIN hMidiIn, UINT uMsg, DWORD dwInstance, 1047 DWORD dwParam1, DWORD dwParam2 ) 1048 { 1049 int message; 1050 1051 switch ( uMsg ) 1052 { 1053 case MIM_OPEN: 1054 break; 1055 case MIM_CLOSE: 1056 break; 1057 case MIM_DATA: 1058 message = dwParam1 & 0xff; 1059 1060 // note on 1061 if ( ( message & 0xf0 ) == 0x90 ) 1062 { 1063 if ( ( ( message & 0x0f ) + 1 ) == in_midichannel->integer ) 1064 MIDI_NoteOn( ( dwParam1 & 0xff00 ) >> 8, ( dwParam1 & 0xff0000 ) >> 16 ); 1065 } 1066 else if ( ( message & 0xf0 ) == 0x80 ) 1067 { 1068 if ( ( ( message & 0x0f ) + 1 ) == in_midichannel->integer ) 1069 MIDI_NoteOff( ( dwParam1 & 0xff00 ) >> 8 ); 1070 } 1071 break; 1072 case MIM_LONGDATA: 1073 break; 1074 case MIM_ERROR: 1075 break; 1076 case MIM_LONGERROR: 1077 break; 1078 } 1079 1080 // Sys_QueEvent( sys_msg_time, SE_KEY, wMsg, qtrue, 0, NULL ); 1081 } 1082 1083 static void MidiInfo_f( void ) 1084 { 1085 int i; 1086 1087 const char *enableStrings[] = { "disabled", "enabled" }; 1088 1089 Com_Printf( "\nMIDI control: %s\n", enableStrings[in_midi->integer != 0] ); 1090 Com_Printf( "port: %d\n", in_midiport->integer ); 1091 Com_Printf( "channel: %d\n", in_midichannel->integer ); 1092 Com_Printf( "current device: %d\n", in_mididevice->integer ); 1093 Com_Printf( "number of devices: %d\n", s_midiInfo.numDevices ); 1094 for ( i = 0; i < s_midiInfo.numDevices; i++ ) 1095 { 1096 if ( i == Cvar_VariableValue( "in_mididevice" ) ) 1097 Com_Printf( "***" ); 1098 else 1099 Com_Printf( "..." ); 1100 Com_Printf( "device %2d: %s\n", i, s_midiInfo.caps[i].szPname ); 1101 Com_Printf( "...manufacturer ID: 0x%hx\n", s_midiInfo.caps[i].wMid ); 1102 Com_Printf( "...product ID: 0x%hx\n", s_midiInfo.caps[i].wPid ); 1103 1104 Com_Printf( "\n" ); 1105 } 1106 } 1107 1108 static void IN_StartupMIDI( void ) 1109 { 1110 int i; 1111 1112 if ( !Cvar_VariableValue( "in_midi" ) ) 1113 return; 1114 1115 // 1116 // enumerate MIDI IN devices 1117 // 1118 s_midiInfo.numDevices = midiInGetNumDevs(); 1119 1120 for ( i = 0; i < s_midiInfo.numDevices; i++ ) 1121 { 1122 midiInGetDevCaps( i, &s_midiInfo.caps[i], sizeof( s_midiInfo.caps[i] ) ); 1123 } 1124 1125 // 1126 // open the MIDI IN port 1127 // 1128 if ( midiInOpen( &s_midiInfo.hMidiIn, 1129 in_mididevice->integer, 1130 ( unsigned long ) MidiInProc, 1131 ( unsigned long ) NULL, 1132 CALLBACK_FUNCTION ) != MMSYSERR_NOERROR ) 1133 { 1134 Com_Printf( "WARNING: could not open MIDI device %d: '%s'\n", in_mididevice->integer , s_midiInfo.caps[( int ) in_mididevice->value] ); 1135 return; 1136 } 1137 1138 midiInStart( s_midiInfo.hMidiIn ); 1139 } 1140 1141 static void IN_ShutdownMIDI( void ) 1142 { 1143 if ( s_midiInfo.hMidiIn ) 1144 { 1145 midiInClose( s_midiInfo.hMidiIn ); 1146 } 1147 Com_Memset( &s_midiInfo, 0, sizeof( s_midiInfo ) ); 1148 } 1149