📄 effect_linuxinput.c
字号:
/* DirectInput Linux Event Device Effect
*
* Copyright 2005 Daniel Remenak
*
* Thanks to Google's Summer of Code Program (2005)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "config.h"
#ifdef HAVE_STRUCT_FF_EFFECT_DIRECTION
#include <stdarg.h>
#include <string.h>
#ifdef HAVE_LINUX_INPUT_H
# include <linux/input.h>
#endif
#include <errno.h>
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#include <math.h>
#include "wine/debug.h"
#include "wine/unicode.h"
#include "windef.h"
#include "winbase.h"
#include "winerror.h"
#include "dinput.h"
#include "device_private.h"
WINE_DEFAULT_DEBUG_CHANNEL(dinput);
static const IDirectInputEffectVtbl LinuxInputEffectVtbl;
typedef struct LinuxInputEffectImpl LinuxInputEffectImpl;
struct LinuxInputEffectImpl
{
const void *lpVtbl;
LONG ref;
GUID guid;
/* Effect data */
struct ff_effect effect;
/* Parent device */
int* fd;
};
/******************************************************************************
* DirectInputEffect Functional Helper
*/
static DWORD _typeFromGUID(REFGUID guid)
{
if (IsEqualGUID(guid, &GUID_ConstantForce)) {
return DIEFT_CONSTANTFORCE;
} else if (IsEqualGUID(guid, &GUID_Square)
|| IsEqualGUID(guid, &GUID_Sine)
|| IsEqualGUID(guid, &GUID_Triangle)
|| IsEqualGUID(guid, &GUID_SawtoothUp)
|| IsEqualGUID(guid, &GUID_SawtoothDown)) {
return DIEFT_PERIODIC;
} else if (IsEqualGUID(guid, &GUID_RampForce)) {
return DIEFT_RAMPFORCE;
} else if (IsEqualGUID(guid, &GUID_Spring)
|| IsEqualGUID(guid, &GUID_Damper)
|| IsEqualGUID(guid, &GUID_Inertia)
|| IsEqualGUID(guid, &GUID_Friction)) {
return DIEFT_CONDITION;
} else if (IsEqualGUID(guid, &GUID_CustomForce)) {
return DIEFT_CUSTOMFORCE;
} else {
WARN("GUID (%s) is not a known force type\n", _dump_dinput_GUID(guid));
return 0;
}
}
/******************************************************************************
* DirectInputEffect debug helpers
*/
static void _dump_DIEFFECT_flags(DWORD dwFlags)
{
if (TRACE_ON(dinput)) {
unsigned int i;
static const struct {
DWORD mask;
const char *name;
} flags[] = {
#define FE(x) { x, #x}
FE(DIEFF_CARTESIAN),
FE(DIEFF_OBJECTIDS),
FE(DIEFF_OBJECTOFFSETS),
FE(DIEFF_POLAR),
FE(DIEFF_SPHERICAL)
#undef FE
};
for (i = 0; i < (sizeof(flags) / sizeof(flags[0])); i++)
if (flags[i].mask & dwFlags)
DPRINTF("%s ", flags[i].name);
DPRINTF("\n");
}
}
static void _dump_DIENVELOPE(LPDIENVELOPE env)
{
if (env->dwSize != sizeof(DIENVELOPE)) {
WARN("Non-standard DIENVELOPE structure size (%ld instead of %d).\n",
env->dwSize, sizeof(DIENVELOPE));
}
TRACE("Envelope has attack (level: %ld time: %ld), fade (level: %ld time: %ld)\n",
env->dwAttackLevel, env->dwAttackTime, env->dwFadeLevel, env->dwFadeTime);
}
static void _dump_DICONSTANTFORCE(LPDICONSTANTFORCE frc)
{
TRACE("Constant force has magnitude %ld\n", frc->lMagnitude);
}
static void _dump_DIPERIODIC(LPDIPERIODIC frc)
{
TRACE("Periodic force has magnitude %ld, offset %ld, phase %ld, period %ld\n",
frc->dwMagnitude, frc->lOffset, frc->dwPhase, frc->dwPeriod);
}
static void _dump_DIRAMPFORCE(LPDIRAMPFORCE frc)
{
TRACE("Ramp force has start %ld, end %ld\n",
frc->lStart, frc->lEnd);
}
static void _dump_DICONDITION(LPDICONDITION frc)
{
TRACE("Condition has offset %ld, pos/neg coefficients %ld and %ld, pos/neg saturations %ld and %ld, deadband %ld\n",
frc->lOffset, frc->lPositiveCoefficient, frc->lNegativeCoefficient,
frc->dwPositiveSaturation, frc->dwNegativeSaturation, frc->lDeadBand);
}
static void _dump_DICUSTOMFORCE(LPDICUSTOMFORCE frc)
{
unsigned int i;
TRACE("Custom force uses %ld channels, sample period %ld. Has %ld samples at %p.\n",
frc->cChannels, frc->dwSamplePeriod, frc->cSamples, frc->rglForceData);
if (frc->cSamples % frc->cChannels != 0)
WARN("Custom force has a non-integral samples-per-channel count!\n");
if (TRACE_ON(dinput)) {
DPRINTF("Custom force data (time aligned, axes in order):\n");
for (i = 1; i <= frc->cSamples; ++i) {
DPRINTF("%ld ", frc->rglForceData[i]);
if (i % frc->cChannels == 0)
DPRINTF("\n");
}
}
}
static void _dump_DIEFFECT(LPCDIEFFECT eff, REFGUID guid)
{
unsigned int i;
DWORD type = _typeFromGUID(guid);
TRACE("Dumping DIEFFECT structure:\n");
TRACE(" - dwSize: %ld\n", eff->dwSize);
if ((eff->dwSize != sizeof(DIEFFECT)) && (eff->dwSize != sizeof(DIEFFECT_DX5))) {
WARN("Non-standard DIEFFECT structure size (%ld instead of %d or %d).\n",
eff->dwSize, sizeof(DIEFFECT), sizeof(DIEFFECT_DX5));
}
TRACE(" - dwFlags: %ld\n", eff->dwFlags);
TRACE(" ");
_dump_DIEFFECT_flags(eff->dwFlags);
TRACE(" - dwDuration: %ld\n", eff->dwDuration);
TRACE(" - dwGain: %ld\n", eff->dwGain);
if ((eff->dwGain > 10000) || (eff->dwGain < 0))
WARN("dwGain is out of range (0 - 10,000)\n");
TRACE(" - dwTriggerButton: %ld\n", eff->dwTriggerButton);
TRACE(" - dwTriggerRepeatInterval: %ld\n", eff->dwTriggerRepeatInterval);
TRACE(" - cAxes: %ld\n", eff->cAxes);
TRACE(" - rgdwAxes: %p\n", eff->rgdwAxes);
if (TRACE_ON(dinput)) {
TRACE(" ");
for (i = 0; i < eff->cAxes; ++i)
DPRINTF("%ld ", eff->rgdwAxes[i]);
DPRINTF("\n");
}
TRACE(" - rglDirection: %p\n", eff->rglDirection);
TRACE(" - lpEnvelope: %p\n", eff->lpEnvelope);
TRACE(" - cbTypeSpecificParams: %ld\n", eff->cbTypeSpecificParams);
TRACE(" - lpvTypeSpecificParams: %p\n", eff->lpvTypeSpecificParams);
if (eff->dwSize > sizeof(DIEFFECT_DX5))
TRACE(" - dwStartDelay: %ld\n", eff->dwStartDelay);
if (eff->lpEnvelope != NULL)
_dump_DIENVELOPE(eff->lpEnvelope);
if (type == DIEFT_CONSTANTFORCE) {
if (eff->cbTypeSpecificParams != sizeof(DICONSTANTFORCE)) {
WARN("Effect claims to be a constant force but the type-specific params are the wrong size!\n");
} else {
_dump_DICONSTANTFORCE(eff->lpvTypeSpecificParams);
}
} else if (type == DIEFT_PERIODIC) {
if (eff->cbTypeSpecificParams != sizeof(DIPERIODIC)) {
WARN("Effect claims to be a periodic force but the type-specific params are the wrong size!\n");
} else {
_dump_DIPERIODIC(eff->lpvTypeSpecificParams);
}
} else if (type == DIEFT_RAMPFORCE) {
if (eff->cbTypeSpecificParams != sizeof(DIRAMPFORCE)) {
WARN("Effect claims to be a ramp force but the type-specific params are the wrong size!\n");
} else {
_dump_DIRAMPFORCE(eff->lpvTypeSpecificParams);
}
} else if (type == DIEFT_CONDITION) {
if (eff->cbTypeSpecificParams != sizeof(DICONDITION)) {
WARN("Effect claims to be a condition but the type-specific params are the wrong size!\n");
} else {
_dump_DICONDITION(eff->lpvTypeSpecificParams);
}
} else if (type == DIEFT_CUSTOMFORCE) {
if (eff->cbTypeSpecificParams != sizeof(DICUSTOMFORCE)) {
WARN("Effect claims to be a custom force but the type-specific params are the wrong size!\n");
} else {
_dump_DICUSTOMFORCE(eff->lpvTypeSpecificParams);
}
}
}
/******************************************************************************
* LinuxInputEffectImpl
*/
static ULONG WINAPI LinuxInputEffectImpl_AddRef(
LPDIRECTINPUTEFFECT iface)
{
LinuxInputEffectImpl *This = (LinuxInputEffectImpl *)iface;
return InterlockedIncrement(&(This->ref));
}
static HRESULT WINAPI LinuxInputEffectImpl_Download(
LPDIRECTINPUTEFFECT iface)
{
LinuxInputEffectImpl *This = (LinuxInputEffectImpl *)iface;
TRACE("(this=%p)\n", This);
if (ioctl(*(This->fd), EVIOCSFF, &This->effect) == -1) {
if (errno == ENOMEM) {
return DIERR_DEVICEFULL;
} else {
FIXME("Could not upload effect. Assuming a disconnected device.\n");
return DIERR_INPUTLOST;
}
}
return DI_OK;
}
static HRESULT WINAPI LinuxInputEffectImpl_Escape(
LPDIRECTINPUTEFFECT iface,
LPDIEFFESCAPE pesc)
{
WARN("(this=%p,%p): invalid: no hardware-specific escape codes in this"
" driver!\n", iface, pesc);
return DI_OK;
}
static HRESULT WINAPI LinuxInputEffectImpl_GetEffectGuid(
LPDIRECTINPUTEFFECT iface,
LPGUID pguid)
{
LinuxInputEffectImpl *This = (LinuxInputEffectImpl*)iface;
TRACE("(this=%p,%p)\n", This, pguid);
pguid = &This->guid;
return DI_OK;
}
static HRESULT WINAPI LinuxInputEffectImpl_GetEffectStatus(
LPDIRECTINPUTEFFECT iface,
LPDWORD pdwFlags)
{
TRACE("(this=%p,%p)\n", iface, pdwFlags);
/* linux sends the effect status through an event.
* that event is trapped by our parent joystick driver
* and there is no clean way to pass it back to us. */
FIXME("Not enough information to provide a status.\n");
(*pdwFlags) = 0;
return DI_OK;
}
static HRESULT WINAPI LinuxInputEffectImpl_GetParameters(
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -