mirror of
https://github.com/libretro/RetroArch.git
synced 2024-12-04 14:27:38 +00:00
Merge pull request #4426 from jprjr/osx-iohidmanager
OSX Joypad Improvements
This commit is contained in:
commit
ddc11e2d17
@ -31,12 +31,20 @@
|
||||
#include "../../tasks/tasks_internal.h"
|
||||
#include "../../verbosity.h"
|
||||
|
||||
typedef struct apple_input_rec
|
||||
{
|
||||
IOHIDElementCookie cookie;
|
||||
uint32_t id;
|
||||
struct apple_input_rec *next;
|
||||
} apple_input_rec_t;
|
||||
|
||||
typedef struct apple_hid
|
||||
{
|
||||
IOHIDManagerRef ptr;
|
||||
joypad_connection_t *slots;
|
||||
uint32_t buttons[MAX_USERS];
|
||||
int16_t axes[MAX_USERS][6];
|
||||
int8_t hats[MAX_USERS][2]; /* MacOS only supports 1 hat AFAICT */
|
||||
} iohidmanager_hid_t;
|
||||
|
||||
struct iohidmanager_hid_adapter
|
||||
@ -44,9 +52,53 @@ struct iohidmanager_hid_adapter
|
||||
uint32_t slot;
|
||||
IOHIDDeviceRef handle;
|
||||
char name[PATH_MAX_LENGTH];
|
||||
apple_input_rec_t *axes;
|
||||
apple_input_rec_t *hats;
|
||||
apple_input_rec_t *buttons;
|
||||
uint8_t data[2048];
|
||||
};
|
||||
|
||||
CFComparisonResult iohidmanager_sort_elements(const void *val1, const void *val2, void *context)
|
||||
{
|
||||
uint32_t page1 = IOHIDElementGetUsagePage((IOHIDElementRef)val1);
|
||||
uint32_t page2 = IOHIDElementGetUsagePage((IOHIDElementRef)val2);
|
||||
uint32_t use1 = IOHIDElementGetUsage((IOHIDElementRef)val1);
|
||||
uint32_t use2 = IOHIDElementGetUsage((IOHIDElementRef)val2);
|
||||
uint32_t cookie1 = IOHIDElementGetCookie((IOHIDElementRef)val1);
|
||||
uint32_t cookie2 = IOHIDElementGetCookie((IOHIDElementRef)val2);
|
||||
|
||||
if(page1 != page2)
|
||||
{
|
||||
return page1 > page2;
|
||||
}
|
||||
|
||||
if(use1 != use2)
|
||||
{
|
||||
return use1 > use2;
|
||||
}
|
||||
|
||||
return cookie1 > cookie2;
|
||||
}
|
||||
|
||||
static bool iohidmanager_check_for_id(apple_input_rec_t *rec, uint32_t id)
|
||||
{
|
||||
while(rec) {
|
||||
if(rec->id == id) return true;
|
||||
rec = rec->next;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static void iohidmanager_append_record(apple_input_rec_t *rec, apple_input_rec_t *new)
|
||||
{
|
||||
apple_input_rec_t *tmp = rec;
|
||||
while(tmp->next)
|
||||
{
|
||||
tmp = tmp->next;
|
||||
}
|
||||
tmp->next = new;
|
||||
}
|
||||
|
||||
static bool iohidmanager_hid_joypad_query(void *data, unsigned pad)
|
||||
{
|
||||
return pad < MAX_USERS;
|
||||
@ -75,10 +127,28 @@ static bool iohidmanager_hid_joypad_button(void *data,
|
||||
uint64_t buttons =
|
||||
iohidmanager_hid_joypad_get_buttons(data, port);
|
||||
iohidmanager_hid_t *hid = (iohidmanager_hid_t*)data;
|
||||
unsigned h = GET_HAT(joykey);
|
||||
unsigned hat_dir = GET_HAT_DIR(joykey);
|
||||
|
||||
/* Check hat. */
|
||||
if (GET_HAT_DIR(joykey))
|
||||
return false;
|
||||
if (hat_dir)
|
||||
{
|
||||
if(h >= 1) {
|
||||
return false;
|
||||
}
|
||||
switch(hat_dir)
|
||||
{
|
||||
case HAT_LEFT_MASK:
|
||||
return hid->hats[port][0] < 0;
|
||||
case HAT_RIGHT_MASK:
|
||||
return hid->hats[port][0] > 0;
|
||||
case HAT_UP_MASK:
|
||||
return hid->hats[port][1] < 0;
|
||||
case HAT_DOWN_MASK:
|
||||
return hid->hats[port][1] > 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Check the button. */
|
||||
if ((port < MAX_USERS) && (joykey < 32))
|
||||
@ -166,6 +236,8 @@ static void iohidmanager_hid_device_input_callback(void *data, IOReturn result,
|
||||
uint32_t type = IOHIDElementGetType(element);
|
||||
uint32_t page = IOHIDElementGetUsagePage(element);
|
||||
uint32_t use = IOHIDElementGetUsage(element);
|
||||
uint32_t cookie = IOHIDElementGetCookie(element);
|
||||
apple_input_rec_t *tmp = NULL;
|
||||
|
||||
if (type != kIOHIDElementTypeInput_Misc)
|
||||
if (type != kIOHIDElementTypeInput_Button)
|
||||
@ -184,32 +256,86 @@ static void iohidmanager_hid_device_input_callback(void *data, IOReturn result,
|
||||
switch (use)
|
||||
{
|
||||
case kHIDUsage_GD_Hatswitch:
|
||||
break;
|
||||
{
|
||||
tmp = adapter->hats;
|
||||
while(tmp && tmp->cookie != cookie)
|
||||
{
|
||||
tmp = tmp->next;
|
||||
}
|
||||
if(tmp->cookie == cookie)
|
||||
{
|
||||
CFIndex range = IOHIDElementGetLogicalMax(element) - IOHIDElementGetLogicalMin(element);
|
||||
CFIndex val = IOHIDValueGetIntegerValue(value);
|
||||
if(range == 3)
|
||||
{
|
||||
val *= 2;
|
||||
}
|
||||
switch(val)
|
||||
{
|
||||
case 0:
|
||||
/* pos = up */
|
||||
hid->hats[adapter->slot][0] = 0;
|
||||
hid->hats[adapter->slot][1] = -1;
|
||||
break;
|
||||
case 1:
|
||||
/* pos = up+right */
|
||||
hid->hats[adapter->slot][0] = 1;
|
||||
hid->hats[adapter->slot][1] = -1;
|
||||
break;
|
||||
case 2:
|
||||
/* pos = right */
|
||||
hid->hats[adapter->slot][0] = 1;
|
||||
hid->hats[adapter->slot][1] = 0;
|
||||
break;
|
||||
case 3:
|
||||
/* pos = down+right */
|
||||
hid->hats[adapter->slot][0] = 1;
|
||||
hid->hats[adapter->slot][1] = 1;
|
||||
break;
|
||||
case 4:
|
||||
/* pos = down */
|
||||
hid->hats[adapter->slot][0] = 0;
|
||||
hid->hats[adapter->slot][1] = 1;
|
||||
break;
|
||||
case 5:
|
||||
/* pos = down+left */
|
||||
hid->hats[adapter->slot][0] = -1;
|
||||
hid->hats[adapter->slot][1] = 1;
|
||||
break;
|
||||
case 6:
|
||||
/* pos = left */
|
||||
hid->hats[adapter->slot][0] = -1;
|
||||
hid->hats[adapter->slot][1] = 0;
|
||||
break;
|
||||
case 7:
|
||||
/* pos = up_left */
|
||||
hid->hats[adapter->slot][0] = -1;
|
||||
hid->hats[adapter->slot][1] = -1;
|
||||
break;
|
||||
default:
|
||||
/* pos = centered */
|
||||
hid->hats[adapter->slot][0] = 0;
|
||||
hid->hats[adapter->slot][1] = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
{
|
||||
int i;
|
||||
static const uint32_t axis_use_ids[6] =
|
||||
{ 48, 49, 51, 52, 50, 53 };
|
||||
|
||||
/* +0/-0 => Left Stick Horizontal => 48
|
||||
* +1/-1 => Left Stick Vertical => 49
|
||||
* +2/-2 => Right Stick Horizontal => 51
|
||||
* +3/-3 => Right Stick Vertical => 52
|
||||
* +4/-4 => Left Trigger (if exists) => 50
|
||||
* +5/-5 => Right Trigger (if exists) => 53
|
||||
*/
|
||||
|
||||
for (i = 0; i < 6; i ++)
|
||||
tmp = adapter->axes;
|
||||
while(tmp && tmp->cookie != cookie)
|
||||
{
|
||||
tmp = tmp->next;
|
||||
}
|
||||
if(tmp->cookie == cookie)
|
||||
{
|
||||
CFIndex min = IOHIDElementGetPhysicalMin(element);
|
||||
CFIndex state = IOHIDValueGetIntegerValue(value) - min;
|
||||
CFIndex max = IOHIDElementGetPhysicalMax(element) - min;
|
||||
float val = (float)state / (float)max;
|
||||
|
||||
if (use != axis_use_ids[i])
|
||||
continue;
|
||||
|
||||
hid->axes[adapter->slot][i] =
|
||||
hid->axes[adapter->slot][tmp->id] =
|
||||
((val * 2.0f) - 1.0f) * 32767.0f;
|
||||
}
|
||||
}
|
||||
@ -223,13 +349,20 @@ static void iohidmanager_hid_device_input_callback(void *data, IOReturn result,
|
||||
{
|
||||
case kIOHIDElementTypeInput_Button:
|
||||
{
|
||||
CFIndex state = IOHIDValueGetIntegerValue(value);
|
||||
unsigned id = use - 1;
|
||||
tmp = adapter->buttons;
|
||||
while(tmp && tmp->cookie != cookie)
|
||||
{
|
||||
tmp = tmp->next;
|
||||
}
|
||||
if(tmp->cookie == cookie)
|
||||
{
|
||||
CFIndex state = IOHIDValueGetIntegerValue(value);
|
||||
|
||||
if (state)
|
||||
BIT64_SET(hid->buttons[adapter->slot], id);
|
||||
else
|
||||
BIT64_CLEAR(hid->buttons[adapter->slot], id);
|
||||
if (state)
|
||||
BIT64_SET(hid->buttons[adapter->slot], tmp->id);
|
||||
else
|
||||
BIT64_CLEAR(hid->buttons[adapter->slot], tmp->id);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -256,7 +389,28 @@ static void iohidmanager_hid_device_remove(void *data,
|
||||
}
|
||||
|
||||
if (adapter)
|
||||
{
|
||||
struct apple_input_rec_t* tmp;
|
||||
while(adapter->hats != NULL)
|
||||
{
|
||||
tmp = adapter->hats;
|
||||
adapter->hats = adapter->hats->next;
|
||||
free(tmp);
|
||||
}
|
||||
while(adapter->axes != NULL)
|
||||
{
|
||||
tmp = adapter->axes;
|
||||
adapter->axes = adapter->axes->next;
|
||||
free(tmp);
|
||||
}
|
||||
while(adapter->buttons != NULL)
|
||||
{
|
||||
tmp = adapter->buttons;
|
||||
adapter->buttons = adapter->buttons->next;
|
||||
free(tmp);
|
||||
}
|
||||
free(adapter);
|
||||
}
|
||||
}
|
||||
|
||||
static int32_t iohidmanager_hid_device_get_int_property(
|
||||
@ -367,13 +521,205 @@ static void iohidmanager_hid_device_add(void *data, IOReturn result,
|
||||
if (string_is_empty(adapter->name))
|
||||
goto error;
|
||||
|
||||
/* scan for buttons, axis, hats */
|
||||
CFArrayRef elements_raw = IOHIDDeviceCopyMatchingElements(device, NULL, kIOHIDOptionsTypeNone);
|
||||
int count = (int)CFArrayGetCount(elements_raw);
|
||||
CFMutableArrayRef elements = CFArrayCreateMutableCopy(kCFAllocatorDefault,(CFIndex)count,elements_raw);
|
||||
CFRange range = CFRangeMake(0,count);
|
||||
CFArraySortValues(elements,range,iohidmanager_sort_elements,NULL);
|
||||
int i;
|
||||
bool found_axis[6] =
|
||||
{ false, false, false, false, false, false };
|
||||
|
||||
apple_input_rec_t *tmpButtons = NULL;
|
||||
apple_input_rec_t *tmpAxes = NULL;
|
||||
|
||||
for(i=0; i<count; i++) {
|
||||
IOHIDElementRef element = (IOHIDElementRef)CFArrayGetValueAtIndex(elements, i);
|
||||
if (!element) continue;
|
||||
IOHIDElementType type = IOHIDElementGetType(element);
|
||||
uint32_t page = IOHIDElementGetUsagePage(element);
|
||||
uint32_t use = IOHIDElementGetUsage(element);
|
||||
uint32_t cookie = IOHIDElementGetCookie(element);
|
||||
|
||||
switch (page)
|
||||
{
|
||||
case kHIDPage_GenericDesktop:
|
||||
switch (type)
|
||||
{
|
||||
case kIOHIDElementTypeInput_Misc:
|
||||
switch (use)
|
||||
{
|
||||
case kHIDUsage_GD_Hatswitch:
|
||||
{
|
||||
/* as far as I can tell, OSX only reports one Hat */
|
||||
apple_input_rec_t *hat = (apple_input_rec_t *)malloc(sizeof(apple_input_rec_t));
|
||||
hat->id = 0;
|
||||
hat->cookie = cookie;
|
||||
hat->next = NULL;
|
||||
adapter->hats = hat;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
{
|
||||
uint32_t i = 0;
|
||||
static const uint32_t axis_use_ids[6] =
|
||||
{ 48, 49, 51, 52, 50, 53 };
|
||||
|
||||
while(axis_use_ids[i] != use)
|
||||
{
|
||||
i++;
|
||||
}
|
||||
|
||||
if (i < 6)
|
||||
{
|
||||
|
||||
apple_input_rec_t *axis = (apple_input_rec_t *)malloc(sizeof(apple_input_rec_t));
|
||||
axis->id = i;
|
||||
axis->cookie = cookie;
|
||||
axis->next = NULL;
|
||||
|
||||
if(iohidmanager_check_for_id(adapter->axes,i))
|
||||
{
|
||||
/* axis ID already exists, save to tmp for appending later */
|
||||
if(tmpAxes == NULL)
|
||||
{
|
||||
tmpAxes = axis;
|
||||
}
|
||||
else
|
||||
{
|
||||
iohidmanager_append_record(tmpAxes,axis);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
found_axis[axis->id] = true;
|
||||
if(adapter->axes == NULL)
|
||||
{
|
||||
adapter->axes = axis;
|
||||
}
|
||||
else
|
||||
{
|
||||
iohidmanager_append_record(adapter->axes,axis);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case kHIDPage_Button:
|
||||
switch (type)
|
||||
{
|
||||
case kIOHIDElementTypeInput_Button:
|
||||
{
|
||||
apple_input_rec_t *btn = (apple_input_rec_t *)malloc(sizeof(apple_input_rec_t));
|
||||
btn->id = use - 1;
|
||||
btn->cookie = cookie;
|
||||
btn->next = NULL;
|
||||
if(iohidmanager_check_for_id(adapter->buttons,btn->id))
|
||||
{
|
||||
if(tmpButtons == NULL)
|
||||
{
|
||||
tmpButtons = btn;
|
||||
}
|
||||
else
|
||||
{
|
||||
iohidmanager_append_record(tmpButtons,btn);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(adapter->buttons == NULL)
|
||||
{
|
||||
adapter->buttons = btn;
|
||||
}
|
||||
else
|
||||
{
|
||||
iohidmanager_append_record(adapter->buttons,btn);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* take care of buttons/axes with duplicate 'use' values */
|
||||
for(i=0; i<6; i++)
|
||||
{
|
||||
if(found_axis[i] == false && tmpAxes)
|
||||
{
|
||||
apple_input_rec_t *next = tmpAxes->next;
|
||||
tmpAxes->id = i;
|
||||
tmpAxes->next = NULL;
|
||||
iohidmanager_append_record(adapter->axes, tmpAxes);
|
||||
tmpAxes = next;
|
||||
}
|
||||
}
|
||||
|
||||
apple_input_rec_t *tmp = adapter->buttons;
|
||||
while(tmp->next)
|
||||
{
|
||||
tmp = tmp->next;
|
||||
}
|
||||
|
||||
while(tmpButtons)
|
||||
{
|
||||
apple_input_rec_t *next = tmpButtons->next;
|
||||
|
||||
tmpButtons->id = tmp->id + 1;
|
||||
tmpButtons->next = NULL;
|
||||
tmp->next = tmpButtons;
|
||||
|
||||
tmp = tmp->next;
|
||||
tmpButtons = next;
|
||||
}
|
||||
|
||||
|
||||
iohidmanager_hid_device_add_autodetect(adapter->slot,
|
||||
adapter->name, iohidmanager_hid.ident, dev_vid, dev_pid);
|
||||
|
||||
return;
|
||||
|
||||
error:
|
||||
free(adapter);
|
||||
{
|
||||
struct apple_input_rec_t *tmp = NULL;
|
||||
while(adapter->hats != NULL)
|
||||
{
|
||||
tmp = adapter->hats;
|
||||
adapter->hats = adapter->hats->next;
|
||||
free(tmp);
|
||||
}
|
||||
while(adapter->axes != NULL)
|
||||
{
|
||||
tmp = adapter->axes;
|
||||
adapter->axes = adapter->axes->next;
|
||||
free(tmp);
|
||||
}
|
||||
while(adapter->buttons != NULL)
|
||||
{
|
||||
tmp = adapter->buttons;
|
||||
adapter->buttons = adapter->buttons->next;
|
||||
free(tmp);
|
||||
}
|
||||
while(tmpAxes != NULL)
|
||||
{
|
||||
tmp = tmpAxes;
|
||||
tmpAxes = tmpAxes->next;
|
||||
free(tmp);
|
||||
}
|
||||
while(tmpButtons != NULL)
|
||||
{
|
||||
tmp = tmpButtons;
|
||||
tmpButtons = tmpButtons->next;
|
||||
free(tmp);
|
||||
}
|
||||
free(adapter);
|
||||
}
|
||||
}
|
||||
|
||||
static void iohidmanager_hid_append_matching_dictionary(
|
||||
|
Loading…
Reference in New Issue
Block a user