Cocoa Port:

- Do a bunch of optimization and cleanup of the input handler.
- Add support for using analog inputs in their native format.
- The paddle controller now supports native analog control.
- NOTE: Due to the changes in the input handler, users will need to rebind any hatswitch inputs that were previously used. Only hatswitch inputs were affected by these changes.
This commit is contained in:
rogerman 2014-01-07 18:35:40 +00:00
parent ac146b26d2
commit 0ec2b21a20
17 changed files with 2072 additions and 831 deletions

View File

@ -129,4 +129,14 @@ public:
} }
}; };
u16 Paddle_GetValue()
{
return nds.paddle;
}
void Paddle_SetValue(u16 theValue)
{
nds.paddle = theValue;
}
ISlot2Interface* construct_Slot2_Paddle() { return new Slot2_Paddle(); } ISlot2Interface* construct_Slot2_Paddle() { return new Slot2_Paddle(); }

View File

@ -20,6 +20,7 @@
<string>Microphone</string> <string>Microphone</string>
<string>Lid</string> <string>Lid</string>
<string>Debug</string> <string>Debug</string>
<string>Paddle</string>
<string>Execute/Pause</string> <string>Execute/Pause</string>
<string>Reset</string> <string>Reset</string>
<string>Mute/Unmute</string> <string>Mute/Unmute</string>
@ -33,7 +34,6 @@
<string>Enable/Disable Auto Frame Skip</string> <string>Enable/Disable Auto Frame Skip</string>
<string>Enable/Disable Cheats</string> <string>Enable/Disable Cheats</string>
<string>Enable/Disable GPU State</string> <string>Enable/Disable GPU State</string>
<string>Paddle</string>
</array> </array>
<key>DefaultInputProfiles</key> <key>DefaultInputProfiles</key>
<array> <array>
@ -281,6 +281,45 @@
</array> </array>
<key>Debug</key> <key>Debug</key>
<array/> <array/>
<key>Paddle</key>
<array>
<dict>
<key>deviceInfoSummary</key>
<string>Keyboard: K</string>
<key>deviceCode</key>
<string>NSEventKeyboard</string>
<key>deviceName</key>
<string>Keyboard</string>
<key>elementCode</key>
<string>40</string>
<key>elementName</key>
<string>K</string>
<key>isInputAnalog</key>
<false/>
<key>inputSettingsSummary</key>
<string>Paddle Adjust: -5</string>
<key>intValue1</key>
<integer>-5</integer>
</dict>
<dict>
<key>deviceInfoSummary</key>
<string>Keyboard: L</string>
<key>deviceCode</key>
<string>NSEventKeyboard</string>
<key>deviceName</key>
<string>Keyboard</string>
<key>elementCode</key>
<string>37</string>
<key>elementName</key>
<string>L</string>
<key>isInputAnalog</key>
<false/>
<key>inputSettingsSummary</key>
<string>Paddle Adjust: +5</string>
<key>intValue1</key>
<integer>5</integer>
</dict>
</array>
<key>HUD</key> <key>HUD</key>
<array> <array>
<dict> <dict>
@ -411,8 +450,6 @@
<array/> <array/>
<key>Enable/Disable GPU State</key> <key>Enable/Disable GPU State</key>
<array/> <array/>
<key>Paddle</key>
<array/>
</dict> </dict>
</dict> </dict>
</array> </array>

View File

@ -69,12 +69,14 @@ enum
NSPoint touchLocation; NSPoint touchLocation;
bool controllerState[DSControllerState_StatesCount]; bool controllerState[DSControllerState_StatesCount];
AudioSampleBlockGenerator *selectedAudioFileGenerator; AudioSampleBlockGenerator *selectedAudioFileGenerator;
NSInteger paddleAdjust;
OSSpinLock spinlockControllerState; OSSpinLock spinlockControllerState;
} }
@property (assign) NSInteger micMode; @property (assign) NSInteger micMode;
@property (assign) AudioSampleBlockGenerator *selectedAudioFileGenerator; @property (assign) AudioSampleBlockGenerator *selectedAudioFileGenerator;
@property (assign) NSInteger paddleAdjust;
- (void) setControllerState:(BOOL)theState controlID:(const NSUInteger)controlID; - (void) setControllerState:(BOOL)theState controlID:(const NSUInteger)controlID;
- (void) setTouchState:(BOOL)theState location:(const NSPoint)theLocation; - (void) setTouchState:(BOOL)theState location:(const NSPoint)theLocation;

View File

@ -20,6 +20,7 @@
#import "cocoa_globals.h" #import "cocoa_globals.h"
#include "../NDSSystem.h" #include "../NDSSystem.h"
#include "../slot2.h"
#undef BOOL #undef BOOL
@ -27,6 +28,7 @@
@synthesize micMode; @synthesize micMode;
@synthesize selectedAudioFileGenerator; @synthesize selectedAudioFileGenerator;
@synthesize paddleAdjust;
- (id)init - (id)init
{ {
@ -45,6 +47,7 @@
micMode = MICMODE_NONE; micMode = MICMODE_NONE;
selectedAudioFileGenerator = NULL; selectedAudioFileGenerator = NULL;
touchLocation = NSMakePoint(0.0f, 0.0f); touchLocation = NSMakePoint(0.0f, 0.0f);
paddleAdjust = 0;
return self; return self;
} }
@ -131,6 +134,13 @@
NDS_releaseTouch(); NDS_releaseTouch();
} }
// Setup the paddle.
if (slot2_GetSelectedType() == NDS_SLOT2_PADDLE)
{
const u16 newPaddleValue = Paddle_GetValue() + (u16)[self paddleAdjust];
Paddle_SetValue(newPaddleValue);
}
// Setup the DS mic. // Setup the DS mic.
AudioGenerator *selectedGenerator = &nullSampleGenerator; AudioGenerator *selectedGenerator = &nullSampleGenerator;
switch (theMicMode) switch (theMicMode)

View File

@ -49,7 +49,6 @@
@property (copy) NSURL *gbaCartridgeURL; @property (copy) NSURL *gbaCartridgeURL;
@property (copy) NSURL *gbaSRamURL; @property (copy) NSURL *gbaSRamURL;
@property (readonly) BOOL doesGbaCartridgeSaveExist; @property (readonly) BOOL doesGbaCartridgeSaveExist;
@property (assign) UInt16 paddleValue;
- (CocoaDSSlot2Device *) autoSelectedDevice; - (CocoaDSSlot2Device *) autoSelectedDevice;
- (NSString *) autoSelectedDeviceName; - (NSString *) autoSelectedDeviceName;

View File

@ -47,8 +47,6 @@
- (void) dealloc - (void) dealloc
{ {
[self setEnabled:nil];
[super dealloc]; [super dealloc];
} }
@ -91,7 +89,6 @@
@dynamic gbaCartridgeURL; @dynamic gbaCartridgeURL;
@dynamic gbaSRamURL; @dynamic gbaSRamURL;
@dynamic doesGbaCartridgeSaveExist; @dynamic doesGbaCartridgeSaveExist;
@dynamic paddleValue;
- (id) init - (id) init
{ {
@ -211,16 +208,6 @@
return NO; return NO;
} }
- (void) setPaddleValue:(UInt16)value
{
nds.paddle = value;
}
- (UInt16) paddleValue
{
return nds.paddle;
}
- (CocoaDSSlot2Device *) autoSelectedDevice - (CocoaDSSlot2Device *) autoSelectedDevice
{ {
return [self findDeviceByType:slot2_DetermineType()]; return [self findDeviceByType:slot2_DetermineType()];

File diff suppressed because it is too large Load Diff

View File

@ -1792,14 +1792,13 @@ static std::tr1::unordered_map<NSScreen *, DisplayWindowController *> _screenMap
} }
#pragma mark InputHIDManagerTarget Protocol #pragma mark InputHIDManagerTarget Protocol
- (BOOL) handleHIDQueue:(IOHIDQueueRef)hidQueue - (BOOL) handleHIDQueue:(IOHIDQueueRef)hidQueue hidManager:(InputHIDManager *)hidManager
{ {
BOOL isHandled = NO; BOOL isHandled = NO;
DisplayWindowController *windowController = (DisplayWindowController *)[[self window] delegate]; DisplayWindowController *windowController = (DisplayWindowController *)[[self window] delegate];
InputAttributesList inputList = InputManagerEncodeHIDQueue(hidQueue); InputAttributesList inputList = InputManagerEncodeHIDQueue(hidQueue, [hidManager inputManager], false);
char inputStr[INPUT_HANDLER_STRING_LENGTH*2]; NSString *newStatusText = nil;
memset(inputStr, '\0', INPUT_HANDLER_STRING_LENGTH*2);
const size_t inputCount = inputList.size(); const size_t inputCount = inputList.size();
@ -1807,18 +1806,21 @@ static std::tr1::unordered_map<NSScreen *, DisplayWindowController *> _screenMap
{ {
const InputAttributes &inputAttr = inputList[i]; const InputAttributes &inputAttr = inputList[i];
if (inputAttr.state == INPUT_ATTRIBUTE_STATE_ON) if (inputAttr.isAnalog)
{ {
strlcpy(inputStr, inputAttr.deviceName, INPUT_HANDLER_STRING_LENGTH*2); newStatusText = [NSString stringWithFormat:@"%s:%s (%1.2f)", inputAttr.deviceName, inputAttr.elementName, inputAttr.scalar];
strlcat(inputStr, ":", INPUT_HANDLER_STRING_LENGTH*2); break;
strlcat(inputStr, inputAttr.elementName, INPUT_HANDLER_STRING_LENGTH*2); }
else if (inputAttr.state == INPUT_ATTRIBUTE_STATE_ON)
{
newStatusText = [NSString stringWithFormat:@"%s:%s", inputAttr.deviceName, inputAttr.elementName];
break; break;
} }
} }
if (inputStr[0] != '\0' && inputStr[0] != ':') if (newStatusText != nil)
{ {
[[windowController emuControl] setStatusText:[NSString stringWithCString:inputStr encoding:NSUTF8StringEncoding]]; [[windowController emuControl] setStatusText:newStatusText];
} }
CommandAttributesList cmdList = [inputManager generateCommandListUsingInputList:&inputList]; CommandAttributesList cmdList = [inputManager generateCommandListUsingInputList:&inputList];
@ -1842,12 +1844,8 @@ static std::tr1::unordered_map<NSScreen *, DisplayWindowController *> _screenMap
if (keyPressed && [theEvent window] != nil) if (keyPressed && [theEvent window] != nil)
{ {
char inputStr[INPUT_HANDLER_STRING_LENGTH*2]; NSString *newStatusText = [NSString stringWithFormat:@"%s:%s", inputAttr.deviceName, inputAttr.elementName];
strlcpy(inputStr, inputAttr.deviceName, INPUT_HANDLER_STRING_LENGTH*2); [[windowController emuControl] setStatusText:newStatusText];
strlcat(inputStr, ":", INPUT_HANDLER_STRING_LENGTH*2);
strlcat(inputStr, inputAttr.elementName, INPUT_HANDLER_STRING_LENGTH*2);
[[windowController emuControl] setStatusText:[NSString stringWithCString:inputStr encoding:NSUTF8StringEncoding]];
} }
isHandled = [inputManager dispatchCommandUsingInputAttributes:&inputAttr]; isHandled = [inputManager dispatchCommandUsingInputAttributes:&inputAttr];
@ -1862,30 +1860,13 @@ static std::tr1::unordered_map<NSScreen *, DisplayWindowController *> _screenMap
// Convert the clicked location from window coordinates, to view coordinates, // Convert the clicked location from window coordinates, to view coordinates,
// and finally to DS touchscreen coordinates. // and finally to DS touchscreen coordinates.
NSPoint touchLoc = NSMakePoint(-2.0, -2.0); const NSPoint touchLoc = (displayModeID == DS_DISPLAY_TYPE_MAIN) ? NSMakePoint(0.0, 0.0) : [self dsPointFromEvent:theEvent];
if (displayModeID == DS_DISPLAY_TYPE_TOUCH || displayModeID == DS_DISPLAY_TYPE_DUAL)
{
touchLoc = [self dsPointFromEvent:theEvent];
}
const InputAttributes inputAttr = InputManagerEncodeMouseButtonInput([theEvent buttonNumber], touchLoc, buttonPressed); const InputAttributes inputAttr = InputManagerEncodeMouseButtonInput([theEvent buttonNumber], touchLoc, buttonPressed);
if (buttonPressed && [theEvent window] != nil) if (buttonPressed && [theEvent window] != nil)
{ {
static char inputStr[INPUT_HANDLER_STRING_LENGTH*2] = {0}; NSString *newStatusText = (displayModeID == DS_DISPLAY_TYPE_MAIN) ? [NSString stringWithFormat:@"%s:%s", inputAttr.deviceName, inputAttr.elementName] : [NSString stringWithFormat:@"%s:%s X:%i Y:%i", inputAttr.deviceName, inputAttr.elementName, (int)inputAttr.intCoordX, (int)inputAttr.intCoordY];
strlcpy(inputStr, inputAttr.deviceName, INPUT_HANDLER_STRING_LENGTH*2); [[windowController emuControl] setStatusText:newStatusText];
strlcat(inputStr, ":", INPUT_HANDLER_STRING_LENGTH*2);
strlcat(inputStr, inputAttr.elementName, INPUT_HANDLER_STRING_LENGTH*2);
if (inputAttr.intCoordX >= 0)
{
static char inputCoordBuf[64] = {0};
snprintf(inputCoordBuf, 64, " X:%i Y:%i", (int)inputAttr.intCoordX, (int)inputAttr.intCoordY);
strlcat(inputStr, inputCoordBuf, INPUT_HANDLER_STRING_LENGTH*2);
}
[[windowController emuControl] setStatusText:[NSString stringWithCString:inputStr encoding:NSUTF8StringEncoding]];
} }
isHandled = [inputManager dispatchCommandUsingInputAttributes:&inputAttr]; isHandled = [inputManager dispatchCommandUsingInputAttributes:&inputAttr];

View File

@ -987,15 +987,32 @@
} }
else if (controlID == DSControllerState_Paddle) else if (controlID == DSControllerState_Paddle)
{ {
if (cmdAttr.useInputForScalar) if (cmdAttr.input.isAnalog)
{ {
const float paddleScalar = cmdAttr.floatValue[0]; const NSInteger paddleSensitivity = cmdAttr.floatValue[0];
[(Slot2WindowDelegate *)[slot2WindowController content] setPaddleDirectWithScalar:paddleScalar]; const float paddleScalar = cmdAttr.input.scalar;
float paddleAdjust = (paddleScalar * 2.0f) - 1.0f;
// Clamp the paddle value.
if (paddleAdjust < -1.0f)
{
paddleAdjust = -1.0f;
}
if (paddleAdjust > 1.0f)
{
paddleAdjust = 1.0f;
}
// Normalize the input value for the paddle.
paddleAdjust *= (float)paddleSensitivity;
[[cdsCore cdsController] setPaddleAdjust:paddleAdjust];
} }
else else
{ {
const NSInteger paddleRelativeAdjustment = cmdAttr.intValue[1]; const NSInteger paddleAdjust = (theState) ? cmdAttr.intValue[1] : 0;
[(Slot2WindowDelegate *)[slot2WindowController content] setPaddleRelativeWithInteger:paddleRelativeAdjustment]; [[cdsCore cdsController] setPaddleAdjust:paddleAdjust];
} }
} }
else else

View File

@ -47,7 +47,7 @@ enum InputAttributeState
@protocol InputHIDManagerTarget <NSObject> @protocol InputHIDManagerTarget <NSObject>
@required @required
- (BOOL) handleHIDQueue:(IOHIDQueueRef)hidQueue; - (BOOL) handleHIDQueue:(IOHIDQueueRef)hidQueue hidManager:(InputHIDManager *)hidManager;
@end @end
@ -57,6 +57,7 @@ typedef struct
char deviceCode[INPUT_HANDLER_STRING_LENGTH]; char deviceCode[INPUT_HANDLER_STRING_LENGTH];
char elementName[INPUT_HANDLER_STRING_LENGTH]; char elementName[INPUT_HANDLER_STRING_LENGTH];
char elementCode[INPUT_HANDLER_STRING_LENGTH]; char elementCode[INPUT_HANDLER_STRING_LENGTH];
bool isAnalog; // This is an analog input, as opposed to being a digital input.
InputAttributeState state; // The input state that is sent on command dispatch InputAttributeState state; // The input state that is sent on command dispatch
int32_t intCoordX; // The X-coordinate as an int for commands that require a location int32_t intCoordX; // The X-coordinate as an int for commands that require a location
@ -81,6 +82,7 @@ typedef struct
bool useInputForSender; // The command will prefer the input device's sender bool useInputForSender; // The command will prefer the input device's sender
InputAttributes input; // The input device's attributes InputAttributes input; // The input device's attributes
bool allowAnalogInput; // Flag for allowing a command to accept analog inputs
} CommandAttributes; } CommandAttributes;
typedef std::vector<InputAttributes> InputAttributesList; typedef std::vector<InputAttributes> InputAttributesList;
@ -141,12 +143,12 @@ typedef std::tr1::unordered_map<std::string, AudioSampleBlockGenerator> AudioFil
@end @end
bool GetOnStateFromHIDValueRef(IOHIDValueRef hidValueRef); bool InputElementCodeFromHIDElement(const IOHIDElementRef hidElementRef, char *charBuffer);
void InputDeviceCodeFromHIDDevice(const IOHIDDeviceRef hidDeviceRef, char *charBuffer); bool InputElementNameFromHIDElement(const IOHIDElementRef hidElementRef, char *charBuffer);
void InputDeviceNameFromHIDDevice(const IOHIDDeviceRef hidDeviceRef, char *charBuffer, const char *altName); bool InputDeviceCodeFromHIDDevice(const IOHIDDeviceRef hidDeviceRef, char *charBuffer);
InputAttributes InputAttributesOfHIDValue(IOHIDValueRef hidValueRef, const char *altElementCode, const char *altElementName, const bool *altOnState); bool InputDeviceNameFromHIDDevice(const IOHIDDeviceRef hidDeviceRef, char *charBuffer);
InputAttributesList InputListFromHIDValue(IOHIDValueRef hidValueRef); InputAttributes InputAttributesOfHIDValue(IOHIDValueRef hidValueRef);
InputAttributesList InputListFromHatSwitchValue(IOHIDValueRef hidValueRef, bool useEightDirection); InputAttributesList InputListFromHIDValue(IOHIDValueRef hidValueRef, InputManager *inputManager, bool forceDigitalInput);
size_t ClearHIDQueue(const IOHIDQueueRef hidQueue); size_t ClearHIDQueue(const IOHIDQueueRef hidQueue);
void HandleQueueValueAvailableCallback(void *inContext, IOReturn inResult, void *inSender); void HandleQueueValueAvailableCallback(void *inContext, IOReturn inResult, void *inSender);
@ -238,7 +240,7 @@ NSMutableDictionary* DeviceInfoDictionaryWithCommandAttributes(const CommandAttr
NSString *elementCode, NSString *elementCode,
NSString *elementName); NSString *elementName);
InputAttributesList InputManagerEncodeHIDQueue(const IOHIDQueueRef hidQueue); InputAttributesList InputManagerEncodeHIDQueue(const IOHIDQueueRef hidQueue, InputManager *inputManager, bool forceDigitalInput);
InputAttributes InputManagerEncodeKeyboardInput(const unsigned short keyCode, BOOL keyPressed); InputAttributes InputManagerEncodeKeyboardInput(const unsigned short keyCode, BOOL keyPressed);
InputAttributes InputManagerEncodeMouseButtonInput(const NSInteger buttonNumber, const NSPoint touchLoc, BOOL buttonPressed); InputAttributes InputManagerEncodeMouseButtonInput(const NSInteger buttonNumber, const NSPoint touchLoc, BOOL buttonPressed);
InputAttributes InputManagerEncodeIBAction(const SEL theSelector, id sender); InputAttributes InputManagerEncodeIBAction(const SEL theSelector, id sender);

View File

@ -221,6 +221,7 @@ static NSDictionary *hidUsageTable = nil;
- (void)dealloc - (void)dealloc
{ {
[self stopForceFeedback];
[self stop]; [self stop];
[self setRunLoop:nil]; [self setRunLoop:nil];
[self setHidManager:nil]; [self setHidManager:nil];
@ -233,8 +234,8 @@ static NSDictionary *hidUsageTable = nil;
if (ffDevice != NULL) if (ffDevice != NULL)
{ {
FFReleaseDevice(ffDevice);
FFEffectUnload(ffEffect); FFEffectUnload(ffEffect);
FFReleaseDevice(ffDevice);
ffDevice = NULL; ffDevice = NULL;
} }
@ -411,9 +412,6 @@ static NSDictionary *hidUsageTable = nil;
Takes: Takes:
hidValueRef - The IOHIDValueRef to parse. hidValueRef - The IOHIDValueRef to parse.
altElementCode - A char buffer that overrides the default element code.
altElementName - A char buffer that overrides the default element name.
altOnState - A pointer to a bool value that overrides the default on state.
Returns: Returns:
An InputAttributes struct with the parsed input attributes. An InputAttributes struct with the parsed input attributes.
@ -421,7 +419,7 @@ static NSDictionary *hidUsageTable = nil;
Details: Details:
None. None.
********************************************************************************************/ ********************************************************************************************/
InputAttributes InputAttributesOfHIDValue(IOHIDValueRef hidValueRef, const char *altElementCode, const char *altElementName, const bool *altOnState) InputAttributes InputAttributesOfHIDValue(IOHIDValueRef hidValueRef)
{ {
InputAttributes inputAttr; InputAttributes inputAttr;
@ -430,63 +428,25 @@ InputAttributes InputAttributesOfHIDValue(IOHIDValueRef hidValueRef, const char
return inputAttr; return inputAttr;
} }
IOHIDElementRef hidElementRef = IOHIDValueGetElement(hidValueRef); const IOHIDElementRef hidElementRef = IOHIDValueGetElement(hidValueRef);
NSInteger elementUsagePage = IOHIDElementGetUsagePage(hidElementRef);
NSInteger elementUsage = IOHIDElementGetUsage(hidElementRef);
if (altElementCode == NULL)
{
snprintf(inputAttr.elementCode, INPUT_HANDLER_STRING_LENGTH, "0x%04lX/0x%04lX", (long)elementUsagePage, (long)elementUsage);
}
else
{
strncpy(inputAttr.elementCode, altElementCode, INPUT_HANDLER_STRING_LENGTH);
}
if (altElementName == NULL)
{
CFStringRef cfElementName = IOHIDElementGetName(hidElementRef);
if (cfElementName == nil)
{
if (elementUsagePage == kHIDPage_Button)
{
snprintf(inputAttr.elementName, INPUT_HANDLER_STRING_LENGTH, "Button %li", (long)elementUsage);
}
else if (elementUsagePage == kHIDPage_VendorDefinedStart)
{
snprintf(inputAttr.elementName, INPUT_HANDLER_STRING_LENGTH, "VendorDefined %li", (long)elementUsage);
}
else
{
NSDictionary *elementUsagePageDict = (NSDictionary *)[hidUsageTable valueForKey:[NSString stringWithFormat:@"0x%04lX", (long)elementUsagePage]];
NSString *elementNameLookup = (NSString *)[elementUsagePageDict valueForKey:[NSString stringWithFormat:@"0x%04lX", (long)elementUsage]];
if (elementNameLookup != nil)
{
strncpy(inputAttr.elementName, [elementNameLookup cStringUsingEncoding:NSUTF8StringEncoding], 256);
}
}
}
else
{
CFStringGetCString(cfElementName, inputAttr.elementName, INPUT_HANDLER_STRING_LENGTH, kCFStringEncodingUTF8);
}
}
else
{
strncpy(inputAttr.elementName, altElementName, INPUT_HANDLER_STRING_LENGTH);
}
const IOHIDDeviceRef hidDeviceRef = IOHIDElementGetDevice(hidElementRef); const IOHIDDeviceRef hidDeviceRef = IOHIDElementGetDevice(hidElementRef);
InputDeviceCodeFromHIDDevice(hidDeviceRef, inputAttr.deviceCode);
InputDeviceNameFromHIDDevice(hidDeviceRef, inputAttr.deviceName, inputAttr.deviceCode);
const bool onState = (altOnState == NULL) ? GetOnStateFromHIDValueRef(hidValueRef) : *altOnState; InputElementCodeFromHIDElement(hidElementRef, inputAttr.elementCode);
InputDeviceCodeFromHIDDevice(hidDeviceRef, inputAttr.deviceCode);
strncpy(inputAttr.elementName, inputAttr.elementCode, INPUT_HANDLER_STRING_LENGTH);
InputElementNameFromHIDElement(hidElementRef, inputAttr.elementName);
strncpy(inputAttr.deviceName, inputAttr.deviceCode, INPUT_HANDLER_STRING_LENGTH);
InputDeviceNameFromHIDDevice(hidDeviceRef, inputAttr.deviceName);
const NSInteger logicalValue = IOHIDValueGetIntegerValue(hidValueRef); const NSInteger logicalValue = IOHIDValueGetIntegerValue(hidValueRef);
const NSInteger logicalMin = IOHIDElementGetLogicalMin(hidElementRef); const NSInteger logicalMin = IOHIDElementGetLogicalMin(hidElementRef);
const NSInteger logicalMax = IOHIDElementGetLogicalMax(hidElementRef); const NSInteger logicalMax = IOHIDElementGetLogicalMax(hidElementRef);
const NSInteger elementType = IOHIDElementGetType(hidElementRef);
const NSInteger elementUsage = IOHIDElementGetUsage(hidElementRef);
inputAttr.state = (onState) ? INPUT_ATTRIBUTE_STATE_ON : INPUT_ATTRIBUTE_STATE_OFF; inputAttr.isAnalog = (elementType != kIOHIDElementTypeInput_Button) && !(logicalMin == 0 && logicalMax == 1);
inputAttr.intCoordX = 0; inputAttr.intCoordX = 0;
inputAttr.intCoordY = 0; inputAttr.intCoordY = 0;
inputAttr.floatCoordX = 0.0f; inputAttr.floatCoordX = 0.0f;
@ -494,10 +454,61 @@ InputAttributes InputAttributesOfHIDValue(IOHIDValueRef hidValueRef, const char
inputAttr.scalar = (float)(logicalValue - logicalMin) / (float)(logicalMax - logicalMin); inputAttr.scalar = (float)(logicalValue - logicalMin) / (float)(logicalMax - logicalMin);
inputAttr.sender = nil; inputAttr.sender = nil;
if (!inputAttr.isAnalog)
{
inputAttr.state = (logicalValue == 1) ? INPUT_ATTRIBUTE_STATE_ON : INPUT_ATTRIBUTE_STATE_OFF;
}
else if (elementUsage == kHIDUsage_GD_Hatswitch)
{
// For hatswitch inputs, use the intCoord fields to store the axis information.
inputAttr.state = (logicalValue >= logicalMin && logicalValue <= logicalMax) ? INPUT_ATTRIBUTE_STATE_ON : INPUT_ATTRIBUTE_STATE_OFF;
if (inputAttr.state == INPUT_ATTRIBUTE_STATE_ON)
{
struct IntCoord
{
int x;
int y;
};
static const IntCoord coords4Way[4] = {
{0, -1}, // Up
{1, 0}, // Right
{0, 1}, // Down
{-1, 0} // Left
};
static const IntCoord coords8Way[8] = {
{0, -1}, // Up
{1, -1}, // Up/Right
{1, 0}, // Right
{1, 1}, // Down/Right
{0, 1}, // Down
{-1, 1}, // Down/Left
{-1, 0}, // Left
{-1, -1} // Up/Left
};
if (logicalMax == 3) // For a 4-way hatswitch
{
inputAttr.intCoordX = coords4Way[logicalValue].x;
inputAttr.intCoordY = coords4Way[logicalValue].y;
}
else if (logicalMax == 7) // For an 8-way hatswitch
{
inputAttr.intCoordX = coords8Way[logicalValue].x;
inputAttr.intCoordY = coords8Way[logicalValue].y;
}
}
}
else // Some generic analog input
{
inputAttr.state = (inputAttr.scalar <= 0.30f || inputAttr.scalar >= 0.7f) ? INPUT_ATTRIBUTE_STATE_ON : INPUT_ATTRIBUTE_STATE_OFF;
}
return inputAttr; return inputAttr;
} }
InputAttributesList InputListFromHIDValue(IOHIDValueRef hidValueRef) InputAttributesList InputListFromHIDValue(IOHIDValueRef hidValueRef, InputManager *inputManager, bool forceDigitalInput)
{ {
InputAttributesList inputList; InputAttributesList inputList;
@ -506,10 +517,6 @@ InputAttributesList InputListFromHIDValue(IOHIDValueRef hidValueRef)
return inputList; return inputList;
} }
IOHIDElementRef hidElementRef = IOHIDValueGetElement(hidValueRef);
NSInteger elementUsagePage = IOHIDElementGetUsagePage(hidElementRef);
NSInteger elementUsage = IOHIDElementGetUsage(hidElementRef);
// IOHIDValueGetIntegerValue() will crash if the value length is too large. // IOHIDValueGetIntegerValue() will crash if the value length is too large.
// Do a bounds check here to prevent crashing. This workaround makes the PS3 // Do a bounds check here to prevent crashing. This workaround makes the PS3
// controller usable, since it returns a length of 39 on some elements. // controller usable, since it returns a length of 39 on some elements.
@ -518,245 +525,199 @@ InputAttributesList InputListFromHIDValue(IOHIDValueRef hidValueRef)
return inputList; return inputList;
} }
NSInteger logicalValue = IOHIDValueGetIntegerValue(hidValueRef); InputAttributes inputAttr = InputAttributesOfHIDValue(hidValueRef);
NSInteger logicalMin = IOHIDElementGetLogicalMin(hidElementRef); if (inputAttr.deviceCode[0] == '\0' || inputAttr.elementCode[0] == '\0')
NSInteger logicalMax = IOHIDElementGetLogicalMax(hidElementRef);
inputList.resize(2);
if (logicalMin == 0 && logicalMax == 1)
{ {
inputList.push_back(InputAttributesOfHIDValue(hidValueRef, NULL, NULL, NULL)); return inputList;
}
if (!inputAttr.isAnalog)
{
inputList.push_back(inputAttr);
} }
else else
{ {
const NSInteger lowerThreshold = ((logicalMax - logicalMin) / 4) + logicalMin; const IOHIDElementRef hidElementRef = IOHIDValueGetElement(hidValueRef);
const NSInteger upperThreshold = (((logicalMax - logicalMin) * 3) / 4) + logicalMin; const NSInteger elementUsage = IOHIDElementGetUsage(hidElementRef);
const bool onState = true;
const bool offState = false;
char elementCodeLowerThresholdBuf[256] = {0}; if (elementUsage == kHIDUsage_GD_Hatswitch)
char elementCodeUpperThresholdBuf[256] = {0};
snprintf(elementCodeLowerThresholdBuf, 256, "0x%04lX/0x%04lX/LowerThreshold", (long)elementUsagePage, (long)elementUsage);
snprintf(elementCodeUpperThresholdBuf, 256, "0x%04lX/0x%04lX/UpperThreshold", (long)elementUsagePage, (long)elementUsage);
if (logicalValue <= lowerThreshold)
{ {
inputList.push_back(InputAttributesOfHIDValue(hidValueRef, elementCodeLowerThresholdBuf, NULL, &onState)); InputAttributes hatUp = inputAttr;
inputList.push_back(InputAttributesOfHIDValue(hidValueRef, elementCodeUpperThresholdBuf, NULL, &offState)); hatUp.isAnalog = false;
} strncat(hatUp.elementName, "/Up", INPUT_HANDLER_STRING_LENGTH);
else if (logicalValue >= upperThreshold) strncat(hatUp.elementCode, "/Up", INPUT_HANDLER_STRING_LENGTH);
{
inputList.push_back(InputAttributesOfHIDValue(hidValueRef, elementCodeLowerThresholdBuf, NULL, &offState)); InputAttributes hatRight = inputAttr;
inputList.push_back(InputAttributesOfHIDValue(hidValueRef, elementCodeUpperThresholdBuf, NULL, &onState)); hatRight.isAnalog = false;
strncat(hatRight.elementName, "/Right", INPUT_HANDLER_STRING_LENGTH);
strncat(hatRight.elementCode, "/Right", INPUT_HANDLER_STRING_LENGTH);
InputAttributes hatDown = inputAttr;
hatDown.isAnalog = false;
strncat(hatDown.elementName, "/Down", INPUT_HANDLER_STRING_LENGTH);
strncat(hatDown.elementCode, "/Down", INPUT_HANDLER_STRING_LENGTH);
InputAttributes hatLeft = inputAttr;
hatLeft.isAnalog = false;
strncat(hatLeft.elementName, "/Left", INPUT_HANDLER_STRING_LENGTH);
strncat(hatLeft.elementCode, "/Left", INPUT_HANDLER_STRING_LENGTH);
if (inputAttr.intCoordX == -1)
{
hatRight.state = INPUT_ATTRIBUTE_STATE_OFF;
hatLeft.state = INPUT_ATTRIBUTE_STATE_ON;
}
else if (inputAttr.intCoordX == 1)
{
hatRight.state = INPUT_ATTRIBUTE_STATE_ON;
hatLeft.state = INPUT_ATTRIBUTE_STATE_OFF;
}
else
{
hatRight.state = INPUT_ATTRIBUTE_STATE_OFF;
hatLeft.state = INPUT_ATTRIBUTE_STATE_OFF;
}
if (inputAttr.intCoordY == -1)
{
hatDown.state = INPUT_ATTRIBUTE_STATE_OFF;
hatUp.state = INPUT_ATTRIBUTE_STATE_ON;
}
else if (inputAttr.intCoordY == 1)
{
hatDown.state = INPUT_ATTRIBUTE_STATE_ON;
hatUp.state = INPUT_ATTRIBUTE_STATE_OFF;
}
else
{
hatDown.state = INPUT_ATTRIBUTE_STATE_OFF;
hatUp.state = INPUT_ATTRIBUTE_STATE_OFF;
}
inputList.resize(4);
inputList.push_back(hatUp);
inputList.push_back(hatRight);
inputList.push_back(hatDown);
inputList.push_back(hatLeft);
} }
else else
{ {
inputList.push_back(InputAttributesOfHIDValue(hidValueRef, elementCodeLowerThresholdBuf, NULL, &offState)); CommandAttributes cmdAttr = [inputManager mappedCommandAttributesOfDeviceCode:inputAttr.deviceCode elementCode:inputAttr.elementCode];
inputList.push_back(InputAttributesOfHIDValue(hidValueRef, elementCodeUpperThresholdBuf, NULL, &offState)); if (cmdAttr.tag[0] == '\0' || cmdAttr.selector == nil)
{
std::string tempElementCode = std::string(inputAttr.elementCode) + "/LowerThreshold";
cmdAttr = [inputManager mappedCommandAttributesOfDeviceCode:inputAttr.deviceCode elementCode:tempElementCode.c_str()];
if (cmdAttr.tag[0] == '\0' || cmdAttr.selector == nil)
{
tempElementCode = std::string(inputAttr.elementCode) + "/UpperThreshold";
cmdAttr = [inputManager mappedCommandAttributesOfDeviceCode:inputAttr.deviceCode elementCode:tempElementCode.c_str()];
}
}
const bool useAnalog = (cmdAttr.tag[0] == '\0' || cmdAttr.selector == nil) ? !forceDigitalInput : (!forceDigitalInput && cmdAttr.allowAnalogInput);
if (useAnalog)
{
inputList.push_back(inputAttr);
}
else
{
InputAttributes loInputAttr = inputAttr;
loInputAttr.isAnalog = false;
strncat(loInputAttr.elementName, "-", INPUT_HANDLER_STRING_LENGTH);
strncat(loInputAttr.elementCode, "/LowerThreshold", INPUT_HANDLER_STRING_LENGTH);
InputAttributes hiInputAttr = inputAttr;
hiInputAttr.isAnalog = false;
strncat(hiInputAttr.elementName, "+", INPUT_HANDLER_STRING_LENGTH);
strncat(hiInputAttr.elementCode, "/UpperThreshold", INPUT_HANDLER_STRING_LENGTH);
if (loInputAttr.scalar <= 0.30f)
{
loInputAttr.state = INPUT_ATTRIBUTE_STATE_ON;
hiInputAttr.state = INPUT_ATTRIBUTE_STATE_OFF;
}
else if (loInputAttr.scalar >= 0.70f)
{
loInputAttr.state = INPUT_ATTRIBUTE_STATE_OFF;
hiInputAttr.state = INPUT_ATTRIBUTE_STATE_ON;
}
else
{
loInputAttr.state = INPUT_ATTRIBUTE_STATE_OFF;
hiInputAttr.state = INPUT_ATTRIBUTE_STATE_OFF;
}
inputList.resize(2);
inputList.push_back(loInputAttr);
inputList.push_back(hiInputAttr);
}
} }
} }
return inputList; return inputList;
} }
InputAttributesList InputListFromHatSwitchValue(IOHIDValueRef hidValueRef, bool useEightDirection) bool InputElementCodeFromHIDElement(const IOHIDElementRef hidElementRef, char *charBuffer)
{ {
InputAttributesList inputList; NSInteger elementUsagePage = IOHIDElementGetUsagePage(hidElementRef);
NSInteger elementUsage = IOHIDElementGetUsage(hidElementRef);
snprintf(charBuffer, INPUT_HANDLER_STRING_LENGTH, "0x%04lX/0x%04lX", (long)elementUsagePage, (long)elementUsage);
if (hidValueRef == NULL) return true;
}
bool InputElementNameFromHIDElement(const IOHIDElementRef hidElementRef, char *charBuffer)
{
CFStringRef cfElementName = IOHIDElementGetName(hidElementRef);
bool propertyExists = (cfElementName != nil);
if (propertyExists)
{ {
return inputList; CFStringGetCString(cfElementName, charBuffer, INPUT_HANDLER_STRING_LENGTH, kCFStringEncodingUTF8);
return propertyExists;
} }
IOHIDElementRef hidElementRef = IOHIDValueGetElement(hidValueRef); // If the name property is not present, then generate a name ourselves.
NSInteger elementUsagePage = IOHIDElementGetUsagePage(hidElementRef); NSInteger elementUsagePage = IOHIDElementGetUsagePage(hidElementRef);
NSInteger elementUsage = IOHIDElementGetUsage(hidElementRef); NSInteger elementUsage = IOHIDElementGetUsage(hidElementRef);
if (elementUsage != kHIDUsage_GD_Hatswitch) if (elementUsage == kHIDUsage_GD_Hatswitch)
{ {
return inputList; strncpy(charBuffer, "Hatswitch", INPUT_HANDLER_STRING_LENGTH);
propertyExists = true;
return propertyExists;
} }
else if (elementUsagePage == kHIDPage_Button)
inputList.resize(8);
NSInteger logicalMax = IOHIDElementGetLogicalMax(hidElementRef);
NSInteger logicalValue = IOHIDValueGetIntegerValue(hidValueRef);
bool onState = true;
bool offState = false;
char elementCodeFourWay[4][256];
for (size_t i = 0; i < 4; i++)
{ {
snprintf(elementCodeFourWay[i], 256, "0x%04lX/0x%04lX/%d-FourDirection", (long)elementUsagePage, (long)elementUsage, (unsigned int)i); snprintf(charBuffer, INPUT_HANDLER_STRING_LENGTH, "Button %li", (long)elementUsage);
propertyExists = true;
return propertyExists;
} }
else if (elementUsagePage == kHIDPage_VendorDefinedStart)
const char *elementNameFourWay[4] = {
"Hatswitch - Up",
"Hatswitch - Right",
"Hatswitch - Down",
"Hatswitch - Left" };
char elementCodeEightWay[8][256];
for (size_t i = 0; i < 8; i++)
{ {
snprintf(elementCodeEightWay[i], 256, "0x%04lX/0x%04lX/%d-EightDirection", (long)elementUsagePage, (long)elementUsage, (unsigned int)i); snprintf(charBuffer, INPUT_HANDLER_STRING_LENGTH, "VendorDefined %li", (long)elementUsage);
propertyExists = true;
return propertyExists;
} }
else
const char *elementNameEightWay[8] = {
"Hatswitch - Up",
"Hatswitch - Up/Right",
"Hatswitch - Right",
"Hatswitch - Down/Right",
"Hatswitch - Down",
"Hatswitch - Down/Left",
"Hatswitch - Left",
"Hatswitch - Up/Left" };
if (logicalMax == 3)
{ {
for (size_t i = 0; i <= (size_t)logicalMax; i++) // Only look up the HID Usage Table as a last resort, since this can be relatively slow.
NSDictionary *elementUsagePageDict = (NSDictionary *)[hidUsageTable valueForKey:[NSString stringWithFormat:@"0x%04lX", (long)elementUsagePage]];
NSString *elementNameLookup = (NSString *)[elementUsagePageDict valueForKey:[NSString stringWithFormat:@"0x%04lX", (long)elementUsage]];
propertyExists = (elementNameLookup != nil);
if (propertyExists)
{ {
inputList.push_back(InputAttributesOfHIDValue(hidValueRef, elementCodeFourWay[i], elementNameFourWay[i], (i == (size_t)logicalValue) ? &onState : &offState)); strncpy(charBuffer, [elementNameLookup cStringUsingEncoding:NSUTF8StringEncoding], INPUT_HANDLER_STRING_LENGTH);
} return propertyExists;
}
else if (logicalMax == 7)
{
if (useEightDirection)
{
for (size_t i = 0; i <= (size_t)logicalMax; i++)
{
inputList.push_back(InputAttributesOfHIDValue(hidValueRef, elementCodeEightWay[i], elementNameEightWay[i], (i == (size_t)logicalValue) ? &onState : &offState));
}
}
else
{
switch (logicalValue)
{
case 0:
inputList.push_back(InputAttributesOfHIDValue(hidValueRef, elementCodeEightWay[0], elementNameEightWay[0], &onState));
inputList.push_back(InputAttributesOfHIDValue(hidValueRef, elementCodeEightWay[2], elementNameEightWay[2], &offState));
inputList.push_back(InputAttributesOfHIDValue(hidValueRef, elementCodeEightWay[4], elementNameEightWay[4], &offState));
inputList.push_back(InputAttributesOfHIDValue(hidValueRef, elementCodeEightWay[6], elementNameEightWay[6], &offState));
break;
case 1:
inputList.push_back(InputAttributesOfHIDValue(hidValueRef, elementCodeEightWay[0], elementNameEightWay[0], &onState));
inputList.push_back(InputAttributesOfHIDValue(hidValueRef, elementCodeEightWay[2], elementNameEightWay[2], &onState));
inputList.push_back(InputAttributesOfHIDValue(hidValueRef, elementCodeEightWay[4], elementNameEightWay[4], &offState));
inputList.push_back(InputAttributesOfHIDValue(hidValueRef, elementCodeEightWay[6], elementNameEightWay[6], &offState));
break;
case 2:
inputList.push_back(InputAttributesOfHIDValue(hidValueRef, elementCodeEightWay[0], elementNameEightWay[0], &offState));
inputList.push_back(InputAttributesOfHIDValue(hidValueRef, elementCodeEightWay[2], elementNameEightWay[2], &onState));
inputList.push_back(InputAttributesOfHIDValue(hidValueRef, elementCodeEightWay[4], elementNameEightWay[4], &offState));
inputList.push_back(InputAttributesOfHIDValue(hidValueRef, elementCodeEightWay[6], elementNameEightWay[6], &offState));
break;
case 3:
inputList.push_back(InputAttributesOfHIDValue(hidValueRef, elementCodeEightWay[0], elementNameEightWay[0], &offState));
inputList.push_back(InputAttributesOfHIDValue(hidValueRef, elementCodeEightWay[2], elementNameEightWay[2], &onState));
inputList.push_back(InputAttributesOfHIDValue(hidValueRef, elementCodeEightWay[4], elementNameEightWay[4], &onState));
inputList.push_back(InputAttributesOfHIDValue(hidValueRef, elementCodeEightWay[6], elementNameEightWay[6], &offState));
break;
case 4:
inputList.push_back(InputAttributesOfHIDValue(hidValueRef, elementCodeEightWay[0], elementNameEightWay[0], &offState));
inputList.push_back(InputAttributesOfHIDValue(hidValueRef, elementCodeEightWay[2], elementNameEightWay[2], &offState));
inputList.push_back(InputAttributesOfHIDValue(hidValueRef, elementCodeEightWay[4], elementNameEightWay[4], &onState));
inputList.push_back(InputAttributesOfHIDValue(hidValueRef, elementCodeEightWay[6], elementNameEightWay[6], &offState));
break;
case 5:
inputList.push_back(InputAttributesOfHIDValue(hidValueRef, elementCodeEightWay[0], elementNameEightWay[0], &offState));
inputList.push_back(InputAttributesOfHIDValue(hidValueRef, elementCodeEightWay[2], elementNameEightWay[2], &offState));
inputList.push_back(InputAttributesOfHIDValue(hidValueRef, elementCodeEightWay[4], elementNameEightWay[4], &onState));
inputList.push_back(InputAttributesOfHIDValue(hidValueRef, elementCodeEightWay[6], elementNameEightWay[6], &onState));
break;
case 6:
inputList.push_back(InputAttributesOfHIDValue(hidValueRef, elementCodeEightWay[0], elementNameEightWay[0], &offState));
inputList.push_back(InputAttributesOfHIDValue(hidValueRef, elementCodeEightWay[2], elementNameEightWay[2], &offState));
inputList.push_back(InputAttributesOfHIDValue(hidValueRef, elementCodeEightWay[4], elementNameEightWay[4], &offState));
inputList.push_back(InputAttributesOfHIDValue(hidValueRef, elementCodeEightWay[6], elementNameEightWay[6], &onState));
break;
case 7:
inputList.push_back(InputAttributesOfHIDValue(hidValueRef, elementCodeEightWay[0], elementNameEightWay[0], &onState));
inputList.push_back(InputAttributesOfHIDValue(hidValueRef, elementCodeEightWay[2], elementNameEightWay[2], &offState));
inputList.push_back(InputAttributesOfHIDValue(hidValueRef, elementCodeEightWay[4], elementNameEightWay[4], &offState));
inputList.push_back(InputAttributesOfHIDValue(hidValueRef, elementCodeEightWay[6], elementNameEightWay[6], &onState));
break;
default:
inputList.push_back(InputAttributesOfHIDValue(hidValueRef, elementCodeEightWay[0], elementNameEightWay[0], &offState));
inputList.push_back(InputAttributesOfHIDValue(hidValueRef, elementCodeEightWay[2], elementNameEightWay[2], &offState));
inputList.push_back(InputAttributesOfHIDValue(hidValueRef, elementCodeEightWay[4], elementNameEightWay[4], &offState));
inputList.push_back(InputAttributesOfHIDValue(hidValueRef, elementCodeEightWay[6], elementNameEightWay[6], &offState));
break;
}
} }
} }
return inputList; return propertyExists;
} }
bool GetOnStateFromHIDValueRef(IOHIDValueRef hidValueRef) bool InputDeviceCodeFromHIDDevice(const IOHIDDeviceRef hidDeviceRef, char *charBuffer)
{
bool onState = false;
if (hidValueRef == nil)
{
return onState;
}
const IOHIDElementRef hidElementRef = IOHIDValueGetElement(hidValueRef);
const NSInteger logicalValue = IOHIDValueGetIntegerValue(hidValueRef);
const NSInteger logicalMin = IOHIDElementGetLogicalMin(hidElementRef);
const NSInteger logicalMax = IOHIDElementGetLogicalMax(hidElementRef);
const NSInteger lowerThreshold = ((logicalMax - logicalMin) / 4) + logicalMin;
const NSInteger upperThreshold = (((logicalMax - logicalMin) * 3) / 4) + logicalMin;
const NSInteger elementType = IOHIDElementGetType(hidElementRef);
switch (elementType)
{
case kIOHIDElementTypeInput_Misc:
{
if ( (logicalMin == 0 && logicalMax == 1 && logicalValue == 1) ||
(logicalValue <= lowerThreshold || logicalValue >= upperThreshold) )
{
onState = true;
}
break;
}
case kIOHIDElementTypeInput_Button:
{
if (logicalValue == 1)
{
onState = true;
}
break;
}
case kIOHIDElementTypeInput_Axis:
{
if ( (logicalMin == 0 && logicalMax == 1 && logicalValue == 1) ||
(logicalValue <= lowerThreshold || logicalValue >= upperThreshold) )
{
onState = true;
}
break;
}
default:
break;
}
return onState;
}
void InputDeviceCodeFromHIDDevice(const IOHIDDeviceRef hidDeviceRef, char *charBuffer)
{ {
CFNumberRef cfVendorIDNumber = (CFNumberRef)IOHIDDeviceGetProperty(hidDeviceRef, CFSTR(kIOHIDVendorIDKey)); CFNumberRef cfVendorIDNumber = (CFNumberRef)IOHIDDeviceGetProperty(hidDeviceRef, CFSTR(kIOHIDVendorIDKey));
SInt32 vendorID = 0; SInt32 vendorID = 0;
@ -781,19 +742,25 @@ void InputDeviceCodeFromHIDDevice(const IOHIDDeviceRef hidDeviceRef, char *charB
CFStringGetCString(cfDeviceCode, cfDeviceCodeBuf, 256, kCFStringEncodingUTF8); CFStringGetCString(cfDeviceCode, cfDeviceCodeBuf, 256, kCFStringEncodingUTF8);
snprintf(charBuffer, INPUT_HANDLER_STRING_LENGTH, "%d/%d/%s", (int)vendorID, (int)productID, cfDeviceCodeBuf); snprintf(charBuffer, INPUT_HANDLER_STRING_LENGTH, "%d/%d/%s", (int)vendorID, (int)productID, cfDeviceCodeBuf);
} }
return true;
} }
void InputDeviceNameFromHIDDevice(const IOHIDDeviceRef hidDeviceRef, char *charBuffer, const char *altName) bool InputDeviceNameFromHIDDevice(const IOHIDDeviceRef hidDeviceRef, char *charBuffer)
{ {
CFStringRef cfDeviceName = (CFStringRef)IOHIDDeviceGetProperty(hidDeviceRef, CFSTR(kIOHIDProductKey)); CFStringRef cfDeviceName = (CFStringRef)IOHIDDeviceGetProperty(hidDeviceRef, CFSTR(kIOHIDProductKey));
if (cfDeviceName == nil) bool propertyExists = (cfDeviceName != nil);
{
strncpy(charBuffer, (altName != NULL) ? altName : "Unknown Device", INPUT_HANDLER_STRING_LENGTH); if (propertyExists)
}
else
{ {
CFStringGetCString(cfDeviceName, charBuffer, INPUT_HANDLER_STRING_LENGTH, kCFStringEncodingUTF8); CFStringGetCString(cfDeviceName, charBuffer, INPUT_HANDLER_STRING_LENGTH, kCFStringEncodingUTF8);
} }
else
{
strncpy(charBuffer, "Unknown Device", INPUT_HANDLER_STRING_LENGTH);
}
return propertyExists;
} }
size_t ClearHIDQueue(const IOHIDQueueRef hidQueue) size_t ClearHIDQueue(const IOHIDQueueRef hidQueue)
@ -837,7 +804,7 @@ void HandleQueueValueAvailableCallback(void *inContext, IOReturn inResult, void
if (target != nil) if (target != nil)
{ {
NSAutoreleasePool *tempPool = [[NSAutoreleasePool alloc] init]; NSAutoreleasePool *tempPool = [[NSAutoreleasePool alloc] init];
[[hidManager target] handleHIDQueue:hidQueue]; [[hidManager target] handleHIDQueue:hidQueue hidManager:hidManager];
[tempPool release]; [tempPool release];
} }
else else
@ -1162,9 +1129,9 @@ static std::tr1::unordered_map<unsigned short, std::string> keyboardNameTable; /
CommandAttributes cmdPianoHighC = NewCommandAttributesForDSControl("Piano: High C", DSControllerState_Piano_HighC); CommandAttributes cmdPianoHighC = NewCommandAttributesForDSControl("Piano: High C", DSControllerState_Piano_HighC);
CommandAttributes cmdPaddle = NewCommandAttributesForDSControl("Paddle", DSControllerState_Paddle); CommandAttributes cmdPaddle = NewCommandAttributesForDSControl("Paddle", DSControllerState_Paddle);
cmdPaddle.useInputForScalar = false; cmdPaddle.allowAnalogInput = true;
cmdPaddle.intValue[1] = 0; cmdPaddle.intValue[1] = 0;
cmdPaddle.floatValue[0] = 0.0f; cmdPaddle.floatValue[0] = 10.0f;
CommandAttributes cmdLoadEmuSaveStateSlot = NewCommandAttributesForSelector("Load State Slot", commandSelector["Load State Slot"]); CommandAttributes cmdLoadEmuSaveStateSlot = NewCommandAttributesForSelector("Load State Slot", commandSelector["Load State Slot"]);
CommandAttributes cmdSaveEmuSaveStateSlot = NewCommandAttributesForSelector("Save State Slot", commandSelector["Save State Slot"]); CommandAttributes cmdSaveEmuSaveStateSlot = NewCommandAttributesForSelector("Save State Slot", commandSelector["Save State Slot"]);
@ -1373,6 +1340,7 @@ static std::tr1::unordered_map<unsigned short, std::string> keyboardNameTable; /
[NSString stringWithCString:inputAttr->elementCode encoding:NSUTF8StringEncoding], [NSString stringWithCString:inputAttr->elementCode encoding:NSUTF8StringEncoding],
[NSString stringWithCString:inputAttr->elementName encoding:NSUTF8StringEncoding]); [NSString stringWithCString:inputAttr->elementName encoding:NSUTF8StringEncoding]);
[deviceInfo setValue:[NSNumber numberWithBool:(cmdAttr->allowAnalogInput) ? inputAttr->isAnalog : NO] forKey:@"isInputAnalog"];
[self addMappingUsingDeviceInfoDictionary:deviceInfo commandAttributes:cmdAttr]; [self addMappingUsingDeviceInfoDictionary:deviceInfo commandAttributes:cmdAttr];
} }
@ -1740,22 +1708,23 @@ static std::tr1::unordered_map<unsigned short, std::string> keyboardNameTable; /
} }
else if (strncmp(commandTag, "Paddle", INPUT_HANDLER_STRING_LENGTH) == 0) else if (strncmp(commandTag, "Paddle", INPUT_HANDLER_STRING_LENGTH) == 0)
{ {
const BOOL useInputForScalar = [(NSNumber *)[deviceInfo valueForKey:@"useInputForScalar"] boolValue]; const BOOL isInputAnalog = [(NSNumber *)[deviceInfo valueForKey:@"isInputAnalog"] boolValue];
if (useInputForScalar) if (isInputAnalog)
{ {
inputSummary = @"Direct Control"; const float paddleSensitivity = [(NSNumber *)[deviceInfo valueForKey:@"floatValue0"] floatValue];
inputSummary = [NSString stringWithFormat:@"Paddle Sensitivity: %1.1f", paddleSensitivity];
} }
else else
{ {
const NSInteger paddleRelativeAdjustment = [(NSNumber *)[deviceInfo valueForKey:@"intValue1"] integerValue]; const NSInteger paddleAdjust = [(NSNumber *)[deviceInfo valueForKey:@"intValue1"] integerValue];
if (paddleRelativeAdjustment > 0) if (paddleAdjust > 0)
{ {
inputSummary = [NSString stringWithFormat:@"Paddle Adjust: +%ld", (long)paddleRelativeAdjustment]; inputSummary = [NSString stringWithFormat:@"Paddle Adjust: +%ld", (long)paddleAdjust];
} }
else else
{ {
inputSummary = [NSString stringWithFormat:@"Paddle Adjust: %ld", (long)paddleRelativeAdjustment]; inputSummary = [NSString stringWithFormat:@"Paddle Adjust: %ld", (long)paddleAdjust];
} }
} }
} }
@ -1958,6 +1927,7 @@ CommandAttributes NewDefaultCommandAttributes(const char *commandTag)
cmdAttr.useInputForFloatCoord = false; cmdAttr.useInputForFloatCoord = false;
cmdAttr.useInputForScalar = false; cmdAttr.useInputForScalar = false;
cmdAttr.useInputForSender = false; cmdAttr.useInputForSender = false;
cmdAttr.allowAnalogInput = false;
return cmdAttr; return cmdAttr;
} }
@ -2001,6 +1971,7 @@ void UpdateCommandAttributesWithDeviceInfoDictionary(CommandAttributes *cmdAttr,
NSNumber *useInputForFloatCoord = (NSNumber *)[deviceInfo valueForKey:@"useInputForFloatCoord"]; NSNumber *useInputForFloatCoord = (NSNumber *)[deviceInfo valueForKey:@"useInputForFloatCoord"];
NSNumber *useInputForScalar = (NSNumber *)[deviceInfo valueForKey:@"useInputForScalar"]; NSNumber *useInputForScalar = (NSNumber *)[deviceInfo valueForKey:@"useInputForScalar"];
NSNumber *useInputForSender = (NSNumber *)[deviceInfo valueForKey:@"useInputForSender"]; NSNumber *useInputForSender = (NSNumber *)[deviceInfo valueForKey:@"useInputForSender"];
NSNumber *isInputAnalog = (NSNumber *)[deviceInfo valueForKey:@"isInputAnalog"];
if (intValue0 != nil) cmdAttr->intValue[0] = [intValue0 intValue]; if (intValue0 != nil) cmdAttr->intValue[0] = [intValue0 intValue];
if (intValue1 != nil) cmdAttr->intValue[1] = [intValue1 intValue]; if (intValue1 != nil) cmdAttr->intValue[1] = [intValue1 intValue];
@ -2014,6 +1985,7 @@ void UpdateCommandAttributesWithDeviceInfoDictionary(CommandAttributes *cmdAttr,
if (useInputForFloatCoord != nil) cmdAttr->useInputForFloatCoord = [useInputForFloatCoord boolValue]; if (useInputForFloatCoord != nil) cmdAttr->useInputForFloatCoord = [useInputForFloatCoord boolValue];
if (useInputForScalar != nil) cmdAttr->useInputForScalar = [useInputForScalar boolValue]; if (useInputForScalar != nil) cmdAttr->useInputForScalar = [useInputForScalar boolValue];
if (useInputForSender != nil) cmdAttr->useInputForSender = [useInputForSender boolValue]; if (useInputForSender != nil) cmdAttr->useInputForSender = [useInputForSender boolValue];
if (isInputAnalog != nil) cmdAttr->allowAnalogInput = [isInputAnalog boolValue];
cmdAttr->object[0] = object0; cmdAttr->object[0] = object0;
cmdAttr->object[1] = object1; cmdAttr->object[1] = object1;
@ -2043,7 +2015,7 @@ NSMutableDictionary* DeviceInfoDictionaryWithCommandAttributes(const CommandAttr
deviceName, @"deviceName", deviceName, @"deviceName",
elementCode, @"elementCode", elementCode, @"elementCode",
elementName, @"elementName", elementName, @"elementName",
[NSNumber numberWithBool:NO], @"isElementAnalog", [NSNumber numberWithBool:cmdAttr->allowAnalogInput], @"isInputAnalog",
deviceInfoSummary, @"deviceInfoSummary", deviceInfoSummary, @"deviceInfoSummary",
@"", @"inputSettingsSummary", @"", @"inputSettingsSummary",
[NSNumber numberWithInt:cmdAttr->intValue[0]], @"intValue0", [NSNumber numberWithInt:cmdAttr->intValue[0]], @"intValue0",
@ -2069,7 +2041,7 @@ NSMutableDictionary* DeviceInfoDictionaryWithCommandAttributes(const CommandAttr
return newDeviceInfo; return newDeviceInfo;
} }
InputAttributesList InputManagerEncodeHIDQueue(const IOHIDQueueRef hidQueue) InputAttributesList InputManagerEncodeHIDQueue(const IOHIDQueueRef hidQueue, InputManager *inputManager, bool forceDigitalInput)
{ {
InputAttributesList inputList; InputAttributesList inputList;
if (hidQueue == nil) if (hidQueue == nil)
@ -2084,21 +2056,11 @@ InputAttributesList InputManagerEncodeHIDQueue(const IOHIDQueueRef hidQueue)
{ {
break; break;
} }
InputAttributesList hidInputList = InputListFromHatSwitchValue(hidValueRef, false); InputAttributesList hidInputList = InputListFromHIDValue(hidValueRef, inputManager, forceDigitalInput);
if (hidInputList.empty())
{
hidInputList = InputListFromHIDValue(hidValueRef);
}
const size_t hidInputCount = hidInputList.size(); const size_t hidInputCount = hidInputList.size();
for (size_t i = 0; i < hidInputCount; i++) for (size_t i = 0; i < hidInputCount; i++)
{ {
if (hidInputList[i].deviceCode[0] == '\0' || hidInputList[i].elementCode[0] == '\0')
{
continue;
}
inputList.push_back(hidInputList[i]); inputList.push_back(hidInputList[i]);
} }
@ -2125,6 +2087,7 @@ InputAttributes InputManagerEncodeKeyboardInput(const unsigned short keyCode, BO
snprintf(inputAttr.elementCode, INPUT_HANDLER_STRING_LENGTH, "%d", keyCode); snprintf(inputAttr.elementCode, INPUT_HANDLER_STRING_LENGTH, "%d", keyCode);
strncpy(inputAttr.elementName, (elementName.empty()) ? inputAttr.elementCode : elementName.c_str(), INPUT_HANDLER_STRING_LENGTH); strncpy(inputAttr.elementName, (elementName.empty()) ? inputAttr.elementCode : elementName.c_str(), INPUT_HANDLER_STRING_LENGTH);
inputAttr.isAnalog = false;
inputAttr.state = (keyPressed) ? INPUT_ATTRIBUTE_STATE_ON : INPUT_ATTRIBUTE_STATE_OFF; inputAttr.state = (keyPressed) ? INPUT_ATTRIBUTE_STATE_ON : INPUT_ATTRIBUTE_STATE_OFF;
inputAttr.intCoordX = 0; inputAttr.intCoordX = 0;
inputAttr.intCoordY = 0; inputAttr.intCoordY = 0;
@ -2162,6 +2125,7 @@ InputAttributes InputManagerEncodeMouseButtonInput(const NSInteger buttonNumber,
break; break;
} }
inputAttr.isAnalog = false;
inputAttr.state = (buttonPressed) ? INPUT_ATTRIBUTE_STATE_ON : INPUT_ATTRIBUTE_STATE_OFF; inputAttr.state = (buttonPressed) ? INPUT_ATTRIBUTE_STATE_ON : INPUT_ATTRIBUTE_STATE_OFF;
inputAttr.intCoordX = (int32_t)touchLoc.x; inputAttr.intCoordX = (int32_t)touchLoc.x;
inputAttr.intCoordY = (int32_t)touchLoc.y; inputAttr.intCoordY = (int32_t)touchLoc.y;
@ -2181,6 +2145,7 @@ InputAttributes InputManagerEncodeIBAction(const SEL theSelector, id sender)
strncpy(inputAttr.elementCode, sel_getName(theSelector), INPUT_HANDLER_STRING_LENGTH); strncpy(inputAttr.elementCode, sel_getName(theSelector), INPUT_HANDLER_STRING_LENGTH);
strncpy(inputAttr.elementName, inputAttr.elementCode, INPUT_HANDLER_STRING_LENGTH); strncpy(inputAttr.elementName, inputAttr.elementCode, INPUT_HANDLER_STRING_LENGTH);
inputAttr.isAnalog = false;
inputAttr.state = INPUT_ATTRIBUTE_STATE_ON; inputAttr.state = INPUT_ATTRIBUTE_STATE_ON;
inputAttr.intCoordX = 0; inputAttr.intCoordX = 0;
inputAttr.intCoordY = 0; inputAttr.intCoordY = 0;

View File

@ -130,7 +130,5 @@
#pragma mark - #pragma mark -
#pragma mark Paddle #pragma mark Paddle
- (void) setPaddleDirectWithScalar:(float)scalar;
- (void) setPaddleRelativeWithInteger:(NSInteger)value;
@end @end

View File

@ -664,29 +664,6 @@
#pragma mark - #pragma mark -
#pragma mark Paddle #pragma mark Paddle
- (void) setPaddleDirectWithScalar:(float)scalar
{
// Clamp the input value.
if (scalar < -1.0f)
{
scalar = -1.0f;
}
if (scalar > 1.0f)
{
scalar = 1.0f;
}
// Normalize the input value for the paddle.
const float paddleValue = 256.0f * scalar;
[[self deviceManager] setPaddleValue:(UInt16)paddleValue];
}
- (void) setPaddleRelativeWithInteger:(NSInteger)value
{
NSInteger paddleValue = [[self deviceManager] paddleValue] + value;
[[self deviceManager] setPaddleValue:(UInt16)paddleValue];
}
#pragma mark - #pragma mark -
#pragma mark NSTableViewDelegate Protocol #pragma mark NSTableViewDelegate Protocol

View File

@ -416,35 +416,33 @@
} }
#pragma mark InputHIDManagerTarget Protocol #pragma mark InputHIDManagerTarget Protocol
- (BOOL) handleHIDQueue:(IOHIDQueueRef)hidQueue - (BOOL) handleHIDQueue:(IOHIDQueueRef)hidQueue hidManager:(InputHIDManager *)hidManager
{ {
BOOL isHandled = NO; BOOL isHandled = NO;
NSString *cmdTagTarget = [self configInputTargetID];
if ([self configInputTargetID] == nil) if (cmdTagTarget == nil)
{ {
ClearHIDQueue(hidQueue); ClearHIDQueue(hidQueue);
return isHandled; return isHandled;
} }
InputAttributesList inputList = InputManagerEncodeHIDQueue(hidQueue); CommandAttributes cmdAttr = [[hidManager inputManager] defaultCommandAttributesForCommandTag:[cmdTagTarget cStringUsingEncoding:NSUTF8StringEncoding]];
bool forceDigitalInput = !cmdAttr.allowAnalogInput;
InputAttributesList inputList = InputManagerEncodeHIDQueue(hidQueue, [hidManager inputManager], forceDigitalInput);
const size_t inputCount = inputList.size(); const size_t inputCount = inputList.size();
for (size_t i = 0; i < inputCount; i++) for (size_t i = 0; i < inputCount; i++)
{ {
const InputAttributes &inputAttr = inputList[i]; const InputAttributes &inputAttr = inputList[i];
char inputKey[INPUT_HANDLER_STRING_LENGTH*2]; NSString *inputKey = [NSString stringWithFormat:@"%s:%s", inputAttr.deviceCode, inputAttr.elementCode];
strlcpy(inputKey, inputAttr.deviceCode, INPUT_HANDLER_STRING_LENGTH*2); NSDate *inputOnDate = [configInputList valueForKey:inputKey];
strlcat(inputKey, ":", INPUT_HANDLER_STRING_LENGTH*2);
strlcat(inputKey, inputAttr.elementCode, INPUT_HANDLER_STRING_LENGTH*2);
NSString *inputKeyStr = [NSString stringWithCString:inputKey encoding:NSUTF8StringEncoding];
NSDate *inputOnDate = [configInputList valueForKey:inputKeyStr];
if (inputAttr.state == INPUT_ATTRIBUTE_STATE_ON) if (inputAttr.state == INPUT_ATTRIBUTE_STATE_ON)
{ {
if (inputOnDate == nil) if (inputOnDate == nil)
{ {
[configInputList setValue:[NSDate date] forKey:inputKeyStr]; [configInputList setValue:[NSDate date] forKey:inputKey];
} }
} }
else else
@ -454,11 +452,11 @@
if (([inputOnDate timeIntervalSinceNow] * -1.0) < INPUT_HOLD_TIME) if (([inputOnDate timeIntervalSinceNow] * -1.0) < INPUT_HOLD_TIME)
{ {
// If the button isn't held for at least INPUT_HOLD_TIME seconds, then reject the input. // If the button isn't held for at least INPUT_HOLD_TIME seconds, then reject the input.
[configInputList setValue:nil forKey:inputKeyStr]; [configInputList setValue:nil forKey:inputKey];
} }
else else
{ {
isHandled = [self addMappingUsingInputAttributes:&inputAttr commandTag:[self configInputTargetID]]; isHandled = [self addMappingUsingInputAttributes:&inputAttr commandTag:cmdTagTarget];
break; break;
} }
} }

View File

@ -149,6 +149,9 @@ extern ADDON_CFLASH_MODE CFlash_Mode;
extern std::string CFlash_Path; extern std::string CFlash_Path;
inline bool CFlash_IsUsingPath() { return CFlash_Mode==ADDON_CFLASH_MODE_Path || CFlash_Mode==ADDON_CFLASH_MODE_RomPath; } inline bool CFlash_IsUsingPath() { return CFlash_Mode==ADDON_CFLASH_MODE_Path || CFlash_Mode==ADDON_CFLASH_MODE_RomPath; }
u16 Paddle_GetValue();
void Paddle_SetValue(u16 theValue);
extern void guitarGrip_setKey(bool green, bool red, bool yellow, bool blue); // Guitar grip keys extern void guitarGrip_setKey(bool green, bool red, bool yellow, bool blue); // Guitar grip keys
extern void piano_setKey(bool c, bool cs, bool d, bool ds, bool e, bool f, bool fs, bool g, bool gs, bool a, bool as, bool b, bool hic); //piano keys extern void piano_setKey(bool c, bool cs, bool d, bool ds, bool e, bool f, bool fs, bool g, bool gs, bool a, bool as, bool b, bool hic); //piano keys
#endif //__SLOT_H__ #endif //__SLOT_H__