Redline/source/maccontrols.cpp

664 lines
22 KiB
C++
Raw Normal View History

//maccontrols.cpp
//mac-specific input code
#include <math.h>
#include <string.h>
#include <HID_Utilities_External.h>
#include <IOKit/hid/IOHIDUsageTables.h>
//needed for ForceFeedback.h
//-----------------------------------------------------------------
typedef OSStatus HRESULT;
typedef UInt32 IOByteCount;
typedef unsigned int io_service_t;
typedef unsigned int io_object_t;
#define S_OK ((HRESULT)0x00000000L)
//-----------------------------------------------------------------
#include <ForceFeedback/ForceFeedback.h>
extern "C"{
#include "ImmrHIDUtilAddOn.h"
}
#include "controls.h"
#include "config.h"
#include "error.h"
#include "gameframe.h"
#include "gamesystem.h"
#include "gametime.h"
typedef struct{
pRecDevice device;
int numElements;
pRecElement *elements;
} tHIDController;
tHIDController *gControllers;
int gInputHID=false;
int gNumControllers=0;
int gIShockIIFFB=false;
//iS2F_DeviceRef_t giShockList[iS2F_MAX_ISHOCK2_NUM];
int gIShockIIFFBBlock=0;
int gFFB=false;
FFDeviceObjectReference gFFDeviceRef;
FFEffectObjectReference gGroundRumbleEffectRef = NULL;
FFEffectObjectReference gJoltEffectRef = NULL;
FFEffectObjectReference gFrictionEffectRef = NULL;
FFEffectObjectReference gAlignEffectRef = NULL;
FFEffectObjectReference gEngineEffectRef = NULL;
DWORD dwAxes[2] = {FFJOFS_X,FFJOFS_Y};
LONG lDirection[2] = {0,0};
extern int gAxisSteering;
//returns true if the key with the key code k is pressed, false otherwise
short IsPressed(unsigned short k )
{
if(k<0||k>255)
return false;
KeyMapByteArray km;
GetKeys( *((KeyMap*)&km));
return ( ( km[k>>3] >> (k & 7) ) & 1);
}
//Initialize controls
void ControlInit()
{
if(HIDBuildDeviceList(NULL,NULL))
{
gNumControllers=0;
pRecDevice device=HIDGetFirstDevice();
do{
//if(!(device->usagePage==kHIDPage_Unknown||(device->usagePage==kHIDPage_GenericDesktop&&(device->usage==kHIDUsage_GD_Mouse||device->usage==kHIDUsage_GD_Keyboard))))
if(device->usagePage==kHIDPage_GenericDesktop&&(device->usage==kHIDUsage_GD_Joystick||device->usage==kHIDUsage_GD_GamePad))//||kHIDUsage_GD_Mouse))
gNumControllers++;
device=HIDGetNextDevice(device);
}while(device);
gControllers=(tHIDController*)NewPtr(sizeof(tHIDController)*gNumControllers);
gNumControllers=0;
device=HIDGetFirstDevice();
do{
// if(!(device->usagePage==kHIDPage_Unknown||(device->usagePage==kHIDPage_GenericDesktop&&(device->usage==kHIDUsage_GD_Mouse||device->usage==kHIDUsage_GD_Keyboard))))
if(device->usagePage==kHIDPage_GenericDesktop&&(device->usage==kHIDUsage_GD_Joystick||device->usage==kHIDUsage_GD_GamePad))//||kHIDUsage_GD_Mouse))
{
io_service_t hidDeviceObject=AllocateHIDObjectFromRecDevice(device);
if(hidDeviceObject)
if(FFIsForceFeedback(hidDeviceObject)==FF_OK)
if(FFCreateDevice(hidDeviceObject,&gFFDeviceRef)==FF_OK)
gFFB=true;
gControllers[gNumControllers].device=device;
gControllers[gNumControllers].numElements=HIDCountDeviceElements(gControllers[gNumControllers].device,kHIDElementTypeInput);
gControllers[gNumControllers].elements=(pRecElement*)NewPtr(sizeof(pRecElement)*gControllers[gNumControllers].numElements);
gControllers[gNumControllers].elements[0]=HIDGetFirstDeviceElement(gControllers[gNumControllers].device,kHIDElementTypeInput);
for(int j=1;j<gControllers[gNumControllers].numElements;j++)
gControllers[gNumControllers].elements[j]=HIDGetNextDeviceElement(gControllers[gNumControllers].elements[j-1],kHIDElementTypeInput);
gInputHID=true;
gNumControllers++;
}
device=HIDGetNextDevice(device);
}while(device);
}
}
//Wrapper functions for the iShock II SDK.
void FFBJolt(float lMag,float rMag,float duration)
{
#ifndef __TARGET_TOOLAPP
/* if(gIShockIIFFB&&gConfig->iShockFFB)
{
iS2F_JoltCmd_t joltCmd;
joltCmd.motorCmd.leftMotorMagnitude=lMag*10;
joltCmd.motorCmd.rightMotorMagnitude=rMag*10;
joltCmd.duration=duration*1000;
iS2F_SimpleJolt(giShockList[0],&joltCmd);
gIShockIIFFBBlock=gFrameCount+duration*kFPS;
}*/
if(gFFB&&gAxisSteering&&gConfig->ffb)
{
float mag=(rMag+lMag)*0.5;
float offset=rMag-lMag;
HRESULT hr;
FFEFFECT ffeffect;
FFPERIODIC ffperiodic;
FFENVELOPE ffenvelope;
ffenvelope.dwSize = sizeof(ffenvelope);
ffenvelope.dwAttackLevel = 0;
ffenvelope.dwAttackTime = 0; /* Microseconds */
ffenvelope.dwFadeLevel = 0;
ffenvelope.dwFadeTime = duration*FF_SECONDS; /* Microseconds */
ffperiodic.dwMagnitude = FF_FFNOMINALMAX*gConfig->ffbIntensity*mag;
ffperiodic.lOffset = FF_FFNOMINALMAX*gConfig->ffbIntensity*offset;
ffperiodic.dwPhase = 0;
ffperiodic.dwPeriod = 0.1*FF_SECONDS; // 10 Hz
ffeffect.dwSize = sizeof(ffeffect); /* sizeof(FFEFFECT) */
ffeffect.dwFlags = FFEFF_CARTESIAN; /* FFEFF_* */
ffeffect.dwDuration = duration*FF_SECONDS; /* Microseconds */
ffeffect.dwSamplePeriod = 1000; /* Microseconds */
ffeffect.dwGain = FF_FFNOMINALMAX;
ffeffect.dwTriggerButton = FFEB_NOTRIGGER; /* or FFEB_NOTRIGGER */
ffeffect.dwTriggerRepeatInterval = 0; /* Microseconds */
ffeffect.cAxes = 1; /* Number of axes */
ffeffect.rgdwAxes = dwAxes; /* Array of axes */
ffeffect.rglDirection = lDirection; /* Array of directions */
ffeffect.lpEnvelope = &ffenvelope; /* Optional */
ffeffect.cbTypeSpecificParams = sizeof(ffperiodic); /* Size of params */
ffeffect.lpvTypeSpecificParams = &ffperiodic; /* Pointer to params */
ffeffect.dwStartDelay = 0; /* Microseconds */
if(gJoltEffectRef==NULL)
{
FFDeviceCreateEffect(gFFDeviceRef, kFFEffectType_Square_ID, &ffeffect, &gJoltEffectRef);
FFEffectDownload(gJoltEffectRef);
FFEffectStart(gJoltEffectRef, 1, 0);
}
else
{
FFEffectSetParameters(gJoltEffectRef,&ffeffect,FFEP_GAIN);
FFEffectStart(gJoltEffectRef, 1, 0);
}
}
#endif
}
void FFBSetGoundRumble(float velo, float rumble)
{
if(gFFB&&gConfig->ffb)
{
if(!gAxisSteering)
rumble=0;
velo/=60;
if(velo>1)velo=1;
HRESULT hr;
FFEFFECT ffeffect;
FFPERIODIC ffperiodic;
ffperiodic.dwMagnitude = FF_FFNOMINALMAX*gConfig->ffbIntensity*rumble*velo*0.5;
ffperiodic.lOffset = 0;
ffperiodic.dwPhase = 0;
if(velo)
ffperiodic.dwPeriod = FF_SECONDS*0.8/velo;
else
ffperiodic.dwPeriod = 0;
ffeffect.dwSize = sizeof(ffeffect); /* sizeof(FFEFFECT) */
ffeffect.dwFlags = FFEFF_CARTESIAN; /* FFEFF_* */
ffeffect.dwDuration = FF_INFINITE; /* Microseconds */
ffeffect.dwSamplePeriod = 1000; /* Microseconds */
ffeffect.dwGain = FF_FFNOMINALMAX;
ffeffect.dwTriggerButton = FFEB_NOTRIGGER; /* or FFEB_NOTRIGGER */
ffeffect.dwTriggerRepeatInterval = 0; /* Microseconds */
ffeffect.cAxes = 1; /* Number of axes */
ffeffect.rgdwAxes = dwAxes; /* Array of axes */
ffeffect.rglDirection = lDirection; /* Array of directions */
ffeffect.lpEnvelope = NULL; /* Optional */
ffeffect.cbTypeSpecificParams = sizeof(ffperiodic); /* Size of params */
ffeffect.lpvTypeSpecificParams = &ffperiodic; /* Pointer to params */
ffeffect.dwStartDelay = 0; /* Microseconds */
if(gGroundRumbleEffectRef==NULL)
{
FFDeviceCreateEffect(gFFDeviceRef, kFFEffectType_Sine_ID, &ffeffect, &gGroundRumbleEffectRef);
FFEffectDownload(gGroundRumbleEffectRef);
FFEffectStart(gGroundRumbleEffectRef, 1, 0);
}
else
{
FFEffectSetParameters(gGroundRumbleEffectRef,&ffeffect,FFEP_TYPESPECIFICPARAMS+FFEP_GAIN);
FFEffectStatusFlag pFlags;
FFEffectGetEffectStatus(gGroundRumbleEffectRef,&pFlags);
if(!pFlags&FFEGES_PLAYING)
FFEffectStart(gGroundRumbleEffectRef, 1, 0);
}
}
}
void FFBSetSteerResistance(float res,float alignment)
{
if(gFFB&&gConfig->ffb)
{
if(!gAxisSteering)
{
res=0;
alignment=0;
}
HRESULT hr;
FFEFFECT ffeffect;
FFCONDITION ffcondition;
ffcondition.lOffset=0;
ffcondition.lPositiveCoefficient=FF_FFNOMINALMAX*gConfig->ffbIntensity*res;
ffcondition.lNegativeCoefficient=FF_FFNOMINALMAX*gConfig->ffbIntensity*res;
ffcondition.dwPositiveSaturation=FF_FFNOMINALMAX*gConfig->ffbIntensity*res;
ffcondition.dwNegativeSaturation=FF_FFNOMINALMAX*gConfig->ffbIntensity*res;
ffcondition.lDeadBand=0;
ffeffect.dwSize = sizeof(ffeffect); /* sizeof(FFEFFECT) */
ffeffect.dwFlags = FFEFF_CARTESIAN; /* FFEFF_* */
ffeffect.dwDuration = FF_INFINITE; /* Microseconds */
ffeffect.dwSamplePeriod = 1000; /* Microseconds */
ffeffect.dwGain = FF_FFNOMINALMAX;
ffeffect.dwTriggerButton = FFEB_NOTRIGGER; /* or FFEB_NOTRIGGER */
ffeffect.dwTriggerRepeatInterval = 0; /* Microseconds */
ffeffect.cAxes = 1; /* Number of axes */
ffeffect.rgdwAxes = dwAxes; /* Array of axes */
ffeffect.rglDirection = lDirection; /* Array of directions */
ffeffect.lpEnvelope = NULL; /* Optional */
ffeffect.cbTypeSpecificParams = sizeof(ffcondition); /* Size of params */
ffeffect.lpvTypeSpecificParams = &ffcondition; /* Pointer to params */
ffeffect.dwStartDelay = 0; /* Microseconds */
if(gFrictionEffectRef==NULL)
{
FFDeviceCreateEffect(gFFDeviceRef, kFFEffectType_Friction_ID, &ffeffect, &gFrictionEffectRef);
FFEffectDownload(gFrictionEffectRef);
FFEffectStart(gFrictionEffectRef, 1, 0);
}
else
{
FFEffectSetParameters(gFrictionEffectRef,&ffeffect,FFEP_TYPESPECIFICPARAMS+FFEP_GAIN);
FFEffectStatusFlag pFlags;
FFEffectGetEffectStatus(gFrictionEffectRef,&pFlags);
if(!pFlags&FFEGES_PLAYING)
FFEffectStart(gFrictionEffectRef, 1, 0);
}
ffcondition.lOffset=0;
ffcondition.lPositiveCoefficient=FF_FFNOMINALMAX*gConfig->ffbIntensity*alignment;
ffcondition.lNegativeCoefficient=FF_FFNOMINALMAX*gConfig->ffbIntensity*alignment;
ffcondition.dwPositiveSaturation=FF_FFNOMINALMAX*gConfig->ffbIntensity*alignment;
ffcondition.dwNegativeSaturation=FF_FFNOMINALMAX*gConfig->ffbIntensity*alignment;
ffcondition.lDeadBand=0;
if(gAlignEffectRef==NULL)
{
FFDeviceCreateEffect(gFFDeviceRef, kFFEffectType_Spring_ID, &ffeffect, &gAlignEffectRef);
FFEffectDownload(gAlignEffectRef);
FFEffectStart(gAlignEffectRef, 1, 0);
}
else
{
FFEffectSetParameters(gAlignEffectRef,&ffeffect,FFEP_TYPESPECIFICPARAMS+FFEP_GAIN);
FFEffectStatusFlag pFlags;
FFEffectGetEffectStatus(gAlignEffectRef,&pFlags);
if(!pFlags&FFEGES_PLAYING)
FFEffectStart(gAlignEffectRef, 1, 0);
}
}
}
void FFBiShockDirect(float lMag,float rMag)
{
/* if(gIShockIIFFB&&gConfig->iShockFFB&&gFrameCount>gIShockIIFFBBlock)
{
iS2F_MotorCmd_t directCmd;
directCmd.leftMotorMagnitude=lMag*10;
directCmd.rightMotorMagnitude=rMag*10;
iS2F_SimpleDirectControl(giShockList[0],&directCmd);
}*/
}
void FFBStop()
{
/* if(gIShockIIFFB&&gConfig->iShockFFB)
{
iS2F_MotorCmd_t directCmd;
directCmd.leftMotorMagnitude=0;
directCmd.rightMotorMagnitude=0;
iS2F_SimpleDirectControl(giShockList[0],&directCmd);
}*/
if(gFFB&&gConfig->ffb)
{
FFEffectStop(gGroundRumbleEffectRef);
FFEffectStop(gJoltEffectRef);
FFEffectStop(gFrictionEffectRef);
FFEffectStop(gAlignEffectRef);
FFEffectStop(gEngineEffectRef);
gGroundRumbleEffectRef = NULL;
gJoltEffectRef = NULL;
gFrictionEffectRef = NULL;
gAlignEffectRef = NULL;
gEngineEffectRef = NULL;
}
}
//Dispose*/ Control structures
void ControlExit()
{
/* if(gInputHID)
{
HIDReleaseDeviceList();
TearDownHIDCFM();
}
/* if(gIShockIIFFB)
{
FFBStop();
iS2F_Final();
}*/
}
void CalibrateAxis(int id)
{
while(GetInterfaceKey(kInterfaceKeyReturn)||GetInterfaceKey(kInterfaceKeyEnter));
int controller=-1;
for(int i=0;i<gNumControllers;i++)
if(gControllers[i].device->vendorID==gConfig->axis[id].axisControllerID1&&gControllers[i].device->productID==gConfig->axis[id].axisControllerID2)
controller=i;
int element=gConfig->axis[id].axisElementID;
if(controller<gNumControllers&&controller>=0)
{
gConfig->axis[id].max=gConfig->axis[id].mid+1;
gConfig->axis[id].min=gConfig->axis[id].mid-1;
while(!(GetInterfaceKey(kInterfaceKeyReturn)||GetInterfaceKey(kInterfaceKeyEnter)))
{
SInt32 value=HIDGetElementValue(gControllers[controller].device,gControllers[controller].elements[element]);
if(value<gConfig->axis[id].min)gConfig->axis[id].min=value;
if(value>gConfig->axis[id].max)gConfig->axis[id].max=value;
}
}
}
#define kAxisMaxZone 0.9
//read an analogue axis
float GetAxisInput(int id)
{
if(gConfig->axis[id].axisControllerID1==-1&&gConfig->axis[id].axisControllerID2==-1)
{
//mouse pos
tVector2 p=GetMousePos();
if(gConfig->axis[id].axisElementID==1)
return p.x;
if(gConfig->axis[id].axisElementID==2)
return p.y;
}
if(gConfig->axis[id].axisControllerID1&&gInputHID){
int controller=-1;
for(int i=0;i<gNumControllers;i++)
if(gControllers[i].device->vendorID==gConfig->axis[id].axisControllerID1&&gControllers[i].device->productID==gConfig->axis[id].axisControllerID2)
controller=i;
int element=gConfig->axis[id].axisElementID;
if(controller<gNumControllers&&controller>=0)
if(element<gControllers[controller].numElements&&element>=0)
{
SInt32 value=HIDGetElementValue(gControllers[controller].device,gControllers[controller].elements[element]);
int min=gConfig->axis[id].mid-(gConfig->axis[id].mid-gConfig->axis[id].min)*kAxisMaxZone;
int max=gConfig->axis[id].mid-(gConfig->axis[id].mid-gConfig->axis[id].max)*kAxisMaxZone;
float ax;
if(id>=kInputThrottleAxis)
{
if(value<(gConfig->axis[id].max-gConfig->axis[id].min)*gConfig->axis[id].deadzone*0.5)
ax=0;
else
ax=(value-(gConfig->axis[id].max-gConfig->axis[id].min)*gConfig->axis[id].deadzone*0.5)/((gConfig->axis[id].max-min)*(1-0.5*gConfig->axis[id].deadzone));
}
else
{
if(fabs(gConfig->axis[id].mid-value)<(gConfig->axis[id].max-gConfig->axis[id].min)*gConfig->axis[id].deadzone)
ax=0;
else if(value>gConfig->axis[id].mid)
ax=(value-(gConfig->axis[id].mid+(gConfig->axis[id].max-gConfig->axis[id].min)*gConfig->axis[id].deadzone))/((gConfig->axis[id].mid-max)*(1-0.5*gConfig->axis[id].deadzone));
else
ax=(value-(gConfig->axis[id].mid-(gConfig->axis[id].max-gConfig->axis[id].min)*gConfig->axis[id].deadzone))/((min-gConfig->axis[id].mid)*(1-0.5*gConfig->axis[id].deadzone));
}
if(ax>1)ax=1;
else if(ax<-1)ax=-1;
return ax;
}
}
return 0;
}
//read a digital input
int GetButtonInput(int id)
{
if(gInputChatMode)
return false;
//is the key pressed?
int key=gSystemSuspended?false:IsPressed(gConfig->keys[id].keyID);
//is the HID button pressed?
if(gConfig->axis[id].axisControllerID1==-1&&gConfig->axis[id].axisControllerID2==-1)
if(Button())
key=true;
if(gConfig->keys[id].controllerID1&&gInputHID)
{
int controller=-1;
for(int i=0;i<gNumControllers;i++)
if(gControllers[i].device->vendorID==gConfig->keys[id].controllerID1&&gControllers[i].device->productID==gConfig->keys[id].controllerID2)
controller=i;
int element=gConfig->keys[id].elementID;
if(controller<gNumControllers&&controller>=0)
if(element<gControllers[controller].numElements&&element>=0)
return key||HIDGetElementValue(gControllers[controller].device,gControllers[controller].elements[element]);
}
return key;
}
int gInterfaceKeys[kInterfaceNumKeys]={0x00,0x7e,0x7d,0x7b,0x7c,0x31,0x24,0x4c,0x35,0x07,0x33,0x37,0x3a,0x01,0x0f,0x0c,0xff};
int GetInterfaceKey(int id)
{
if(id==kInterfaceMouseDown)
return gSystemSuspended?false:Button();
else
return gSystemSuspended?false:IsPressed(gInterfaceKeys[id]);
}
static void GetElementName (pRecDevice pDevice,pRecElement pElement, char *strElementName)
{
if(!HIDGetElementNameFromVendorProductUsage (pDevice->vendorID, pDevice->productID, pElement->usagePage, pElement->usage,strElementName))
{
// set name from vendor id/product id look up
HIDGetElementNameFromVendorProductCookie (pDevice->vendorID, pDevice->productID, (long) pElement->cookie, strElementName);
if (!*strElementName) { // if no name
char buffer[1024];
HIDGetUsageName (pElement->usagePage, pElement->usage,buffer);
if (!*buffer) // if not usage
sprintf (strElementName, "Unknown");
else
sprintf(strElementName,"%s %s",pDevice->product,buffer);
}
}
}
//used to user-configure input. if any key or HID button is pressed,
//this changes the according ID and Identifier string.
void GetInput(tKeyConfig *keyConfig)
{
//FlushEvents(keyDownMask,0);
int key=-1;
do{
for(int i=0;i<128;i++)
if(IsPressed(i))
if(i!=0x35&&i!=0x33)
key=i;
else
{
if(i==0x33)
{
keyConfig->controllerID1=0;
keyConfig->controllerID2=0;
keyConfig->elementID=0;
strcpy(keyConfig->controllerIdentifier,"");
keyConfig->keyID=-1;
strcpy(keyConfig->identifier,"<none>");
}
FlushEvents(keyDownMask|mDownMask,0);
FlushKeys();
return;
}
if(gInputHID)
for(int j=0;j<gNumControllers;j++)
for(int i=0;i<gControllers[j].numElements;i++)
if(gControllers[j].elements[i])
if(gControllers[j].elements[i]->type==kIOHIDElementTypeInput_Button)
if(HIDGetElementValue(gControllers[j].device,gControllers[j].elements[i]))
{
keyConfig->controllerID1=gControllers[j].device->vendorID;
keyConfig->controllerID2=gControllers[j].device->productID;
keyConfig->elementID=i;
char elementName[256];
GetElementName(gControllers[j].device,gControllers[j].elements[i],elementName);
// sprintf(keyConfig->controllerIdentifier,"%s: %s",gControllers[j].device->product,elementName);
strcpy(keyConfig->controllerIdentifier,elementName);
return;
}
if(Button()&&!StillDown())
{
keyConfig->controllerID1=-1;
keyConfig->controllerID2=-1;
keyConfig->elementID=1;
strcpy(keyConfig->controllerIdentifier,"Mouse Button");
FlushEvents(keyDownMask|mDownMask,0);
FlushKeys();
return;
}
}while(key==-1);
int clear;
do{
clear=true;
for(int i=0;i<128;i++)
if(IsPressed(i))
clear=false;
}while(!clear);
EventRecord evt;
Str255 str;
GetIndString(str,128,key+1);
int len=str[0];
BlockMoveData(str+1,str,255);
str[len]='\0';
if(str[0])
strcpy(keyConfig->identifier,(char*)str);
else
{
strcpy(keyConfig->identifier,"unknown key");
while(WaitNextEvent(keyUpMask,&evt,1,nil))
{
keyConfig->identifier[0]=evt.message&charCodeMask;
if(keyConfig->identifier[0]>='a'&&keyConfig->identifier[0]<='z')
keyConfig->identifier[0]+='A'-'a';
keyConfig->identifier[1]='\0';
}
}
keyConfig->keyID=key;
FlushEvents(keyDownMask|mDownMask,0);
FlushKeys();
}
//used to user-configure input. if any HID axis is moved,
//this changes the according ID and Identifier string.
void GetAxis(tAxisConfig *axis,bool allowVendor)
{
tVector2 basep=GetMousePos();
float **values=(float**)NewPtr(sizeof(float)*gNumControllers);
for(int j=0;j<gNumControllers;j++)
{
values[j]=(float*)NewPtr(sizeof(float)*gControllers[j].numElements);
for(int i=0;i<gControllers[j].numElements;i++)
if(gControllers[j].elements[i]->type!=kIOHIDElementTypeInput_Button)
values[j][i]=HIDGetElementValue(gControllers[j].device,gControllers[j].elements[i]);
}
int key=-1;
do{
long maxDiff=0;
for(int i=0;i<128;i++)
if(IsPressed(i))
key=i;
if(key==0x33)
{
axis->axisControllerID1=0;
axis->axisControllerID2=0;
axis->axisElementID=0;
strcpy(axis->axisIdentifier,"<none>");
}
for(int j=0;j<gNumControllers;j++)
for(int i=0;i<gControllers[j].numElements;i++)
if(gControllers[j].elements[i]->usagePage!=kHIDPage_VendorDefinedStart||allowVendor)
if(gControllers[j].elements[i]->type!=kIOHIDElementTypeInput_Button)
if(abs(values[j][i]-HIDGetElementValue(gControllers[j].device,gControllers[j].elements[i]))>0)
{
maxDiff=abs(values[j][i]-HIDGetElementValue(gControllers[j].device,gControllers[j].elements[i]));
axis->axisControllerID1=gControllers[j].device->vendorID;
axis->axisControllerID2=gControllers[j].device->productID;
axis->axisElementID=i;
axis->min=gControllers[j].elements[i]->min;
axis->max=gControllers[j].elements[i]->max;
axis->mid=(axis->min+axis->max)/2;
char elementName[256];
GetElementName(gControllers[j].device,gControllers[j].elements[i],elementName);
//sprintf(axis->axisIdentifier,"%s: %s",gControllers[j].device->product,elementName);
strcpy(axis->axisIdentifier,elementName);
}
if(maxDiff)
{
for(int j=0;j<gNumControllers;j++)
DisposePtr((Ptr)(values[j]));
DisposePtr((Ptr)values);
FlushEvents(keyDownMask|mDownMask,0);
FlushKeys();
return;
}
tVector2 p=GetMousePos();
if(~(p-basep)>0.1)
{
axis->axisControllerID1=-1;
axis->axisControllerID2=-1;
axis->axisElementID=fabs(p.x-basep.x)>fabs(p.y-basep.y)?1:2;
sprintf(axis->axisIdentifier,"Mouse %c Axis",'W'+axis->axisElementID);
for(int j=0;j<gNumControllers;j++)
DisposePtr((Ptr)(values[j]));
DisposePtr((Ptr)values);
FlushEvents(keyDownMask|mDownMask,0);
FlushKeys();
return;
}
}while(key!=0x24&&key!=0x4c&&key!=0x35);
FlushEvents(keyDownMask|mDownMask,0);
FlushKeys();
for(int j=0;j<gNumControllers;j++)
DisposePtr((Ptr)(values[j]));
DisposePtr((Ptr)values);
}
tVector2 GetMousePos()
{
Point p;
GetMouse(&p);
return Vector(-(2.0*p.h/gConfig->screenXSize)+1,(2.0*p.v/gConfig->screenYSize)-1);
}