Skip to content

Commit

Permalink
Merge pull request #16 from skajacore/deadZone
Browse files Browse the repository at this point in the history
Added Deadzone Functionality
  • Loading branch information
emoose authored Jul 5, 2020
2 parents 11e1352 + 8b68d6c commit c701c72
Show file tree
Hide file tree
Showing 4 changed files with 153 additions and 13 deletions.
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
123 changes: 112 additions & 11 deletions Xb2XInput/XboxController.cpp
Original file line number Diff line number Diff line change
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

0 comments on commit c701c72

Please sign in to comment.