1 /* DirectInput Joystick device
3 * Copyright 1998,2000 Marcus Meissner
4 * Copyright 1998,1999 Lionel Ulmer
5 * Copyright 2000-2001 TransGaming Technologies Inc.
6 * Copyright 2005 Daniel Remenak
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24 #include "wine/port.h"
34 #ifdef HAVE_SYS_TIME_H
35 # include <sys/time.h>
37 #include <sys/fcntl.h>
38 #ifdef HAVE_SYS_IOCTL_H
39 # include <sys/ioctl.h>
42 #ifdef HAVE_SYS_ERRNO_H
43 # include <sys/errno.h>
45 #ifdef HAVE_LINUX_INPUT_H
46 # include <linux/input.h>
47 # if defined(EVIOCGBIT) && defined(EV_ABS) && defined(BTN_PINKIE)
48 # define HAVE_CORRECT_LINUXINPUT_H
52 #include "wine/debug.h"
53 #include "wine/unicode.h"
59 #include "dinput_private.h"
60 #include "device_private.h"
62 WINE_DEFAULT_DEBUG_CHANNEL(dinput
);
64 #ifdef HAVE_CORRECT_LINUXINPUT_H
66 #define EVDEVPREFIX "/dev/input/event"
68 /* Wine joystick driver object instances */
69 #define WINE_JOYSTICK_AXIS_BASE 0
70 #define WINE_JOYSTICK_POV_BASE 6
71 #define WINE_JOYSTICK_BUTTON_BASE 8
73 typedef struct EffectListItem EffectListItem
;
76 LPDIRECTINPUTEFFECT ref
;
77 struct EffectListItem
* next
;
80 /* implemented in effect_linuxinput.c */
81 HRESULT
linuxinput_create_effect(int* fd
, REFGUID rguid
, LPDIRECTINPUTEFFECT
* peff
);
82 HRESULT
linuxinput_get_info_A(int fd
, REFGUID rguid
, LPDIEFFECTINFOA info
);
83 HRESULT
linuxinput_get_info_W(int fd
, REFGUID rguid
, LPDIEFFECTINFOW info
);
85 typedef struct JoystickImpl JoystickImpl
;
86 static const IDirectInputDevice8AVtbl JoystickAvt
;
87 static const IDirectInputDevice8WVtbl JoystickWvt
;
95 /* The 'parent' DInput */
96 IDirectInputImpl
*dinput
;
98 /* joystick private */
99 /* what range and deadzone the game wants */
100 LONG wantmin
[ABS_MAX
];
101 LONG wantmax
[ABS_MAX
];
104 /* autodetecting ranges per axe by following movement */
105 LONG havemax
[ABS_MAX
];
106 LONG havemin
[ABS_MAX
];
112 LPDIDEVICEOBJECTDATA data_queue
;
113 int queue_head
, queue_tail
, queue_len
;
117 /* Force feedback variables */
120 EffectListItem
* top_effect
;
123 /* data returned by the EVIOCGABS() ioctl */
124 int axes
[ABS_MAX
][5];
125 /* LUT for KEY_ to offset in rgbButtons */
126 BYTE buttons
[KEY_MAX
];
131 #define AXE_ABSFUZZ 3
132 #define AXE_ABSFLAT 4
135 /* data returned by EVIOCGBIT for caps, EV_ABS, EV_KEY, and EV_FF */
136 BYTE evbits
[(EV_MAX
+7)/8];
137 BYTE absbits
[(ABS_MAX
+7)/8];
138 BYTE keybits
[(KEY_MAX
+7)/8];
139 BYTE ffbits
[(FF_MAX
+7)/8];
142 /* This GUID is slightly different from the linux joystick one. Take note. */
143 static GUID DInput_Wine_Joystick_GUID
= { /* 9e573eda-7734-11d2-8d4a-23903fb6bdf7 */
147 {0x8d, 0x4a, 0x23, 0x90, 0x3f, 0xb6, 0xbd, 0xf7}
150 static void fake_current_js_state(JoystickImpl
*ji
);
151 static int find_property_offset(JoystickImpl
*This
, LPCDIPROPHEADER ph
);
152 static DWORD
map_pov(int event_value
, int is_x
);
154 #define test_bit(arr,bit) (((BYTE*)(arr))[(bit)>>3]&(1<<((bit)&7)))
156 static int joydev_have(BOOL require_ff
)
158 int i
, fd
, flags
, num_effects
;
163 BYTE absbits
[(ABS_MAX
+7)/8],keybits
[(KEY_MAX
+7)/8];
164 BYTE evbits
[(EV_MAX
+7)/8],ffbits
[(FF_MAX
+7)/8];
166 sprintf(buf
,EVDEVPREFIX
"%d",i
);
173 if (-1!=(fd
=open(buf
,flags
))) {
174 if (-1==ioctl(fd
,EVIOCGBIT(EV_ABS
,sizeof(absbits
)),absbits
)) {
175 perror("EVIOCGBIT EV_ABS");
179 if (-1==ioctl(fd
,EVIOCGBIT(EV_KEY
,sizeof(keybits
)),keybits
)) {
180 perror("EVIOCGBIT EV_KEY");
185 /* test for force feedback if it's required */
187 if ((-1==ioctl(fd
,EVIOCGBIT(0,sizeof(evbits
)),evbits
))) {
188 perror("EVIOCGBIT 0");
192 if ( (!test_bit(evbits
,EV_FF
))
193 || (-1==ioctl(fd
,EVIOCGBIT(EV_FF
,sizeof(ffbits
)),ffbits
))
194 || (-1==ioctl(fd
,EVIOCGEFFECTS
,&num_effects
))
195 || (num_effects
<= 0)) {
201 /* A true joystick has at least axis X and Y, and at least 1
202 * button. copied from linux/drivers/input/joydev.c */
203 if (test_bit(absbits
,ABS_X
) && test_bit(absbits
,ABS_Y
) &&
204 ( test_bit(keybits
,BTN_TRIGGER
) ||
205 test_bit(keybits
,BTN_A
) ||
206 test_bit(keybits
,BTN_1
)
209 FIXME("found a joystick at %s!\n",buf
);
214 if (havejoy
|| (errno
==ENODEV
))
220 static BOOL
joydev_enum_deviceA(DWORD dwDevType
, DWORD dwFlags
, LPDIDEVICEINSTANCEA lpddi
, DWORD version
, int id
)
227 if (!((dwDevType
== 0) ||
228 ((dwDevType
== DIDEVTYPE_JOYSTICK
) && (version
< 0x0800)) ||
229 (((dwDevType
== DI8DEVCLASS_GAMECTRL
) || (dwDevType
== DI8DEVTYPE_JOYSTICK
)) && (version
>= 0x0800))))
232 #ifndef HAVE_STRUCT_FF_EFFECT_DIRECTION
233 if (dwFlags
& DIEDFL_FORCEFEEDBACK
)
237 havejoy
= joydev_have(dwFlags
& DIEDFL_FORCEFEEDBACK
);
242 TRACE("Enumerating the linuxinput Joystick device\n");
244 /* Return joystick */
245 lpddi
->guidInstance
= GUID_Joystick
;
246 lpddi
->guidProduct
= DInput_Wine_Joystick_GUID
;
248 lpddi
->guidFFDriver
= GUID_NULL
;
249 if (version
>= 0x0800)
250 lpddi
->dwDevType
= DI8DEVTYPE_JOYSTICK
| (DI8DEVTYPEJOYSTICK_STANDARD
<< 8);
252 lpddi
->dwDevType
= DIDEVTYPE_JOYSTICK
| (DIDEVTYPEJOYSTICK_TRADITIONAL
<< 8);
254 strcpy(lpddi
->tszInstanceName
, "Joystick");
255 /* ioctl JSIOCGNAME(len) */
256 strcpy(lpddi
->tszProductName
, "Wine Joystick");
260 static BOOL
joydev_enum_deviceW(DWORD dwDevType
, DWORD dwFlags
, LPDIDEVICEINSTANCEW lpddi
, DWORD version
, int id
)
267 if (!((dwDevType
== 0) ||
268 ((dwDevType
== DIDEVTYPE_JOYSTICK
) && (version
< 0x0800)) ||
269 (((dwDevType
== DI8DEVCLASS_GAMECTRL
) || (dwDevType
== DI8DEVTYPE_JOYSTICK
)) && (version
>= 0x0800))))
272 #ifndef HAVE_STRUCT_FF_EFFECT_DIRECTION
273 if (dwFlags
& DIEDFL_FORCEFEEDBACK
)
277 havejoy
= joydev_have(dwFlags
& DIEDFL_FORCEFEEDBACK
);
282 TRACE("Enumerating the linuxinput Joystick device\n");
284 /* Return joystick */
285 lpddi
->guidInstance
= GUID_Joystick
;
286 lpddi
->guidProduct
= DInput_Wine_Joystick_GUID
;
288 lpddi
->guidFFDriver
= GUID_NULL
;
289 if (version
>= 0x0800)
290 lpddi
->dwDevType
= DI8DEVTYPE_JOYSTICK
| (DI8DEVTYPEJOYSTICK_STANDARD
<< 8);
292 lpddi
->dwDevType
= DIDEVTYPE_JOYSTICK
| (DIDEVTYPEJOYSTICK_TRADITIONAL
<< 8);
294 MultiByteToWideChar(CP_ACP
, 0, "Joystick", -1, lpddi
->tszInstanceName
, MAX_PATH
);
295 /* ioctl JSIOCGNAME(len) */
296 MultiByteToWideChar(CP_ACP
, 0, "Wine Joystick", -1, lpddi
->tszProductName
, MAX_PATH
);
300 static JoystickImpl
*alloc_device(REFGUID rguid
, const void *jvt
, IDirectInputImpl
*dinput
)
302 JoystickImpl
* newDevice
;
305 newDevice
= HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,sizeof(JoystickImpl
));
306 newDevice
->lpVtbl
= jvt
;
308 newDevice
->joyfd
= -1;
309 newDevice
->dinput
= dinput
;
310 #ifdef HAVE_STRUCT_FF_EFFECT_DIRECTION
311 newDevice
->ff_state
= FF_STATUS_STOPPED
;
313 memcpy(&(newDevice
->guid
),rguid
,sizeof(*rguid
));
314 for (i
=0;i
<ABS_MAX
;i
++) {
315 newDevice
->wantmin
[i
] = -32768;
316 newDevice
->wantmax
[i
] = 32767;
318 * direct input defines a default for the deadzone somewhere; but as long
319 * as in map_axis the code for the dead zone is commented out its no
322 newDevice
->deadz
[i
] = 0;
324 fake_current_js_state(newDevice
);
328 static HRESULT
joydev_create_deviceA(IDirectInputImpl
*dinput
, REFGUID rguid
, REFIID riid
, LPDIRECTINPUTDEVICEA
* pdev
)
332 havejoy
= joydev_have(FALSE
);
335 return DIERR_DEVICENOTREG
;
337 if ((IsEqualGUID(&GUID_Joystick
,rguid
)) ||
338 (IsEqualGUID(&DInput_Wine_Joystick_GUID
,rguid
))) {
339 if ((riid
== NULL
) ||
340 IsEqualGUID(&IID_IDirectInputDeviceA
,riid
) ||
341 IsEqualGUID(&IID_IDirectInputDevice2A
,riid
) ||
342 IsEqualGUID(&IID_IDirectInputDevice7A
,riid
) ||
343 IsEqualGUID(&IID_IDirectInputDevice8A
,riid
)) {
344 *pdev
= (IDirectInputDeviceA
*) alloc_device(rguid
, &JoystickAvt
, dinput
);
345 TRACE("Creating a Joystick device (%p)\n", *pdev
);
348 return DIERR_NOINTERFACE
;
351 return DIERR_DEVICENOTREG
;
355 static HRESULT
joydev_create_deviceW(IDirectInputImpl
*dinput
, REFGUID rguid
, REFIID riid
, LPDIRECTINPUTDEVICEW
* pdev
)
359 havejoy
= joydev_have(FALSE
);
362 return DIERR_DEVICENOTREG
;
364 if ((IsEqualGUID(&GUID_Joystick
,rguid
)) ||
365 (IsEqualGUID(&DInput_Wine_Joystick_GUID
,rguid
))) {
366 if ((riid
== NULL
) ||
367 IsEqualGUID(&IID_IDirectInputDeviceW
,riid
) ||
368 IsEqualGUID(&IID_IDirectInputDevice2W
,riid
) ||
369 IsEqualGUID(&IID_IDirectInputDevice7W
,riid
) ||
370 IsEqualGUID(&IID_IDirectInputDevice8W
,riid
)) {
371 *pdev
= (IDirectInputDeviceW
*) alloc_device(rguid
, &JoystickWvt
, dinput
);
372 TRACE("Creating a Joystick device (%p)\n", *pdev
);
375 return DIERR_NOINTERFACE
;
378 return DIERR_DEVICENOTREG
;
381 const struct dinput_device joystick_linuxinput_device
= {
382 "Wine Linux-input joystick driver",
385 joydev_create_deviceA
,
386 joydev_create_deviceW
389 /******************************************************************************
392 static ULONG WINAPI
JoystickAImpl_Release(LPDIRECTINPUTDEVICE8A iface
)
394 JoystickImpl
*This
= (JoystickImpl
*)iface
;
397 ref
= InterlockedDecrement(&(This
->ref
));
401 /* Reset the FF state, free all effects, etc */
402 IDirectInputDevice8_SendForceFeedbackCommand(iface
, DISFFC_RESET
);
404 /* Free the data queue */
405 HeapFree(GetProcessHeap(),0,This
->data_queue
);
407 /* Free the DataFormat */
408 HeapFree(GetProcessHeap(), 0, This
->df
);
410 HeapFree(GetProcessHeap(),0,This
);
414 /******************************************************************************
415 * SetDataFormat : the application can choose the format of the data
416 * the device driver sends back with GetDeviceState.
418 static HRESULT WINAPI
JoystickAImpl_SetDataFormat(
419 LPDIRECTINPUTDEVICE8A iface
,LPCDIDATAFORMAT df
422 JoystickImpl
*This
= (JoystickImpl
*)iface
;
424 TRACE("(this=%p,%p)\n",This
,df
);
427 WARN("invalid pointer\n");
431 if (df
->dwSize
!= sizeof(*df
)) {
432 WARN("invalid argument\n");
433 return DIERR_INVALIDPARAM
;
436 _dump_DIDATAFORMAT(df
);
438 if (This
->joyfd
!=-1) {
440 return DIERR_ACQUIRED
;
443 /* Store the new data format */
444 This
->df
= HeapAlloc(GetProcessHeap(),0,df
->dwSize
);
445 if (This
->df
==NULL
) {
446 return DIERR_OUTOFMEMORY
;
448 memcpy(This
->df
, df
, df
->dwSize
);
449 This
->df
->rgodf
= HeapAlloc(GetProcessHeap(),0,df
->dwNumObjs
*df
->dwObjSize
);
450 if (This
->df
->rgodf
==NULL
) {
451 HeapFree(GetProcessHeap(), 0, This
->df
);
452 return DIERR_OUTOFMEMORY
;
454 memcpy(This
->df
->rgodf
,df
->rgodf
,df
->dwNumObjs
*df
->dwObjSize
);
459 /******************************************************************************
460 * Acquire : gets exclusive control of the joystick
462 static HRESULT WINAPI
JoystickAImpl_Acquire(LPDIRECTINPUTDEVICE8A iface
)
465 JoystickImpl
*This
= (JoystickImpl
*)iface
;
467 BOOL readonly
= TRUE
;
469 TRACE("(this=%p)\n",This
);
472 if (This
->df
==NULL
) {
473 return DIERR_INVALIDPARAM
;
476 sprintf(buf
,EVDEVPREFIX
"%d",i
);
477 if (-1==(This
->joyfd
=open(buf
,O_RDWR
))) {
478 if (-1==(This
->joyfd
=open(buf
,O_RDONLY
))) {
479 /* Couldn't open the device at all */
481 return DIERR_NOTFOUND
;
486 /* Couldn't open in r/w but opened in read-only. */
487 WARN("Could not open %s in read-write mode. Force feedback will be disabled.\n",buf
);
491 /* Opened device in read-write */
494 if ((-1!=ioctl(This
->joyfd
,EVIOCGBIT(0,sizeof(This
->evbits
)),This
->evbits
)) &&
495 (-1!=ioctl(This
->joyfd
,EVIOCGBIT(EV_ABS
,sizeof(This
->absbits
)),This
->absbits
)) &&
496 (-1!=ioctl(This
->joyfd
,EVIOCGBIT(EV_KEY
,sizeof(This
->keybits
)),This
->keybits
)) &&
497 (test_bit(This
->absbits
,ABS_X
) && test_bit(This
->absbits
,ABS_Y
) &&
498 (test_bit(This
->keybits
,BTN_TRIGGER
)||
499 test_bit(This
->keybits
,BTN_A
) ||
500 test_bit(This
->keybits
,BTN_1
)
509 return DIERR_NOTFOUND
;
511 This
->has_ff
= FALSE
;
512 This
->num_effects
= 0;
514 #ifdef HAVE_STRUCT_FF_EFFECT_DIRECTION
515 if (!readonly
&& test_bit(This
->evbits
, EV_FF
)) {
516 if (-1!=ioctl(This
->joyfd
,EVIOCGBIT(EV_FF
,sizeof(This
->ffbits
)),This
->ffbits
)) {
517 if (-1!=ioctl(This
->joyfd
,EVIOCGEFFECTS
,&This
->num_effects
)
518 && This
->num_effects
> 0) {
520 TRACE("Joystick seems to be capable of force feedback.\n");
523 TRACE("Joystick does not support any effects, disabling force feedback.\n");
527 TRACE("Could not get EV_FF bits; disabling force feedback.\n");
531 TRACE("Force feedback disabled (device is readonly or joystick incapable).\n");
535 for (i
=0;i
<ABS_MAX
;i
++) {
536 if (test_bit(This
->absbits
,i
)) {
537 if (-1==ioctl(This
->joyfd
,EVIOCGABS(i
),&(This
->axes
[i
])))
539 TRACE("axe %d: cur=%d, min=%d, max=%d, fuzz=%d, flat=%d\n",
541 This
->axes
[i
][AXE_ABS
],
542 This
->axes
[i
][AXE_ABSMIN
],
543 This
->axes
[i
][AXE_ABSMAX
],
544 This
->axes
[i
][AXE_ABSFUZZ
],
545 This
->axes
[i
][AXE_ABSFLAT
]
547 This
->havemin
[i
] = This
->axes
[i
][AXE_ABSMIN
];
548 This
->havemax
[i
] = This
->axes
[i
][AXE_ABSMAX
];
552 for (i
=0;i
<KEY_MAX
;i
++) {
553 if (test_bit(This
->keybits
,i
)) {
554 TRACE("button %d: %d\n", i
, buttons
);
555 This
->buttons
[i
] = 0x80 | buttons
;
560 fake_current_js_state(This
);
565 /******************************************************************************
566 * Unacquire : frees the joystick
568 static HRESULT WINAPI
JoystickAImpl_Unacquire(LPDIRECTINPUTDEVICE8A iface
)
570 JoystickImpl
*This
= (JoystickImpl
*)iface
;
572 TRACE("(this=%p)\n",This
);
573 if (This
->joyfd
!=-1) {
583 * This maps the read value (from the input event) to a value in the
584 * 'wanted' range. It also autodetects the possible range of the axe and
585 * adapts values accordingly.
588 map_axis(JoystickImpl
* This
, int axis
, int val
) {
589 int xmin
= This
->axes
[axis
][AXE_ABSMIN
];
590 int xmax
= This
->axes
[axis
][AXE_ABSMAX
];
591 int hmax
= This
->havemax
[axis
];
592 int hmin
= This
->havemin
[axis
];
593 int wmin
= This
->wantmin
[axis
];
594 int wmax
= This
->wantmax
[axis
];
597 if (val
> hmax
) This
->havemax
[axis
] = hmax
= val
;
598 if (val
< hmin
) This
->havemin
[axis
] = hmin
= val
;
600 if (xmin
== xmax
) return val
;
602 /* map the value from the hmin-hmax range into the wmin-wmax range */
603 ret
= ((val
-hmin
) * (wmax
-wmin
)) / (hmax
-hmin
) + wmin
;
605 TRACE("xmin=%d xmax=%d hmin=%d hmax=%d wmin=%d wmax=%d val=%d ret=%d\n", xmin
, xmax
, hmin
, hmax
, wmin
, wmax
, val
, ret
);
608 /* deadzone doesn't work comfortably enough right now. needs more testing*/
609 if ((ret
> -deadz
/2 ) && (ret
< deadz
/2)) {
610 FIXME("%d in deadzone, return mid.\n",val
);
611 return (wmax
-wmin
)/2+wmin
;
618 * set the current state of the js device as it would be with the middle
621 static void fake_current_js_state(JoystickImpl
*ji
)
624 /* center the axes */
625 ji
->js
.lX
= map_axis(ji
, ABS_X
, ji
->axes
[ABS_X
][AXE_ABS
]);
626 ji
->js
.lY
= map_axis(ji
, ABS_Y
, ji
->axes
[ABS_Y
][AXE_ABS
]);
627 ji
->js
.lZ
= map_axis(ji
, ABS_Z
, ji
->axes
[ABS_Z
][AXE_ABS
]);
628 ji
->js
.lRx
= map_axis(ji
, ABS_RX
, ji
->axes
[ABS_RX
][AXE_ABS
]);
629 ji
->js
.lRy
= map_axis(ji
, ABS_RY
, ji
->axes
[ABS_RY
][AXE_ABS
]);
630 ji
->js
.lRz
= map_axis(ji
, ABS_RZ
, ji
->axes
[ABS_RZ
][AXE_ABS
]);
631 ji
->js
.rglSlider
[0] = map_axis(ji
, ABS_THROTTLE
, ji
->axes
[ABS_THROTTLE
][AXE_ABS
]);
632 ji
->js
.rglSlider
[1] = map_axis(ji
, ABS_RUDDER
, ji
->axes
[ABS_RUDDER
][AXE_ABS
]);
633 /* POV center is -1 */
634 for (i
=0; i
<4; i
++) {
635 ji
->js
.rgdwPOV
[i
] = -1;
640 * Maps an event value to a DX "clock" position:
645 static DWORD
map_pov(int event_value
, int is_x
)
651 } else if (event_value
>0) {
657 } else if (event_value
>0) {
664 static int find_property_offset(JoystickImpl
*This
, LPCDIPROPHEADER ph
)
667 case DIPH_BYOFFSET
: {
669 for (i
=0; i
<This
->df
->dwNumObjs
; i
++) {
670 if (This
->df
->rgodf
[i
].dwOfs
== ph
->dwObj
) {
677 return DIDFT_GETINSTANCE(ph
->dwObj
)>>WINE_JOYSTICK_AXIS_BASE
;
681 FIXME("Unhandled ph->dwHow=='%04X'\n", (unsigned int)ph
->dwHow
);
687 static void joy_polldev(JoystickImpl
*This
) {
690 struct input_event ie
;
697 memset(&tv
,0,sizeof(tv
));
699 FD_SET(This
->joyfd
,&readfds
);
701 if (1>select(This
->joyfd
+1,&readfds
,NULL
,NULL
,&tv
))
704 /* we have one event, so we can read */
705 if (sizeof(ie
)!=read(This
->joyfd
,&ie
,sizeof(ie
)))
708 TRACE("input_event: type %d, code %d, value %d\n",ie
.type
,ie
.code
,ie
.value
);
710 case EV_KEY
: /* button */
711 btn
= This
->buttons
[ie
.code
];
712 TRACE("(%p) %d -> %d\n", This
, ie
.code
, btn
);
715 This
->js
.rgbButtons
[btn
] = ie
.value
?0x80:0x00;
716 GEN_EVENT(DIJOFS_BUTTON(btn
),ie
.value
?0x80:0x0,ie
.time
.tv_usec
,(This
->dinput
->evsequence
)++);
722 This
->js
.lX
= map_axis(This
,ABS_X
,ie
.value
);
723 GEN_EVENT(DIJOFS_X
,This
->js
.lX
,ie
.time
.tv_usec
,(This
->dinput
->evsequence
)++);
726 This
->js
.lY
= map_axis(This
,ABS_Y
,ie
.value
);
727 GEN_EVENT(DIJOFS_Y
,This
->js
.lY
,ie
.time
.tv_usec
,(This
->dinput
->evsequence
)++);
730 This
->js
.lZ
= map_axis(This
,ABS_Z
,ie
.value
);
731 GEN_EVENT(DIJOFS_Z
,This
->js
.lZ
,ie
.time
.tv_usec
,(This
->dinput
->evsequence
)++);
734 This
->js
.lRx
= map_axis(This
,ABS_RX
,ie
.value
);
735 GEN_EVENT(DIJOFS_RX
,This
->js
.lRx
,ie
.time
.tv_usec
,(This
->dinput
->evsequence
)++);
738 This
->js
.lRy
= map_axis(This
,ABS_RY
,ie
.value
);
739 GEN_EVENT(DIJOFS_RY
,This
->js
.lRy
,ie
.time
.tv_usec
,(This
->dinput
->evsequence
)++);
742 This
->js
.lRz
= map_axis(This
,ABS_RZ
,ie
.value
);
743 GEN_EVENT(DIJOFS_RZ
,This
->js
.lRz
,ie
.time
.tv_usec
,(This
->dinput
->evsequence
)++);
746 This
->js
.rglSlider
[0] = map_axis(This
,ABS_THROTTLE
,ie
.value
);
747 GEN_EVENT(DIJOFS_SLIDER(0),This
->js
.rglSlider
[0],ie
.time
.tv_usec
,(This
->dinput
->evsequence
)++);
750 This
->js
.rglSlider
[1] = map_axis(This
,ABS_RUDDER
,ie
.value
);
751 GEN_EVENT(DIJOFS_SLIDER(1),This
->js
.rglSlider
[1],ie
.time
.tv_usec
,(This
->dinput
->evsequence
)++);
755 This
->js
.rgdwPOV
[0] = map_pov(ie
.value
,ie
.code
==ABS_HAT0X
);
756 GEN_EVENT(DIJOFS_POV(0),This
->js
.rgdwPOV
[0],ie
.time
.tv_usec
,(This
->dinput
->evsequence
)++);
760 This
->js
.rgdwPOV
[1] = map_pov(ie
.value
,ie
.code
==ABS_HAT1X
);
761 GEN_EVENT(DIJOFS_POV(1),This
->js
.rgdwPOV
[1],ie
.time
.tv_usec
,(This
->dinput
->evsequence
)++);
765 This
->js
.rgdwPOV
[2] = map_pov(ie
.value
,ie
.code
==ABS_HAT2X
);
766 GEN_EVENT(DIJOFS_POV(2),This
->js
.rgdwPOV
[2],ie
.time
.tv_usec
,(This
->dinput
->evsequence
)++);
770 This
->js
.rgdwPOV
[3] = map_pov(ie
.value
,ie
.code
==ABS_HAT3X
);
771 GEN_EVENT(DIJOFS_POV(3),This
->js
.rgdwPOV
[3],ie
.time
.tv_usec
,(This
->dinput
->evsequence
)++);
774 FIXME("unhandled joystick axe event (code %d, value %d)\n",ie
.code
,ie
.value
);
778 #ifdef HAVE_STRUCT_FF_EFFECT_DIRECTION
780 This
->ff_state
= ie
.value
;
785 /* there is nothing to do */
789 FIXME("joystick cannot handle type %d event (code %d)\n",ie
.type
,ie
.code
);
795 /******************************************************************************
796 * GetDeviceState : returns the "state" of the joystick.
799 static HRESULT WINAPI
JoystickAImpl_GetDeviceState(
800 LPDIRECTINPUTDEVICE8A iface
,DWORD len
,LPVOID ptr
802 JoystickImpl
*This
= (JoystickImpl
*)iface
;
806 TRACE("(this=%p,0x%08lx,%p)\n",This
,len
,ptr
);
807 if ((len
!= sizeof(DIJOYSTATE
)) && (len
!= sizeof(DIJOYSTATE2
))) {
808 FIXME("len %ld is not sizeof(DIJOYSTATE) or DIJOYSTATE2, unsupported format.\n",len
);
811 memcpy(ptr
,&(This
->js
),len
);
812 This
->queue_head
= 0;
813 This
->queue_tail
= 0;
817 /******************************************************************************
818 * GetDeviceData : gets buffered input data.
820 static HRESULT WINAPI
JoystickAImpl_GetDeviceData(LPDIRECTINPUTDEVICE8A iface
,
822 LPDIDEVICEOBJECTDATA dod
,
826 JoystickImpl
*This
= (JoystickImpl
*)iface
;
831 TRACE("(%p)->(dods=%ld,entries=%ld,fl=0x%08lx)\n",This
,dodsize
,*entries
,flags
);
833 if (This
->joyfd
==-!1) {
834 WARN("not acquired\n");
835 return DIERR_NOTACQUIRED
;
839 if (flags
& DIGDD_PEEK
)
840 FIXME("DIGDD_PEEK\n");
842 len
= ((This
->queue_head
< This
->queue_tail
) ? This
->queue_len
: 0)
843 + (This
->queue_head
- This
->queue_tail
);
849 TRACE("Application discarding %ld event(s).\n", len
);
852 nqtail
= This
->queue_tail
+ len
;
853 while (nqtail
>= This
->queue_len
)
854 nqtail
-= This
->queue_len
;
856 if (dodsize
< sizeof(DIDEVICEOBJECTDATA_DX3
)) {
857 ERR("Wrong structure size !\n");
858 return DIERR_INVALIDPARAM
;
862 TRACE("Application retrieving %ld event(s).\n", len
);
865 nqtail
= This
->queue_tail
;
867 /* Copy the buffered data into the application queue */
868 memcpy((char *)dod
+ *entries
* dodsize
, This
->data_queue
+ nqtail
, dodsize
);
869 /* Advance position */
871 if (nqtail
>= This
->queue_len
)
872 nqtail
-= This
->queue_len
;
878 if (This
->overflow
) {
879 hr
= DI_BUFFEROVERFLOW
;
880 if (!(flags
& DIGDD_PEEK
)) {
881 This
->overflow
= FALSE
;
885 if (!(flags
& DIGDD_PEEK
))
886 This
->queue_tail
= nqtail
;
891 /******************************************************************************
892 * SetProperty : change input device properties
894 static HRESULT WINAPI
JoystickAImpl_SetProperty(LPDIRECTINPUTDEVICE8A iface
,
898 JoystickImpl
*This
= (JoystickImpl
*)iface
;
901 WARN("invalid argument\n");
902 return DIERR_INVALIDPARAM
;
905 TRACE("(this=%p,%s,%p)\n",This
,debugstr_guid(rguid
),ph
);
906 TRACE("ph.dwSize = %ld, ph.dwHeaderSize =%ld, ph.dwObj = %ld, ph.dwHow= %ld\n",ph
->dwSize
, ph
->dwHeaderSize
,ph
->dwObj
,ph
->dwHow
);
908 if (!HIWORD(rguid
)) {
909 switch (LOWORD(rguid
)) {
910 case (DWORD
) DIPROP_BUFFERSIZE
: {
911 LPCDIPROPDWORD pd
= (LPCDIPROPDWORD
)ph
;
913 TRACE("buffersize = %ld\n",pd
->dwData
);
914 if (This
->data_queue
) {
915 This
->data_queue
= HeapReAlloc(GetProcessHeap(),0, This
->data_queue
, pd
->dwData
* sizeof(DIDEVICEOBJECTDATA
));
917 This
->data_queue
= HeapAlloc(GetProcessHeap(),0, pd
->dwData
* sizeof(DIDEVICEOBJECTDATA
));
919 This
->queue_head
= 0;
920 This
->queue_tail
= 0;
921 This
->queue_len
= pd
->dwData
;
924 case (DWORD
)DIPROP_RANGE
: {
925 LPCDIPROPRANGE pr
= (LPCDIPROPRANGE
)ph
;
927 if (ph
->dwHow
== DIPH_DEVICE
) {
929 TRACE("proprange(%ld,%ld) all\n",pr
->lMin
,pr
->lMax
);
930 for (i
= 0; i
< This
->df
->dwNumObjs
; i
++) {
931 This
->wantmin
[i
] = pr
->lMin
;
932 This
->wantmax
[i
] = pr
->lMax
;
935 int obj
= find_property_offset(This
, ph
);
936 TRACE("proprange(%ld,%ld) obj=%d\n",pr
->lMin
,pr
->lMax
,obj
);
938 This
->wantmin
[obj
] = pr
->lMin
;
939 This
->wantmax
[obj
] = pr
->lMax
;
944 case (DWORD
)DIPROP_DEADZONE
: {
945 LPCDIPROPDWORD pd
= (LPCDIPROPDWORD
)ph
;
946 if (ph
->dwHow
== DIPH_DEVICE
) {
948 TRACE("deadzone(%ld) all\n",pd
->dwData
);
949 for (i
= 0; i
< This
->df
->dwNumObjs
; i
++) {
950 This
->deadz
[i
] = pd
->dwData
;
953 int obj
= find_property_offset(This
, ph
);
954 TRACE("deadzone(%ld) obj=%d\n",pd
->dwData
,obj
);
956 This
->deadz
[obj
] = pd
->dwData
;
962 FIXME("Unknown type %p (%s)\n",rguid
,debugstr_guid(rguid
));
966 fake_current_js_state(This
);
970 /******************************************************************************
971 * SetEventNotification : specifies event to be sent on state change
973 static HRESULT WINAPI
JoystickAImpl_SetEventNotification(
974 LPDIRECTINPUTDEVICE8A iface
, HANDLE hnd
976 JoystickImpl
*This
= (JoystickImpl
*)iface
;
978 TRACE("(this=%p,%p)\n",This
,hnd
);
983 static HRESULT WINAPI
JoystickAImpl_GetCapabilities(
984 LPDIRECTINPUTDEVICE8A iface
,
985 LPDIDEVCAPS lpDIDevCaps
)
987 JoystickImpl
*This
= (JoystickImpl
*)iface
;
988 int xfd
= This
->joyfd
;
991 TRACE("%p->(%p)\n",iface
,lpDIDevCaps
);
994 WARN("invalid pointer\n");
998 if (lpDIDevCaps
->dwSize
!= sizeof(DIDEVCAPS
)) {
999 WARN("invalid argument\n");
1000 return DIERR_INVALIDPARAM
;
1004 /* yes, games assume we return something, even if unacquired */
1005 JoystickAImpl_Acquire(iface
);
1008 lpDIDevCaps
->dwFlags
= DIDC_ATTACHED
;
1009 if (This
->dinput
->dwVersion
>= 0x0800)
1010 lpDIDevCaps
->dwDevType
= DI8DEVTYPE_JOYSTICK
| (DI8DEVTYPEJOYSTICK_STANDARD
<< 8);
1012 lpDIDevCaps
->dwDevType
= DIDEVTYPE_JOYSTICK
| (DIDEVTYPEJOYSTICK_TRADITIONAL
<< 8);
1015 for (i
=0;i
<ABS_MAX
;i
++) if (test_bit(This
->absbits
,i
)) axes
++;
1017 for (i
=0;i
<KEY_MAX
;i
++) if (test_bit(This
->keybits
,i
)) buttons
++;
1020 lpDIDevCaps
->dwFlags
|= DIDC_FORCEFEEDBACK
;
1022 lpDIDevCaps
->dwAxes
= axes
;
1023 lpDIDevCaps
->dwButtons
= buttons
;
1026 JoystickAImpl_Unacquire(iface
);
1032 static HRESULT WINAPI
JoystickAImpl_Poll(LPDIRECTINPUTDEVICE8A iface
) {
1033 JoystickImpl
*This
= (JoystickImpl
*)iface
;
1034 TRACE("(%p)\n",This
);
1036 if (This
->joyfd
==-1) {
1037 return DIERR_NOTACQUIRED
;
1044 /******************************************************************************
1045 * EnumObjects : enumerate the different buttons and axis...
1047 static HRESULT WINAPI
JoystickAImpl_EnumObjects(
1048 LPDIRECTINPUTDEVICE8A iface
,
1049 LPDIENUMDEVICEOBJECTSCALLBACKA lpCallback
,
1053 JoystickImpl
*This
= (JoystickImpl
*)iface
;
1054 DIDEVICEOBJECTINSTANCEA ddoi
;
1055 int xfd
= This
->joyfd
;
1057 TRACE("(this=%p,%p,%p,%08lx)\n", This
, lpCallback
, lpvRef
, dwFlags
);
1058 if (TRACE_ON(dinput
)) {
1059 TRACE(" - flags = ");
1060 _dump_EnumObjects_flags(dwFlags
);
1064 /* We need to work even if we're not yet acquired */
1066 IDirectInputDevice8_Acquire(iface
);
1068 /* Only the fields till dwFFMaxForce are relevant */
1069 ddoi
.dwSize
= FIELD_OFFSET(DIDEVICEOBJECTINSTANCEA
, dwFFMaxForce
);
1071 /* For the joystick, do as is done in the GetCapabilities function */
1072 /* FIXME: needs more items */
1073 if ((dwFlags
== DIDFT_ALL
) ||
1074 (dwFlags
& DIDFT_AXIS
)) {
1077 for (i
= 0; i
< ABS_MAX
; i
++) {
1078 if (!test_bit(This
->absbits
,i
)) continue;
1082 ddoi
.guidType
= GUID_XAxis
;
1083 ddoi
.dwOfs
= DIJOFS_X
;
1086 ddoi
.guidType
= GUID_YAxis
;
1087 ddoi
.dwOfs
= DIJOFS_Y
;
1090 ddoi
.guidType
= GUID_ZAxis
;
1091 ddoi
.dwOfs
= DIJOFS_Z
;
1094 ddoi
.guidType
= GUID_RxAxis
;
1095 ddoi
.dwOfs
= DIJOFS_RX
;
1098 ddoi
.guidType
= GUID_RyAxis
;
1099 ddoi
.dwOfs
= DIJOFS_RY
;
1102 ddoi
.guidType
= GUID_RzAxis
;
1103 ddoi
.dwOfs
= DIJOFS_RZ
;
1106 ddoi
.guidType
= GUID_Slider
;
1107 ddoi
.dwOfs
= DIJOFS_SLIDER(0);
1110 ddoi
.guidType
= GUID_Slider
;
1111 ddoi
.dwOfs
= DIJOFS_SLIDER(1);
1114 FIXME("unhandled abs axis %d, ignoring!\n",i
);
1116 ddoi
.dwType
= DIDFT_MAKEINSTANCE(i
<< WINE_JOYSTICK_AXIS_BASE
) | DIDFT_ABSAXIS
;
1117 /* Linux event force feedback supports only (and always) x and y axes */
1118 if (i
== ABS_X
|| i
== ABS_Y
) {
1120 ddoi
.dwFlags
|= DIDOI_FFACTUATOR
;
1122 sprintf(ddoi
.tszName
, "%d-Axis", i
);
1123 _dump_OBJECTINSTANCEA(&ddoi
);
1124 if (lpCallback(&ddoi
, lpvRef
) != DIENUM_CONTINUE
) {
1125 /* return to unaquired state if that's where we were */
1127 IDirectInputDevice8_Unacquire(iface
);
1133 if ((dwFlags
== DIDFT_ALL
) ||
1134 (dwFlags
& DIDFT_POV
)) {
1136 ddoi
.guidType
= GUID_POV
;
1137 for (i
=0; i
<4; i
++) {
1138 if (test_bit(This
->absbits
,ABS_HAT0X
+(i
<<1)) && test_bit(This
->absbits
,ABS_HAT0Y
+(i
<<1))) {
1139 ddoi
.dwOfs
= DIJOFS_POV(i
);
1140 ddoi
.dwType
= DIDFT_MAKEINSTANCE(i
<< WINE_JOYSTICK_POV_BASE
) | DIDFT_POV
;
1141 sprintf(ddoi
.tszName
, "%d-POV", i
);
1142 _dump_OBJECTINSTANCEA(&ddoi
);
1143 if (lpCallback(&ddoi
, lpvRef
) != DIENUM_CONTINUE
) {
1144 /* return to unaquired state if that's where we were */
1146 IDirectInputDevice8_Unacquire(iface
);
1153 if ((dwFlags
== DIDFT_ALL
) ||
1154 (dwFlags
& DIDFT_BUTTON
)) {
1157 /*The DInput SDK says that GUID_Button is only for mouse buttons but well*/
1159 ddoi
.guidType
= GUID_Button
;
1161 for (i
= 0; i
< KEY_MAX
; i
++) {
1162 if (!test_bit(This
->keybits
,i
)) continue;
1163 ddoi
.dwOfs
= DIJOFS_BUTTON(btncount
);
1164 ddoi
.dwType
= DIDFT_MAKEINSTANCE(btncount
<< WINE_JOYSTICK_BUTTON_BASE
) | DIDFT_PSHBUTTON
;
1165 sprintf(ddoi
.tszName
, "%d-Button", btncount
);
1167 _dump_OBJECTINSTANCEA(&ddoi
);
1168 if (lpCallback(&ddoi
, lpvRef
) != DIENUM_CONTINUE
) {
1169 /* return to unaquired state if that's where we were */
1171 IDirectInputDevice8_Unacquire(iface
);
1177 /* return to unaquired state if that's where we were */
1179 IDirectInputDevice8_Unacquire(iface
);
1184 static HRESULT WINAPI
JoystickWImpl_EnumObjects(LPDIRECTINPUTDEVICE8W iface
,
1185 LPDIENUMDEVICEOBJECTSCALLBACKW lpCallback
,
1189 JoystickImpl
*This
= (JoystickImpl
*)iface
;
1191 device_enumobjects_AtoWcb_data data
;
1193 data
.lpCallBack
= lpCallback
;
1194 data
.lpvRef
= lpvRef
;
1196 return JoystickAImpl_EnumObjects((LPDIRECTINPUTDEVICE8A
) This
, (LPDIENUMDEVICEOBJECTSCALLBACKA
) DIEnumDevicesCallbackAtoW
, (LPVOID
) &data
, dwFlags
);
1199 /******************************************************************************
1200 * GetProperty : get input device properties
1202 static HRESULT WINAPI
JoystickAImpl_GetProperty(LPDIRECTINPUTDEVICE8A iface
,
1204 LPDIPROPHEADER pdiph
)
1206 JoystickImpl
*This
= (JoystickImpl
*)iface
;
1208 TRACE("(this=%p,%s,%p)\n",
1209 iface
, debugstr_guid(rguid
), pdiph
);
1211 if (TRACE_ON(dinput
))
1212 _dump_DIPROPHEADER(pdiph
);
1214 if (!HIWORD(rguid
)) {
1215 switch (LOWORD(rguid
)) {
1216 case (DWORD
) DIPROP_BUFFERSIZE
: {
1217 LPDIPROPDWORD pd
= (LPDIPROPDWORD
)pdiph
;
1219 TRACE(" return buffersize = %d\n",This
->queue_len
);
1220 pd
->dwData
= This
->queue_len
;
1224 case (DWORD
) DIPROP_RANGE
: {
1225 /* LPDIPROPRANGE pr = (LPDIPROPRANGE) pdiph; */
1226 if ((pdiph
->dwHow
== DIPH_BYID
) &&
1227 (pdiph
->dwObj
& DIDFT_ABSAXIS
)) {
1228 /* The app is querying the current range of the axis : return the lMin and lMax values */
1229 FIXME("unimplemented axis range query.\n");
1236 FIXME("Unknown type %p (%s)\n",rguid
,debugstr_guid(rguid
));
1245 /******************************************************************************
1246 * CreateEffect - Create a new FF effect with the specified params
1248 static HRESULT WINAPI
JoystickAImpl_CreateEffect(LPDIRECTINPUTDEVICE8A iface
,
1251 LPDIRECTINPUTEFFECT
*ppdef
,
1252 LPUNKNOWN pUnkOuter
)
1254 #ifdef HAVE_STRUCT_FF_EFFECT_DIRECTION
1255 EffectListItem
* new = NULL
;
1256 HRESULT retval
= DI_OK
;
1259 JoystickImpl
* This
= (JoystickImpl
*)iface
;
1260 TRACE("(this=%p,%p,%p,%p,%p)\n", This
, rguid
, lpeff
, ppdef
, pUnkOuter
);
1262 #ifndef HAVE_STRUCT_FF_EFFECT_DIRECTION
1263 TRACE("not available (compiled w/o ff support)\n");
1268 new = malloc(sizeof(EffectListItem
));
1269 new->next
= This
->top_effect
;
1270 This
->top_effect
= new;
1272 retval
= linuxinput_create_effect(&(This
->joyfd
), rguid
, &(new->ref
));
1273 if (retval
!= DI_OK
)
1277 retval
= IDirectInputEffect_SetParameters(new->ref
, lpeff
, 0);
1278 if (retval
!= DI_OK
&& retval
!= DI_DOWNLOADSKIPPED
)
1283 if (pUnkOuter
!= NULL
)
1284 FIXME("Interface aggregation not implemented.\n");
1288 #endif /* HAVE_STRUCT_FF_EFFECT_DIRECTION */
1291 /*******************************************************************************
1292 * EnumEffects - Enumerate available FF effects
1294 static HRESULT WINAPI
JoystickAImpl_EnumEffects(LPDIRECTINPUTDEVICE8A iface
,
1295 LPDIENUMEFFECTSCALLBACKA lpCallback
,
1299 #ifdef HAVE_STRUCT_FF_EFFECT_DIRECTION
1300 DIEFFECTINFOA dei
; /* feif */
1301 DWORD type
= DIEFT_GETTYPE(dwEffType
);
1302 JoystickImpl
* This
= (JoystickImpl
*)iface
;
1303 int xfd
= This
->joyfd
;
1305 TRACE("(this=%p,%p,%ld) type=%ld fd=%d\n", This
, pvRef
, dwEffType
, type
, xfd
);
1307 dei
.dwSize
= sizeof(DIEFFECTINFOA
);
1309 /* We need to return something even if we're not yet acquired */
1311 IDirectInputDevice8_Acquire(iface
);
1313 if ((type
== DIEFT_ALL
|| type
== DIEFT_CONSTANTFORCE
)
1314 && test_bit(This
->ffbits
, FF_CONSTANT
)) {
1315 IDirectInputDevice8_GetEffectInfo(iface
, &dei
, &GUID_ConstantForce
);
1316 (*lpCallback
)(&dei
, pvRef
);
1319 if ((type
== DIEFT_ALL
|| type
== DIEFT_PERIODIC
)
1320 && test_bit(This
->ffbits
, FF_PERIODIC
)) {
1321 if (test_bit(This
->ffbits
, FF_SQUARE
)) {
1322 IDirectInputDevice8_GetEffectInfo(iface
, &dei
, &GUID_Square
);
1323 (*lpCallback
)(&dei
, pvRef
);
1325 if (test_bit(This
->ffbits
, FF_SINE
)) {
1326 IDirectInputDevice8_GetEffectInfo(iface
, &dei
, &GUID_Sine
);
1327 (*lpCallback
)(&dei
, pvRef
);
1329 if (test_bit(This
->ffbits
, FF_TRIANGLE
)) {
1330 IDirectInputDevice8_GetEffectInfo(iface
, &dei
, &GUID_Triangle
);
1331 (*lpCallback
)(&dei
, pvRef
);
1333 if (test_bit(This
->ffbits
, FF_SAW_UP
)) {
1334 IDirectInputDevice8_GetEffectInfo(iface
, &dei
, &GUID_SawtoothUp
);
1335 (*lpCallback
)(&dei
, pvRef
);
1337 if (test_bit(This
->ffbits
, FF_SAW_DOWN
)) {
1338 IDirectInputDevice8_GetEffectInfo(iface
, &dei
, &GUID_SawtoothDown
);
1339 (*lpCallback
)(&dei
, pvRef
);
1343 if ((type
== DIEFT_ALL
|| type
== DIEFT_RAMPFORCE
)
1344 && test_bit(This
->ffbits
, FF_RAMP
)) {
1345 IDirectInputDevice8_GetEffectInfo(iface
, &dei
, &GUID_RampForce
);
1346 (*lpCallback
)(&dei
, pvRef
);
1349 if (type
== DIEFT_ALL
|| type
== DIEFT_CONDITION
) {
1350 if (test_bit(This
->ffbits
, FF_SPRING
)) {
1351 IDirectInputDevice8_GetEffectInfo(iface
, &dei
, &GUID_Spring
);
1352 (*lpCallback
)(&dei
, pvRef
);
1354 if (test_bit(This
->ffbits
, FF_DAMPER
)) {
1355 IDirectInputDevice8_GetEffectInfo(iface
, &dei
, &GUID_Damper
);
1356 (*lpCallback
)(&dei
, pvRef
);
1358 if (test_bit(This
->ffbits
, FF_INERTIA
)) {
1359 IDirectInputDevice8_GetEffectInfo(iface
, &dei
, &GUID_Inertia
);
1360 (*lpCallback
)(&dei
, pvRef
);
1362 if (test_bit(This
->ffbits
, FF_FRICTION
)) {
1363 IDirectInputDevice8_GetEffectInfo(iface
, &dei
, &GUID_Friction
);
1364 (*lpCallback
)(&dei
, pvRef
);
1368 /* return to unaquired state if that's where it was */
1370 IDirectInputDevice8_Unacquire(iface
);
1376 static HRESULT WINAPI
JoystickWImpl_EnumEffects(LPDIRECTINPUTDEVICE8W iface
,
1377 LPDIENUMEFFECTSCALLBACKW lpCallback
,
1381 #ifdef HAVE_STRUCT_FF_EFFECT_DIRECTION
1382 /* seems silly to duplicate all this code but all the structures and functions
1383 * are actually different (A/W) */
1384 DIEFFECTINFOW dei
; /* feif */
1385 DWORD type
= DIEFT_GETTYPE(dwEffType
);
1386 JoystickImpl
* This
= (JoystickImpl
*)iface
;
1387 int xfd
= This
->joyfd
;
1389 TRACE("(this=%p,%p,%ld) type=%ld fd=%d\n", This
, pvRef
, dwEffType
, type
, xfd
);
1391 dei
.dwSize
= sizeof(DIEFFECTINFOW
);
1393 /* We need to return something even if we're not yet acquired */
1395 IDirectInputDevice8_Acquire(iface
);
1397 if ((type
== DIEFT_ALL
|| type
== DIEFT_CONSTANTFORCE
)
1398 && test_bit(This
->ffbits
, FF_CONSTANT
)) {
1399 IDirectInputDevice8_GetEffectInfo(iface
, &dei
, &GUID_ConstantForce
);
1400 (*lpCallback
)(&dei
, pvRef
);
1403 if ((type
== DIEFT_ALL
|| type
== DIEFT_PERIODIC
)
1404 && test_bit(This
->ffbits
, FF_PERIODIC
)) {
1405 if (test_bit(This
->ffbits
, FF_SQUARE
)) {
1406 IDirectInputDevice8_GetEffectInfo(iface
, &dei
, &GUID_Square
);
1407 (*lpCallback
)(&dei
, pvRef
);
1409 if (test_bit(This
->ffbits
, FF_SINE
)) {
1410 IDirectInputDevice8_GetEffectInfo(iface
, &dei
, &GUID_Sine
);
1411 (*lpCallback
)(&dei
, pvRef
);
1413 if (test_bit(This
->ffbits
, FF_TRIANGLE
)) {
1414 IDirectInputDevice8_GetEffectInfo(iface
, &dei
, &GUID_Triangle
);
1415 (*lpCallback
)(&dei
, pvRef
);
1417 if (test_bit(This
->ffbits
, FF_SAW_UP
)) {
1418 IDirectInputDevice8_GetEffectInfo(iface
, &dei
, &GUID_SawtoothUp
);
1419 (*lpCallback
)(&dei
, pvRef
);
1421 if (test_bit(This
->ffbits
, FF_SAW_DOWN
)) {
1422 IDirectInputDevice8_GetEffectInfo(iface
, &dei
, &GUID_SawtoothDown
);
1423 (*lpCallback
)(&dei
, pvRef
);
1427 if ((type
== DIEFT_ALL
|| type
== DIEFT_RAMPFORCE
)
1428 && test_bit(This
->ffbits
, FF_RAMP
)) {
1429 IDirectInputDevice8_GetEffectInfo(iface
, &dei
, &GUID_RampForce
);
1430 (*lpCallback
)(&dei
, pvRef
);
1433 if (type
== DIEFT_ALL
|| type
== DIEFT_CONDITION
) {
1434 if (test_bit(This
->ffbits
, FF_SPRING
)) {
1435 IDirectInputDevice8_GetEffectInfo(iface
, &dei
, &GUID_Spring
);
1436 (*lpCallback
)(&dei
, pvRef
);
1438 if (test_bit(This
->ffbits
, FF_DAMPER
)) {
1439 IDirectInputDevice8_GetEffectInfo(iface
, &dei
, &GUID_Damper
);
1440 (*lpCallback
)(&dei
, pvRef
);
1442 if (test_bit(This
->ffbits
, FF_INERTIA
)) {
1443 IDirectInputDevice8_GetEffectInfo(iface
, &dei
, &GUID_Inertia
);
1444 (*lpCallback
)(&dei
, pvRef
);
1446 if (test_bit(This
->ffbits
, FF_FRICTION
)) {
1447 IDirectInputDevice8_GetEffectInfo(iface
, &dei
, &GUID_Friction
);
1448 (*lpCallback
)(&dei
, pvRef
);
1452 /* return to unaquired state if that's where it was */
1454 IDirectInputDevice8_Unacquire(iface
);
1460 /*******************************************************************************
1461 * GetEffectInfo - Get information about a particular effect
1463 static HRESULT WINAPI
JoystickAImpl_GetEffectInfo(LPDIRECTINPUTDEVICE8A iface
,
1464 LPDIEFFECTINFOA pdei
,
1467 JoystickImpl
* This
= (JoystickImpl
*)iface
;
1469 TRACE("(this=%p,%p,%s)\n", This
, pdei
, _dump_dinput_GUID(guid
));
1471 #ifdef HAVE_STRUCT_FF_EFFECT_DIRECTION
1472 return linuxinput_get_info_A(This
->joyfd
, guid
, pdei
);
1478 static HRESULT WINAPI
JoystickWImpl_GetEffectInfo(LPDIRECTINPUTDEVICE8W iface
,
1479 LPDIEFFECTINFOW pdei
,
1482 JoystickImpl
* This
= (JoystickImpl
*)iface
;
1484 TRACE("(this=%p,%p,%s)\n", This
, pdei
, _dump_dinput_GUID(guid
));
1486 #ifdef HAVE_STRUCT_FF_EFFECT_DIRECTION
1487 return linuxinput_get_info_W(This
->joyfd
, guid
, pdei
);
1493 /*******************************************************************************
1494 * GetForceFeedbackState - Get information about the device's FF state
1496 static HRESULT WINAPI
JoystickAImpl_GetForceFeedbackState(
1497 LPDIRECTINPUTDEVICE8A iface
,
1500 JoystickImpl
* This
= (JoystickImpl
*)iface
;
1502 TRACE("(this=%p,%p)\n", This
, pdwOut
);
1506 #ifdef HAVE_STRUCT_FF_EFFECT_DIRECTION
1507 /* DIGFFS_STOPPED is the only mandatory flag to report */
1508 if (This
->ff_state
== FF_STATUS_STOPPED
)
1509 (*pdwOut
) |= DIGFFS_STOPPED
;
1515 /*******************************************************************************
1516 * SendForceFeedbackCommand - Send a command to the device's FF system
1518 static HRESULT WINAPI
JoystickAImpl_SendForceFeedbackCommand(
1519 LPDIRECTINPUTDEVICE8A iface
,
1522 JoystickImpl
* This
= (JoystickImpl
*)iface
;
1523 TRACE("(this=%p,%ld)\n", This
, dwFlags
);
1525 #ifdef HAVE_STRUCT_FF_EFFECT_DIRECTION
1526 if (dwFlags
== DISFFC_STOPALL
) {
1527 /* Stop all effects */
1528 EffectListItem
* itr
= This
->top_effect
;
1530 IDirectInputEffect_Stop(itr
->ref
);
1533 } else if (dwFlags
== DISFFC_RESET
) {
1534 /* Stop, unload, release and free all effects */
1535 /* This returns the device to its "bare" state */
1536 while (This
->top_effect
) {
1537 EffectListItem
* temp
= This
->top_effect
;
1538 IDirectInputEffect_Stop(temp
->ref
);
1539 IDirectInputEffect_Unload(temp
->ref
);
1540 IDirectInputEffect_Release(temp
->ref
);
1541 This
->top_effect
= temp
->next
;
1544 } else if (dwFlags
== DISFFC_PAUSE
|| dwFlags
== DISFFC_CONTINUE
) {
1545 FIXME("No support for Pause or Continue in linux\n");
1546 } else if (dwFlags
== DISFFC_SETACTUATORSOFF
1547 || dwFlags
== DISFFC_SETACTUATORSON
) {
1548 FIXME("No direct actuator control in linux\n");
1550 FIXME("Unknown Force Feedback Command!\n");
1551 return DIERR_INVALIDPARAM
;
1555 return DIERR_UNSUPPORTED
;
1559 /*******************************************************************************
1560 * EnumCreatedEffectObjects - Enumerate all the effects that have been
1561 * created for this device.
1563 static HRESULT WINAPI
JoystickAImpl_EnumCreatedEffectObjects(
1564 LPDIRECTINPUTDEVICE8A iface
,
1565 LPDIENUMCREATEDEFFECTOBJECTSCALLBACK lpCallback
,
1569 /* this function is safe to call on non-ff-enabled builds */
1571 JoystickImpl
* This
= (JoystickImpl
*)iface
;
1572 EffectListItem
* itr
= This
->top_effect
;
1573 TRACE("(this=%p,%p,%p,%ld)\n", This
, lpCallback
, pvRef
, dwFlags
);
1576 return DIERR_INVALIDPARAM
;
1579 FIXME("Flags specified, but no flags exist yet (DX9)!");
1582 (*lpCallback
)(itr
->ref
, pvRef
);
1589 static const IDirectInputDevice8AVtbl JoystickAvt
=
1591 IDirectInputDevice2AImpl_QueryInterface
,
1592 IDirectInputDevice2AImpl_AddRef
,
1593 JoystickAImpl_Release
,
1594 JoystickAImpl_GetCapabilities
,
1595 JoystickAImpl_EnumObjects
,
1596 JoystickAImpl_GetProperty
,
1597 JoystickAImpl_SetProperty
,
1598 JoystickAImpl_Acquire
,
1599 JoystickAImpl_Unacquire
,
1600 JoystickAImpl_GetDeviceState
,
1601 JoystickAImpl_GetDeviceData
,
1602 JoystickAImpl_SetDataFormat
,
1603 JoystickAImpl_SetEventNotification
,
1604 IDirectInputDevice2AImpl_SetCooperativeLevel
,
1605 IDirectInputDevice2AImpl_GetObjectInfo
,
1606 IDirectInputDevice2AImpl_GetDeviceInfo
,
1607 IDirectInputDevice2AImpl_RunControlPanel
,
1608 IDirectInputDevice2AImpl_Initialize
,
1609 JoystickAImpl_CreateEffect
,
1610 JoystickAImpl_EnumEffects
,
1611 JoystickAImpl_GetEffectInfo
,
1612 JoystickAImpl_GetForceFeedbackState
,
1613 JoystickAImpl_SendForceFeedbackCommand
,
1614 JoystickAImpl_EnumCreatedEffectObjects
,
1615 IDirectInputDevice2AImpl_Escape
,
1617 IDirectInputDevice2AImpl_SendDeviceData
,
1618 IDirectInputDevice7AImpl_EnumEffectsInFile
,
1619 IDirectInputDevice7AImpl_WriteEffectToFile
,
1620 IDirectInputDevice8AImpl_BuildActionMap
,
1621 IDirectInputDevice8AImpl_SetActionMap
,
1622 IDirectInputDevice8AImpl_GetImageInfo
1625 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
1626 # define XCAST(fun) (typeof(JoystickWvt.fun))
1628 # define XCAST(fun) (void*)
1631 static const IDirectInputDevice8WVtbl JoystickWvt
=
1633 IDirectInputDevice2WImpl_QueryInterface
,
1634 XCAST(AddRef
)IDirectInputDevice2AImpl_AddRef
,
1635 XCAST(Release
)JoystickAImpl_Release
,
1636 XCAST(GetCapabilities
)JoystickAImpl_GetCapabilities
,
1637 JoystickWImpl_EnumObjects
,
1638 XCAST(GetProperty
)JoystickAImpl_GetProperty
,
1639 XCAST(SetProperty
)JoystickAImpl_SetProperty
,
1640 XCAST(Acquire
)JoystickAImpl_Acquire
,
1641 XCAST(Unacquire
)JoystickAImpl_Unacquire
,
1642 XCAST(GetDeviceState
)JoystickAImpl_GetDeviceState
,
1643 XCAST(GetDeviceData
)JoystickAImpl_GetDeviceData
,
1644 XCAST(SetDataFormat
)JoystickAImpl_SetDataFormat
,
1645 XCAST(SetEventNotification
)JoystickAImpl_SetEventNotification
,
1646 XCAST(SetCooperativeLevel
)IDirectInputDevice2AImpl_SetCooperativeLevel
,
1647 IDirectInputDevice2WImpl_GetObjectInfo
,
1648 IDirectInputDevice2WImpl_GetDeviceInfo
,
1649 XCAST(RunControlPanel
)IDirectInputDevice2AImpl_RunControlPanel
,
1650 XCAST(Initialize
)IDirectInputDevice2AImpl_Initialize
,
1651 XCAST(CreateEffect
)JoystickAImpl_CreateEffect
,
1652 JoystickWImpl_EnumEffects
,
1653 JoystickWImpl_GetEffectInfo
,
1654 XCAST(GetForceFeedbackState
)JoystickAImpl_GetForceFeedbackState
,
1655 XCAST(SendForceFeedbackCommand
)JoystickAImpl_SendForceFeedbackCommand
,
1656 XCAST(EnumCreatedEffectObjects
)JoystickAImpl_EnumCreatedEffectObjects
,
1657 XCAST(Escape
)IDirectInputDevice2AImpl_Escape
,
1658 XCAST(Poll
)JoystickAImpl_Poll
,
1659 XCAST(SendDeviceData
)IDirectInputDevice2AImpl_SendDeviceData
,
1660 IDirectInputDevice7WImpl_EnumEffectsInFile
,
1661 IDirectInputDevice7WImpl_WriteEffectToFile
,
1662 IDirectInputDevice8WImpl_BuildActionMap
,
1663 IDirectInputDevice8WImpl_SetActionMap
,
1664 IDirectInputDevice8WImpl_GetImageInfo
1668 #else /* HAVE_CORRECT_LINUXINPUT_H */
1670 const struct dinput_device joystick_linuxinput_device
= {
1671 "Wine Linux-input joystick driver",
1678 #endif /* HAVE_CORRECT_LINUXINPUT_H */