Skip to content

Commit c451086

Browse files
committed
Add guide button emulation + vibration toggle option, & apply timeout to interrupt transfers
1 parent 37aa744 commit c451086

File tree

4 files changed

+69
-11
lines changed

4 files changed

+69
-11
lines changed

README.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,18 @@ Similarly, unplugging a controller will show a notification about the controller
4848
#### Viewing status
4949
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)
5050

51+
#### Guide button emulation
52+
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.
53+
54+
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.
55+
56+
(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)
57+
58+
#### Vibration toggle
59+
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.
60+
61+
(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)
62+
5163
#### Run on startup
5264
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.
5365
If you move the Xb2XInput exe (and associated dlls) make sure to choose the "Run on startup" option again to update the startup path.

Xb2XInput/Xb2XInput.cpp

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,15 @@
88
// how many times to check the USB device each second, must be 1000 or lower, higher value = higher CPU usage
99
// 144 seems a good value, i don't really know anyone that uses a higher refresh rate than that...
1010
// TODO: make this configurable?
11-
int poll_rate = 144;
11+
const int poll_rate = 144;
12+
13+
int poll_ms = (1000 / min(1000, poll_rate));
14+
15+
// LT + RT + LS + RS to emulate guide button
16+
bool guideCombinationEnabled = true;
17+
18+
// Vibration support
19+
bool vibrationEnabled = true;
1220

1321
WCHAR title[256];
1422
bool usb_end = false;
@@ -109,6 +117,8 @@ bool StartupDeleteEntry()
109117
#define ID_TRAY_SEP 5003
110118
#define ID_TRAY_EXIT 5004
111119
#define ID_TRAY_CONTROLLER 5006
120+
#define ID_TRAY_GUIDEBTN 5007
121+
#define ID_TRAY_VIBING 5008
112122

113123
WCHAR tray_text[128];
114124

@@ -159,6 +169,10 @@ void SysTrayShowContextMenu()
159169
}
160170

161171
InsertMenu(hPopMenu, 0xFFFFFFFF, MF_SEPARATOR, ID_TRAY_SEP, L"SEP");
172+
InsertMenu(hPopMenu, 0xFFFFFFFF, MF_BYPOSITION | MF_STRING |
173+
(guideCombinationEnabled ? MF_CHECKED : MF_UNCHECKED), ID_TRAY_GUIDEBTN, L"Enable guide button combination (LT+RT+LS+RS)");
174+
InsertMenu(hPopMenu, 0xFFFFFFFF, MF_BYPOSITION | MF_STRING |
175+
(vibrationEnabled ? MF_CHECKED : MF_UNCHECKED), ID_TRAY_VIBING, L"Enable controller vibration");
162176
InsertMenu(hPopMenu, 0xFFFFFFFF, MF_BYPOSITION | MF_STRING |
163177
(StartupIsSet() ? MF_CHECKED : MF_UNCHECKED), ID_TRAY_STARTUP, L"Run on startup");
164178
InsertMenu(hPopMenu, 0xFFFFFFFF, MF_SEPARATOR, ID_TRAY_SEP, L"SEP");
@@ -194,6 +208,12 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
194208
else
195209
StartupCreateEntry();
196210
break;
211+
case ID_TRAY_GUIDEBTN:
212+
guideCombinationEnabled = !guideCombinationEnabled;
213+
break;
214+
case ID_TRAY_VIBING:
215+
vibrationEnabled = !vibrationEnabled;
216+
break;
197217
default:
198218
return DefWindowProc(hWnd, message, wParam, lParam);
199219
}
@@ -294,7 +314,7 @@ void USBUpdateThread()
294314
Sleep(500); // sleep for a bit so we don't hammer the CPU
295315

296316
XboxController::UpdateAll();
297-
Sleep(1000 / min(1000, poll_rate));
317+
Sleep(poll_ms);
298318
}
299319
}
300320
#pragma endregion

Xb2XInput/Xb2XInput.rc

0 Bytes
Binary file not shown.

Xb2XInput/XboxController.cpp

Lines changed: 35 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,12 @@ void CALLBACK XboxController::OnVigemNotification(PVIGEM_CLIENT Client, PVIGEM_T
273273
if (controller.target_ != Target)
274274
continue;
275275

276+
extern bool vibrationEnabled;
277+
if (!vibrationEnabled)
278+
{
279+
LargeMotor = SmallMotor = 0;
280+
}
281+
276282
memset(&controller.output_prev_, 0, sizeof(XboxOutputReport));
277283
controller.output_prev_.bSize = sizeof(XboxOutputReport);
278284
controller.output_prev_.Rumble.wLeftMotorSpeed = _byteswap_ushort(LargeMotor); // why do these need to be byteswapped???
@@ -326,25 +332,30 @@ bool XboxController::update()
326332
if (closing_)
327333
return true;
328334

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

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

337-
if (ret < 0)
340+
// if we have interrupt endpoints use those for better compatibility, otherwise fallback to control transfers
341+
if (endpoint_in_)
342+
{
343+
extern int poll_ms;
344+
ret = libusb_interrupt_transfer(usb_handle_, endpoint_in_, (unsigned char*)&input_prev_, sizeof(XboxInputReport), &length, poll_ms);
345+
if (ret < 0)
346+
return true; // No input available atm
347+
}
348+
else
338349
{
339350
std::lock_guard<std::mutex> guard(usb_mutex_);
340351
ret = libusb_control_transfer(usb_handle_, LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE,
341352
HID_GET_REPORT, (HID_REPORT_TYPE_INPUT << 8) | 0x00, 0, (unsigned char*)&input_prev_, sizeof(XboxInputReport), 1000);
342-
}
343353

344-
if (ret < 0)
345-
{
346-
dbgprintf(__FUNCTION__ ": libusb transfer failed (code %d)", ret);
347-
return false;
354+
if (ret < 0)
355+
{
356+
dbgprintf(__FUNCTION__ ": libusb control transfer failed (code %d)", ret);
357+
return false;
358+
}
348359
}
349360

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

384+
// Secret guide combination: LT + RT + LS + RS
385+
extern bool guideCombinationEnabled;
386+
if(guideCombinationEnabled)
387+
if ((input_prev_.Gamepad.wButtons & OGXINPUT_GAMEPAD_LEFT_THUMB) && (input_prev_.Gamepad.wButtons & OGXINPUT_GAMEPAD_RIGHT_THUMB) &&
388+
(gamepad_.bLeftTrigger >= 0x8) && (gamepad_.bRightTrigger >= 0x8))
389+
{
390+
gamepad_.wButtons |= XUSB_GAMEPAD_GUIDE;
391+
392+
// Clear combination from the emulated pad, don't want it to interfere with guide:
393+
gamepad_.wButtons &= ~XUSB_GAMEPAD_LEFT_THUMB;
394+
gamepad_.wButtons &= ~XUSB_GAMEPAD_RIGHT_THUMB;
395+
gamepad_.bLeftTrigger = 0;
396+
gamepad_.bRightTrigger = 0;
397+
}
398+
373399
gamepad_.sThumbLX = input_prev_.Gamepad.sThumbLX;
374400
gamepad_.sThumbLY = input_prev_.Gamepad.sThumbLY;
375401
gamepad_.sThumbRX = input_prev_.Gamepad.sThumbRX;

0 commit comments

Comments
 (0)