Joystick hat support in Cocoa

This commit is contained in:
Lior Halphon 2019-06-14 18:06:15 +03:00
parent 66b814a226
commit b2397a2e7a
4 changed files with 124 additions and 2 deletions

View File

@ -4,5 +4,6 @@
- (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 hat: (unsigned)hat changedState: (int8_t) value;
@end

View File

@ -309,6 +309,42 @@
[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
{
return _aspectRatioCheckbox;

View File

@ -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
{

View File

@ -53,6 +53,9 @@ struct _SDL_Joystick
int nbuttons; /* Number of buttons on the joystick */
uint8_t *buttons; /* Current button states */
int nhats;
uint8_t *hats;
struct joystick_hwdata *hwdata; /* Driver dependent information */
int ref_count; /* Reference count for multiple opens */
@ -93,10 +96,12 @@ struct joystick_hwdata
int axes; /* number of axis (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) */
recElement *firstAxis;
recElement *firstButton;
recElement *firstHat;
bool removed;
@ -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
FreeElementList(recElement *pElement)
{
@ -202,6 +231,7 @@ FreeDevice(recDevice *removeDevice)
/* free element lists */
FreeElementList(removeDevice->firstAxis);
FreeElementList(removeDevice->firstButton);
FreeElementList(removeDevice->firstHat);
free(removeDevice);
}
@ -315,6 +345,15 @@ AddHIDElement(const void *value, void *parameter)
}
}
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_DPadDown:
@ -535,6 +574,27 @@ SDL_SYS_JoystickUpdate(SDL_Joystick * joystick)
element = element->pNext;
++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(
@ -579,6 +639,7 @@ JoystickDeviceWasAddedCallback(void *ctx, IOReturn res, void *sender, IOHIDDevic
joystick->naxes = device->axes;
joystick->nbuttons = device->buttons;
joystick->nhats = device->hats;
if (joystick->naxes > 0) {
joystick->axes = (SDL_JoystickAxisInfo *) calloc(joystick->naxes, sizeof(SDL_JoystickAxisInfo));
@ -586,6 +647,9 @@ JoystickDeviceWasAddedCallback(void *ctx, IOReturn res, void *sender, IOHIDDevic
if (joystick->nbuttons > 0) {
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. */
IOHIDDeviceRegisterRemovalCallback(ioHIDDeviceObject, JoystickDeviceWasRemovedCallback, device);