Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added Deadzone Functionality #16

Merged
merged 4 commits into from
Jul 5, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,11 @@ By default this button combination will be enabled, but if desired you can easil

(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)

#### Deadzone settings
Similarly to the Guide button emulation, use the LT+RT+(LS/RS)+DPAD Up/Dn combinaiton for analog stick deadzone and (LT/RT)+LS+RS+DPAD Up/Dn for trigger deadzone adjustment. The deadzone may be set individually on each controller. The current deadzones will be displayed in the context menu each time it is displayed (not live updating). For example, to increase the left analog stick deadzone radius use the button combination LT+RT+LS+DPAD Up (Keep pressing DPAD Up while holding LT+RT+LS to increase by increments of 500). A setting of 3500-4000 works well on my XBOX Controller v2 (US), but ymmv. Xb2XInput does remap the remaining useable range of the axes from origin to max extent. To disable the deadzone button combination, deselect the option through the system tray menu. The deadzone will remain active if the button combination is disabled.

(right now you'll have to set the deadzone 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.

Expand Down
23 changes: 22 additions & 1 deletion Xb2XInput/Xb2XInput.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ int poll_ms = (1000 / min(1000, poll_rate));
// LT + RT + LS + RS to emulate guide button
bool guideCombinationEnabled = true;

// Analog Stick and Trigger Deadzone Adjustment Enabled
bool deadzoneCombinationEnabled = true;

// Vibration support
bool vibrationEnabled = true;

Expand Down Expand Up @@ -119,6 +122,7 @@ bool StartupDeleteEntry()
#define ID_TRAY_CONTROLLER 5006
#define ID_TRAY_GUIDEBTN 5007
#define ID_TRAY_VIBING 5008
#define ID_TRAY_DEADZONE 5100

WCHAR tray_text[128];

Expand Down Expand Up @@ -167,10 +171,24 @@ void SysTrayShowContextMenu()
InsertMenu(hPopMenu, 0xFFFFFFFF, MF_BYPOSITION | MF_STRING | MF_GRAYED, ID_TRAY_CONTROLLER + i, ctl_text);
i++;
}

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 |
(deadzoneCombinationEnabled ? MF_CHECKED : MF_UNCHECKED), ID_TRAY_DEADZONE, L"Enable Deadzone Adjustment:");
InsertMenu(hPopMenu, 0xFFFFFFFF, MF_BYPOSITION | MF_STRING | MF_GRAYED | MF_UNCHECKED, ID_TRAY_DEADZONE, L" - Analog Stick (LT+RT+(LS/RS)+DPAD Up/Dn)");
InsertMenu(hPopMenu, 0xFFFFFFFF, MF_BYPOSITION | MF_STRING | MF_GRAYED | MF_UNCHECKED, ID_TRAY_DEADZONE, L" - Trigger ((LT/RT)+LS+RS+DPAD Up/Dn)");

// Insert current deadzone adjustments into context menu
i = 0;
for (auto& controller : pads) {
i++;
auto dz = controller.GetDeadzone();
swprintf_s(ctl_text, L"Deadzone %d: LS(%d) RS(%d) LT(%d) RT(%d)",i, dz.sThumbL, dz.sThumbR, dz.bLeftTrigger, dz.bRightTrigger);
InsertMenu(hPopMenu, 0xFFFFFFFF, MF_BYPOSITION | MF_STRING | MF_GRAYED, ID_TRAY_DEADZONE+i, ctl_text);
}

InsertMenu(hPopMenu, 0xFFFFFFFF, MF_SEPARATOR, ID_TRAY_SEP, L"SEP");
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 |
Expand Down Expand Up @@ -211,6 +229,9 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
case ID_TRAY_GUIDEBTN:
guideCombinationEnabled = !guideCombinationEnabled;
break;
case ID_TRAY_DEADZONE:
deadzoneCombinationEnabled = !deadzoneCombinationEnabled;
break;
case ID_TRAY_VIBING:
vibrationEnabled = !vibrationEnabled;
break;
Expand Down
127 changes: 114 additions & 13 deletions Xb2XInput/XboxController.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -107,8 +107,8 @@ libusb_device_handle* XboxController::OpenDevice()
if (exists)
continue;

ret = libusb_open_device_with_vid_pid(NULL, desc.idVendor, desc.idProduct);
if (!ret)
// open USB device by libusb_device* returned from device list
if (libusb_open(devs[i],&ret))
continue;

auto controller = XboxController(ret, (uint8_t*)&usb_ports, num_ports);
Expand Down Expand Up @@ -304,6 +304,56 @@ int XboxController::GetUserIndex() {
return -1;
}

int XboxController::deadZoneCalc(short *x_out, short *y_out, short x, short y, short deadzone, short sickzone){
// Returns 0 if in deadzone, 1 in sickzone, 2 if passthrough.

// Protect from NULL input pointers (used for 1-D deadzone)
short dummyvar;
if (!x_out){
x_out = &dummyvar;
}
if (!y_out){
y_out = &dummyvar;
}

short status;

// If no deadzone, pass directly through.
if (deadzone == 0){
*x_out = x;
*y_out = y;
return 2;
}

// convert to polar coordinates
int r_in = sqrt(pow(x,2)+pow(y,2));
short r_sign = (y >= 0 ? 1 : -1); // For negative Y-axis cartesian coordinates
float theta = acos((float)x/fmax(1.0,r_in));
int r_out;

// Return origin if in Deadzone
if (r_in < deadzone){
status = 0;
r_out = 0;
}

// Scale to full range over "sickzone" for precision near deadzone
// this way output doesn't jump from 0,0 to deadzone limit.
else if (r_in < sickzone){
status = 1;
r_out = (float)(r_in - deadzone) / (float)(sickzone - deadzone) * sickzone;
} else {
status = 2;
r_out = r_in;
}

// Convert back to cartesian coordinates for x,y output
*x_out = r_out*cos(theta);
*y_out = r_sign*r_out*sin(theta);

return status;
}

// XboxController::Update: returns false if controller disconnected
bool XboxController::update()
{
Expand Down Expand Up @@ -377,32 +427,83 @@ bool XboxController::update()
gamepad_.wButtons |= input_prev_.Gamepad.bAnalogButtons[OGXINPUT_GAMEPAD_WHITE] ? XUSB_GAMEPAD_LEFT_SHOULDER : 0;
gamepad_.wButtons |= input_prev_.Gamepad.bAnalogButtons[OGXINPUT_GAMEPAD_BLACK] ? XUSB_GAMEPAD_RIGHT_SHOULDER : 0;

// Copy over remaining analog values
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))
(input_prev_.Gamepad.bAnalogButtons[OGXINPUT_GAMEPAD_LEFT_TRIGGER] >= 0x8) && (input_prev_.Gamepad.bAnalogButtons[OGXINPUT_GAMEPAD_RIGHT_TRIGGER] >= 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;
input_prev_.Gamepad.bAnalogButtons[OGXINPUT_GAMEPAD_LEFT_TRIGGER] = 0;
input_prev_.Gamepad.bAnalogButtons[OGXINPUT_GAMEPAD_RIGHT_TRIGGER] = 0;
}

gamepad_.sThumbLX = input_prev_.Gamepad.sThumbLX;
gamepad_.sThumbLY = input_prev_.Gamepad.sThumbLY;
gamepad_.sThumbRX = input_prev_.Gamepad.sThumbRX;
gamepad_.sThumbRY = input_prev_.Gamepad.sThumbRY;
// Secret Deadzone Adjustment Combinations:
extern bool deadzoneCombinationEnabled;
if(deadzoneCombinationEnabled){

// Analog Stick Deadzone Adjustment: LT + RT + (LS | RS) + D-Pad Up/Down
if ((input_prev_.Gamepad.wButtons & OGXINPUT_GAMEPAD_LEFT_THUMB) ^ (input_prev_.Gamepad.wButtons & OGXINPUT_GAMEPAD_RIGHT_THUMB) && // // (LS XOR RS) AND
((input_prev_.Gamepad.bAnalogButtons[OGXINPUT_GAMEPAD_LEFT_TRIGGER] >= 0x8) && (input_prev_.Gamepad.bAnalogButtons[OGXINPUT_GAMEPAD_RIGHT_TRIGGER] >= 0x8)) && // Left and Right Trigger AND
(input_prev_.Gamepad.wButtons & (OGXINPUT_GAMEPAD_DPAD_UP | OGXINPUT_GAMEPAD_DPAD_DOWN))) // Direction to change deadzone
{
// wait for previous deadzone adjustment button release
if (!deadzone_.hold){
short adjustment = (input_prev_.Gamepad.wButtons & OGXINPUT_GAMEPAD_DPAD_UP ? 500 : -500);

if (input_prev_.Gamepad.wButtons & OGXINPUT_GAMEPAD_LEFT_THUMB){
deadzone_.sThumbL = min(max(deadzone_.sThumbL+adjustment,0), SHRT_MAX);
}
if (input_prev_.Gamepad.wButtons & OGXINPUT_GAMEPAD_RIGHT_THUMB){
deadzone_.sThumbR = min(max(deadzone_.sThumbR+adjustment,0), SHRT_MAX);
}

// wait for button release
deadzone_.hold = true;
}

// Trigger Deadzone Adjustment: (LT | RT) + LS + RS + D-Pad Up/Down
} else if ((input_prev_.Gamepad.wButtons & OGXINPUT_GAMEPAD_LEFT_THUMB) && (input_prev_.Gamepad.wButtons & OGXINPUT_GAMEPAD_RIGHT_THUMB) && // // (LS && RS) AND
((input_prev_.Gamepad.bAnalogButtons[OGXINPUT_GAMEPAD_LEFT_TRIGGER] >= 0x8) ^ (input_prev_.Gamepad.bAnalogButtons[OGXINPUT_GAMEPAD_RIGHT_TRIGGER] >= 0x8)) && // Left XOR Right Trigger AND
(input_prev_.Gamepad.wButtons & (OGXINPUT_GAMEPAD_DPAD_UP | OGXINPUT_GAMEPAD_DPAD_DOWN))) // Direction to change deadzone
{
if(!deadzone_.hold){
short adjustment = (input_prev_.Gamepad.wButtons & OGXINPUT_GAMEPAD_DPAD_UP ? 15 : -15);

if (input_prev_.Gamepad.bAnalogButtons[OGXINPUT_GAMEPAD_LEFT_TRIGGER]){
deadzone_.bLeftTrigger = min(max(deadzone_.bLeftTrigger+adjustment,0), 0xFF);
}
if (input_prev_.Gamepad.bAnalogButtons[OGXINPUT_GAMEPAD_RIGHT_TRIGGER]){
deadzone_.bRightTrigger = min(max(deadzone_.bRightTrigger+adjustment,0), 0xFF);
}

// wait for button release
deadzone_.hold = true;
}
} else {
// reset button release
deadzone_.hold = false;
}
}

// Analog Stick Deadzone Calculations
deadZoneCalc(&gamepad_.sThumbLX, &gamepad_.sThumbLY, input_prev_.Gamepad.sThumbLX, input_prev_.Gamepad.sThumbLY, deadzone_.sThumbL, SHRT_MAX);
deadZoneCalc(&gamepad_.sThumbRX, &gamepad_.sThumbRY, input_prev_.Gamepad.sThumbRX, input_prev_.Gamepad.sThumbRY, deadzone_.sThumbR, SHRT_MAX);

// Trigger Deadzone Calculations
short triggerbuf;
deadZoneCalc(&triggerbuf, NULL, input_prev_.Gamepad.bAnalogButtons[OGXINPUT_GAMEPAD_LEFT_TRIGGER], 0, deadzone_.bLeftTrigger, 0xFF);
gamepad_.bLeftTrigger = triggerbuf;
deadZoneCalc(&triggerbuf, NULL, input_prev_.Gamepad.bAnalogButtons[OGXINPUT_GAMEPAD_RIGHT_TRIGGER], 0, deadzone_.bRightTrigger, 0xFF);
gamepad_.bRightTrigger = triggerbuf;

// Write gamepad to virtual XInput device
vigem_target_x360_update(vigem, target_, gamepad_);

return true;
}

15 changes: 14 additions & 1 deletion Xb2XInput/XboxController.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,15 @@ struct XboxOutputReport {

OGXINPUT_RUMBLE Rumble;
};

struct Deadzone {
short sThumbL;
short sThumbR;
BYTE bLeftTrigger;
BYTE bRightTrigger;
bool hold;
};

#pragma pack(pop)

#define HID_GET_REPORT 0x01
Expand Down Expand Up @@ -90,6 +99,9 @@ class XboxController
uint8_t endpoint_in_ = 0;
uint8_t endpoint_out_ = 0;

Deadzone deadzone_ = {0};
int deadZoneCalc(short *x_out, short *y_out, short x, short y, short deadzone, short sickzone);

bool update();
public:
XboxController(libusb_device_handle* handle, uint8_t* usb_ports, int num_ports);
Expand All @@ -98,7 +110,8 @@ class XboxController
int GetVendorId() const { return usb_vendor_; }
const char* GetProductName() const { return usb_productname_; }
const char* GetVendorName() const { return usb_vendorname_; }

Deadzone GetDeadzone() { return deadzone_; }

int GetControllerIndex()
{
if (!target_)
Expand Down