Joystick hat support in Cocoa
This commit is contained in:
parent
66b814a226
commit
b2397a2e7a
@ -4,5 +4,6 @@
|
|||||||
|
|
||||||
- (void) joystick:(NSString *)joystick_name button: (unsigned)button changedState: (bool) state;
|
- (void) joystick:(NSString *)joystick_name button: (unsigned)button changedState: (bool) state;
|
||||||
- (void) joystick:(NSString *)joystick_name axis: (unsigned)axis movedTo: (signed) value;
|
- (void) joystick:(NSString *)joystick_name axis: (unsigned)axis movedTo: (signed) value;
|
||||||
|
- (void) joystick:(NSString *)joystick_name hat: (unsigned)hat changedState: (int8_t) value;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
@ -309,6 +309,42 @@
|
|||||||
[self advanceConfigurationStateMachine];
|
[self advanceConfigurationStateMachine];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void) joystick:(NSString *)joystick_name hat: (unsigned)hat changedState: (int8_t) state
|
||||||
|
{
|
||||||
|
/* Hats are always mapped to the D-pad, ignore them on non-Dpad keys and skip the D-pad configuration if used*/
|
||||||
|
if (!state) return;
|
||||||
|
if (joystick_configuration_state == -1) return;
|
||||||
|
if (joystick_configuration_state > GBDown) return;
|
||||||
|
if (!joystick_being_configured) {
|
||||||
|
joystick_being_configured = joystick_name;
|
||||||
|
}
|
||||||
|
else if (![joystick_being_configured isEqualToString:joystick_name]) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
NSMutableDictionary *all_mappings = [[[NSUserDefaults standardUserDefaults] dictionaryForKey:@"GBJoypadMappings"] mutableCopy];
|
||||||
|
|
||||||
|
if (!all_mappings) {
|
||||||
|
all_mappings = [[NSMutableDictionary alloc] init];
|
||||||
|
}
|
||||||
|
|
||||||
|
NSMutableDictionary *mapping = [[all_mappings objectForKey:joystick_name] mutableCopy];
|
||||||
|
|
||||||
|
if (!mapping) {
|
||||||
|
mapping = [[NSMutableDictionary alloc] init];
|
||||||
|
}
|
||||||
|
|
||||||
|
for (joystick_configuration_state = 0;; joystick_configuration_state++) {
|
||||||
|
[mapping removeObjectForKey:GBButtonNames[joystick_configuration_state]];
|
||||||
|
if (joystick_configuration_state == GBDown) break;
|
||||||
|
}
|
||||||
|
|
||||||
|
all_mappings[joystick_name] = mapping;
|
||||||
|
[[NSUserDefaults standardUserDefaults] setObject:all_mappings forKey:@"GBJoypadMappings"];
|
||||||
|
[self refreshJoypadMenu:nil];
|
||||||
|
[self advanceConfigurationStateMachine];
|
||||||
|
}
|
||||||
|
|
||||||
- (NSButton *)aspectRatioCheckbox
|
- (NSButton *)aspectRatioCheckbox
|
||||||
{
|
{
|
||||||
return _aspectRatioCheckbox;
|
return _aspectRatioCheckbox;
|
||||||
|
@ -341,6 +341,27 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void) joystick:(NSString *)joystick_name hat: (unsigned)hat changedState: (int8_t) state
|
||||||
|
{
|
||||||
|
unsigned player_count = GB_get_player_count(_gb);
|
||||||
|
|
||||||
|
UpdateSystemActivity(UsrActivity);
|
||||||
|
for (unsigned player = 0; player < player_count; player++) {
|
||||||
|
NSString *preferred_joypad = [[[NSUserDefaults standardUserDefaults] dictionaryForKey:@"GBDefaultJoypads"]
|
||||||
|
objectForKey:[NSString stringWithFormat:@"%u", player]];
|
||||||
|
if (player_count != 1 && // Single player, accpet inputs from all joypads
|
||||||
|
!(player == 0 && !preferred_joypad) && // Multiplayer, but player 1 has no joypad configured, so it takes inputs from all joypads
|
||||||
|
![preferred_joypad isEqualToString:joystick_name]) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
assert(state + 1 < 9);
|
||||||
|
/* - N NE E SE S SW W NW */
|
||||||
|
GB_set_key_state_for_player(_gb, GB_KEY_UP, player, (bool []){0, 1, 1, 0, 0, 0, 0, 0, 1}[state + 1]);
|
||||||
|
GB_set_key_state_for_player(_gb, GB_KEY_RIGHT, player, (bool []){0, 0, 1, 1, 1, 0, 0, 0, 0}[state + 1]);
|
||||||
|
GB_set_key_state_for_player(_gb, GB_KEY_DOWN, player, (bool []){0, 0, 0, 0, 1, 1, 1, 0, 0}[state + 1]);
|
||||||
|
GB_set_key_state_for_player(_gb, GB_KEY_LEFT, player, (bool []){0, 0, 0, 0, 0, 0, 1, 1, 1}[state + 1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
- (BOOL)acceptsFirstResponder
|
- (BOOL)acceptsFirstResponder
|
||||||
{
|
{
|
||||||
|
@ -53,6 +53,9 @@ struct _SDL_Joystick
|
|||||||
int nbuttons; /* Number of buttons on the joystick */
|
int nbuttons; /* Number of buttons on the joystick */
|
||||||
uint8_t *buttons; /* Current button states */
|
uint8_t *buttons; /* Current button states */
|
||||||
|
|
||||||
|
int nhats;
|
||||||
|
uint8_t *hats;
|
||||||
|
|
||||||
struct joystick_hwdata *hwdata; /* Driver dependent information */
|
struct joystick_hwdata *hwdata; /* Driver dependent information */
|
||||||
|
|
||||||
int ref_count; /* Reference count for multiple opens */
|
int ref_count; /* Reference count for multiple opens */
|
||||||
@ -93,11 +96,13 @@ struct joystick_hwdata
|
|||||||
|
|
||||||
int axes; /* number of axis (calculated, not reported by device) */
|
int axes; /* number of axis (calculated, not reported by device) */
|
||||||
int buttons; /* number of buttons (calculated, not reported by device) */
|
int buttons; /* number of buttons (calculated, not reported by device) */
|
||||||
|
int hats;
|
||||||
int elements; /* number of total elements (should be total of above) (calculated, not reported by device) */
|
int elements; /* number of total elements (should be total of above) (calculated, not reported by device) */
|
||||||
|
|
||||||
recElement *firstAxis;
|
recElement *firstAxis;
|
||||||
recElement *firstButton;
|
recElement *firstButton;
|
||||||
|
recElement *firstHat;
|
||||||
|
|
||||||
bool removed;
|
bool removed;
|
||||||
|
|
||||||
int instance_id;
|
int instance_id;
|
||||||
@ -178,6 +183,30 @@ void SDL_PrivateJoystickButton(SDL_Joystick *joystick, uint8_t button, uint8_t s
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SDL_PrivateJoystickHat(SDL_Joystick *joystick, uint8_t hat, uint8_t state)
|
||||||
|
{
|
||||||
|
|
||||||
|
/* Make sure we're not getting garbage or duplicate events */
|
||||||
|
if (hat >= joystick->nhats) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (state == joystick->hats[hat]) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Update internal joystick state */
|
||||||
|
joystick->hats[hat] = state;
|
||||||
|
|
||||||
|
NSResponder<GBJoystickListener> *responder = (typeof(responder)) [[NSApp keyWindow] firstResponder];
|
||||||
|
while (responder) {
|
||||||
|
if ([responder respondsToSelector:@selector(joystick:button:changedState:)]) {
|
||||||
|
[responder joystick:@(joystick->name) hat:hat changedState:state];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
responder = (typeof(responder)) [responder nextResponder];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
FreeElementList(recElement *pElement)
|
FreeElementList(recElement *pElement)
|
||||||
{
|
{
|
||||||
@ -202,6 +231,7 @@ FreeDevice(recDevice *removeDevice)
|
|||||||
/* free element lists */
|
/* free element lists */
|
||||||
FreeElementList(removeDevice->firstAxis);
|
FreeElementList(removeDevice->firstAxis);
|
||||||
FreeElementList(removeDevice->firstButton);
|
FreeElementList(removeDevice->firstButton);
|
||||||
|
FreeElementList(removeDevice->firstHat);
|
||||||
|
|
||||||
free(removeDevice);
|
free(removeDevice);
|
||||||
}
|
}
|
||||||
@ -315,6 +345,15 @@ AddHIDElement(const void *value, void *parameter)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case kHIDUsage_GD_Hatswitch:
|
||||||
|
if (!ElementAlreadyAdded(cookie, pDevice->firstHat)) {
|
||||||
|
element = (recElement *) calloc(1, sizeof (recElement));
|
||||||
|
if (element) {
|
||||||
|
pDevice->hats++;
|
||||||
|
headElement = &(pDevice->firstHat);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case kHIDUsage_GD_DPadUp:
|
case kHIDUsage_GD_DPadUp:
|
||||||
case kHIDUsage_GD_DPadDown:
|
case kHIDUsage_GD_DPadDown:
|
||||||
@ -535,6 +574,27 @@ SDL_SYS_JoystickUpdate(SDL_Joystick * joystick)
|
|||||||
element = element->pNext;
|
element = element->pNext;
|
||||||
++i;
|
++i;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
element = device->firstHat;
|
||||||
|
i = 0;
|
||||||
|
while (element) {
|
||||||
|
signed range = (element->max - element->min + 1);
|
||||||
|
value = GetHIDElementState(device, element) - element->min;
|
||||||
|
if (range == 4) { /* 4 position hatswitch - scale up value */
|
||||||
|
value *= 2;
|
||||||
|
} else if (range != 8) { /* Neither a 4 nor 8 positions - fall back to default position (centered) */
|
||||||
|
value = -1;
|
||||||
|
}
|
||||||
|
if ((unsigned)value >= 8) {
|
||||||
|
value = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_PrivateJoystickHat(joystick, i, value);
|
||||||
|
|
||||||
|
element = element->pNext;
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void JoystickInputCallback(
|
static void JoystickInputCallback(
|
||||||
@ -579,13 +639,17 @@ JoystickDeviceWasAddedCallback(void *ctx, IOReturn res, void *sender, IOHIDDevic
|
|||||||
|
|
||||||
joystick->naxes = device->axes;
|
joystick->naxes = device->axes;
|
||||||
joystick->nbuttons = device->buttons;
|
joystick->nbuttons = device->buttons;
|
||||||
|
joystick->nhats = device->hats;
|
||||||
|
|
||||||
if (joystick->naxes > 0) {
|
if (joystick->naxes > 0) {
|
||||||
joystick->axes = (SDL_JoystickAxisInfo *) calloc(joystick->naxes, sizeof(SDL_JoystickAxisInfo));
|
joystick->axes = (SDL_JoystickAxisInfo *) calloc(joystick->naxes, sizeof(SDL_JoystickAxisInfo));
|
||||||
}
|
}
|
||||||
if (joystick->nbuttons > 0) {
|
if (joystick->nbuttons > 0) {
|
||||||
joystick->buttons = (uint8_t *) calloc(joystick->nbuttons, 1);
|
joystick->buttons = (uint8_t *) calloc(joystick->nbuttons, 1);
|
||||||
}
|
}
|
||||||
|
if (joystick->nhats > 0) {
|
||||||
|
joystick->hats = (uint8_t *) calloc(joystick->nhats, 1);
|
||||||
|
}
|
||||||
|
|
||||||
/* Get notified when this device is disconnected. */
|
/* Get notified when this device is disconnected. */
|
||||||
IOHIDDeviceRegisterRemovalCallback(ioHIDDeviceObject, JoystickDeviceWasRemovedCallback, device);
|
IOHIDDeviceRegisterRemovalCallback(ioHIDDeviceObject, JoystickDeviceWasRemovedCallback, device);
|
||||||
|
Loading…
Reference in New Issue
Block a user