Main Page | Class Hierarchy | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals

win_input.c

Go to the documentation of this file.
00001 /*
00002 ===========================================================================
00003 Copyright (C) 1999-2005 Id Software, Inc.
00004 
00005 This file is part of Quake III Arena source code.
00006 
00007 Quake III Arena source code is free software; you can redistribute it
00008 and/or modify it under the terms of the GNU General Public License as
00009 published by the Free Software Foundation; either version 2 of the License,
00010 or (at your option) any later version.
00011 
00012 Quake III Arena source code is distributed in the hope that it will be
00013 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015 GNU General Public License for more details.
00016 
00017 You should have received a copy of the GNU General Public License
00018 along with Foobar; if not, write to the Free Software
00019 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00020 ===========================================================================
00021 */
00022 // win_input.c -- win32 mouse and joystick code
00023 // 02/21/97 JCB Added extended DirectInput code to support external controllers.
00024 
00025 #include "../client/client.h"
00026 #include "win_local.h"
00027 
00028 
00029 typedef struct {
00030     int         oldButtonState;
00031 
00032     qboolean    mouseActive;
00033     qboolean    mouseInitialized;
00034   qboolean  mouseStartupDelayed; // delay mouse init to try DI again when we have a window
00035 } WinMouseVars_t;
00036 
00037 static WinMouseVars_t s_wmv;
00038 
00039 static int  window_center_x, window_center_y;
00040 
00041 //
00042 // MIDI definitions
00043 //
00044 static void IN_StartupMIDI( void );
00045 static void IN_ShutdownMIDI( void );
00046 
00047 #define MAX_MIDIIN_DEVICES  8
00048 
00049 typedef struct {
00050     int         numDevices;
00051     MIDIINCAPS  caps[MAX_MIDIIN_DEVICES];
00052 
00053     HMIDIIN     hMidiIn;
00054 } MidiInfo_t;
00055 
00056 static MidiInfo_t s_midiInfo;
00057 
00058 //
00059 // Joystick definitions
00060 //
00061 #define JOY_MAX_AXES        6               // X, Y, Z, R, U, V
00062 
00063 typedef struct {
00064     qboolean    avail;
00065     int         id;         // joystick number
00066     JOYCAPS     jc;
00067 
00068     int         oldbuttonstate;
00069     int         oldpovstate;
00070 
00071     JOYINFOEX   ji;
00072 } joystickInfo_t;
00073 
00074 static  joystickInfo_t  joy;
00075 
00076 
00077 
00078 cvar_t  *in_midi;
00079 cvar_t  *in_midiport;
00080 cvar_t  *in_midichannel;
00081 cvar_t  *in_mididevice;
00082 
00083 cvar_t  *in_mouse;
00084 cvar_t  *in_logitechbug;
00085 cvar_t  *in_joystick;
00086 cvar_t  *in_joyBallScale;
00087 cvar_t  *in_debugJoystick;
00088 cvar_t  *joy_threshold;
00089 
00090 qboolean    in_appactive;
00091 
00092 // forward-referenced functions
00093 void IN_StartupJoystick (void);
00094 void IN_JoyMove(void);
00095 
00096 static void MidiInfo_f( void );
00097 
00098 /*
00099 ============================================================
00100 
00101 WIN32 MOUSE CONTROL
00102 
00103 ============================================================
00104 */
00105 
00106 /*
00107 ================
00108 IN_InitWin32Mouse
00109 ================
00110 */
00111 void IN_InitWin32Mouse( void ) 
00112 {
00113 }
00114 
00115 /*
00116 ================
00117 IN_ShutdownWin32Mouse
00118 ================
00119 */
00120 void IN_ShutdownWin32Mouse( void ) {
00121 }
00122 
00123 /*
00124 ================
00125 IN_ActivateWin32Mouse
00126 ================
00127 */
00128 void IN_ActivateWin32Mouse( void ) {
00129     int         width, height;
00130     RECT        window_rect;
00131 
00132     width = GetSystemMetrics (SM_CXSCREEN);
00133     height = GetSystemMetrics (SM_CYSCREEN);
00134 
00135     GetWindowRect ( g_wv.hWnd, &window_rect);
00136     if (window_rect.left < 0)
00137         window_rect.left = 0;
00138     if (window_rect.top < 0)
00139         window_rect.top = 0;
00140     if (window_rect.right >= width)
00141         window_rect.right = width-1;
00142     if (window_rect.bottom >= height-1)
00143         window_rect.bottom = height-1;
00144     window_center_x = (window_rect.right + window_rect.left)/2;
00145     window_center_y = (window_rect.top + window_rect.bottom)/2;
00146 
00147     SetCursorPos (window_center_x, window_center_y);
00148 
00149     SetCapture ( g_wv.hWnd );
00150     ClipCursor (&window_rect);
00151     while (ShowCursor (FALSE) >= 0)
00152         ;
00153 }
00154 
00155 /*
00156 ================
00157 IN_DeactivateWin32Mouse
00158 ================
00159 */
00160 void IN_DeactivateWin32Mouse( void ) 
00161 {
00162     ClipCursor (NULL);
00163     ReleaseCapture ();
00164     while (ShowCursor (TRUE) < 0)
00165         ;
00166 }
00167 
00168 /*
00169 ================
00170 IN_Win32Mouse
00171 ================
00172 */
00173 void IN_Win32Mouse( int *mx, int *my ) {
00174     POINT       current_pos;
00175 
00176     // find mouse movement
00177     GetCursorPos (&current_pos);
00178 
00179     // force the mouse to the center, so there's room to move
00180     SetCursorPos (window_center_x, window_center_y);
00181 
00182     *mx = current_pos.x - window_center_x;
00183     *my = current_pos.y - window_center_y;
00184 }
00185 
00186 
00187 /*
00188 ============================================================
00189 
00190 DIRECT INPUT MOUSE CONTROL
00191 
00192 ============================================================
00193 */
00194 
00195 #undef DEFINE_GUID
00196 
00197 #define DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
00198         EXTERN_C const GUID name \
00199                 = { l, w1, w2, { b1, b2,  b3,  b4,  b5,  b6,  b7,  b8 } }
00200 
00201 DEFINE_GUID(GUID_SysMouse,   0x6F1D2B60,0xD5A0,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00);
00202 DEFINE_GUID(GUID_XAxis,   0xA36D02E0,0xC9F3,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00);
00203 DEFINE_GUID(GUID_YAxis,   0xA36D02E1,0xC9F3,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00);
00204 DEFINE_GUID(GUID_ZAxis,   0xA36D02E2,0xC9F3,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00);
00205 
00206 
00207 #define DINPUT_BUFFERSIZE           16
00208 #define iDirectInputCreate(a,b,c,d) pDirectInputCreate(a,b,c,d)
00209 
00210 HRESULT (WINAPI *pDirectInputCreate)(HINSTANCE hinst, DWORD dwVersion,
00211     LPDIRECTINPUT * lplpDirectInput, LPUNKNOWN punkOuter);
00212 
00213 static HINSTANCE hInstDI;
00214 
00215 typedef struct MYDATA {
00216     LONG  lX;                   // X axis goes here
00217     LONG  lY;                   // Y axis goes here
00218     LONG  lZ;                   // Z axis goes here
00219     BYTE  bButtonA;             // One button goes here
00220     BYTE  bButtonB;             // Another button goes here
00221     BYTE  bButtonC;             // Another button goes here
00222     BYTE  bButtonD;             // Another button goes here
00223 } MYDATA;
00224 
00225 static DIOBJECTDATAFORMAT rgodf[] = {
00226   { &GUID_XAxis,    FIELD_OFFSET(MYDATA, lX),       DIDFT_AXIS | DIDFT_ANYINSTANCE,   0,},
00227   { &GUID_YAxis,    FIELD_OFFSET(MYDATA, lY),       DIDFT_AXIS | DIDFT_ANYINSTANCE,   0,},
00228   { &GUID_ZAxis,    FIELD_OFFSET(MYDATA, lZ),       0x80000000 | DIDFT_AXIS | DIDFT_ANYINSTANCE,   0,},
00229   { 0,              FIELD_OFFSET(MYDATA, bButtonA), DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0,},
00230   { 0,              FIELD_OFFSET(MYDATA, bButtonB), DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0,},
00231   { 0,              FIELD_OFFSET(MYDATA, bButtonC), 0x80000000 | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0,},
00232   { 0,              FIELD_OFFSET(MYDATA, bButtonD), 0x80000000 | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0,},
00233 };
00234 
00235 #define NUM_OBJECTS (sizeof(rgodf) / sizeof(rgodf[0]))
00236 
00237 // NOTE TTimo: would be easier using c_dfDIMouse or c_dfDIMouse2 
00238 static DIDATAFORMAT df = {
00239     sizeof(DIDATAFORMAT),       // this structure
00240     sizeof(DIOBJECTDATAFORMAT), // size of object data format
00241     DIDF_RELAXIS,               // absolute axis coordinates
00242     sizeof(MYDATA),             // device data size
00243     NUM_OBJECTS,                // number of objects
00244     rgodf,                      // and here they are
00245 };
00246 
00247 static LPDIRECTINPUT        g_pdi;
00248 static LPDIRECTINPUTDEVICE  g_pMouse;
00249 
00250 void IN_DIMouse( int *mx, int *my );
00251 
00252 /*
00253 ========================
00254 IN_InitDIMouse
00255 ========================
00256 */
00257 qboolean IN_InitDIMouse( void ) {
00258     HRESULT     hr;
00259     int         x, y;
00260     DIPROPDWORD dipdw = {
00261         {
00262             sizeof(DIPROPDWORD),        // diph.dwSize
00263             sizeof(DIPROPHEADER),       // diph.dwHeaderSize
00264             0,                          // diph.dwObj
00265             DIPH_DEVICE,                // diph.dwHow
00266         },
00267         DINPUT_BUFFERSIZE,              // dwData
00268     };
00269 
00270     Com_Printf( "Initializing DirectInput...\n");
00271 
00272     if (!hInstDI) {
00273         hInstDI = LoadLibrary("dinput.dll");
00274         
00275         if (hInstDI == NULL) {
00276             Com_Printf ("Couldn't load dinput.dll\n");
00277             return qfalse;
00278         }
00279     }
00280 
00281     if (!pDirectInputCreate) {
00282         pDirectInputCreate = (long (__stdcall *)(void *,unsigned long ,struct IDirectInputA ** ,struct IUnknown *))
00283             GetProcAddress(hInstDI,"DirectInputCreateA");
00284 
00285         if (!pDirectInputCreate) {
00286             Com_Printf ("Couldn't get DI proc addr\n");
00287             return qfalse;
00288         }
00289     }
00290 
00291     // register with DirectInput and get an IDirectInput to play with.
00292     hr = iDirectInputCreate( g_wv.hInstance, DIRECTINPUT_VERSION, &g_pdi, NULL);
00293 
00294     if (FAILED(hr)) {
00295         Com_Printf ("iDirectInputCreate failed\n");
00296         return qfalse;
00297     }
00298 
00299     // obtain an interface to the system mouse device.
00300     hr = IDirectInput_CreateDevice(g_pdi, &GUID_SysMouse, &g_pMouse, NULL);
00301 
00302     if (FAILED(hr)) {
00303         Com_Printf ("Couldn't open DI mouse device\n");
00304         return qfalse;
00305     }
00306 
00307     // set the data format to "mouse format".
00308     hr = IDirectInputDevice_SetDataFormat(g_pMouse, &df);
00309 
00310     if (FAILED(hr))     {
00311         Com_Printf ("Couldn't set DI mouse format\n");
00312         return qfalse;
00313     }
00314 
00315     // set the cooperativity level.
00316     hr = IDirectInputDevice_SetCooperativeLevel(g_pMouse, g_wv.hWnd,
00317             DISCL_EXCLUSIVE | DISCL_FOREGROUND);
00318 
00319     // https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=50
00320     if (FAILED(hr)) {
00321         Com_Printf ("Couldn't set DI coop level\n");
00322         return qfalse;
00323     }
00324 
00325 
00326     // set the buffer size to DINPUT_BUFFERSIZE elements.
00327     // the buffer size is a DWORD property associated with the device
00328     hr = IDirectInputDevice_SetProperty(g_pMouse, DIPROP_BUFFERSIZE, &dipdw.diph);
00329 
00330     if (FAILED(hr)) {
00331         Com_Printf ("Couldn't set DI buffersize\n");
00332         return qfalse;
00333     }
00334 
00335     // clear any pending samples
00336     IN_DIMouse( &x, &y );
00337     IN_DIMouse( &x, &y );
00338 
00339     Com_Printf( "DirectInput initialized.\n");
00340     return qtrue;
00341 }
00342 
00343 /*
00344 ==========================
00345 IN_ShutdownDIMouse
00346 ==========================
00347 */
00348 void IN_ShutdownDIMouse( void ) {
00349     if (g_pMouse) {
00350         IDirectInputDevice_Release(g_pMouse);
00351         g_pMouse = NULL;
00352     }
00353 
00354     if (g_pdi) {
00355         IDirectInput_Release(g_pdi);
00356         g_pdi = NULL;
00357     }
00358 }
00359 
00360 /*
00361 ==========================
00362 IN_ActivateDIMouse
00363 ==========================
00364 */
00365 void IN_ActivateDIMouse( void ) {
00366     HRESULT     hr;
00367 
00368     if (!g_pMouse) {
00369         return;
00370     }
00371 
00372     // we may fail to reacquire if the window has been recreated
00373     hr = IDirectInputDevice_Acquire( g_pMouse );
00374     if (FAILED(hr)) {
00375         if ( !IN_InitDIMouse() ) {
00376             Com_Printf ("Falling back to Win32 mouse support...\n");
00377             Cvar_Set( "in_mouse", "-1" );
00378         }
00379     }
00380 }
00381 
00382 /*
00383 ==========================
00384 IN_DeactivateDIMouse
00385 ==========================
00386 */
00387 void IN_DeactivateDIMouse( void ) {
00388     if (!g_pMouse) {
00389         return;
00390     }
00391     IDirectInputDevice_Unacquire( g_pMouse );
00392 }
00393 
00394 
00395 /*
00396 ===================
00397 IN_DIMouse
00398 ===================
00399 */
00400 void IN_DIMouse( int *mx, int *my ) {
00401     DIDEVICEOBJECTDATA  od;
00402     DIMOUSESTATE        state;
00403     DWORD               dwElements;
00404     HRESULT             hr;
00405   int value;
00406     static float        oldSysTime;
00407 
00408     if ( !g_pMouse ) {
00409         return;
00410     }
00411 
00412     // fetch new events
00413     for (;;)
00414     {
00415         dwElements = 1;
00416 
00417         hr = IDirectInputDevice_GetDeviceData(g_pMouse,
00418                 sizeof(DIDEVICEOBJECTDATA), &od, &dwElements, 0);
00419         if ((hr == DIERR_INPUTLOST) || (hr == DIERR_NOTACQUIRED)) {
00420             IDirectInputDevice_Acquire(g_pMouse);
00421             return;
00422         }
00423 
00424         /* Unable to read data or no data available */
00425         if ( FAILED(hr) ) {
00426             break;
00427         }
00428 
00429         if ( dwElements == 0 ) {
00430             break;
00431         }
00432 
00433         switch (od.dwOfs) {
00434         case DIMOFS_BUTTON0:
00435             if (od.dwData & 0x80)
00436                 Sys_QueEvent( od.dwTimeStamp, SE_KEY, K_MOUSE1, qtrue, 0, NULL );
00437             else
00438                 Sys_QueEvent( od.dwTimeStamp, SE_KEY, K_MOUSE1, qfalse, 0, NULL );
00439             break;
00440 
00441         case DIMOFS_BUTTON1:
00442             if (od.dwData & 0x80)
00443                 Sys_QueEvent( od.dwTimeStamp, SE_KEY, K_MOUSE2, qtrue, 0, NULL );
00444             else
00445                 Sys_QueEvent( od.dwTimeStamp, SE_KEY, K_MOUSE2, qfalse, 0, NULL );
00446             break;
00447             
00448         case DIMOFS_BUTTON2:
00449             if (od.dwData & 0x80)
00450                 Sys_QueEvent( od.dwTimeStamp, SE_KEY, K_MOUSE3, qtrue, 0, NULL );
00451             else
00452                 Sys_QueEvent( od.dwTimeStamp, SE_KEY, K_MOUSE3, qfalse, 0, NULL );
00453             break;
00454 
00455         case DIMOFS_BUTTON3:
00456             if (od.dwData & 0x80)
00457                 Sys_QueEvent( od.dwTimeStamp, SE_KEY, K_MOUSE4, qtrue, 0, NULL );
00458             else
00459                 Sys_QueEvent( od.dwTimeStamp, SE_KEY, K_MOUSE4, qfalse, 0, NULL );
00460             break;      
00461     // https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=50
00462         case DIMOFS_Z:
00463             value = od.dwData;
00464             if (value == 0) {
00465 
00466             } else if (value < 0) {
00467                 Sys_QueEvent( od.dwTimeStamp, SE_KEY, K_MWHEELDOWN, qtrue, 0, NULL );
00468                 Sys_QueEvent( od.dwTimeStamp, SE_KEY, K_MWHEELDOWN, qfalse, 0, NULL );
00469             } else {
00470                 Sys_QueEvent( od.dwTimeStamp, SE_KEY, K_MWHEELUP, qtrue, 0, NULL );
00471                 Sys_QueEvent( od.dwTimeStamp, SE_KEY, K_MWHEELUP, qfalse, 0, NULL );
00472             }
00473             break;
00474         }
00475     }
00476 
00477     // read the raw delta counter and ignore
00478     // the individual sample time / values
00479     hr = IDirectInputDevice_GetDeviceState(g_pMouse,
00480             sizeof(DIDEVICEOBJECTDATA), &state);
00481     if ( FAILED(hr) ) {
00482         *mx = *my = 0;
00483         return;
00484     }
00485     *mx = state.lX;
00486     *my = state.lY;
00487 }
00488 
00489 /*
00490 ============================================================
00491 
00492   MOUSE CONTROL
00493 
00494 ============================================================
00495 */
00496 
00497 /*
00498 ===========
00499 IN_ActivateMouse
00500 
00501 Called when the window gains focus or changes in some way
00502 ===========
00503 */
00504 void IN_ActivateMouse( void ) 
00505 {
00506     if (!s_wmv.mouseInitialized ) {
00507         return;
00508     }
00509     if ( !in_mouse->integer ) 
00510     {
00511         s_wmv.mouseActive = qfalse;
00512         return;
00513     }
00514     if ( s_wmv.mouseActive ) 
00515     {
00516         return;
00517     }
00518 
00519     s_wmv.mouseActive = qtrue;
00520 
00521     if ( in_mouse->integer != -1 ) {
00522         IN_ActivateDIMouse();
00523     }
00524     IN_ActivateWin32Mouse();
00525 }
00526 
00527 
00528 /*
00529 ===========
00530 IN_DeactivateMouse
00531 
00532 Called when the window loses focus
00533 ===========
00534 */
00535 void IN_DeactivateMouse( void ) {
00536     if (!s_wmv.mouseInitialized ) {
00537         return;
00538     }
00539     if (!s_wmv.mouseActive ) {
00540         return;
00541     }
00542     s_wmv.mouseActive = qfalse;
00543 
00544     IN_DeactivateDIMouse();
00545     IN_DeactivateWin32Mouse();
00546 }
00547 
00548 
00549 
00550 /*
00551 ===========
00552 IN_StartupMouse
00553 ===========
00554 */
00555 void IN_StartupMouse( void ) 
00556 {
00557     s_wmv.mouseInitialized = qfalse;
00558   s_wmv.mouseStartupDelayed = qfalse;
00559 
00560     if ( in_mouse->integer == 0 ) {
00561         Com_Printf ("Mouse control not active.\n");
00562         return;
00563     }
00564 
00565     // nt4.0 direct input is screwed up
00566     if ( ( g_wv.osversion.dwPlatformId == VER_PLATFORM_WIN32_NT ) &&
00567          ( g_wv.osversion.dwMajorVersion == 4 ) )
00568     {
00569         Com_Printf ("Disallowing DirectInput on NT 4.0\n");
00570         Cvar_Set( "in_mouse", "-1" );
00571     }
00572 
00573     if ( in_mouse->integer == -1 ) {
00574         Com_Printf ("Skipping check for DirectInput\n");
00575     } else {
00576     if (!g_wv.hWnd)
00577     {
00578       Com_Printf ("No window for DirectInput mouse init, delaying\n");
00579       s_wmv.mouseStartupDelayed = qtrue;
00580       return;
00581     }
00582         if ( IN_InitDIMouse() ) {
00583         s_wmv.mouseInitialized = qtrue;
00584             return;
00585         }
00586         Com_Printf ("Falling back to Win32 mouse support...\n");
00587     }
00588     s_wmv.mouseInitialized = qtrue;
00589     IN_InitWin32Mouse();
00590 }
00591 
00592 /*
00593 ===========
00594 IN_MouseEvent
00595 ===========
00596 */
00597 void IN_MouseEvent (int mstate)
00598 {
00599     int     i;
00600 
00601     if ( !s_wmv.mouseInitialized )
00602         return;
00603 
00604 // perform button actions
00605     for  (i = 0 ; i < 3 ; i++ )
00606     {
00607         if ( (mstate & (1<<i)) &&
00608             !(s_wmv.oldButtonState & (1<<i)) )
00609         {
00610             Sys_QueEvent( g_wv.sysMsgTime, SE_KEY, K_MOUSE1 + i, qtrue, 0, NULL );
00611         }
00612 
00613         if ( !(mstate & (1<<i)) &&
00614             (s_wmv.oldButtonState & (1<<i)) )
00615         {
00616             Sys_QueEvent( g_wv.sysMsgTime, SE_KEY, K_MOUSE1 + i, qfalse, 0, NULL );
00617         }
00618     }   
00619 
00620     s_wmv.oldButtonState = mstate;
00621 }
00622 
00623 
00624 /*
00625 ===========
00626 IN_MouseMove
00627 ===========
00628 */
00629 void IN_MouseMove ( void ) {
00630     int     mx, my;
00631 
00632     if ( g_pMouse ) {
00633         IN_DIMouse( &mx, &my );
00634     } else {
00635         IN_Win32Mouse( &mx, &my );
00636     }
00637 
00638     if ( !mx && !my ) {
00639         return;
00640     }
00641 
00642     Sys_QueEvent( 0, SE_MOUSE, mx, my, 0, NULL );
00643 }
00644 
00645 
00646 /*
00647 =========================================================================
00648 
00649 =========================================================================
00650 */
00651 
00652 /*
00653 ===========
00654 IN_Startup
00655 ===========
00656 */
00657 void IN_Startup( void ) {
00658     Com_Printf ("\n------- Input Initialization -------\n");
00659     IN_StartupMouse ();
00660     IN_StartupJoystick ();
00661     IN_StartupMIDI();
00662     Com_Printf ("------------------------------------\n");
00663 
00664     in_mouse->modified = qfalse;
00665     in_joystick->modified = qfalse;
00666 }
00667 
00668 /*
00669 ===========
00670 IN_Shutdown
00671 ===========
00672 */
00673 void IN_Shutdown( void ) {
00674     IN_DeactivateMouse();
00675     IN_ShutdownDIMouse();
00676     IN_ShutdownMIDI();
00677     Cmd_RemoveCommand("midiinfo" );
00678 }
00679 
00680 
00681 /*
00682 ===========
00683 IN_Init
00684 ===========
00685 */
00686 void IN_Init( void ) {
00687     // MIDI input controler variables
00688     in_midi                 = Cvar_Get ("in_midi",                  "0",        CVAR_ARCHIVE);
00689     in_midiport             = Cvar_Get ("in_midiport",              "1",        CVAR_ARCHIVE);
00690     in_midichannel          = Cvar_Get ("in_midichannel",           "1",        CVAR_ARCHIVE);
00691     in_mididevice           = Cvar_Get ("in_mididevice",            "0",        CVAR_ARCHIVE);
00692 
00693     Cmd_AddCommand( "midiinfo", MidiInfo_f );
00694 
00695     // mouse variables
00696   in_mouse              = Cvar_Get ("in_mouse",                 "1",        CVAR_ARCHIVE|CVAR_LATCH);
00697     in_logitechbug  = Cvar_Get ("in_logitechbug", "0", CVAR_ARCHIVE);
00698 
00699     // joystick variables
00700     in_joystick             = Cvar_Get ("in_joystick",              "0",        CVAR_ARCHIVE|CVAR_LATCH);
00701     in_joyBallScale         = Cvar_Get ("in_joyBallScale",          "0.02",     CVAR_ARCHIVE);
00702     in_debugJoystick        = Cvar_Get ("in_debugjoystick",         "0",        CVAR_TEMP);
00703 
00704     joy_threshold           = Cvar_Get ("joy_threshold",            "0.15",     CVAR_ARCHIVE);
00705 
00706     IN_Startup();
00707 }
00708 
00709 
00710 /*
00711 ===========
00712 IN_Activate
00713 
00714 Called when the main window gains or loses focus.
00715 The window may have been destroyed and recreated
00716 between a deactivate and an activate.
00717 ===========
00718 */
00719 void IN_Activate (qboolean active) {
00720     in_appactive = active;
00721 
00722     if ( !active )
00723     {
00724         IN_DeactivateMouse();
00725     }
00726 }
00727 
00728 
00729 /*
00730 ==================
00731 IN_Frame
00732 
00733 Called every frame, even if not generating commands
00734 ==================
00735 */
00736 void IN_Frame (void) {
00737     // post joystick events
00738     IN_JoyMove();
00739 
00740     if ( !s_wmv.mouseInitialized ) {
00741     if (s_wmv.mouseStartupDelayed && g_wv.hWnd)
00742         {
00743             Com_Printf("Proceeding with delayed mouse init\n");
00744       IN_StartupMouse();
00745             s_wmv.mouseStartupDelayed = qfalse;
00746         }
00747         return;
00748     }
00749 
00750     if ( cls.keyCatchers & KEYCATCH_CONSOLE ) {
00751         // temporarily deactivate if not in the game and
00752         // running on the desktop
00753         // voodoo always counts as full screen
00754         if (Cvar_VariableValue ("r_fullscreen") == 0
00755             && strcmp( Cvar_VariableString("r_glDriver"), _3DFX_DRIVER_NAME) )  {
00756             IN_DeactivateMouse ();
00757             return;
00758         }
00759     }
00760 
00761     if ( !in_appactive ) {
00762         IN_DeactivateMouse ();
00763         return;
00764     }
00765 
00766     IN_ActivateMouse();
00767 
00768     // post events to the system que
00769     IN_MouseMove();
00770 
00771 }
00772 
00773 
00774 /*
00775 ===================
00776 IN_ClearStates
00777 ===================
00778 */
00779 void IN_ClearStates (void) 
00780 {
00781     s_wmv.oldButtonState = 0;
00782 }
00783 
00784 
00785 /*
00786 =========================================================================
00787 
00788 JOYSTICK
00789 
00790 =========================================================================
00791 */
00792 
00793 /* 
00794 =============== 
00795 IN_StartupJoystick 
00796 =============== 
00797 */  
00798 void IN_StartupJoystick (void) { 
00799     int         numdevs;
00800     MMRESULT    mmr;
00801 
00802     // assume no joystick
00803     joy.avail = qfalse; 
00804 
00805     if (! in_joystick->integer ) {
00806         Com_Printf ("Joystick is not active.\n");
00807         return;
00808     }
00809 
00810     // verify joystick driver is present
00811     if ((numdevs = joyGetNumDevs ()) == 0)
00812     {
00813         Com_Printf ("joystick not found -- driver not present\n");
00814         return;
00815     }
00816 
00817     // cycle through the joystick ids for the first valid one
00818     mmr = 0;
00819     for (joy.id=0 ; joy.id<numdevs ; joy.id++)
00820     {
00821         Com_Memset (&joy.ji, 0, sizeof(joy.ji));
00822         joy.ji.dwSize = sizeof(joy.ji);
00823         joy.ji.dwFlags = JOY_RETURNCENTERED;
00824 
00825         if ((mmr = joyGetPosEx (joy.id, &joy.ji)) == JOYERR_NOERROR)
00826             break;
00827     } 
00828 
00829     // abort startup if we didn't find a valid joystick
00830     if (mmr != JOYERR_NOERROR)
00831     {
00832         Com_Printf ("joystick not found -- no valid joysticks (%x)\n", mmr);
00833         return;
00834     }
00835 
00836     // get the capabilities of the selected joystick
00837     // abort startup if command fails
00838     Com_Memset (&joy.jc, 0, sizeof(joy.jc));
00839     if ((mmr = joyGetDevCaps (joy.id, &joy.jc, sizeof(joy.jc))) != JOYERR_NOERROR)
00840     {
00841         Com_Printf ("joystick not found -- invalid joystick capabilities (%x)\n", mmr); 
00842         return;
00843     }
00844 
00845     Com_Printf( "Joystick found.\n" );
00846     Com_Printf( "Pname: %s\n", joy.jc.szPname );
00847     Com_Printf( "OemVxD: %s\n", joy.jc.szOEMVxD );
00848     Com_Printf( "RegKey: %s\n", joy.jc.szRegKey );
00849 
00850     Com_Printf( "Numbuttons: %i / %i\n", joy.jc.wNumButtons, joy.jc.wMaxButtons );
00851     Com_Printf( "Axis: %i / %i\n", joy.jc.wNumAxes, joy.jc.wMaxAxes );
00852     Com_Printf( "Caps: 0x%x\n", joy.jc.wCaps );
00853     if ( joy.jc.wCaps & JOYCAPS_HASPOV ) {
00854         Com_Printf( "HASPOV\n" );
00855     } else {
00856         Com_Printf( "no POV\n" );
00857     }
00858 
00859     // old button and POV states default to no buttons pressed
00860     joy.oldbuttonstate = 0;
00861     joy.oldpovstate = 0;
00862 
00863     // mark the joystick as available
00864     joy.avail = qtrue; 
00865 }
00866 
00867 /*
00868 ===========
00869 JoyToF
00870 ===========
00871 */
00872 float JoyToF( int value ) {
00873     float   fValue;
00874 
00875     // move centerpoint to zero
00876     value -= 32768;
00877 
00878     // convert range from -32768..32767 to -1..1 
00879     fValue = (float)value / 32768.0;
00880 
00881     if ( fValue < -1 ) {
00882         fValue = -1;
00883     }
00884     if ( fValue > 1 ) {
00885         fValue = 1;
00886     }
00887     return fValue;
00888 }
00889 
00890 int JoyToI( int value ) {
00891     // move centerpoint to zero
00892     value -= 32768;
00893 
00894     return value;
00895 }
00896 
00897 int joyDirectionKeys[16] = {
00898     K_LEFTARROW, K_RIGHTARROW,
00899     K_UPARROW, K_DOWNARROW,
00900     K_JOY16, K_JOY17,
00901     K_JOY18, K_JOY19,
00902     K_JOY20, K_JOY21,
00903     K_JOY22, K_JOY23,
00904 
00905     K_JOY24, K_JOY25,
00906     K_JOY26, K_JOY27
00907 };
00908 
00909 /*
00910 ===========
00911 IN_JoyMove
00912 ===========
00913 */
00914 void IN_JoyMove( void ) {
00915     float   fAxisValue;
00916     int     i;
00917     DWORD   buttonstate, povstate;
00918     int     x, y;
00919 
00920     // verify joystick is available and that the user wants to use it
00921     if ( !joy.avail ) {
00922         return; 
00923     }
00924 
00925     // collect the joystick data, if possible
00926     Com_Memset (&joy.ji, 0, sizeof(joy.ji));
00927     joy.ji.dwSize = sizeof(joy.ji);
00928     joy.ji.dwFlags = JOY_RETURNALL;
00929 
00930     if ( joyGetPosEx (joy.id, &joy.ji) != JOYERR_NOERROR ) {
00931         // read error occurred
00932         // turning off the joystick seems too harsh for 1 read error,\
00933         // but what should be done?
00934         // Com_Printf ("IN_ReadJoystick: no response\n");
00935         // joy.avail = false;
00936         return;
00937     }
00938 
00939     if ( in_debugJoystick->integer ) {
00940         Com_Printf( "%8x %5i %5.2f %5.2f %5.2f %5.2f %6i %6i\n", 
00941             joy.ji.dwButtons,
00942             joy.ji.dwPOV,
00943             JoyToF( joy.ji.dwXpos ), JoyToF( joy.ji.dwYpos ),
00944             JoyToF( joy.ji.dwZpos ), JoyToF( joy.ji.dwRpos ),
00945             JoyToI( joy.ji.dwUpos ), JoyToI( joy.ji.dwVpos ) );
00946     }
00947 
00948     // loop through the joystick buttons
00949     // key a joystick event or auxillary event for higher number buttons for each state change
00950     buttonstate = joy.ji.dwButtons;
00951     for ( i=0 ; i < joy.jc.wNumButtons ; i++ ) {
00952         if ( (buttonstate & (1<<i)) && !(joy.oldbuttonstate & (1<<i)) ) {
00953             Sys_QueEvent( g_wv.sysMsgTime, SE_KEY, K_JOY1 + i, qtrue, 0, NULL );
00954         }
00955         if ( !(buttonstate & (1<<i)) && (joy.oldbuttonstate & (1<<i)) ) {
00956             Sys_QueEvent( g_wv.sysMsgTime, SE_KEY, K_JOY1 + i, qfalse, 0, NULL );
00957         }
00958     }
00959     joy.oldbuttonstate = buttonstate;
00960 
00961     povstate = 0;
00962 
00963     // convert main joystick motion into 6 direction button bits
00964     for (i = 0; i < joy.jc.wNumAxes && i < 4 ; i++) {
00965         // get the floating point zero-centered, potentially-inverted data for the current axis
00966         fAxisValue = JoyToF( (&joy.ji.dwXpos)[i] );
00967 
00968         if ( fAxisValue < -joy_threshold->value ) {
00969             povstate |= (1<<(i*2));
00970         } else if ( fAxisValue > joy_threshold->value ) {
00971             povstate |= (1<<(i*2+1));
00972         }
00973     }
00974 
00975     // convert POV information from a direction into 4 button bits
00976     if ( joy.jc.wCaps & JOYCAPS_HASPOV ) {
00977         if ( joy.ji.dwPOV != JOY_POVCENTERED ) {
00978             if (joy.ji.dwPOV == JOY_POVFORWARD)
00979                 povstate |= 1<<12;
00980             if (joy.ji.dwPOV == JOY_POVBACKWARD)
00981                 povstate |= 1<<13;
00982             if (joy.ji.dwPOV == JOY_POVRIGHT)
00983                 povstate |= 1<<14;
00984             if (joy.ji.dwPOV == JOY_POVLEFT)
00985                 povstate |= 1<<15;
00986         }
00987     }
00988 
00989     // determine which bits have changed and key an auxillary event for each change
00990     for (i=0 ; i < 16 ; i++) {
00991         if ( (povstate & (1<<i)) && !(joy.oldpovstate & (1<<i)) ) {
00992             Sys_QueEvent( g_wv.sysMsgTime, SE_KEY, joyDirectionKeys[i], qtrue, 0, NULL );
00993         }
00994 
00995         if ( !(povstate & (1<<i)) && (joy.oldpovstate & (1<<i)) ) {
00996             Sys_QueEvent( g_wv.sysMsgTime, SE_KEY, joyDirectionKeys[i], qfalse, 0, NULL );
00997         }
00998     }
00999     joy.oldpovstate = povstate;
01000 
01001     // if there is a trackball like interface, simulate mouse moves
01002     if ( joy.jc.wNumAxes >= 6 ) {
01003         x = JoyToI( joy.ji.dwUpos ) * in_joyBallScale->value;
01004         y = JoyToI( joy.ji.dwVpos ) * in_joyBallScale->value;
01005         if ( x || y ) {
01006             Sys_QueEvent( g_wv.sysMsgTime, SE_MOUSE, x, y, 0, NULL );
01007         }
01008     }
01009 }
01010 
01011 /*
01012 =========================================================================
01013 
01014 MIDI
01015 
01016 =========================================================================
01017 */
01018 
01019 static void MIDI_NoteOff( int note )
01020 {
01021     int qkey;
01022 
01023     qkey = note - 60 + K_AUX1;
01024 
01025     if ( qkey > 255 || qkey < K_AUX1 )
01026         return;
01027 
01028     Sys_QueEvent( g_wv.sysMsgTime, SE_KEY, qkey, qfalse, 0, NULL );
01029 }
01030 
01031 static void MIDI_NoteOn( int note, int velocity )
01032 {
01033     int qkey;
01034 
01035     if ( velocity == 0 )
01036         MIDI_NoteOff( note );
01037 
01038     qkey = note - 60 + K_AUX1;
01039 
01040     if ( qkey > 255 || qkey < K_AUX1 )
01041         return;
01042 
01043     Sys_QueEvent( g_wv.sysMsgTime, SE_KEY, qkey, qtrue, 0, NULL );
01044 }
01045 
01046 static void CALLBACK MidiInProc( HMIDIIN hMidiIn, UINT uMsg, DWORD dwInstance, 
01047                                  DWORD dwParam1, DWORD dwParam2 )
01048 {
01049     int message;
01050 
01051     switch ( uMsg )
01052     {
01053     case MIM_OPEN:
01054         break;
01055     case MIM_CLOSE:
01056         break;
01057     case MIM_DATA:
01058         message = dwParam1 & 0xff;
01059 
01060         // note on
01061         if ( ( message & 0xf0 ) == 0x90 )
01062         {
01063             if ( ( ( message & 0x0f ) + 1 ) == in_midichannel->integer )
01064                 MIDI_NoteOn( ( dwParam1 & 0xff00 ) >> 8, ( dwParam1 & 0xff0000 ) >> 16 );
01065         }
01066         else if ( ( message & 0xf0 ) == 0x80 )
01067         {
01068             if ( ( ( message & 0x0f ) + 1 ) == in_midichannel->integer )
01069                 MIDI_NoteOff( ( dwParam1 & 0xff00 ) >> 8 );
01070         }
01071         break;
01072     case MIM_LONGDATA:
01073         break;
01074     case MIM_ERROR:
01075         break;
01076     case MIM_LONGERROR:
01077         break;
01078     }
01079 
01080 //  Sys_QueEvent( sys_msg_time, SE_KEY, wMsg, qtrue, 0, NULL );
01081 }
01082 
01083 static void MidiInfo_f( void )
01084 {
01085     int i;
01086 
01087     const char *enableStrings[] = { "disabled", "enabled" };
01088 
01089     Com_Printf( "\nMIDI control:       %s\n", enableStrings[in_midi->integer != 0] );
01090     Com_Printf( "port:               %d\n", in_midiport->integer );
01091     Com_Printf( "channel:            %d\n", in_midichannel->integer );
01092     Com_Printf( "current device:     %d\n", in_mididevice->integer );
01093     Com_Printf( "number of devices:  %d\n", s_midiInfo.numDevices );
01094     for ( i = 0; i < s_midiInfo.numDevices; i++ )
01095     {
01096         if ( i == Cvar_VariableValue( "in_mididevice" ) )
01097             Com_Printf( "***" );
01098         else
01099             Com_Printf( "..." );
01100         Com_Printf(    "device %2d:       %s\n", i, s_midiInfo.caps[i].szPname );
01101         Com_Printf( "...manufacturer ID: 0x%hx\n", s_midiInfo.caps[i].wMid );
01102         Com_Printf( "...product ID:      0x%hx\n", s_midiInfo.caps[i].wPid );
01103 
01104         Com_Printf( "\n" );
01105     }
01106 }
01107 
01108 static void IN_StartupMIDI( void )
01109 {
01110     int i;
01111 
01112     if ( !Cvar_VariableValue( "in_midi" ) )
01113         return;
01114 
01115     //
01116     // enumerate MIDI IN devices
01117     //
01118     s_midiInfo.numDevices = midiInGetNumDevs();
01119 
01120     for ( i = 0; i < s_midiInfo.numDevices; i++ )
01121     {
01122         midiInGetDevCaps( i, &s_midiInfo.caps[i], sizeof( s_midiInfo.caps[i] ) );
01123     }
01124 
01125     //
01126     // open the MIDI IN port
01127     //
01128     if ( midiInOpen( &s_midiInfo.hMidiIn, 
01129                      in_mididevice->integer,
01130                      ( unsigned long ) MidiInProc,
01131                      ( unsigned long ) NULL,
01132                      CALLBACK_FUNCTION ) != MMSYSERR_NOERROR )
01133     {
01134         Com_Printf( "WARNING: could not open MIDI device %d: '%s'\n", in_mididevice->integer , s_midiInfo.caps[( int ) in_mididevice->value] );
01135         return;
01136     }
01137 
01138     midiInStart( s_midiInfo.hMidiIn );
01139 }
01140 
01141 static void IN_ShutdownMIDI( void )
01142 {
01143     if ( s_midiInfo.hMidiIn )
01144     {
01145         midiInClose( s_midiInfo.hMidiIn );
01146     }
01147     Com_Memset( &s_midiInfo, 0, sizeof( s_midiInfo ) );
01148 }
01149 

Generated on Thu Aug 25 12:38:05 2005 for Quake III Arena by  doxygen 1.3.9.1