#include "../client/client.h"
#include "winquake.h"
extern unsigned sys_msg_time;
#define JOY_ABSOLUTE_AXIS 0x00000000
#define JOY_RELATIVE_AXIS 0x00000010
#define JOY_MAX_AXES 6
#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, AxisUp };
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];
cvar_t *in_mouse;
cvar_t *in_joystick;
cvar_t *joy_name;
cvar_t *joy_advanced;
cvar_t *joy_advaxisx;
cvar_t *joy_advaxisy;
cvar_t *joy_advaxisz;
cvar_t *joy_advaxisr;
cvar_t *joy_advaxisu;
cvar_t *joy_advaxisv;
cvar_t *joy_forwardthreshold;
cvar_t *joy_sidethreshold;
cvar_t *joy_pitchthreshold;
cvar_t *joy_yawthreshold;
cvar_t *joy_forwardsensitivity;
cvar_t *joy_sidesensitivity;
cvar_t *joy_pitchsensitivity;
cvar_t *joy_yawsensitivity;
cvar_t *joy_upthreshold;
cvar_t *joy_upsensitivity;
bool joy_avail, joy_advancedinit, joy_haspov;
DWORD joy_oldbuttonstate, joy_oldpovstate;
int joy_id;
DWORD joy_flags;
DWORD joy_numbuttons;
static JOYINFOEX ji;
bool in_appactive;
void IN_StartupJoystick(void);
void Joy_AdvancedUpdate_f(void);
void IN_JoyMove(usercmd_t *cmd);
cvar_t *m_filter;
bool mlooking;
void IN_MLookDown(void) { mlooking = true; }
void IN_MLookUp(void) {
mlooking = false;
if(!freelook->value && lookspring->value)
IN_CenterView();
}
int mouse_buttons;
int mouse_oldbuttonstate;
POINT current_pos;
int mouse_x, mouse_y, old_mouse_x, old_mouse_y, mx_accum, my_accum;
int old_x, old_y;
bool mouseactive;
bool restore_spi;
bool mouseinitialized;
int originalmouseparms[3], newmouseparms[3] = {0, 0, 1};
bool mouseparmsvalid;
int window_center_x, window_center_y;
RECT window_rect;
void IN_ActivateMouse(void) {
int width, height;
if(!mouseinitialized)
return;
if(!in_mouse->value) {
mouseactive = false;
return;
}
if(mouseactive)
return;
mouseactive = true;
if(mouseparmsvalid)
restore_spi = SystemParametersInfo(SPI_SETMOUSE, 0, newmouseparms, 0);
width = GetSystemMetrics(SM_CXSCREEN);
height = GetSystemMetrics(SM_CYSCREEN);
GetWindowRect(cl_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);
old_x = window_center_x;
old_y = window_center_y;
SetCapture(cl_hwnd);
ClipCursor(&window_rect);
while(ShowCursor(FALSE) >= 0)
;
}
void IN_DeactivateMouse(void) {
if(!mouseinitialized)
return;
if(!mouseactive)
return;
if(restore_spi)
SystemParametersInfo(SPI_SETMOUSE, 0, originalmouseparms, 0);
mouseactive = false;
ClipCursor(NULL);
ReleaseCapture();
while(ShowCursor(TRUE) < 0)
;
}
void IN_StartupMouse(void) {
cvar_t *cv;
cv = Cvar_Get("in_initmouse", "1", CVAR_NOSET);
if(!cv->value)
return;
mouseinitialized = true;
mouseparmsvalid = SystemParametersInfo(SPI_GETMOUSE, 0, originalmouseparms, 0);
mouse_buttons = 3;
}
void IN_MouseEvent(int mstate) {
int i;
if(!mouseinitialized)
return;
for(i = 0; i < mouse_buttons; i++) {
if((mstate & (1 << i)) && !(mouse_oldbuttonstate & (1 << i))) {
Key_Event(K_MOUSE1 + i, true, sys_msg_time);
}
if(!(mstate & (1 << i)) && (mouse_oldbuttonstate & (1 << i))) {
Key_Event(K_MOUSE1 + i, false, sys_msg_time);
}
}
mouse_oldbuttonstate = mstate;
}
void IN_MouseMove(usercmd_t *cmd) {
int mx, my;
if(!mouseactive)
return;
if(!GetCursorPos(¤t_pos))
return;
mx = current_pos.x - window_center_x;
my = current_pos.y - window_center_y;
#if 0#endif
if(m_filter->value) {
mouse_x = (mx + old_mouse_x) * 0.5;
mouse_y = (my + old_mouse_y) * 0.5;
} else {
mouse_x = mx;
mouse_y = my;
}
old_mouse_x = mx;
old_mouse_y = my;
mouse_x *= sensitivity->value;
mouse_y *= sensitivity->value;
if((in_strafe.state & 1) || (lookstrafe->value && mlooking))
cmd->sidemove += m_side->value * mouse_x;
else
cl.viewangles[YAW] -= m_yaw->value * mouse_x;
if((mlooking || freelook->value) && !(in_strafe.state & 1)) {
cl.viewangles[PITCH] += m_pitch->value * mouse_y;
} else {
cmd->forwardmove -= m_forward->value * mouse_y;
}
if(mx || my)
SetCursorPos(window_center_x, window_center_y);
}
cvar_t *v_centermove;
cvar_t *v_centerspeed;
void IN_Init(void) {
m_filter = Cvar_Get("m_filter", "0", 0);
in_mouse = Cvar_Get("in_mouse", "1", CVAR_ARCHIVE);
in_joystick = Cvar_Get("in_joystick", "0", CVAR_ARCHIVE);
joy_name = Cvar_Get("joy_name", "joystick", 0);
joy_advanced = Cvar_Get("joy_advanced", "0", 0);
joy_advaxisx = Cvar_Get("joy_advaxisx", "0", 0);
joy_advaxisy = Cvar_Get("joy_advaxisy", "0", 0);
joy_advaxisz = Cvar_Get("joy_advaxisz", "0", 0);
joy_advaxisr = Cvar_Get("joy_advaxisr", "0", 0);
joy_advaxisu = Cvar_Get("joy_advaxisu", "0", 0);
joy_advaxisv = Cvar_Get("joy_advaxisv", "0", 0);
joy_forwardthreshold = Cvar_Get("joy_forwardthreshold", "0.15", 0);
joy_sidethreshold = Cvar_Get("joy_sidethreshold", "0.15", 0);
joy_upthreshold = Cvar_Get("joy_upthreshold", "0.15", 0);
joy_pitchthreshold = Cvar_Get("joy_pitchthreshold", "0.15", 0);
joy_yawthreshold = Cvar_Get("joy_yawthreshold", "0.15", 0);
joy_forwardsensitivity = Cvar_Get("joy_forwardsensitivity", "-1", 0);
joy_sidesensitivity = Cvar_Get("joy_sidesensitivity", "-1", 0);
joy_upsensitivity = Cvar_Get("joy_upsensitivity", "-1", 0);
joy_pitchsensitivity = Cvar_Get("joy_pitchsensitivity", "1", 0);
joy_yawsensitivity = Cvar_Get("joy_yawsensitivity", "-1", 0);
v_centermove = Cvar_Get("v_centermove", "0.15", 0);
v_centerspeed = Cvar_Get("v_centerspeed", "500", 0);
Cmd_AddCommand("+mlook", IN_MLookDown);
Cmd_AddCommand("-mlook", IN_MLookUp);
Cmd_AddCommand("joy_advancedupdate", Joy_AdvancedUpdate_f);
IN_StartupMouse();
IN_StartupJoystick();
}
void IN_Shutdown(void) { IN_DeactivateMouse(); }
void IN_Activate(bool active) {
in_appactive = active;
mouseactive = !active; }
void IN_Frame(void) {
if(!mouseinitialized)
return;
if(!in_mouse || !in_appactive) {
IN_DeactivateMouse();
return;
}
if(!cl.refresh_prepped || cls.key_dest == key_console || cls.key_dest == key_menu) {
if(Cvar_VariableValue("vid_fullscreen") == 0) {
IN_DeactivateMouse();
return;
}
}
IN_ActivateMouse();
}
void IN_Move(usercmd_t *cmd) {
IN_MouseMove(cmd);
if(ActiveApp)
IN_JoyMove(cmd);
}
void IN_ClearStates(void) {
mx_accum = 0;
my_accum = 0;
mouse_oldbuttonstate = 0;
}
void IN_StartupJoystick(void) {
int numdevs;
JOYCAPS jc;
MMRESULT mmr;
cvar_t *cv;
joy_avail = false;
cv = Cvar_Get("in_initjoy", "1", CVAR_NOSET);
if(!cv->value)
return;
if((numdevs = joyGetNumDevs()) == 0) {
return;
}
for(joy_id = 0; joy_id < numdevs; joy_id++) {
memset(&ji, 0, sizeof(ji));
ji.dwSize = sizeof(ji);
ji.dwFlags = JOY_RETURNCENTERED;
if((mmr = joyGetPosEx(joy_id, &ji)) == JOYERR_NOERROR)
break;
}
if(mmr != JOYERR_NOERROR) {
Com_Printf("\njoystick not found -- no valid joysticks (%x)\n\n", mmr);
return;
}
memset(&jc, 0, sizeof(jc));
if((mmr = joyGetDevCaps(joy_id, &jc, sizeof(jc))) != JOYERR_NOERROR) {
Com_Printf("\njoystick not found -- invalid joystick capabilities (%x)\n\n", mmr);
return;
}
joy_numbuttons = jc.wNumButtons;
joy_haspov = jc.wCaps & JOYCAPS_HASPOV;
joy_oldbuttonstate = joy_oldpovstate = 0;
joy_avail = true;
joy_advancedinit = false;
Com_Printf("\njoystick detected\n\n");
}
PDWORD RawValuePointer(int axis) {
switch(axis) {
case JOY_AXIS_X:
return &ji.dwXpos;
case JOY_AXIS_Y:
return &ji.dwYpos;
case JOY_AXIS_Z:
return &ji.dwZpos;
case JOY_AXIS_R:
return &ji.dwRpos;
case JOY_AXIS_U:
return &ji.dwUpos;
case JOY_AXIS_V:
return &ji.dwVpos;
}
}
void Joy_AdvancedUpdate_f(void) {
int i;
DWORD dwTemp;
for(i = 0; i < JOY_MAX_AXES; i++) {
dwAxisMap[i] = AxisNada;
dwControlMap[i] = JOY_ABSOLUTE_AXIS;
pdwRawValue[i] = RawValuePointer(i);
}
if(joy_advanced->value == 0.0) {
dwAxisMap[JOY_AXIS_X] = AxisTurn;
dwAxisMap[JOY_AXIS_Y] = AxisForward;
} else {
if(strcmp(joy_name->string, "joystick") != 0) {
Com_Printf("\n%s configured\n\n", joy_name->string);
}
dwTemp = (DWORD)joy_advaxisx->value;
dwAxisMap[JOY_AXIS_X] = dwTemp & 0x0000000f;
dwControlMap[JOY_AXIS_X] = dwTemp & JOY_RELATIVE_AXIS;
dwTemp = (DWORD)joy_advaxisy->value;
dwAxisMap[JOY_AXIS_Y] = dwTemp & 0x0000000f;
dwControlMap[JOY_AXIS_Y] = dwTemp & JOY_RELATIVE_AXIS;
dwTemp = (DWORD)joy_advaxisz->value;
dwAxisMap[JOY_AXIS_Z] = dwTemp & 0x0000000f;
dwControlMap[JOY_AXIS_Z] = dwTemp & JOY_RELATIVE_AXIS;
dwTemp = (DWORD)joy_advaxisr->value;
dwAxisMap[JOY_AXIS_R] = dwTemp & 0x0000000f;
dwControlMap[JOY_AXIS_R] = dwTemp & JOY_RELATIVE_AXIS;
dwTemp = (DWORD)joy_advaxisu->value;
dwAxisMap[JOY_AXIS_U] = dwTemp & 0x0000000f;
dwControlMap[JOY_AXIS_U] = dwTemp & JOY_RELATIVE_AXIS;
dwTemp = (DWORD)joy_advaxisv->value;
dwAxisMap[JOY_AXIS_V] = dwTemp & 0x0000000f;
dwControlMap[JOY_AXIS_V] = dwTemp & JOY_RELATIVE_AXIS;
}
joy_flags = JOY_RETURNCENTERED | JOY_RETURNBUTTONS | JOY_RETURNPOV;
for(i = 0; i < JOY_MAX_AXES; i++) {
if(dwAxisMap[i] != AxisNada) {
joy_flags |= dwAxisFlags[i];
}
}
}
void IN_Commands(void) {
int i, key_index;
DWORD buttonstate, povstate;
if(!joy_avail) {
return;
}
buttonstate = ji.dwButtons;
for(i = 0; i < joy_numbuttons; i++) {
if((buttonstate & (1 << i)) && !(joy_oldbuttonstate & (1 << i))) {
key_index = (i < 4) ? K_JOY1 : K_AUX1;
Key_Event(key_index + i, true, 0);
}
if(!(buttonstate & (1 << i)) && (joy_oldbuttonstate & (1 << i))) {
key_index = (i < 4) ? K_JOY1 : K_AUX1;
Key_Event(key_index + i, false, 0);
}
}
joy_oldbuttonstate = buttonstate;
if(joy_haspov) {
povstate = 0;
if(ji.dwPOV != JOY_POVCENTERED) {
if(ji.dwPOV == JOY_POVFORWARD)
povstate |= 0x01;
if(ji.dwPOV == JOY_POVRIGHT)
povstate |= 0x02;
if(ji.dwPOV == JOY_POVBACKWARD)
povstate |= 0x04;
if(ji.dwPOV == JOY_POVLEFT)
povstate |= 0x08;
}
for(i = 0; i < 4; i++) {
if((povstate & (1 << i)) && !(joy_oldpovstate & (1 << i))) {
Key_Event(K_AUX29 + i, true, 0);
}
if(!(povstate & (1 << i)) && (joy_oldpovstate & (1 << i))) {
Key_Event(K_AUX29 + i, false, 0);
}
}
joy_oldpovstate = povstate;
}
}
bool IN_ReadJoystick(void) {
memset(&ji, 0, sizeof(ji));
ji.dwSize = sizeof(ji);
ji.dwFlags = joy_flags;
if(joyGetPosEx(joy_id, &ji) == JOYERR_NOERROR) {
return true;
} else {
return false;
}
}
void IN_JoyMove(usercmd_t *cmd) {
float speed, aspeed;
float fAxisValue;
int i;
if(joy_advancedinit != true) {
Joy_AdvancedUpdate_f();
joy_advancedinit = true;
}
if(!joy_avail || !in_joystick->value) {
return;
}
if(IN_ReadJoystick() != true) {
return;
}
if((in_speed.state & 1) ^ (int)cl_run->value)
speed = 2;
else
speed = 1;
aspeed = speed * cls.frametime;
for(i = 0; i < JOY_MAX_AXES; i++) {
fAxisValue = (float)*pdwRawValue[i];
fAxisValue -= 32768.0;
fAxisValue /= 32768.0;
switch(dwAxisMap[i]) {
case AxisForward:
if((joy_advanced->value == 0.0) && mlooking) {
if(fabs(fAxisValue) > joy_pitchthreshold->value) {
if(m_pitch->value < 0.0) {
cl.viewangles[PITCH] -= (fAxisValue * joy_pitchsensitivity->value) * aspeed * cl_pitchspeed->value;
} else {
cl.viewangles[PITCH] += (fAxisValue * joy_pitchsensitivity->value) * aspeed * cl_pitchspeed->value;
}
}
} else {
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 AxisUp:
if(fabs(fAxisValue) > joy_upthreshold->value) {
cmd->upmove += (fAxisValue * joy_upsensitivity->value) * speed * cl_upspeed->value;
}
break;
case AxisTurn:
if((in_strafe.state & 1) || (lookstrafe->value && mlooking)) {
if(fabs(fAxisValue) > joy_sidethreshold->value) {
cmd->sidemove -= (fAxisValue * joy_sidesensitivity->value) * speed * cl_sidespeed->value;
}
} else {
if(fabs(fAxisValue) > joy_yawthreshold->value) {
if(dwControlMap[i] == JOY_ABSOLUTE_AXIS) {
cl.viewangles[YAW] += (fAxisValue * joy_yawsensitivity->value) * aspeed * cl_yawspeed->value;
} else {
cl.viewangles[YAW] += (fAxisValue * joy_yawsensitivity->value) * speed * 180.0;
}
}
}
break;
case AxisLook:
if(mlooking) {
if(fabs(fAxisValue) > joy_pitchthreshold->value) {
if(dwControlMap[i] == JOY_ABSOLUTE_AXIS) {
cl.viewangles[PITCH] += (fAxisValue * joy_pitchsensitivity->value) * aspeed * cl_pitchspeed->value;
} else {
cl.viewangles[PITCH] += (fAxisValue * joy_pitchsensitivity->value) * speed * 180.0;
}
}
}
break;
default:
break;
}
}
}