Actually, don’t use rumble threads at all, because IOHIDDeviceSetReport seems to queue stuff despite being blocking
This commit is contained in:
parent
af5cb72edc
commit
c9b401135f
@ -272,9 +272,7 @@
|
|||||||
|
|
||||||
- (void)setRumble:(double)amp
|
- (void)setRumble:(double)amp
|
||||||
{
|
{
|
||||||
dispatch_async(dispatch_get_main_queue(), ^{
|
|
||||||
[lastController setRumbleAmplitude:amp];
|
[lastController setRumbleAmplitude:amp];
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)controller:(JOYController *)controller movedAxis:(JOYAxis *)axis
|
- (void)controller:(JOYController *)controller movedAxis:(JOYAxis *)axis
|
||||||
|
@ -39,8 +39,6 @@ static bool axesEmulateButtons = false;
|
|||||||
static bool axes2DEmulateButtons = false;
|
static bool axes2DEmulateButtons = false;
|
||||||
static bool hatsEmulateButtons = false;
|
static bool hatsEmulateButtons = false;
|
||||||
|
|
||||||
static NSLock *globalRumbleThreadLock;
|
|
||||||
|
|
||||||
@interface JOYController ()
|
@interface JOYController ()
|
||||||
+ (void)controllerAdded:(IOHIDDeviceRef) device;
|
+ (void)controllerAdded:(IOHIDDeviceRef) device;
|
||||||
+ (void)controllerRemoved:(IOHIDDeviceRef) device;
|
+ (void)controllerRemoved:(IOHIDDeviceRef) device;
|
||||||
@ -95,8 +93,10 @@ static void HIDInput(void *context, IOReturn result, void *sender, IOHIDValueRef
|
|||||||
static void HIDReport(void *context, IOReturn result, void *sender, IOHIDReportType type,
|
static void HIDReport(void *context, IOReturn result, void *sender, IOHIDReportType type,
|
||||||
uint32_t reportID, uint8_t *report, CFIndex reportLength)
|
uint32_t reportID, uint8_t *report, CFIndex reportLength)
|
||||||
{
|
{
|
||||||
|
if (reportLength) {
|
||||||
[(__bridge JOYController *)context gotReport:[[NSData alloc] initWithBytesNoCopy:report length:reportLength freeWhenDone:NO]];
|
[(__bridge JOYController *)context gotReport:[[NSData alloc] initWithBytesNoCopy:report length:reportLength freeWhenDone:NO]];
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
typedef struct __attribute__((packed)) {
|
typedef struct __attribute__((packed)) {
|
||||||
uint8_t reportID;
|
uint8_t reportID;
|
||||||
@ -152,12 +152,9 @@ typedef union {
|
|||||||
bool _isSwitch; // Does this controller use the Switch protocol?
|
bool _isSwitch; // Does this controller use the Switch protocol?
|
||||||
bool _isDualShock3; // Does this controller use DS3 outputs?
|
bool _isDualShock3; // Does this controller use DS3 outputs?
|
||||||
JOYVendorSpecificOutput _lastVendorSpecificOutput;
|
JOYVendorSpecificOutput _lastVendorSpecificOutput;
|
||||||
NSLock *_rumbleThreadLock;
|
volatile double _rumbleAmplitude;
|
||||||
volatile double _rumblePWMRatio;
|
|
||||||
bool _physicallyConnected;
|
bool _physicallyConnected;
|
||||||
bool _logicallyConnected;
|
bool _logicallyConnected;
|
||||||
bool _rumbleThreadRunning;
|
|
||||||
volatile bool _forceStopRumbleThread;
|
|
||||||
|
|
||||||
NSDictionary *_hacks;
|
NSDictionary *_hacks;
|
||||||
NSMutableData *_lastReport;
|
NSMutableData *_lastReport;
|
||||||
@ -166,7 +163,8 @@ typedef union {
|
|||||||
JOYElement *_previousAxisElement;
|
JOYElement *_previousAxisElement;
|
||||||
|
|
||||||
uint8_t _playerLEDs;
|
uint8_t _playerLEDs;
|
||||||
|
double _sentRumbleAmp;
|
||||||
|
unsigned _rumbleCounter;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (instancetype)initWithDevice:(IOHIDDeviceRef) device hacks:(NSDictionary *)hacks
|
- (instancetype)initWithDevice:(IOHIDDeviceRef) device hacks:(NSDictionary *)hacks
|
||||||
@ -358,7 +356,6 @@ typedef union {
|
|||||||
_axes2DEmulatedButtons = [NSMutableDictionary dictionary];
|
_axes2DEmulatedButtons = [NSMutableDictionary dictionary];
|
||||||
_hatEmulatedButtons = [NSMutableDictionary dictionary];
|
_hatEmulatedButtons = [NSMutableDictionary dictionary];
|
||||||
_iokitToJOY = [NSMutableDictionary dictionary];
|
_iokitToJOY = [NSMutableDictionary dictionary];
|
||||||
_rumbleThreadLock = [[NSLock alloc] init];
|
|
||||||
|
|
||||||
|
|
||||||
//NSMutableArray *axes3d = [NSMutableArray array];
|
//NSMutableArray *axes3d = [NSMutableArray array];
|
||||||
@ -368,10 +365,6 @@ typedef union {
|
|||||||
_isDualShock3 = [_hacks[JOYIsDualShock3] boolValue];
|
_isDualShock3 = [_hacks[JOYIsDualShock3] boolValue];
|
||||||
|
|
||||||
NSDictionary *customReports = hacks[JOYCustomReports];
|
NSDictionary *customReports = hacks[JOYCustomReports];
|
||||||
|
|
||||||
if (hacks[JOYCustomReports]) {
|
|
||||||
_multiElements = [NSMutableDictionary dictionary];
|
|
||||||
_fullReportElements = [NSMutableDictionary dictionary];
|
|
||||||
_lastReport = [NSMutableData dataWithLength:MAX(
|
_lastReport = [NSMutableData dataWithLength:MAX(
|
||||||
MAX(
|
MAX(
|
||||||
[(__bridge NSNumber *)IOHIDDeviceGetProperty(device, CFSTR(kIOHIDMaxInputReportSizeKey)) unsignedIntValue],
|
[(__bridge NSNumber *)IOHIDDeviceGetProperty(device, CFSTR(kIOHIDMaxInputReportSizeKey)) unsignedIntValue],
|
||||||
@ -381,6 +374,11 @@ typedef union {
|
|||||||
)];
|
)];
|
||||||
IOHIDDeviceRegisterInputReportCallback(device, _lastReport.mutableBytes, _lastReport.length, HIDReport, (void *)self);
|
IOHIDDeviceRegisterInputReportCallback(device, _lastReport.mutableBytes, _lastReport.length, HIDReport, (void *)self);
|
||||||
|
|
||||||
|
if (hacks[JOYCustomReports]) {
|
||||||
|
_multiElements = [NSMutableDictionary dictionary];
|
||||||
|
_fullReportElements = [NSMutableDictionary dictionary];
|
||||||
|
|
||||||
|
|
||||||
for (NSNumber *_reportID in customReports) {
|
for (NSNumber *_reportID in customReports) {
|
||||||
signed reportID = [_reportID intValue];
|
signed reportID = [_reportID intValue];
|
||||||
bool isOutput = false;
|
bool isOutput = false;
|
||||||
@ -555,7 +553,7 @@ typedef union {
|
|||||||
- (void)gotReport:(NSData *)report
|
- (void)gotReport:(NSData *)report
|
||||||
{
|
{
|
||||||
JOYFullReportElement *element = _fullReportElements[@(*(uint8_t *)report.bytes)];
|
JOYFullReportElement *element = _fullReportElements[@(*(uint8_t *)report.bytes)];
|
||||||
if (!element) return;
|
if (element) {
|
||||||
[element updateValue:report];
|
[element updateValue:report];
|
||||||
|
|
||||||
NSArray<JOYElement *> *subElements = _multiElements[element];
|
NSArray<JOYElement *> *subElements = _multiElements[element];
|
||||||
@ -563,9 +561,10 @@ typedef union {
|
|||||||
for (JOYElement *subElement in subElements) {
|
for (JOYElement *subElement in subElements) {
|
||||||
[self _elementChanged:subElement];
|
[self _elementChanged:subElement];
|
||||||
}
|
}
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
[self updateRumble];
|
||||||
|
}
|
||||||
|
|
||||||
- (void)elementChanged:(IOHIDElementRef)element
|
- (void)elementChanged:(IOHIDElementRef)element
|
||||||
{
|
{
|
||||||
@ -697,7 +696,6 @@ typedef union {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
_physicallyConnected = false;
|
_physicallyConnected = false;
|
||||||
[self _forceStopRumbleThread]; // Stop the rumble thread.
|
|
||||||
[exposedControllers removeObject:self];
|
[exposedControllers removeObject:self];
|
||||||
_device = nil;
|
_device = nil;
|
||||||
}
|
}
|
||||||
@ -731,43 +729,30 @@ typedef union {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)rumbleThread
|
- (void)updateRumble
|
||||||
{
|
{
|
||||||
unsigned rumbleCounter = 0;
|
if (!self.connected) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (_rumbleElement.max == 1 && _rumbleElement.min == 0) {
|
if (_rumbleElement.max == 1 && _rumbleElement.min == 0) {
|
||||||
while (self.connected && !_forceStopRumbleThread) {
|
double ampToSend = _rumbleCounter < round(_rumbleAmplitude * PWM_RESOLUTION);
|
||||||
if ([_rumbleElement setValue:rumbleCounter < round(_rumblePWMRatio * PWM_RESOLUTION)]) {
|
if (ampToSend != _sentRumbleAmp) {
|
||||||
break;
|
[_rumbleElement setValue:ampToSend];
|
||||||
}
|
_sentRumbleAmp = ampToSend;
|
||||||
rumbleCounter += round(_rumblePWMRatio * PWM_RESOLUTION);
|
|
||||||
if (rumbleCounter >= PWM_RESOLUTION) {
|
|
||||||
rumbleCounter -= PWM_RESOLUTION;
|
|
||||||
}
|
}
|
||||||
|
_rumbleCounter += round(_rumbleAmplitude * PWM_RESOLUTION);
|
||||||
|
if (_rumbleCounter >= PWM_RESOLUTION) {
|
||||||
|
_rumbleCounter -= PWM_RESOLUTION;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
while (self.connected && !_forceStopRumbleThread) {
|
if (_rumbleAmplitude == _sentRumbleAmp) {
|
||||||
[_rumbleElement setValue:_rumblePWMRatio * (_rumbleElement.max - _rumbleElement.min) + _rumbleElement.min];
|
return;
|
||||||
}
|
}
|
||||||
}
|
_sentRumbleAmp = _rumbleAmplitude;
|
||||||
[_rumbleThreadLock lock];
|
|
||||||
[_rumbleElement setValue:0];
|
|
||||||
_rumbleThreadRunning = false;
|
|
||||||
_forceStopRumbleThread = false;
|
|
||||||
[_rumbleThreadLock unlock];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)setRumbleAmplitude:(double)amp /* andFrequency: (double)frequency */
|
|
||||||
{
|
|
||||||
double frequency = 144; // I have no idea what I'm doing.
|
|
||||||
|
|
||||||
if (amp < 0) amp = 0;
|
|
||||||
if (amp > 1) amp = 1;
|
|
||||||
if (_isSwitch) {
|
if (_isSwitch) {
|
||||||
if (amp == 0) {
|
double frequency = 144;
|
||||||
amp = 1;
|
double amp = _rumbleAmplitude;
|
||||||
frequency = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t highAmp = amp * 0x64;
|
uint8_t highAmp = amp * 0x64;
|
||||||
uint8_t lowAmp = amp * 0x32 + 0x40;
|
uint8_t lowAmp = amp * 0x32 + 0x40;
|
||||||
@ -801,33 +786,21 @@ typedef union {
|
|||||||
}
|
}
|
||||||
else if (_isDualShock3) {
|
else if (_isDualShock3) {
|
||||||
_lastVendorSpecificOutput.ds3Output.reportID = 1;
|
_lastVendorSpecificOutput.ds3Output.reportID = 1;
|
||||||
_lastVendorSpecificOutput.ds3Output.rumbleLeftDuration = _lastVendorSpecificOutput.ds3Output.rumbleRightDuration = amp? 0xff : 0;
|
_lastVendorSpecificOutput.ds3Output.rumbleLeftDuration = _lastVendorSpecificOutput.ds3Output.rumbleRightDuration = _rumbleAmplitude? 0xff : 0;
|
||||||
_lastVendorSpecificOutput.ds3Output.rumbleLeftStrength = _lastVendorSpecificOutput.ds3Output.rumbleRightStrength = amp * 0xff;
|
_lastVendorSpecificOutput.ds3Output.rumbleLeftStrength = _lastVendorSpecificOutput.ds3Output.rumbleRightStrength = round(_rumbleAmplitude * 0xff);
|
||||||
[self sendReport:[NSData dataWithBytes:&_lastVendorSpecificOutput.ds3Output length:sizeof(_lastVendorSpecificOutput.ds3Output)]];
|
[self sendReport:[NSData dataWithBytes:&_lastVendorSpecificOutput.ds3Output length:sizeof(_lastVendorSpecificOutput.ds3Output)]];
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
[_rumbleThreadLock lock];
|
[_rumbleElement setValue:_rumbleAmplitude * (_rumbleElement.max - _rumbleElement.min) + _rumbleElement.min];
|
||||||
_rumblePWMRatio = amp;
|
}
|
||||||
if (!_rumbleThreadRunning) { // PWM thread not running, start it.
|
}
|
||||||
if (amp != 0) {
|
}
|
||||||
/* TODO: The PWM thread does not handle correctly the case of having a multi-port controller where more
|
|
||||||
than one controller uses rumble. At least make sure any sibling controllers don't have their
|
|
||||||
PWM thread running. */
|
|
||||||
|
|
||||||
[globalRumbleThreadLock lock];
|
- (void)setRumbleAmplitude:(double)amp /* andFrequency: (double)frequency */
|
||||||
for (JOYController *controller in [JOYController allControllers]) {
|
{
|
||||||
if (controller != self && controller->_device == _device) {
|
if (amp < 0) amp = 0;
|
||||||
[controller _forceStopRumbleThread];
|
if (amp > 1) amp = 1;
|
||||||
}
|
_rumbleAmplitude = amp;
|
||||||
}
|
|
||||||
_rumblePWMRatio = amp;
|
|
||||||
_rumbleThreadRunning = true;
|
|
||||||
[self performSelectorInBackground:@selector(rumbleThread) withObject:nil];
|
|
||||||
[globalRumbleThreadLock unlock];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
[_rumbleThreadLock unlock];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (bool)isConnected
|
- (bool)isConnected
|
||||||
@ -835,16 +808,6 @@ typedef union {
|
|||||||
return _logicallyConnected && _physicallyConnected;
|
return _logicallyConnected && _physicallyConnected;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)_forceStopRumbleThread
|
|
||||||
{
|
|
||||||
[_rumbleThreadLock lock];
|
|
||||||
if (_rumbleThreadRunning) {
|
|
||||||
_forceStopRumbleThread = true;
|
|
||||||
}
|
|
||||||
[_rumbleThreadLock unlock];
|
|
||||||
while (_rumbleThreadRunning);
|
|
||||||
}
|
|
||||||
|
|
||||||
+ (void)controllerAdded:(IOHIDDeviceRef) device
|
+ (void)controllerAdded:(IOHIDDeviceRef) device
|
||||||
{
|
{
|
||||||
NSString *name = (__bridge NSString *)IOHIDDeviceGetProperty(device, CFSTR(kIOHIDProductKey));
|
NSString *name = (__bridge NSString *)IOHIDDeviceGetProperty(device, CFSTR(kIOHIDProductKey));
|
||||||
@ -902,7 +865,6 @@ typedef union {
|
|||||||
|
|
||||||
controllers = [NSMutableDictionary dictionary];
|
controllers = [NSMutableDictionary dictionary];
|
||||||
exposedControllers = [NSMutableArray array];
|
exposedControllers = [NSMutableArray array];
|
||||||
globalRumbleThreadLock = [[NSLock alloc] init];
|
|
||||||
NSArray *array = @[
|
NSArray *array = @[
|
||||||
CreateHIDDeviceMatchDictionary(kHIDPage_GenericDesktop, kHIDUsage_GD_Joystick),
|
CreateHIDDeviceMatchDictionary(kHIDPage_GenericDesktop, kHIDUsage_GD_Joystick),
|
||||||
CreateHIDDeviceMatchDictionary(kHIDPage_GenericDesktop, kHIDUsage_GD_GamePad),
|
CreateHIDDeviceMatchDictionary(kHIDPage_GenericDesktop, kHIDUsage_GD_GamePad),
|
||||||
|
Loading…
Reference in New Issue
Block a user