/* Copyright (C) 1996-1997 Id Software, Inc. This program 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. This program 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 this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ // in_win.c -- windows 95 mouse and joystick code // 02/21/97 JCB Added extended DirectInput code to support external controllers. #include "quakedef.h" #include "winquake.h" //#include "dosisms.h" #define USINGRAWINPUT #ifdef USINGRAWINPUT #include "in_raw.h" #endif #ifndef NODIRECTX #ifdef _MSC_VER #pragma comment (lib, "dxguid.lib") #else #define DIRECTINPUT_VERSION 0x0500 #endif #include #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); #endif #define DINPUT_VERSION_DX3 0x0300 #define DINPUT_VERSION_DX7 0x0700 // mouse variables cvar_t m_filter = SCVAR("m_filter","0"); cvar_t m_accel = SCVAR("m_accel", "0"); cvar_t m_forcewheel = SCVAR("m_forcewheel", "1"); cvar_t m_forcewheel_threshold = SCVAR("m_forcewheel_threshold", "32"); cvar_t in_mwhook = SCVARF("in_mwhook","0", CVAR_ARCHIVE); cvar_t in_dinput = SCVARF("in_dinput","0", CVAR_ARCHIVE); cvar_t m_accel_noforce = SCVAR("m_accel_noforce", "0"); cvar_t m_threshold_noforce = SCVAR("m_threshold_noforce", "0"); cvar_t cl_keypad = SCVAR("cl_keypad", "0"); qboolean CSQC_MouseMove(float xdelta, float ydelta); qboolean Key_MouseShouldBeFree(void); typedef struct { union { struct { // serial mouse HANDLE comhandle; HANDLE threadhandle; DWORD threadid; }; HANDLE rawinputhandle; // raw input } handles; int numbuttons; volatile int buttons; volatile int oldbuttons; volatile int wheeldelta; volatile int delta[2]; int old_delta[2]; int accum[2]; int pos[2]; } mouse_t; mouse_t sysmouse; #ifdef SERIALMOUSE mouse_t serialmouse; #endif //int mouse_buttons; //int mouse_oldbuttonstate; //int mouse_x, mouse_y, old_mouse_x, old_mouse_y, mx_accum, my_accum; static qboolean restore_spi; static int originalmouseparms[3], newmouseparms[3] = {0, 0, 0}; qboolean mouseinitialized; static qboolean mouseparmsvalid, mouseactivatetoggle; static qboolean mouseshowtoggle = 1; static qboolean dinput_acquired; unsigned int uiWheelMessage; qboolean mouseactive; // joystick defines and variables // where should defines be moved? #define JOY_ABSOLUTE_AXIS 0x00000000 // control like a joystick #define JOY_RELATIVE_AXIS 0x00000010 // control like a mouse, spinner, trackball #define JOY_MAX_AXES 6 // X, Y, Z, R, U, V #define JOY_AXIS_X 0 #define JOY_AXIS_Y 1 #define JOY_AXIS_Z 2 #define JOY_AXIS_R 3 #define JOY_AXIS_U 4 #define JOY_AXIS_V 5 enum _ControlList { AxisNada = 0, AxisForward, AxisLook, AxisSide, AxisTurn }; DWORD dwAxisFlags[JOY_MAX_AXES] = { JOY_RETURNX, JOY_RETURNY, JOY_RETURNZ, JOY_RETURNR, JOY_RETURNU, JOY_RETURNV }; DWORD dwAxisMap[JOY_MAX_AXES]; DWORD dwControlMap[JOY_MAX_AXES]; PDWORD pdwRawValue[JOY_MAX_AXES]; #ifdef IN_XFLIP cvar_t in_xflip = SCVAR("in_xflip", "0"); #endif // none of these cvars are saved over a session // this means that advanced controller configuration needs to be executed // each time. this avoids any problems with getting back to a default usage // or when changing from one controller to another. this way at least something // works. cvar_t in_joystick = SCVARF("joystick","0", CVAR_ARCHIVE); cvar_t joy_name = SCVAR("joyname", "joystick"); cvar_t joy_advanced = SCVAR("joyadvanced", "0"); cvar_t joy_advaxisx = SCVAR("joyadvaxisx", "0"); cvar_t joy_advaxisy = SCVAR("joyadvaxisy", "0"); cvar_t joy_advaxisz = SCVAR("joyadvaxisz", "0"); cvar_t joy_advaxisr = SCVAR("joyadvaxisr", "0"); cvar_t joy_advaxisu = SCVAR("joyadvaxisu", "0"); cvar_t joy_advaxisv = SCVAR("joyadvaxisv", "0"); cvar_t joy_forwardthreshold = SCVAR("joyforwardthreshold", "0.15"); cvar_t joy_sidethreshold = SCVAR("joysidethreshold", "0.15"); cvar_t joy_pitchthreshold = SCVAR("joypitchthreshold", "0.15"); cvar_t joy_yawthreshold = SCVAR("joyyawthreshold", "0.15"); cvar_t joy_forwardsensitivity = SCVAR("joyforwardsensitivity", "-1.0"); cvar_t joy_sidesensitivity = SCVAR("joysidesensitivity", "-1.0"); cvar_t joy_pitchsensitivity = SCVAR("joypitchsensitivity", "1.0"); cvar_t joy_yawsensitivity = SCVAR("joyyawsensitivity", "-1.0"); cvar_t joy_wwhack1 = SCVAR("joywwhack1", "0.0"); cvar_t joy_wwhack2 = SCVAR("joywwhack2", "0.0"); qboolean joy_avail, joy_advancedinit, joy_haspov; DWORD joy_oldbuttonstate, joy_oldpovstate; int joy_id; DWORD joy_flags; DWORD joy_numbuttons; #ifndef NODIRECTX // devices LPDIRECTINPUT g_pdi; LPDIRECTINPUTDEVICE g_pMouse; static HINSTANCE hInstDI; // current DirectInput version in use, 0 means using no DirectInput static int dinput; 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 #if (DIRECTINPUT_VERSION >= DINPUT_VERSION_DX7) BYTE bButtonE; // DX7 buttons BYTE bButtonF; BYTE bButtonG; BYTE bButtonH; #endif } 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,}, #if (DIRECTINPUT_VERSION >= DINPUT_VERSION_DX7) { 0, FIELD_OFFSET(MYDATA, bButtonE), 0x80000000 | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0,}, { 0, FIELD_OFFSET(MYDATA, bButtonF), 0x80000000 | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0,}, { 0, FIELD_OFFSET(MYDATA, bButtonG), 0x80000000 | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0,}, { 0, FIELD_OFFSET(MYDATA, bButtonH), 0x80000000 | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0,}, #endif }; #define NUM_OBJECTS (sizeof(rgodf) / sizeof(rgodf[0])) 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 }; #if (DIRECTINPUT_VERSION >= DINPUT_VERSION_DX7) // DX7 devices LPDIRECTINPUT7 g_pdi7; LPDIRECTINPUTDEVICE7 g_pMouse7; // DX7 specific calls #define iDirectInputCreateEx(a,b,c,d,e) pDirectInputCreateEx(a,b,c,d,e) static HRESULT (WINAPI *pDirectInputCreateEx)(HINSTANCE hinst, DWORD dwVersion, REFIID riidltf, LPVOID *ppvOut, LPUNKNOWN punkOuter); #endif #else #define dinput 0 #endif static JOYINFOEX ji; // raw input specific defines #ifdef USINGRAWINPUT // defines #define MAX_RI_DEVICE_SIZE 128 #define INIT_RIBUFFER_SIZE (sizeof(RAWINPUTHEADER)+sizeof(RAWMOUSE)) #define RI_RAWBUTTON_MASK 0x000003E0 #define RI_INVALID_POS 0x80000000 // raw input dynamic functions typedef INT (WINAPI *pGetRawInputDeviceList)(OUT PRAWINPUTDEVICELIST pRawInputDeviceList, IN OUT PINT puiNumDevices, IN UINT cbSize); typedef INT(WINAPI *pGetRawInputData)(IN HRAWINPUT hRawInput, IN UINT uiCommand, OUT LPVOID pData, IN OUT PINT pcbSize, IN UINT cbSizeHeader); typedef INT(WINAPI *pGetRawInputDeviceInfoA)(IN HANDLE hDevice, IN UINT uiCommand, OUT LPVOID pData, IN OUT PINT pcbSize); typedef BOOL (WINAPI *pRegisterRawInputDevices)(IN PCRAWINPUTDEVICE pRawInputDevices, IN UINT uiNumDevices, IN UINT cbSize); pGetRawInputDeviceList _GRIDL; pGetRawInputData _GRID; pGetRawInputDeviceInfoA _GRIDIA; pRegisterRawInputDevices _RRID; mouse_t *rawmice; int rawmicecount; RAWINPUT *raw; int ribuffersize; cvar_t in_rawinput = SCVAR("in_rawinput", "0"); cvar_t in_rawinput_combine = SCVAR("in_rawinput_combine", "0"); cvar_t in_rawinput_rdp = SCVAR("in_rawinput_rdp", "0"); void IN_RawInput_DeRegister(void); int IN_RawInput_Register(void); void IN_RawInput_DeInit(void); #endif // forward-referenced functions void IN_StartupJoystick (void); void Joy_AdvancedUpdate_f (void); void IN_JoyMove (usercmd_t *cmd, int pnum); /* =========== Force_CenterView_f =========== */ void Force_CenterView_f (void) { cl.viewangles[0][PITCH] = 0; } typedef void (*MW_DllFunc1)(void); typedef int (*MW_DllFunc2)(HWND); MW_DllFunc1 DLL_MW_RemoveHook = NULL; MW_DllFunc2 DLL_MW_SetHook = NULL; qboolean MW_Hook_enabled = false; HINSTANCE mw_hDLL; qboolean MW_Hook_allowed; static void MW_Set_Hook (void) { if (!mainwindow) return; if (!MW_Hook_allowed && !in_mwhook.value) return; if (MW_Hook_enabled) { Con_Printf("MouseWare hook already loaded\n"); return; } if (!(mw_hDLL = LoadLibrary("mw_hook.dll"))) { Con_Printf("Couldn't find mw_hook.dll\n"); in_mwhook.value = 0; MW_Hook_allowed=0; return; } DLL_MW_RemoveHook = (MW_DllFunc1) GetProcAddress(mw_hDLL, "MW_RemoveHook"); DLL_MW_SetHook = (MW_DllFunc2) GetProcAddress(mw_hDLL, "MW_SetHook"); if (!DLL_MW_SetHook || !DLL_MW_RemoveHook) { Con_Printf("Error initializing MouseWare hook\n"); FreeLibrary(mw_hDLL); in_mwhook.value = 0; MW_Hook_allowed=0; return; } if (!DLL_MW_SetHook(mainwindow)) { Con_Printf("Couldn't initialize MouseWare hook\n"); FreeLibrary(mw_hDLL); in_mwhook.value = 0; MW_Hook_allowed=0; return; } MW_Hook_enabled = true; // Con_Printf("MouseWare hook initialized\n"); } static void MW_Remove_Hook (void) { if (MW_Hook_enabled) { DLL_MW_RemoveHook(); FreeLibrary(mw_hDLL); MW_Hook_enabled = false; // Con_Printf("MouseWare hook removed\n"); return; } Con_Printf("MouseWare hook not loaded\n"); } static void MW_Shutdown(void) { if (!MW_Hook_enabled) return; MW_Remove_Hook(); } void MW_Hook_Message (long buttons) { static long old_buttons = 0; buttons &= 0xFFFF; switch (buttons ^ old_buttons) { case 8: Key_Event(K_MOUSE4, buttons > old_buttons ? true : false); break; case 16: Key_Event(K_MOUSE5, buttons > old_buttons ? true : false); break; case 32: Key_Event(K_MOUSE6, buttons > old_buttons ? true : false); break; case 64: Key_Event(K_MOUSE7, buttons > old_buttons ? true : false); break; case 128: Key_Event(K_MOUSE8, buttons > old_buttons ? true : false); break; default: break; } old_buttons = buttons; } /* =========== IN_UpdateClipCursor =========== */ void IN_UpdateClipCursor (void) { if (mouseinitialized && mouseactive && !dinput) { ClipCursor (&window_rect); } } /* =========== IN_ShowMouse =========== */ void IN_ShowMouse (void) { if (!mouseshowtoggle) { ShowCursor (TRUE); mouseshowtoggle = 1; } } /* =========== IN_HideMouse =========== */ void IN_HideMouse (void) { if (mouseshowtoggle) { ShowCursor (FALSE); mouseshowtoggle = 0; } } /* =========== IN_ActivateMouse =========== */ void IN_ActivateMouse (void) { mouseactivatetoggle = true; if (mouseinitialized) { #ifndef NODIRECTX #if (DIRECTINPUT_VERSION >= DINPUT_VERSION_DX7) if (dinput >= DINPUT_VERSION_DX7) { if (g_pMouse7) { if (!dinput_acquired) { IDirectInputDevice7_Acquire(g_pMouse7); dinput_acquired = true; } } else { return; } } else #endif if (dinput) { if (g_pMouse) { if (!dinput_acquired) { IDirectInputDevice_Acquire(g_pMouse); dinput_acquired = true; } } else { return; } } else #endif { #ifdef USINGRAWINPUT if (rawmicecount > 0) { if (IN_RawInput_Register()) { Con_SafePrintf("Raw input: unable to register raw input, deinitializing\n"); IN_RawInput_DeInit(); } } #endif if (mouseparmsvalid) restore_spi = SystemParametersInfo (SPI_SETMOUSE, 0, newmouseparms, 0); SetCursorPos (window_center_x, window_center_y); SetCapture (mainwindow); ClipCursor (&window_rect); } MW_Set_Hook(); mouseactive = true; } } /* =========== IN_SetQuakeMouseState =========== */ void IN_SetQuakeMouseState (void) { if (mouseactivatetoggle) IN_ActivateMouse (); else IN_DeactivateMouse(); } /* =========== IN_DeactivateMouse =========== */ void IN_DeactivateMouse (void) { mouseactivatetoggle = false; if (mouseinitialized) { #ifndef NODIRECTX #if (DIRECTINPUT_VERSION >= DINPUT_VERSION_DX7) if (dinput >= DINPUT_VERSION_DX7) { if (g_pMouse7) { if (dinput_acquired) { IDirectInputDevice_Unacquire(g_pMouse7); dinput_acquired = false; } } else { return; } } else #endif if (dinput) { if (g_pMouse) { if (dinput_acquired) { IDirectInputDevice_Unacquire(g_pMouse); dinput_acquired = false; } } } else #endif { #ifdef USINGRAWINPUT if (rawmicecount > 0) IN_RawInput_DeRegister(); #endif if (restore_spi) SystemParametersInfo (SPI_SETMOUSE, 0, originalmouseparms, 0); ClipCursor (NULL); ReleaseCapture (); } MW_Shutdown(); mouseactive = false; } } /* =========== IN_RestoreOriginalMouseState =========== */ void IN_RestoreOriginalMouseState (void) { if (mouseactivatetoggle) { IN_DeactivateMouse (); mouseactivatetoggle = true; } // try to redraw the cursor so it gets reinitialized, because sometimes it // has garbage after the mode switch ShowCursor (TRUE); ShowCursor (FALSE); } #ifndef NODIRECTX BOOL CALLBACK IN_EnumerateDevices(LPCDIDEVICEINSTANCE inst, LPVOID parm) { Con_DPrintf("EnumerateDevices found: %s\n", inst->tszProductName); return DIENUM_CONTINUE; } /* =========== IN_InitDInput =========== */ int IN_InitDInput (void) { HRESULT hr; DIPROPDWORD dipdw = { { sizeof(DIPROPDWORD), // diph.dwSize sizeof(DIPROPHEADER), // diph.dwHeaderSize 0, // diph.dwObj DIPH_DEVICE, // diph.dwHow }, DINPUT_BUFFERSIZE, // dwData }; if (!hInstDI) { hInstDI = LoadLibrary("dinput.dll"); if (hInstDI == NULL) { Con_SafePrintf ("Couldn't load dinput.dll\n"); return 0; } } #if (DIRECTINPUT_VERSION >= DINPUT_VERSION_DX7) if (!pDirectInputCreateEx) pDirectInputCreateEx = (void *)GetProcAddress(hInstDI,"DirectInputCreateEx"); if (pDirectInputCreateEx) // use DirectInput 7 { // register with DirectInput and get an IDirectInput to play with. hr = iDirectInputCreateEx(global_hInstance, DINPUT_VERSION_DX7, &IID_IDirectInput7, &g_pdi7, NULL); if (FAILED(hr)) return 0; IDirectInput7_EnumDevices(g_pdi7, 0, &IN_EnumerateDevices, NULL, DIEDFL_ATTACHEDONLY); // obtain an interface to the system mouse device. hr = IDirectInput7_CreateDeviceEx(g_pdi7, &GUID_SysMouse, &IID_IDirectInputDevice7, &g_pMouse7, NULL); if (FAILED(hr)) { Con_SafePrintf ("Couldn't open DI7 mouse device\n"); return 0; } // set the data format to "mouse format". hr = IDirectInputDevice7_SetDataFormat(g_pMouse7, &df); if (FAILED(hr)) { Con_SafePrintf ("Couldn't set DI7 mouse format\n"); return 0; } // set the cooperativity level. hr = IDirectInputDevice7_SetCooperativeLevel(g_pMouse7, mainwindow, DISCL_EXCLUSIVE | DISCL_FOREGROUND); if (FAILED(hr)) { Con_SafePrintf ("Couldn't set DI7 coop level\n"); return 0; } // set the buffer size to DINPUT_BUFFERSIZE elements. // the buffer size is a DWORD property associated with the device hr = IDirectInputDevice7_SetProperty(g_pMouse7, DIPROP_BUFFERSIZE, &dipdw.diph); if (FAILED(hr)) { Con_SafePrintf ("Couldn't set DI7 buffersize\n"); return 0; } return DINPUT_VERSION_DX7; } #endif if (!pDirectInputCreate) { pDirectInputCreate = (void *)GetProcAddress(hInstDI,"DirectInputCreateA"); if (!pDirectInputCreate) { Con_SafePrintf ("Couldn't get DI3 proc addr\n"); return 0; } } // register with DirectInput and get an IDirectInput to play with. hr = iDirectInputCreate(global_hInstance, DINPUT_VERSION_DX3, &g_pdi, NULL); if (FAILED(hr)) { return 0; } IDirectInput_EnumDevices(g_pdi, 0, &IN_EnumerateDevices, NULL, DIEDFL_ATTACHEDONLY); // obtain an interface to the system mouse device. hr = IDirectInput_CreateDevice(g_pdi, &GUID_SysMouse, &g_pMouse, NULL); if (FAILED(hr)) { Con_SafePrintf ("Couldn't open DI3 mouse device\n"); return 0; } // set the data format to "mouse format". hr = IDirectInputDevice_SetDataFormat(g_pMouse, &df); if (FAILED(hr)) { Con_SafePrintf ("Couldn't set DI3 mouse format\n"); return 0; } // set the cooperativity level. hr = IDirectInputDevice_SetCooperativeLevel(g_pMouse, mainwindow, DISCL_EXCLUSIVE | DISCL_FOREGROUND); if (FAILED(hr)) { Con_SafePrintf ("Couldn't set DI3 coop level\n"); return 0; } // 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)) { Con_SafePrintf ("Couldn't set DI3 buffersize\n"); return 0; } return DINPUT_VERSION_DX3; } void IN_CloseDInput (void) { #if (DIRECTINPUT_VERSION >= DINPUT_VERSION_DX7) if (g_pMouse7) { IDirectInputDevice7_Release(g_pMouse7); g_pMouse7 = NULL; } if (g_pdi7) { IDirectInput7_Release(g_pdi7); g_pdi7 = NULL; } #endif if (g_pMouse) { IDirectInputDevice_Release(g_pMouse); g_pMouse = NULL; } if (g_pdi) { IDirectInput_Release(g_pdi); g_pdi = NULL; } if (hInstDI) { FreeLibrary(hInstDI); hInstDI = NULL; pDirectInputCreate = NULL; } } #endif #ifdef USINGRAWINPUT void IN_RawInput_DeRegister(void) { RAWINPUTDEVICE Rid; // deregister raw input Rid.usUsagePage = 0x01; Rid.usUsage = 0x02; Rid.dwFlags = RIDEV_REMOVE; Rid.hwndTarget = NULL; (*_RRID)(&Rid, 1, sizeof(Rid)); } void IN_RawInput_DeInit(void) { if (rawmicecount < 1) return; IN_RawInput_DeRegister(); Z_Free(rawmice); // dealloc mouse structure rawmicecount = 0; } #endif void IN_SetSerialBoad(HANDLE port, int boadrate) { DCB dcb; memset(&dcb, 0, sizeof(dcb)); dcb.DCBlength = sizeof(dcb); GetCommState(port, &dcb); dcb.fBinary = TRUE; dcb.fParity = FALSE; dcb.fOutxCtsFlow = 0; dcb.fOutxDsrFlow = 0; dcb.fDtrControl = DTR_CONTROL_DISABLE; dcb.fDsrSensitivity = 0; dcb.fTXContinueOnXoff = FALSE; dcb.fOutX = 0; dcb.fInX = 0; dcb.fErrorChar = 0; dcb.fNull = 0; dcb.fRtsControl = RTS_CONTROL_DISABLE; dcb.fAbortOnError = 0; dcb.ByteSize = 7; dcb.StopBits = ONESTOPBIT; dcb.Parity = NOPARITY; dcb.ErrorChar = 0; dcb.EvtChar = 0; dcb.EofChar = 0; dcb.BaudRate = boadrate; // set the baud rate SetCommState(port, &dcb); //now get the com port to electricute the mouse... powering up... EscapeCommFunction(port, SETDTR); EscapeCommFunction(port, SETRTS); } //microsoft's 2 button mouse protocol unsigned int _stdcall IN_SerialMSRun(void *param) { mouse_t *mouse = param; char code[3]; DWORD read; int total=0; IN_SetSerialBoad(mouse->handles.comhandle, 1200); total=0; while(1) { ReadFile(mouse->handles.comhandle, code, sizeof(code)-total, &read, NULL); total+=read; if (total == 3) { mouse->buttons = 0; /* No button - should only happen on an error */ if ((code[0] & 0x20) != 0) mouse->buttons |= 1; else if ((code[0] & 0x10) != 0) mouse->buttons |= 2; mouse->delta[0] = (code[0] & 0x03) * 64 + (code[1] & 0x3F); if (mouse->delta[0] > 127) mouse->delta[0] = mouse->delta[0] - 256; mouse->delta[1] = (code[0] & 0x0C) * 16 + (code[2] & 0x3F); if (mouse->delta[1] > 127) mouse->delta[1] = mouse->delta[1] - 256; // Con_Printf("%i %i %i\n", serialmousexmove, serialmouseymove, serialmousebuttons); total=0; } } return true; } //microsofts's intellimouse protocol //used by most wheel mice. unsigned long __stdcall IN_SerialMSIntelliRun(void *param) { mouse_t *mouse = param; unsigned char code[80]; DWORD read, total=0; IN_SetSerialBoad(mouse->handles.comhandle, 1200); ReadFile(mouse->handles.comhandle, code, 11*4+2, &read, NULL); //header info which we choose to ignore mouse->numbuttons = 3; while(1) { ReadFile(mouse->handles.comhandle, code+total, 4-total, &read, NULL); total+=read; if (total >= 4) { // if (mouse->oldbuttons == mouse->buttons) // mouse->buttons=0; //don't clear prematurly. mouse->buttons = ((code[0] & 0x20) >> 5) /* left */ | ((code[3] & 0x10) >> 2) /* middle */ | ((code[0] & 0x10) >> 3); /* right */ mouse->delta[0] += (signed char)(((code[0] & 0x03) << 6) | (code[1]/* & 0x3F*/)); mouse->delta[1] += (signed char)(((code[0] & 0x0C) << 4) | (code[2]/* & 0x3F*/)); if (m_forcewheel.value) { int wdv; wdv = (signed char)((code[3] & 0x0f)<<4)/16; mouse->wheeldelta += wdv * m_forcewheel_threshold.value; } total=0; } else //an else shouldn't happen... { Sleep(4); // return false; } } return true; } #ifdef USINGRAWINPUT // raw input registration functions int IN_RawInput_Register(void) { // This function registers to receive the WM_INPUT messages RAWINPUTDEVICE Rid; // Register only for mouse messages from wm_input. //register to get wm_input messages Rid.usUsagePage = 0x01; Rid.usUsage = 0x02; Rid.dwFlags = RIDEV_NOLEGACY; // adds HID mouse and also ignores legacy mouse messages Rid.hwndTarget = NULL; // Register to receive the WM_INPUT message for any change in mouse (buttons, wheel, and movement will all generate the same message) if (!(*_RRID)(&Rid, 1, sizeof(Rid))) return 1; return 0; } int IN_RawInput_IsRDPMouse(char *cDeviceString) { char cRDPString[] = "\\??\\Root#RDP_MOU#"; int i; if (strlen(cDeviceString) < strlen(cRDPString)) { return 0; } for (i = strlen(cRDPString) - 1; i >= 0; i--) { if (cDeviceString[i] != cRDPString[i]) return 0; } return 1; // is RDP mouse } void IN_RawInput_Init(void) { // "0" to exclude, "1" to include PRAWINPUTDEVICELIST pRawInputDeviceList; int inputdevices, i, j, mtemp; char dname[MAX_RI_DEVICE_SIZE]; // Return 0 if rawinput is not available HMODULE user32 = LoadLibrary("user32.dll"); if (!user32) { Con_SafePrintf("Raw input: unable to load user32.dll\n"); return; } _RRID = (pRegisterRawInputDevices)GetProcAddress(user32,"RegisterRawInputDevices"); if (!_RRID) { Con_SafePrintf("Raw input: function RegisterRawInputDevices could not be registered\n"); return; } _GRIDL = (pGetRawInputDeviceList)GetProcAddress(user32,"GetRawInputDeviceList"); if (!_GRIDL) { Con_SafePrintf("Raw input: function GetRawInputDeviceList could not be registered\n"); return; } _GRIDIA = (pGetRawInputDeviceInfoA)GetProcAddress(user32,"GetRawInputDeviceInfoA"); if (!_GRIDIA) { Con_SafePrintf("Raw input: function GetRawInputDeviceInfoA could not be registered\n"); return; } _GRID = (pGetRawInputData)GetProcAddress(user32,"GetRawInputData"); if (!_GRID) { Con_SafePrintf("Raw input: function GetRawInputData could not be registered\n"); return; } rawmicecount = 0; rawmice = NULL; raw = NULL; ribuffersize = 0; // 1st call to GetRawInputDeviceList: Pass NULL to get the number of devices. if ((*_GRIDL)(NULL, &inputdevices, sizeof(RAWINPUTDEVICELIST)) != 0) { Con_SafePrintf("Raw input: unable to count raw input devices\n"); return; } // Allocate the array to hold the DeviceList pRawInputDeviceList = Z_Malloc(sizeof(RAWINPUTDEVICELIST) * inputdevices); // 2nd call to GetRawInputDeviceList: Pass the pointer to our DeviceList and GetRawInputDeviceList() will fill the array if ((*_GRIDL)(pRawInputDeviceList, &inputdevices, sizeof(RAWINPUTDEVICELIST)) == -1) { Con_SafePrintf("Raw input: unable to get raw input device list\n"); return; } // Loop through all devices and count the mice for (i = 0, mtemp = 0; i < inputdevices; i++) { if (pRawInputDeviceList[i].dwType == RIM_TYPEMOUSE) { j = MAX_RI_DEVICE_SIZE; // Get the device name and use it to determine if it's the RDP Terminal Services virtual device. if ((*_GRIDIA)(pRawInputDeviceList[i].hDevice, RIDI_DEVICENAME, dname, &j) < 0) dname[0] = 0; if (!(in_rawinput_rdp.value) && IN_RawInput_IsRDPMouse(dname)) // use rdp mouse (cvar) continue; // advance temp device count mtemp++; } } // exit out if no devices found if (!mtemp) { Con_SafePrintf("Raw input: no usable device found\n"); return; } // Loop again and bind devices rawmice = Z_Malloc(sizeof(mouse_t) * mtemp); for (i = 0; i < inputdevices; i++) { if (pRawInputDeviceList[i].dwType == RIM_TYPEMOUSE) { j = MAX_RI_DEVICE_SIZE; // Get the device name and use it to determine if it's the RDP Terminal Services virtual device. if ((*_GRIDIA)(pRawInputDeviceList[i].hDevice, RIDI_DEVICENAME, dname, &j) < 0) dname[0] = 0; if (!(in_rawinput_rdp.value) && IN_RawInput_IsRDPMouse(dname)) // use rdp mouse (cvar) continue; // print pretty message about the mouse dname[MAX_RI_DEVICE_SIZE - 1] = 0; for (mtemp = strlen(dname); mtemp >= 0; mtemp--) { if (dname[mtemp] == '#') { dname[mtemp + 1] = 0; break; } } Con_SafePrintf("Raw input: [%i] %s\n", i, dname); // set handle rawmice[rawmicecount].handles.rawinputhandle = pRawInputDeviceList[i].hDevice; rawmice[rawmicecount].numbuttons = 10; rawmice[rawmicecount].pos[0] = RI_INVALID_POS; rawmicecount++; } } // free the RAWINPUTDEVICELIST Z_Free(pRawInputDeviceList); // alloc raw input buffer raw = BZ_Malloc(INIT_RIBUFFER_SIZE); ribuffersize = INIT_RIBUFFER_SIZE; Con_SafePrintf("Raw input: initialized with %i mice\n", rawmicecount); return; // success } #endif /* =========== IN_StartupMouse =========== */ void IN_StartupMouse (void) { if ( COM_CheckParm ("-nomouse") ) return; mouseinitialized = true; #ifndef NODIRECTX if (in_dinput.value) { dinput = IN_InitDInput (); if (dinput) { Con_SafePrintf ("DirectInput initialized, version %i\n", (dinput >> 8 & 0xFF)); } else { Con_SafePrintf ("DirectInput not initialized\n"); } } else dinput = 0; if (!dinput) #endif { if (!mouseparmsvalid) mouseparmsvalid = SystemParametersInfo (SPI_GETMOUSE, 0, originalmouseparms, 0); if (mouseparmsvalid) { if ( m_accel_noforce.value ) newmouseparms[2] = originalmouseparms[2]; if ( m_threshold_noforce.value ) { newmouseparms[0] = originalmouseparms[0]; newmouseparms[1] = originalmouseparms[1]; } } #ifdef USINGRAWINPUT if (in_rawinput.value) { IN_RawInput_Init(); } #endif } if (COM_CheckParm("-m_mwhook")) MW_Hook_allowed = true; sysmouse.numbuttons = 10; // if a fullscreen video mode was set before the mouse was initialized, // set the mouse state appropriately if (mouseactivatetoggle) IN_ActivateMouse (); #ifdef SERIALMOUSE if (serialmouse.handles.comhandle) { TerminateThread(serialmouse.handles.threadhandle, 0); CloseHandle(serialmouse.handles.threadhandle); CloseHandle(serialmouse.handles.comhandle); } serialmouse.numbuttons = 0; if (COM_CheckParm("-mouse2")) { serialmouse.handles.comhandle = CreateFile("\\\\.\\COM2", GENERIC_READ, 0, // share for reading NULL, // default security OPEN_EXISTING, // existing file only FILE_ATTRIBUTE_NORMAL, // normal file NULL); // no attr. template if (serialmouse.handles.comhandle == INVALID_HANDLE_VALUE) { serialmouse.handles.comhandle = NULL; return; } serialmouse.handles.threadhandle = CreateThread(NULL, 1024, IN_SerialMSIntelliRun, (void *)&serialmouse, CREATE_SUSPENDED, &serialmouse.handles.threadid); SetThreadPriority(serialmouse.handles.threadhandle, THREAD_PRIORITY_HIGHEST); ResumeThread(serialmouse.handles.threadhandle); } else serialmouse.handles.comhandle = NULL; #endif } /* =========== IN_Init =========== */ void IN_ReInit (void) { IN_StartupMouse (); IN_StartupJoystick (); // IN_ActivateMouse(); } void IN_Init (void) { //keyboard variables Cvar_Register (&cl_keypad, "Input Controls"); // mouse variables Cvar_Register (&m_filter, "Input Controls"); Cvar_Register (&m_accel, "Input Controls"); Cvar_Register (&m_forcewheel, "Input Controls"); Cvar_Register (&m_forcewheel_threshold, "Input Controls"); Cvar_Register (&in_mwhook, "Input Controls"); Cvar_Register (&in_dinput, "Input Controls"); Cvar_Register (&m_accel_noforce, "Input Controls"); Cvar_Register (&m_threshold_noforce, "Input Controls"); // this looks strange but quake cmdline definitions // and MS documentation don't agree with each other if (COM_CheckParm ("-noforcemspd")) Cvar_Set(&m_accel_noforce, "1"); if (COM_CheckParm ("-noforcemaccel")) Cvar_Set(&m_threshold_noforce, "1"); if (COM_CheckParm ("-noforcemparms")) { Cvar_Set(&m_accel_noforce, "1"); Cvar_Set(&m_threshold_noforce, "1"); } if (COM_CheckParm ("-dinput")) Cvar_Set(&in_dinput, "1"); #ifdef IN_XFLIP Cvar_Register (&in_xflip, "Input stuff"); #endif // joystick variables Cvar_Register (&in_joystick, "Joystick variables"); Cvar_Register (&joy_name, "Joystick variables"); Cvar_Register (&joy_advanced, "Joystick variables"); Cvar_Register (&joy_advaxisx, "Joystick variables"); Cvar_Register (&joy_advaxisy, "Joystick variables"); Cvar_Register (&joy_advaxisz, "Joystick variables"); Cvar_Register (&joy_advaxisr, "Joystick variables"); Cvar_Register (&joy_advaxisu, "Joystick variables"); Cvar_Register (&joy_advaxisv, "Joystick variables"); Cvar_Register (&joy_forwardthreshold, "Joystick variables"); Cvar_Register (&joy_sidethreshold, "Joystick variables"); Cvar_Register (&joy_pitchthreshold, "Joystick variables"); Cvar_Register (&joy_yawthreshold, "Joystick variables"); Cvar_Register (&joy_forwardsensitivity, "Joystick variables"); Cvar_Register (&joy_sidesensitivity, "Joystick variables"); Cvar_Register (&joy_pitchsensitivity, "Joystick variables"); Cvar_Register (&joy_yawsensitivity, "Joystick variables"); Cvar_Register (&joy_wwhack1, "Joystick variables"); Cvar_Register (&joy_wwhack2, "Joystick variables"); Cmd_AddCommand ("force_centerview", Force_CenterView_f); Cmd_AddCommand ("joyadvancedupdate", Joy_AdvancedUpdate_f); uiWheelMessage = RegisterWindowMessage ( "MSWHEEL_ROLLMSG" ); #ifdef USINGRAWINPUT Cvar_Register (&in_rawinput, "Input Controls"); Cvar_Register (&in_rawinput_combine, "Input Controls"); Cvar_Register (&in_rawinput_rdp, "Input Controls"); #endif IN_ReInit(); } /* =========== IN_Shutdown =========== */ void IN_Shutdown (void) { IN_DeactivateMouse (); IN_ShowMouse (); mouseparmsvalid = false; #ifndef NODIRECTX IN_CloseDInput(); #endif #ifdef USINGRAWINPUT IN_RawInput_DeInit(); #endif } /* =========== IN_MouseEvent =========== */ void IN_MouseEvent (int mstate) { int i; if ((mouseactive || (key_dest != key_game)) && !dinput) { // perform button actions for (i=0 ; inumbuttons ; i++) { if ( (mouse->buttons & (1<oldbuttons & (1<buttons & (1<oldbuttons & (1<oldbuttons = mouse->buttons; if (m_forcewheel.value) { mfwt = (int)m_forcewheel_threshold.value; while(mouse->wheeldelta <= -mfwt) { Key_Event (K_MWHEELUP, true); Key_Event (K_MWHEELUP, false); mouse->wheeldelta += mfwt; } while(mouse->wheeldelta >= mfwt) { Key_Event (K_MWHEELDOWN, true); Key_Event (K_MWHEELDOWN, false); mouse->wheeldelta -= mfwt; } if (m_forcewheel.value < 2) mouse->wheeldelta = 0; } mx = mouse->delta[0]; mouse->delta[0]=0; my = mouse->delta[1]; mouse->delta[1]=0; #ifdef IN_XFLIP if(in_xflip.value) mx *= -1; #endif if (Key_MouseShouldBeFree()) { mousemove_x += mx; mousemove_y += my; mousecursor_x += mx; mousecursor_y += my; if (mousecursor_y<0) mousecursor_y=0; if (mousecursor_x<0) mousecursor_x=0; if (mousecursor_x >= vid.width) mousecursor_x = vid.width - 1; if (mousecursor_y >= vid.height) mousecursor_y = vid.height - 1; mx=my=0; #ifdef VM_UI UI_MousePosition(mousecursor_x, mousecursor_y); #endif } #ifdef PEXT_CSQC if (CSQC_MouseMove(mx, my)) { mx = 0; my = 0; } #endif if (m_filter.value) { double fraction = bound(0, m_filter.value, 2) * 0.5; mouse_x = (mx*(1-fraction) + mouse->old_delta[0]*fraction); mouse_y = (my*(1-fraction) + mouse->old_delta[1]*fraction); } else { mouse_x = mx; mouse_y = my; } mouse->old_delta[0] = mx; mouse->old_delta[1] = my; if (m_accel.value) { mouse_deltadist = sqrt(mx*mx + my*my); mouse_x *= (mouse_deltadist*m_accel.value + sensitivity.value*in_sensitivityscale); mouse_y *= (mouse_deltadist*m_accel.value + sensitivity.value*in_sensitivityscale); } else { mouse_x *= sensitivity.value*in_sensitivityscale; mouse_y *= sensitivity.value*in_sensitivityscale; } if (cl.stats[pnum][STAT_VIEWZOOM]) { mouse_x *= cl.stats[pnum][STAT_VIEWZOOM]/255.0f; mouse_y *= cl.stats[pnum][STAT_VIEWZOOM]/255.0f; } if (!cmd) { if (mx || my) { SetCursorPos (window_center_x, window_center_y); } return; } if (cl.paused) return; // add mouse X/Y movement to cmd if ( (in_strafe.state[pnum] & 1) || (lookstrafe.value && (in_mlook.state[pnum] & 1) )) cmd->sidemove += m_side.value * mouse_x; else { // if ((int)((cl.viewangles[pnum][PITCH]+89.99)/180) & 1) // mouse_x *= -1; cl.viewangles[pnum][YAW] -= m_yaw.value * mouse_x; } if (in_mlook.state[pnum] & 1) V_StopPitchDrift (pnum); if ( (in_mlook.state[pnum] & 1) && !(in_strafe.state[pnum] & 1)) { cl.viewangles[pnum][PITCH] += m_pitch.value * mouse_y; CL_ClampPitch(pnum); } else { if ((in_strafe.state[pnum] & 1) && noclip_anglehack) cmd->upmove -= m_forward.value * mouse_y; else cmd->forwardmove -= m_forward.value * mouse_y; } } /* =========== IN_MouseMove =========== */ void IN_MouseMove (usercmd_t *cmd, int pnum) { #ifdef RGLQUAKE extern int glwidth, glheight; #endif POINT current_pos; extern int mousecursor_x, mousecursor_y; extern int window_x, window_y; if (!mouseactive) { GetCursorPos (¤t_pos); mousecursor_x = current_pos.x-window_x; mousecursor_y = current_pos.y-window_y; #ifdef RGLQUAKE if (qrenderer == QR_OPENGL) //2d res scaling. { mousecursor_x *= vid.width/(float)glwidth; mousecursor_y *= vid.height/(float)glheight; } #endif #ifdef VM_UI UI_MousePosition(mousecursor_x, mousecursor_y); #endif return; } #ifndef NODIRECTX if (dinput) { DIDEVICEOBJECTDATA od; DWORD dwElements; HRESULT hr; for (;;) { dwElements = 1; #if (DIRECTINPUT_VERSION >= DINPUT_VERSION_DX7) if (dinput >= DINPUT_VERSION_DX7) { hr = IDirectInputDevice7_GetDeviceData(g_pMouse7, sizeof(DIDEVICEOBJECTDATA), &od, &dwElements, 0); if ((hr == DIERR_INPUTLOST) || (hr == DIERR_NOTACQUIRED)) { dinput_acquired = true; IDirectInputDevice7_Acquire(g_pMouse7); break; } } else #endif { hr = IDirectInputDevice_GetDeviceData(g_pMouse, sizeof(DIDEVICEOBJECTDATA), &od, &dwElements, 0); if ((hr == DIERR_INPUTLOST) || (hr == DIERR_NOTACQUIRED)) { dinput_acquired = true; IDirectInputDevice_Acquire(g_pMouse); break; } } /* Unable to read data or no data available */ if (FAILED(hr) || dwElements == 0) { break; } /* Look at the element to see what happened */ switch (od.dwOfs) { case DIMOFS_X: sysmouse.delta[0] += od.dwData; break; case DIMOFS_Y: sysmouse.delta[1] += od.dwData; break; case DIMOFS_Z: if (m_forcewheel.value >= 2) sysmouse.wheeldelta -= (signed int)od.dwData; else if (m_forcewheel.value) { int mfwt = (int)m_forcewheel_threshold.value; if ((signed int)od.dwData > mfwt) sysmouse.wheeldelta -= mfwt; else if ((signed int)od.dwData < -mfwt) sysmouse.wheeldelta += mfwt; } break; case DIMOFS_BUTTON0: if (od.dwData & 0x80) sysmouse.buttons |= 1; else sysmouse.buttons &= ~1; break; case DIMOFS_BUTTON1: if (od.dwData & 0x80) sysmouse.buttons |= (1 << 1); else sysmouse.buttons &= ~(1 << 1); break; case DIMOFS_BUTTON2: if (od.dwData & 0x80) sysmouse.buttons |= (1 << 2); else sysmouse.buttons &= ~(1 << 2); break; case DIMOFS_BUTTON3: if (od.dwData & 0x80) sysmouse.buttons |= (1 << 3); else sysmouse.buttons &= ~(1 << 3); break; #if (DIRECTINPUT_VERSION >= DINPUT_VERSION_DX7) case DIMOFS_BUTTON4: if (od.dwData & 0x80) sysmouse.buttons |= (1 << 4); else sysmouse.buttons &= ~(1 << 4); break; case DIMOFS_BUTTON5: if (od.dwData & 0x80) sysmouse.buttons |= (1 << 5); else sysmouse.buttons &= ~(1 << 5); break; case DIMOFS_BUTTON6: if (od.dwData & 0x80) sysmouse.buttons |= (1 << 6); else sysmouse.buttons &= ~(1 << 6); break; case DIMOFS_BUTTON7: if (od.dwData & 0x80) sysmouse.buttons |= (1 << 7); else sysmouse.buttons &= ~(1 << 7); break; #endif } } } else #endif { IN_Accumulate(); sysmouse.buttons = sysmouse.oldbuttons; //don't do it!!! Our buttons are event driven. We don't want to merge em and forget do we now? } #ifdef USINGRAWINPUT if (rawmicecount) { if (in_rawinput_combine.value && pnum == 0) { // not the right way to do this but it'll work for now int x; for (x = 0; x < rawmicecount; x++) { ProcessMouse(rawmice + x, cmd, 0); } } else if (pnum < rawmicecount) { ProcessMouse(rawmice + pnum, cmd, pnum); } } #endif if (pnum == 0) ProcessMouse(&sysmouse, cmd, pnum); #ifdef SERIALMOUSE if (pnum == 1 || cl.splitclients<2) ProcessMouse(&serialmouse, cmd, pnum); #endif } /* =========== IN_Move =========== */ void IN_Move (usercmd_t *cmd, int pnum) { if (ActiveApp && !Minimized) { IN_MouseMove (cmd, pnum); if (pnum == 1 || cl.splitclients<2) IN_JoyMove (cmd, pnum); } } /* =========== IN_Accumulate =========== */ void IN_Accumulate (void) { if (mouseactive && !dinput) { #ifdef USINGRAWINPUT if (rawmicecount) { } else #endif { POINT current_pos; GetCursorPos (¤t_pos); sysmouse.delta[0] += current_pos.x - window_center_x; sysmouse.delta[1] += current_pos.y - window_center_y; } // force the mouse to the center, so there's room to move SetCursorPos (window_center_x, window_center_y); } } #ifdef USINGRAWINPUT void IN_RawInput_MouseRead(HANDLE in_device_handle) { int i = 0, tbuttons, j; int dwSize; // get raw input if ((*_GRID)((HRAWINPUT)in_device_handle, RID_INPUT, NULL, &dwSize, sizeof(RAWINPUTHEADER)) == -1) { Con_Printf("Raw input: unable to add to get size of raw input header.\n"); return; } if (dwSize > ribuffersize) { ribuffersize = dwSize; raw = BZ_Realloc(raw, dwSize); } if ((*_GRID)((HRAWINPUT)in_device_handle, RID_INPUT, raw, &dwSize, sizeof(RAWINPUTHEADER)) != dwSize ) { Con_Printf("Raw input: unable to add to get raw input header.\n"); return; } // find mouse in our mouse list for (; i < rawmicecount; i++) { if (rawmice[i].handles.rawinputhandle == raw->header.hDevice) break; } if (i == rawmicecount) // we're not tracking this mouse return; // movement if (raw->data.mouse.usFlags & MOUSE_MOVE_ABSOLUTE) { if (rawmice[i].pos[0] != RI_INVALID_POS) { rawmice[i].delta[0] += raw->data.mouse.lLastX - rawmice[i].pos[0]; rawmice[i].delta[1] += raw->data.mouse.lLastY - rawmice[i].pos[1]; } rawmice[i].pos[0] = raw->data.mouse.lLastX; rawmice[i].pos[1] = raw->data.mouse.lLastY; } else // RELATIVE { rawmice[i].delta[0] += raw->data.mouse.lLastX; rawmice[i].delta[1] += raw->data.mouse.lLastY; rawmice[i].pos[0] = RI_INVALID_POS; } // buttons if (raw->data.mouse.usButtonFlags & RI_MOUSE_BUTTON_1_DOWN) Key_Event(K_MOUSE1, true); if (raw->data.mouse.usButtonFlags & RI_MOUSE_BUTTON_1_UP) Key_Event(K_MOUSE1, false); if (raw->data.mouse.usButtonFlags & RI_MOUSE_BUTTON_2_DOWN) Key_Event(K_MOUSE2, true); if (raw->data.mouse.usButtonFlags & RI_MOUSE_BUTTON_2_UP) Key_Event(K_MOUSE2, false); if (raw->data.mouse.usButtonFlags & RI_MOUSE_BUTTON_3_DOWN) Key_Event(K_MOUSE3, true); if (raw->data.mouse.usButtonFlags & RI_MOUSE_BUTTON_3_UP) Key_Event(K_MOUSE3, false); if (raw->data.mouse.usButtonFlags & RI_MOUSE_BUTTON_4_DOWN) Key_Event(K_MOUSE4, true); if (raw->data.mouse.usButtonFlags & RI_MOUSE_BUTTON_4_UP) Key_Event(K_MOUSE4, false); if (raw->data.mouse.usButtonFlags & RI_MOUSE_BUTTON_5_DOWN) Key_Event(K_MOUSE5, true); if (raw->data.mouse.usButtonFlags & RI_MOUSE_BUTTON_5_UP) Key_Event(K_MOUSE5, false); // mouse wheel if (raw->data.mouse.usButtonFlags & RI_MOUSE_WHEEL) { // If the current message has a mouse_wheel message if ((SHORT)raw->data.mouse.usButtonData > 0) { Key_Event(K_MWHEELUP, true); Key_Event(K_MWHEELUP, false); } if ((SHORT)raw->data.mouse.usButtonData < 0) { Key_Event(K_MWHEELDOWN, true); Key_Event(K_MWHEELDOWN, false); } } // extra buttons tbuttons = raw->data.mouse.ulRawButtons & RI_RAWBUTTON_MASK; for (j=6 ; j 14000.0) fTemp = 14000.0; // restore direction information fAxisValue = (fAxisValue > 0.0) ? fTemp : -fTemp; } } // convert range from -32768..32767 to -1..1 fAxisValue /= 32768.0; switch (dwAxisMap[i]) { case AxisForward: if ((joy_advanced.value == 0.0) && (in_mlook.state[pnum] & 1)) { // user wants forward control to become look control if (fabs(fAxisValue) > joy_pitchthreshold.value) { // if mouse invert is on, invert the joystick pitch value // only absolute control support here (joy_advanced is false) if (m_pitch.value < 0.0) { cl.viewangles[pnum][PITCH] -= (fAxisValue * joy_pitchsensitivity.value) * aspeed * cl_pitchspeed.value; } else { cl.viewangles[pnum][PITCH] += (fAxisValue * joy_pitchsensitivity.value) * aspeed * cl_pitchspeed.value; } V_StopPitchDrift(pnum); } else { // no pitch movement // disable pitch return-to-center unless requested by user // *** this code can be removed when the lookspring bug is fixed // *** the bug always has the lookspring feature on if(lookspring.value == 0.0) V_StopPitchDrift(pnum); } } else { // user wants forward control to be forward control if (fabs(fAxisValue) > joy_forwardthreshold.value) { cmd->forwardmove += (fAxisValue * joy_forwardsensitivity.value) * speed * cl_forwardspeed.value; } } break; case AxisSide: if (fabs(fAxisValue) > joy_sidethreshold.value) { cmd->sidemove += (fAxisValue * joy_sidesensitivity.value) * speed * cl_sidespeed.value; } break; case AxisTurn: if ((in_strafe.state[pnum] & 1) || (lookstrafe.value && (in_mlook.state[pnum] & 1))) { // user wants turn control to become side control if (fabs(fAxisValue) > joy_sidethreshold.value) { cmd->sidemove -= (fAxisValue * joy_sidesensitivity.value) * speed * cl_sidespeed.value; } } else { // user wants turn control to be turn control if (fabs(fAxisValue) > joy_yawthreshold.value) { if(dwControlMap[i] == JOY_ABSOLUTE_AXIS) { cl.viewangles[pnum][YAW] += (fAxisValue * joy_yawsensitivity.value) * aspeed * cl_yawspeed.value; } else { cl.viewangles[pnum][YAW] += (fAxisValue * joy_yawsensitivity.value) * speed * 180.0; } } } break; case AxisLook: if (in_mlook.state[pnum] & 1) { if (fabs(fAxisValue) > joy_pitchthreshold.value) { // pitch movement detected and pitch movement desired by user if(dwControlMap[i] == JOY_ABSOLUTE_AXIS) { cl.viewangles[pnum][PITCH] += (fAxisValue * joy_pitchsensitivity.value) * aspeed * cl_pitchspeed.value; } else { cl.viewangles[pnum][PITCH] += (fAxisValue * joy_pitchsensitivity.value) * speed * 180.0; } V_StopPitchDrift(pnum); } else { // no pitch movement // disable pitch return-to-center unless requested by user // *** this code can be removed when the lookspring bug is fixed // *** the bug always has the lookspring feature on if(lookspring.value == 0.0) V_StopPitchDrift(pnum); } } break; default: break; } } CL_ClampPitch(pnum); } qbyte scantokey[128] = { // 0 1 2 3 4 5 6 7 // 8 9 A B C D E F 0 , 27, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', K_BACKSPACE, 9, // 0 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', 13 , K_CTRL, 'a', 's', // 1 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', '\'', '`', K_SHIFT, '\\', 'z', 'x', 'c', 'v', // 2 'b', 'n', 'm', ',', '.', '/', K_SHIFT, '*', K_ALT, ' ', K_CAPSLOCK, K_F1, K_F2, K_F3, K_F4, K_F5, // 3 K_F6, K_F7, K_F8, K_F9, K_F10, K_PAUSE, K_SCRLCK, K_HOME, K_UPARROW, K_PGUP, '-', K_LEFTARROW,'5', K_RIGHTARROW,'+', K_END, // 4 K_DOWNARROW,K_PGDN, K_INS, K_DEL, 0, 0, 0, K_F11, K_F12, 0, 0, 0, 0, 0, 0, 0, // 5 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 6 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // 7 }; qbyte shiftscantokey[128] = { // 0 1 2 3 4 5 6 7 // 8 9 A B C D E F 0 , 27, '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '+', K_BACKSPACE, 9, // 0 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '{', '}', 13 , K_CTRL,'A', 'S', // 1 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', '"' , '~', K_SHIFT,'|', 'Z', 'X', 'C', 'V', // 2 'B', 'N', 'M', '<', '>', '?', K_SHIFT,'*', K_ALT,' ', K_CAPSLOCK , K_F1, K_F2, K_F3, K_F4, K_F5, // 3 K_F6, K_F7, K_F8, K_F9, K_F10, K_PAUSE , K_SCRLCK , K_HOME, K_UPARROW,K_PGUP,'_',K_LEFTARROW,'%',K_RIGHTARROW,'+',K_END, //4 K_DOWNARROW,K_PGDN,K_INS,K_DEL,0,0, 0, K_F11, K_F12, 0 , 0 , 0 , 0 , 0 , 0 , 0, // 5 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0, // 6 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 // 7 }; /* ======= MapKey Map from windows to quake keynums ======= */ int MapKey (int vkey) { int key; key = (vkey>>16)&255; if (cl_keypad.value) { switch (key) { case 0x1c: if ((vkey>>24)&1) //not compleatly seperate return K_KP_ENTER; break; case 0x47: if (!((vkey>>24)&1)) //not compleatly seperate return K_KP_HOME; break; case 0x48: if (!((vkey>>24)&1)) //not compleatly seperate return K_KP_UPARROW; break; case 0x49: if (!((vkey>>24)&1)) //not compleatly seperate return K_KP_PGUP; break; case 0x4b: if (!((vkey>>24)&1)) //not compleatly seperate return K_KP_LEFTARROW; break; case 0x4c: return K_KP_5; case 0x4d: if (!((vkey>>24)&1)) //not compleatly seperate return K_KP_RIGHTARROW; break; case 0x4f: if (!((vkey>>24)&1)) //not compleatly seperate return K_KP_END; break; case 0x50: if (!((vkey>>24)&1)) //not compleatly seperate return K_KP_DOWNARROW; break; case 0x51: if (!((vkey>>24)&1)) //not compleatly seperate return K_KP_PGDN; break; case 0x52: if (!((vkey>>24)&1)) //not compleatly seperate return K_KP_INS; break; case 0x53: if (!((vkey>>24)&1)) //not compleatly seperate return K_KP_DEL; break; case 0x35: if ((vkey>>24)&1) //not compleatly seperate return K_KP_SLASH; break; case 0x4a: return K_KP_MINUS; case 0x4e: return K_KP_PLUS; case 0x45: if ((vkey>>24)&1) //not compleatly seperate return K_KP_NUMLOCK; break; case 0x37: return K_KP_STAR; // case 0x // return K_KP_EQUALS; } } if (key > 127) return 0; if (scantokey[key] == 0) Con_DPrintf("key 0x%02x has no translation\n", key); return scantokey[key]; }