diff --git a/src/win/win_joystick_xinput.cpp b/src/win/win_joystick_xinput.cpp
new file mode 100644
index 000000000..8a7f11b7f
--- /dev/null
+++ b/src/win/win_joystick_xinput.cpp
@@ -0,0 +1,255 @@
+/*
+ * 86Box A hypervisor and IBM PC system emulator that specializes in
+ * running old operating systems and software designed for IBM
+ * PC systems and compatibles from 1981 through fairly recent
+ * system designs based on the PCI bus.
+ *
+ * This file is part of the 86Box distribution.
+ *
+ * Xinput joystick interface.
+ *
+ * Version: @(#)win_joystick_xinput.cpp 1.0.0 2019/3/19
+ *
+ * Authors: Sarah Walker,
+ * Miran Grca,
+ * GH Cao,
+ *
+ * Copyright 2008-2018 Sarah Walker.
+ * Copyright 2016-2018 Miran Grca.
+ * Copyright 2019 GH Cao.
+ */
+#include
+#include
+#include
+#include
+#include
+#define HAVE_STDARG_H
+#include "../86box.h"
+#include "../device.h"
+#include "../plat.h"
+#include "../game/gameport.h"
+#include "win.h"
+
+#define XINPUT_MAX_JOYSTICKS 4
+#define XINPUT_NAME "Xinput compatiable controller"
+#define XINPUT_NAME_LX "Left Stick X"
+#define XINPUT_NAME_LY "Left Stick Y"
+#define XINPUT_NAME_RX "Right Stick X"
+#define XINPUT_NAME_RY "Right Stick Y"
+#define XINPUT_NAME_DPAD_X "D-pad X"
+#define XINPUT_NAME_DPAD_Y "D-pad Y"
+#define XINPUT_NAME_LB "LB"
+#define XINPUT_NAME_RB "RB"
+#define XINPUT_NAME_LT "LT"
+#define XINPUT_NAME_RT "RT"
+#define XINPUT_NAME_A "A"
+#define XINPUT_NAME_B "B"
+#define XINPUT_NAME_X "X"
+#define XINPUT_NAME_Y "Y"
+#define XINPUT_NAME_BACK "Back/View"
+#define XINPUT_NAME_START "Start/Menu"
+#define XINPUT_NAME_LS "Left Stick"
+#define XINPUT_NAME_RS "Right Stick"
+
+#ifdef ENABLE_JOYSTICK_LOG
+int joystick_do_log = ENABLE_JOYSTICK_LOG;
+
+
+static void
+joystick_log(const char *fmt, ...)
+{
+ va_list ap;
+
+ if (joystick_do_log) {
+ va_start(ap, fmt);
+ pclog_ex(fmt, ap);
+ va_end(ap);
+ }
+}
+#else
+#define joystick_log(fmt, ...)
+#endif
+
+plat_joystick_t plat_joystick_state[MAX_PLAT_JOYSTICKS];
+joystick_t joystick_state[MAX_JOYSTICKS];
+int joysticks_present = 0;
+
+XINPUT_STATE controllers[XINPUT_MAX_JOYSTICKS];
+
+void joystick_init()
+{
+ int c;
+
+ atexit(joystick_close);
+
+ joysticks_present = 0;
+
+ memset(controllers, 0, sizeof(XINPUT_STATE) * XINPUT_MAX_JOYSTICKS);
+
+ for (c=0; c 127) ? 128 : 0;
+ plat_joystick_state[c].b[7] = (controllers[c].Gamepad.bRightTrigger > 127) ? 128 : 0;
+ plat_joystick_state[c].b[8] = (controllers[c].Gamepad.wButtons & XINPUT_GAMEPAD_BACK) ? 128 : 0;
+ plat_joystick_state[c].b[9] = (controllers[c].Gamepad.wButtons & XINPUT_GAMEPAD_START) ? 128 : 0;
+ plat_joystick_state[c].b[10] = (controllers[c].Gamepad.wButtons & XINPUT_GAMEPAD_LEFT_THUMB) ? 128 : 0;
+ plat_joystick_state[c].b[11] = (controllers[c].Gamepad.wButtons & XINPUT_GAMEPAD_RIGHT_THUMB) ? 128 : 0;
+
+ int dpad_x = 0, dpad_y = 0;
+ if (controllers[c].Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_UP)
+ dpad_y+=32767;
+ if (controllers[c].Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_DOWN)
+ dpad_y-=32767;
+ if (controllers[c].Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_RIGHT)
+ dpad_x+=32767;
+ if (controllers[c].Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_LEFT)
+ dpad_x-=32767;
+
+ plat_joystick_state[c].a[2] = dpad_x;
+ plat_joystick_state[c].a[5] = dpad_y;
+ }
+}
+
+static int joystick_get_axis(int joystick_nr, int mapping)
+{
+ if (mapping & POV_X)
+ {
+ int pov = plat_joystick_state[joystick_nr].p[mapping & 3];
+
+ if (LOWORD(pov) == 0xFFFF)
+ return 0;
+ else
+ return sin((2*M_PI * (double)pov) / 36000.0) * 32767;
+ }
+ else if (mapping & POV_Y)
+ {
+ int pov = plat_joystick_state[joystick_nr].p[mapping & 3];
+
+ if (LOWORD(pov) == 0xFFFF)
+ return 0;
+ else
+ return -cos((2*M_PI * (double)pov) / 36000.0) * 32767;
+ }
+ else
+ return plat_joystick_state[joystick_nr].a[plat_joystick_state[joystick_nr].axis[mapping].id];
+}
+
+void joystick_process(void)
+{
+ int c, d;
+
+ if (joystick_type == 7) return;
+
+ joystick_poll();
+
+ for (c = 0; c < joystick_get_max_joysticks(joystick_type); c++)
+ {
+ if (joystick_state[c].plat_joystick_nr)
+ {
+ int joystick_nr = joystick_state[c].plat_joystick_nr - 1;
+
+ for (d = 0; d < joystick_get_axis_count(joystick_type); d++)
+ joystick_state[c].axis[d] = joystick_get_axis(joystick_nr, joystick_state[c].axis_mapping[d]);
+ for (d = 0; d < joystick_get_button_count(joystick_type); d++)
+ joystick_state[c].button[d] = plat_joystick_state[joystick_nr].b[joystick_state[c].button_mapping[d]];
+
+ for (d = 0; d < joystick_get_pov_count(joystick_type); d++)
+ {
+ int x, y;
+ double angle, magnitude;
+
+ x = joystick_get_axis(joystick_nr, joystick_state[c].pov_mapping[d][0]);
+ y = joystick_get_axis(joystick_nr, joystick_state[c].pov_mapping[d][1]);
+
+ angle = (atan2((double)y, (double)x) * 360.0) / (2*M_PI);
+ magnitude = sqrt((double)x*(double)x + (double)y*(double)y);
+
+ if (magnitude < 16384)
+ joystick_state[c].pov[d] = -1;
+ else
+ joystick_state[c].pov[d] = ((int)angle + 90 + 360) % 360;
+ }
+ }
+ else
+ {
+ for (d = 0; d < joystick_get_axis_count(joystick_type); d++)
+ joystick_state[c].axis[d] = 0;
+ for (d = 0; d < joystick_get_button_count(joystick_type); d++)
+ joystick_state[c].button[d] = 0;
+ for (d = 0; d < joystick_get_pov_count(joystick_type); d++)
+ joystick_state[c].pov[d] = -1;
+ }
+ }
+}
+