From c451086ea043a9a435d6426bcabd18db92d2f460 Mon Sep 17 00:00:00 2001 From: emoose Date: Sat, 22 Feb 2020 15:49:09 +0000 Subject: [PATCH] Add guide button emulation + vibration toggle option, & apply timeout to interrupt transfers --- README.md | 12 ++++++++++ Xb2XInput/Xb2XInput.cpp | 24 +++++++++++++++++-- Xb2XInput/Xb2XInput.rc | Bin 6452 -> 6452 bytes Xb2XInput/XboxController.cpp | 44 ++++++++++++++++++++++++++++------- 4 files changed, 69 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index f8a5fa3..f447555 100644 --- a/README.md +++ b/README.md @@ -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. diff --git a/Xb2XInput/Xb2XInput.cpp b/Xb2XInput/Xb2XInput.cpp index d5889ee..db7dca3 100644 --- a/Xb2XInput/Xb2XInput.cpp +++ b/Xb2XInput/Xb2XInput.cpp @@ -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; @@ -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]; @@ -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"); @@ -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); } @@ -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 diff --git a/Xb2XInput/Xb2XInput.rc b/Xb2XInput/Xb2XInput.rc index 1da05c52732482206519c90ec914d5a8dc8e942e..440a8aa6ac237fc84d82836720d511783102b1c6 100644 GIT binary patch delta 50 zcmdmDw8dz{Cw@kw$)EWR8I3lp3S4GlHDb_XFqrHpq`O&5_!c9aE52DlRD=ZplBx}C delta 50 zcmdmDw8dz{Cw@l5$)EWR84Wk93S4GlHDu6ZFqrHpq`O&5_!c9aE52DlRD=Zpk}(Zv diff --git a/Xb2XInput/XboxController.cpp b/Xb2XInput/XboxController.cpp index cdcad32..005f6b0 100644 --- a/Xb2XInput/XboxController.cpp +++ b/Xb2XInput/XboxController.cpp @@ -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??? @@ -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 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)) @@ -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;