Skip to content

Commit

Permalink
Merge pull request #10 from grayver/hid-hide
Browse files Browse the repository at this point in the history
HidHide integration
  • Loading branch information
grayver authored Jul 18, 2022
2 parents 7661474 + 6d1a551 commit 670e9b1
Show file tree
Hide file tree
Showing 15 changed files with 1,420 additions and 769 deletions.
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@ XBox360 emulation driver is provided by ViGEm (https://github.com/ViGEm/ViGEmBus
Mi-ViGEm program at start scans for Xiaomi Gamepad devices and then proxies found Xiaomi gamepads to virtual XBox360 gamepads (with help of ViGEmBus). Also Mi-ViGEm subscribes to system device plug/unplug notifications and rescan devices on each notification.
All found devices are displayed in tray icon context menu (along with their battery level). Manual device rescan can be initiated via tray icon context menu.

## Double input problem
Mi-ViGEm doesn't replace Xiaomi gamepad with XBox360 gamepad, it just creates virtual XBox360 gamepad in parallel, so both gamepads are presented in OS. This causes problems in some games, which read input from both real and virtual gamepads. There is nothing to do with that on user application level, only kernel level driver can help. Fortunately, ViGEm developed HidHide driver which deals with that problem (can be downloaded [here](https://github.com/ViGEm/HidHide/releases)).

Mi-ViGEm provides integration with HidHide driver since version 1.2. It automatically detects HidHide presence and makes necessary changes in white and black lists. You only need to install HidHide (reboot is required) and run Mi-ViGEm.

## Thanks to

This project is inspired by following projects written on C#:
Expand Down
407 changes: 188 additions & 219 deletions include/ViGEm/Client.h

Large diffs are not rendered by default.

62 changes: 56 additions & 6 deletions include/ViGEm/Common.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,15 +33,11 @@ typedef enum _VIGEM_TARGET_TYPE
//
// Microsoft Xbox 360 Controller (wired)
//
Xbox360Wired,
//
// Microsoft Xbox One Controller (wired)
//
XboxOneWired,
Xbox360Wired = 0,
//
// Sony DualShock 4 (wired)
//
DualShock4Wired
DualShock4Wired = 2 // NOTE: 1 skipped on purpose to maintain compatibility

} VIGEM_TARGET_TYPE, *PVIGEM_TARGET_TYPE;

Expand Down Expand Up @@ -204,3 +200,57 @@ VOID FORCEINLINE DS4_REPORT_INIT(
DS4_SET_DPAD(Report, DS4_BUTTON_DPAD_NONE);
}

#include <pshpack1.h> // pack structs tightly
//
// DualShock 4 HID Touchpad structure
//
typedef struct _DS4_TOUCH
{
BYTE bPacketCounter; // timestamp / packet counter associated with touch event
BYTE bIsUpTrackingNum1; // 0 means down; active low
// unique to each finger down, so for a lift and repress the value is incremented
BYTE bTouchData1[3]; // Two 12 bits values (for X and Y)
// middle byte holds last 4 bits of X and the starting 4 bits of Y
BYTE bIsUpTrackingNum2; // second touch data immediately follows data of first touch
BYTE bTouchData2[3]; // resolution is 1920x943
} DS4_TOUCH, * PDS4_TOUCH;

//
// DualShock 4 v1 complete HID Input report
//
typedef struct _DS4_REPORT_EX
{
union
{
struct
{
BYTE bThumbLX;
BYTE bThumbLY;
BYTE bThumbRX;
BYTE bThumbRY;
USHORT wButtons;
BYTE bSpecial;
BYTE bTriggerL;
BYTE bTriggerR;
USHORT wTimestamp;
BYTE bBatteryLvl;
SHORT wGyroX;
SHORT wGyroY;
SHORT wGyroZ;
SHORT wAccelX;
SHORT wAccelY;
SHORT wAccelZ;
BYTE _bUnknown1[5];
BYTE bBatteryLvlSpecial;
// really should have a enum to show everything that this can represent (USB charging, battery level; EXT, headset, microphone connected)
BYTE _bUnknown2[2];
BYTE bTouchPacketsN; // 0x00 to 0x03 (USB max)
DS4_TOUCH sCurrentTouch;
DS4_TOUCH sPreviousTouch[2];
} Report;

UCHAR ReportBuffer[63];
};
} DS4_REPORT_EX, *PDS4_REPORT_EX;

#include <poppack.h>
115 changes: 42 additions & 73 deletions include/ViGEm/km/BusShared.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,13 +62,14 @@ DEFINE_GUID(GUID_DEVINTERFACE_BUSENUM_VIGEM,
#define IOCTL_VIGEM_PLUGIN_TARGET BUSENUM_W_IOCTL (IOCTL_VIGEM_BASE + 0x000)
#define IOCTL_VIGEM_UNPLUG_TARGET BUSENUM_W_IOCTL (IOCTL_VIGEM_BASE + 0x001)
#define IOCTL_VIGEM_CHECK_VERSION BUSENUM_W_IOCTL (IOCTL_VIGEM_BASE + 0x002)
#define IOCTL_VIGEM_WAIT_DEVICE_READY BUSENUM_W_IOCTL (IOCTL_VIGEM_BASE + 0x003)

#define IOCTL_XUSB_REQUEST_NOTIFICATION BUSENUM_RW_IOCTL(IOCTL_VIGEM_BASE + 0x200)
#define IOCTL_XUSB_SUBMIT_REPORT BUSENUM_W_IOCTL (IOCTL_VIGEM_BASE + 0x201)
#define IOCTL_DS4_SUBMIT_REPORT BUSENUM_W_IOCTL (IOCTL_VIGEM_BASE + 0x202)
#define IOCTL_DS4_REQUEST_NOTIFICATION BUSENUM_W_IOCTL (IOCTL_VIGEM_BASE + 0x203)
#define IOCTL_XGIP_SUBMIT_REPORT BUSENUM_W_IOCTL (IOCTL_VIGEM_BASE + 0x204)
#define IOCTL_XGIP_SUBMIT_INTERRUPT BUSENUM_W_IOCTL (IOCTL_VIGEM_BASE + 0x205)
//#define IOCTL_XGIP_SUBMIT_REPORT BUSENUM_W_IOCTL (IOCTL_VIGEM_BASE + 0x204)
//#define IOCTL_XGIP_SUBMIT_INTERRUPT BUSENUM_W_IOCTL (IOCTL_VIGEM_BASE + 0x205)
#define IOCTL_XUSB_GET_USER_INDEX BUSENUM_RW_IOCTL(IOCTL_VIGEM_BASE + 0x206)


Expand Down Expand Up @@ -184,6 +185,29 @@ VOID FORCEINLINE VIGEM_CHECK_VERSION_INIT(
CheckVersion->Version = Version;
}

#pragma endregion

#pragma region Wait device ready

typedef struct _VIGEM_WAIT_DEVICE_READY
{
IN ULONG Size;

IN ULONG SerialNo;

} VIGEM_WAIT_DEVICE_READY, * PVIGEM_WAIT_DEVICE_READY;

VOID FORCEINLINE VIGEM_WAIT_DEVICE_READY_INIT(
_Out_ PVIGEM_WAIT_DEVICE_READY WaitReady,
_In_ ULONG SerialNo
)
{
RtlZeroMemory(WaitReady, sizeof(VIGEM_WAIT_DEVICE_READY));

WaitReady->Size = sizeof(VIGEM_WAIT_DEVICE_READY);
WaitReady->SerialNo = SerialNo;
}

#pragma endregion

#pragma region XUSB (aka Xbox 360 device) section
Expand Down Expand Up @@ -400,99 +424,44 @@ VOID FORCEINLINE DS4_SUBMIT_REPORT_INIT(
DS4_REPORT_INIT(&Report->Report);
}

#pragma endregion

#pragma region XGIP (aka Xbox One device) section - EXPERIMENTAL

typedef struct _XGIP_REPORT
{
UCHAR Buttons1;
UCHAR Buttons2;
SHORT LeftTrigger;
SHORT RightTrigger;
SHORT ThumbLX;
SHORT ThumbLY;
SHORT ThumbRX;
SHORT ThumbRY;

} XGIP_REPORT, *PXGIP_REPORT;

//
// Xbox One request data
//
typedef struct _XGIP_SUBMIT_REPORT
{
//
// sizeof(struct _XGIP_SUBMIT_REPORT)
//
ULONG Size;

//
// Serial number of target device.
//
ULONG SerialNo;

//
// HID Input report
//
XGIP_REPORT Report;

} XGIP_SUBMIT_REPORT, *PXGIP_SUBMIT_REPORT;

//
// Initializes an Xbox One report.
//
VOID FORCEINLINE XGIP_SUBMIT_REPORT_INIT(
_Out_ PXGIP_SUBMIT_REPORT Report,
_In_ ULONG SerialNo
)
{
RtlZeroMemory(Report, sizeof(XGIP_SUBMIT_REPORT));

Report->Size = sizeof(XGIP_SUBMIT_REPORT);
Report->SerialNo = SerialNo;
}
#include <pshpack1.h>

//
// Xbox One interrupt data
// DualShock 4 extended report request
//
typedef struct _XGIP_SUBMIT_INTERRUPT
typedef struct _DS4_SUBMIT_REPORT_EX
{
//
// sizeof(struct _XGIP_SUBMIT_INTERRUPT)
//
ULONG Size;
// sizeof(struct _DS4_SUBMIT_REPORT_EX)
//
_In_ ULONG Size;

//
// Serial number of target device.
//
ULONG SerialNo;
_In_ ULONG SerialNo;

//
// Interrupt buffer.
// Full size HID report excluding fixed Report ID.
//
UCHAR Interrupt[64];
_In_ DS4_REPORT_EX Report;

//
// Length of interrupt buffer.
//
ULONG InterruptLength;
} DS4_SUBMIT_REPORT_EX, * PDS4_SUBMIT_REPORT_EX;

} XGIP_SUBMIT_INTERRUPT, *PXGIP_SUBMIT_INTERRUPT;
#include <poppack.h>

//
// Initializes an Xbox One interrupt.
// Initializes a DualShock 4 extended report.
//
VOID FORCEINLINE XGIP_SUBMIT_INTERRUPT_INIT(
_Out_ PXGIP_SUBMIT_INTERRUPT Report,
VOID FORCEINLINE DS4_SUBMIT_REPORT_EX_INIT(
_Out_ PDS4_SUBMIT_REPORT_EX Report,
_In_ ULONG SerialNo
)
{
RtlZeroMemory(Report, sizeof(XGIP_SUBMIT_INTERRUPT));
RtlZeroMemory(Report, sizeof(DS4_SUBMIT_REPORT_EX));

Report->Size = sizeof(XGIP_SUBMIT_INTERRUPT);
Report->Size = sizeof(DS4_SUBMIT_REPORT_EX);
Report->SerialNo = SerialNo;
}

#pragma endregion

3 changes: 1 addition & 2 deletions lib/ViGEmClient/Internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,7 @@ typedef struct _VIGEM_TARGET_T
VIGEM_TARGET_TYPE Type;
FARPROC Notification;
LPVOID NotificationUserData;
BOOLEAN IsWaitReadyUnsupported;

bool closingNotificationThreads;
HANDLE cancelNotificationThreadEvent;
std::unique_ptr<std::vector<std::thread>> notificationThreadList;
} VIGEM_TARGET;
Loading

0 comments on commit 670e9b1

Please sign in to comment.