diff options
Diffstat (limited to 'code/win32/win_input.c')
-rwxr-xr-x | code/win32/win_input.c | 2298 |
1 files changed, 1149 insertions, 1149 deletions
diff --git a/code/win32/win_input.c b/code/win32/win_input.c index 7012558..a5ec47a 100755 --- a/code/win32/win_input.c +++ b/code/win32/win_input.c @@ -1,1149 +1,1149 @@ -/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Foobar; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-// win_input.c -- win32 mouse and joystick code
-// 02/21/97 JCB Added extended DirectInput code to support external controllers.
-
-#include "../client/client.h"
-#include "win_local.h"
-
-
-typedef struct {
- int oldButtonState;
-
- qboolean mouseActive;
- qboolean mouseInitialized;
- qboolean mouseStartupDelayed; // delay mouse init to try DI again when we have a window
-} WinMouseVars_t;
-
-static WinMouseVars_t s_wmv;
-
-static int window_center_x, window_center_y;
-
-//
-// MIDI definitions
-//
-static void IN_StartupMIDI( void );
-static void IN_ShutdownMIDI( void );
-
-#define MAX_MIDIIN_DEVICES 8
-
-typedef struct {
- int numDevices;
- MIDIINCAPS caps[MAX_MIDIIN_DEVICES];
-
- HMIDIIN hMidiIn;
-} MidiInfo_t;
-
-static MidiInfo_t s_midiInfo;
-
-//
-// Joystick definitions
-//
-#define JOY_MAX_AXES 6 // X, Y, Z, R, U, V
-
-typedef struct {
- qboolean avail;
- int id; // joystick number
- JOYCAPS jc;
-
- int oldbuttonstate;
- int oldpovstate;
-
- JOYINFOEX ji;
-} joystickInfo_t;
-
-static joystickInfo_t joy;
-
-
-
-cvar_t *in_midi;
-cvar_t *in_midiport;
-cvar_t *in_midichannel;
-cvar_t *in_mididevice;
-
-cvar_t *in_mouse;
-cvar_t *in_logitechbug;
-cvar_t *in_joystick;
-cvar_t *in_joyBallScale;
-cvar_t *in_debugJoystick;
-cvar_t *joy_threshold;
-
-qboolean in_appactive;
-
-// forward-referenced functions
-void IN_StartupJoystick (void);
-void IN_JoyMove(void);
-
-static void MidiInfo_f( void );
-
-/*
-============================================================
-
-WIN32 MOUSE CONTROL
-
-============================================================
-*/
-
-/*
-================
-IN_InitWin32Mouse
-================
-*/
-void IN_InitWin32Mouse( void )
-{
-}
-
-/*
-================
-IN_ShutdownWin32Mouse
-================
-*/
-void IN_ShutdownWin32Mouse( void ) {
-}
-
-/*
-================
-IN_ActivateWin32Mouse
-================
-*/
-void IN_ActivateWin32Mouse( void ) {
- int width, height;
- RECT window_rect;
-
- width = GetSystemMetrics (SM_CXSCREEN);
- height = GetSystemMetrics (SM_CYSCREEN);
-
- GetWindowRect ( g_wv.hWnd, &window_rect);
- if (window_rect.left < 0)
- window_rect.left = 0;
- if (window_rect.top < 0)
- window_rect.top = 0;
- if (window_rect.right >= width)
- window_rect.right = width-1;
- if (window_rect.bottom >= height-1)
- window_rect.bottom = height-1;
- window_center_x = (window_rect.right + window_rect.left)/2;
- window_center_y = (window_rect.top + window_rect.bottom)/2;
-
- SetCursorPos (window_center_x, window_center_y);
-
- SetCapture ( g_wv.hWnd );
- ClipCursor (&window_rect);
- while (ShowCursor (FALSE) >= 0)
- ;
-}
-
-/*
-================
-IN_DeactivateWin32Mouse
-================
-*/
-void IN_DeactivateWin32Mouse( void )
-{
- ClipCursor (NULL);
- ReleaseCapture ();
- while (ShowCursor (TRUE) < 0)
- ;
-}
-
-/*
-================
-IN_Win32Mouse
-================
-*/
-void IN_Win32Mouse( int *mx, int *my ) {
- POINT current_pos;
-
- // find mouse movement
- GetCursorPos (¤t_pos);
-
- // force the mouse to the center, so there's room to move
- SetCursorPos (window_center_x, window_center_y);
-
- *mx = current_pos.x - window_center_x;
- *my = current_pos.y - window_center_y;
-}
-
-
-/*
-============================================================
-
-DIRECT INPUT MOUSE CONTROL
-
-============================================================
-*/
-
-#undef DEFINE_GUID
-
-#define DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
- EXTERN_C const GUID name \
- = { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } }
-
-DEFINE_GUID(GUID_SysMouse, 0x6F1D2B60,0xD5A0,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00);
-DEFINE_GUID(GUID_XAxis, 0xA36D02E0,0xC9F3,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00);
-DEFINE_GUID(GUID_YAxis, 0xA36D02E1,0xC9F3,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00);
-DEFINE_GUID(GUID_ZAxis, 0xA36D02E2,0xC9F3,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00);
-
-
-#define DINPUT_BUFFERSIZE 16
-#define iDirectInputCreate(a,b,c,d) pDirectInputCreate(a,b,c,d)
-
-HRESULT (WINAPI *pDirectInputCreate)(HINSTANCE hinst, DWORD dwVersion,
- LPDIRECTINPUT * lplpDirectInput, LPUNKNOWN punkOuter);
-
-static HINSTANCE hInstDI;
-
-typedef struct MYDATA {
- LONG lX; // X axis goes here
- LONG lY; // Y axis goes here
- LONG lZ; // Z axis goes here
- BYTE bButtonA; // One button goes here
- BYTE bButtonB; // Another button goes here
- BYTE bButtonC; // Another button goes here
- BYTE bButtonD; // Another button goes here
-} MYDATA;
-
-static DIOBJECTDATAFORMAT rgodf[] = {
- { &GUID_XAxis, FIELD_OFFSET(MYDATA, lX), DIDFT_AXIS | DIDFT_ANYINSTANCE, 0,},
- { &GUID_YAxis, FIELD_OFFSET(MYDATA, lY), DIDFT_AXIS | DIDFT_ANYINSTANCE, 0,},
- { &GUID_ZAxis, FIELD_OFFSET(MYDATA, lZ), 0x80000000 | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0,},
- { 0, FIELD_OFFSET(MYDATA, bButtonA), DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0,},
- { 0, FIELD_OFFSET(MYDATA, bButtonB), DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0,},
- { 0, FIELD_OFFSET(MYDATA, bButtonC), 0x80000000 | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0,},
- { 0, FIELD_OFFSET(MYDATA, bButtonD), 0x80000000 | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0,},
-};
-
-#define NUM_OBJECTS (sizeof(rgodf) / sizeof(rgodf[0]))
-
-// NOTE TTimo: would be easier using c_dfDIMouse or c_dfDIMouse2
-static DIDATAFORMAT df = {
- sizeof(DIDATAFORMAT), // this structure
- sizeof(DIOBJECTDATAFORMAT), // size of object data format
- DIDF_RELAXIS, // absolute axis coordinates
- sizeof(MYDATA), // device data size
- NUM_OBJECTS, // number of objects
- rgodf, // and here they are
-};
-
-static LPDIRECTINPUT g_pdi;
-static LPDIRECTINPUTDEVICE g_pMouse;
-
-void IN_DIMouse( int *mx, int *my );
-
-/*
-========================
-IN_InitDIMouse
-========================
-*/
-qboolean IN_InitDIMouse( void ) {
- HRESULT hr;
- int x, y;
- DIPROPDWORD dipdw = {
- {
- sizeof(DIPROPDWORD), // diph.dwSize
- sizeof(DIPROPHEADER), // diph.dwHeaderSize
- 0, // diph.dwObj
- DIPH_DEVICE, // diph.dwHow
- },
- DINPUT_BUFFERSIZE, // dwData
- };
-
- Com_Printf( "Initializing DirectInput...\n");
-
- if (!hInstDI) {
- hInstDI = LoadLibrary("dinput.dll");
-
- if (hInstDI == NULL) {
- Com_Printf ("Couldn't load dinput.dll\n");
- return qfalse;
- }
- }
-
- if (!pDirectInputCreate) {
- pDirectInputCreate = (long (__stdcall *)(void *,unsigned long ,struct IDirectInputA ** ,struct IUnknown *))
- GetProcAddress(hInstDI,"DirectInputCreateA");
-
- if (!pDirectInputCreate) {
- Com_Printf ("Couldn't get DI proc addr\n");
- return qfalse;
- }
- }
-
- // register with DirectInput and get an IDirectInput to play with.
- hr = iDirectInputCreate( g_wv.hInstance, DIRECTINPUT_VERSION, &g_pdi, NULL);
-
- if (FAILED(hr)) {
- Com_Printf ("iDirectInputCreate failed\n");
- return qfalse;
- }
-
- // obtain an interface to the system mouse device.
- hr = IDirectInput_CreateDevice(g_pdi, &GUID_SysMouse, &g_pMouse, NULL);
-
- if (FAILED(hr)) {
- Com_Printf ("Couldn't open DI mouse device\n");
- return qfalse;
- }
-
- // set the data format to "mouse format".
- hr = IDirectInputDevice_SetDataFormat(g_pMouse, &df);
-
- if (FAILED(hr)) {
- Com_Printf ("Couldn't set DI mouse format\n");
- return qfalse;
- }
-
- // set the cooperativity level.
- hr = IDirectInputDevice_SetCooperativeLevel(g_pMouse, g_wv.hWnd,
- DISCL_EXCLUSIVE | DISCL_FOREGROUND);
-
- // https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=50
- if (FAILED(hr)) {
- Com_Printf ("Couldn't set DI coop level\n");
- return qfalse;
- }
-
-
- // set the buffer size to DINPUT_BUFFERSIZE elements.
- // the buffer size is a DWORD property associated with the device
- hr = IDirectInputDevice_SetProperty(g_pMouse, DIPROP_BUFFERSIZE, &dipdw.diph);
-
- if (FAILED(hr)) {
- Com_Printf ("Couldn't set DI buffersize\n");
- return qfalse;
- }
-
- // clear any pending samples
- IN_DIMouse( &x, &y );
- IN_DIMouse( &x, &y );
-
- Com_Printf( "DirectInput initialized.\n");
- return qtrue;
-}
-
-/*
-==========================
-IN_ShutdownDIMouse
-==========================
-*/
-void IN_ShutdownDIMouse( void ) {
- if (g_pMouse) {
- IDirectInputDevice_Release(g_pMouse);
- g_pMouse = NULL;
- }
-
- if (g_pdi) {
- IDirectInput_Release(g_pdi);
- g_pdi = NULL;
- }
-}
-
-/*
-==========================
-IN_ActivateDIMouse
-==========================
-*/
-void IN_ActivateDIMouse( void ) {
- HRESULT hr;
-
- if (!g_pMouse) {
- return;
- }
-
- // we may fail to reacquire if the window has been recreated
- hr = IDirectInputDevice_Acquire( g_pMouse );
- if (FAILED(hr)) {
- if ( !IN_InitDIMouse() ) {
- Com_Printf ("Falling back to Win32 mouse support...\n");
- Cvar_Set( "in_mouse", "-1" );
- }
- }
-}
-
-/*
-==========================
-IN_DeactivateDIMouse
-==========================
-*/
-void IN_DeactivateDIMouse( void ) {
- if (!g_pMouse) {
- return;
- }
- IDirectInputDevice_Unacquire( g_pMouse );
-}
-
-
-/*
-===================
-IN_DIMouse
-===================
-*/
-void IN_DIMouse( int *mx, int *my ) {
- DIDEVICEOBJECTDATA od;
- DIMOUSESTATE state;
- DWORD dwElements;
- HRESULT hr;
- int value;
- static float oldSysTime;
-
- if ( !g_pMouse ) {
- return;
- }
-
- // fetch new events
- for (;;)
- {
- dwElements = 1;
-
- hr = IDirectInputDevice_GetDeviceData(g_pMouse,
- sizeof(DIDEVICEOBJECTDATA), &od, &dwElements, 0);
- if ((hr == DIERR_INPUTLOST) || (hr == DIERR_NOTACQUIRED)) {
- IDirectInputDevice_Acquire(g_pMouse);
- return;
- }
-
- /* Unable to read data or no data available */
- if ( FAILED(hr) ) {
- break;
- }
-
- if ( dwElements == 0 ) {
- break;
- }
-
- switch (od.dwOfs) {
- case DIMOFS_BUTTON0:
- if (od.dwData & 0x80)
- Sys_QueEvent( od.dwTimeStamp, SE_KEY, K_MOUSE1, qtrue, 0, NULL );
- else
- Sys_QueEvent( od.dwTimeStamp, SE_KEY, K_MOUSE1, qfalse, 0, NULL );
- break;
-
- case DIMOFS_BUTTON1:
- if (od.dwData & 0x80)
- Sys_QueEvent( od.dwTimeStamp, SE_KEY, K_MOUSE2, qtrue, 0, NULL );
- else
- Sys_QueEvent( od.dwTimeStamp, SE_KEY, K_MOUSE2, qfalse, 0, NULL );
- break;
-
- case DIMOFS_BUTTON2:
- if (od.dwData & 0x80)
- Sys_QueEvent( od.dwTimeStamp, SE_KEY, K_MOUSE3, qtrue, 0, NULL );
- else
- Sys_QueEvent( od.dwTimeStamp, SE_KEY, K_MOUSE3, qfalse, 0, NULL );
- break;
-
- case DIMOFS_BUTTON3:
- if (od.dwData & 0x80)
- Sys_QueEvent( od.dwTimeStamp, SE_KEY, K_MOUSE4, qtrue, 0, NULL );
- else
- Sys_QueEvent( od.dwTimeStamp, SE_KEY, K_MOUSE4, qfalse, 0, NULL );
- break;
- // https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=50
- case DIMOFS_Z:
- value = od.dwData;
- if (value == 0) {
-
- } else if (value < 0) {
- Sys_QueEvent( od.dwTimeStamp, SE_KEY, K_MWHEELDOWN, qtrue, 0, NULL );
- Sys_QueEvent( od.dwTimeStamp, SE_KEY, K_MWHEELDOWN, qfalse, 0, NULL );
- } else {
- Sys_QueEvent( od.dwTimeStamp, SE_KEY, K_MWHEELUP, qtrue, 0, NULL );
- Sys_QueEvent( od.dwTimeStamp, SE_KEY, K_MWHEELUP, qfalse, 0, NULL );
- }
- break;
- }
- }
-
- // read the raw delta counter and ignore
- // the individual sample time / values
- hr = IDirectInputDevice_GetDeviceState(g_pMouse,
- sizeof(DIDEVICEOBJECTDATA), &state);
- if ( FAILED(hr) ) {
- *mx = *my = 0;
- return;
- }
- *mx = state.lX;
- *my = state.lY;
-}
-
-/*
-============================================================
-
- MOUSE CONTROL
-
-============================================================
-*/
-
-/*
-===========
-IN_ActivateMouse
-
-Called when the window gains focus or changes in some way
-===========
-*/
-void IN_ActivateMouse( void )
-{
- if (!s_wmv.mouseInitialized ) {
- return;
- }
- if ( !in_mouse->integer )
- {
- s_wmv.mouseActive = qfalse;
- return;
- }
- if ( s_wmv.mouseActive )
- {
- return;
- }
-
- s_wmv.mouseActive = qtrue;
-
- if ( in_mouse->integer != -1 ) {
- IN_ActivateDIMouse();
- }
- IN_ActivateWin32Mouse();
-}
-
-
-/*
-===========
-IN_DeactivateMouse
-
-Called when the window loses focus
-===========
-*/
-void IN_DeactivateMouse( void ) {
- if (!s_wmv.mouseInitialized ) {
- return;
- }
- if (!s_wmv.mouseActive ) {
- return;
- }
- s_wmv.mouseActive = qfalse;
-
- IN_DeactivateDIMouse();
- IN_DeactivateWin32Mouse();
-}
-
-
-
-/*
-===========
-IN_StartupMouse
-===========
-*/
-void IN_StartupMouse( void )
-{
- s_wmv.mouseInitialized = qfalse;
- s_wmv.mouseStartupDelayed = qfalse;
-
- if ( in_mouse->integer == 0 ) {
- Com_Printf ("Mouse control not active.\n");
- return;
- }
-
- // nt4.0 direct input is screwed up
- if ( ( g_wv.osversion.dwPlatformId == VER_PLATFORM_WIN32_NT ) &&
- ( g_wv.osversion.dwMajorVersion == 4 ) )
- {
- Com_Printf ("Disallowing DirectInput on NT 4.0\n");
- Cvar_Set( "in_mouse", "-1" );
- }
-
- if ( in_mouse->integer == -1 ) {
- Com_Printf ("Skipping check for DirectInput\n");
- } else {
- if (!g_wv.hWnd)
- {
- Com_Printf ("No window for DirectInput mouse init, delaying\n");
- s_wmv.mouseStartupDelayed = qtrue;
- return;
- }
- if ( IN_InitDIMouse() ) {
- s_wmv.mouseInitialized = qtrue;
- return;
- }
- Com_Printf ("Falling back to Win32 mouse support...\n");
- }
- s_wmv.mouseInitialized = qtrue;
- IN_InitWin32Mouse();
-}
-
-/*
-===========
-IN_MouseEvent
-===========
-*/
-void IN_MouseEvent (int mstate)
-{
- int i;
-
- if ( !s_wmv.mouseInitialized )
- return;
-
-// perform button actions
- for (i = 0 ; i < 3 ; i++ )
- {
- if ( (mstate & (1<<i)) &&
- !(s_wmv.oldButtonState & (1<<i)) )
- {
- Sys_QueEvent( g_wv.sysMsgTime, SE_KEY, K_MOUSE1 + i, qtrue, 0, NULL );
- }
-
- if ( !(mstate & (1<<i)) &&
- (s_wmv.oldButtonState & (1<<i)) )
- {
- Sys_QueEvent( g_wv.sysMsgTime, SE_KEY, K_MOUSE1 + i, qfalse, 0, NULL );
- }
- }
-
- s_wmv.oldButtonState = mstate;
-}
-
-
-/*
-===========
-IN_MouseMove
-===========
-*/
-void IN_MouseMove ( void ) {
- int mx, my;
-
- if ( g_pMouse ) {
- IN_DIMouse( &mx, &my );
- } else {
- IN_Win32Mouse( &mx, &my );
- }
-
- if ( !mx && !my ) {
- return;
- }
-
- Sys_QueEvent( 0, SE_MOUSE, mx, my, 0, NULL );
-}
-
-
-/*
-=========================================================================
-
-=========================================================================
-*/
-
-/*
-===========
-IN_Startup
-===========
-*/
-void IN_Startup( void ) {
- Com_Printf ("\n------- Input Initialization -------\n");
- IN_StartupMouse ();
- IN_StartupJoystick ();
- IN_StartupMIDI();
- Com_Printf ("------------------------------------\n");
-
- in_mouse->modified = qfalse;
- in_joystick->modified = qfalse;
-}
-
-/*
-===========
-IN_Shutdown
-===========
-*/
-void IN_Shutdown( void ) {
- IN_DeactivateMouse();
- IN_ShutdownDIMouse();
- IN_ShutdownMIDI();
- Cmd_RemoveCommand("midiinfo" );
-}
-
-
-/*
-===========
-IN_Init
-===========
-*/
-void IN_Init( void ) {
- // MIDI input controler variables
- in_midi = Cvar_Get ("in_midi", "0", CVAR_ARCHIVE);
- in_midiport = Cvar_Get ("in_midiport", "1", CVAR_ARCHIVE);
- in_midichannel = Cvar_Get ("in_midichannel", "1", CVAR_ARCHIVE);
- in_mididevice = Cvar_Get ("in_mididevice", "0", CVAR_ARCHIVE);
-
- Cmd_AddCommand( "midiinfo", MidiInfo_f );
-
- // mouse variables
- in_mouse = Cvar_Get ("in_mouse", "1", CVAR_ARCHIVE|CVAR_LATCH);
- in_logitechbug = Cvar_Get ("in_logitechbug", "0", CVAR_ARCHIVE);
-
- // joystick variables
- in_joystick = Cvar_Get ("in_joystick", "0", CVAR_ARCHIVE|CVAR_LATCH);
- in_joyBallScale = Cvar_Get ("in_joyBallScale", "0.02", CVAR_ARCHIVE);
- in_debugJoystick = Cvar_Get ("in_debugjoystick", "0", CVAR_TEMP);
-
- joy_threshold = Cvar_Get ("joy_threshold", "0.15", CVAR_ARCHIVE);
-
- IN_Startup();
-}
-
-
-/*
-===========
-IN_Activate
-
-Called when the main window gains or loses focus.
-The window may have been destroyed and recreated
-between a deactivate and an activate.
-===========
-*/
-void IN_Activate (qboolean active) {
- in_appactive = active;
-
- if ( !active )
- {
- IN_DeactivateMouse();
- }
-}
-
-
-/*
-==================
-IN_Frame
-
-Called every frame, even if not generating commands
-==================
-*/
-void IN_Frame (void) {
- // post joystick events
- IN_JoyMove();
-
- if ( !s_wmv.mouseInitialized ) {
- if (s_wmv.mouseStartupDelayed && g_wv.hWnd)
- {
- Com_Printf("Proceeding with delayed mouse init\n");
- IN_StartupMouse();
- s_wmv.mouseStartupDelayed = qfalse;
- }
- return;
- }
-
- if ( cls.keyCatchers & KEYCATCH_CONSOLE ) {
- // temporarily deactivate if not in the game and
- // running on the desktop
- // voodoo always counts as full screen
- if (Cvar_VariableValue ("r_fullscreen") == 0
- && strcmp( Cvar_VariableString("r_glDriver"), _3DFX_DRIVER_NAME) ) {
- IN_DeactivateMouse ();
- return;
- }
- }
-
- if ( !in_appactive ) {
- IN_DeactivateMouse ();
- return;
- }
-
- IN_ActivateMouse();
-
- // post events to the system que
- IN_MouseMove();
-
-}
-
-
-/*
-===================
-IN_ClearStates
-===================
-*/
-void IN_ClearStates (void)
-{
- s_wmv.oldButtonState = 0;
-}
-
-
-/*
-=========================================================================
-
-JOYSTICK
-
-=========================================================================
-*/
-
-/*
-===============
-IN_StartupJoystick
-===============
-*/
-void IN_StartupJoystick (void) {
- int numdevs;
- MMRESULT mmr;
-
- // assume no joystick
- joy.avail = qfalse;
-
- if (! in_joystick->integer ) {
- Com_Printf ("Joystick is not active.\n");
- return;
- }
-
- // verify joystick driver is present
- if ((numdevs = joyGetNumDevs ()) == 0)
- {
- Com_Printf ("joystick not found -- driver not present\n");
- return;
- }
-
- // cycle through the joystick ids for the first valid one
- mmr = 0;
- for (joy.id=0 ; joy.id<numdevs ; joy.id++)
- {
- Com_Memset (&joy.ji, 0, sizeof(joy.ji));
- joy.ji.dwSize = sizeof(joy.ji);
- joy.ji.dwFlags = JOY_RETURNCENTERED;
-
- if ((mmr = joyGetPosEx (joy.id, &joy.ji)) == JOYERR_NOERROR)
- break;
- }
-
- // abort startup if we didn't find a valid joystick
- if (mmr != JOYERR_NOERROR)
- {
- Com_Printf ("joystick not found -- no valid joysticks (%x)\n", mmr);
- return;
- }
-
- // get the capabilities of the selected joystick
- // abort startup if command fails
- Com_Memset (&joy.jc, 0, sizeof(joy.jc));
- if ((mmr = joyGetDevCaps (joy.id, &joy.jc, sizeof(joy.jc))) != JOYERR_NOERROR)
- {
- Com_Printf ("joystick not found -- invalid joystick capabilities (%x)\n", mmr);
- return;
- }
-
- Com_Printf( "Joystick found.\n" );
- Com_Printf( "Pname: %s\n", joy.jc.szPname );
- Com_Printf( "OemVxD: %s\n", joy.jc.szOEMVxD );
- Com_Printf( "RegKey: %s\n", joy.jc.szRegKey );
-
- Com_Printf( "Numbuttons: %i / %i\n", joy.jc.wNumButtons, joy.jc.wMaxButtons );
- Com_Printf( "Axis: %i / %i\n", joy.jc.wNumAxes, joy.jc.wMaxAxes );
- Com_Printf( "Caps: 0x%x\n", joy.jc.wCaps );
- if ( joy.jc.wCaps & JOYCAPS_HASPOV ) {
- Com_Printf( "HASPOV\n" );
- } else {
- Com_Printf( "no POV\n" );
- }
-
- // old button and POV states default to no buttons pressed
- joy.oldbuttonstate = 0;
- joy.oldpovstate = 0;
-
- // mark the joystick as available
- joy.avail = qtrue;
-}
-
-/*
-===========
-JoyToF
-===========
-*/
-float JoyToF( int value ) {
- float fValue;
-
- // move centerpoint to zero
- value -= 32768;
-
- // convert range from -32768..32767 to -1..1
- fValue = (float)value / 32768.0;
-
- if ( fValue < -1 ) {
- fValue = -1;
- }
- if ( fValue > 1 ) {
- fValue = 1;
- }
- return fValue;
-}
-
-int JoyToI( int value ) {
- // move centerpoint to zero
- value -= 32768;
-
- return value;
-}
-
-int joyDirectionKeys[16] = {
- K_LEFTARROW, K_RIGHTARROW,
- K_UPARROW, K_DOWNARROW,
- K_JOY16, K_JOY17,
- K_JOY18, K_JOY19,
- K_JOY20, K_JOY21,
- K_JOY22, K_JOY23,
-
- K_JOY24, K_JOY25,
- K_JOY26, K_JOY27
-};
-
-/*
-===========
-IN_JoyMove
-===========
-*/
-void IN_JoyMove( void ) {
- float fAxisValue;
- int i;
- DWORD buttonstate, povstate;
- int x, y;
-
- // verify joystick is available and that the user wants to use it
- if ( !joy.avail ) {
- return;
- }
-
- // collect the joystick data, if possible
- Com_Memset (&joy.ji, 0, sizeof(joy.ji));
- joy.ji.dwSize = sizeof(joy.ji);
- joy.ji.dwFlags = JOY_RETURNALL;
-
- if ( joyGetPosEx (joy.id, &joy.ji) != JOYERR_NOERROR ) {
- // read error occurred
- // turning off the joystick seems too harsh for 1 read error,\
- // but what should be done?
- // Com_Printf ("IN_ReadJoystick: no response\n");
- // joy.avail = false;
- return;
- }
-
- if ( in_debugJoystick->integer ) {
- Com_Printf( "%8x %5i %5.2f %5.2f %5.2f %5.2f %6i %6i\n",
- joy.ji.dwButtons,
- joy.ji.dwPOV,
- JoyToF( joy.ji.dwXpos ), JoyToF( joy.ji.dwYpos ),
- JoyToF( joy.ji.dwZpos ), JoyToF( joy.ji.dwRpos ),
- JoyToI( joy.ji.dwUpos ), JoyToI( joy.ji.dwVpos ) );
- }
-
- // loop through the joystick buttons
- // key a joystick event or auxillary event for higher number buttons for each state change
- buttonstate = joy.ji.dwButtons;
- for ( i=0 ; i < joy.jc.wNumButtons ; i++ ) {
- if ( (buttonstate & (1<<i)) && !(joy.oldbuttonstate & (1<<i)) ) {
- Sys_QueEvent( g_wv.sysMsgTime, SE_KEY, K_JOY1 + i, qtrue, 0, NULL );
- }
- if ( !(buttonstate & (1<<i)) && (joy.oldbuttonstate & (1<<i)) ) {
- Sys_QueEvent( g_wv.sysMsgTime, SE_KEY, K_JOY1 + i, qfalse, 0, NULL );
- }
- }
- joy.oldbuttonstate = buttonstate;
-
- povstate = 0;
-
- // convert main joystick motion into 6 direction button bits
- for (i = 0; i < joy.jc.wNumAxes && i < 4 ; i++) {
- // get the floating point zero-centered, potentially-inverted data for the current axis
- fAxisValue = JoyToF( (&joy.ji.dwXpos)[i] );
-
- if ( fAxisValue < -joy_threshold->value ) {
- povstate |= (1<<(i*2));
- } else if ( fAxisValue > joy_threshold->value ) {
- povstate |= (1<<(i*2+1));
- }
- }
-
- // convert POV information from a direction into 4 button bits
- if ( joy.jc.wCaps & JOYCAPS_HASPOV ) {
- if ( joy.ji.dwPOV != JOY_POVCENTERED ) {
- if (joy.ji.dwPOV == JOY_POVFORWARD)
- povstate |= 1<<12;
- if (joy.ji.dwPOV == JOY_POVBACKWARD)
- povstate |= 1<<13;
- if (joy.ji.dwPOV == JOY_POVRIGHT)
- povstate |= 1<<14;
- if (joy.ji.dwPOV == JOY_POVLEFT)
- povstate |= 1<<15;
- }
- }
-
- // determine which bits have changed and key an auxillary event for each change
- for (i=0 ; i < 16 ; i++) {
- if ( (povstate & (1<<i)) && !(joy.oldpovstate & (1<<i)) ) {
- Sys_QueEvent( g_wv.sysMsgTime, SE_KEY, joyDirectionKeys[i], qtrue, 0, NULL );
- }
-
- if ( !(povstate & (1<<i)) && (joy.oldpovstate & (1<<i)) ) {
- Sys_QueEvent( g_wv.sysMsgTime, SE_KEY, joyDirectionKeys[i], qfalse, 0, NULL );
- }
- }
- joy.oldpovstate = povstate;
-
- // if there is a trackball like interface, simulate mouse moves
- if ( joy.jc.wNumAxes >= 6 ) {
- x = JoyToI( joy.ji.dwUpos ) * in_joyBallScale->value;
- y = JoyToI( joy.ji.dwVpos ) * in_joyBallScale->value;
- if ( x || y ) {
- Sys_QueEvent( g_wv.sysMsgTime, SE_MOUSE, x, y, 0, NULL );
- }
- }
-}
-
-/*
-=========================================================================
-
-MIDI
-
-=========================================================================
-*/
-
-static void MIDI_NoteOff( int note )
-{
- int qkey;
-
- qkey = note - 60 + K_AUX1;
-
- if ( qkey > 255 || qkey < K_AUX1 )
- return;
-
- Sys_QueEvent( g_wv.sysMsgTime, SE_KEY, qkey, qfalse, 0, NULL );
-}
-
-static void MIDI_NoteOn( int note, int velocity )
-{
- int qkey;
-
- if ( velocity == 0 )
- MIDI_NoteOff( note );
-
- qkey = note - 60 + K_AUX1;
-
- if ( qkey > 255 || qkey < K_AUX1 )
- return;
-
- Sys_QueEvent( g_wv.sysMsgTime, SE_KEY, qkey, qtrue, 0, NULL );
-}
-
-static void CALLBACK MidiInProc( HMIDIIN hMidiIn, UINT uMsg, DWORD dwInstance,
- DWORD dwParam1, DWORD dwParam2 )
-{
- int message;
-
- switch ( uMsg )
- {
- case MIM_OPEN:
- break;
- case MIM_CLOSE:
- break;
- case MIM_DATA:
- message = dwParam1 & 0xff;
-
- // note on
- if ( ( message & 0xf0 ) == 0x90 )
- {
- if ( ( ( message & 0x0f ) + 1 ) == in_midichannel->integer )
- MIDI_NoteOn( ( dwParam1 & 0xff00 ) >> 8, ( dwParam1 & 0xff0000 ) >> 16 );
- }
- else if ( ( message & 0xf0 ) == 0x80 )
- {
- if ( ( ( message & 0x0f ) + 1 ) == in_midichannel->integer )
- MIDI_NoteOff( ( dwParam1 & 0xff00 ) >> 8 );
- }
- break;
- case MIM_LONGDATA:
- break;
- case MIM_ERROR:
- break;
- case MIM_LONGERROR:
- break;
- }
-
-// Sys_QueEvent( sys_msg_time, SE_KEY, wMsg, qtrue, 0, NULL );
-}
-
-static void MidiInfo_f( void )
-{
- int i;
-
- const char *enableStrings[] = { "disabled", "enabled" };
-
- Com_Printf( "\nMIDI control: %s\n", enableStrings[in_midi->integer != 0] );
- Com_Printf( "port: %d\n", in_midiport->integer );
- Com_Printf( "channel: %d\n", in_midichannel->integer );
- Com_Printf( "current device: %d\n", in_mididevice->integer );
- Com_Printf( "number of devices: %d\n", s_midiInfo.numDevices );
- for ( i = 0; i < s_midiInfo.numDevices; i++ )
- {
- if ( i == Cvar_VariableValue( "in_mididevice" ) )
- Com_Printf( "***" );
- else
- Com_Printf( "..." );
- Com_Printf( "device %2d: %s\n", i, s_midiInfo.caps[i].szPname );
- Com_Printf( "...manufacturer ID: 0x%hx\n", s_midiInfo.caps[i].wMid );
- Com_Printf( "...product ID: 0x%hx\n", s_midiInfo.caps[i].wPid );
-
- Com_Printf( "\n" );
- }
-}
-
-static void IN_StartupMIDI( void )
-{
- int i;
-
- if ( !Cvar_VariableValue( "in_midi" ) )
- return;
-
- //
- // enumerate MIDI IN devices
- //
- s_midiInfo.numDevices = midiInGetNumDevs();
-
- for ( i = 0; i < s_midiInfo.numDevices; i++ )
- {
- midiInGetDevCaps( i, &s_midiInfo.caps[i], sizeof( s_midiInfo.caps[i] ) );
- }
-
- //
- // open the MIDI IN port
- //
- if ( midiInOpen( &s_midiInfo.hMidiIn,
- in_mididevice->integer,
- ( unsigned long ) MidiInProc,
- ( unsigned long ) NULL,
- CALLBACK_FUNCTION ) != MMSYSERR_NOERROR )
- {
- Com_Printf( "WARNING: could not open MIDI device %d: '%s'\n", in_mididevice->integer , s_midiInfo.caps[( int ) in_mididevice->value] );
- return;
- }
-
- midiInStart( s_midiInfo.hMidiIn );
-}
-
-static void IN_ShutdownMIDI( void )
-{
- if ( s_midiInfo.hMidiIn )
- {
- midiInClose( s_midiInfo.hMidiIn );
- }
- Com_Memset( &s_midiInfo, 0, sizeof( s_midiInfo ) );
-}
-
+/* +=========================================================================== +Copyright (C) 1999-2005 Id Software, Inc. + +This file is part of Quake III Arena source code. + +Quake III Arena source code 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. + +Quake III Arena source code 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 Foobar; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ +// win_input.c -- win32 mouse and joystick code +// 02/21/97 JCB Added extended DirectInput code to support external controllers. + +#include "../client/client.h" +#include "win_local.h" + + +typedef struct { + int oldButtonState; + + qboolean mouseActive; + qboolean mouseInitialized; + qboolean mouseStartupDelayed; // delay mouse init to try DI again when we have a window +} WinMouseVars_t; + +static WinMouseVars_t s_wmv; + +static int window_center_x, window_center_y; + +// +// MIDI definitions +// +static void IN_StartupMIDI( void ); +static void IN_ShutdownMIDI( void ); + +#define MAX_MIDIIN_DEVICES 8 + +typedef struct { + int numDevices; + MIDIINCAPS caps[MAX_MIDIIN_DEVICES]; + + HMIDIIN hMidiIn; +} MidiInfo_t; + +static MidiInfo_t s_midiInfo; + +// +// Joystick definitions +// +#define JOY_MAX_AXES 6 // X, Y, Z, R, U, V + +typedef struct { + qboolean avail; + int id; // joystick number + JOYCAPS jc; + + int oldbuttonstate; + int oldpovstate; + + JOYINFOEX ji; +} joystickInfo_t; + +static joystickInfo_t joy; + + + +cvar_t *in_midi; +cvar_t *in_midiport; +cvar_t *in_midichannel; +cvar_t *in_mididevice; + +cvar_t *in_mouse; +cvar_t *in_logitechbug; +cvar_t *in_joystick; +cvar_t *in_joyBallScale; +cvar_t *in_debugJoystick; +cvar_t *joy_threshold; + +qboolean in_appactive; + +// forward-referenced functions +void IN_StartupJoystick (void); +void IN_JoyMove(void); + +static void MidiInfo_f( void ); + +/* +============================================================ + +WIN32 MOUSE CONTROL + +============================================================ +*/ + +/* +================ +IN_InitWin32Mouse +================ +*/ +void IN_InitWin32Mouse( void ) +{ +} + +/* +================ +IN_ShutdownWin32Mouse +================ +*/ +void IN_ShutdownWin32Mouse( void ) { +} + +/* +================ +IN_ActivateWin32Mouse +================ +*/ +void IN_ActivateWin32Mouse( void ) { + int width, height; + RECT window_rect; + + width = GetSystemMetrics (SM_CXSCREEN); + height = GetSystemMetrics (SM_CYSCREEN); + + GetWindowRect ( g_wv.hWnd, &window_rect); + if (window_rect.left < 0) + window_rect.left = 0; + if (window_rect.top < 0) + window_rect.top = 0; + if (window_rect.right >= width) + window_rect.right = width-1; + if (window_rect.bottom >= height-1) + window_rect.bottom = height-1; + window_center_x = (window_rect.right + window_rect.left)/2; + window_center_y = (window_rect.top + window_rect.bottom)/2; + + SetCursorPos (window_center_x, window_center_y); + + SetCapture ( g_wv.hWnd ); + ClipCursor (&window_rect); + while (ShowCursor (FALSE) >= 0) + ; +} + +/* +================ +IN_DeactivateWin32Mouse +================ +*/ +void IN_DeactivateWin32Mouse( void ) +{ + ClipCursor (NULL); + ReleaseCapture (); + while (ShowCursor (TRUE) < 0) + ; +} + +/* +================ +IN_Win32Mouse +================ +*/ +void IN_Win32Mouse( int *mx, int *my ) { + POINT current_pos; + + // find mouse movement + GetCursorPos (¤t_pos); + + // force the mouse to the center, so there's room to move + SetCursorPos (window_center_x, window_center_y); + + *mx = current_pos.x - window_center_x; + *my = current_pos.y - window_center_y; +} + + +/* +============================================================ + +DIRECT INPUT MOUSE CONTROL + +============================================================ +*/ + +#undef DEFINE_GUID + +#define DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \ + EXTERN_C const GUID name \ + = { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } } + +DEFINE_GUID(GUID_SysMouse, 0x6F1D2B60,0xD5A0,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00); +DEFINE_GUID(GUID_XAxis, 0xA36D02E0,0xC9F3,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00); +DEFINE_GUID(GUID_YAxis, 0xA36D02E1,0xC9F3,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00); +DEFINE_GUID(GUID_ZAxis, 0xA36D02E2,0xC9F3,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00); + + +#define DINPUT_BUFFERSIZE 16 +#define iDirectInputCreate(a,b,c,d) pDirectInputCreate(a,b,c,d) + +HRESULT (WINAPI *pDirectInputCreate)(HINSTANCE hinst, DWORD dwVersion, + LPDIRECTINPUT * lplpDirectInput, LPUNKNOWN punkOuter); + +static HINSTANCE hInstDI; + +typedef struct MYDATA { + LONG lX; // X axis goes here + LONG lY; // Y axis goes here + LONG lZ; // Z axis goes here + BYTE bButtonA; // One button goes here + BYTE bButtonB; // Another button goes here + BYTE bButtonC; // Another button goes here + BYTE bButtonD; // Another button goes here +} MYDATA; + +static DIOBJECTDATAFORMAT rgodf[] = { + { &GUID_XAxis, FIELD_OFFSET(MYDATA, lX), DIDFT_AXIS | DIDFT_ANYINSTANCE, 0,}, + { &GUID_YAxis, FIELD_OFFSET(MYDATA, lY), DIDFT_AXIS | DIDFT_ANYINSTANCE, 0,}, + { &GUID_ZAxis, FIELD_OFFSET(MYDATA, lZ), 0x80000000 | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0,}, + { 0, FIELD_OFFSET(MYDATA, bButtonA), DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0,}, + { 0, FIELD_OFFSET(MYDATA, bButtonB), DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0,}, + { 0, FIELD_OFFSET(MYDATA, bButtonC), 0x80000000 | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0,}, + { 0, FIELD_OFFSET(MYDATA, bButtonD), 0x80000000 | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0,}, +}; + +#define NUM_OBJECTS (sizeof(rgodf) / sizeof(rgodf[0])) + +// NOTE TTimo: would be easier using c_dfDIMouse or c_dfDIMouse2 +static DIDATAFORMAT df = { + sizeof(DIDATAFORMAT), // this structure + sizeof(DIOBJECTDATAFORMAT), // size of object data format + DIDF_RELAXIS, // absolute axis coordinates + sizeof(MYDATA), // device data size + NUM_OBJECTS, // number of objects + rgodf, // and here they are +}; + +static LPDIRECTINPUT g_pdi; +static LPDIRECTINPUTDEVICE g_pMouse; + +void IN_DIMouse( int *mx, int *my ); + +/* +======================== +IN_InitDIMouse +======================== +*/ +qboolean IN_InitDIMouse( void ) { + HRESULT hr; + int x, y; + DIPROPDWORD dipdw = { + { + sizeof(DIPROPDWORD), // diph.dwSize + sizeof(DIPROPHEADER), // diph.dwHeaderSize + 0, // diph.dwObj + DIPH_DEVICE, // diph.dwHow + }, + DINPUT_BUFFERSIZE, // dwData + }; + + Com_Printf( "Initializing DirectInput...\n"); + + if (!hInstDI) { + hInstDI = LoadLibrary("dinput.dll"); + + if (hInstDI == NULL) { + Com_Printf ("Couldn't load dinput.dll\n"); + return qfalse; + } + } + + if (!pDirectInputCreate) { + pDirectInputCreate = (long (__stdcall *)(void *,unsigned long ,struct IDirectInputA ** ,struct IUnknown *)) + GetProcAddress(hInstDI,"DirectInputCreateA"); + + if (!pDirectInputCreate) { + Com_Printf ("Couldn't get DI proc addr\n"); + return qfalse; + } + } + + // register with DirectInput and get an IDirectInput to play with. + hr = iDirectInputCreate( g_wv.hInstance, DIRECTINPUT_VERSION, &g_pdi, NULL); + + if (FAILED(hr)) { + Com_Printf ("iDirectInputCreate failed\n"); + return qfalse; + } + + // obtain an interface to the system mouse device. + hr = IDirectInput_CreateDevice(g_pdi, &GUID_SysMouse, &g_pMouse, NULL); + + if (FAILED(hr)) { + Com_Printf ("Couldn't open DI mouse device\n"); + return qfalse; + } + + // set the data format to "mouse format". + hr = IDirectInputDevice_SetDataFormat(g_pMouse, &df); + + if (FAILED(hr)) { + Com_Printf ("Couldn't set DI mouse format\n"); + return qfalse; + } + + // set the cooperativity level. + hr = IDirectInputDevice_SetCooperativeLevel(g_pMouse, g_wv.hWnd, + DISCL_EXCLUSIVE | DISCL_FOREGROUND); + + // https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=50 + if (FAILED(hr)) { + Com_Printf ("Couldn't set DI coop level\n"); + return qfalse; + } + + + // set the buffer size to DINPUT_BUFFERSIZE elements. + // the buffer size is a DWORD property associated with the device + hr = IDirectInputDevice_SetProperty(g_pMouse, DIPROP_BUFFERSIZE, &dipdw.diph); + + if (FAILED(hr)) { + Com_Printf ("Couldn't set DI buffersize\n"); + return qfalse; + } + + // clear any pending samples + IN_DIMouse( &x, &y ); + IN_DIMouse( &x, &y ); + + Com_Printf( "DirectInput initialized.\n"); + return qtrue; +} + +/* +========================== +IN_ShutdownDIMouse +========================== +*/ +void IN_ShutdownDIMouse( void ) { + if (g_pMouse) { + IDirectInputDevice_Release(g_pMouse); + g_pMouse = NULL; + } + + if (g_pdi) { + IDirectInput_Release(g_pdi); + g_pdi = NULL; + } +} + +/* +========================== +IN_ActivateDIMouse +========================== +*/ +void IN_ActivateDIMouse( void ) { + HRESULT hr; + + if (!g_pMouse) { + return; + } + + // we may fail to reacquire if the window has been recreated + hr = IDirectInputDevice_Acquire( g_pMouse ); + if (FAILED(hr)) { + if ( !IN_InitDIMouse() ) { + Com_Printf ("Falling back to Win32 mouse support...\n"); + Cvar_Set( "in_mouse", "-1" ); + } + } +} + +/* +========================== +IN_DeactivateDIMouse +========================== +*/ +void IN_DeactivateDIMouse( void ) { + if (!g_pMouse) { + return; + } + IDirectInputDevice_Unacquire( g_pMouse ); +} + + +/* +=================== +IN_DIMouse +=================== +*/ +void IN_DIMouse( int *mx, int *my ) { + DIDEVICEOBJECTDATA od; + DIMOUSESTATE state; + DWORD dwElements; + HRESULT hr; + int value; + static float oldSysTime; + + if ( !g_pMouse ) { + return; + } + + // fetch new events + for (;;) + { + dwElements = 1; + + hr = IDirectInputDevice_GetDeviceData(g_pMouse, + sizeof(DIDEVICEOBJECTDATA), &od, &dwElements, 0); + if ((hr == DIERR_INPUTLOST) || (hr == DIERR_NOTACQUIRED)) { + IDirectInputDevice_Acquire(g_pMouse); + return; + } + + /* Unable to read data or no data available */ + if ( FAILED(hr) ) { + break; + } + + if ( dwElements == 0 ) { + break; + } + + switch (od.dwOfs) { + case DIMOFS_BUTTON0: + if (od.dwData & 0x80) + Sys_QueEvent( od.dwTimeStamp, SE_KEY, K_MOUSE1, qtrue, 0, NULL ); + else + Sys_QueEvent( od.dwTimeStamp, SE_KEY, K_MOUSE1, qfalse, 0, NULL ); + break; + + case DIMOFS_BUTTON1: + if (od.dwData & 0x80) + Sys_QueEvent( od.dwTimeStamp, SE_KEY, K_MOUSE2, qtrue, 0, NULL ); + else + Sys_QueEvent( od.dwTimeStamp, SE_KEY, K_MOUSE2, qfalse, 0, NULL ); + break; + + case DIMOFS_BUTTON2: + if (od.dwData & 0x80) + Sys_QueEvent( od.dwTimeStamp, SE_KEY, K_MOUSE3, qtrue, 0, NULL ); + else + Sys_QueEvent( od.dwTimeStamp, SE_KEY, K_MOUSE3, qfalse, 0, NULL ); + break; + + case DIMOFS_BUTTON3: + if (od.dwData & 0x80) + Sys_QueEvent( od.dwTimeStamp, SE_KEY, K_MOUSE4, qtrue, 0, NULL ); + else + Sys_QueEvent( od.dwTimeStamp, SE_KEY, K_MOUSE4, qfalse, 0, NULL ); + break; + // https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=50 + case DIMOFS_Z: + value = od.dwData; + if (value == 0) { + + } else if (value < 0) { + Sys_QueEvent( od.dwTimeStamp, SE_KEY, K_MWHEELDOWN, qtrue, 0, NULL ); + Sys_QueEvent( od.dwTimeStamp, SE_KEY, K_MWHEELDOWN, qfalse, 0, NULL ); + } else { + Sys_QueEvent( od.dwTimeStamp, SE_KEY, K_MWHEELUP, qtrue, 0, NULL ); + Sys_QueEvent( od.dwTimeStamp, SE_KEY, K_MWHEELUP, qfalse, 0, NULL ); + } + break; + } + } + + // read the raw delta counter and ignore + // the individual sample time / values + hr = IDirectInputDevice_GetDeviceState(g_pMouse, + sizeof(DIDEVICEOBJECTDATA), &state); + if ( FAILED(hr) ) { + *mx = *my = 0; + return; + } + *mx = state.lX; + *my = state.lY; +} + +/* +============================================================ + + MOUSE CONTROL + +============================================================ +*/ + +/* +=========== +IN_ActivateMouse + +Called when the window gains focus or changes in some way +=========== +*/ +void IN_ActivateMouse( void ) +{ + if (!s_wmv.mouseInitialized ) { + return; + } + if ( !in_mouse->integer ) + { + s_wmv.mouseActive = qfalse; + return; + } + if ( s_wmv.mouseActive ) + { + return; + } + + s_wmv.mouseActive = qtrue; + + if ( in_mouse->integer != -1 ) { + IN_ActivateDIMouse(); + } + IN_ActivateWin32Mouse(); +} + + +/* +=========== +IN_DeactivateMouse + +Called when the window loses focus +=========== +*/ +void IN_DeactivateMouse( void ) { + if (!s_wmv.mouseInitialized ) { + return; + } + if (!s_wmv.mouseActive ) { + return; + } + s_wmv.mouseActive = qfalse; + + IN_DeactivateDIMouse(); + IN_DeactivateWin32Mouse(); +} + + + +/* +=========== +IN_StartupMouse +=========== +*/ +void IN_StartupMouse( void ) +{ + s_wmv.mouseInitialized = qfalse; + s_wmv.mouseStartupDelayed = qfalse; + + if ( in_mouse->integer == 0 ) { + Com_Printf ("Mouse control not active.\n"); + return; + } + + // nt4.0 direct input is screwed up + if ( ( g_wv.osversion.dwPlatformId == VER_PLATFORM_WIN32_NT ) && + ( g_wv.osversion.dwMajorVersion == 4 ) ) + { + Com_Printf ("Disallowing DirectInput on NT 4.0\n"); + Cvar_Set( "in_mouse", "-1" ); + } + + if ( in_mouse->integer == -1 ) { + Com_Printf ("Skipping check for DirectInput\n"); + } else { + if (!g_wv.hWnd) + { + Com_Printf ("No window for DirectInput mouse init, delaying\n"); + s_wmv.mouseStartupDelayed = qtrue; + return; + } + if ( IN_InitDIMouse() ) { + s_wmv.mouseInitialized = qtrue; + return; + } + Com_Printf ("Falling back to Win32 mouse support...\n"); + } + s_wmv.mouseInitialized = qtrue; + IN_InitWin32Mouse(); +} + +/* +=========== +IN_MouseEvent +=========== +*/ +void IN_MouseEvent (int mstate) +{ + int i; + + if ( !s_wmv.mouseInitialized ) + return; + +// perform button actions + for (i = 0 ; i < 3 ; i++ ) + { + if ( (mstate & (1<<i)) && + !(s_wmv.oldButtonState & (1<<i)) ) + { + Sys_QueEvent( g_wv.sysMsgTime, SE_KEY, K_MOUSE1 + i, qtrue, 0, NULL ); + } + + if ( !(mstate & (1<<i)) && + (s_wmv.oldButtonState & (1<<i)) ) + { + Sys_QueEvent( g_wv.sysMsgTime, SE_KEY, K_MOUSE1 + i, qfalse, 0, NULL ); + } + } + + s_wmv.oldButtonState = mstate; +} + + +/* +=========== +IN_MouseMove +=========== +*/ +void IN_MouseMove ( void ) { + int mx, my; + + if ( g_pMouse ) { + IN_DIMouse( &mx, &my ); + } else { + IN_Win32Mouse( &mx, &my ); + } + + if ( !mx && !my ) { + return; + } + + Sys_QueEvent( 0, SE_MOUSE, mx, my, 0, NULL ); +} + + +/* +========================================================================= + +========================================================================= +*/ + +/* +=========== +IN_Startup +=========== +*/ +void IN_Startup( void ) { + Com_Printf ("\n------- Input Initialization -------\n"); + IN_StartupMouse (); + IN_StartupJoystick (); + IN_StartupMIDI(); + Com_Printf ("------------------------------------\n"); + + in_mouse->modified = qfalse; + in_joystick->modified = qfalse; +} + +/* +=========== +IN_Shutdown +=========== +*/ +void IN_Shutdown( void ) { + IN_DeactivateMouse(); + IN_ShutdownDIMouse(); + IN_ShutdownMIDI(); + Cmd_RemoveCommand("midiinfo" ); +} + + +/* +=========== +IN_Init +=========== +*/ +void IN_Init( void ) { + // MIDI input controler variables + in_midi = Cvar_Get ("in_midi", "0", CVAR_ARCHIVE); + in_midiport = Cvar_Get ("in_midiport", "1", CVAR_ARCHIVE); + in_midichannel = Cvar_Get ("in_midichannel", "1", CVAR_ARCHIVE); + in_mididevice = Cvar_Get ("in_mididevice", "0", CVAR_ARCHIVE); + + Cmd_AddCommand( "midiinfo", MidiInfo_f ); + + // mouse variables + in_mouse = Cvar_Get ("in_mouse", "1", CVAR_ARCHIVE|CVAR_LATCH); + in_logitechbug = Cvar_Get ("in_logitechbug", "0", CVAR_ARCHIVE); + + // joystick variables + in_joystick = Cvar_Get ("in_joystick", "0", CVAR_ARCHIVE|CVAR_LATCH); + in_joyBallScale = Cvar_Get ("in_joyBallScale", "0.02", CVAR_ARCHIVE); + in_debugJoystick = Cvar_Get ("in_debugjoystick", "0", CVAR_TEMP); + + joy_threshold = Cvar_Get ("joy_threshold", "0.15", CVAR_ARCHIVE); + + IN_Startup(); +} + + +/* +=========== +IN_Activate + +Called when the main window gains or loses focus. +The window may have been destroyed and recreated +between a deactivate and an activate. +=========== +*/ +void IN_Activate (qboolean active) { + in_appactive = active; + + if ( !active ) + { + IN_DeactivateMouse(); + } +} + + +/* +================== +IN_Frame + +Called every frame, even if not generating commands +================== +*/ +void IN_Frame (void) { + // post joystick events + IN_JoyMove(); + + if ( !s_wmv.mouseInitialized ) { + if (s_wmv.mouseStartupDelayed && g_wv.hWnd) + { + Com_Printf("Proceeding with delayed mouse init\n"); + IN_StartupMouse(); + s_wmv.mouseStartupDelayed = qfalse; + } + return; + } + + if ( cls.keyCatchers & KEYCATCH_CONSOLE ) { + // temporarily deactivate if not in the game and + // running on the desktop + // voodoo always counts as full screen + if (Cvar_VariableValue ("r_fullscreen") == 0 + && strcmp( Cvar_VariableString("r_glDriver"), _3DFX_DRIVER_NAME) ) { + IN_DeactivateMouse (); + return; + } + } + + if ( !in_appactive ) { + IN_DeactivateMouse (); + return; + } + + IN_ActivateMouse(); + + // post events to the system que + IN_MouseMove(); + +} + + +/* +=================== +IN_ClearStates +=================== +*/ +void IN_ClearStates (void) +{ + s_wmv.oldButtonState = 0; +} + + +/* +========================================================================= + +JOYSTICK + +========================================================================= +*/ + +/* +=============== +IN_StartupJoystick +=============== +*/ +void IN_StartupJoystick (void) { + int numdevs; + MMRESULT mmr; + + // assume no joystick + joy.avail = qfalse; + + if (! in_joystick->integer ) { + Com_Printf ("Joystick is not active.\n"); + return; + } + + // verify joystick driver is present + if ((numdevs = joyGetNumDevs ()) == 0) + { + Com_Printf ("joystick not found -- driver not present\n"); + return; + } + + // cycle through the joystick ids for the first valid one + mmr = 0; + for (joy.id=0 ; joy.id<numdevs ; joy.id++) + { + Com_Memset (&joy.ji, 0, sizeof(joy.ji)); + joy.ji.dwSize = sizeof(joy.ji); + joy.ji.dwFlags = JOY_RETURNCENTERED; + + if ((mmr = joyGetPosEx (joy.id, &joy.ji)) == JOYERR_NOERROR) + break; + } + + // abort startup if we didn't find a valid joystick + if (mmr != JOYERR_NOERROR) + { + Com_Printf ("joystick not found -- no valid joysticks (%x)\n", mmr); + return; + } + + // get the capabilities of the selected joystick + // abort startup if command fails + Com_Memset (&joy.jc, 0, sizeof(joy.jc)); + if ((mmr = joyGetDevCaps (joy.id, &joy.jc, sizeof(joy.jc))) != JOYERR_NOERROR) + { + Com_Printf ("joystick not found -- invalid joystick capabilities (%x)\n", mmr); + return; + } + + Com_Printf( "Joystick found.\n" ); + Com_Printf( "Pname: %s\n", joy.jc.szPname ); + Com_Printf( "OemVxD: %s\n", joy.jc.szOEMVxD ); + Com_Printf( "RegKey: %s\n", joy.jc.szRegKey ); + + Com_Printf( "Numbuttons: %i / %i\n", joy.jc.wNumButtons, joy.jc.wMaxButtons ); + Com_Printf( "Axis: %i / %i\n", joy.jc.wNumAxes, joy.jc.wMaxAxes ); + Com_Printf( "Caps: 0x%x\n", joy.jc.wCaps ); + if ( joy.jc.wCaps & JOYCAPS_HASPOV ) { + Com_Printf( "HASPOV\n" ); + } else { + Com_Printf( "no POV\n" ); + } + + // old button and POV states default to no buttons pressed + joy.oldbuttonstate = 0; + joy.oldpovstate = 0; + + // mark the joystick as available + joy.avail = qtrue; +} + +/* +=========== +JoyToF +=========== +*/ +float JoyToF( int value ) { + float fValue; + + // move centerpoint to zero + value -= 32768; + + // convert range from -32768..32767 to -1..1 + fValue = (float)value / 32768.0; + + if ( fValue < -1 ) { + fValue = -1; + } + if ( fValue > 1 ) { + fValue = 1; + } + return fValue; +} + +int JoyToI( int value ) { + // move centerpoint to zero + value -= 32768; + + return value; +} + +int joyDirectionKeys[16] = { + K_LEFTARROW, K_RIGHTARROW, + K_UPARROW, K_DOWNARROW, + K_JOY16, K_JOY17, + K_JOY18, K_JOY19, + K_JOY20, K_JOY21, + K_JOY22, K_JOY23, + + K_JOY24, K_JOY25, + K_JOY26, K_JOY27 +}; + +/* +=========== +IN_JoyMove +=========== +*/ +void IN_JoyMove( void ) { + float fAxisValue; + int i; + DWORD buttonstate, povstate; + int x, y; + + // verify joystick is available and that the user wants to use it + if ( !joy.avail ) { + return; + } + + // collect the joystick data, if possible + Com_Memset (&joy.ji, 0, sizeof(joy.ji)); + joy.ji.dwSize = sizeof(joy.ji); + joy.ji.dwFlags = JOY_RETURNALL; + + if ( joyGetPosEx (joy.id, &joy.ji) != JOYERR_NOERROR ) { + // read error occurred + // turning off the joystick seems too harsh for 1 read error,\ + // but what should be done? + // Com_Printf ("IN_ReadJoystick: no response\n"); + // joy.avail = false; + return; + } + + if ( in_debugJoystick->integer ) { + Com_Printf( "%8x %5i %5.2f %5.2f %5.2f %5.2f %6i %6i\n", + joy.ji.dwButtons, + joy.ji.dwPOV, + JoyToF( joy.ji.dwXpos ), JoyToF( joy.ji.dwYpos ), + JoyToF( joy.ji.dwZpos ), JoyToF( joy.ji.dwRpos ), + JoyToI( joy.ji.dwUpos ), JoyToI( joy.ji.dwVpos ) ); + } + + // loop through the joystick buttons + // key a joystick event or auxillary event for higher number buttons for each state change + buttonstate = joy.ji.dwButtons; + for ( i=0 ; i < joy.jc.wNumButtons ; i++ ) { + if ( (buttonstate & (1<<i)) && !(joy.oldbuttonstate & (1<<i)) ) { + Sys_QueEvent( g_wv.sysMsgTime, SE_KEY, K_JOY1 + i, qtrue, 0, NULL ); + } + if ( !(buttonstate & (1<<i)) && (joy.oldbuttonstate & (1<<i)) ) { + Sys_QueEvent( g_wv.sysMsgTime, SE_KEY, K_JOY1 + i, qfalse, 0, NULL ); + } + } + joy.oldbuttonstate = buttonstate; + + povstate = 0; + + // convert main joystick motion into 6 direction button bits + for (i = 0; i < joy.jc.wNumAxes && i < 4 ; i++) { + // get the floating point zero-centered, potentially-inverted data for the current axis + fAxisValue = JoyToF( (&joy.ji.dwXpos)[i] ); + + if ( fAxisValue < -joy_threshold->value ) { + povstate |= (1<<(i*2)); + } else if ( fAxisValue > joy_threshold->value ) { + povstate |= (1<<(i*2+1)); + } + } + + // convert POV information from a direction into 4 button bits + if ( joy.jc.wCaps & JOYCAPS_HASPOV ) { + if ( joy.ji.dwPOV != JOY_POVCENTERED ) { + if (joy.ji.dwPOV == JOY_POVFORWARD) + povstate |= 1<<12; + if (joy.ji.dwPOV == JOY_POVBACKWARD) + povstate |= 1<<13; + if (joy.ji.dwPOV == JOY_POVRIGHT) + povstate |= 1<<14; + if (joy.ji.dwPOV == JOY_POVLEFT) + povstate |= 1<<15; + } + } + + // determine which bits have changed and key an auxillary event for each change + for (i=0 ; i < 16 ; i++) { + if ( (povstate & (1<<i)) && !(joy.oldpovstate & (1<<i)) ) { + Sys_QueEvent( g_wv.sysMsgTime, SE_KEY, joyDirectionKeys[i], qtrue, 0, NULL ); + } + + if ( !(povstate & (1<<i)) && (joy.oldpovstate & (1<<i)) ) { + Sys_QueEvent( g_wv.sysMsgTime, SE_KEY, joyDirectionKeys[i], qfalse, 0, NULL ); + } + } + joy.oldpovstate = povstate; + + // if there is a trackball like interface, simulate mouse moves + if ( joy.jc.wNumAxes >= 6 ) { + x = JoyToI( joy.ji.dwUpos ) * in_joyBallScale->value; + y = JoyToI( joy.ji.dwVpos ) * in_joyBallScale->value; + if ( x || y ) { + Sys_QueEvent( g_wv.sysMsgTime, SE_MOUSE, x, y, 0, NULL ); + } + } +} + +/* +========================================================================= + +MIDI + +========================================================================= +*/ + +static void MIDI_NoteOff( int note ) +{ + int qkey; + + qkey = note - 60 + K_AUX1; + + if ( qkey > 255 || qkey < K_AUX1 ) + return; + + Sys_QueEvent( g_wv.sysMsgTime, SE_KEY, qkey, qfalse, 0, NULL ); +} + +static void MIDI_NoteOn( int note, int velocity ) +{ + int qkey; + + if ( velocity == 0 ) + MIDI_NoteOff( note ); + + qkey = note - 60 + K_AUX1; + + if ( qkey > 255 || qkey < K_AUX1 ) + return; + + Sys_QueEvent( g_wv.sysMsgTime, SE_KEY, qkey, qtrue, 0, NULL ); +} + +static void CALLBACK MidiInProc( HMIDIIN hMidiIn, UINT uMsg, DWORD dwInstance, + DWORD dwParam1, DWORD dwParam2 ) +{ + int message; + + switch ( uMsg ) + { + case MIM_OPEN: + break; + case MIM_CLOSE: + break; + case MIM_DATA: + message = dwParam1 & 0xff; + + // note on + if ( ( message & 0xf0 ) == 0x90 ) + { + if ( ( ( message & 0x0f ) + 1 ) == in_midichannel->integer ) + MIDI_NoteOn( ( dwParam1 & 0xff00 ) >> 8, ( dwParam1 & 0xff0000 ) >> 16 ); + } + else if ( ( message & 0xf0 ) == 0x80 ) + { + if ( ( ( message & 0x0f ) + 1 ) == in_midichannel->integer ) + MIDI_NoteOff( ( dwParam1 & 0xff00 ) >> 8 ); + } + break; + case MIM_LONGDATA: + break; + case MIM_ERROR: + break; + case MIM_LONGERROR: + break; + } + +// Sys_QueEvent( sys_msg_time, SE_KEY, wMsg, qtrue, 0, NULL ); +} + +static void MidiInfo_f( void ) +{ + int i; + + const char *enableStrings[] = { "disabled", "enabled" }; + + Com_Printf( "\nMIDI control: %s\n", enableStrings[in_midi->integer != 0] ); + Com_Printf( "port: %d\n", in_midiport->integer ); + Com_Printf( "channel: %d\n", in_midichannel->integer ); + Com_Printf( "current device: %d\n", in_mididevice->integer ); + Com_Printf( "number of devices: %d\n", s_midiInfo.numDevices ); + for ( i = 0; i < s_midiInfo.numDevices; i++ ) + { + if ( i == Cvar_VariableValue( "in_mididevice" ) ) + Com_Printf( "***" ); + else + Com_Printf( "..." ); + Com_Printf( "device %2d: %s\n", i, s_midiInfo.caps[i].szPname ); + Com_Printf( "...manufacturer ID: 0x%hx\n", s_midiInfo.caps[i].wMid ); + Com_Printf( "...product ID: 0x%hx\n", s_midiInfo.caps[i].wPid ); + + Com_Printf( "\n" ); + } +} + +static void IN_StartupMIDI( void ) +{ + int i; + + if ( !Cvar_VariableValue( "in_midi" ) ) + return; + + // + // enumerate MIDI IN devices + // + s_midiInfo.numDevices = midiInGetNumDevs(); + + for ( i = 0; i < s_midiInfo.numDevices; i++ ) + { + midiInGetDevCaps( i, &s_midiInfo.caps[i], sizeof( s_midiInfo.caps[i] ) ); + } + + // + // open the MIDI IN port + // + if ( midiInOpen( &s_midiInfo.hMidiIn, + in_mididevice->integer, + ( unsigned long ) MidiInProc, + ( unsigned long ) NULL, + CALLBACK_FUNCTION ) != MMSYSERR_NOERROR ) + { + Com_Printf( "WARNING: could not open MIDI device %d: '%s'\n", in_mididevice->integer , s_midiInfo.caps[( int ) in_mididevice->value] ); + return; + } + + midiInStart( s_midiInfo.hMidiIn ); +} + +static void IN_ShutdownMIDI( void ) +{ + if ( s_midiInfo.hMidiIn ) + { + midiInClose( s_midiInfo.hMidiIn ); + } + Com_Memset( &s_midiInfo, 0, sizeof( s_midiInfo ) ); +} + |