Skip to content

Commit

Permalink
Add guide button emulation + vibration toggle option, & apply timeout…
Browse files Browse the repository at this point in the history
… to interrupt transfers
  • Loading branch information
emoose committed Feb 22, 2020
1 parent 37aa744 commit c451086
Show file tree
Hide file tree
Showing 4 changed files with 69 additions and 11 deletions.
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,18 @@ Similarly, unplugging a controller will show a notification about the controller
#### Viewing status
To view the status of Xb2XInput just hover over the icon, any details about connected devices should be shown in the tooltip (if tooltip doesn't appear, click the icon instead)

#### Guide button emulation
Sadly the Xbox OG controller doesn't contain the guide button usually found on XInput devices. However as of Xb2XInput v1.3.2 this button can now be emulated, through the use of the LT+RT+LS+RS button combination.

By default this button combination will be enabled, but if desired you can easily disable it through the system tray menu, in case it interferes with something else you need the combination for.

(right now you'll have to disable the combination manually each time XB2X is ran, but hopefully in future we can store your preference somewhere instead)

#### Vibration toggle
In case you wish to disable your controllers vibration function, eg. if a game has issues with it, or your controller has problems with the motors, you can also do this through the context-menu.

(As with the guide button emulation toggle above, your choice isn't saved yet unfortunately, so you will have to disable it manually each time XB2X is ran)

#### Run on startup
To run Xb2XInput on startup just click the icon and choose the "Run on startup" option, a registry entry will be made for Xb2XInput to be ran from it's current path.
If you move the Xb2XInput exe (and associated dlls) make sure to choose the "Run on startup" option again to update the startup path.
Expand Down
24 changes: 22 additions & 2 deletions Xb2XInput/Xb2XInput.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,15 @@
// how many times to check the USB device each second, must be 1000 or lower, higher value = higher CPU usage
// 144 seems a good value, i don't really know anyone that uses a higher refresh rate than that...
// TODO: make this configurable?
int poll_rate = 144;
const int poll_rate = 144;

int poll_ms = (1000 / min(1000, poll_rate));

// LT + RT + LS + RS to emulate guide button
bool guideCombinationEnabled = true;

// Vibration support
bool vibrationEnabled = true;

WCHAR title[256];
bool usb_end = false;
Expand Down Expand Up @@ -109,6 +117,8 @@ bool StartupDeleteEntry()
#define ID_TRAY_SEP 5003
#define ID_TRAY_EXIT 5004
#define ID_TRAY_CONTROLLER 5006
#define ID_TRAY_GUIDEBTN 5007
#define ID_TRAY_VIBING 5008

WCHAR tray_text[128];

Expand Down Expand Up @@ -159,6 +169,10 @@ void SysTrayShowContextMenu()
}

InsertMenu(hPopMenu, 0xFFFFFFFF, MF_SEPARATOR, ID_TRAY_SEP, L"SEP");
InsertMenu(hPopMenu, 0xFFFFFFFF, MF_BYPOSITION | MF_STRING |
(guideCombinationEnabled ? MF_CHECKED : MF_UNCHECKED), ID_TRAY_GUIDEBTN, L"Enable guide button combination (LT+RT+LS+RS)");
InsertMenu(hPopMenu, 0xFFFFFFFF, MF_BYPOSITION | MF_STRING |
(vibrationEnabled ? MF_CHECKED : MF_UNCHECKED), ID_TRAY_VIBING, L"Enable controller vibration");
InsertMenu(hPopMenu, 0xFFFFFFFF, MF_BYPOSITION | MF_STRING |
(StartupIsSet() ? MF_CHECKED : MF_UNCHECKED), ID_TRAY_STARTUP, L"Run on startup");
InsertMenu(hPopMenu, 0xFFFFFFFF, MF_SEPARATOR, ID_TRAY_SEP, L"SEP");
Expand Down Expand Up @@ -194,6 +208,12 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
else
StartupCreateEntry();
break;
case ID_TRAY_GUIDEBTN:
guideCombinationEnabled = !guideCombinationEnabled;
break;
case ID_TRAY_VIBING:
vibrationEnabled = !vibrationEnabled;
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
Expand Down Expand Up @@ -294,7 +314,7 @@ void USBUpdateThread()
Sleep(500); // sleep for a bit so we don't hammer the CPU

XboxController::UpdateAll();
Sleep(1000 / min(1000, poll_rate));
Sleep(poll_ms);
}
}
#pragma endregion
Expand Down
Binary file modified Xb2XInput/Xb2XInput.rc
Binary file not shown.
44 changes: 35 additions & 9 deletions Xb2XInput/XboxController.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,12 @@ void CALLBACK XboxController::OnVigemNotification(PVIGEM_CLIENT Client, PVIGEM_T
if (controller.target_ != Target)
continue;

extern bool vibrationEnabled;
if (!vibrationEnabled)
{
LargeMotor = SmallMotor = 0;
}

memset(&controller.output_prev_, 0, sizeof(XboxOutputReport));
controller.output_prev_.bSize = sizeof(XboxOutputReport);
controller.output_prev_.Rumble.wLeftMotorSpeed = _byteswap_ushort(LargeMotor); // why do these need to be byteswapped???
Expand Down Expand Up @@ -326,25 +332,30 @@ bool XboxController::update()
if (closing_)
return true;

// if we have interrupt endpoints use those for better compatibility, otherwise fallback to control transfers
memset(&input_prev_, 0, sizeof(XboxInputReport));
int length = 0;
int ret = -1;

if (endpoint_in_)
ret = libusb_interrupt_transfer(usb_handle_, endpoint_in_, (unsigned char*)&input_prev_, sizeof(XboxInputReport), &length, 0);

if (ret < 0)
// if we have interrupt endpoints use those for better compatibility, otherwise fallback to control transfers
if (endpoint_in_)
{
extern int poll_ms;
ret = libusb_interrupt_transfer(usb_handle_, endpoint_in_, (unsigned char*)&input_prev_, sizeof(XboxInputReport), &length, poll_ms);
if (ret < 0)
return true; // No input available atm
}
else
{
std::lock_guard<std::mutex> guard(usb_mutex_);
ret = libusb_control_transfer(usb_handle_, LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE,
HID_GET_REPORT, (HID_REPORT_TYPE_INPUT << 8) | 0x00, 0, (unsigned char*)&input_prev_, sizeof(XboxInputReport), 1000);
}

if (ret < 0)
{
dbgprintf(__FUNCTION__ ": libusb transfer failed (code %d)", ret);
return false;
if (ret < 0)
{
dbgprintf(__FUNCTION__ ": libusb control transfer failed (code %d)", ret);
return false;
}
}

if (input_prev_.bSize != sizeof(XboxInputReport))
Expand All @@ -370,6 +381,21 @@ bool XboxController::update()
gamepad_.bLeftTrigger = input_prev_.Gamepad.bAnalogButtons[OGXINPUT_GAMEPAD_LEFT_TRIGGER];
gamepad_.bRightTrigger = input_prev_.Gamepad.bAnalogButtons[OGXINPUT_GAMEPAD_RIGHT_TRIGGER];

// Secret guide combination: LT + RT + LS + RS
extern bool guideCombinationEnabled;
if(guideCombinationEnabled)
if ((input_prev_.Gamepad.wButtons & OGXINPUT_GAMEPAD_LEFT_THUMB) && (input_prev_.Gamepad.wButtons & OGXINPUT_GAMEPAD_RIGHT_THUMB) &&
(gamepad_.bLeftTrigger >= 0x8) && (gamepad_.bRightTrigger >= 0x8))
{
gamepad_.wButtons |= XUSB_GAMEPAD_GUIDE;

// Clear combination from the emulated pad, don't want it to interfere with guide:
gamepad_.wButtons &= ~XUSB_GAMEPAD_LEFT_THUMB;
gamepad_.wButtons &= ~XUSB_GAMEPAD_RIGHT_THUMB;
gamepad_.bLeftTrigger = 0;
gamepad_.bRightTrigger = 0;
}

gamepad_.sThumbLX = input_prev_.Gamepad.sThumbLX;
gamepad_.sThumbLY = input_prev_.Gamepad.sThumbLY;
gamepad_.sThumbRX = input_prev_.Gamepad.sThumbRX;
Expand Down

0 comments on commit c451086

Please sign in to comment.