aboutsummaryrefslogtreecommitdiffstats
path: root/code/win32/win_input.c
diff options
context:
space:
mode:
Diffstat (limited to 'code/win32/win_input.c')
-rwxr-xr-xcode/win32/win_input.c1149
1 files changed, 1149 insertions, 0 deletions
diff --git a/code/win32/win_input.c b/code/win32/win_input.c
new file mode 100755
index 0000000..7012558
--- /dev/null
+++ b/code/win32/win_input.c
@@ -0,0 +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 (&current_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 ) );
+}
+