dinput: Remove legacy joystick backends.
Signed-off-by: Rémi Bernon <rbernon@codeweavers.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
7011685e1e
commit
adfee25b45
|
@ -731,7 +731,6 @@ SYSTEMCONFIGURATION_LIBS
|
|||
APPKIT_LIBS
|
||||
CORESERVICES_LIBS
|
||||
APPLICATIONSERVICES_LIBS
|
||||
FORCEFEEDBACK_LIBS
|
||||
IOKIT_LIBS
|
||||
COREFOUNDATION_LIBS
|
||||
OBJCPP
|
||||
|
@ -8764,8 +8763,6 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu
|
|||
|
||||
IOKIT_LIBS="-framework IOKit -framework CoreFoundation"
|
||||
|
||||
FORCEFEEDBACK_LIBS="-framework ForceFeedback -framework CoreFoundation"
|
||||
|
||||
APPLICATIONSERVICES_LIBS="-framework ApplicationServices"
|
||||
|
||||
CORESERVICES_LIBS="-framework CoreServices"
|
||||
|
@ -19615,7 +19612,6 @@ ALL_VARS_RULES="I386_LIBS = $I386_LIBS
|
|||
OPENGL_LIBS = $OPENGL_LIBS
|
||||
COREFOUNDATION_LIBS = $COREFOUNDATION_LIBS
|
||||
IOKIT_LIBS = $IOKIT_LIBS
|
||||
FORCEFEEDBACK_LIBS = $FORCEFEEDBACK_LIBS
|
||||
APPLICATIONSERVICES_LIBS = $APPLICATIONSERVICES_LIBS
|
||||
CORESERVICES_LIBS = $CORESERVICES_LIBS
|
||||
APPKIT_LIBS = $APPKIT_LIBS
|
||||
|
|
|
@ -740,7 +740,6 @@ case $host_os in
|
|||
dnl declare needed frameworks
|
||||
AC_SUBST(COREFOUNDATION_LIBS,"-framework CoreFoundation")
|
||||
AC_SUBST(IOKIT_LIBS,"-framework IOKit -framework CoreFoundation")
|
||||
AC_SUBST(FORCEFEEDBACK_LIBS,"-framework ForceFeedback -framework CoreFoundation")
|
||||
AC_SUBST(APPLICATIONSERVICES_LIBS,"-framework ApplicationServices")
|
||||
AC_SUBST(CORESERVICES_LIBS,"-framework CoreServices")
|
||||
AC_SUBST(APPKIT_LIBS,"-framework AppKit")
|
||||
|
|
|
@ -2,7 +2,6 @@ MODULE = dinput.dll
|
|||
IMPORTLIB = dinput
|
||||
IMPORTS = dinput dxguid uuid comctl32 ole32 user32 advapi32 hid setupapi
|
||||
EXTRADEFS = -DDIRECTINPUT_VERSION=0x0700
|
||||
EXTRALIBS = $(IOKIT_LIBS) $(FORCEFEEDBACK_LIBS)
|
||||
|
||||
EXTRADLLFLAGS = -mcygwin
|
||||
|
||||
|
@ -12,12 +11,7 @@ C_SRCS = \
|
|||
data_formats.c \
|
||||
device.c \
|
||||
dinput_main.c \
|
||||
effect_linuxinput.c \
|
||||
joystick.c \
|
||||
joystick_hid.c \
|
||||
joystick_linux.c \
|
||||
joystick_linuxinput.c \
|
||||
joystick_osx.c \
|
||||
keyboard.c \
|
||||
mouse.c
|
||||
|
||||
|
|
|
@ -187,11 +187,6 @@ void _dump_DIPROPHEADER(LPCDIPROPHEADER diph) {
|
|||
}
|
||||
}
|
||||
|
||||
void _dump_OBJECTINSTANCEA(const DIDEVICEOBJECTINSTANCEA *ddoi) {
|
||||
TRACE(" - enumerating : %s ('%s') - %2d - 0x%08x - %s - 0x%x\n",
|
||||
debugstr_guid(&ddoi->guidType), _dump_dinput_GUID(&ddoi->guidType), ddoi->dwOfs, ddoi->dwType, ddoi->tszName, ddoi->dwFlags);
|
||||
}
|
||||
|
||||
void _dump_OBJECTINSTANCEW(const DIDEVICEOBJECTINSTANCEW *ddoi) {
|
||||
TRACE(" - enumerating : %s ('%s'), - %2d - 0x%08x - %s - 0x%x\n",
|
||||
debugstr_guid(&ddoi->guidType), _dump_dinput_GUID(&ddoi->guidType), ddoi->dwOfs, ddoi->dwType, debugstr_w(ddoi->tszName), ddoi->dwFlags);
|
||||
|
@ -437,7 +432,7 @@ void fill_DataFormat(void *out, DWORD size, const void *in, const DataFormat *df
|
|||
}
|
||||
}
|
||||
|
||||
void release_DataFormat(DataFormat * format)
|
||||
static void release_DataFormat( DataFormat *format )
|
||||
{
|
||||
TRACE("Deleting DataFormat: %p\n", format);
|
||||
|
||||
|
@ -637,20 +632,7 @@ static int verify_offset(const DataFormat *df, int offset)
|
|||
return -1;
|
||||
}
|
||||
|
||||
/* find an object by its offset in a data format */
|
||||
static int offset_to_object(const DataFormat *df, int offset)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!df->offsets) return -1;
|
||||
|
||||
for (i = 0; i < df->wine_df->dwNumObjs; i++)
|
||||
if (df->offsets[i] == offset) return i;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int id_to_object(LPCDIDATAFORMAT df, int id)
|
||||
static int id_to_object( LPCDIDATAFORMAT df, int id )
|
||||
{
|
||||
int i;
|
||||
|
||||
|
@ -669,18 +651,6 @@ static int id_to_offset(const DataFormat *df, int id)
|
|||
return obj >= 0 && df->offsets ? df->offsets[obj] : -1;
|
||||
}
|
||||
|
||||
int find_property(const DataFormat *df, LPCDIPROPHEADER ph)
|
||||
{
|
||||
switch (ph->dwHow)
|
||||
{
|
||||
case DIPH_BYID: return id_to_object(df->wine_df, ph->dwObj);
|
||||
case DIPH_BYOFFSET: return offset_to_object(df, ph->dwObj);
|
||||
}
|
||||
FIXME("Unhandled ph->dwHow=='%04X'\n", (unsigned int)ph->dwHow);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static DWORD semantic_to_obj_id(IDirectInputDeviceImpl* This, DWORD dwSemantic)
|
||||
{
|
||||
DWORD type = (0x0000ff00 & dwSemantic) >> 8;
|
||||
|
|
|
@ -102,43 +102,16 @@ extern BOOL device_instance_is_disabled( DIDEVICEINSTANCEW *instance, BOOL *over
|
|||
|
||||
/* Routines to do DataFormat / WineFormat conversions */
|
||||
extern void fill_DataFormat(void *out, DWORD size, const void *in, const DataFormat *df) DECLSPEC_HIDDEN;
|
||||
extern void release_DataFormat(DataFormat *df) DECLSPEC_HIDDEN;
|
||||
extern void queue_event( IDirectInputDevice8W *iface, int inst_id, DWORD data, DWORD time, DWORD seq ) DECLSPEC_HIDDEN;
|
||||
/* Helper functions to work with data format */
|
||||
extern int id_to_object(LPCDIDATAFORMAT df, int id) DECLSPEC_HIDDEN;
|
||||
extern int find_property(const DataFormat *df, LPCDIPROPHEADER ph) DECLSPEC_HIDDEN;
|
||||
|
||||
/* Common joystick stuff */
|
||||
typedef struct
|
||||
{
|
||||
LONG lDevMin;
|
||||
LONG lDevMax;
|
||||
LONG lMin;
|
||||
LONG lMax;
|
||||
LONG lDeadZone;
|
||||
LONG lSaturation;
|
||||
} ObjProps;
|
||||
|
||||
extern DWORD joystick_map_pov(const POINTL *p) DECLSPEC_HIDDEN;
|
||||
extern LONG joystick_map_axis(ObjProps *props, int val) DECLSPEC_HIDDEN;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
struct list entry;
|
||||
LPDIRECTINPUTEFFECT ref;
|
||||
} effect_list_item;
|
||||
|
||||
extern const GUID dinput_pidvid_guid DECLSPEC_HIDDEN;
|
||||
|
||||
/* Various debug tools */
|
||||
extern void _dump_DIPROPHEADER(LPCDIPROPHEADER diph) DECLSPEC_HIDDEN;
|
||||
extern void _dump_OBJECTINSTANCEA(const DIDEVICEOBJECTINSTANCEA *ddoi) DECLSPEC_HIDDEN;
|
||||
extern void _dump_OBJECTINSTANCEW(const DIDEVICEOBJECTINSTANCEW *ddoi) DECLSPEC_HIDDEN;
|
||||
extern void _dump_DIDATAFORMAT(const DIDATAFORMAT *df) DECLSPEC_HIDDEN;
|
||||
extern const char *_dump_dinput_GUID(const GUID *guid) DECLSPEC_HIDDEN;
|
||||
|
||||
extern LPDIOBJECTDATAFORMAT dataformat_to_odf_by_type(LPCDIDATAFORMAT df, int n, DWORD type) DECLSPEC_HIDDEN;
|
||||
|
||||
extern HRESULT _build_action_map(LPDIRECTINPUTDEVICE8W iface, LPDIACTIONFORMATW lpdiaf, LPCWSTR lpszUserName, DWORD dwFlags, DWORD devMask, LPCDIDATAFORMAT df) DECLSPEC_HIDDEN;
|
||||
extern HRESULT _set_action_map(LPDIRECTINPUTDEVICE8W iface, LPDIACTIONFORMATW lpdiaf, LPCWSTR lpszUserName, DWORD dwFlags, LPCDIDATAFORMAT df) DECLSPEC_HIDDEN;
|
||||
|
||||
|
|
|
@ -78,9 +78,6 @@ static const struct dinput_device *dinput_devices[] =
|
|||
{
|
||||
&mouse_device,
|
||||
&keyboard_device,
|
||||
&joystick_linuxinput_device,
|
||||
&joystick_linux_device,
|
||||
&joystick_osx_device,
|
||||
&joystick_hid_device,
|
||||
};
|
||||
|
||||
|
|
|
@ -68,9 +68,6 @@ struct DevicePlayer {
|
|||
extern const struct dinput_device mouse_device DECLSPEC_HIDDEN;
|
||||
extern const struct dinput_device keyboard_device DECLSPEC_HIDDEN;
|
||||
extern const struct dinput_device joystick_hid_device DECLSPEC_HIDDEN;
|
||||
extern const struct dinput_device joystick_linux_device DECLSPEC_HIDDEN;
|
||||
extern const struct dinput_device joystick_linuxinput_device DECLSPEC_HIDDEN;
|
||||
extern const struct dinput_device joystick_osx_device DECLSPEC_HIDDEN;
|
||||
|
||||
extern void dinput_hooks_acquire_device(LPDIRECTINPUTDEVICE8W iface);
|
||||
extern void dinput_hooks_unacquire_device(LPDIRECTINPUTDEVICE8W iface);
|
||||
|
|
|
@ -1,906 +0,0 @@
|
|||
/* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, 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>
|
||||
# undef SW_MAX
|
||||
#endif
|
||||
#include <limits.h>
|
||||
#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"
|
||||
#include "joystick_private.h"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(dinput);
|
||||
|
||||
static const IDirectInputEffectVtbl LinuxInputEffectVtbl;
|
||||
typedef struct LinuxInputEffectImpl LinuxInputEffectImpl;
|
||||
struct LinuxInputEffectImpl
|
||||
{
|
||||
IDirectInputEffect IDirectInputEffect_iface;
|
||||
LONG ref;
|
||||
GUID guid;
|
||||
|
||||
struct ff_effect effect; /* Effect data */
|
||||
int gain; /* Effect gain */
|
||||
BOOL first_axis_is_x;
|
||||
int* fd; /* Parent device */
|
||||
struct list *entry; /* Entry into the parent's list of effects */
|
||||
};
|
||||
|
||||
static inline LinuxInputEffectImpl *impl_from_IDirectInputEffect(IDirectInputEffect *iface)
|
||||
{
|
||||
return CONTAINING_RECORD(iface, LinuxInputEffectImpl, IDirectInputEffect_iface);
|
||||
}
|
||||
|
||||
static double ff_effect_direction_to_rad(unsigned int dir)
|
||||
{
|
||||
return (dir & 0xffff) * M_PI / 0x8000;
|
||||
}
|
||||
|
||||
static void ff_dump_effect(struct ff_effect *effect)
|
||||
{
|
||||
const char *type = "(Unknown)", *length = "INFINITE";
|
||||
struct ff_envelope *env = NULL;
|
||||
double angle;
|
||||
#define FE(x) case x: type = #x; break
|
||||
switch (effect->type)
|
||||
{
|
||||
FE(FF_RUMBLE);
|
||||
FE(FF_PERIODIC);
|
||||
FE(FF_CONSTANT);
|
||||
FE(FF_SPRING);
|
||||
FE(FF_FRICTION);
|
||||
FE(FF_DAMPER);
|
||||
FE(FF_INERTIA);
|
||||
FE(FF_RAMP);
|
||||
}
|
||||
#undef FE
|
||||
|
||||
/* rotate so 0 points right */
|
||||
angle = 360 - ff_effect_direction_to_rad(effect->direction + 0xc000) * 180 / M_PI;
|
||||
|
||||
if (effect->replay.length)
|
||||
length = wine_dbg_sprintf("%u ms", effect->replay.length);
|
||||
|
||||
TRACE("type 0x%x %s, id %d, direction 0x%x (source angle %.2f), time length %s, start delay %u ms\n",
|
||||
effect->type, type, effect->id, effect->direction, angle, length, effect->replay.delay);
|
||||
if (effect->trigger.button || effect->trigger.interval)
|
||||
TRACE(" -> trigger button %u, re-trigger interval %u ms\n",
|
||||
effect->trigger.button, effect->trigger.interval);
|
||||
|
||||
if (effect->type == FF_PERIODIC)
|
||||
{
|
||||
struct ff_periodic_effect *per = &effect->u.periodic;
|
||||
const char *wave = "(Unknown)";
|
||||
#define FE(x) case x: wave = #x; break
|
||||
switch (per->waveform)
|
||||
{
|
||||
FE(FF_SQUARE);
|
||||
FE(FF_TRIANGLE);
|
||||
FE(FF_SINE);
|
||||
FE(FF_SAW_UP);
|
||||
FE(FF_SAW_DOWN);
|
||||
FE(FF_CUSTOM);
|
||||
}
|
||||
#undef FE
|
||||
angle = ff_effect_direction_to_rad(per->phase) * 180 / M_PI;
|
||||
TRACE(" -> waveform 0x%x %s, period %u ms, magnitude %d, offset %d, phase 0x%x (angle %.2f), custom len %d\n",
|
||||
per->waveform, wave, per->period, per->magnitude, per->offset, per->phase, angle, per->custom_len);
|
||||
env = &per->envelope;
|
||||
}
|
||||
else if (effect->type == FF_CONSTANT)
|
||||
{
|
||||
struct ff_constant_effect *cons = &effect->u.constant;
|
||||
TRACE(" -> level %d\n", cons->level);
|
||||
env = &cons->envelope;
|
||||
}
|
||||
else if (effect->type == FF_RAMP)
|
||||
{
|
||||
struct ff_ramp_effect *ramp = &effect->u.ramp;
|
||||
TRACE(" -> start/end level %d/%d\n", ramp->start_level, ramp->end_level);
|
||||
env = &ramp->envelope;
|
||||
}
|
||||
else if (effect->type == FF_RUMBLE)
|
||||
{
|
||||
struct ff_rumble_effect *rumble = &effect->u.rumble;
|
||||
TRACE(" -> strong/weak magnitude %u/%u\n", rumble->strong_magnitude, rumble->weak_magnitude);
|
||||
}
|
||||
else if (effect->type == FF_SPRING || effect->type == FF_FRICTION ||
|
||||
effect->type == FF_DAMPER || effect->type == FF_INERTIA)
|
||||
{
|
||||
struct ff_condition_effect *cond = effect->u.condition;
|
||||
int i;
|
||||
for (i = 0; i < 2; i++)
|
||||
{
|
||||
/* format numbers here to make them align correctly */
|
||||
TRACE(" -> [%d] right/left saturation %5u/%5u, right/left coefficient %5d/%5d,"
|
||||
" deadband %5u, center %5d\n", i, cond[i].right_saturation, cond[i].left_saturation,
|
||||
cond[i].right_coeff, cond[i].left_coeff, cond[i].deadband, cond[i].center);
|
||||
}
|
||||
}
|
||||
|
||||
if (env)
|
||||
TRACE(" -> envelope attack length(ms)/level %u/%u, fade length(ms)/level %u/%u\n",
|
||||
env->attack_length, env->attack_level, env->fade_length, env->fade_level);
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* LinuxInputEffectImpl
|
||||
*/
|
||||
|
||||
static ULONG WINAPI LinuxInputEffectImpl_AddRef(
|
||||
LPDIRECTINPUTEFFECT iface)
|
||||
{
|
||||
LinuxInputEffectImpl *This = impl_from_IDirectInputEffect(iface);
|
||||
ULONG ref = InterlockedIncrement(&This->ref);
|
||||
TRACE( "(%p) ref %d\n", This, ref );
|
||||
return ref;
|
||||
}
|
||||
|
||||
static HRESULT WINAPI LinuxInputEffectImpl_Download(
|
||||
LPDIRECTINPUTEFFECT iface)
|
||||
{
|
||||
LinuxInputEffectImpl *This = impl_from_IDirectInputEffect(iface);
|
||||
int ret, old_effect_id;
|
||||
|
||||
TRACE("(this=%p)\n", This);
|
||||
ff_dump_effect(&This->effect);
|
||||
|
||||
old_effect_id = This->effect.id;
|
||||
if (ioctl(*(This->fd), EVIOCSFF, &This->effect) != -1)
|
||||
return DI_OK;
|
||||
|
||||
/* Linux kernel < 3.14 has a bug that incorrectly assigns an effect ID even
|
||||
* on error, restore it here if that is the case. */
|
||||
This->effect.id = old_effect_id;
|
||||
|
||||
switch (errno)
|
||||
{
|
||||
case EINVAL:
|
||||
ret = DIERR_INVALIDPARAM;
|
||||
break;
|
||||
case ENOSPC:
|
||||
ret = DIERR_DEVICEFULL;
|
||||
break;
|
||||
case ENOMEM:
|
||||
ret = DIERR_OUTOFMEMORY;
|
||||
break;
|
||||
default:
|
||||
ret = DIERR_INPUTLOST;
|
||||
break;
|
||||
}
|
||||
TRACE("Could not upload effect to fd %d, errno %d \"%s\", returning 0x%x.\n",
|
||||
*This->fd, errno, strerror(errno), ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
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 = impl_from_IDirectInputEffect(iface);
|
||||
|
||||
TRACE("(this=%p,%p)\n", This, pguid);
|
||||
|
||||
*pguid = This->guid;
|
||||
|
||||
return DI_OK;
|
||||
}
|
||||
|
||||
static HRESULT WINAPI LinuxInputEffectImpl_GetEffectStatus(
|
||||
LPDIRECTINPUTEFFECT iface,
|
||||
LPDWORD pdwFlags)
|
||||
{
|
||||
LinuxInputEffectImpl *This = impl_from_IDirectInputEffect(iface);
|
||||
|
||||
TRACE("(this=%p,%p)\n", This, pdwFlags);
|
||||
|
||||
if (!pdwFlags)
|
||||
return E_POINTER;
|
||||
|
||||
if (This->effect.id == -1)
|
||||
return DIERR_NOTDOWNLOADED;
|
||||
|
||||
/* 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(
|
||||
LPDIRECTINPUTEFFECT iface,
|
||||
LPDIEFFECT peff,
|
||||
DWORD dwFlags)
|
||||
{
|
||||
HRESULT diErr = DI_OK;
|
||||
LinuxInputEffectImpl *This = impl_from_IDirectInputEffect(iface);
|
||||
TRACE("(this=%p,%p,%d)\n", This, peff, dwFlags);
|
||||
|
||||
/* Major conversion factors are:
|
||||
* times: millisecond (linux) -> microsecond (windows) (x * 1000)
|
||||
* forces: scale 0x7FFF (linux) -> scale 10000 (windows) approx ((x / 33) * 10)
|
||||
* angles: scale 0x7FFF (linux) -> scale 35999 (windows) approx ((x / 33) * 36)
|
||||
* angle bases: 0 -> -y (down) (linux) -> 0 -> +x (right) (windows)
|
||||
*/
|
||||
|
||||
if (dwFlags & DIEP_AXES) {
|
||||
if (peff->cAxes < 2 /* linuxinput effects always use 2 axes, x and y */)
|
||||
diErr = DIERR_MOREDATA;
|
||||
peff->cAxes = 2;
|
||||
if (diErr)
|
||||
return diErr;
|
||||
else {
|
||||
peff->rgdwAxes[0] = DIJOFS_X;
|
||||
peff->rgdwAxes[1] = DIJOFS_Y;
|
||||
}
|
||||
}
|
||||
|
||||
if (dwFlags & DIEP_DIRECTION) {
|
||||
if (peff->cAxes < 2)
|
||||
diErr = DIERR_MOREDATA;
|
||||
peff->cAxes = 2;
|
||||
if (diErr)
|
||||
return diErr;
|
||||
else {
|
||||
if (peff->dwFlags & DIEFF_CARTESIAN) {
|
||||
/* rotate so 0 points right */
|
||||
double angle = ff_effect_direction_to_rad(This->effect.direction + 0xc000);
|
||||
peff->rglDirection[0] = sin(angle) * 1000;
|
||||
peff->rglDirection[1] = -cos(angle) * 1000;
|
||||
} else {
|
||||
/* Polar and spherical coordinates are the same for two or less
|
||||
* axes.
|
||||
* Note that we also use this case if NO flags are marked.
|
||||
* According to MSDN, we should return the direction in the
|
||||
* format that it was specified in, if no flags are marked.
|
||||
*/
|
||||
peff->rglDirection[0] = (This->effect.direction / 33) * 36 + 9000;
|
||||
if (peff->rglDirection[0] > 35999)
|
||||
peff->rglDirection[0] -= 35999;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (dwFlags & DIEP_DURATION)
|
||||
{
|
||||
if (!This->effect.replay.length) /* infinite for the linux driver */
|
||||
peff->dwDuration = INFINITE;
|
||||
else
|
||||
peff->dwDuration = (DWORD)This->effect.replay.length * 1000;
|
||||
}
|
||||
|
||||
if (dwFlags & DIEP_ENVELOPE) {
|
||||
struct ff_envelope* env;
|
||||
if (This->effect.type == FF_CONSTANT) env = &This->effect.u.constant.envelope;
|
||||
else if (This->effect.type == FF_PERIODIC) env = &This->effect.u.periodic.envelope;
|
||||
else if (This->effect.type == FF_RAMP) env = &This->effect.u.ramp.envelope;
|
||||
else env = NULL;
|
||||
if (env == NULL) {
|
||||
peff->lpEnvelope = NULL;
|
||||
} else if (peff->lpEnvelope == NULL) {
|
||||
return DIERR_INVALIDPARAM;
|
||||
} else {
|
||||
peff->lpEnvelope->dwAttackLevel = (env->attack_level / 33) * 10;
|
||||
peff->lpEnvelope->dwAttackTime = env->attack_length * 1000;
|
||||
peff->lpEnvelope->dwFadeLevel = (env->fade_level / 33) * 10;
|
||||
peff->lpEnvelope->dwFadeTime = env->fade_length * 1000;
|
||||
}
|
||||
}
|
||||
|
||||
if (dwFlags & DIEP_GAIN) {
|
||||
peff->dwGain = This->gain * 10000 / 0xFFFF;
|
||||
}
|
||||
|
||||
if (dwFlags & DIEP_SAMPLEPERIOD) {
|
||||
/* the linux input ff driver has no support for setting
|
||||
* the playback sample period. 0 means default. */
|
||||
peff->dwSamplePeriod = 0;
|
||||
}
|
||||
|
||||
if ((dwFlags & DIEP_STARTDELAY) && peff->dwSize > sizeof(DIEFFECT_DX5))
|
||||
peff->dwStartDelay = This->effect.replay.delay * 1000;
|
||||
|
||||
if (dwFlags & DIEP_TRIGGERBUTTON) {
|
||||
FIXME("LinuxInput button mapping needs redoing; for now, assuming we're using an actual joystick.\n");
|
||||
peff->dwTriggerButton = DIJOFS_BUTTON(This->effect.trigger.button - BTN_JOYSTICK);
|
||||
}
|
||||
|
||||
if (dwFlags & DIEP_TRIGGERREPEATINTERVAL) {
|
||||
peff->dwTriggerRepeatInterval = This->effect.trigger.interval * 1000;
|
||||
}
|
||||
|
||||
if (dwFlags & DIEP_TYPESPECIFICPARAMS) {
|
||||
DWORD expectedsize = 0;
|
||||
if (This->effect.type == FF_PERIODIC) {
|
||||
expectedsize = sizeof(DIPERIODIC);
|
||||
} else if (This->effect.type == FF_CONSTANT) {
|
||||
expectedsize = sizeof(DICONSTANTFORCE);
|
||||
} else if (This->effect.type == FF_SPRING
|
||||
|| This->effect.type == FF_FRICTION
|
||||
|| This->effect.type == FF_INERTIA
|
||||
|| This->effect.type == FF_DAMPER) {
|
||||
expectedsize = sizeof(DICONDITION) * 2;
|
||||
} else if (This->effect.type == FF_RAMP) {
|
||||
expectedsize = sizeof(DIRAMPFORCE);
|
||||
}
|
||||
if (expectedsize > peff->cbTypeSpecificParams)
|
||||
diErr = DIERR_MOREDATA;
|
||||
peff->cbTypeSpecificParams = expectedsize;
|
||||
if (diErr)
|
||||
return diErr;
|
||||
else {
|
||||
if (This->effect.type == FF_PERIODIC) {
|
||||
LPDIPERIODIC tsp = peff->lpvTypeSpecificParams;
|
||||
tsp->dwMagnitude = (This->effect.u.periodic.magnitude / 33) * 10;
|
||||
tsp->lOffset = (This->effect.u.periodic.offset / 33) * 10;
|
||||
tsp->dwPhase = (This->effect.u.periodic.phase / 33) * 36;
|
||||
tsp->dwPeriod = (This->effect.u.periodic.period * 1000);
|
||||
} else if (This->effect.type == FF_CONSTANT) {
|
||||
LPDICONSTANTFORCE tsp = peff->lpvTypeSpecificParams;
|
||||
tsp->lMagnitude = (This->effect.u.constant.level / 33) * 10;
|
||||
} else if (This->effect.type == FF_SPRING
|
||||
|| This->effect.type == FF_FRICTION
|
||||
|| This->effect.type == FF_INERTIA
|
||||
|| This->effect.type == FF_DAMPER) {
|
||||
LPDICONDITION tsp = peff->lpvTypeSpecificParams;
|
||||
int i;
|
||||
for (i = 0; i < 2; ++i) {
|
||||
tsp[i].lOffset = (This->effect.u.condition[i].center / 33) * 10;
|
||||
tsp[i].lPositiveCoefficient = (This->effect.u.condition[i].right_coeff / 33) * 10;
|
||||
tsp[i].lNegativeCoefficient = (This->effect.u.condition[i].left_coeff / 33) * 10;
|
||||
tsp[i].dwPositiveSaturation = (This->effect.u.condition[i].right_saturation / 33) * 10;
|
||||
tsp[i].dwNegativeSaturation = (This->effect.u.condition[i].left_saturation / 33) * 10;
|
||||
tsp[i].lDeadBand = (This->effect.u.condition[i].deadband / 33) * 10;
|
||||
}
|
||||
} else if (This->effect.type == FF_RAMP) {
|
||||
LPDIRAMPFORCE tsp = peff->lpvTypeSpecificParams;
|
||||
tsp->lStart = (This->effect.u.ramp.start_level / 33) * 10;
|
||||
tsp->lEnd = (This->effect.u.ramp.end_level / 33) * 10;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return diErr;
|
||||
}
|
||||
|
||||
static HRESULT WINAPI LinuxInputEffectImpl_Initialize(
|
||||
LPDIRECTINPUTEFFECT iface,
|
||||
HINSTANCE hinst,
|
||||
DWORD dwVersion,
|
||||
REFGUID rguid)
|
||||
{
|
||||
FIXME("(this=%p,%p,%d,%s): stub!\n",
|
||||
iface, hinst, dwVersion, debugstr_guid(rguid));
|
||||
|
||||
return DI_OK;
|
||||
}
|
||||
|
||||
static HRESULT WINAPI LinuxInputEffectImpl_QueryInterface(
|
||||
LPDIRECTINPUTEFFECT iface,
|
||||
REFIID riid,
|
||||
void **ppvObject)
|
||||
{
|
||||
LinuxInputEffectImpl *This = impl_from_IDirectInputEffect(iface);
|
||||
|
||||
TRACE("(this=%p,%s,%p)\n", This, debugstr_guid(riid), ppvObject);
|
||||
|
||||
if (IsEqualGUID(&IID_IUnknown, riid) ||
|
||||
IsEqualGUID(&IID_IDirectInputEffect, riid)) {
|
||||
LinuxInputEffectImpl_AddRef(iface);
|
||||
*ppvObject = This;
|
||||
return 0;
|
||||
}
|
||||
|
||||
TRACE("Unsupported interface!\n");
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
static HRESULT WINAPI LinuxInputEffectImpl_Start(
|
||||
LPDIRECTINPUTEFFECT iface,
|
||||
DWORD dwIterations,
|
||||
DWORD dwFlags)
|
||||
{
|
||||
struct input_event event;
|
||||
LinuxInputEffectImpl *This = impl_from_IDirectInputEffect(iface);
|
||||
|
||||
TRACE("(this=%p,%d,%d)\n", This, dwIterations, dwFlags);
|
||||
|
||||
if (!(dwFlags & DIES_NODOWNLOAD)) {
|
||||
/* Download the effect if necessary */
|
||||
if (This->effect.id == -1) {
|
||||
HRESULT res = LinuxInputEffectImpl_Download(iface);
|
||||
if (res != DI_OK)
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
if (dwFlags & DIES_SOLO) {
|
||||
FIXME("Solo mode requested: should be stopping all effects here!\n");
|
||||
}
|
||||
|
||||
event.type = EV_FF;
|
||||
event.code = This->effect.id;
|
||||
event.value = min( dwIterations, INT_MAX );
|
||||
if (write(*(This->fd), &event, sizeof(event)) == -1) {
|
||||
FIXME("Unable to write event. Assuming device disconnected.\n");
|
||||
return DIERR_INPUTLOST;
|
||||
}
|
||||
|
||||
return DI_OK;
|
||||
}
|
||||
|
||||
static HRESULT WINAPI LinuxInputEffectImpl_SetParameters(
|
||||
LPDIRECTINPUTEFFECT iface,
|
||||
LPCDIEFFECT peff,
|
||||
DWORD dwFlags)
|
||||
{
|
||||
LinuxInputEffectImpl *This = impl_from_IDirectInputEffect(iface);
|
||||
DWORD type = typeFromGUID(&This->guid);
|
||||
HRESULT retval = DI_OK;
|
||||
|
||||
TRACE("(this=%p,%p,%d)\n", This, peff, dwFlags);
|
||||
|
||||
dump_DIEFFECT(peff, &This->guid, dwFlags);
|
||||
|
||||
if (!dwFlags)
|
||||
return DI_NOEFFECT;
|
||||
|
||||
if (dwFlags & DIEP_AXES) {
|
||||
if (!(peff->rgdwAxes))
|
||||
return DIERR_INVALIDPARAM;
|
||||
|
||||
/* the linux input effect system only supports one or two axes */
|
||||
if (peff->cAxes > 2)
|
||||
return DIERR_INVALIDPARAM;
|
||||
else if (peff->cAxes < 1)
|
||||
return DIERR_INCOMPLETEEFFECT;
|
||||
This->first_axis_is_x = peff->rgdwAxes[0] == DIJOFS_X;
|
||||
}
|
||||
|
||||
/* some of this may look funky, but it's 'cause the linux driver and directx have
|
||||
* different opinions about which way direction "0" is. directx has 0 along the x
|
||||
* axis (left), linux has it along the y axis (down). */
|
||||
if (dwFlags & DIEP_DIRECTION) {
|
||||
if (!(peff->rglDirection))
|
||||
return DIERR_INVALIDPARAM;
|
||||
|
||||
if (peff->cAxes == 1) {
|
||||
if (peff->dwFlags & DIEFF_CARTESIAN) {
|
||||
if (dwFlags & DIEP_AXES) {
|
||||
if (peff->rgdwAxes[0] == DIJOFS_X && peff->rglDirection[0] >= 0)
|
||||
This->effect.direction = 0x4000;
|
||||
else if (peff->rgdwAxes[0] == DIJOFS_X && peff->rglDirection[0] < 0)
|
||||
This->effect.direction = 0xC000;
|
||||
else if (peff->rgdwAxes[0] == DIJOFS_Y && peff->rglDirection[0] >= 0)
|
||||
This->effect.direction = 0;
|
||||
else if (peff->rgdwAxes[0] == DIJOFS_Y && peff->rglDirection[0] < 0)
|
||||
This->effect.direction = 0x8000;
|
||||
}
|
||||
} else {
|
||||
/* one-axis effects must use cartesian coords */
|
||||
return DIERR_INVALIDPARAM;
|
||||
}
|
||||
}
|
||||
/* two axes */
|
||||
else
|
||||
{
|
||||
if (peff->dwFlags & DIEFF_CARTESIAN)
|
||||
{
|
||||
LONG x, y;
|
||||
if (This->first_axis_is_x)
|
||||
{
|
||||
x = peff->rglDirection[0];
|
||||
y = peff->rglDirection[1];
|
||||
}
|
||||
else
|
||||
{
|
||||
x = peff->rglDirection[1];
|
||||
y = peff->rglDirection[0];
|
||||
}
|
||||
This->effect.direction = (unsigned int)((M_PI / 2 + atan2(y, x)) * 0x8000 / M_PI);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Polar and spherical are the same for 2 axes */
|
||||
/* Precision is important here, so we do double math with exact constants */
|
||||
This->effect.direction = (unsigned int)(((double)peff->rglDirection[0] / 18000) * 0x8000);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (dwFlags & DIEP_DURATION)
|
||||
{
|
||||
if (peff->dwDuration == INFINITE)
|
||||
This->effect.replay.length = 0; /* infinite for the linux driver */
|
||||
else if(peff->dwDuration > 1000)
|
||||
This->effect.replay.length = peff->dwDuration / 1000;
|
||||
else
|
||||
This->effect.replay.length = 1;
|
||||
}
|
||||
|
||||
if (dwFlags & DIEP_ENVELOPE)
|
||||
{
|
||||
struct ff_envelope* env;
|
||||
if (This->effect.type == FF_CONSTANT)
|
||||
env = &This->effect.u.constant.envelope;
|
||||
else if (This->effect.type == FF_PERIODIC)
|
||||
env = &This->effect.u.periodic.envelope;
|
||||
else if (This->effect.type == FF_RAMP)
|
||||
env = &This->effect.u.ramp.envelope;
|
||||
else
|
||||
env = NULL;
|
||||
|
||||
/* copy the envelope if it is present and the linux effect supports it */
|
||||
if (peff->lpEnvelope && env)
|
||||
{
|
||||
env->attack_length = peff->lpEnvelope->dwAttackTime / 1000;
|
||||
env->attack_level = (peff->lpEnvelope->dwAttackLevel / 10) * 32;
|
||||
env->fade_length = peff->lpEnvelope->dwFadeTime / 1000;
|
||||
env->fade_level = (peff->lpEnvelope->dwFadeLevel / 10) * 32;
|
||||
}
|
||||
/* if the dinput envelope is NULL we will clear the linux envelope */
|
||||
else if (env)
|
||||
{
|
||||
env->attack_length = 0;
|
||||
env->attack_level = 0;
|
||||
env->fade_length = 0;
|
||||
env->fade_level = 0;
|
||||
}
|
||||
else if(peff->lpEnvelope)
|
||||
{
|
||||
if(peff->lpEnvelope->dwAttackTime || peff->lpEnvelope->dwAttackLevel ||
|
||||
peff->lpEnvelope->dwFadeTime || peff->lpEnvelope->dwFadeLevel)
|
||||
WARN("Ignoring dinput envelope not supported in the linux effect\n");
|
||||
}
|
||||
}
|
||||
|
||||
/* Gain and Sample Period settings are not supported by the linux
|
||||
* event system */
|
||||
if (dwFlags & DIEP_GAIN) {
|
||||
This->gain = 0xFFFF * peff->dwGain / 10000;
|
||||
TRACE("Effect gain requested but no effect gain functionality present.\n");
|
||||
}
|
||||
|
||||
if (dwFlags & DIEP_SAMPLEPERIOD)
|
||||
TRACE("Sample period requested but no sample period functionality present.\n");
|
||||
|
||||
if (dwFlags & DIEP_STARTDELAY)
|
||||
if ((dwFlags & DIEP_STARTDELAY) && peff->dwSize > sizeof(DIEFFECT_DX5))
|
||||
This->effect.replay.delay = peff->dwStartDelay / 1000;
|
||||
|
||||
if (dwFlags & DIEP_TRIGGERBUTTON) {
|
||||
if (peff->dwTriggerButton != -1) {
|
||||
FIXME("Linuxinput button mapping needs redoing, assuming we're using a joystick.\n");
|
||||
FIXME("Trigger button translation not yet implemented!\n");
|
||||
}
|
||||
This->effect.trigger.button = 0;
|
||||
}
|
||||
|
||||
if (dwFlags & DIEP_TRIGGERREPEATINTERVAL)
|
||||
This->effect.trigger.interval = peff->dwTriggerRepeatInterval / 1000;
|
||||
|
||||
if (dwFlags & DIEP_TYPESPECIFICPARAMS)
|
||||
{
|
||||
if (!(peff->lpvTypeSpecificParams))
|
||||
return DIERR_INVALIDPARAM;
|
||||
|
||||
if (type == DIEFT_PERIODIC)
|
||||
{
|
||||
DIPERIODIC *tsp;
|
||||
if (peff->cbTypeSpecificParams != sizeof(DIPERIODIC))
|
||||
return DIERR_INVALIDPARAM;
|
||||
tsp = peff->lpvTypeSpecificParams;
|
||||
|
||||
This->effect.u.periodic.magnitude = (tsp->dwMagnitude / 10) * 32;
|
||||
This->effect.u.periodic.offset = (tsp->lOffset / 10) * 32;
|
||||
/* phase ranges from 0 - 35999 in dinput and 0 - 65535 on Linux */
|
||||
This->effect.u.periodic.phase = (tsp->dwPhase / 36) * 65;
|
||||
/* dinput uses microseconds, Linux uses milliseconds */
|
||||
if (tsp->dwPeriod <= 1000)
|
||||
This->effect.u.periodic.period = 1;
|
||||
else
|
||||
This->effect.u.periodic.period = tsp->dwPeriod / 1000;
|
||||
}
|
||||
else if (type == DIEFT_CONSTANTFORCE)
|
||||
{
|
||||
LPCDICONSTANTFORCE tsp;
|
||||
if (peff->cbTypeSpecificParams != sizeof(DICONSTANTFORCE))
|
||||
return DIERR_INVALIDPARAM;
|
||||
tsp = peff->lpvTypeSpecificParams;
|
||||
This->effect.u.constant.level = (max(min(tsp->lMagnitude, 10000), -10000) / 10) * 32;
|
||||
} else if (type == DIEFT_RAMPFORCE) {
|
||||
LPCDIRAMPFORCE tsp;
|
||||
if (peff->cbTypeSpecificParams != sizeof(DIRAMPFORCE))
|
||||
return DIERR_INVALIDPARAM;
|
||||
tsp = peff->lpvTypeSpecificParams;
|
||||
This->effect.u.ramp.start_level = (tsp->lStart / 10) * 32;
|
||||
This->effect.u.ramp.end_level = (tsp->lEnd / 10) * 32;
|
||||
}
|
||||
else if (type == DIEFT_CONDITION)
|
||||
{
|
||||
DICONDITION *tsp = peff->lpvTypeSpecificParams;
|
||||
struct ff_condition_effect *cond = This->effect.u.condition;
|
||||
int i, j, sources;
|
||||
double factor[2];
|
||||
|
||||
if (peff->cbTypeSpecificParams == sizeof(DICONDITION))
|
||||
{
|
||||
/* One condition block. This needs to be rotated to direction,
|
||||
* and expanded to separate x and y conditions. Ensures 0 points right */
|
||||
double angle = ff_effect_direction_to_rad(This->effect.direction + 0xc000);
|
||||
factor[0] = sin(angle);
|
||||
factor[1] = -cos(angle);
|
||||
sources = 1;
|
||||
}
|
||||
else if (peff->cbTypeSpecificParams == 2 * sizeof(DICONDITION))
|
||||
{
|
||||
/* Direct parameter copy without changes */
|
||||
factor[0] = factor[1] = 1;
|
||||
sources = 2;
|
||||
}
|
||||
else
|
||||
return DIERR_INVALIDPARAM;
|
||||
|
||||
for (i = j = 0; i < 2; ++i)
|
||||
{
|
||||
cond[i].center = (int)(factor[i] * (tsp[j].lOffset / 10) * 32);
|
||||
cond[i].right_coeff = (int)(factor[i] * (tsp[j].lPositiveCoefficient / 10) * 32);
|
||||
cond[i].left_coeff = (int)(factor[i] * (tsp[j].lNegativeCoefficient / 10) * 32);
|
||||
cond[i].right_saturation = (int)(factor[i] * (tsp[j].dwPositiveSaturation / 10) * 65);
|
||||
cond[i].left_saturation = (int)(factor[i] * (tsp[j].dwNegativeSaturation / 10) * 65);
|
||||
cond[i].deadband = (int)(factor[i] * (tsp[j].lDeadBand / 10) * 32);
|
||||
if (sources == 2)
|
||||
j++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
FIXME("Custom force types are not supported\n");
|
||||
return DIERR_INVALIDPARAM;
|
||||
}
|
||||
}
|
||||
|
||||
if (!(dwFlags & DIEP_NODOWNLOAD))
|
||||
retval = LinuxInputEffectImpl_Download(iface);
|
||||
if (retval != DI_OK)
|
||||
return DI_DOWNLOADSKIPPED;
|
||||
|
||||
if (dwFlags & DIEP_NORESTART)
|
||||
TRACE("DIEP_NORESTART: not handled (we have no control of that).\n");
|
||||
|
||||
if (dwFlags & DIEP_START)
|
||||
retval = LinuxInputEffectImpl_Start(iface, 1, 0);
|
||||
if (retval != DI_OK)
|
||||
return retval;
|
||||
|
||||
return DI_OK;
|
||||
}
|
||||
|
||||
static HRESULT WINAPI LinuxInputEffectImpl_Stop(
|
||||
LPDIRECTINPUTEFFECT iface)
|
||||
{
|
||||
struct input_event event;
|
||||
LinuxInputEffectImpl *This = impl_from_IDirectInputEffect(iface);
|
||||
|
||||
TRACE("(this=%p)\n", This);
|
||||
|
||||
event.type = EV_FF;
|
||||
event.code = This->effect.id;
|
||||
event.value = 0;
|
||||
/* we don't care about the success or failure of this call */
|
||||
write(*(This->fd), &event, sizeof(event));
|
||||
|
||||
return DI_OK;
|
||||
}
|
||||
|
||||
static HRESULT WINAPI LinuxInputEffectImpl_Unload(
|
||||
LPDIRECTINPUTEFFECT iface)
|
||||
{
|
||||
LinuxInputEffectImpl *This = impl_from_IDirectInputEffect(iface);
|
||||
TRACE("(this=%p)\n", This);
|
||||
|
||||
/* Erase the downloaded effect */
|
||||
if (ioctl(*(This->fd), EVIOCRMFF, This->effect.id) == -1)
|
||||
return DIERR_INVALIDPARAM;
|
||||
|
||||
/* Mark the effect as deallocated */
|
||||
This->effect.id = -1;
|
||||
|
||||
return DI_OK;
|
||||
}
|
||||
|
||||
static ULONG WINAPI LinuxInputEffectImpl_Release(LPDIRECTINPUTEFFECT iface)
|
||||
{
|
||||
LinuxInputEffectImpl *This = impl_from_IDirectInputEffect(iface);
|
||||
ULONG ref = InterlockedDecrement(&(This->ref));
|
||||
|
||||
TRACE( "(%p) ref %d\n", This, ref );
|
||||
|
||||
if (ref == 0)
|
||||
{
|
||||
LinuxInputEffectImpl_Stop(iface);
|
||||
LinuxInputEffectImpl_Unload(iface);
|
||||
list_remove(This->entry);
|
||||
HeapFree(GetProcessHeap(), 0, LIST_ENTRY(This->entry, effect_list_item, entry));
|
||||
HeapFree(GetProcessHeap(), 0, This);
|
||||
}
|
||||
return ref;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* LinuxInputEffect
|
||||
*/
|
||||
|
||||
DECLSPEC_HIDDEN HRESULT linuxinput_create_effect(
|
||||
int* fd,
|
||||
REFGUID rguid,
|
||||
struct list *parent_list_entry,
|
||||
LPDIRECTINPUTEFFECT* peff)
|
||||
{
|
||||
LinuxInputEffectImpl* newEffect = HeapAlloc(GetProcessHeap(),
|
||||
HEAP_ZERO_MEMORY, sizeof(LinuxInputEffectImpl));
|
||||
DWORD type = typeFromGUID(rguid);
|
||||
|
||||
newEffect->IDirectInputEffect_iface.lpVtbl = &LinuxInputEffectVtbl;
|
||||
newEffect->ref = 1;
|
||||
newEffect->guid = *rguid;
|
||||
newEffect->fd = fd;
|
||||
newEffect->gain = 0xFFFF;
|
||||
|
||||
/* set the type. this cannot be changed over the effect's life. */
|
||||
switch (type) {
|
||||
case DIEFT_PERIODIC:
|
||||
newEffect->effect.type = FF_PERIODIC;
|
||||
if (IsEqualGUID(rguid, &GUID_Sine)) {
|
||||
newEffect->effect.u.periodic.waveform = FF_SINE;
|
||||
} else if (IsEqualGUID(rguid, &GUID_Triangle)) {
|
||||
newEffect->effect.u.periodic.waveform = FF_TRIANGLE;
|
||||
} else if (IsEqualGUID(rguid, &GUID_Square)) {
|
||||
newEffect->effect.u.periodic.waveform = FF_SQUARE;
|
||||
} else if (IsEqualGUID(rguid, &GUID_SawtoothUp)) {
|
||||
newEffect->effect.u.periodic.waveform = FF_SAW_UP;
|
||||
} else if (IsEqualGUID(rguid, &GUID_SawtoothDown)) {
|
||||
newEffect->effect.u.periodic.waveform = FF_SAW_DOWN;
|
||||
}
|
||||
break;
|
||||
case DIEFT_CONSTANTFORCE:
|
||||
newEffect->effect.type = FF_CONSTANT;
|
||||
break;
|
||||
case DIEFT_RAMPFORCE:
|
||||
newEffect->effect.type = FF_RAMP;
|
||||
break;
|
||||
case DIEFT_CONDITION:
|
||||
if (IsEqualGUID(rguid, &GUID_Spring)) {
|
||||
newEffect->effect.type = FF_SPRING;
|
||||
} else if (IsEqualGUID(rguid, &GUID_Friction)) {
|
||||
newEffect->effect.type = FF_FRICTION;
|
||||
} else if (IsEqualGUID(rguid, &GUID_Inertia)) {
|
||||
newEffect->effect.type = FF_INERTIA;
|
||||
} else if (IsEqualGUID(rguid, &GUID_Damper)) {
|
||||
newEffect->effect.type = FF_DAMPER;
|
||||
}
|
||||
break;
|
||||
case DIEFT_CUSTOMFORCE:
|
||||
FIXME("Custom forces are not supported.\n");
|
||||
HeapFree(GetProcessHeap(), 0, newEffect);
|
||||
return DIERR_INVALIDPARAM;
|
||||
default:
|
||||
FIXME("Unknown force type 0x%x.\n", type);
|
||||
HeapFree(GetProcessHeap(), 0, newEffect);
|
||||
return DIERR_INVALIDPARAM;
|
||||
}
|
||||
|
||||
/* mark as non-uploaded */
|
||||
newEffect->effect.id = -1;
|
||||
|
||||
newEffect->entry = parent_list_entry;
|
||||
|
||||
*peff = &newEffect->IDirectInputEffect_iface;
|
||||
|
||||
TRACE("Creating linux input system effect (%p) with guid %s\n",
|
||||
*peff, _dump_dinput_GUID(rguid));
|
||||
|
||||
return DI_OK;
|
||||
}
|
||||
|
||||
DECLSPEC_HIDDEN HRESULT linuxinput_get_info_W(
|
||||
int fd,
|
||||
REFGUID rguid,
|
||||
LPDIEFFECTINFOW info)
|
||||
{
|
||||
DWORD type = typeFromGUID(rguid);
|
||||
|
||||
TRACE("(%d, %s, %p) type=%d\n", fd, _dump_dinput_GUID(rguid), info, type);
|
||||
|
||||
if (!info) return E_POINTER;
|
||||
|
||||
if (info->dwSize != sizeof(DIEFFECTINFOW)) return DIERR_INVALIDPARAM;
|
||||
|
||||
info->guid = *rguid;
|
||||
|
||||
info->dwEffType = type;
|
||||
/* the event device API does not support querying for all these things
|
||||
* therefore we assume that we have support for them
|
||||
* that's not as dangerous as it sounds, since drivers are allowed to
|
||||
* ignore parameters they claim to support anyway */
|
||||
info->dwEffType |= DIEFT_DEADBAND | DIEFT_FFATTACK | DIEFT_FFFADE
|
||||
| DIEFT_POSNEGCOEFFICIENTS | DIEFT_POSNEGSATURATION
|
||||
| DIEFT_SATURATION | DIEFT_STARTDELAY;
|
||||
|
||||
/* again, assume we have support for everything */
|
||||
info->dwStaticParams = DIEP_ALLPARAMS;
|
||||
info->dwDynamicParams = info->dwStaticParams;
|
||||
|
||||
/* yes, this is windows behavior (print the GUID_Name for name) */
|
||||
MultiByteToWideChar(CP_ACP, 0, _dump_dinput_GUID(rguid), -1,
|
||||
info->tszName, MAX_PATH);
|
||||
|
||||
return DI_OK;
|
||||
}
|
||||
|
||||
static const IDirectInputEffectVtbl LinuxInputEffectVtbl = {
|
||||
LinuxInputEffectImpl_QueryInterface,
|
||||
LinuxInputEffectImpl_AddRef,
|
||||
LinuxInputEffectImpl_Release,
|
||||
LinuxInputEffectImpl_Initialize,
|
||||
LinuxInputEffectImpl_GetEffectGuid,
|
||||
LinuxInputEffectImpl_GetParameters,
|
||||
LinuxInputEffectImpl_SetParameters,
|
||||
LinuxInputEffectImpl_Start,
|
||||
LinuxInputEffectImpl_Stop,
|
||||
LinuxInputEffectImpl_GetEffectStatus,
|
||||
LinuxInputEffectImpl_Download,
|
||||
LinuxInputEffectImpl_Unload,
|
||||
LinuxInputEffectImpl_Escape
|
||||
};
|
||||
|
||||
#endif /* HAVE_STRUCT_FF_EFFECT_DIRECTION */
|
|
@ -1,962 +0,0 @@
|
|||
/* DirectInput Generic Joystick device
|
||||
*
|
||||
* Copyright 1998 Marcus Meissner
|
||||
* Copyright 1998,1999 Lionel Ulmer
|
||||
* Copyright 2000-2001 TransGaming Technologies Inc.
|
||||
* Copyright 2009 Aric Stewart, CodeWeavers
|
||||
*
|
||||
* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
/*
|
||||
* To Do:
|
||||
* dead zone
|
||||
* force feedback
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "joystick_private.h"
|
||||
#include "wine/debug.h"
|
||||
#include "winreg.h"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(dinput);
|
||||
|
||||
#define VID_MICROSOFT 0x045e
|
||||
|
||||
static const WORD PID_XBOX_CONTROLLERS[] = {
|
||||
0x0202, /* Xbox Controller */
|
||||
0x0285, /* Xbox Controller S */
|
||||
0x0289, /* Xbox Controller S */
|
||||
0x028e, /* Xbox360 Controller */
|
||||
0x028f, /* Xbox360 Wireless Controller */
|
||||
0x02d1, /* Xbox One Controller */
|
||||
0x02dd, /* Xbox One Controller (Covert Forces/Firmware 2015) */
|
||||
0x02e0, /* Xbox One X Controller */
|
||||
0x02e3, /* Xbox One Elite Controller */
|
||||
0x02e6, /* Wireless XBox Controller Dongle */
|
||||
0x02ea, /* Xbox One S Controller */
|
||||
0x02fd, /* Xbox One S Controller (Firmware 2017) */
|
||||
0x0719, /* Xbox 360 Wireless Adapter */
|
||||
};
|
||||
|
||||
static inline JoystickGenericImpl *impl_from_IDirectInputDevice8W(IDirectInputDevice8W *iface)
|
||||
{
|
||||
return CONTAINING_RECORD(CONTAINING_RECORD(iface, IDirectInputDeviceImpl, IDirectInputDevice8W_iface), JoystickGenericImpl, base);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
DWORD get_device_type(DWORD version, BOOL is_joystick)
|
||||
{
|
||||
if (is_joystick)
|
||||
return version >= 0x0800 ? DI8DEVTYPE_JOYSTICK | (DI8DEVTYPEJOYSTICK_STANDARD << 8) :
|
||||
DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_TRADITIONAL << 8);
|
||||
|
||||
return version >= 0x0800 ? DI8DEVTYPE_GAMEPAD | (DI8DEVTYPEJOYSTICK_STANDARD << 8) :
|
||||
DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_GAMEPAD << 8);
|
||||
}
|
||||
|
||||
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 < ARRAY_SIZE(flags); i++)
|
||||
if (flags[i].mask & dwFlags)
|
||||
TRACE("%s ", flags[i].name);
|
||||
TRACE("\n");
|
||||
}
|
||||
}
|
||||
|
||||
static void _dump_DIENVELOPE(LPCDIENVELOPE env)
|
||||
{
|
||||
if (env->dwSize != sizeof(DIENVELOPE)) {
|
||||
WARN("Non-standard DIENVELOPE structure size %d.\n", env->dwSize);
|
||||
}
|
||||
TRACE("Envelope has attack (level: %d time: %d), fade (level: %d time: %d)\n",
|
||||
env->dwAttackLevel, env->dwAttackTime, env->dwFadeLevel, env->dwFadeTime);
|
||||
}
|
||||
|
||||
static void _dump_DICONSTANTFORCE(LPCDICONSTANTFORCE frc)
|
||||
{
|
||||
TRACE("Constant force has magnitude %d\n", frc->lMagnitude);
|
||||
}
|
||||
|
||||
static void _dump_DIPERIODIC(LPCDIPERIODIC frc)
|
||||
{
|
||||
TRACE("Periodic force has magnitude %d, offset %d, phase %d, period %d\n",
|
||||
frc->dwMagnitude, frc->lOffset, frc->dwPhase, frc->dwPeriod);
|
||||
}
|
||||
|
||||
static void _dump_DIRAMPFORCE(LPCDIRAMPFORCE frc)
|
||||
{
|
||||
TRACE("Ramp force has start %d, end %d\n",
|
||||
frc->lStart, frc->lEnd);
|
||||
}
|
||||
|
||||
static void _dump_DICONDITION(LPCDICONDITION frc)
|
||||
{
|
||||
TRACE("Condition has offset %d, pos/neg coefficients %d and %d, pos/neg saturations %d and %d, deadband %d\n",
|
||||
frc->lOffset, frc->lPositiveCoefficient, frc->lNegativeCoefficient,
|
||||
frc->dwPositiveSaturation, frc->dwNegativeSaturation, frc->lDeadBand);
|
||||
}
|
||||
|
||||
static void _dump_DICUSTOMFORCE(LPCDICUSTOMFORCE frc)
|
||||
{
|
||||
unsigned int i;
|
||||
TRACE("Custom force uses %d channels, sample period %d. Has %d 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)) {
|
||||
TRACE("Custom force data (time aligned, axes in order):\n");
|
||||
for (i = 1; i <= frc->cSamples; ++i) {
|
||||
TRACE("%d ", frc->rglForceData[i]);
|
||||
if (i % frc->cChannels == 0)
|
||||
TRACE("\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void dump_DIEFFECT(LPCDIEFFECT eff, REFGUID guid, DWORD dwFlags)
|
||||
{
|
||||
DWORD type = typeFromGUID(guid);
|
||||
unsigned int i;
|
||||
|
||||
TRACE("Dumping DIEFFECT structure:\n");
|
||||
TRACE(" - dwSize: %d\n", eff->dwSize);
|
||||
if ((eff->dwSize != sizeof(DIEFFECT)) && (eff->dwSize != sizeof(DIEFFECT_DX5))) {
|
||||
WARN("Non-standard DIEFFECT structure size %d\n", eff->dwSize);
|
||||
}
|
||||
TRACE(" - dwFlags: %d\n", eff->dwFlags);
|
||||
TRACE(" ");
|
||||
_dump_DIEFFECT_flags(eff->dwFlags);
|
||||
TRACE(" - dwDuration: %d\n", eff->dwDuration);
|
||||
TRACE(" - dwGain: %d\n", eff->dwGain);
|
||||
|
||||
if (eff->dwGain > 10000)
|
||||
WARN("dwGain is out of range (>10,000)\n");
|
||||
|
||||
TRACE(" - dwTriggerButton: %d\n", eff->dwTriggerButton);
|
||||
TRACE(" - dwTriggerRepeatInterval: %d\n", eff->dwTriggerRepeatInterval);
|
||||
TRACE(" - rglDirection: %p\n", eff->rglDirection);
|
||||
if (dwFlags & DIEP_DIRECTION && eff->rglDirection) {
|
||||
TRACE(" ");
|
||||
for (i = 0; i < eff->cAxes; ++i)
|
||||
TRACE("%d ", eff->rglDirection[i]);
|
||||
TRACE("\n");
|
||||
}
|
||||
TRACE(" - cbTypeSpecificParams: %d\n", eff->cbTypeSpecificParams);
|
||||
TRACE(" - lpvTypeSpecificParams: %p\n", eff->lpvTypeSpecificParams);
|
||||
|
||||
/* Only trace some members if dwFlags indicates they have data */
|
||||
if (dwFlags & DIEP_AXES) {
|
||||
TRACE(" - cAxes: %d\n", eff->cAxes);
|
||||
TRACE(" - rgdwAxes: %p\n", eff->rgdwAxes);
|
||||
|
||||
if (TRACE_ON(dinput) && eff->rgdwAxes) {
|
||||
TRACE(" ");
|
||||
for (i = 0; i < eff->cAxes; ++i)
|
||||
TRACE("%d ", eff->rgdwAxes[i]);
|
||||
TRACE("\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (dwFlags & DIEP_ENVELOPE) {
|
||||
TRACE(" - lpEnvelope: %p\n", eff->lpEnvelope);
|
||||
if (eff->lpEnvelope != NULL)
|
||||
_dump_DIENVELOPE(eff->lpEnvelope);
|
||||
}
|
||||
|
||||
if (eff->dwSize > sizeof(DIEFFECT_DX5))
|
||||
TRACE(" - dwStartDelay: %d\n", eff->dwStartDelay);
|
||||
|
||||
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 if (!eff->lpvTypeSpecificParams) {
|
||||
WARN("Size of type-specific params is correct but pointer is NULL!\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 if (!eff->lpvTypeSpecificParams) {
|
||||
WARN("Size of type-specific params is correct but pointer is NULL!\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 if (!eff->lpvTypeSpecificParams) {
|
||||
WARN("Size of type-specific params is correct but pointer is NULL!\n");
|
||||
} else {
|
||||
_dump_DIRAMPFORCE(eff->lpvTypeSpecificParams);
|
||||
}
|
||||
} else if (type == DIEFT_CONDITION) {
|
||||
if (eff->cbTypeSpecificParams == sizeof(DICONDITION) && eff->lpvTypeSpecificParams) {
|
||||
_dump_DICONDITION(eff->lpvTypeSpecificParams);
|
||||
} else if (eff->cbTypeSpecificParams == 2 * sizeof(DICONDITION) && eff->lpvTypeSpecificParams) {
|
||||
DICONDITION *condition = eff->lpvTypeSpecificParams;
|
||||
_dump_DICONDITION(&condition[0]);
|
||||
_dump_DICONDITION(&condition[1]);
|
||||
} else {
|
||||
WARN("Effect claims to be a condition but the type-specific params are the wrong size or NULL!\n");
|
||||
}
|
||||
} 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 if (!eff->lpvTypeSpecificParams) {
|
||||
WARN("Size of type-specific params is correct but pointer is NULL!\n");
|
||||
} else {
|
||||
_dump_DICUSTOMFORCE(eff->lpvTypeSpecificParams);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BOOL device_disabled_registry(const char* name)
|
||||
{
|
||||
DIDEVICEINSTANCEW instance;
|
||||
|
||||
MultiByteToWideChar( CP_ACP, 0, name, -1, instance.tszInstanceName, MAX_PATH );
|
||||
return device_instance_is_disabled( &instance, NULL );
|
||||
}
|
||||
|
||||
BOOL is_xinput_device(const DIDEVCAPS *devcaps, WORD vid, WORD pid)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (vid == VID_MICROSOFT)
|
||||
{
|
||||
for (i = 0; i < ARRAY_SIZE(PID_XBOX_CONTROLLERS); i++)
|
||||
if (pid == PID_XBOX_CONTROLLERS[i]) return TRUE;
|
||||
}
|
||||
|
||||
return (devcaps->dwAxes == 6 && devcaps->dwButtons >= 14);
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* SetProperty : change input device properties
|
||||
*/
|
||||
HRESULT WINAPI JoystickWGenericImpl_SetProperty(LPDIRECTINPUTDEVICE8W iface, REFGUID rguid, LPCDIPROPHEADER ph)
|
||||
{
|
||||
JoystickGenericImpl *This = impl_from_IDirectInputDevice8W(iface);
|
||||
DWORD i;
|
||||
ObjProps remap_props;
|
||||
|
||||
TRACE("(%p,%s,%p)\n",This,debugstr_guid(rguid),ph);
|
||||
|
||||
if (ph == NULL) {
|
||||
WARN("invalid parameter: ph == NULL\n");
|
||||
return DIERR_INVALIDPARAM;
|
||||
}
|
||||
|
||||
if (TRACE_ON(dinput))
|
||||
_dump_DIPROPHEADER(ph);
|
||||
|
||||
if (IS_DIPROP(rguid)) {
|
||||
switch (LOWORD(rguid)) {
|
||||
case (DWORD_PTR)DIPROP_RANGE: {
|
||||
LPCDIPROPRANGE pr = (LPCDIPROPRANGE)ph;
|
||||
if (ph->dwHow == DIPH_DEVICE) {
|
||||
|
||||
/* Many games poll the joystick immediately after setting the range
|
||||
* for calibration purposes, so the old values need to be remapped
|
||||
* to the new range before it does so */
|
||||
|
||||
TRACE("proprange(%d,%d) all\n", pr->lMin, pr->lMax);
|
||||
for (i = 0; i < This->base.data_format.wine_df->dwNumObjs; i++) {
|
||||
|
||||
remap_props.lDevMin = This->props[i].lMin;
|
||||
remap_props.lDevMax = This->props[i].lMax;
|
||||
|
||||
remap_props.lDeadZone = This->props[i].lDeadZone;
|
||||
remap_props.lSaturation = This->props[i].lSaturation;
|
||||
|
||||
remap_props.lMin = pr->lMin;
|
||||
remap_props.lMax = pr->lMax;
|
||||
|
||||
switch (This->base.data_format.wine_df->rgodf[i].dwOfs) {
|
||||
case DIJOFS_X : This->js.lX = joystick_map_axis(&remap_props, This->js.lX); break;
|
||||
case DIJOFS_Y : This->js.lY = joystick_map_axis(&remap_props, This->js.lY); break;
|
||||
case DIJOFS_Z : This->js.lZ = joystick_map_axis(&remap_props, This->js.lZ); break;
|
||||
case DIJOFS_RX : This->js.lRx = joystick_map_axis(&remap_props, This->js.lRx); break;
|
||||
case DIJOFS_RY : This->js.lRy = joystick_map_axis(&remap_props, This->js.lRy); break;
|
||||
case DIJOFS_RZ : This->js.lRz = joystick_map_axis(&remap_props, This->js.lRz); break;
|
||||
case DIJOFS_SLIDER(0): This->js.rglSlider[0] = joystick_map_axis(&remap_props, This->js.rglSlider[0]); break;
|
||||
case DIJOFS_SLIDER(1): This->js.rglSlider[1] = joystick_map_axis(&remap_props, This->js.rglSlider[1]); break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
This->props[i].lMin = pr->lMin;
|
||||
This->props[i].lMax = pr->lMax;
|
||||
}
|
||||
} else {
|
||||
int obj = find_property(&This->base.data_format, ph);
|
||||
|
||||
TRACE("proprange(%d,%d) obj=%d\n", pr->lMin, pr->lMax, obj);
|
||||
if (obj >= 0) {
|
||||
|
||||
remap_props.lDevMin = This->props[obj].lMin;
|
||||
remap_props.lDevMax = This->props[obj].lMax;
|
||||
|
||||
remap_props.lDeadZone = This->props[obj].lDeadZone;
|
||||
remap_props.lSaturation = This->props[obj].lSaturation;
|
||||
|
||||
remap_props.lMin = pr->lMin;
|
||||
remap_props.lMax = pr->lMax;
|
||||
|
||||
switch (This->base.data_format.wine_df->rgodf[obj].dwOfs) {
|
||||
case DIJOFS_X : This->js.lX = joystick_map_axis(&remap_props, This->js.lX); break;
|
||||
case DIJOFS_Y : This->js.lY = joystick_map_axis(&remap_props, This->js.lY); break;
|
||||
case DIJOFS_Z : This->js.lZ = joystick_map_axis(&remap_props, This->js.lZ); break;
|
||||
case DIJOFS_RX : This->js.lRx = joystick_map_axis(&remap_props, This->js.lRx); break;
|
||||
case DIJOFS_RY : This->js.lRy = joystick_map_axis(&remap_props, This->js.lRy); break;
|
||||
case DIJOFS_RZ : This->js.lRz = joystick_map_axis(&remap_props, This->js.lRz); break;
|
||||
case DIJOFS_SLIDER(0): This->js.rglSlider[0] = joystick_map_axis(&remap_props, This->js.rglSlider[0]); break;
|
||||
case DIJOFS_SLIDER(1): This->js.rglSlider[1] = joystick_map_axis(&remap_props, This->js.rglSlider[1]); break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
This->props[obj].lMin = pr->lMin;
|
||||
This->props[obj].lMax = pr->lMax;
|
||||
return DI_OK;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case (DWORD_PTR)DIPROP_DEADZONE: {
|
||||
LPCDIPROPDWORD pd = (LPCDIPROPDWORD)ph;
|
||||
if (ph->dwHow == DIPH_DEVICE) {
|
||||
TRACE("deadzone(%d) all\n", pd->dwData);
|
||||
for (i = 0; i < This->base.data_format.wine_df->dwNumObjs; i++)
|
||||
This->props[i].lDeadZone = pd->dwData;
|
||||
} else {
|
||||
int obj = find_property(&This->base.data_format, ph);
|
||||
|
||||
TRACE("deadzone(%d) obj=%d\n", pd->dwData, obj);
|
||||
if (obj >= 0) {
|
||||
This->props[obj].lDeadZone = pd->dwData;
|
||||
return DI_OK;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case (DWORD_PTR)DIPROP_SATURATION: {
|
||||
LPCDIPROPDWORD pd = (LPCDIPROPDWORD)ph;
|
||||
if (ph->dwHow == DIPH_DEVICE) {
|
||||
TRACE("saturation(%d) all\n", pd->dwData);
|
||||
for (i = 0; i < This->base.data_format.wine_df->dwNumObjs; i++)
|
||||
This->props[i].lSaturation = pd->dwData;
|
||||
} else {
|
||||
int obj = find_property(&This->base.data_format, ph);
|
||||
|
||||
TRACE("saturation(%d) obj=%d\n", pd->dwData, obj);
|
||||
if (obj >= 0) {
|
||||
This->props[obj].lSaturation = pd->dwData;
|
||||
return DI_OK;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case (DWORD_PTR)DIPROP_CALIBRATIONMODE: {
|
||||
LPCDIPROPDWORD pd = (LPCDIPROPDWORD)ph;
|
||||
FIXME("DIPROP_CALIBRATIONMODE(%d)\n", pd->dwData);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return IDirectInputDevice2WImpl_SetProperty(iface, rguid, ph);
|
||||
}
|
||||
}
|
||||
|
||||
return DI_OK;
|
||||
}
|
||||
|
||||
#define DEBUG_TYPE(x) case (x): str = #x; break
|
||||
void _dump_DIDEVCAPS(const DIDEVCAPS *lpDIDevCaps)
|
||||
{
|
||||
int type = GET_DIDEVICE_TYPE(lpDIDevCaps->dwDevType);
|
||||
const char *str, *hid = "";
|
||||
TRACE("dwSize: %d\n", lpDIDevCaps->dwSize);
|
||||
TRACE("dwFlags: %08x\n", lpDIDevCaps->dwFlags);
|
||||
switch(type)
|
||||
{
|
||||
/* Direct X <= 7 definitions */
|
||||
DEBUG_TYPE(DIDEVTYPE_DEVICE);
|
||||
DEBUG_TYPE(DIDEVTYPE_MOUSE);
|
||||
DEBUG_TYPE(DIDEVTYPE_KEYBOARD);
|
||||
DEBUG_TYPE(DIDEVTYPE_JOYSTICK);
|
||||
/* Direct X >= 8 definitions */
|
||||
DEBUG_TYPE(DI8DEVTYPE_DEVICE);
|
||||
DEBUG_TYPE(DI8DEVTYPE_MOUSE);
|
||||
DEBUG_TYPE(DI8DEVTYPE_KEYBOARD);
|
||||
DEBUG_TYPE(DI8DEVTYPE_JOYSTICK);
|
||||
DEBUG_TYPE(DI8DEVTYPE_GAMEPAD);
|
||||
DEBUG_TYPE(DI8DEVTYPE_DRIVING);
|
||||
DEBUG_TYPE(DI8DEVTYPE_FLIGHT);
|
||||
DEBUG_TYPE(DI8DEVTYPE_1STPERSON);
|
||||
DEBUG_TYPE(DI8DEVTYPE_DEVICECTRL);
|
||||
DEBUG_TYPE(DI8DEVTYPE_SCREENPOINTER);
|
||||
DEBUG_TYPE(DI8DEVTYPE_REMOTE);
|
||||
DEBUG_TYPE(DI8DEVTYPE_SUPPLEMENTAL);
|
||||
default: str = "UNKNOWN";
|
||||
}
|
||||
|
||||
if (lpDIDevCaps->dwDevType & DIDEVTYPE_HID)
|
||||
hid = " (HID)";
|
||||
|
||||
TRACE("dwDevType: %08x %s%s\n", lpDIDevCaps->dwDevType, str, hid);
|
||||
TRACE("dwAxes: %d\n", lpDIDevCaps->dwAxes);
|
||||
TRACE("dwButtons: %d\n", lpDIDevCaps->dwButtons);
|
||||
TRACE("dwPOVs: %d\n", lpDIDevCaps->dwPOVs);
|
||||
if (lpDIDevCaps->dwSize > sizeof(DIDEVCAPS_DX3)) {
|
||||
TRACE("dwFFSamplePeriod: %d\n", lpDIDevCaps->dwFFSamplePeriod);
|
||||
TRACE("dwFFMinTimeResolution: %d\n", lpDIDevCaps->dwFFMinTimeResolution);
|
||||
TRACE("dwFirmwareRevision: %d\n", lpDIDevCaps->dwFirmwareRevision);
|
||||
TRACE("dwHardwareRevision: %d\n", lpDIDevCaps->dwHardwareRevision);
|
||||
TRACE("dwFFDriverVersion: %d\n", lpDIDevCaps->dwFFDriverVersion);
|
||||
}
|
||||
}
|
||||
#undef DEBUG_TYPE
|
||||
|
||||
HRESULT WINAPI JoystickWGenericImpl_GetCapabilities(LPDIRECTINPUTDEVICE8W iface, LPDIDEVCAPS lpDIDevCaps)
|
||||
{
|
||||
JoystickGenericImpl *This = impl_from_IDirectInputDevice8W(iface);
|
||||
int size;
|
||||
|
||||
TRACE("%p->(%p)\n",This,lpDIDevCaps);
|
||||
|
||||
if (lpDIDevCaps == NULL) {
|
||||
WARN("invalid pointer\n");
|
||||
return E_POINTER;
|
||||
}
|
||||
|
||||
size = lpDIDevCaps->dwSize;
|
||||
|
||||
if (!(size == sizeof(DIDEVCAPS) || size == sizeof(DIDEVCAPS_DX3))) {
|
||||
WARN("invalid parameter\n");
|
||||
return DIERR_INVALIDPARAM;
|
||||
}
|
||||
|
||||
CopyMemory(lpDIDevCaps, &This->devcaps, size);
|
||||
lpDIDevCaps->dwSize = size;
|
||||
|
||||
if (TRACE_ON(dinput))
|
||||
_dump_DIDEVCAPS(lpDIDevCaps);
|
||||
|
||||
return DI_OK;
|
||||
}
|
||||
|
||||
|
||||
ULONG WINAPI JoystickWGenericImpl_Release(LPDIRECTINPUTDEVICE8W iface)
|
||||
{
|
||||
JoystickGenericImpl *This = impl_from_IDirectInputDevice8W(iface);
|
||||
void *axis_map = This->axis_map;
|
||||
ULONG res = IDirectInputDevice2WImpl_Release(iface);
|
||||
if (!res) HeapFree(GetProcessHeap(), 0, axis_map);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* GetObjectInfo : get object info
|
||||
*/
|
||||
HRESULT WINAPI JoystickWGenericImpl_GetObjectInfo(LPDIRECTINPUTDEVICE8W iface,
|
||||
LPDIDEVICEOBJECTINSTANCEW pdidoi, DWORD dwObj, DWORD dwHow)
|
||||
{
|
||||
static const WCHAR axisW[] = {'A','x','i','s',' ','%','d',0};
|
||||
static const WCHAR povW[] = {'P','O','V',' ','%','d',0};
|
||||
static const WCHAR buttonW[] = {'B','u','t','t','o','n',' ','%','d',0};
|
||||
HRESULT res;
|
||||
|
||||
res = IDirectInputDevice2WImpl_GetObjectInfo(iface, pdidoi, dwObj, dwHow);
|
||||
if (res != DI_OK) return res;
|
||||
|
||||
if (pdidoi->dwType & DIDFT_AXIS) {
|
||||
sprintfW(pdidoi->tszName, axisW, DIDFT_GETINSTANCE(pdidoi->dwType));
|
||||
pdidoi->dwFlags |= DIDOI_ASPECTPOSITION;
|
||||
} else if (pdidoi->dwType & DIDFT_POV)
|
||||
sprintfW(pdidoi->tszName, povW, DIDFT_GETINSTANCE(pdidoi->dwType));
|
||||
else if (pdidoi->dwType & DIDFT_BUTTON)
|
||||
sprintfW(pdidoi->tszName, buttonW, DIDFT_GETINSTANCE(pdidoi->dwType));
|
||||
|
||||
_dump_OBJECTINSTANCEW(pdidoi);
|
||||
return res;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* GetProperty : get input device properties
|
||||
*/
|
||||
HRESULT WINAPI JoystickWGenericImpl_GetProperty(LPDIRECTINPUTDEVICE8W iface, REFGUID rguid, LPDIPROPHEADER pdiph)
|
||||
{
|
||||
JoystickGenericImpl *This = impl_from_IDirectInputDevice8W(iface);
|
||||
|
||||
TRACE("(%p,%s,%p)\n", This, debugstr_guid(rguid), pdiph);
|
||||
|
||||
if (TRACE_ON(dinput))
|
||||
_dump_DIPROPHEADER(pdiph);
|
||||
|
||||
if (IS_DIPROP(rguid)) {
|
||||
switch (LOWORD(rguid)) {
|
||||
case (DWORD_PTR) DIPROP_RANGE: {
|
||||
LPDIPROPRANGE pr = (LPDIPROPRANGE)pdiph;
|
||||
int obj = find_property(&This->base.data_format, pdiph);
|
||||
|
||||
/* The app is querying the current range of the axis
|
||||
* return the lMin and lMax values */
|
||||
if (obj >= 0) {
|
||||
pr->lMin = This->props[obj].lMin;
|
||||
pr->lMax = This->props[obj].lMax;
|
||||
TRACE("range(%d, %d) obj=%d\n", pr->lMin, pr->lMax, obj);
|
||||
return DI_OK;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case (DWORD_PTR) DIPROP_DEADZONE: {
|
||||
LPDIPROPDWORD pd = (LPDIPROPDWORD)pdiph;
|
||||
int obj = find_property(&This->base.data_format, pdiph);
|
||||
|
||||
if (obj >= 0) {
|
||||
pd->dwData = This->props[obj].lDeadZone;
|
||||
TRACE("deadzone(%d) obj=%d\n", pd->dwData, obj);
|
||||
return DI_OK;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case (DWORD_PTR) DIPROP_SATURATION: {
|
||||
LPDIPROPDWORD pd = (LPDIPROPDWORD)pdiph;
|
||||
int obj = find_property(&This->base.data_format, pdiph);
|
||||
|
||||
if (obj >= 0) {
|
||||
pd->dwData = This->props[obj].lSaturation;
|
||||
TRACE("saturation(%d) obj=%d\n", pd->dwData, obj);
|
||||
return DI_OK;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case (DWORD_PTR) DIPROP_PRODUCTNAME:
|
||||
case (DWORD_PTR) DIPROP_INSTANCENAME: {
|
||||
DIPROPSTRING *ps = (DIPROPSTRING*) pdiph;
|
||||
DIDEVICEINSTANCEW didev;
|
||||
|
||||
didev.dwSize = sizeof(didev);
|
||||
|
||||
IDirectInputDevice_GetDeviceInfo(iface, &didev);
|
||||
if (LOWORD(rguid) == (DWORD_PTR) DIPROP_PRODUCTNAME)
|
||||
lstrcpynW(ps->wsz, didev.tszProductName, MAX_PATH);
|
||||
else
|
||||
lstrcpynW(ps->wsz, didev.tszInstanceName, MAX_PATH);
|
||||
|
||||
return DI_OK;
|
||||
}
|
||||
default:
|
||||
return IDirectInputDevice2WImpl_GetProperty(iface, rguid, pdiph);
|
||||
}
|
||||
}
|
||||
|
||||
return DI_OK;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* GetDeviceInfo : get information about a device's identity
|
||||
*/
|
||||
HRESULT WINAPI JoystickWGenericImpl_GetDeviceInfo(
|
||||
LPDIRECTINPUTDEVICE8W iface,
|
||||
LPDIDEVICEINSTANCEW pdidi)
|
||||
{
|
||||
JoystickGenericImpl *This = impl_from_IDirectInputDevice8W(iface);
|
||||
CHAR buffer[MAX_PATH];
|
||||
DIPROPDWORD pd;
|
||||
DWORD index = 0;
|
||||
|
||||
TRACE("(%p,%p)\n", iface, pdidi);
|
||||
|
||||
if ((pdidi->dwSize != sizeof(DIDEVICEINSTANCE_DX3W)) &&
|
||||
(pdidi->dwSize != sizeof(DIDEVICEINSTANCEW))) {
|
||||
WARN("invalid parameter: pdidi->dwSize = %d\n", pdidi->dwSize);
|
||||
return DIERR_INVALIDPARAM;
|
||||
}
|
||||
|
||||
/* Try to get joystick index */
|
||||
pd.diph.dwSize = sizeof(pd);
|
||||
pd.diph.dwHeaderSize = sizeof(pd.diph);
|
||||
pd.diph.dwObj = 0;
|
||||
pd.diph.dwHow = DIPH_DEVICE;
|
||||
if (SUCCEEDED(IDirectInputDevice2_GetProperty(iface, DIPROP_JOYSTICKID, &pd.diph)))
|
||||
index = pd.dwData;
|
||||
|
||||
/* Return joystick */
|
||||
pdidi->guidInstance = This->base.guid;
|
||||
pdidi->guidProduct = This->guidProduct;
|
||||
/* we only support traditional joysticks for now */
|
||||
pdidi->dwDevType = This->devcaps.dwDevType;
|
||||
snprintf(buffer, sizeof(buffer), "Joystick %d", index);
|
||||
MultiByteToWideChar(CP_ACP, 0, buffer, -1, pdidi->tszInstanceName, MAX_PATH);
|
||||
MultiByteToWideChar(CP_ACP, 0, This->name, -1, pdidi->tszProductName, MAX_PATH);
|
||||
if (pdidi->dwSize > sizeof(DIDEVICEINSTANCE_DX3W)) {
|
||||
pdidi->guidFFDriver = GUID_NULL;
|
||||
pdidi->wUsagePage = 0;
|
||||
pdidi->wUsage = 0;
|
||||
}
|
||||
|
||||
return DI_OK;
|
||||
}
|
||||
|
||||
HRESULT WINAPI JoystickWGenericImpl_Poll(LPDIRECTINPUTDEVICE8W iface)
|
||||
{
|
||||
JoystickGenericImpl *This = impl_from_IDirectInputDevice8W(iface);
|
||||
|
||||
TRACE("(%p)\n",This);
|
||||
|
||||
if (!This->base.acquired) {
|
||||
WARN("not acquired\n");
|
||||
return DIERR_NOTACQUIRED;
|
||||
}
|
||||
|
||||
This->joy_polldev( iface );
|
||||
return DI_OK;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* GetDeviceState : returns the "state" of the joystick.
|
||||
*
|
||||
*/
|
||||
HRESULT WINAPI JoystickWGenericImpl_GetDeviceState(LPDIRECTINPUTDEVICE8W iface, DWORD len, LPVOID ptr)
|
||||
{
|
||||
JoystickGenericImpl *This = impl_from_IDirectInputDevice8W(iface);
|
||||
|
||||
TRACE("(%p,0x%08x,%p)\n", This, len, ptr);
|
||||
|
||||
if (!This->base.acquired) {
|
||||
WARN("not acquired\n");
|
||||
return DIERR_NOTACQUIRED;
|
||||
}
|
||||
|
||||
/* update joystick state */
|
||||
This->joy_polldev( iface );
|
||||
|
||||
/* convert and copy data to user supplied buffer */
|
||||
fill_DataFormat(ptr, len, &This->js, &This->base.data_format);
|
||||
|
||||
return DI_OK;
|
||||
}
|
||||
|
||||
HRESULT WINAPI JoystickWGenericImpl_BuildActionMap(LPDIRECTINPUTDEVICE8W iface,
|
||||
LPDIACTIONFORMATW lpdiaf,
|
||||
LPCWSTR lpszUserName,
|
||||
DWORD dwFlags)
|
||||
{
|
||||
static const DWORD object_types[] = { DIDFT_AXIS, DIDFT_BUTTON };
|
||||
static const DWORD type_map[] = { DIDFT_RELAXIS, DIDFT_PSHBUTTON };
|
||||
JoystickGenericImpl *This = impl_from_IDirectInputDevice8W(iface);
|
||||
unsigned int i, j;
|
||||
BOOL has_actions = FALSE;
|
||||
|
||||
FIXME("(%p)->(%p,%s,%08x): semi-stub !\n", This, lpdiaf, debugstr_w(lpszUserName), dwFlags);
|
||||
|
||||
for (i=0; i < lpdiaf->dwNumActions; i++)
|
||||
{
|
||||
DWORD inst = (0x000000ff & (lpdiaf->rgoAction[i].dwSemantic)) - 1;
|
||||
DWORD type = 0x000000ff & (lpdiaf->rgoAction[i].dwSemantic >> 8);
|
||||
DWORD genre = 0xff000000 & lpdiaf->rgoAction[i].dwSemantic;
|
||||
|
||||
/* Don't touch a user configured action */
|
||||
if (lpdiaf->rgoAction[i].dwHow == DIAH_USERCONFIG) continue;
|
||||
|
||||
/* Only consider actions of the right genre */
|
||||
if (lpdiaf->dwGenre != genre && genre != DIGENRE_ANY) continue;
|
||||
|
||||
for (j = 0; j < ARRAY_SIZE(object_types); j++)
|
||||
{
|
||||
if (type & object_types[j])
|
||||
{
|
||||
/* Ensure that the object exists */
|
||||
LPDIOBJECTDATAFORMAT odf = dataformat_to_odf_by_type(This->base.data_format.wine_df, inst, object_types[j]);
|
||||
|
||||
if (odf != NULL)
|
||||
{
|
||||
lpdiaf->rgoAction[i].dwObjID = type_map[j] | (0x0000ff00 & (inst << 8));
|
||||
lpdiaf->rgoAction[i].guidInstance = This->base.guid;
|
||||
lpdiaf->rgoAction[i].dwHow = DIAH_DEFAULT;
|
||||
|
||||
has_actions = TRUE;
|
||||
|
||||
/* No need to try other types if the action was already mapped */
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!has_actions) return DI_NOEFFECT;
|
||||
|
||||
return IDirectInputDevice8WImpl_BuildActionMap(iface, lpdiaf, lpszUserName, dwFlags);
|
||||
}
|
||||
|
||||
HRESULT WINAPI JoystickWGenericImpl_SetActionMap(LPDIRECTINPUTDEVICE8W iface,
|
||||
LPDIACTIONFORMATW lpdiaf,
|
||||
LPCWSTR lpszUserName,
|
||||
DWORD dwFlags)
|
||||
{
|
||||
JoystickGenericImpl *This = impl_from_IDirectInputDevice8W(iface);
|
||||
|
||||
FIXME("(%p)->(%p,%s,%08x): semi-stub !\n", This, lpdiaf, debugstr_w(lpszUserName), dwFlags);
|
||||
|
||||
return _set_action_map(iface, lpdiaf, lpszUserName, dwFlags, This->base.data_format.wine_df);
|
||||
}
|
||||
|
||||
/*
|
||||
* This maps the read value (from the input event) to a value in the
|
||||
* 'wanted' range.
|
||||
* Notes:
|
||||
* Dead zone is in % multiplied by a 100 (range 0..10000)
|
||||
*/
|
||||
LONG joystick_map_axis(ObjProps *props, int val)
|
||||
{
|
||||
LONG ret;
|
||||
LONG dead_zone = MulDiv( props->lDeadZone, props->lDevMax - props->lDevMin, 10000 );
|
||||
LONG dev_range = props->lDevMax - props->lDevMin - dead_zone;
|
||||
|
||||
/* Center input */
|
||||
val -= (props->lDevMin + props->lDevMax) / 2;
|
||||
|
||||
/* Remove dead zone */
|
||||
if (abs( val ) <= dead_zone / 2)
|
||||
val = 0;
|
||||
else
|
||||
val = val < 0 ? val + dead_zone / 2 : val - dead_zone / 2;
|
||||
|
||||
/* Scale and map the value from the device range into the required range */
|
||||
ret = MulDiv( val, props->lMax - props->lMin, dev_range ) +
|
||||
(props->lMin + props->lMax) / 2;
|
||||
|
||||
/* Clamp in case or rounding errors */
|
||||
if (ret > props->lMax) ret = props->lMax;
|
||||
else if (ret < props->lMin) ret = props->lMin;
|
||||
|
||||
TRACE( "(%d <%d> %d) -> (%d <%d> %d): val=%d ret=%d\n",
|
||||
props->lDevMin, dead_zone, props->lDevMax,
|
||||
props->lMin, props->lDeadZone, props->lMax,
|
||||
val, ret );
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Maps POV x & y event values to a DX "clock" position:
|
||||
* 0
|
||||
* 31500 4500
|
||||
* 27000 -1 9000
|
||||
* 22500 13500
|
||||
* 18000
|
||||
*/
|
||||
DWORD joystick_map_pov(const POINTL *p)
|
||||
{
|
||||
if (p->x > 0)
|
||||
return p->y < 0 ? 4500 : !p->y ? 9000 : 13500;
|
||||
else if (p->x < 0)
|
||||
return p->y < 0 ? 31500 : !p->y ? 27000 : 22500;
|
||||
else
|
||||
return p->y < 0 ? 0 : !p->y ? -1 : 18000;
|
||||
}
|
||||
|
||||
static DWORD get_config_key_a( HKEY defkey, HKEY appkey, const char *name, char *buffer, DWORD size )
|
||||
{
|
||||
if (appkey && !RegQueryValueExA( appkey, name, 0, NULL, (LPBYTE)buffer, &size )) return 0;
|
||||
|
||||
if (defkey && !RegQueryValueExA( defkey, name, 0, NULL, (LPBYTE)buffer, &size )) return 0;
|
||||
|
||||
return ERROR_FILE_NOT_FOUND;
|
||||
}
|
||||
|
||||
/*
|
||||
* Setup the dinput options.
|
||||
*/
|
||||
|
||||
HRESULT setup_dinput_options(JoystickGenericImpl *This, const int *default_axis_map)
|
||||
{
|
||||
char buffer[MAX_PATH+16];
|
||||
HKEY hkey, appkey;
|
||||
int tokens = 0;
|
||||
int axis = 0;
|
||||
int pov = 0;
|
||||
|
||||
get_app_key(&hkey, &appkey);
|
||||
|
||||
/* get options */
|
||||
|
||||
if (!get_config_key_a( hkey, appkey, "DefaultDeadZone", buffer, sizeof(buffer) ))
|
||||
{
|
||||
This->deadzone = atoi(buffer);
|
||||
TRACE("setting default deadzone to: \"%s\" %d\n", buffer, This->deadzone);
|
||||
}
|
||||
|
||||
This->axis_map = HeapAlloc(GetProcessHeap(), 0, This->device_axis_count * sizeof(int));
|
||||
if (!This->axis_map) return DIERR_OUTOFMEMORY;
|
||||
|
||||
if (!get_config_key_a( hkey, appkey, This->name, buffer, sizeof(buffer) ))
|
||||
{
|
||||
static const char *axis_names[] = {"X", "Y", "Z", "Rx", "Ry", "Rz",
|
||||
"Slider1", "Slider2",
|
||||
"POV1", "POV2", "POV3", "POV4"};
|
||||
const char *delim = ",";
|
||||
char * ptr;
|
||||
TRACE("\"%s\" = \"%s\"\n", This->name, buffer);
|
||||
|
||||
if ((ptr = strtok(buffer, delim)) != NULL)
|
||||
{
|
||||
do
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(axis_names); i++)
|
||||
{
|
||||
if (!strcmp(ptr, axis_names[i]))
|
||||
{
|
||||
if (!strncmp(ptr, "POV", 3))
|
||||
{
|
||||
if (pov >= 4)
|
||||
{
|
||||
WARN("Only 4 POVs supported - ignoring extra\n");
|
||||
i = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Pov takes two axes */
|
||||
This->axis_map[tokens++] = i;
|
||||
pov++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (axis >= 8)
|
||||
{
|
||||
FIXME("Only 8 Axes supported - ignoring extra\n");
|
||||
i = -1;
|
||||
}
|
||||
else
|
||||
axis++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (i == ARRAY_SIZE(axis_names))
|
||||
{
|
||||
ERR("invalid joystick axis type: \"%s\"\n", ptr);
|
||||
i = -1;
|
||||
}
|
||||
|
||||
This->axis_map[tokens] = i;
|
||||
tokens++;
|
||||
} while ((ptr = strtok(NULL, delim)) != NULL);
|
||||
|
||||
if (tokens != This->device_axis_count)
|
||||
{
|
||||
ERR("not all joystick axes mapped: %d axes(%d,%d), %d arguments\n",
|
||||
This->device_axis_count, axis, pov, tokens);
|
||||
while (tokens < This->device_axis_count)
|
||||
{
|
||||
This->axis_map[tokens] = -1;
|
||||
tokens++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int i;
|
||||
|
||||
if (default_axis_map)
|
||||
{
|
||||
/* Use default mapping from the driver */
|
||||
for (i = 0; i < This->device_axis_count; i++)
|
||||
{
|
||||
This->axis_map[i] = default_axis_map[i];
|
||||
tokens = default_axis_map[i];
|
||||
if (tokens < 0)
|
||||
continue;
|
||||
if (tokens < 8)
|
||||
axis++;
|
||||
else if (tokens < 15)
|
||||
{
|
||||
i++;
|
||||
pov++;
|
||||
This->axis_map[i] = default_axis_map[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* No config - set default mapping. */
|
||||
for (i = 0; i < This->device_axis_count; i++)
|
||||
{
|
||||
if (i < 8)
|
||||
This->axis_map[i] = axis++;
|
||||
else if (i < 15)
|
||||
{
|
||||
This->axis_map[i++] = 8 + pov;
|
||||
This->axis_map[i ] = 8 + pov++;
|
||||
}
|
||||
else
|
||||
This->axis_map[i] = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
This->devcaps.dwAxes = axis;
|
||||
This->devcaps.dwPOVs = pov;
|
||||
|
||||
if (appkey) RegCloseKey(appkey);
|
||||
if (hkey) RegCloseKey(hkey);
|
||||
|
||||
return DI_OK;
|
||||
}
|
|
@ -37,16 +37,16 @@
|
|||
#include "dinput.h"
|
||||
#include "setupapi.h"
|
||||
|
||||
#include "wine/debug.h"
|
||||
#include "wine/hid.h"
|
||||
|
||||
#include "dinput_private.h"
|
||||
#include "device_private.h"
|
||||
#include "joystick_private.h"
|
||||
|
||||
#include "initguid.h"
|
||||
#include "devpkey.h"
|
||||
|
||||
#include "wine/unicode.h"
|
||||
#include "wine/debug.h"
|
||||
#include "wine/hid.h"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(dinput);
|
||||
|
||||
DEFINE_GUID( GUID_DEVINTERFACE_WINEXINPUT,0x6c53d5fd,0x6480,0x440f,0xb6,0x18,0x47,0x67,0x50,0xc5,0xe1,0xa6 );
|
||||
|
|
|
@ -1,831 +0,0 @@
|
|||
/* DirectInput Joystick device
|
||||
*
|
||||
* Copyright 1998 Marcus Meissner
|
||||
* Copyright 1998,1999 Lionel Ulmer
|
||||
* Copyright 2000-2001 TransGaming Technologies Inc.
|
||||
*
|
||||
* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
/*
|
||||
* To Do:
|
||||
* dead zone
|
||||
* force feedback
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "wine/port.h"
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#ifdef HAVE_UNISTD_H
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_TIME_H
|
||||
# include <sys/time.h>
|
||||
#endif
|
||||
#include <fcntl.h>
|
||||
#ifdef HAVE_SYS_IOCTL_H
|
||||
# include <sys/ioctl.h>
|
||||
#endif
|
||||
#include <errno.h>
|
||||
#ifdef HAVE_LINUX_IOCTL_H
|
||||
# include <linux/ioctl.h>
|
||||
#endif
|
||||
#ifdef HAVE_LINUX_JOYSTICK_H
|
||||
# include <linux/joystick.h>
|
||||
# undef SW_MAX
|
||||
#endif
|
||||
#ifdef HAVE_SYS_POLL_H
|
||||
# include <sys/poll.h>
|
||||
#endif
|
||||
|
||||
#include "wine/debug.h"
|
||||
#include "wine/unicode.h"
|
||||
#include "windef.h"
|
||||
#include "winbase.h"
|
||||
#include "winerror.h"
|
||||
#include "devguid.h"
|
||||
#include "dinput.h"
|
||||
|
||||
#include "dinput_private.h"
|
||||
#include "device_private.h"
|
||||
#include "joystick_private.h"
|
||||
|
||||
#ifdef HAVE_LINUX_22_JOYSTICK_API
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(dinput);
|
||||
|
||||
#define JOYDEV_NEW "/dev/input/js"
|
||||
#define JOYDEV_OLD "/dev/js"
|
||||
#define JOYDEVDRIVER " (js)"
|
||||
|
||||
struct JoyDev
|
||||
{
|
||||
char device[MAX_PATH];
|
||||
char name[MAX_PATH];
|
||||
GUID guid_product;
|
||||
|
||||
BYTE axis_count;
|
||||
BYTE button_count;
|
||||
int *dev_axes_map;
|
||||
|
||||
WORD vendor_id, product_id, bus_type;
|
||||
|
||||
BOOL is_joystick;
|
||||
};
|
||||
|
||||
typedef struct JoystickImpl JoystickImpl;
|
||||
static const IDirectInputDevice8WVtbl JoystickWvt;
|
||||
struct JoystickImpl
|
||||
{
|
||||
struct JoystickGenericImpl generic;
|
||||
|
||||
struct JoyDev *joydev;
|
||||
|
||||
/* joystick private */
|
||||
int joyfd;
|
||||
POINTL povs[4];
|
||||
};
|
||||
|
||||
static inline JoystickImpl *impl_from_IDirectInputDevice8W(IDirectInputDevice8W *iface)
|
||||
{
|
||||
return CONTAINING_RECORD(CONTAINING_RECORD(CONTAINING_RECORD(iface, IDirectInputDeviceImpl, IDirectInputDevice8W_iface),
|
||||
JoystickGenericImpl, base), JoystickImpl, generic);
|
||||
}
|
||||
|
||||
static const GUID DInput_Wine_Joystick_GUID = { /* 9e573ed9-7734-11d2-8d4a-23903fb6bdf7 */
|
||||
0x9e573ed9,
|
||||
0x7734,
|
||||
0x11d2,
|
||||
{0x8d, 0x4a, 0x23, 0x90, 0x3f, 0xb6, 0xbd, 0xf7}
|
||||
};
|
||||
|
||||
#define MAX_JOYSTICKS 64
|
||||
static INT joystick_devices_count = -1;
|
||||
static struct JoyDev *joystick_devices;
|
||||
|
||||
static void joy_polldev( IDirectInputDevice8W *iface );
|
||||
|
||||
#define SYS_PATH_FORMAT "/sys/class/input/js%d/device/id/%s"
|
||||
static BOOL read_sys_id_variable(int index, const char *property, WORD *value)
|
||||
{
|
||||
char sys_path[sizeof(SYS_PATH_FORMAT) + 16], id_str[5];
|
||||
int sys_fd;
|
||||
BOOL ret = FALSE;
|
||||
|
||||
sprintf(sys_path, SYS_PATH_FORMAT, index, property);
|
||||
if ((sys_fd = open(sys_path, O_RDONLY)) != -1)
|
||||
{
|
||||
if (read(sys_fd, id_str, 4) == 4)
|
||||
{
|
||||
id_str[4] = '\0';
|
||||
*value = strtol(id_str, NULL, 16);
|
||||
ret = TRUE;
|
||||
}
|
||||
|
||||
close(sys_fd);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
#undef SYS_PATH_FORMAT
|
||||
|
||||
static INT find_joystick_devices(void)
|
||||
{
|
||||
INT i;
|
||||
|
||||
if (joystick_devices_count != -1) return joystick_devices_count;
|
||||
|
||||
joystick_devices_count = 0;
|
||||
for (i = 0; i < MAX_JOYSTICKS; i++)
|
||||
{
|
||||
int fd;
|
||||
struct JoyDev joydev, *new_joydevs;
|
||||
BYTE axes_map[ABS_MAX + 1];
|
||||
SHORT btn_map[KEY_MAX - BTN_MISC + 1];
|
||||
BOOL non_js = FALSE;
|
||||
|
||||
snprintf(joydev.device, sizeof(joydev.device), "%s%d", JOYDEV_NEW, i);
|
||||
if ((fd = open(joydev.device, O_RDONLY)) == -1)
|
||||
{
|
||||
snprintf(joydev.device, sizeof(joydev.device), "%s%d", JOYDEV_OLD, i);
|
||||
if ((fd = open(joydev.device, O_RDONLY)) == -1) continue;
|
||||
}
|
||||
|
||||
strcpy(joydev.name, "Wine Joystick");
|
||||
#if defined(JSIOCGNAME)
|
||||
if (ioctl(fd, JSIOCGNAME(sizeof(joydev.name) - sizeof(JOYDEVDRIVER)), joydev.name) < 0)
|
||||
WARN("ioctl(%s,JSIOCGNAME) failed: %s\n", joydev.device, strerror(errno));
|
||||
#endif
|
||||
|
||||
/* Append driver name */
|
||||
strcat(joydev.name, JOYDEVDRIVER);
|
||||
|
||||
if (device_disabled_registry(joydev.name)) {
|
||||
close(fd);
|
||||
continue;
|
||||
}
|
||||
|
||||
#ifdef JSIOCGAXES
|
||||
if (ioctl(fd, JSIOCGAXES, &joydev.axis_count) < 0)
|
||||
{
|
||||
WARN("ioctl(%s,JSIOCGAXES) failed: %s, defaulting to 2\n", joydev.device, strerror(errno));
|
||||
joydev.axis_count = 2;
|
||||
}
|
||||
#else
|
||||
WARN("reading number of joystick axes unsupported in this platform, defaulting to 2\n");
|
||||
joydev.axis_count = 2;
|
||||
#endif
|
||||
#ifdef JSIOCGBUTTONS
|
||||
if (ioctl(fd, JSIOCGBUTTONS, &joydev.button_count) < 0)
|
||||
{
|
||||
WARN("ioctl(%s,JSIOCGBUTTONS) failed: %s, defaulting to 2\n", joydev.device, strerror(errno));
|
||||
joydev.button_count = 2;
|
||||
}
|
||||
#else
|
||||
WARN("reading number of joystick buttons unsupported in this platform, defaulting to 2\n");
|
||||
joydev.button_count = 2;
|
||||
#endif
|
||||
|
||||
joydev.is_joystick = FALSE;
|
||||
if (ioctl(fd, JSIOCGBTNMAP, btn_map) < 0)
|
||||
{
|
||||
WARN("ioctl(%s,JSIOCGBTNMAP) failed: %s\n", joydev.device, strerror(errno));
|
||||
}
|
||||
else
|
||||
{
|
||||
INT j;
|
||||
/* in lieu of properly reporting HID usage, detect presence of
|
||||
* "joystick buttons" and report those devices as joysticks instead of
|
||||
* gamepads */
|
||||
for (j = 0; !joydev.is_joystick && j < joydev.button_count; j++)
|
||||
{
|
||||
switch (btn_map[j])
|
||||
{
|
||||
case BTN_TRIGGER:
|
||||
case BTN_THUMB:
|
||||
case BTN_THUMB2:
|
||||
case BTN_TOP:
|
||||
case BTN_TOP2:
|
||||
case BTN_PINKIE:
|
||||
case BTN_BASE:
|
||||
case BTN_BASE2:
|
||||
case BTN_BASE3:
|
||||
case BTN_BASE4:
|
||||
case BTN_BASE5:
|
||||
case BTN_BASE6:
|
||||
case BTN_DEAD:
|
||||
joydev.is_joystick = TRUE;
|
||||
break;
|
||||
case BTN_MOUSE:
|
||||
case BTN_STYLUS:
|
||||
non_js = TRUE;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(non_js)
|
||||
{
|
||||
TRACE("Non-joystick detected. Skipping\n");
|
||||
close(fd);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ioctl(fd, JSIOCGAXMAP, axes_map) < 0)
|
||||
{
|
||||
WARN("ioctl(%s,JSIOCGAXMAP) failed: %s\n", joydev.device, strerror(errno));
|
||||
joydev.dev_axes_map = NULL;
|
||||
}
|
||||
else
|
||||
if ((joydev.dev_axes_map = HeapAlloc(GetProcessHeap(), 0, joydev.axis_count * sizeof(int))))
|
||||
{
|
||||
INT j, found_axes = 0;
|
||||
|
||||
/* Remap to DI numbers */
|
||||
for (j = 0; j < joydev.axis_count; j++)
|
||||
{
|
||||
if (axes_map[j] < 8)
|
||||
{
|
||||
/* Axis match 1-to-1 */
|
||||
joydev.dev_axes_map[j] = j;
|
||||
found_axes++;
|
||||
}
|
||||
else if (axes_map[j] <= 10)
|
||||
{
|
||||
/* Axes 8 through 10 are Wheel, Gas and Brake,
|
||||
* remap to 0, 1 and 2
|
||||
*/
|
||||
joydev.dev_axes_map[j] = axes_map[j] - 8;
|
||||
found_axes++;
|
||||
}
|
||||
else if (axes_map[j] == 16 ||
|
||||
axes_map[j] == 17)
|
||||
{
|
||||
/* POV axis */
|
||||
joydev.dev_axes_map[j] = 8;
|
||||
found_axes++;
|
||||
}
|
||||
else
|
||||
joydev.dev_axes_map[j] = -1;
|
||||
}
|
||||
|
||||
/* If no axes were configured but there are axes assume a 1-to-1 (wii controller) */
|
||||
if (joydev.axis_count && !found_axes)
|
||||
{
|
||||
int axes_limit = min(joydev.axis_count, 8); /* generic driver limit */
|
||||
|
||||
ERR("Incoherent joystick data, advertised %d axes, detected 0. Assuming 1-to-1.\n",
|
||||
joydev.axis_count);
|
||||
for (j = 0; j < axes_limit; j++)
|
||||
joydev.dev_axes_map[j] = j;
|
||||
|
||||
joydev.axis_count = axes_limit;
|
||||
}
|
||||
}
|
||||
|
||||
/* Find vendor_id and product_id in sysfs */
|
||||
joydev.vendor_id = 0;
|
||||
joydev.product_id = 0;
|
||||
|
||||
read_sys_id_variable(i, "vendor", &joydev.vendor_id);
|
||||
read_sys_id_variable(i, "product", &joydev.product_id);
|
||||
read_sys_id_variable(i, "bustype", &joydev.bus_type);
|
||||
|
||||
if (joydev.vendor_id == 0 || joydev.product_id == 0)
|
||||
{
|
||||
joydev.guid_product = DInput_Wine_Joystick_GUID;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Concatenate product_id with vendor_id to mimic Windows behaviour */
|
||||
joydev.guid_product = dinput_pidvid_guid;
|
||||
joydev.guid_product.Data1 = MAKELONG(joydev.vendor_id, joydev.product_id);
|
||||
}
|
||||
|
||||
close(fd);
|
||||
|
||||
if (!joystick_devices_count)
|
||||
new_joydevs = HeapAlloc(GetProcessHeap(), 0, sizeof(struct JoyDev));
|
||||
else
|
||||
new_joydevs = HeapReAlloc(GetProcessHeap(), 0, joystick_devices,
|
||||
(joystick_devices_count + 1) * sizeof(struct JoyDev));
|
||||
if (!new_joydevs) continue;
|
||||
|
||||
TRACE("Found a joystick on %s: %s\n with %d axes and %d buttons\n", joydev.device,
|
||||
joydev.name, joydev.axis_count, joydev.button_count);
|
||||
|
||||
joystick_devices = new_joydevs;
|
||||
joystick_devices[joystick_devices_count++] = joydev;
|
||||
}
|
||||
|
||||
return joystick_devices_count;
|
||||
}
|
||||
|
||||
static void fill_joystick_dideviceinstanceW(LPDIDEVICEINSTANCEW lpddi, DWORD version, int id)
|
||||
{
|
||||
DWORD dwSize = lpddi->dwSize;
|
||||
|
||||
TRACE("%d %p\n", dwSize, lpddi);
|
||||
memset(lpddi, 0, dwSize);
|
||||
|
||||
/* Return joystick */
|
||||
lpddi->dwSize = dwSize;
|
||||
lpddi->guidInstance = DInput_Wine_Joystick_GUID;
|
||||
lpddi->guidInstance.Data3 = id;
|
||||
lpddi->guidProduct = joystick_devices[id].guid_product;
|
||||
lpddi->dwDevType = get_device_type(version, joystick_devices[id].is_joystick);
|
||||
|
||||
/* Assume the joystick as HID if it is attached to USB bus and has a valid VID/PID */
|
||||
if (joystick_devices[id].bus_type == BUS_USB &&
|
||||
joystick_devices[id].vendor_id && joystick_devices[id].product_id)
|
||||
{
|
||||
lpddi->dwDevType |= DIDEVTYPE_HID;
|
||||
lpddi->wUsagePage = 0x01; /* Desktop */
|
||||
if (joystick_devices[id].is_joystick)
|
||||
lpddi->wUsage = 0x04; /* Joystick */
|
||||
else
|
||||
lpddi->wUsage = 0x05; /* Game Pad */
|
||||
}
|
||||
|
||||
MultiByteToWideChar(CP_ACP, 0, joystick_devices[id].name, -1, lpddi->tszInstanceName, MAX_PATH);
|
||||
MultiByteToWideChar(CP_ACP, 0, joystick_devices[id].name, -1, lpddi->tszProductName, MAX_PATH);
|
||||
lpddi->guidFFDriver = GUID_NULL;
|
||||
}
|
||||
|
||||
static HRESULT joydev_enum_device(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEW lpddi, DWORD version, int id)
|
||||
{
|
||||
int fd = -1;
|
||||
|
||||
if (id >= find_joystick_devices()) return E_FAIL;
|
||||
|
||||
if (dwFlags & DIEDFL_FORCEFEEDBACK) {
|
||||
WARN("force feedback not supported\n");
|
||||
return S_FALSE;
|
||||
}
|
||||
|
||||
if ((dwDevType == 0) ||
|
||||
((dwDevType == DIDEVTYPE_JOYSTICK) && (version >= 0x0300 && version < 0x0800)) ||
|
||||
(((dwDevType == DI8DEVCLASS_GAMECTRL) || (dwDevType == DI8DEVTYPE_JOYSTICK)) && (version >= 0x0800))) {
|
||||
/* check whether we have a joystick */
|
||||
if ((fd = open(joystick_devices[id].device, O_RDONLY)) == -1)
|
||||
{
|
||||
WARN("open(%s, O_RDONLY) failed: %s\n", joystick_devices[id].device, strerror(errno));
|
||||
return S_FALSE;
|
||||
}
|
||||
fill_joystick_dideviceinstanceW( lpddi, version, id );
|
||||
close(fd);
|
||||
TRACE("Enumerating the linux Joystick device: %s (%s)\n", joystick_devices[id].device, joystick_devices[id].name);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
return S_FALSE;
|
||||
}
|
||||
|
||||
static HRESULT alloc_device( REFGUID rguid, IDirectInputImpl *dinput, JoystickImpl **out, unsigned short index )
|
||||
{
|
||||
DWORD i;
|
||||
JoystickImpl* newDevice;
|
||||
HRESULT hr;
|
||||
LPDIDATAFORMAT df = NULL;
|
||||
int idx = 0;
|
||||
DIDEVICEINSTANCEW ddi;
|
||||
|
||||
TRACE( "%s %p %p %hu\n", debugstr_guid( rguid ), dinput, out, index );
|
||||
|
||||
if (FAILED(hr = direct_input_device_alloc( sizeof(JoystickImpl), &JoystickWvt, rguid, dinput, (void **)&newDevice )))
|
||||
return hr;
|
||||
df = newDevice->generic.base.data_format.wine_df;
|
||||
newDevice->generic.base.crit.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": JoystickImpl*->generic.base.crit");
|
||||
|
||||
newDevice->joydev = &joystick_devices[index];
|
||||
newDevice->joyfd = -1;
|
||||
newDevice->generic.guidInstance = DInput_Wine_Joystick_GUID;
|
||||
newDevice->generic.guidInstance.Data3 = index;
|
||||
newDevice->generic.guidProduct = DInput_Wine_Joystick_GUID;
|
||||
newDevice->generic.joy_polldev = joy_polldev;
|
||||
newDevice->generic.name = newDevice->joydev->name;
|
||||
newDevice->generic.device_axis_count = newDevice->joydev->axis_count;
|
||||
newDevice->generic.devcaps.dwButtons = newDevice->joydev->button_count;
|
||||
|
||||
if (newDevice->generic.devcaps.dwButtons > 128)
|
||||
{
|
||||
WARN("Can't support %d buttons. Clamping down to 128\n", newDevice->generic.devcaps.dwButtons);
|
||||
newDevice->generic.devcaps.dwButtons = 128;
|
||||
}
|
||||
|
||||
/* setup_dinput_options may change these */
|
||||
newDevice->generic.deadzone = 0;
|
||||
|
||||
/* do any user specified configuration */
|
||||
hr = setup_dinput_options(&newDevice->generic, newDevice->joydev->dev_axes_map);
|
||||
if (hr != DI_OK)
|
||||
goto FAILED1;
|
||||
|
||||
/* Create copy of default data format */
|
||||
memcpy(df, &c_dfDIJoystick2, c_dfDIJoystick2.dwSize);
|
||||
|
||||
df->dwNumObjs = newDevice->generic.devcaps.dwAxes + newDevice->generic.devcaps.dwPOVs + newDevice->generic.devcaps.dwButtons;
|
||||
if (!(df->rgodf = HeapAlloc(GetProcessHeap(), 0, df->dwNumObjs * df->dwObjSize))) goto FAILED;
|
||||
|
||||
for (i = 0; i < newDevice->generic.device_axis_count; i++)
|
||||
{
|
||||
int wine_obj = newDevice->generic.axis_map[i];
|
||||
|
||||
if (wine_obj < 0) continue;
|
||||
|
||||
memcpy(&df->rgodf[idx], &c_dfDIJoystick2.rgodf[wine_obj], df->dwObjSize);
|
||||
if (wine_obj < 8)
|
||||
df->rgodf[idx++].dwType = DIDFT_MAKEINSTANCE(wine_obj) | DIDFT_ABSAXIS;
|
||||
else
|
||||
{
|
||||
df->rgodf[idx++].dwType = DIDFT_MAKEINSTANCE(wine_obj - 8) | DIDFT_POV;
|
||||
i++; /* POV takes 2 axes */
|
||||
}
|
||||
}
|
||||
for (i = 0; i < newDevice->generic.devcaps.dwButtons; i++)
|
||||
{
|
||||
memcpy(&df->rgodf[idx], &c_dfDIJoystick2.rgodf[i + 12], df->dwObjSize);
|
||||
df->rgodf[idx ].pguid = &GUID_Button;
|
||||
df->rgodf[idx++].dwType = DIDFT_MAKEINSTANCE(i) | DIDFT_PSHBUTTON;
|
||||
}
|
||||
|
||||
/* initialize default properties */
|
||||
for (i = 0; i < c_dfDIJoystick2.dwNumObjs; i++) {
|
||||
newDevice->generic.props[i].lDevMin = -32767;
|
||||
newDevice->generic.props[i].lDevMax = +32767;
|
||||
newDevice->generic.props[i].lMin = 0;
|
||||
newDevice->generic.props[i].lMax = 0xffff;
|
||||
newDevice->generic.props[i].lDeadZone = newDevice->generic.deadzone; /* % * 1000 */
|
||||
newDevice->generic.props[i].lSaturation = 0;
|
||||
}
|
||||
|
||||
newDevice->generic.devcaps.dwSize = sizeof(newDevice->generic.devcaps);
|
||||
newDevice->generic.devcaps.dwFlags = DIDC_ATTACHED;
|
||||
|
||||
ddi.dwSize = sizeof(ddi);
|
||||
fill_joystick_dideviceinstanceW(&ddi, newDevice->generic.base.dinput->dwVersion, index);
|
||||
newDevice->generic.devcaps.dwDevType = ddi.dwDevType;
|
||||
|
||||
newDevice->generic.devcaps.dwFFSamplePeriod = 0;
|
||||
newDevice->generic.devcaps.dwFFMinTimeResolution = 0;
|
||||
newDevice->generic.devcaps.dwFirmwareRevision = 0;
|
||||
newDevice->generic.devcaps.dwHardwareRevision = 0;
|
||||
newDevice->generic.devcaps.dwFFDriverVersion = 0;
|
||||
|
||||
if (TRACE_ON(dinput)) {
|
||||
_dump_DIDATAFORMAT(newDevice->generic.base.data_format.wine_df);
|
||||
for (i = 0; i < (newDevice->generic.device_axis_count); i++)
|
||||
TRACE("axis_map[%d] = %d\n", i, newDevice->generic.axis_map[i]);
|
||||
_dump_DIDEVCAPS(&newDevice->generic.devcaps);
|
||||
}
|
||||
|
||||
*out = newDevice;
|
||||
return DI_OK;
|
||||
|
||||
FAILED:
|
||||
hr = DIERR_OUTOFMEMORY;
|
||||
FAILED1:
|
||||
if (df) HeapFree(GetProcessHeap(), 0, df->rgodf);
|
||||
HeapFree(GetProcessHeap(), 0, df);
|
||||
release_DataFormat(&newDevice->generic.base.data_format);
|
||||
HeapFree(GetProcessHeap(),0,newDevice->generic.axis_map);
|
||||
HeapFree(GetProcessHeap(),0,newDevice);
|
||||
return hr;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* get_joystick_index : Get the joystick index from a given GUID
|
||||
*/
|
||||
static unsigned short get_joystick_index(REFGUID guid)
|
||||
{
|
||||
GUID wine_joystick = DInput_Wine_Joystick_GUID;
|
||||
GUID dev_guid = *guid;
|
||||
INT i;
|
||||
|
||||
wine_joystick.Data3 = 0;
|
||||
dev_guid.Data3 = 0;
|
||||
|
||||
/* for the standard joystick GUID use index 0 */
|
||||
if(IsEqualGUID(&GUID_Joystick,guid)) return 0;
|
||||
|
||||
/* for the wine joystick GUIDs use the index stored in Data3 */
|
||||
if(IsEqualGUID(&wine_joystick, &dev_guid)) return guid->Data3;
|
||||
|
||||
for(i = 0; i < joystick_devices_count; i++)
|
||||
if(IsEqualGUID(&joystick_devices[i].guid_product, guid)) return i;
|
||||
|
||||
return MAX_JOYSTICKS;
|
||||
}
|
||||
|
||||
static HRESULT joydev_create_device( IDirectInputImpl *dinput, REFGUID rguid, IDirectInputDevice8W **out )
|
||||
{
|
||||
unsigned short index;
|
||||
|
||||
TRACE( "%p %s %p\n", dinput, debugstr_guid( rguid ), out );
|
||||
find_joystick_devices();
|
||||
*out = NULL;
|
||||
|
||||
if ((index = get_joystick_index(rguid)) < MAX_JOYSTICKS &&
|
||||
joystick_devices_count && index < joystick_devices_count)
|
||||
{
|
||||
JoystickImpl *This;
|
||||
HRESULT hr;
|
||||
|
||||
if (FAILED(hr = alloc_device( rguid, dinput, &This, index ))) return hr;
|
||||
|
||||
TRACE( "Created a Joystick device (%p)\n", This );
|
||||
|
||||
*out = &This->generic.base.IDirectInputDevice8W_iface;
|
||||
return hr;
|
||||
}
|
||||
|
||||
return DIERR_DEVICENOTREG;
|
||||
}
|
||||
|
||||
#undef MAX_JOYSTICKS
|
||||
|
||||
const struct dinput_device joystick_linux_device = {
|
||||
"Wine Linux joystick driver",
|
||||
joydev_enum_device,
|
||||
joydev_create_device
|
||||
};
|
||||
|
||||
/******************************************************************************
|
||||
* Acquire : gets exclusive control of the joystick
|
||||
*/
|
||||
static HRESULT WINAPI JoystickLinuxWImpl_Acquire(LPDIRECTINPUTDEVICE8W iface)
|
||||
{
|
||||
JoystickImpl *This = impl_from_IDirectInputDevice8W(iface);
|
||||
HRESULT res;
|
||||
|
||||
TRACE("(%p)\n",This);
|
||||
|
||||
res = IDirectInputDevice2WImpl_Acquire(iface);
|
||||
if (res != DI_OK)
|
||||
return res;
|
||||
|
||||
/* open the joystick device */
|
||||
if (This->joyfd==-1) {
|
||||
TRACE("opening joystick device %s\n", This->joydev->device);
|
||||
|
||||
This->joyfd = open(This->joydev->device, O_RDONLY);
|
||||
if (This->joyfd==-1) {
|
||||
ERR("open(%s) failed: %s\n", This->joydev->device, strerror(errno));
|
||||
IDirectInputDevice2WImpl_Unacquire(iface);
|
||||
return DIERR_NOTFOUND;
|
||||
}
|
||||
}
|
||||
|
||||
return DI_OK;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* GetProperty : get input device properties
|
||||
*/
|
||||
static HRESULT WINAPI JoystickLinuxWImpl_GetProperty(LPDIRECTINPUTDEVICE8W iface, REFGUID rguid, LPDIPROPHEADER pdiph)
|
||||
{
|
||||
JoystickImpl *This = impl_from_IDirectInputDevice8W(iface);
|
||||
|
||||
TRACE("(%p)->(%s,%p)\n", This, debugstr_guid(rguid), pdiph);
|
||||
_dump_DIPROPHEADER(pdiph);
|
||||
|
||||
if (!IS_DIPROP(rguid)) return DI_OK;
|
||||
|
||||
switch (LOWORD(rguid)) {
|
||||
|
||||
case (DWORD_PTR) DIPROP_VIDPID:
|
||||
{
|
||||
LPDIPROPDWORD pd = (LPDIPROPDWORD)pdiph;
|
||||
|
||||
if (!This->joydev->product_id || !This->joydev->vendor_id)
|
||||
return DIERR_UNSUPPORTED;
|
||||
pd->dwData = MAKELONG(This->joydev->vendor_id, This->joydev->product_id);
|
||||
TRACE("DIPROP_VIDPID(%08x)\n", pd->dwData);
|
||||
break;
|
||||
}
|
||||
case (DWORD_PTR) DIPROP_JOYSTICKID:
|
||||
{
|
||||
LPDIPROPDWORD pd = (LPDIPROPDWORD)pdiph;
|
||||
|
||||
pd->dwData = get_joystick_index(&This->generic.base.guid);
|
||||
TRACE("DIPROP_JOYSTICKID(%d)\n", pd->dwData);
|
||||
break;
|
||||
}
|
||||
|
||||
case (DWORD_PTR) DIPROP_GUIDANDPATH:
|
||||
{
|
||||
static const WCHAR formatW[] = {'\\','\\','?','\\','h','i','d','#','v','i','d','_','%','0','4','x','&',
|
||||
'p','i','d','_','%','0','4','x','&','%','s','_','%','h','u',0};
|
||||
static const WCHAR miW[] = {'m','i',0};
|
||||
static const WCHAR igW[] = {'i','g',0};
|
||||
|
||||
BOOL is_gamepad;
|
||||
LPDIPROPGUIDANDPATH pd = (LPDIPROPGUIDANDPATH)pdiph;
|
||||
WORD vid = This->joydev->vendor_id;
|
||||
WORD pid = This->joydev->product_id;
|
||||
|
||||
if (!pid || !vid)
|
||||
return DIERR_UNSUPPORTED;
|
||||
|
||||
is_gamepad = is_xinput_device(&This->generic.devcaps, vid, pid);
|
||||
pd->guidClass = GUID_DEVCLASS_HIDCLASS;
|
||||
sprintfW(pd->wszPath, formatW, vid, pid, is_gamepad ? igW : miW, get_joystick_index(&This->generic.base.guid));
|
||||
|
||||
TRACE("DIPROP_GUIDANDPATH(%s, %s): returning fake path\n", debugstr_guid(&pd->guidClass), debugstr_w(pd->wszPath));
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
return JoystickWGenericImpl_GetProperty(iface, rguid, pdiph);
|
||||
}
|
||||
|
||||
return DI_OK;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* GetDeviceInfo : get information about a device's identity
|
||||
*/
|
||||
static HRESULT WINAPI JoystickLinuxWImpl_GetDeviceInfo(LPDIRECTINPUTDEVICE8W iface, LPDIDEVICEINSTANCEW ddi)
|
||||
{
|
||||
JoystickImpl *This = impl_from_IDirectInputDevice8W(iface);
|
||||
|
||||
TRACE("(%p) %p\n", This, ddi);
|
||||
|
||||
if (ddi == NULL) return E_POINTER;
|
||||
if ((ddi->dwSize != sizeof(DIDEVICEINSTANCE_DX3W)) &&
|
||||
(ddi->dwSize != sizeof(DIDEVICEINSTANCEW)))
|
||||
return DIERR_INVALIDPARAM;
|
||||
|
||||
fill_joystick_dideviceinstanceW( ddi, This->generic.base.dinput->dwVersion,
|
||||
get_joystick_index(&This->generic.base.guid) );
|
||||
|
||||
ddi->guidInstance = This->generic.base.guid;
|
||||
|
||||
return DI_OK;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* Unacquire : frees the joystick
|
||||
*/
|
||||
static HRESULT WINAPI JoystickLinuxWImpl_Unacquire(LPDIRECTINPUTDEVICE8W iface)
|
||||
{
|
||||
JoystickImpl *This = impl_from_IDirectInputDevice8W(iface);
|
||||
HRESULT res;
|
||||
|
||||
TRACE("(%p)\n",This);
|
||||
|
||||
res = IDirectInputDevice2WImpl_Unacquire(iface);
|
||||
|
||||
if (res != DI_OK)
|
||||
return res;
|
||||
|
||||
if (This->joyfd!=-1) {
|
||||
TRACE("closing joystick device\n");
|
||||
close(This->joyfd);
|
||||
This->joyfd = -1;
|
||||
return DI_OK;
|
||||
}
|
||||
|
||||
return DI_NOEFFECT;
|
||||
}
|
||||
|
||||
static void joy_polldev( IDirectInputDevice8W *iface )
|
||||
{
|
||||
struct pollfd plfd;
|
||||
struct js_event jse;
|
||||
JoystickImpl *This = impl_from_IDirectInputDevice8W( iface );
|
||||
|
||||
TRACE("(%p)\n", This);
|
||||
|
||||
if (This->joyfd==-1) {
|
||||
WARN("no device\n");
|
||||
return;
|
||||
}
|
||||
while (1)
|
||||
{
|
||||
LONG value;
|
||||
int inst_id = -1;
|
||||
|
||||
plfd.fd = This->joyfd;
|
||||
plfd.events = POLLIN;
|
||||
if (poll(&plfd,1,0) != 1)
|
||||
return;
|
||||
/* we have one event, so we can read */
|
||||
if (sizeof(jse)!=read(This->joyfd,&jse,sizeof(jse))) {
|
||||
return;
|
||||
}
|
||||
TRACE("js_event: type 0x%x, number %d, value %d\n",
|
||||
jse.type,jse.number,jse.value);
|
||||
if (jse.type & JS_EVENT_BUTTON)
|
||||
{
|
||||
if (jse.number >= This->generic.devcaps.dwButtons) return;
|
||||
|
||||
inst_id = DIDFT_MAKEINSTANCE(jse.number) | DIDFT_PSHBUTTON;
|
||||
This->generic.js.rgbButtons[jse.number] = value = jse.value ? 0x80 : 0x00;
|
||||
}
|
||||
else if (jse.type & JS_EVENT_AXIS)
|
||||
{
|
||||
int number = This->generic.axis_map[jse.number]; /* wine format object index */
|
||||
|
||||
if (number < 0) return;
|
||||
inst_id = number < 8 ? DIDFT_MAKEINSTANCE(number) | DIDFT_ABSAXIS :
|
||||
DIDFT_MAKEINSTANCE(number - 8) | DIDFT_POV;
|
||||
value = joystick_map_axis(&This->generic.props[id_to_object(This->generic.base.data_format.wine_df, inst_id)], jse.value);
|
||||
|
||||
TRACE("changing axis %d => %d\n", jse.number, number);
|
||||
switch (number)
|
||||
{
|
||||
case 0: This->generic.js.lX = value; break;
|
||||
case 1: This->generic.js.lY = value; break;
|
||||
case 2: This->generic.js.lZ = value; break;
|
||||
case 3: This->generic.js.lRx = value; break;
|
||||
case 4: This->generic.js.lRy = value; break;
|
||||
case 5: This->generic.js.lRz = value; break;
|
||||
case 6: This->generic.js.rglSlider[0] = value; break;
|
||||
case 7: This->generic.js.rglSlider[1] = value; break;
|
||||
case 8: case 9: case 10: case 11:
|
||||
{
|
||||
int idx = number - 8;
|
||||
|
||||
if (jse.number % 2)
|
||||
This->povs[idx].y = jse.value;
|
||||
else
|
||||
This->povs[idx].x = jse.value;
|
||||
|
||||
This->generic.js.rgdwPOV[idx] = value = joystick_map_pov(&This->povs[idx]);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
WARN("axis %d not supported\n", number);
|
||||
}
|
||||
}
|
||||
if (inst_id >= 0)
|
||||
{
|
||||
queue_event(iface, inst_id, value, GetCurrentTime(), This->generic.base.dinput->evsequence++);
|
||||
if (This->generic.base.hEvent) SetEvent( This->generic.base.hEvent );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static const IDirectInputDevice8WVtbl JoystickWvt =
|
||||
{
|
||||
IDirectInputDevice2WImpl_QueryInterface,
|
||||
IDirectInputDevice2WImpl_AddRef,
|
||||
JoystickWGenericImpl_Release,
|
||||
JoystickWGenericImpl_GetCapabilities,
|
||||
IDirectInputDevice2WImpl_EnumObjects,
|
||||
JoystickLinuxWImpl_GetProperty,
|
||||
JoystickWGenericImpl_SetProperty,
|
||||
JoystickLinuxWImpl_Acquire,
|
||||
JoystickLinuxWImpl_Unacquire,
|
||||
JoystickWGenericImpl_GetDeviceState,
|
||||
IDirectInputDevice2WImpl_GetDeviceData,
|
||||
IDirectInputDevice2WImpl_SetDataFormat,
|
||||
IDirectInputDevice2WImpl_SetEventNotification,
|
||||
IDirectInputDevice2WImpl_SetCooperativeLevel,
|
||||
JoystickWGenericImpl_GetObjectInfo,
|
||||
JoystickLinuxWImpl_GetDeviceInfo,
|
||||
IDirectInputDevice2WImpl_RunControlPanel,
|
||||
IDirectInputDevice2WImpl_Initialize,
|
||||
IDirectInputDevice2WImpl_CreateEffect,
|
||||
IDirectInputDevice2WImpl_EnumEffects,
|
||||
IDirectInputDevice2WImpl_GetEffectInfo,
|
||||
IDirectInputDevice2WImpl_GetForceFeedbackState,
|
||||
IDirectInputDevice2WImpl_SendForceFeedbackCommand,
|
||||
IDirectInputDevice2WImpl_EnumCreatedEffectObjects,
|
||||
IDirectInputDevice2WImpl_Escape,
|
||||
JoystickWGenericImpl_Poll,
|
||||
IDirectInputDevice2WImpl_SendDeviceData,
|
||||
IDirectInputDevice7WImpl_EnumEffectsInFile,
|
||||
IDirectInputDevice7WImpl_WriteEffectToFile,
|
||||
JoystickWGenericImpl_BuildActionMap,
|
||||
JoystickWGenericImpl_SetActionMap,
|
||||
IDirectInputDevice8WImpl_GetImageInfo
|
||||
};
|
||||
|
||||
#else /* HAVE_LINUX_22_JOYSTICK_API */
|
||||
|
||||
const struct dinput_device joystick_linux_device = {
|
||||
"Wine Linux joystick driver",
|
||||
NULL,
|
||||
NULL,
|
||||
};
|
||||
|
||||
#endif /* HAVE_LINUX_22_JOYSTICK_API */
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -1,91 +0,0 @@
|
|||
/*
|
||||
* Copyright 2009, Aric Stewart, CodeWeavers
|
||||
*
|
||||
* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#ifndef __WINE_DLLS_DINPUT_JOYSTICK_PRIVATE_H
|
||||
#define __WINE_DLLS_DINPUT_JOYSTICK_PRIVATE_H
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "windef.h"
|
||||
#include "winbase.h"
|
||||
#include "dinput.h"
|
||||
#include "wine/list.h"
|
||||
#include "wine/unicode.h"
|
||||
#include "dinput_private.h"
|
||||
#include "device_private.h"
|
||||
|
||||
/* Number of objects in the default data format */
|
||||
#define MAX_PROPS 164
|
||||
struct JoystickGenericImpl;
|
||||
|
||||
typedef void joy_polldev_handler( IDirectInputDevice8W *iface );
|
||||
|
||||
typedef struct JoystickGenericImpl
|
||||
{
|
||||
struct IDirectInputDeviceImpl base;
|
||||
|
||||
ObjProps props[MAX_PROPS];
|
||||
DIDEVCAPS devcaps;
|
||||
DIJOYSTATE2 js; /* wine data */
|
||||
GUID guidProduct;
|
||||
GUID guidInstance;
|
||||
char *name;
|
||||
int device_axis_count; /* Total number of axes in the device */
|
||||
int *axis_map; /* User axes remapping */
|
||||
LONG deadzone; /* Default dead-zone */
|
||||
|
||||
joy_polldev_handler *joy_polldev;
|
||||
} JoystickGenericImpl;
|
||||
|
||||
LONG joystick_map_axis(ObjProps *props, int val) DECLSPEC_HIDDEN;
|
||||
HRESULT setup_dinput_options(JoystickGenericImpl *This, const int *default_axis_map) DECLSPEC_HIDDEN;
|
||||
|
||||
DWORD joystick_map_pov(const POINTL *p) DECLSPEC_HIDDEN;
|
||||
|
||||
BOOL device_disabled_registry(const char* name) DECLSPEC_HIDDEN;
|
||||
BOOL device_instance_is_disabled( DIDEVICEINSTANCEW *instance, BOOL *override ) DECLSPEC_HIDDEN;
|
||||
|
||||
ULONG WINAPI JoystickWGenericImpl_Release(LPDIRECTINPUTDEVICE8W iface);
|
||||
|
||||
HRESULT WINAPI JoystickWGenericImpl_GetObjectInfo(LPDIRECTINPUTDEVICE8W iface,
|
||||
LPDIDEVICEOBJECTINSTANCEW pdidoi, DWORD dwObj, DWORD dwHow) DECLSPEC_HIDDEN;
|
||||
|
||||
HRESULT WINAPI JoystickWGenericImpl_GetProperty(LPDIRECTINPUTDEVICE8W iface, REFGUID rguid, LPDIPROPHEADER pdiph) DECLSPEC_HIDDEN;
|
||||
|
||||
HRESULT WINAPI JoystickWGenericImpl_GetCapabilities(LPDIRECTINPUTDEVICE8W iface, LPDIDEVCAPS lpDIDevCaps) DECLSPEC_HIDDEN;
|
||||
|
||||
void _dump_DIDEVCAPS(const DIDEVCAPS *lpDIDevCaps) DECLSPEC_HIDDEN;
|
||||
|
||||
HRESULT WINAPI JoystickWGenericImpl_SetProperty(LPDIRECTINPUTDEVICE8W iface, REFGUID rguid, LPCDIPROPHEADER ph) DECLSPEC_HIDDEN;
|
||||
|
||||
HRESULT WINAPI JoystickWGenericImpl_GetDeviceInfo( LPDIRECTINPUTDEVICE8W iface,
|
||||
LPDIDEVICEINSTANCEW pdidi) DECLSPEC_HIDDEN;
|
||||
|
||||
HRESULT WINAPI JoystickWGenericImpl_Poll(LPDIRECTINPUTDEVICE8W iface) DECLSPEC_HIDDEN;
|
||||
|
||||
HRESULT WINAPI JoystickWGenericImpl_GetDeviceState(LPDIRECTINPUTDEVICE8W iface, DWORD len, LPVOID ptr) DECLSPEC_HIDDEN;
|
||||
|
||||
HRESULT WINAPI JoystickWGenericImpl_BuildActionMap(LPDIRECTINPUTDEVICE8W iface, LPDIACTIONFORMATW lpdiaf, LPCWSTR lpszUserName, DWORD dwFlags) DECLSPEC_HIDDEN;
|
||||
|
||||
HRESULT WINAPI JoystickWGenericImpl_SetActionMap(LPDIRECTINPUTDEVICE8W iface, LPDIACTIONFORMATW lpdiaf, LPCWSTR lpszUserName, DWORD dwFlags) DECLSPEC_HIDDEN;
|
||||
|
||||
DWORD typeFromGUID(REFGUID guid) DECLSPEC_HIDDEN;
|
||||
void dump_DIEFFECT(LPCDIEFFECT eff, REFGUID guid, DWORD dwFlags) DECLSPEC_HIDDEN;
|
||||
BOOL is_xinput_device(const DIDEVCAPS *devcaps, WORD vid, WORD pid) DECLSPEC_HIDDEN;
|
||||
|
||||
#endif /* __WINE_DLLS_DINPUT_JOYSTICK_PRIVATE_H */
|
|
@ -2,7 +2,6 @@ MODULE = dinput8.dll
|
|||
IMPORTLIB = dinput8
|
||||
IMPORTS = dinput8 dxguid uuid comctl32 ole32 user32 advapi32 hid setupapi
|
||||
EXTRADEFS = -DDIRECTINPUT_VERSION=0x0800
|
||||
EXTRALIBS = $(IOKIT_LIBS) $(FORCEFEEDBACK_LIBS)
|
||||
PARENTSRC = ../dinput
|
||||
|
||||
EXTRADLLFLAGS = -mcygwin
|
||||
|
@ -13,12 +12,7 @@ C_SRCS = \
|
|||
data_formats.c \
|
||||
device.c \
|
||||
dinput_main.c \
|
||||
effect_linuxinput.c \
|
||||
joystick.c \
|
||||
joystick_hid.c \
|
||||
joystick_linux.c \
|
||||
joystick_linuxinput.c \
|
||||
joystick_osx.c \
|
||||
keyboard.c \
|
||||
mouse.c
|
||||
|
||||
|
|
Loading…
Reference in New Issue