2016-04-02 12:43:55 +00:00
|
|
|
//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"
|
2016-04-02 13:48:12 +00:00
|
|
|
#include "gamemem.h"
|
2016-04-02 12:43:55 +00:00
|
|
|
|
|
|
|
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];
|
2016-04-02 13:48:12 +00:00
|
|
|
MemoryMove(str+1,str,255);
|
2016-04-02 12:43:55 +00:00
|
|
|
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);
|
|
|
|
}
|