+#endif
+
+float VID_JoyState_GetAxis(const vid_joystate_t *joystate, int axis, float fsensitivity, float deadzone)
+{
+ float value;
+ value = (axis >= 0 && axis < MAXJOYAXIS) ? joystate->axis[axis] : 0.0f;
+ value = value > deadzone ? (value - deadzone) : (value < -deadzone ? (value + deadzone) : 0.0f);
+ value *= deadzone > 0 ? (1.0f / (1.0f - deadzone)) : 1.0f;
+ value = bound(-1, value, 1);
+ return value * fsensitivity;
+}
+
+qboolean VID_JoyBlockEmulatedKeys(int keycode)
+{
+ int j;
+ vid_joystate_t joystate;
+
+ if (!joy_axiskeyevents.integer)
+ return false;
+ if (vid_joystate.is360)
+ return false;
+ if (keycode != K_UPARROW && keycode != K_DOWNARROW && keycode != K_RIGHTARROW && keycode != K_LEFTARROW)
+ return false;
+
+ // block system-generated key events for arrow keys if we're emulating the arrow keys ourselves
+ VID_BuildJoyState(&joystate);
+ for (j = 32;j < 36;j++)
+ if (vid_joystate.button[j] || joystate.button[j])
+ return true;
+
+ return false;
+}
+
+void VID_Shared_BuildJoyState_Begin(vid_joystate_t *joystate)
+{
+#ifdef WIN32
+ xinput_state_t xinputstate;
+#endif
+ memset(joystate, 0, sizeof(*joystate));
+#ifdef WIN32
+ if (vid_xinputindex >= 0 && qXInputGetState && qXInputGetState(vid_xinputindex, &xinputstate) == S_OK)
+ {
+ joystate->is360 = true;
+ joystate->button[ 0] = (xinputstate.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_UP) != 0;
+ joystate->button[ 1] = (xinputstate.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_DOWN) != 0;
+ joystate->button[ 2] = (xinputstate.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_LEFT) != 0;
+ joystate->button[ 3] = (xinputstate.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_RIGHT) != 0;
+ joystate->button[ 4] = (xinputstate.Gamepad.wButtons & XINPUT_GAMEPAD_START) != 0;
+ joystate->button[ 5] = (xinputstate.Gamepad.wButtons & XINPUT_GAMEPAD_BACK) != 0;
+ joystate->button[ 6] = (xinputstate.Gamepad.wButtons & XINPUT_GAMEPAD_LEFT_THUMB) != 0;
+ joystate->button[ 7] = (xinputstate.Gamepad.wButtons & XINPUT_GAMEPAD_RIGHT_THUMB) != 0;
+ joystate->button[ 8] = (xinputstate.Gamepad.wButtons & XINPUT_GAMEPAD_LEFT_SHOULDER) != 0;
+ joystate->button[ 9] = (xinputstate.Gamepad.wButtons & XINPUT_GAMEPAD_RIGHT_SHOULDER) != 0;
+ joystate->button[10] = (xinputstate.Gamepad.wButtons & XINPUT_GAMEPAD_A) != 0;
+ joystate->button[11] = (xinputstate.Gamepad.wButtons & XINPUT_GAMEPAD_B) != 0;
+ joystate->button[12] = (xinputstate.Gamepad.wButtons & XINPUT_GAMEPAD_X) != 0;
+ joystate->button[13] = (xinputstate.Gamepad.wButtons & XINPUT_GAMEPAD_Y) != 0;
+ joystate->button[14] = xinputstate.Gamepad.bLeftTrigger >= XINPUT_GAMEPAD_TRIGGER_THRESHOLD;
+ joystate->button[15] = xinputstate.Gamepad.bRightTrigger >= XINPUT_GAMEPAD_TRIGGER_THRESHOLD;
+ joystate->button[16] = xinputstate.Gamepad.sThumbLY < -16384;
+ joystate->button[17] = xinputstate.Gamepad.sThumbLY > 16384;
+ joystate->button[18] = xinputstate.Gamepad.sThumbLX < -16384;
+ joystate->button[19] = xinputstate.Gamepad.sThumbLX > 16384;
+ joystate->button[20] = xinputstate.Gamepad.sThumbRY < -16384;
+ joystate->button[21] = xinputstate.Gamepad.sThumbRY > 16384;
+ joystate->button[22] = xinputstate.Gamepad.sThumbRX < -16384;
+ joystate->button[23] = xinputstate.Gamepad.sThumbRX > 16384;
+ joystate->axis[ 4] = xinputstate.Gamepad.bLeftTrigger * (1.0f / 255.0f);
+ joystate->axis[ 5] = xinputstate.Gamepad.bRightTrigger * (1.0f / 255.0f);
+ joystate->axis[ 0] = xinputstate.Gamepad.sThumbLX * (1.0f / 32767.0f);
+ joystate->axis[ 1] = xinputstate.Gamepad.sThumbLY * (1.0f / 32767.0f);
+ joystate->axis[ 2] = xinputstate.Gamepad.sThumbRX * (1.0f / 32767.0f);
+ joystate->axis[ 3] = xinputstate.Gamepad.sThumbRY * (1.0f / 32767.0f);
+ }
+#endif
+}
+
+void VID_Shared_BuildJoyState_Finish(vid_joystate_t *joystate)
+{
+ float f, r;
+ if (joystate->is360)
+ return;
+ // emulate key events for thumbstick
+ f = VID_JoyState_GetAxis(joystate, joy_axisforward.integer, 1, joy_axiskeyevents_deadzone.value) * joy_sensitivityforward.value;
+ r = VID_JoyState_GetAxis(joystate, joy_axisside.integer , 1, joy_axiskeyevents_deadzone.value) * joy_sensitivityside.value;
+#if MAXJOYBUTTON != 36
+#error this code must be updated if MAXJOYBUTTON changes!
+#endif
+ joystate->button[32] = f > 0.0f;
+ joystate->button[33] = f < 0.0f;
+ joystate->button[34] = r > 0.0f;
+ joystate->button[35] = r < 0.0f;
+}
+
+static void VID_KeyEventForButton(qboolean oldbutton, qboolean newbutton, int key, double *timer)
+{
+ if (oldbutton)
+ {
+ if (newbutton)
+ {
+ if (realtime >= *timer)
+ {
+ Key_Event(key, 0, true);
+ *timer = realtime + 0.1;
+ }
+ }
+ else
+ {
+ Key_Event(key, 0, false);
+ *timer = 0;
+ }
+ }
+ else
+ {
+ if (newbutton)
+ {
+ Key_Event(key, 0, true);
+ *timer = realtime + 0.5;
+ }
+ }
+}
+
+#if MAXJOYBUTTON != 36
+#error this code must be updated if MAXJOYBUTTON changes!
+#endif
+static int joybuttonkey[MAXJOYBUTTON][2] =
+{
+ {K_JOY1, K_ENTER}, {K_JOY2, K_ESCAPE}, {K_JOY3, 0}, {K_JOY4, 0}, {K_JOY5, 0}, {K_JOY6, 0}, {K_JOY7, 0}, {K_JOY8, 0}, {K_JOY9, 0}, {K_JOY10, 0}, {K_JOY11, 0}, {K_JOY12, 0}, {K_JOY13, 0}, {K_JOY14, 0}, {K_JOY15, 0}, {K_JOY16, 0},
+ {K_AUX1, 0}, {K_AUX2, 0}, {K_AUX3, 0}, {K_AUX4, 0}, {K_AUX5, 0}, {K_AUX6, 0}, {K_AUX7, 0}, {K_AUX8, 0}, {K_AUX9, 0}, {K_AUX10, 0}, {K_AUX11, 0}, {K_AUX12, 0}, {K_AUX13, 0}, {K_AUX14, 0}, {K_AUX15, 0}, {K_AUX16, 0},
+ {K_JOY_UP, K_UPARROW}, {K_JOY_DOWN, K_DOWNARROW}, {K_JOY_RIGHT, K_RIGHTARROW}, {K_JOY_LEFT, K_LEFTARROW},
+};
+
+static int joybuttonkey360[][2] =
+{
+ {K_X360_DPAD_UP, K_UPARROW},
+ {K_X360_DPAD_DOWN, K_DOWNARROW},
+ {K_X360_DPAD_LEFT, K_LEFTARROW},
+ {K_X360_DPAD_RIGHT, K_RIGHTARROW},
+ {K_X360_START, K_ESCAPE},
+ {K_X360_BACK, K_ESCAPE},
+ {K_X360_LEFT_THUMB, 0},
+ {K_X360_RIGHT_THUMB, 0},
+ {K_X360_LEFT_SHOULDER, 0},
+ {K_X360_RIGHT_SHOULDER, 0},
+ {K_X360_A, K_ENTER},
+ {K_X360_B, K_ESCAPE},
+ {K_X360_X, 0},
+ {K_X360_Y, 0},
+ {K_X360_LEFT_TRIGGER, 0},
+ {K_X360_RIGHT_TRIGGER, 0},
+ {K_X360_LEFT_THUMB_DOWN, K_DOWNARROW},
+ {K_X360_LEFT_THUMB_UP, K_UPARROW},
+ {K_X360_LEFT_THUMB_LEFT, K_LEFTARROW},
+ {K_X360_LEFT_THUMB_RIGHT, K_RIGHTARROW},
+ {K_X360_RIGHT_THUMB_DOWN, 0},
+ {K_X360_RIGHT_THUMB_UP, 0},
+ {K_X360_RIGHT_THUMB_LEFT, 0},
+ {K_X360_RIGHT_THUMB_RIGHT, 0},
+};