📄 joystick_linux.c
字号:
}
device->user_df->rgodf[i].dwType = type;
}
}
static HRESULT alloc_device(REFGUID rguid, const void *jvt, IDirectInputImpl *dinput, LPDIRECTINPUTDEVICEA* pdev)
{
DWORD i;
JoystickImpl* newDevice;
char name[MAX_PATH];
HRESULT hr;
newDevice = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(JoystickImpl));
if (newDevice == 0) {
WARN("out of memory\n");
*pdev = 0;
return DIERR_OUTOFMEMORY;
}
sprintf(newDevice->dev, "%s%d", JOYDEV, rguid->Data3);
if ((newDevice->joyfd = open(newDevice->dev,O_RDONLY)) < 0) {
WARN("open(%s,O_RDONLY) failed: %s\n", newDevice->dev, strerror(errno));
HeapFree(GetProcessHeap(), 0, newDevice);
return DIERR_DEVICENOTREG;
}
/* get the device name */
#if defined(JSIOCGNAME)
if (ioctl(newDevice->joyfd,JSIOCGNAME(MAX_PATH),name) < 0) {
WARN("ioctl(%s,JSIOCGNAME) failed: %s\n", newDevice->dev, strerror(errno));
strcpy(name, "Wine Joystick");
}
#else
strcpy(name, "Wine Joystick");
#endif
/* copy the device name */
newDevice->name = HeapAlloc(GetProcessHeap(),0,strlen(name) + 1);
strcpy(newDevice->name, name);
#ifdef JSIOCGAXES
if (ioctl(newDevice->joyfd,JSIOCGAXES,&newDevice->axes) < 0) {
WARN("ioctl(%s,JSIOCGAXES) failed: %s, defauting to 2\n", newDevice->dev, strerror(errno));
newDevice->axes = 2;
}
#endif
#ifdef JSIOCGBUTTONS
if (ioctl(newDevice->joyfd,JSIOCGBUTTONS,&newDevice->buttons) < 0) {
WARN("ioctl(%s,JSIOCGBUTTONS) failed: %s, defauting to 2\n", newDevice->dev, strerror(errno));
newDevice->buttons = 2;
}
#endif
newDevice->lpVtbl = jvt;
newDevice->ref = 1;
newDevice->dinput = dinput;
newDevice->acquired = FALSE;
newDevice->overflow = FALSE;
CopyMemory(&(newDevice->guid),rguid,sizeof(*rguid));
/* setup_dinput_options may change these */
newDevice->deadzone = 5000;
newDevice->devcaps.dwButtons = newDevice->buttons;
newDevice->devcaps.dwAxes = newDevice->axes;
newDevice->devcaps.dwPOVs = 0;
/* do any user specified configuration */
hr = setup_dinput_options(newDevice);
if (hr != DI_OK)
goto FAILED1;
if (newDevice->axis_map == 0) {
newDevice->axis_map = HeapAlloc(GetProcessHeap(), 0, newDevice->axes * sizeof(int));
if (newDevice->axis_map == 0)
goto FAILED;
for (i = 0; i < newDevice->axes; i++)
newDevice->axis_map[i] = i;
}
/* wine uses DIJOYSTATE2 as it's internal format so copy
* the already defined format c_dfDIJoystick2 */
newDevice->user_df = HeapAlloc(GetProcessHeap(),0,c_dfDIJoystick2.dwSize);
if (newDevice->user_df == 0)
goto FAILED;
CopyMemory(newDevice->user_df, &c_dfDIJoystick2, c_dfDIJoystick2.dwSize);
/* copy default objects */
newDevice->user_df->rgodf = HeapAlloc(GetProcessHeap(),0,c_dfDIJoystick2.dwNumObjs*c_dfDIJoystick2.dwObjSize);
if (newDevice->user_df->rgodf == 0)
goto FAILED;
CopyMemory(newDevice->user_df->rgodf,c_dfDIJoystick2.rgodf,c_dfDIJoystick2.dwNumObjs*c_dfDIJoystick2.dwObjSize);
/* create default properties */
newDevice->props = HeapAlloc(GetProcessHeap(),0,c_dfDIJoystick2.dwNumObjs*sizeof(ObjProps));
if (newDevice->props == 0)
goto FAILED;
/* initialize default properties */
for (i = 0; i < c_dfDIJoystick2.dwNumObjs; i++) {
newDevice->props[i].lMin = 0;
newDevice->props[i].lMax = 0xffff;
newDevice->props[i].lDeadZone = newDevice->deadzone; /* % * 1000 */
newDevice->props[i].lSaturation = 0;
}
/* create an offsets array */
newDevice->offsets = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,c_dfDIJoystick2.dwNumObjs*sizeof(int));
if (newDevice->offsets == 0)
goto FAILED;
/* create the default transform filter */
newDevice->transform = create_DataFormat(&c_dfDIJoystick2, newDevice->user_df, newDevice->offsets);
calculate_ids(newDevice);
IDirectInputDevice_AddRef((LPDIRECTINPUTDEVICE8A)newDevice->dinput);
InitializeCriticalSection(&(newDevice->crit));
newDevice->crit.DebugInfo->Spare[0] = (DWORD_PTR)"DINPUT_Mouse";
newDevice->devcaps.dwSize = sizeof(newDevice->devcaps);
newDevice->devcaps.dwFlags = DIDC_ATTACHED;
if (newDevice->dinput->dwVersion >= 0x0800)
newDevice->devcaps.dwDevType = DI8DEVTYPE_JOYSTICK | (DI8DEVTYPEJOYSTICK_STANDARD << 8);
else
newDevice->devcaps.dwDevType = DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_TRADITIONAL << 8);
newDevice->devcaps.dwFFSamplePeriod = 0;
newDevice->devcaps.dwFFMinTimeResolution = 0;
newDevice->devcaps.dwFirmwareRevision = 0;
newDevice->devcaps.dwHardwareRevision = 0;
newDevice->devcaps.dwFFDriverVersion = 0;
if (TRACE_ON(dinput)) {
_dump_DIDATAFORMAT(newDevice->user_df);
for (i = 0; i < (newDevice->axes); i++)
TRACE("axis_map[%ld] = %d\n", i, newDevice->axis_map[i]);
_dump_DIDEVCAPS(&newDevice->devcaps);
}
*pdev = (LPDIRECTINPUTDEVICEA)newDevice;
return DI_OK;
FAILED:
hr = DIERR_OUTOFMEMORY;
FAILED1:
HeapFree(GetProcessHeap(),0,newDevice->axis_map);
HeapFree(GetProcessHeap(),0,newDevice->name);
HeapFree(GetProcessHeap(),0,newDevice->props);
HeapFree(GetProcessHeap(),0,newDevice->user_df->rgodf);
HeapFree(GetProcessHeap(),0,newDevice->user_df);
HeapFree(GetProcessHeap(),0,newDevice);
*pdev = 0;
return hr;
}
static BOOL IsJoystickGUID(REFGUID guid)
{
GUID wine_joystick = DInput_Wine_Joystick_GUID;
GUID dev_guid = *guid;
wine_joystick.Data3 = 0;
dev_guid.Data3 = 0;
return IsEqualGUID(&wine_joystick, &dev_guid);
}
static HRESULT joydev_create_deviceA(IDirectInputImpl *dinput, REFGUID rguid, REFIID riid, LPDIRECTINPUTDEVICEA* pdev)
{
if ((IsEqualGUID(&GUID_Joystick,rguid)) ||
(IsJoystickGUID(rguid))) {
if ((riid == NULL) ||
IsEqualGUID(&IID_IDirectInputDeviceA,riid) ||
IsEqualGUID(&IID_IDirectInputDevice2A,riid) ||
IsEqualGUID(&IID_IDirectInputDevice7A,riid) ||
IsEqualGUID(&IID_IDirectInputDevice8A,riid)) {
return alloc_device(rguid, &JoystickAvt, dinput, pdev);
} else {
WARN("no interface\n");
*pdev = 0;
return DIERR_NOINTERFACE;
}
}
WARN("invalid device GUID\n");
*pdev = 0;
return DIERR_DEVICENOTREG;
}
static HRESULT joydev_create_deviceW(IDirectInputImpl *dinput, REFGUID rguid, REFIID riid, LPDIRECTINPUTDEVICEW* pdev)
{
if ((IsEqualGUID(&GUID_Joystick,rguid)) ||
(IsJoystickGUID(rguid))) {
if ((riid == NULL) ||
IsEqualGUID(&IID_IDirectInputDeviceW,riid) ||
IsEqualGUID(&IID_IDirectInputDevice2W,riid) ||
IsEqualGUID(&IID_IDirectInputDevice7W,riid) ||
IsEqualGUID(&IID_IDirectInputDevice8W,riid)) {
return alloc_device(rguid, &JoystickWvt, dinput, (LPDIRECTINPUTDEVICEA *)pdev);
} else {
WARN("no interface\n");
*pdev = 0;
return DIERR_NOINTERFACE;
}
}
WARN("invalid device GUID\n");
*pdev = 0;
return DIERR_DEVICENOTREG;
}
const struct dinput_device joystick_linux_device = {
"Wine Linux joystick driver",
joydev_enum_deviceA,
joydev_enum_deviceW,
joydev_create_deviceA,
joydev_create_deviceW
};
/******************************************************************************
* Joystick
*/
static ULONG WINAPI JoystickAImpl_Release(LPDIRECTINPUTDEVICE8A iface)
{
JoystickImpl *This = (JoystickImpl *)iface;
ULONG ref;
ref = InterlockedDecrement((&This->ref));
if (ref)
return ref;
/* Free the device name */
HeapFree(GetProcessHeap(),0,This->name);
/* Free the axis map */
HeapFree(GetProcessHeap(),0,This->axis_map);
/* Free the data queue */
HeapFree(GetProcessHeap(),0,This->data_queue);
/* Free the DataFormat */
HeapFree(GetProcessHeap(), 0, This->user_df->rgodf);
HeapFree(GetProcessHeap(), 0, This->user_df);
/* Free the properties */
HeapFree(GetProcessHeap(), 0, This->props);
/* Free the offsets array */
HeapFree(GetProcessHeap(),0,This->offsets);
/* release the data transform filter */
release_DataFormat(This->transform);
This->crit.DebugInfo->Spare[0] = 0;
DeleteCriticalSection(&(This->crit));
IDirectInputDevice_Release((LPDIRECTINPUTDEVICE8A)This->dinput);
HeapFree(GetProcessHeap(),0,This);
return 0;
}
/******************************************************************************
* SetDataFormat : the application can choose the format of the data
* the device driver sends back with GetDeviceState.
*/
static HRESULT WINAPI JoystickAImpl_SetDataFormat(
LPDIRECTINPUTDEVICE8A iface,
LPCDIDATAFORMAT df)
{
JoystickImpl *This = (JoystickImpl *)iface;
unsigned int i;
LPDIDATAFORMAT new_df = 0;
LPDIOBJECTDATAFORMAT new_rgodf = 0;
ObjProps * new_props = 0;
TRACE("(%p,%p)\n",This,df);
if (df == NULL) {
WARN("invalid pointer\n");
return E_POINTER;
}
if (df->dwSize != sizeof(*df)) {
WARN("invalid argument\n");
return DIERR_INVALIDPARAM;
}
if (This->acquired) {
WARN("acquired\n");
return DIERR_ACQUIRED;
}
if (TRACE_ON(dinput))
_dump_DIDATAFORMAT(df);
/* Store the new data format */
new_df = HeapAlloc(GetProcessHeap(),0,df->dwSize);
if (new_df == 0)
goto FAILED;
new_rgodf = HeapAlloc(GetProcessHeap(),0,df->dwNumObjs*df->dwObjSize);
if (new_rgodf == 0)
goto FAILED;
new_props = HeapAlloc(GetProcessHeap(),0,df->dwNumObjs*sizeof(ObjProps));
if (new_props == 0)
goto FAILED;
HeapFree(GetProcessHeap(),0,This->user_df);
HeapFree(GetProcessHeap(),0,This->user_df->rgodf);
HeapFree(GetProcessHeap(),0,This->props);
release_DataFormat(This->transform);
This->user_df = new_df;
CopyMemory(This->user_df, df, df->dwSize);
This->user_df->rgodf = new_rgodf;
CopyMemory(This->user_df->rgodf,df->rgodf,df->dwNumObjs*df->dwObjSize);
This->props = new_props;
for (i = 0; i < df->dwNumObjs; i++) {
This->props[i].lMin = 0;
This->props[i].lMax = 0xffff;
This->props[i].lDeadZone = 1000;
This->props[i].lSaturation = 0;
}
This->transform = create_DataFormat(&c_dfDIJoystick2, This->user_df, This->offsets);
calculate_ids(This);
return DI_OK;
FAILED:
WARN("out of memory\n");
HeapFree(GetProcessHeap(),0,new_props);
HeapFree(GetProcessHeap(),0,new_rgodf);
HeapFree(GetProcessHeap(),0,new_df);
return DIERR_OUTOFMEMORY;
}
/******************************************************************************
* Acquire : gets exclusive control of the joystick
*/
static HRESULT WINAPI JoystickAImpl_Acquire(LPDIRECTINPUTDEVICE8A iface)
{
JoystickImpl *This = (JoystickImpl *)iface;
TRACE("(%p)\n",This);
if (This->acquired) {
WARN("already acquired\n");
return S_FALSE;
}
/* open the joystick device */
if (This->joyfd==-1) {
TRACE("opening joystick device %s\n", This->dev);
This->joyfd=open(This->dev,O_RDONLY);
if (This->joyfd==-1) {
ERR("open(%s) failed: %s\n", This->dev, strerror(errno));
return DIERR_NOTFOUND;
}
}
This->acquired = TRUE;
return DI_OK;
}
/******************************************************************************
* Unacquire : frees the joystick
*/
static HRESULT WINAPI JoystickAImpl_Unacquire(LPDIRECTINPUTDEVICE8A iface)
{
JoystickImpl *This = (JoystickImpl *)iface;
TRACE("(%p)\n",This);
if (!This->acquired) {
WARN("not acquired\n");
return DIERR_NOTACQUIRED;
}
if (This->joyfd!=-1) {
TRACE("closing joystick device\n");
close(This->joyfd);
This->joyfd = -1;
This->acquired = FALSE;
return DI_OK;
}
This->acquired = FALSE;
return DI_NOEFFECT;
}
static LONG map_axis(JoystickImpl * This, short val, short index)
{
double fval = val;
double fmin = This->props[index].lMin;
double fmax = This->props[index].lMax;
double fret;
fret = (((fval + 32767.0) * (fmax - fmin)) / (32767.0*2.0)) + fmin;
if (fret >= 0.0)
fret += 0.5;
else
fret -= 0.5;
return fret;
}
/* convert wine format offset to user format object index */
static int offset_to_object(JoystickImpl *This, int offset)
{
int i;
for (i = 0; i < This->user_df->dwNumObjs; i++) {
if (This->user_df->rgodf[i].dwOfs == offset)
return i;
}
return -1;
}
static LONG calculate_pov(JoystickImpl *This, int index)
{
if (This->povs[index].lX < 16384) {
if (This->povs[index].lY < 16384)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -