Major improvements to JoyKit, fixing Xbox and 8BitDo controllers as well as analog mappings in PS controllers in some situations

This commit is contained in:
Lior Halphon 2021-07-29 22:43:55 +03:00
parent 0ff882f3bc
commit 690a263648
11 changed files with 118 additions and 53 deletions

View File

@ -491,16 +491,12 @@
[GBUnderclock] = JOYButtonUsageR1,
};
// Todo: JoyKit might need an API to match an axis to a button
if (joystick_configuration_state == GBUnderclock) {
mapping[@"AnalogUnderclock"] = nil;
double max = 0;
for (JOYAxis *axis in controller.axes) {
if (axis.value > 0.5 ||
(axis.usage == JOYAxisUsageL1 && button.usage == JOYButtonUsageL1) ||
(axis.usage == JOYAxisUsageL2 && button.usage == JOYButtonUsageL2) ||
(axis.usage == JOYAxisUsageL3 && button.usage == JOYButtonUsageL3) ||
(axis.usage == JOYAxisUsageR1 && button.usage == JOYButtonUsageR1) ||
(axis.usage == JOYAxisUsageR2 && button.usage == JOYButtonUsageR2) ||
(axis.usage == JOYAxisUsageR3 && button.usage == JOYButtonUsageR3)) {
if ((axis.value > 0.5 || (axis.equivalentButtonUsage == button.usage)) && axis.value >= max) {
max = axis.value;
mapping[@"AnalogUnderclock"] = @(axis.uniqueID);
break;
}
@ -508,16 +504,12 @@
}
if (joystick_configuration_state == GBTurbo) {
mapping[@"AnalogTurbo"] = nil;
double max = 0;
for (JOYAxis *axis in controller.axes) {
if (axis.value > 0.5 ||
(axis.usage == JOYAxisUsageL1 && button.usage == JOYButtonUsageL1) ||
(axis.usage == JOYAxisUsageL2 && button.usage == JOYButtonUsageL2) ||
(axis.usage == JOYAxisUsageL3 && button.usage == JOYButtonUsageL3) ||
(axis.usage == JOYAxisUsageR1 && button.usage == JOYButtonUsageR1) ||
(axis.usage == JOYAxisUsageR2 && button.usage == JOYButtonUsageR2) ||
(axis.usage == JOYAxisUsageR3 && button.usage == JOYButtonUsageR3)) {
if ((axis.value > 0.5 || (axis.equivalentButtonUsage == button.usage)) && axis.value >= max) {
max = axis.value;
mapping[@"AnalogTurbo"] = @(axis.uniqueID);
break;
}
}
}

View File

@ -736,9 +736,9 @@
</connections>
</button>
<button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="d2I-jU-sLb">
<rect key="frame" x="195" y="13" width="72" height="32"/>
<rect key="frame" x="198" y="13" width="67" height="32"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="push" title="Clear" bezelStyle="rounded" alignment="center" enabled="NO" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="sug-xy-tbw">
<buttonCell key="cell" type="push" title="Skip" bezelStyle="rounded" alignment="center" enabled="NO" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="sug-xy-tbw">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>

View File

@ -4,8 +4,6 @@
hacksByManufacturer = @{
@(0x045E): @{ // Microsoft
/* Generally untested, but Microsoft goes by the book when it comes to HID report descriptors, so
it should work out of the box. The hack is only here for automatic mapping */
JOYAxisGroups: @{
@(kHIDUsage_GD_X): @(0),
@ -13,7 +11,7 @@ hacksByManufacturer = @{
@(kHIDUsage_GD_Z): @(2),
@(kHIDUsage_GD_Rx): @(1),
@(kHIDUsage_GD_Ry): @(1),
@(kHIDUsage_GD_Rz): @(3),
@(kHIDUsage_GD_Rz): @(2),
},
JOYButtonUsageMapping: @{
@ -37,8 +35,10 @@ hacksByManufacturer = @{
JOYAxes2DUsageMapping: @{
AXES2D(1): @(JOYAxes2DUsageLeftStick),
AXES2D(4): @(JOYAxes2DUsageRightStick),
AXES2D(3): @(JOYAxes2DUsageRightStick),
},
JOYEmulateAxisButtons: @YES,
},
@(0x054C): @{ // Sony

View File

@ -1,4 +1,5 @@
#import <Foundation/Foundation.h>
#import "JOYButton.h"
typedef enum {
JOYAxisUsageNone,
@ -8,11 +9,16 @@ typedef enum {
JOYAxisUsageR1,
JOYAxisUsageR2,
JOYAxisUsageR3,
JOYAxisUsageSlider,
JOYAxisUsageDial,
JOYAxisUsageWheel,
JOYAxisUsageRudder,
JOYAxisUsageThrottle,
JOYAxisUsageAccelerator,
JOYAxisUsageBrake,
JOYAxisUsageNonGenericMax,
JOYAxisUsageGeneric0 = 0x10000,
@ -23,6 +29,7 @@ typedef enum {
+ (NSString *)usageToString: (JOYAxisUsage) usage;
- (uint64_t)uniqueID;
- (double)value;
- (JOYButtonUsage)equivalentButtonUsage;
@property JOYAxisUsage usage;
@end

View File

@ -19,6 +19,8 @@
@"Analog R1",
@"Analog R2",
@"Analog R3",
@"Slider",
@"Dial",
@"Wheel",
@"Rudder",
@"Throttle",
@ -57,10 +59,23 @@
if (element.usagePage == kHIDPage_GenericDesktop) {
uint16_t usage = element.usage;
_usage = JOYAxisUsageGeneric0 + usage - kHIDUsage_GD_X + 1;
switch (element.usage) {
case kHIDUsage_GD_Slider: _usage = JOYAxisUsageSlider; break;
case kHIDUsage_GD_Dial: _usage = JOYAxisUsageDial; break;
case kHIDUsage_GD_Wheel: _usage = JOYAxisUsageWheel; break;
default:
_usage = JOYAxisUsageGeneric0 + element.usage - kHIDUsage_GD_X + 1;
break;
}
}
else if (element.usagePage == kHIDPage_Simulation) {
switch (element.usage) {
case kHIDUsage_Sim_Accelerator: _usage = JOYAxisUsageAccelerator; break;
case kHIDUsage_Sim_Brake: _usage = JOYAxisUsageBrake; break;
case kHIDUsage_Sim_Rudder: _usage = JOYAxisUsageRudder; break;
case kHIDUsage_Sim_Throttle: _usage = JOYAxisUsageThrottle; break;
}
}
_min = 1.0;
return self;
@ -87,4 +102,28 @@
return old != _state;
}
- (JOYButtonUsage)equivalentButtonUsage
{
if (self.usage >= JOYAxisUsageGeneric0) {
return self.usage - JOYAxisUsageGeneric0 + JOYButtonUsageGeneric0;
}
switch (self.usage) {
case JOYAxisUsageL1: return JOYButtonUsageL1;
case JOYAxisUsageL2: return JOYButtonUsageL2;
case JOYAxisUsageL3: return JOYButtonUsageL3;
case JOYAxisUsageR1: return JOYButtonUsageR1;
case JOYAxisUsageR2: return JOYButtonUsageR2;
case JOYAxisUsageR3: return JOYButtonUsageR3;
case JOYAxisUsageSlider: return JOYButtonUsageSlider;
case JOYAxisUsageDial: return JOYButtonUsageDial;
case JOYAxisUsageWheel: return JOYButtonUsageWheel;
case JOYAxisUsageRudder: return JOYButtonUsageRudder;
case JOYAxisUsageThrottle: return JOYButtonUsageThrottle;
case JOYAxisUsageAccelerator: return JOYButtonUsageAccelerator;
case JOYAxisUsageBrake: return JOYButtonUsageBrake;
default: return JOYButtonUsageNone;
}
}
@end

View File

@ -26,6 +26,16 @@ typedef enum {
JOYButtonUsageDPadRight,
JOYButtonUsageDPadUp,
JOYButtonUsageDPadDown,
JOYButtonUsageSlider,
JOYButtonUsageDial,
JOYButtonUsageWheel,
JOYButtonUsageRudder,
JOYButtonUsageThrottle,
JOYButtonUsageAccelerator,
JOYButtonUsageBrake,
JOYButtonUsageNonGenericMax,
JOYButtonUsageGeneric0 = 0x10000,

View File

@ -1,5 +1,6 @@
#import "JOYButton.h"
#import "JOYElement.h"
#import <AppKit/AppKit.h>
@implementation JOYButton
{
@ -80,6 +81,12 @@
case kHIDUsage_GD_SystemMainMenu: _usage = JOYButtonUsageHome; break;
}
}
else if (element.usagePage == kHIDPage_Consumer) {
switch (element.usage) {
case kHIDUsage_Csmr_ACHome: _usage = JOYButtonUsageHome; break;
case kHIDUsage_Csmr_ACBack: _usage = JOYButtonUsageSelect; break;
}
}
return self;
}
@ -98,5 +105,4 @@
}
return false;
}
@end

View File

@ -4,7 +4,6 @@
#import "JOYAxes2D.h"
#import "JOYHat.h"
static NSString const *JOYAxesEmulateButtonsKey = @"JOYAxesEmulateButtons";
static NSString const *JOYAxes2DEmulateButtonsKey = @"JOYAxes2DEmulateButtons";
static NSString const *JOYHatsEmulateButtonsKey = @"JOYHatsEmulateButtons";

View File

@ -7,6 +7,9 @@
#import "JOYEmulatedButton.h"
#include <IOKit/hid/IOHIDLib.h>
#include <AppKit/AppKit.h>
extern NSTextField *globalDebugField;
#define PWM_RESOLUTION 16
static NSString const *JOYAxisGroups = @"JOYAxisGroups";
@ -27,6 +30,7 @@ static NSString const *JOYActivationReport = @"JOYActivationReport";
static NSString const *JOYIgnoredReports = @"JOYIgnoredReports";
static NSString const *JOYIsDualShock3 = @"JOYIsDualShock3";
static NSString const *JOYIsSony = @"JOYIsSony";
static NSString const *JOYEmulateAxisButtons = @"JOYEmulateAxisButtons";
static NSMutableDictionary<id, JOYController *> *controllers; // Physical controllers
static NSMutableArray<JOYController *> *exposedControllers; // Logical controllers
@ -36,7 +40,6 @@ static NSDictionary *hacksByManufacturer = nil;
static NSMutableSet<id<JOYListener>> *listeners = nil;
static bool axesEmulateButtons = false;
static bool axes2DEmulateButtons = false;
static bool hatsEmulateButtons = false;
@ -234,29 +237,40 @@ typedef union {
return;
}
if (element.usagePage == kHIDPage_Button) {
NSDictionary *axisGroups = @{
@(kHIDUsage_GD_X): @(0),
@(kHIDUsage_GD_Y): @(0),
@(kHIDUsage_GD_Z): @(1),
@(kHIDUsage_GD_Rx): @(2),
@(kHIDUsage_GD_Ry): @(2),
@(kHIDUsage_GD_Rz): @(1),
};
axisGroups = _hacks[JOYAxisGroups] ?: axisGroups;
if (element.usagePage == kHIDPage_Button ||
(element.usagePage == kHIDPage_Consumer && (element.usage == kHIDUsage_Csmr_ACHome ||
element.usage == kHIDUsage_Csmr_ACBack))) {
button: {
JOYButton *button = [[JOYButton alloc] initWithElement: element];
[_buttons setObject:button forKey:element];
NSNumber *replacementUsage = _hacks[JOYButtonUsageMapping][@(button.usage)];
NSNumber *replacementUsage = element.usagePage == kHIDPage_Button? _hacks[JOYButtonUsageMapping][@(button.usage)] : nil;
if (replacementUsage) {
button.usage = [replacementUsage unsignedIntValue];
}
return;
}
}
else if (element.usagePage == kHIDPage_Simulation) {
switch (element.usage) {
case kHIDUsage_Sim_Accelerator:
case kHIDUsage_Sim_Brake:
case kHIDUsage_Sim_Rudder:
case kHIDUsage_Sim_Throttle:
goto single;
}
}
else if (element.usagePage == kHIDPage_GenericDesktop) {
NSDictionary *axisGroups = @{
@(kHIDUsage_GD_X): @(0),
@(kHIDUsage_GD_Y): @(0),
@(kHIDUsage_GD_Z): @(1),
@(kHIDUsage_GD_Rx): @(2),
@(kHIDUsage_GD_Ry): @(2),
@(kHIDUsage_GD_Rz): @(1),
};
axisGroups = _hacks[JOYAxisGroups] ?: axisGroups;
switch (element.usage) {
case kHIDUsage_GD_X:
case kHIDUsage_GD_Y:
@ -318,30 +332,26 @@ typedef union {
}*/
break;
}
single:
case kHIDUsage_GD_Slider:
case kHIDUsage_GD_Dial:
case kHIDUsage_GD_Wheel: {
case kHIDUsage_GD_Wheel:
{ single: {
JOYAxis *axis = [[JOYAxis alloc] initWithElement: element];
[_axes setObject:axis forKey:element];
NSNumber *replacementUsage = _hacks[JOYAxisUsageMapping][@(axis.usage)];
NSNumber *replacementUsage = element.usagePage == kHIDPage_GenericDesktop? _hacks[JOYAxisUsageMapping][@(axis.usage)] : nil;
if (replacementUsage) {
axis.usage = [replacementUsage unsignedIntValue];
}
if (axesEmulateButtons && axis.usage >= JOYAxisUsageL1 && axis.usage <= JOYAxisUsageR3) {
if ([_hacks[JOYEmulateAxisButtons] boolValue]) {
_axisEmulatedButtons[@(axis.uniqueID)] =
[[JOYEmulatedButton alloc] initWithUsage:axis.usage - JOYAxisUsageL1 + JOYButtonUsageL1 uniqueID:axis.uniqueID];
[[JOYEmulatedButton alloc] initWithUsage:axis.equivalentButtonUsage uniqueID:axis.uniqueID];
}
if (axesEmulateButtons && axis.usage >= JOYAxisUsageGeneric0) {
_axisEmulatedButtons[@(axis.uniqueID)] =
[[JOYEmulatedButton alloc] initWithUsage:axis.usage - JOYAxisUsageGeneric0 + JOYButtonUsageGeneric0 uniqueID:axis.uniqueID];
}
break;
}
}}
case kHIDUsage_GD_DPadUp:
case kHIDUsage_GD_DPadDown:
case kHIDUsage_GD_DPadRight:
@ -1030,7 +1040,6 @@ typedef union {
+ (void)startOnRunLoop:(NSRunLoop *)runloop withOptions: (NSDictionary *)options
{
axesEmulateButtons = [options[JOYAxesEmulateButtonsKey] boolValue];
axes2DEmulateButtons = [options[JOYAxes2DEmulateButtonsKey] boolValue];
hatsEmulateButtons = [options[JOYHatsEmulateButtonsKey] boolValue];

View File

@ -1,4 +1,5 @@
#import "JOYEmulatedButton.h"
#import <AppKit/AppKit.h>
@interface JOYButton ()
{
@ -28,7 +29,7 @@
- (bool)updateStateFromAxis:(JOYAxis *)axis
{
bool old = _state;
_state = [axis value] > 0.5;
_state = [axis value] > 0.8;
return _state != old;
}

View File

@ -1,5 +1,6 @@
#import "JOYHat.h"
#import "JOYElement.h"
#import <AppKit/AppKit.h>
@implementation JOYHat
{
@ -27,6 +28,7 @@
if (!self) return self;
_element = element;
_state = -1;
return self;
}