diff -urN wine-3.0-orig/dlls/xinput1_1/Makefile.in wine-3.0/dlls/xinput1_1/Makefile.in
--- wine-3.0-orig/dlls/xinput1_1/Makefile.in	2018-01-19 00:38:28 +0900
+++ wine-3.0/dlls/xinput1_1/Makefile.in	2018-01-27 09:22:20 +0900
@@ -1,7 +1,9 @@
 MODULE    = xinput1_1.dll
 PARENTSRC = ../xinput1_3
+IMPORTS   = dinput dxguid uuid comctl32 ole32 user32 advapi32
 
 C_SRCS = \
+	dinput_wrapper.c \
 	xinput_main.c
 
 RC_SRCS = version.rc
diff -urN wine-3.0-orig/dlls/xinput1_2/Makefile.in wine-3.0/dlls/xinput1_2/Makefile.in
--- wine-3.0-orig/dlls/xinput1_2/Makefile.in	2018-01-19 00:38:28 +0900
+++ wine-3.0/dlls/xinput1_2/Makefile.in	2018-01-27 09:22:20 +0900
@@ -1,7 +1,9 @@
 MODULE    = xinput1_2.dll
 PARENTSRC = ../xinput1_3
+IMPORTS   = dinput dxguid uuid comctl32 ole32 user32 advapi32
 
 C_SRCS = \
+	dinput_wrapper.c \
 	xinput_main.c
 
 RC_SRCS = version.rc
diff -urN wine-3.0-orig/dlls/xinput1_3/Makefile.in wine-3.0/dlls/xinput1_3/Makefile.in
--- wine-3.0-orig/dlls/xinput1_3/Makefile.in	2018-01-19 00:38:28 +0900
+++ wine-3.0/dlls/xinput1_3/Makefile.in	2018-01-27 09:22:20 +0900
@@ -1,7 +1,9 @@
 MODULE    = xinput1_3.dll
 IMPORTLIB = xinput
+IMPORTS   = dinput dxguid uuid comctl32 ole32 user32 advapi32
 
 C_SRCS = \
+	dinput_wrapper.c \
 	xinput_main.c
 
 RC_SRCS = version.rc
diff -urN wine-3.0-orig/dlls/xinput1_3/dinput_wrapper.c wine-3.0/dlls/xinput1_3/dinput_wrapper.c
--- wine-3.0-orig/dlls/xinput1_3/dinput_wrapper.c	1970-01-01 09:00:00 +0900
+++ wine-3.0/dlls/xinput1_3/dinput_wrapper.c	2018-01-27 09:22:20 +0900
@@ -0,0 +1,574 @@
+/*
+ * The Wine project - Xinput Joystick Library
+ * Copyright 2015 Andrew Church
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include "config.h"
+#include <assert.h>
+#include <stdarg.h>
+#include <string.h>
+
+#include "wine/debug.h"
+#include "windef.h"
+#include "winbase.h"
+#include "winerror.h"
+
+#include "dinput.h"
+#include "xinput.h"
+
+#include "xinput_private.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(xinput);
+
+
+static HINSTANCE this_instance;
+static BOOL did_CoInitialize;
+static IDirectInputA *pDI;
+
+/* Data for a single axis. */
+struct axis_info {
+    BOOL present;
+    LONG min, max;
+    float deadzone;
+};
+
+/* Button indices for device_info.buttons[]. */
+enum {
+    BUTTON_DPAD_UP = 0,
+    BUTTON_DPAD_DOWN,
+    BUTTON_DPAD_LEFT,
+    BUTTON_DPAD_RIGHT,
+    BUTTON_START,
+    BUTTON_BACK,
+    BUTTON_LEFT_THUMB,
+    BUTTON_RIGHT_THUMB,
+    BUTTON_LEFT_SHOULDER,
+    BUTTON_RIGHT_SHOULDER,
+    BUTTON_LEFT_TRIGGER,
+    BUTTON_RIGHT_TRIGGER,
+    BUTTON_A,
+    BUTTON_B,
+    BUTTON_X,
+    BUTTON_Y,
+    NUM_BUTTONS
+};
+
+/* Mapping from BUTTON_* to flag values. */
+static WORD button_to_flag[NUM_BUTTONS] = {
+    XINPUT_GAMEPAD_DPAD_UP,
+    XINPUT_GAMEPAD_DPAD_DOWN,
+    XINPUT_GAMEPAD_DPAD_LEFT,
+    XINPUT_GAMEPAD_DPAD_RIGHT,
+    XINPUT_GAMEPAD_START,
+    XINPUT_GAMEPAD_BACK,
+    XINPUT_GAMEPAD_LEFT_THUMB,
+    XINPUT_GAMEPAD_RIGHT_THUMB,
+    XINPUT_GAMEPAD_LEFT_SHOULDER,
+    XINPUT_GAMEPAD_RIGHT_SHOULDER,
+    0,  /* BUTTON_LEFT_TRIGGER */
+    0,  /* BUTTON_RIGHT_TRIGGER */
+    XINPUT_GAMEPAD_A,
+    XINPUT_GAMEPAD_B,
+    XINPUT_GAMEPAD_X,
+    XINPUT_GAMEPAD_Y,
+};
+
+/* Data for all valid device indices (0-3). */
+struct device_info {
+    BOOL present;
+    GUID guid;  /* If !present, GUID of the last device seen in this slot */
+    IDirectInputDeviceA *didevice;  /* NULL if no device present */
+    XINPUT_CAPABILITIES caps;
+    struct axis_info x, y, z, rx, ry, rz;
+    enum {NONE = 0, Z_RX, Z_RZ, RX_RY} right_stick_axes;
+    BOOL lt_rt_are_axes;  /* TRUE = use Z/RZ axes; FALSE = use buttons */
+    BOOL dpad_is_hat;  /* TRUE = use hat 0; FALSE = use buttons */
+    int button_mapping[NUM_BUTTONS];  /* -1 = button not present */
+    DWORD next_packet;  /* for XInputGetState */
+};
+static struct device_info devices[4];
+
+/***********************************************************************
+ *      enumerate_axis
+ *
+ * Process a single input axis on a DirectInput device.  Helper for
+ * enumerate_device().
+ */
+static BOOL CALLBACK enumerate_axis(const DIDEVICEOBJECTINSTANCEA *ddoi, void *userdata)
+{
+    struct device_info *device = userdata;
+    struct axis_info *axis;
+    HRESULT hr;
+    DIPROPRANGE diprg;
+    DIPROPDWORD dipdw;
+
+    if (IsEqualIID(&ddoi->guidType, &GUID_XAxis)) {
+        axis = &device->x;
+    } else if (IsEqualIID(&ddoi->guidType, &GUID_YAxis)) {
+        axis = &device->y;
+    } else if (IsEqualIID(&ddoi->guidType, &GUID_ZAxis)) {
+        axis = &device->z;
+    } else if (IsEqualIID(&ddoi->guidType, &GUID_RxAxis)) {
+        axis = &device->rx;
+    } else if (IsEqualIID(&ddoi->guidType, &GUID_RyAxis)) {
+        axis = &device->ry;
+    } else if (IsEqualIID(&ddoi->guidType, &GUID_RzAxis)) {
+        axis = &device->rz;
+    } else {
+        return DIENUM_CONTINUE;
+    }
+
+    diprg.diph.dwSize       = sizeof(DIPROPRANGE);
+    diprg.diph.dwHeaderSize = sizeof(DIPROPHEADER);
+    diprg.diph.dwHow        = DIPH_BYID;
+    diprg.diph.dwObj        = ddoi->dwType;
+    hr = IDirectInputDevice_GetProperty(device->didevice, DIPROP_RANGE, &diprg.diph);
+    if (!SUCCEEDED(hr)) {
+        WARN("IDirectInputDevice_GetProperty(DIPROP_RANGE) failed for axis %d on device %s: %08X\n",
+             (int)(axis - &device->x), debugstr_guid(&device->guid), hr);
+        return DIENUM_CONTINUE;
+    }
+    axis->min = diprg.lMin;
+    axis->max = diprg.lMax;
+
+    dipdw.diph.dwSize       = sizeof(dipdw);
+    dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER);
+    dipdw.diph.dwHow        = DIPH_BYID;
+    dipdw.diph.dwObj        = ddoi->dwType;
+    hr = IDirectInputDevice_GetProperty(device->didevice, DIPROP_DEADZONE, &dipdw.diph);
+    if (!SUCCEEDED(hr)) {
+        WARN("IDirectInputDevice_GetProperty(DIPROP_DEADZONE) failed for axis %d on device %s: %08X\n",
+             (int)(axis - &device->x), debugstr_guid(&device->guid), hr);
+        dipdw.dwData = 0;
+    }
+    axis->deadzone = dipdw.dwData / 10000.0f;
+
+    axis->present = TRUE;
+    return DIENUM_CONTINUE;
+}
+
+/***********************************************************************
+ *      enumerate_device
+ *
+ * Process a single DirectInput device.  Helper for scan_devices().
+ */
+static BOOL CALLBACK enumerate_device(const DIDEVICEINSTANCEA *ddi, void *unused)
+{
+    HRESULT hr;
+    DIDEVCAPS caps;
+    int slot;
+    int i;
+
+    /* Choose a slot for this device.  If it's one we've seen before,
+    use the slot we used last time. */
+    slot = -1;
+    for (i = 0; i < 4; i++) {
+        if (memcmp(&ddi->guidInstance, &devices[i].guid, sizeof(GUID)) == 0) {
+            slot = i;
+            break;
+        }
+    }
+    if (slot < 0) {
+        for (i = 0; i < 4; i++) {
+            if (!devices[i].present) {
+                slot = i;
+                break;
+            }
+        }
+    }
+    if (slot < 0) {
+        WARN("No free slots for device %s, stopping enumeration\n",
+             debugstr_guid(&ddi->guidInstance));
+        return DIENUM_STOP;
+    }
+
+    if (devices[slot].didevice) {
+        devices[slot].present = TRUE;
+        return TRUE;
+    }
+
+    memset(&devices[slot], 0, sizeof(devices[slot]));
+    memcpy(&devices[slot].guid, &ddi->guidInstance, sizeof(GUID));
+    hr = IDirectInput_CreateDevice(pDI, &ddi->guidInstance,
+                                   &devices[slot].didevice, NULL);
+    if (hr != DI_OK) {
+        WARN("Failed to create IDirectInputDevice for device %s: %08X",
+             debugstr_guid(&ddi->guidInstance), hr);
+        devices[i].didevice = NULL;  /* Just in case. */
+        return DIENUM_CONTINUE;
+    }
+    hr = IDirectInputDevice_SetDataFormat(devices[slot].didevice,
+                                          &c_dfDIJoystick);
+    if (hr != DI_OK) {
+        WARN("IDirectInputDevice_SetDataFormat() failed for device %s: %08X",
+             debugstr_guid(&ddi->guidInstance), hr);
+        IDirectInputDevice_Release(devices[i].didevice);
+        devices[i].didevice = NULL;
+        return DIENUM_CONTINUE;
+    }
+    memset(&caps, 0, sizeof(caps));
+    caps.dwSize = sizeof(caps);
+    hr = IDirectInputDevice_GetCapabilities(devices[i].didevice, &caps);
+    if (hr != DI_OK) {
+        WARN("IDirectInputDevice_GetCapabilities() failed for device %s: %08X",
+             debugstr_guid(&ddi->guidInstance), hr);
+        IDirectInputDevice_Release(devices[i].didevice);
+        devices[i].didevice = NULL;
+        return DIENUM_CONTINUE;
+    }
+    hr = IDirectInputDevice_EnumObjects(devices[slot].didevice, enumerate_axis,
+                                        &devices[slot], DIDFT_ABSAXIS);
+    if (hr != DI_OK) {
+        WARN("IDirectInputDevice_EnumObjects() failed for device %s: %08X",
+             debugstr_guid(&ddi->guidInstance), hr);
+        IDirectInputDevice_Release(devices[i].didevice);
+        devices[i].didevice = NULL;
+        return DIENUM_CONTINUE;
+    }
+
+    hr = IDirectInputDevice_Acquire(devices[slot].didevice);
+    if (hr != DI_OK) {
+        WARN("IDirectInputDevice_Acquire() failed for device %s: %08X",
+             debugstr_guid(&ddi->guidInstance), hr);
+        IDirectInputDevice_Release(devices[i].didevice);
+        devices[i].didevice = NULL;
+        return DIENUM_CONTINUE;
+    }
+
+    if (devices[slot].x.present && devices[slot].y.present) {
+        if (devices[slot].rx.present && devices[slot].ry.present) {
+            devices[slot].right_stick_axes = RX_RY;
+            if (devices[slot].z.present && devices[slot].rz.present) {
+                devices[slot].lt_rt_are_axes = TRUE;
+            }
+        } else if (devices[slot].z.present) {
+            if (devices[slot].rx.present){ 
+                devices[slot].right_stick_axes = Z_RX;
+            } else if (devices[slot].rz.present){ 
+                devices[slot].right_stick_axes = Z_RZ;
+            }
+        }
+    }
+
+    devices[slot].dpad_is_hat = (caps.dwPOVs > 0);
+
+    /* FIXME: need an env-var or something to control button mapping */
+    /* (this is for the PS3 controller) */
+    memset(devices[slot].button_mapping, -1, sizeof(devices[slot].button_mapping));
+    devices[slot].button_mapping[BUTTON_BACK] = 0;
+    devices[slot].button_mapping[BUTTON_LEFT_THUMB] = 1;
+    devices[slot].button_mapping[BUTTON_RIGHT_THUMB] = 2;
+    devices[slot].button_mapping[BUTTON_START] = 3;
+    devices[slot].button_mapping[BUTTON_DPAD_UP] = 4;
+    devices[slot].button_mapping[BUTTON_DPAD_RIGHT] = 5;
+    devices[slot].button_mapping[BUTTON_DPAD_DOWN] = 6;
+    devices[slot].button_mapping[BUTTON_DPAD_LEFT] = 7;
+    devices[slot].button_mapping[BUTTON_LEFT_TRIGGER] = 8;
+    devices[slot].button_mapping[BUTTON_RIGHT_TRIGGER] = 9;
+    devices[slot].button_mapping[BUTTON_LEFT_SHOULDER] = 10;
+    devices[slot].button_mapping[BUTTON_RIGHT_SHOULDER] = 11;
+    devices[slot].button_mapping[BUTTON_Y] = 12;
+    devices[slot].button_mapping[BUTTON_B] = 13;
+    devices[slot].button_mapping[BUTTON_A] = 14;
+    devices[slot].button_mapping[BUTTON_X] = 15;
+
+    devices[slot].present = TRUE;
+    return DIENUM_CONTINUE;
+}
+
+/***********************************************************************
+ *      scan_devices
+ *
+ * Scan for DirectInput joystick devices and register them as XInput
+ * devices.  Also discard any XInput devices which are no longer present.
+ */
+static void scan_devices(void)
+{
+    HRESULT hr;
+    int i;
+
+    for (i = 0; i < 4; i++) {
+        devices[i].present = FALSE;
+    }
+    hr = IDirectInput_EnumDevices(pDI, DIDEVTYPE_JOYSTICK, enumerate_device,
+                                  NULL, DIEDFL_ALLDEVICES);
+    if (hr != DI_OK) {
+        WARN("IDirectInput_EnumDevices() failed: %08X\n", hr);
+        return;
+    }
+
+    for (i = 0; i < 4; i++) {
+        if (!devices[i].present && devices[i].didevice) {
+            IDirectInputDevice_Release(devices[i].didevice);
+            devices[i].didevice = NULL;
+        }
+    }
+}
+
+/***********************************************************************
+ *      read_state
+ *
+ * Read the state of the given device and set *pGamepad appropriately.
+ */
+static void read_state(int slot, XINPUT_GAMEPAD* pGamepad)
+{
+    DIJOYSTATE js;
+    HRESULT hr;
+    int i;
+
+    memset(pGamepad, 0, sizeof(*pGamepad));
+
+    hr = IDirectInputDevice_GetDeviceState(devices[slot].didevice, sizeof(js), &js);
+    if (hr != DI_OK) {
+        WARN("IDirectInputDevice_GetDeviceState() failed: %08x\n", hr);
+        return;
+    }
+
+    pGamepad->sThumbLX = (SHORT)(js.lX - 0x8000);
+    pGamepad->sThumbLY = (SHORT)(js.lY - 0x8000);
+    if (devices[slot].right_stick_axes == Z_RX) {
+        pGamepad->sThumbLX = (SHORT)(js.lZ - 0x8000);
+        pGamepad->sThumbLY = (SHORT)(js.lRx - 0x8000);
+    } else if (devices[slot].right_stick_axes == Z_RZ) {
+        pGamepad->sThumbLX = (SHORT)(js.lZ - 0x8000);
+        pGamepad->sThumbLY = (SHORT)(js.lRz - 0x8000);
+    } else if (devices[slot].right_stick_axes == RX_RY) {
+        pGamepad->sThumbLX = (SHORT)(js.lRx - 0x8000);
+        pGamepad->sThumbLY = (SHORT)(js.lRy - 0x8000);
+    }
+
+    if (devices[slot].lt_rt_are_axes) {
+        pGamepad->bLeftTrigger = (BYTE)(js.lZ >> 8);
+        pGamepad->bRightTrigger = (BYTE)(js.lRz >> 8);
+    }
+
+    if (devices[slot].dpad_is_hat) {
+        if (LOWORD(js.rgdwPOV[0]) != 0xFFFF) {
+            if (js.rgdwPOV[0] >= 31500 || js.rgdwPOV[0] <= 4500) {
+                pGamepad->wButtons |= XINPUT_GAMEPAD_DPAD_UP;
+            }
+            if (js.rgdwPOV[0] >= 4500 && js.rgdwPOV[0] <= 13500) {
+                pGamepad->wButtons |= XINPUT_GAMEPAD_DPAD_RIGHT;
+            }
+            if (js.rgdwPOV[0] >= 13500 && js.rgdwPOV[0] <= 22500) {
+                pGamepad->wButtons |= XINPUT_GAMEPAD_DPAD_DOWN;
+            }
+            if (js.rgdwPOV[0] >= 22500 && js.rgdwPOV[0] <= 31500) {
+                pGamepad->wButtons |= XINPUT_GAMEPAD_DPAD_LEFT;
+            }
+        }
+    }
+
+    for (i = 0; i < NUM_BUTTONS; i++) {
+        if (devices[slot].button_mapping[i] != -1 && (js.rgbButtons[devices[slot].button_mapping[i]] & 0x80)) {
+            if (i == BUTTON_LEFT_TRIGGER) {
+                pGamepad->bLeftTrigger = 255;
+            } else if (i == BUTTON_RIGHT_TRIGGER) {
+                pGamepad->bRightTrigger = 255;
+            } else {
+                pGamepad->wButtons |= button_to_flag[i];
+            }
+        }
+    }
+}
+
+/***********************************************************************
+ *      _init_dinput
+ */
+void _init_dinput(HINSTANCE hInstance)
+{
+    this_instance = hInstance;
+    did_CoInitialize = FALSE;
+    pDI = NULL;
+    memset(devices, 0, sizeof(devices));
+}
+
+/***********************************************************************
+ *      _close_dinput
+ */
+void _close_dinput(void)
+{
+    if (pDI) {
+        IDirectInput_Release(pDI);
+        pDI = NULL;
+    }
+    if (did_CoInitialize) {
+        CoUninitialize();
+    }
+}
+
+/******************************************************************************
+ *	XInputEnable (XINPUT1_3.5)
+ */
+void WINAPI DECLSPEC_HOTPATCH XInputEnable(BOOL enable)
+{
+    TRACE("(%d)\n", enable);
+
+    /* Setting to false will force XInputGetState to return neutral data,
+    cancel any running vibration effects, and stop messages from XInputSetState
+    being sent to the controllers. Setting to true will send the last vibration
+    value (sent to XInputSetState) to the controller and restore normal set/get
+    behavior. */
+    FIXME("stub!\n");
+}
+
+/******************************************************************************
+ *	XInputSetState (XINPUT1_3.3)
+ */
+DWORD WINAPI XInputSetState(DWORD dwUserIndex, XINPUT_VIBRATION* pVibration)
+{
+    TRACE("(%d %p)\n", dwUserIndex, pVibration);
+
+    if (dwUserIndex >= XUSER_MAX_COUNT || !pVibration) {
+        return ERROR_BAD_ARGUMENTS;
+    } else if (!devices[dwUserIndex].present) {
+        return ERROR_DEVICE_NOT_CONNECTED;
+    }
+
+    FIXME("stub!\n");
+    return ERROR_SUCCESS;
+}
+
+/******************************************************************************
+ *	XInputGetState (XINPUT1_3.2)
+ */
+DWORD WINAPI DECLSPEC_HOTPATCH XInputGetState(DWORD dwUserIndex, XINPUT_STATE* pState)
+{
+    TRACE("(%d %p)\n", dwUserIndex, pState);
+
+    if (!did_CoInitialize) {
+        HRESULT hr;
+        hr = CoInitialize(NULL);
+        did_CoInitialize = (hr == S_OK || hr == S_FALSE);
+        hr = DirectInputCreateA(this_instance, 0x0500, &pDI, NULL);
+        if (hr != DI_OK) {
+            WARN("DirectInputCreateA() failed: %08X\n", hr);
+        } else {
+            TRACE("scanning devices\n");
+            scan_devices();
+            /* FIXME: should rescan periodically */
+        }
+    }
+
+    if (dwUserIndex >= XUSER_MAX_COUNT || !pState) {
+        return ERROR_BAD_ARGUMENTS;
+    } else if (!devices[dwUserIndex].present) {
+        return ERROR_DEVICE_NOT_CONNECTED;
+    }
+
+    pState->dwPacketNumber = devices[dwUserIndex].next_packet++;
+    read_state(dwUserIndex, &pState->Gamepad);
+    return ERROR_SUCCESS;
+}
+
+/******************************************************************************
+ *	XInputGetStateEx (XINPUT1_3.100)
+ */
+DWORD WINAPI DECLSPEC_HOTPATCH XInputGetStateEx(DWORD index, XINPUT_STATE_EX* state_ex)
+{
+    TRACE("(%d %p)\n", index, state_ex);
+
+    if (index >= XUSER_MAX_COUNT) {
+        return ERROR_BAD_ARGUMENTS;
+    } else if (!devices[index].present) {
+        return ERROR_DEVICE_NOT_CONNECTED;
+    }
+
+    FIXME("stub!\n");
+    return ERROR_NOT_SUPPORTED;
+}
+
+/******************************************************************************
+ *	XInputGetKeystroke (XINPUT1_3.8)
+ */
+DWORD WINAPI XInputGetKeystroke(DWORD dwUserIndex, DWORD dwReserve, PXINPUT_KEYSTROKE pKeystroke)
+{
+    TRACE("(%d %d %p)\n", dwUserIndex, dwReserve, pKeystroke);
+
+    if (dwUserIndex >= XUSER_MAX_COUNT || !pKeystroke) {
+        return ERROR_BAD_ARGUMENTS;
+    } else if (!devices[dwUserIndex].present) {
+        return ERROR_DEVICE_NOT_CONNECTED;
+    }
+
+    FIXME("stub!\n");
+    return ERROR_EMPTY;
+}
+
+/******************************************************************************
+ *	XInputGetCapabilities (XINPUT1_3.4)
+ */
+DWORD WINAPI XInputGetCapabilities(DWORD dwUserIndex, DWORD dwFlags, XINPUT_CAPABILITIES* pCapabilities)
+{
+    TRACE("(%d %d %p)\n", dwUserIndex, dwFlags, pCapabilities);
+
+    if (dwUserIndex >= XUSER_MAX_COUNT || !pCapabilities) {
+        return ERROR_BAD_ARGUMENTS;
+    } else if (!devices[dwUserIndex].present) {
+        return ERROR_DEVICE_NOT_CONNECTED;
+    }
+
+    FIXME("stub!\n");
+    pCapabilities->Type = XINPUT_DEVTYPE_GAMEPAD;
+    pCapabilities->SubType = XINPUT_DEVSUBTYPE_GAMEPAD;
+    pCapabilities->Flags = 0;
+    pCapabilities->Gamepad.wButtons = 0xF3FF;  /* all buttons */
+    pCapabilities->Gamepad.bLeftTrigger = 255;
+    pCapabilities->Gamepad.bRightTrigger = 255;
+    pCapabilities->Gamepad.sThumbLX = -1;
+    pCapabilities->Gamepad.sThumbLY = -1;
+    pCapabilities->Gamepad.sThumbRX = -1;
+    pCapabilities->Gamepad.sThumbRY = -1;
+    pCapabilities->Vibration.wLeftMotorSpeed = 0;
+    pCapabilities->Vibration.wRightMotorSpeed = 0;
+    return ERROR_SUCCESS;
+}
+
+/******************************************************************************
+ *	XInputGetDSoundAudioDeviceGuids (XINPUT1_3.6)
+ */
+DWORD WINAPI XInputGetDSoundAudioDeviceGuids(DWORD dwUserIndex, GUID* pDSoundRenderGuid, GUID* pDSoundCaptureGuid)
+{
+    TRACE("(%d %p %p)\n", dwUserIndex, pDSoundRenderGuid, pDSoundCaptureGuid);
+
+    if (dwUserIndex >= XUSER_MAX_COUNT || !pDSoundRenderGuid || !pDSoundCaptureGuid) {
+        return ERROR_BAD_ARGUMENTS;
+    } else if (!devices[dwUserIndex].present) {
+        return ERROR_DEVICE_NOT_CONNECTED;
+    }
+
+    memcpy(pDSoundRenderGuid, &GUID_NULL, sizeof(GUID));
+    memcpy(pDSoundCaptureGuid, &GUID_NULL, sizeof(GUID));
+    return ERROR_SUCCESS;
+}
+
+/******************************************************************************
+ *	XInputGetBatteryInformation (XINPUT1_3.7)
+ */
+DWORD WINAPI XInputGetBatteryInformation(DWORD dwUserIndex, BYTE deviceType, XINPUT_BATTERY_INFORMATION* pBatteryInfo)
+{
+    TRACE("(%d %u %p)\n", dwUserIndex, deviceType, pBatteryInfo);
+
+    if (dwUserIndex >= XUSER_MAX_COUNT || !pBatteryInfo) {
+        return ERROR_BAD_ARGUMENTS;
+    } else if (!devices[dwUserIndex].present) {
+        return ERROR_DEVICE_NOT_CONNECTED;
+    }
+
+    pBatteryInfo->BatteryType = BATTERY_TYPE_UNKNOWN;
+    return ERROR_SUCCESS;
+}
diff -urN wine-3.0-orig/dlls/xinput1_3/xinput_main.c wine-3.0/dlls/xinput1_3/xinput_main.c
--- wine-3.0-orig/dlls/xinput1_3/xinput_main.c	2018-01-19 00:38:28 +0900
+++ wine-3.0/dlls/xinput1_3/xinput_main.c	2018-01-27 09:22:20 +0900
@@ -27,8 +27,11 @@
 #include "winbase.h"
 #include "winerror.h"
 
+#include "dinput.h"
 #include "xinput.h"
 
+#include "xinput_private.h"
+
 /* Not defined in the headers, used only by XInputGetStateEx */
 #define XINPUT_GAMEPAD_GUIDE 0x0400
 
@@ -45,121 +48,11 @@
     {
     case DLL_PROCESS_ATTACH:
         DisableThreadLibraryCalls(inst);
+        _init_dinput(inst);
+        break;
+    case DLL_PROCESS_DETACH:
+        _close_dinput();
         break;
     }
     return TRUE;
 }
-
-void WINAPI DECLSPEC_HOTPATCH XInputEnable(BOOL enable)
-{
-    /* Setting to false will stop messages from XInputSetState being sent
-    to the controllers. Setting to true will send the last vibration
-    value (sent to XInputSetState) to the controller and allow messages to
-    be sent */
-    FIXME("(enable %d) Stub!\n", enable);
-}
-
-DWORD WINAPI XInputSetState(DWORD index, XINPUT_VIBRATION* vibration)
-{
-    FIXME("(index %u, vibration %p) Stub!\n", index, vibration);
-
-    if (index >= XUSER_MAX_COUNT)
-        return ERROR_BAD_ARGUMENTS;
-    if (!controllers[index].connected)
-        return ERROR_DEVICE_NOT_CONNECTED;
-
-    return ERROR_NOT_SUPPORTED;
-}
-
-DWORD WINAPI DECLSPEC_HOTPATCH XInputGetState(DWORD index, XINPUT_STATE* state)
-{
-    union
-    {
-        XINPUT_STATE state;
-        XINPUT_STATE_EX state_ex;
-    } xinput;
-    DWORD ret;
-    static int warn_once;
-
-    if (!warn_once++)
-        FIXME("(index %u, state %p) Stub!\n", index, state);
-
-    ret = XInputGetStateEx(index, &xinput.state_ex);
-    if (ret != ERROR_SUCCESS)
-        return ret;
-
-    /* The main difference between this and the Ex version is the media guide button */
-    xinput.state.Gamepad.wButtons &= ~XINPUT_GAMEPAD_GUIDE;
-    *state = xinput.state;
-
-    return ERROR_SUCCESS;
-}
-
-DWORD WINAPI DECLSPEC_HOTPATCH XInputGetStateEx(DWORD index, XINPUT_STATE_EX* state_ex)
-{
-    static int warn_once;
-
-    if (!warn_once++)
-        FIXME("(index %u, state %p) Stub!\n", index, state_ex);
-
-    if (index >= XUSER_MAX_COUNT)
-        return ERROR_BAD_ARGUMENTS;
-    if (!controllers[index].connected)
-        return ERROR_DEVICE_NOT_CONNECTED;
-
-    return ERROR_NOT_SUPPORTED;
-}
-
-DWORD WINAPI XInputGetKeystroke(DWORD index, DWORD reserved, PXINPUT_KEYSTROKE keystroke)
-{
-    static int warn_once;
-
-    if (!warn_once++)
-        FIXME("(index %u, reserved %u, keystroke %p) Stub!\n", index, reserved, keystroke);
-
-    if (index >= XUSER_MAX_COUNT)
-        return ERROR_BAD_ARGUMENTS;
-    if (!controllers[index].connected)
-        return ERROR_DEVICE_NOT_CONNECTED;
-
-    return ERROR_NOT_SUPPORTED;
-}
-
-DWORD WINAPI XInputGetCapabilities(DWORD index, DWORD flags, XINPUT_CAPABILITIES* capabilities)
-{
-    static int warn_once;
-
-    if (!warn_once++)
-        FIXME("(index %u, flags 0x%x, capabilities %p) Stub!\n", index, flags, capabilities);
-
-    if (index >= XUSER_MAX_COUNT)
-        return ERROR_BAD_ARGUMENTS;
-    if (!controllers[index].connected)
-        return ERROR_DEVICE_NOT_CONNECTED;
-
-    return ERROR_NOT_SUPPORTED;
-}
-
-DWORD WINAPI XInputGetDSoundAudioDeviceGuids(DWORD index, GUID* render_guid, GUID* capture_guid)
-{
-    FIXME("(index %u, render guid %p, capture guid %p) Stub!\n", index, render_guid, capture_guid);
-
-    if (index >= XUSER_MAX_COUNT)
-        return ERROR_BAD_ARGUMENTS;
-    if (!controllers[index].connected)
-        return ERROR_DEVICE_NOT_CONNECTED;
-
-    return ERROR_NOT_SUPPORTED;
-}
-
-DWORD WINAPI XInputGetBatteryInformation(DWORD index, BYTE type, XINPUT_BATTERY_INFORMATION* battery)
-{
-    FIXME("(index %u, type %u, battery %p) Stub!\n", index, type, battery);
-
-    if (index >= XUSER_MAX_COUNT)
-        return ERROR_BAD_ARGUMENTS;
-    if (!controllers[index].connected)
-        return ERROR_DEVICE_NOT_CONNECTED;
-
-    return ERROR_NOT_SUPPORTED;
-}
diff -urN wine-3.0-orig/dlls/xinput1_3/xinput_private.h wine-3.0/dlls/xinput1_3/xinput_private.h
--- wine-3.0-orig/dlls/xinput1_3/xinput_private.h	1970-01-01 09:00:00 +0900
+++ wine-3.0/dlls/xinput1_3/xinput_private.h	2018-01-27 09:22:20 +0900
@@ -0,0 +1,30 @@
+/*
+ * The Wine project - Xinput Joystick Library
+ * Copyright 2015 Andrew Church
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef __WINE_DLLS_XINPUT1_3_XINPUT_PRIVATE_H
+#define __WINE_DLLS_XINPUT1_3_XINPUT_PRIVATE_H
+
+#include "windef.h"
+#include "winbase.h"
+#include "winerror.h"
+
+extern void _init_dinput(HINSTANCE hInstance) DECLSPEC_HIDDEN;
+extern void _close_dinput(void) DECLSPEC_HIDDEN;
+
+#endif /* __WINE_DLLS_XINPUT1_3_XINPUT_PRIVATE_H */
diff -urN wine-3.0-orig/dlls/xinput1_4/Makefile.in wine-3.0/dlls/xinput1_4/Makefile.in
--- wine-3.0-orig/dlls/xinput1_4/Makefile.in	2018-01-19 00:38:28 +0900
+++ wine-3.0/dlls/xinput1_4/Makefile.in	2018-01-27 09:22:20 +0900
@@ -1,7 +1,9 @@
 MODULE    = xinput1_4.dll
 PARENTSRC = ../xinput1_3
+IMPORTS   = dinput dxguid uuid comctl32 ole32 user32 advapi32
 
 C_SRCS = \
+	dinput_wrapper.c \
 	xinput_main.c
 
 RC_SRCS = version.rc
diff -urN wine-3.0-orig/dlls/xinput9_1_0/Makefile.in wine-3.0/dlls/xinput9_1_0/Makefile.in
--- wine-3.0-orig/dlls/xinput9_1_0/Makefile.in	2018-01-19 00:38:28 +0900
+++ wine-3.0/dlls/xinput9_1_0/Makefile.in	2018-01-27 09:22:20 +0900
@@ -1,7 +1,9 @@
 MODULE    = xinput9_1_0.dll
 PARENTSRC = ../xinput1_3
+IMPORTS   = dinput dxguid uuid comctl32 ole32 user32 advapi32
 
 C_SRCS = \
+	dinput_wrapper.c \
 	xinput_main.c
 
 RC_SRCS = version.rc
