1 /* DirectInput Joystick device 2 * 3 * Copyright 1998,2000 Marcus Meissner 4 * Copyright 1998,1999 Lionel Ulmer 5 * Copyright 2000-2001 TransGaming Technologies Inc. 6 * Copyright 2005 Daniel Remenak 7 * 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. 12 * 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. 17 * 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 21 */ 22 23 #include "config.h" 24 #include "wine/port.h" 25 26 #include <assert.h> 27 #include <stdarg.h> 28 #include <stdio.h> 29 #include <string.h> 30 #include <time.h> 31 #ifdef HAVE_UNISTD_H 32 # include <unistd.h> 33 #endif 34 #ifdef HAVE_SYS_TIME_H 35 # include <sys/time.h> 36 #endif 37 #include <fcntl.h> 38 #ifdef HAVE_SYS_IOCTL_H 39 # include <sys/ioctl.h> 40 #endif 41 #include <errno.h> 42 #ifdef HAVE_LINUX_INPUT_H 43 # include <linux/input.h> 44 # undef SW_MAX 45 # if defined(EVIOCGBIT) && defined(EV_ABS) && defined(BTN_PINKIE) 46 # define HAS_PROPER_HEADER 47 # endif 48 #endif 49 #ifdef HAVE_SYS_POLL_H 50 # include <sys/poll.h> 51 #endif 52 53 #include "wine/debug.h" 54 #include "wine/unicode.h" 55 #include "wine/list.h" 56 #include "windef.h" 57 #include "winbase.h" 58 #include "winerror.h" 59 #include "winreg.h" 60 #include "dinput.h" 61 62 #include "dinput_private.h" 63 #include "device_private.h" 64 #include "joystick_private.h" 65 66 #ifdef HAS_PROPER_HEADER 67 68 WINE_DEFAULT_DEBUG_CHANNEL(dinput); 69 70 #define EVDEVPREFIX "/dev/input/event" 71 #define EVDEVDRIVER " (event)" 72 73 /* Wine joystick driver object instances */ 74 #define WINE_JOYSTICK_MAX_AXES 8 75 #define WINE_JOYSTICK_MAX_POVS 4 76 #define WINE_JOYSTICK_MAX_BUTTONS 128 77 78 struct wine_input_absinfo { 79 LONG value; 80 LONG minimum; 81 LONG maximum; 82 LONG fuzz; 83 LONG flat; 84 }; 85 86 /* implemented in effect_linuxinput.c */ 87 HRESULT linuxinput_create_effect(int* fd, REFGUID rguid, struct list *parent_list_entry, LPDIRECTINPUTEFFECT* peff); 88 HRESULT linuxinput_get_info_A(int fd, REFGUID rguid, LPDIEFFECTINFOA info); 89 HRESULT linuxinput_get_info_W(int fd, REFGUID rguid, LPDIEFFECTINFOW info); 90 91 static HRESULT WINAPI JoystickWImpl_SendForceFeedbackCommand(LPDIRECTINPUTDEVICE8W iface, DWORD dwFlags); 92 93 typedef struct JoystickImpl JoystickImpl; 94 static const IDirectInputDevice8AVtbl JoystickAvt; 95 static const IDirectInputDevice8WVtbl JoystickWvt; 96 97 struct JoyDev { 98 char *device; 99 char *name; 100 GUID guid; 101 GUID guid_product; 102 103 BOOL has_ff; 104 int num_effects; 105 106 /* data returned by EVIOCGBIT for caps, EV_ABS, EV_KEY, and EV_FF */ 107 BYTE evbits[(EV_MAX+7)/8]; 108 BYTE absbits[(ABS_MAX+7)/8]; 109 BYTE keybits[(KEY_MAX+7)/8]; 110 BYTE ffbits[(FF_MAX+7)/8]; 111 112 /* data returned by the EVIOCGABS() ioctl */ 113 struct wine_input_absinfo axes[ABS_MAX]; 114 115 WORD vendor_id, product_id, bus_type; 116 }; 117 118 struct JoystickImpl 119 { 120 struct JoystickGenericImpl generic; 121 struct JoyDev *joydev; 122 123 /* joystick private */ 124 int joyfd; 125 126 int dev_axes_to_di[ABS_MAX]; 127 POINTL povs[4]; 128 129 /* LUT for KEY_ to offset in rgbButtons */ 130 BYTE buttons[KEY_MAX]; 131 132 /* Force feedback variables */ 133 struct list ff_effects; 134 int ff_state; 135 int ff_autocenter; 136 int ff_gain; 137 }; 138 139 static inline JoystickImpl *impl_from_IDirectInputDevice8A(IDirectInputDevice8A *iface) 140 { 141 return CONTAINING_RECORD(CONTAINING_RECORD(CONTAINING_RECORD(iface, IDirectInputDeviceImpl, IDirectInputDevice8A_iface), 142 JoystickGenericImpl, base), JoystickImpl, generic); 143 } 144 static inline JoystickImpl *impl_from_IDirectInputDevice8W(IDirectInputDevice8W *iface) 145 { 146 return CONTAINING_RECORD(CONTAINING_RECORD(CONTAINING_RECORD(iface, IDirectInputDeviceImpl, IDirectInputDevice8W_iface), 147 JoystickGenericImpl, base), JoystickImpl, generic); 148 } 149 150 static inline IDirectInputDevice8W *IDirectInputDevice8W_from_impl(JoystickImpl *This) 151 { 152 return &This->generic.base.IDirectInputDevice8W_iface; 153 } 154 155 static void fake_current_js_state(JoystickImpl *ji); 156 static void find_joydevs(void); 157 static void joy_polldev(LPDIRECTINPUTDEVICE8A iface); 158 159 /* This GUID is slightly different from the linux joystick one. Take note. */ 160 static const GUID DInput_Wine_Joystick_Base_GUID = { /* 9e573eda-7734-11d2-8d4a-23903fb6bdf7 */ 161 0x9e573eda, 162 0x7734, 163 0x11d2, 164 {0x8d, 0x4a, 0x23, 0x90, 0x3f, 0xb6, 0xbd, 0xf7} 165 }; 166 167 /* 168 * Construct the GUID in the same way of Windows doing this. 169 * Data1 is concatenation of productid and vendorid. 170 * Data2 and Data3 are NULL. 171 * Data4 seems to be a constant. 172 */ 173 static const GUID DInput_Wine_Joystick_Constant_Part_GUID = { 174 0x000000000, 175 0x0000, 176 0x0000, 177 {0x00, 0x00, 0x50, 0x49, 0x44, 0x56, 0x49, 0x44} 178 }; 179 180 #define test_bit(arr,bit) (((BYTE*)(arr))[(bit)>>3]&(1<<((bit)&7))) 181 182 #define MAX_JOYDEV 64 183 184 static int have_joydevs = -1; 185 static struct JoyDev *joydevs = NULL; 186 187 static void find_joydevs(void) 188 { 189 int i; 190 191 if (InterlockedCompareExchange(&have_joydevs, 0, -1) != -1) 192 /* Someone beat us to it */ 193 return; 194 195 for (i = 0; i < MAX_JOYDEV; i++) 196 { 197 char buf[MAX_PATH]; 198 struct JoyDev joydev = {0}; 199 int fd; 200 BOOL no_ff_check = FALSE; 201 int j; 202 struct JoyDev *new_joydevs; 203 struct input_id device_id = {0}; 204 205 snprintf(buf, sizeof(buf), EVDEVPREFIX"%d", i); 206 207 if ((fd = open(buf, O_RDWR)) == -1) 208 { 209 fd = open(buf, O_RDONLY); 210 no_ff_check = TRUE; 211 } 212 213 if (fd == -1) 214 { 215 WARN("Failed to open \"%s\": %d %s\n", buf, errno, strerror(errno)); 216 continue; 217 } 218 219 if (ioctl(fd, EVIOCGBIT(0, sizeof(joydev.evbits)), joydev.evbits) == -1) 220 { 221 WARN("ioctl(EVIOCGBIT, 0) failed: %d %s\n", errno, strerror(errno)); 222 close(fd); 223 continue; 224 } 225 if (ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(joydev.absbits)), joydev.absbits) == -1) 226 { 227 WARN("ioctl(EVIOCGBIT, EV_ABS) failed: %d %s\n", errno, strerror(errno)); 228 close(fd); 229 continue; 230 } 231 if (ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(joydev.keybits)), joydev.keybits) == -1) 232 { 233 WARN("ioctl(EVIOCGBIT, EV_KEY) failed: %d %s\n", errno, strerror(errno)); 234 close(fd); 235 continue; 236 } 237 238 /* A true joystick has at least axis X and Y, and at least 1 239 * button. copied from linux/drivers/input/joydev.c */ 240 if (!test_bit(joydev.absbits, ABS_X) || !test_bit(joydev.absbits, ABS_Y) || 241 !(test_bit(joydev.keybits, BTN_TRIGGER) || 242 test_bit(joydev.keybits, BTN_A) || 243 test_bit(joydev.keybits, BTN_1))) 244 { 245 close(fd); 246 continue; 247 } 248 249 if (!(joydev.device = HeapAlloc(GetProcessHeap(), 0, strlen(buf) + 1))) 250 { 251 close(fd); 252 continue; 253 } 254 strcpy(joydev.device, buf); 255 256 buf[MAX_PATH - 1] = 0; 257 if (ioctl(fd, EVIOCGNAME(MAX_PATH - 1), buf) != -1 && 258 (joydev.name = HeapAlloc(GetProcessHeap(), 0, strlen(buf) + strlen(EVDEVDRIVER) + 1))) 259 { 260 strcpy(joydev.name, buf); 261 /* Append driver name */ 262 strcat(joydev.name, EVDEVDRIVER); 263 } 264 else 265 joydev.name = joydev.device; 266 267 if (device_disabled_registry(joydev.name)) { 268 close(fd); 269 HeapFree(GetProcessHeap(), 0, joydev.name); 270 if (joydev.name != joydev.device) 271 HeapFree(GetProcessHeap(), 0, joydev.device); 272 continue; 273 } 274 275 joydev.guid = DInput_Wine_Joystick_Base_GUID; 276 joydev.guid.Data3 += have_joydevs; 277 278 TRACE("Found a joystick on %s: %s (%s)\n", 279 joydev.device, joydev.name, 280 debugstr_guid(&joydev.guid) 281 ); 282 283 #ifdef HAVE_STRUCT_FF_EFFECT_DIRECTION 284 if (!no_ff_check && 285 test_bit(joydev.evbits, EV_FF) && 286 ioctl(fd, EVIOCGBIT(EV_FF, sizeof(joydev.ffbits)), joydev.ffbits) != -1 && 287 ioctl(fd, EVIOCGEFFECTS, &joydev.num_effects) != -1 && 288 joydev.num_effects > 0) 289 { 290 TRACE(" ... with force feedback\n"); 291 joydev.has_ff = TRUE; 292 } 293 #endif 294 295 for (j = 0; j < ABS_MAX;j ++) 296 { 297 if (!test_bit(joydev.absbits, j)) continue; 298 if (ioctl(fd, EVIOCGABS(j), &(joydev.axes[j])) != -1) 299 { 300 TRACE(" ... with axis %d: cur=%d, min=%d, max=%d, fuzz=%d, flat=%d\n", 301 j, 302 joydev.axes[j].value, 303 joydev.axes[j].minimum, 304 joydev.axes[j].maximum, 305 joydev.axes[j].fuzz, 306 joydev.axes[j].flat 307 ); 308 } 309 } 310 311 if (ioctl(fd, EVIOCGID, &device_id) == -1) 312 { 313 WARN("ioctl(EVIOCGID) failed: %d %s\n", errno, strerror(errno)); 314 joydev.guid_product = DInput_Wine_Joystick_Base_GUID; 315 } 316 else 317 { 318 joydev.vendor_id = device_id.vendor; 319 joydev.product_id = device_id.product; 320 joydev.bus_type = device_id.bustype; 321 322 /* Concatenate product_id with vendor_id to mimic Windows behaviour */ 323 joydev.guid_product = DInput_Wine_Joystick_Constant_Part_GUID; 324 joydev.guid_product.Data1 = MAKELONG(joydev.vendor_id, joydev.product_id); 325 } 326 327 if (!have_joydevs) 328 new_joydevs = HeapAlloc(GetProcessHeap(), 0, sizeof(struct JoyDev)); 329 else 330 new_joydevs = HeapReAlloc(GetProcessHeap(), 0, joydevs, (1 + have_joydevs) * sizeof(struct JoyDev)); 331 332 if (!new_joydevs) 333 { 334 close(fd); 335 continue; 336 } 337 joydevs = new_joydevs; 338 joydevs[have_joydevs] = joydev; 339 have_joydevs++; 340 341 close(fd); 342 } 343 } 344 345 static void fill_joystick_dideviceinstanceW(LPDIDEVICEINSTANCEW lpddi, DWORD version, int id) 346 { 347 DWORD dwSize = lpddi->dwSize; 348 349 TRACE("%d %p\n", dwSize, lpddi); 350 memset(lpddi, 0, dwSize); 351 352 lpddi->dwSize = dwSize; 353 lpddi->guidInstance = joydevs[id].guid; 354 lpddi->guidProduct = joydevs[id].guid_product; 355 lpddi->guidFFDriver = GUID_NULL; 356 357 if (version >= 0x0800) 358 lpddi->dwDevType = DI8DEVTYPE_JOYSTICK | (DI8DEVTYPEJOYSTICK_STANDARD << 8); 359 else 360 lpddi->dwDevType = DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_TRADITIONAL << 8); 361 362 /* Assume the joystick as HID if it is attached to USB bus and has a valid VID/PID */ 363 if (joydevs[id].bus_type == BUS_USB && 364 joydevs[id].vendor_id && joydevs[id].product_id) 365 { 366 lpddi->dwDevType |= DIDEVTYPE_HID; 367 lpddi->wUsagePage = 0x01; /* Desktop */ 368 if (lpddi->dwDevType == DI8DEVTYPE_JOYSTICK || lpddi->dwDevType == DIDEVTYPE_JOYSTICK) 369 lpddi->wUsage = 0x04; /* Joystick */ 370 else 371 lpddi->wUsage = 0x05; /* Game Pad */ 372 } 373 374 MultiByteToWideChar(CP_ACP, 0, joydevs[id].name, -1, lpddi->tszInstanceName, MAX_PATH); 375 MultiByteToWideChar(CP_ACP, 0, joydevs[id].name, -1, lpddi->tszProductName, MAX_PATH); 376 } 377 378 static void fill_joystick_dideviceinstanceA(LPDIDEVICEINSTANCEA lpddi, DWORD version, int id) 379 { 380 DIDEVICEINSTANCEW lpddiW; 381 DWORD dwSize = lpddi->dwSize; 382 383 lpddiW.dwSize = sizeof(lpddiW); 384 fill_joystick_dideviceinstanceW(&lpddiW, version, id); 385 386 TRACE("%d %p\n", dwSize, lpddi); 387 memset(lpddi, 0, dwSize); 388 389 /* Convert W->A */ 390 lpddi->dwSize = dwSize; 391 lpddi->guidInstance = lpddiW.guidInstance; 392 lpddi->guidProduct = lpddiW.guidProduct; 393 lpddi->dwDevType = lpddiW.dwDevType; 394 strcpy(lpddi->tszInstanceName, joydevs[id].name); 395 strcpy(lpddi->tszProductName, joydevs[id].name); 396 lpddi->guidFFDriver = lpddiW.guidFFDriver; 397 lpddi->wUsagePage = lpddiW.wUsagePage; 398 lpddi->wUsage = lpddiW.wUsage; 399 } 400 401 static HRESULT joydev_enum_deviceA(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEA lpddi, DWORD version, int id) 402 { 403 find_joydevs(); 404 405 if (id >= have_joydevs) { 406 return E_FAIL; 407 } 408 409 if (!((dwDevType == 0) || 410 ((dwDevType == DIDEVTYPE_JOYSTICK) && (version > 0x0300 && version < 0x0800)) || 411 (((dwDevType == DI8DEVCLASS_GAMECTRL) || (dwDevType == DI8DEVTYPE_JOYSTICK)) && (version >= 0x0800)))) 412 return S_FALSE; 413 414 #ifndef HAVE_STRUCT_FF_EFFECT_DIRECTION 415 if (dwFlags & DIEDFL_FORCEFEEDBACK) 416 return S_FALSE; 417 #endif 418 419 if (!(dwFlags & DIEDFL_FORCEFEEDBACK) || joydevs[id].has_ff) { 420 fill_joystick_dideviceinstanceA(lpddi, version, id); 421 return S_OK; 422 } 423 return S_FALSE; 424 } 425 426 static HRESULT joydev_enum_deviceW(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEW lpddi, DWORD version, int id) 427 { 428 find_joydevs(); 429 430 if (id >= have_joydevs) { 431 return E_FAIL; 432 } 433 434 if (!((dwDevType == 0) || 435 ((dwDevType == DIDEVTYPE_JOYSTICK) && (version > 0x0300 && version < 0x0800)) || 436 (((dwDevType == DI8DEVCLASS_GAMECTRL) || (dwDevType == DI8DEVTYPE_JOYSTICK)) && (version >= 0x0800)))) 437 return S_FALSE; 438 439 #ifndef HAVE_STRUCT_FF_EFFECT_DIRECTION 440 if (dwFlags & DIEDFL_FORCEFEEDBACK) 441 return S_FALSE; 442 #endif 443 444 if (!(dwFlags & DIEDFL_FORCEFEEDBACK) || joydevs[id].has_ff) { 445 fill_joystick_dideviceinstanceW(lpddi, version, id); 446 return S_OK; 447 } 448 return S_FALSE; 449 } 450 451 static JoystickImpl *alloc_device(REFGUID rguid, IDirectInputImpl *dinput, unsigned short index) 452 { 453 JoystickImpl* newDevice; 454 LPDIDATAFORMAT df = NULL; 455 int i, idx = 0; 456 int default_axis_map[WINE_JOYSTICK_MAX_AXES + WINE_JOYSTICK_MAX_POVS*2]; 457 DIDEVICEINSTANCEW ddi; 458 459 newDevice = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(JoystickImpl)); 460 if (!newDevice) return NULL; 461 462 newDevice->generic.base.IDirectInputDevice8A_iface.lpVtbl = &JoystickAvt; 463 newDevice->generic.base.IDirectInputDevice8W_iface.lpVtbl = &JoystickWvt; 464 newDevice->generic.base.ref = 1; 465 newDevice->generic.base.guid = *rguid; 466 newDevice->generic.base.dinput = dinput; 467 newDevice->generic.joy_polldev = joy_polldev; 468 newDevice->joyfd = -1; 469 newDevice->joydev = &joydevs[index]; 470 newDevice->generic.name = newDevice->joydev->name; 471 list_init(&newDevice->ff_effects); 472 #ifdef HAVE_STRUCT_FF_EFFECT_DIRECTION 473 newDevice->ff_state = FF_STATUS_STOPPED; 474 #endif 475 /* There is no way in linux to query force feedback autocenter status. 476 Instead, track it with ff_autocenter, and assume it's initially 477 enabled. */ 478 newDevice->ff_autocenter = 1; 479 newDevice->ff_gain = 0xFFFF; 480 InitializeCriticalSection(&newDevice->generic.base.crit); 481 newDevice->generic.base.crit.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": JoystickImpl*->base.crit"); 482 483 /* Count number of available axes - supported Axis & POVs */ 484 for (i = 0; i < ABS_MAX; i++) 485 { 486 if (i < WINE_JOYSTICK_MAX_AXES && 487 test_bit(newDevice->joydev->absbits, i)) 488 { 489 newDevice->generic.device_axis_count++; 490 newDevice->dev_axes_to_di[i] = idx; 491 newDevice->generic.props[idx].lDevMin = newDevice->joydev->axes[i].minimum; 492 newDevice->generic.props[idx].lDevMax = newDevice->joydev->axes[i].maximum; 493 default_axis_map[idx] = i; 494 idx++; 495 } 496 else 497 newDevice->dev_axes_to_di[i] = -1; 498 } 499 500 for (i = 0; i < WINE_JOYSTICK_MAX_POVS; i++) 501 { 502 if (test_bit(newDevice->joydev->absbits, ABS_HAT0X + i * 2) && 503 test_bit(newDevice->joydev->absbits, ABS_HAT0Y + i * 2)) 504 { 505 newDevice->generic.device_axis_count += 2; 506 newDevice->generic.props[idx ].lDevMin = newDevice->joydev->axes[ABS_HAT0X + i * 2].minimum; 507 newDevice->generic.props[idx ].lDevMax = newDevice->joydev->axes[ABS_HAT0X + i * 2].maximum; 508 newDevice->dev_axes_to_di[ABS_HAT0X + i * 2] = idx; 509 newDevice->generic.props[idx+1].lDevMin = newDevice->joydev->axes[ABS_HAT0Y + i * 2].minimum; 510 newDevice->generic.props[idx+1].lDevMax = newDevice->joydev->axes[ABS_HAT0Y + i * 2].maximum; 511 newDevice->dev_axes_to_di[ABS_HAT0Y + i * 2] = idx + 1; 512 513 default_axis_map[idx] = default_axis_map[idx + 1] = WINE_JOYSTICK_MAX_AXES + i; 514 idx += 2; 515 } 516 else 517 newDevice->dev_axes_to_di[ABS_HAT0X + i * 2] = newDevice->dev_axes_to_di[ABS_HAT0Y + i * 2] = -1; 518 } 519 520 /* do any user specified configuration */ 521 if (setup_dinput_options(&newDevice->generic, default_axis_map) != DI_OK) goto failed; 522 523 /* Create copy of default data format */ 524 if (!(df = HeapAlloc(GetProcessHeap(), 0, c_dfDIJoystick2.dwSize))) goto failed; 525 memcpy(df, &c_dfDIJoystick2, c_dfDIJoystick2.dwSize); 526 if (!(df->rgodf = HeapAlloc(GetProcessHeap(), 0, df->dwNumObjs * df->dwObjSize))) goto failed; 527 528 529 /* Construct internal data format */ 530 531 /* Supported Axis & POVs */ 532 for (i = 0, idx = 0; i < newDevice->generic.device_axis_count; i++) 533 { 534 int wine_obj = newDevice->generic.axis_map[i]; 535 536 if (wine_obj < 0) continue; 537 538 memcpy(&df->rgodf[idx], &c_dfDIJoystick2.rgodf[wine_obj], df->dwObjSize); 539 if (wine_obj < 8) 540 df->rgodf[idx].dwType = DIDFT_MAKEINSTANCE(wine_obj) | DIDFT_ABSAXIS; 541 else 542 { 543 df->rgodf[idx].dwType = DIDFT_MAKEINSTANCE(wine_obj - 8) | DIDFT_POV; 544 i++; /* POV takes 2 axes */ 545 } 546 547 newDevice->generic.props[idx].lMin = 0; 548 newDevice->generic.props[idx].lMax = 0xffff; 549 newDevice->generic.props[idx].lSaturation = 0; 550 newDevice->generic.props[idx].lDeadZone = newDevice->generic.deadzone; 551 552 /* Linux supports force-feedback on X & Y axes only */ 553 if (newDevice->joydev->has_ff && (i == 0 || i == 1)) 554 df->rgodf[idx].dwFlags |= DIDOI_FFACTUATOR; 555 556 idx++; 557 } 558 559 /* Buttons can be anywhere, so check all */ 560 for (i = 0; i < KEY_MAX && newDevice->generic.devcaps.dwButtons < WINE_JOYSTICK_MAX_BUTTONS; i++) 561 { 562 if (!test_bit(newDevice->joydev->keybits, i)) continue; 563 564 memcpy(&df->rgodf[idx], &c_dfDIJoystick2.rgodf[newDevice->generic.devcaps.dwButtons + 12], df->dwObjSize); 565 newDevice->buttons[i] = 0x80 | newDevice->generic.devcaps.dwButtons; 566 df->rgodf[idx ].pguid = &GUID_Button; 567 df->rgodf[idx++].dwType = DIDFT_MAKEINSTANCE(newDevice->generic.devcaps.dwButtons++) | DIDFT_PSHBUTTON; 568 } 569 df->dwNumObjs = idx; 570 newDevice->generic.base.data_format.wine_df = df; 571 572 fake_current_js_state(newDevice); 573 574 /* Fill the caps */ 575 newDevice->generic.devcaps.dwSize = sizeof(newDevice->generic.devcaps); 576 newDevice->generic.devcaps.dwFlags = DIDC_ATTACHED; 577 578 ddi.dwSize = sizeof(ddi); 579 fill_joystick_dideviceinstanceW(&ddi, newDevice->generic.base.dinput->dwVersion, index); 580 newDevice->generic.devcaps.dwDevType = ddi.dwDevType; 581 582 if (newDevice->joydev->has_ff) 583 newDevice->generic.devcaps.dwFlags |= DIDC_FORCEFEEDBACK; 584 585 IDirectInput_AddRef(&newDevice->generic.base.dinput->IDirectInput7A_iface); 586 587 EnterCriticalSection(&dinput->crit); 588 list_add_tail(&dinput->devices_list, &newDevice->generic.base.entry); 589 LeaveCriticalSection(&dinput->crit); 590 591 return newDevice; 592 593 failed: 594 if (df) HeapFree(GetProcessHeap(), 0, df->rgodf); 595 HeapFree(GetProcessHeap(), 0, df); 596 HeapFree(GetProcessHeap(), 0, newDevice->generic.axis_map); 597 HeapFree(GetProcessHeap(), 0, newDevice); 598 return NULL; 599 } 600 601 /****************************************************************************** 602 * get_joystick_index : Get the joystick index from a given GUID 603 */ 604 static unsigned short get_joystick_index(REFGUID guid) 605 { 606 GUID wine_joystick = DInput_Wine_Joystick_Base_GUID; 607 GUID dev_guid = *guid; 608 609 wine_joystick.Data3 = 0; 610 dev_guid.Data3 = 0; 611 612 /* for the standard joystick GUID use index 0 */ 613 if(IsEqualGUID(&GUID_Joystick,guid)) return 0; 614 615 /* for the wine joystick GUIDs use the index stored in Data3 */ 616 if(IsEqualGUID(&wine_joystick, &dev_guid)) return guid->Data3 - DInput_Wine_Joystick_Base_GUID.Data3; 617 618 return MAX_JOYDEV; 619 } 620 621 static HRESULT joydev_create_device(IDirectInputImpl *dinput, REFGUID rguid, REFIID riid, LPVOID *pdev, int unicode) 622 { 623 unsigned short index; 624 625 TRACE("%p %s %s %p %i\n", dinput, debugstr_guid(rguid), debugstr_guid(riid), pdev, unicode); 626 find_joydevs(); 627 *pdev = NULL; 628 629 if ((index = get_joystick_index(rguid)) < MAX_JOYDEV && 630 have_joydevs && index < have_joydevs) 631 { 632 JoystickImpl *This; 633 634 if (riid == NULL) 635 ;/* nothing */ 636 else if (IsEqualGUID(&IID_IDirectInputDeviceA, riid) || 637 IsEqualGUID(&IID_IDirectInputDevice2A, riid) || 638 IsEqualGUID(&IID_IDirectInputDevice7A, riid) || 639 IsEqualGUID(&IID_IDirectInputDevice8A, riid)) 640 { 641 unicode = 0; 642 } 643 else if (IsEqualGUID(&IID_IDirectInputDeviceW, riid) || 644 IsEqualGUID(&IID_IDirectInputDevice2W, riid) || 645 IsEqualGUID(&IID_IDirectInputDevice7W, riid) || 646 IsEqualGUID(&IID_IDirectInputDevice8W, riid)) 647 { 648 unicode = 1; 649 } 650 else 651 { 652 WARN("no interface\n"); 653 return DIERR_NOINTERFACE; 654 } 655 656 This = alloc_device(rguid, dinput, index); 657 TRACE("Created a Joystick device (%p)\n", This); 658 659 if (!This) return DIERR_OUTOFMEMORY; 660 661 if (unicode) 662 *pdev = &This->generic.base.IDirectInputDevice8W_iface; 663 else 664 *pdev = &This->generic.base.IDirectInputDevice8A_iface; 665 666 return DI_OK; 667 } 668 669 return DIERR_DEVICENOTREG; 670 } 671 672 673 const struct dinput_device joystick_linuxinput_device = { 674 "Wine Linux-input joystick driver", 675 joydev_enum_deviceA, 676 joydev_enum_deviceW, 677 joydev_create_device 678 }; 679 680 /****************************************************************************** 681 * Acquire : gets exclusive control of the joystick 682 */ 683 static HRESULT WINAPI JoystickWImpl_Acquire(LPDIRECTINPUTDEVICE8W iface) 684 { 685 JoystickImpl *This = impl_from_IDirectInputDevice8W(iface); 686 HRESULT res; 687 688 TRACE("(this=%p)\n",This); 689 690 if ((res = IDirectInputDevice2WImpl_Acquire(iface)) != DI_OK) 691 { 692 WARN("Failed to acquire: %x\n", res); 693 return res; 694 } 695 696 if ((This->joyfd = open(This->joydev->device, O_RDWR)) == -1) 697 { 698 if ((This->joyfd = open(This->joydev->device, O_RDONLY)) == -1) 699 { 700 /* Couldn't open the device at all */ 701 ERR("Failed to open device %s: %d %s\n", This->joydev->device, errno, strerror(errno)); 702 IDirectInputDevice2WImpl_Unacquire(iface); 703 return DIERR_NOTFOUND; 704 } 705 else 706 { 707 /* Couldn't open in r/w but opened in read-only. */ 708 WARN("Could not open %s in read-write mode. Force feedback will be disabled.\n", This->joydev->device); 709 } 710 } 711 else 712 { 713 struct input_event event; 714 715 event.type = EV_FF; 716 event.code = FF_GAIN; 717 event.value = This->ff_gain; 718 if (write(This->joyfd, &event, sizeof(event)) == -1) 719 ERR("Failed to set gain (%i): %d %s\n", This->ff_gain, errno, strerror(errno)); 720 if (!This->ff_autocenter) 721 { 722 /* Disable autocenter. */ 723 event.code = FF_AUTOCENTER; 724 event.value = 0; 725 if (write(This->joyfd, &event, sizeof(event)) == -1) 726 ERR("Failed disabling autocenter: %d %s\n", errno, strerror(errno)); 727 } 728 } 729 730 return DI_OK; 731 } 732 733 static HRESULT WINAPI JoystickAImpl_Acquire(LPDIRECTINPUTDEVICE8A iface) 734 { 735 JoystickImpl *This = impl_from_IDirectInputDevice8A(iface); 736 return JoystickWImpl_Acquire(IDirectInputDevice8W_from_impl(This)); 737 } 738 739 /****************************************************************************** 740 * Unacquire : frees the joystick 741 */ 742 static HRESULT WINAPI JoystickWImpl_Unacquire(LPDIRECTINPUTDEVICE8W iface) 743 { 744 JoystickImpl *This = impl_from_IDirectInputDevice8W(iface); 745 HRESULT res; 746 747 TRACE("(this=%p)\n",This); 748 res = IDirectInputDevice2WImpl_Unacquire(iface); 749 if (res==DI_OK && This->joyfd!=-1) { 750 struct input_event event; 751 752 /* Stop and unload all effects */ 753 JoystickWImpl_SendForceFeedbackCommand(iface, DISFFC_RESET); 754 755 /* Enable autocenter. */ 756 event.type = EV_FF; 757 event.code = FF_AUTOCENTER; 758 /* TODO: Read autocenter strength before disabling it, and use it here 759 * instead of 0xFFFF (maximum strength). 760 */ 761 event.value = 0xFFFF; 762 if (write(This->joyfd, &event, sizeof(event)) == -1) 763 ERR("Failed to set autocenter to %04x: %d %s\n", event.value, errno, strerror(errno)); 764 765 close(This->joyfd); 766 This->joyfd = -1; 767 } 768 return res; 769 } 770 771 static HRESULT WINAPI JoystickAImpl_Unacquire(LPDIRECTINPUTDEVICE8A iface) 772 { 773 JoystickImpl *This = impl_from_IDirectInputDevice8A(iface); 774 return JoystickWImpl_Unacquire(IDirectInputDevice8W_from_impl(This)); 775 } 776 777 /* 778 * set the current state of the js device as it would be with the middle 779 * values on the axes 780 */ 781 #define CENTER_AXIS(a) \ 782 (ji->dev_axes_to_di[a] == -1 ? 0 : joystick_map_axis( &ji->generic.props[ji->dev_axes_to_di[a]], \ 783 ji->joydev->axes[a].value )) 784 static void fake_current_js_state(JoystickImpl *ji) 785 { 786 int i; 787 788 /* center the axes */ 789 ji->generic.js.lX = CENTER_AXIS(ABS_X); 790 ji->generic.js.lY = CENTER_AXIS(ABS_Y); 791 ji->generic.js.lZ = CENTER_AXIS(ABS_Z); 792 ji->generic.js.lRx = CENTER_AXIS(ABS_RX); 793 ji->generic.js.lRy = CENTER_AXIS(ABS_RY); 794 ji->generic.js.lRz = CENTER_AXIS(ABS_RZ); 795 ji->generic.js.rglSlider[0] = CENTER_AXIS(ABS_THROTTLE); 796 ji->generic.js.rglSlider[1] = CENTER_AXIS(ABS_RUDDER); 797 798 /* POV center is -1 */ 799 for (i = 0; i < 4; i++) 800 ji->generic.js.rgdwPOV[i] = -1; 801 } 802 #undef CENTER_AXIS 803 804 /* convert wine format offset to user format object index */ 805 static void joy_polldev(LPDIRECTINPUTDEVICE8A iface) 806 { 807 struct pollfd plfd; 808 struct input_event ie; 809 JoystickImpl *This = impl_from_IDirectInputDevice8A(iface); 810 811 if (This->joyfd==-1) 812 return; 813 814 while (1) 815 { 816 LONG value = 0; 817 int inst_id = -1; 818 819 plfd.fd = This->joyfd; 820 plfd.events = POLLIN; 821 822 if (poll(&plfd,1,0) != 1) 823 return; 824 825 /* we have one event, so we can read */ 826 if (sizeof(ie)!=read(This->joyfd,&ie,sizeof(ie))) 827 return; 828 829 TRACE("input_event: type %d, code %d, value %d\n",ie.type,ie.code,ie.value); 830 switch (ie.type) { 831 case EV_KEY: /* button */ 832 { 833 int btn = This->buttons[ie.code]; 834 835 TRACE("(%p) %d -> %d\n", This, ie.code, btn); 836 if (btn & 0x80) 837 { 838 btn &= 0x7F; 839 inst_id = DIDFT_MAKEINSTANCE(btn) | DIDFT_PSHBUTTON; 840 This->generic.js.rgbButtons[btn] = value = ie.value ? 0x80 : 0x00; 841 } 842 break; 843 } 844 case EV_ABS: 845 { 846 int axis = This->dev_axes_to_di[ie.code]; 847 848 /* User axis remapping */ 849 if (axis < 0) break; 850 axis = This->generic.axis_map[axis]; 851 if (axis < 0) break; 852 853 inst_id = axis < 8 ? DIDFT_MAKEINSTANCE(axis) | DIDFT_ABSAXIS : 854 DIDFT_MAKEINSTANCE(axis - 8) | DIDFT_POV; 855 value = joystick_map_axis(&This->generic.props[id_to_object(This->generic.base.data_format.wine_df, inst_id)], ie.value); 856 857 switch (axis) { 858 case 0: This->generic.js.lX = value; break; 859 case 1: This->generic.js.lY = value; break; 860 case 2: This->generic.js.lZ = value; break; 861 case 3: This->generic.js.lRx = value; break; 862 case 4: This->generic.js.lRy = value; break; 863 case 5: This->generic.js.lRz = value; break; 864 case 6: This->generic.js.rglSlider[0] = value; break; 865 case 7: This->generic.js.rglSlider[1] = value; break; 866 case 8: case 9: case 10: case 11: 867 { 868 int idx = axis - 8; 869 870 if (ie.code % 2) 871 This->povs[idx].y = ie.value; 872 else 873 This->povs[idx].x = ie.value; 874 875 This->generic.js.rgdwPOV[idx] = value = joystick_map_pov(&This->povs[idx]); 876 break; 877 } 878 default: 879 FIXME("unhandled joystick axis event (code %d, value %d)\n",ie.code,ie.value); 880 } 881 break; 882 } 883 #ifdef HAVE_STRUCT_FF_EFFECT_DIRECTION 884 case EV_FF_STATUS: 885 This->ff_state = ie.value; 886 break; 887 #endif 888 #ifdef EV_SYN 889 case EV_SYN: 890 /* there is nothing to do */ 891 break; 892 #endif 893 #ifdef EV_MSC 894 case EV_MSC: 895 /* Ignore */ 896 break; 897 #endif 898 default: 899 TRACE("skipping event\n"); 900 break; 901 } 902 if (inst_id >= 0) 903 queue_event(iface, inst_id, 904 value, GetCurrentTime(), This->generic.base.dinput->evsequence++); 905 } 906 } 907 908 /****************************************************************************** 909 * SetProperty : change input device properties 910 */ 911 static HRESULT WINAPI JoystickWImpl_SetProperty(LPDIRECTINPUTDEVICE8W iface, REFGUID rguid, LPCDIPROPHEADER ph) 912 { 913 JoystickImpl *This = impl_from_IDirectInputDevice8W(iface); 914 915 if (!ph) { 916 WARN("invalid argument\n"); 917 return DIERR_INVALIDPARAM; 918 } 919 920 TRACE("(this=%p,%s,%p)\n",This,debugstr_guid(rguid),ph); 921 TRACE("ph.dwSize = %d, ph.dwHeaderSize =%d, ph.dwObj = %d, ph.dwHow= %d\n", 922 ph->dwSize, ph->dwHeaderSize, ph->dwObj, ph->dwHow); 923 924 if (IS_DIPROP(rguid)) { 925 switch (LOWORD(rguid)) { 926 case (DWORD_PTR)DIPROP_CALIBRATIONMODE: { 927 LPCDIPROPDWORD pd = (LPCDIPROPDWORD)ph; 928 FIXME("DIPROP_CALIBRATIONMODE(%d)\n", pd->dwData); 929 break; 930 } 931 case (DWORD_PTR)DIPROP_AUTOCENTER: { 932 LPCDIPROPDWORD pd = (LPCDIPROPDWORD)ph; 933 934 TRACE("autocenter(%d)\n", pd->dwData); 935 This->ff_autocenter = pd->dwData == DIPROPAUTOCENTER_ON; 936 937 break; 938 } 939 case (DWORD_PTR)DIPROP_FFGAIN: { 940 LPCDIPROPDWORD pd = (LPCDIPROPDWORD)ph; 941 942 TRACE("DIPROP_FFGAIN(%d)\n", pd->dwData); 943 This->ff_gain = MulDiv(pd->dwData, 0xFFFF, 10000); 944 if (This->generic.base.acquired) { 945 /* Update immediately. */ 946 struct input_event event; 947 948 event.type = EV_FF; 949 event.code = FF_GAIN; 950 event.value = This->ff_gain; 951 if (write(This->joyfd, &event, sizeof(event)) == -1) 952 ERR("Failed to set gain (%i): %d %s\n", This->ff_gain, errno, strerror(errno)); 953 } 954 break; 955 } 956 default: 957 return JoystickWGenericImpl_SetProperty(iface, rguid, ph); 958 } 959 } 960 return DI_OK; 961 } 962 963 static HRESULT WINAPI JoystickAImpl_SetProperty(LPDIRECTINPUTDEVICE8A iface, REFGUID rguid, LPCDIPROPHEADER ph) 964 { 965 JoystickImpl *This = impl_from_IDirectInputDevice8A(iface); 966 return JoystickWImpl_SetProperty(IDirectInputDevice8W_from_impl(This), rguid, ph); 967 } 968 969 /****************************************************************************** 970 * GetProperty : get input device properties 971 */ 972 static HRESULT WINAPI JoystickWImpl_GetProperty(LPDIRECTINPUTDEVICE8W iface, REFGUID rguid, LPDIPROPHEADER pdiph) 973 { 974 JoystickImpl *This = impl_from_IDirectInputDevice8W(iface); 975 976 TRACE("(this=%p,%s,%p)\n", iface, debugstr_guid(rguid), pdiph); 977 _dump_DIPROPHEADER(pdiph); 978 979 if (!IS_DIPROP(rguid)) return DI_OK; 980 981 switch (LOWORD(rguid)) { 982 case (DWORD_PTR) DIPROP_AUTOCENTER: 983 { 984 LPDIPROPDWORD pd = (LPDIPROPDWORD)pdiph; 985 986 pd->dwData = This->ff_autocenter ? DIPROPAUTOCENTER_ON : DIPROPAUTOCENTER_OFF; 987 TRACE("autocenter(%d)\n", pd->dwData); 988 break; 989 } 990 case (DWORD_PTR) DIPROP_FFGAIN: 991 { 992 LPDIPROPDWORD pd = (LPDIPROPDWORD)pdiph; 993 994 pd->dwData = MulDiv(This->ff_gain, 10000, 0xFFFF); 995 TRACE("DIPROP_FFGAIN(%d)\n", pd->dwData); 996 break; 997 } 998 999 case (DWORD_PTR) DIPROP_VIDPID: 1000 { 1001 LPDIPROPDWORD pd = (LPDIPROPDWORD)pdiph; 1002 1003 if (!This->joydev->product_id || !This->joydev->vendor_id) 1004 return DIERR_UNSUPPORTED; 1005 pd->dwData = MAKELONG(This->joydev->vendor_id, This->joydev->product_id); 1006 TRACE("DIPROP_VIDPID(%08x)\n", pd->dwData); 1007 break; 1008 } 1009 1010 case (DWORD_PTR) DIPROP_JOYSTICKID: 1011 { 1012 LPDIPROPDWORD pd = (LPDIPROPDWORD)pdiph; 1013 1014 pd->dwData = get_joystick_index(&This->generic.base.guid); 1015 TRACE("DIPROP_JOYSTICKID(%d)\n", pd->dwData); 1016 break; 1017 } 1018 1019 default: 1020 return JoystickWGenericImpl_GetProperty(iface, rguid, pdiph); 1021 } 1022 1023 return DI_OK; 1024 } 1025 1026 static HRESULT WINAPI JoystickAImpl_GetProperty(LPDIRECTINPUTDEVICE8A iface, REFGUID rguid, LPDIPROPHEADER pdiph) 1027 { 1028 JoystickImpl *This = impl_from_IDirectInputDevice8A(iface); 1029 return JoystickWImpl_GetProperty(IDirectInputDevice8W_from_impl(This), rguid, pdiph); 1030 } 1031 1032 /****************************************************************************** 1033 * CreateEffect - Create a new FF effect with the specified params 1034 */ 1035 static HRESULT WINAPI JoystickWImpl_CreateEffect(LPDIRECTINPUTDEVICE8W iface, REFGUID rguid, 1036 LPCDIEFFECT lpeff, LPDIRECTINPUTEFFECT *ppdef, 1037 LPUNKNOWN pUnkOuter) 1038 { 1039 #ifdef HAVE_STRUCT_FF_EFFECT_DIRECTION 1040 effect_list_item* new_effect = NULL; 1041 HRESULT retval = DI_OK; 1042 #endif 1043 1044 JoystickImpl* This = impl_from_IDirectInputDevice8W(iface); 1045 TRACE("(this=%p,%p,%p,%p,%p)\n", This, rguid, lpeff, ppdef, pUnkOuter); 1046 1047 *ppdef = NULL; 1048 if (!This->joydev->has_ff) 1049 { 1050 TRACE("No force feedback support\n"); 1051 return DIERR_UNSUPPORTED; 1052 } 1053 1054 #ifndef HAVE_STRUCT_FF_EFFECT_DIRECTION 1055 TRACE("not available (compiled w/o force feedback support)\n"); 1056 return DIERR_UNSUPPORTED; 1057 #else 1058 1059 if (!(new_effect = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_effect)))) 1060 return DIERR_OUTOFMEMORY; 1061 1062 retval = linuxinput_create_effect(&This->joyfd, rguid, &new_effect->entry, &new_effect->ref); 1063 if (retval != DI_OK) 1064 { 1065 HeapFree(GetProcessHeap(), 0, new_effect); 1066 return retval; 1067 } 1068 1069 if (lpeff != NULL) 1070 { 1071 retval = IDirectInputEffect_SetParameters(new_effect->ref, lpeff, 0); 1072 1073 if (retval != DI_OK && retval != DI_DOWNLOADSKIPPED) 1074 { 1075 HeapFree(GetProcessHeap(), 0, new_effect); 1076 return retval; 1077 } 1078 } 1079 1080 list_add_tail(&This->ff_effects, &new_effect->entry); 1081 *ppdef = new_effect->ref; 1082 1083 if (pUnkOuter != NULL) 1084 FIXME("Interface aggregation not implemented.\n"); 1085 1086 return DI_OK; 1087 1088 #endif /* HAVE_STRUCT_FF_EFFECT_DIRECTION */ 1089 } 1090 1091 static HRESULT WINAPI JoystickAImpl_CreateEffect(LPDIRECTINPUTDEVICE8A iface, REFGUID rguid, 1092 LPCDIEFFECT lpeff, LPDIRECTINPUTEFFECT *ppdef, 1093 LPUNKNOWN pUnkOuter) 1094 { 1095 JoystickImpl *This = impl_from_IDirectInputDevice8A(iface); 1096 return JoystickWImpl_CreateEffect(IDirectInputDevice8W_from_impl(This), rguid, lpeff, ppdef, pUnkOuter); 1097 } 1098 1099 /******************************************************************************* 1100 * EnumEffects - Enumerate available FF effects 1101 */ 1102 static HRESULT WINAPI JoystickAImpl_EnumEffects(LPDIRECTINPUTDEVICE8A iface, 1103 LPDIENUMEFFECTSCALLBACKA lpCallback, 1104 LPVOID pvRef, 1105 DWORD dwEffType) 1106 { 1107 #ifdef HAVE_STRUCT_FF_EFFECT_DIRECTION 1108 DIEFFECTINFOA dei; /* feif */ 1109 DWORD type = DIEFT_GETTYPE(dwEffType); 1110 JoystickImpl* This = impl_from_IDirectInputDevice8A(iface); 1111 1112 TRACE("(this=%p,%p,%d) type=%d\n", This, pvRef, dwEffType, type); 1113 1114 dei.dwSize = sizeof(DIEFFECTINFOA); 1115 1116 if ((type == DIEFT_ALL || type == DIEFT_CONSTANTFORCE) 1117 && test_bit(This->joydev->ffbits, FF_CONSTANT)) { 1118 IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_ConstantForce); 1119 (*lpCallback)(&dei, pvRef); 1120 } 1121 1122 if ((type == DIEFT_ALL || type == DIEFT_PERIODIC) 1123 && test_bit(This->joydev->ffbits, FF_PERIODIC)) { 1124 if (test_bit(This->joydev->ffbits, FF_SQUARE)) { 1125 IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Square); 1126 (*lpCallback)(&dei, pvRef); 1127 } 1128 if (test_bit(This->joydev->ffbits, FF_SINE)) { 1129 IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Sine); 1130 (*lpCallback)(&dei, pvRef); 1131 } 1132 if (test_bit(This->joydev->ffbits, FF_TRIANGLE)) { 1133 IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Triangle); 1134 (*lpCallback)(&dei, pvRef); 1135 } 1136 if (test_bit(This->joydev->ffbits, FF_SAW_UP)) { 1137 IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_SawtoothUp); 1138 (*lpCallback)(&dei, pvRef); 1139 } 1140 if (test_bit(This->joydev->ffbits, FF_SAW_DOWN)) { 1141 IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_SawtoothDown); 1142 (*lpCallback)(&dei, pvRef); 1143 } 1144 } 1145 1146 if ((type == DIEFT_ALL || type == DIEFT_RAMPFORCE) 1147 && test_bit(This->joydev->ffbits, FF_RAMP)) { 1148 IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_RampForce); 1149 (*lpCallback)(&dei, pvRef); 1150 } 1151 1152 if (type == DIEFT_ALL || type == DIEFT_CONDITION) { 1153 if (test_bit(This->joydev->ffbits, FF_SPRING)) { 1154 IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Spring); 1155 (*lpCallback)(&dei, pvRef); 1156 } 1157 if (test_bit(This->joydev->ffbits, FF_DAMPER)) { 1158 IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Damper); 1159 (*lpCallback)(&dei, pvRef); 1160 } 1161 if (test_bit(This->joydev->ffbits, FF_INERTIA)) { 1162 IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Inertia); 1163 (*lpCallback)(&dei, pvRef); 1164 } 1165 if (test_bit(This->joydev->ffbits, FF_FRICTION)) { 1166 IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Friction); 1167 (*lpCallback)(&dei, pvRef); 1168 } 1169 } 1170 1171 #endif 1172 1173 return DI_OK; 1174 } 1175 1176 static HRESULT WINAPI JoystickWImpl_EnumEffects(LPDIRECTINPUTDEVICE8W iface, 1177 LPDIENUMEFFECTSCALLBACKW lpCallback, 1178 LPVOID pvRef, 1179 DWORD dwEffType) 1180 { 1181 #ifdef HAVE_STRUCT_FF_EFFECT_DIRECTION 1182 /* seems silly to duplicate all this code but all the structures and functions 1183 * are actually different (A/W) */ 1184 DIEFFECTINFOW dei; /* feif */ 1185 DWORD type = DIEFT_GETTYPE(dwEffType); 1186 JoystickImpl* This = impl_from_IDirectInputDevice8W(iface); 1187 int xfd = This->joyfd; 1188 1189 TRACE("(this=%p,%p,%d) type=%d fd=%d\n", This, pvRef, dwEffType, type, xfd); 1190 1191 dei.dwSize = sizeof(DIEFFECTINFOW); 1192 1193 if ((type == DIEFT_ALL || type == DIEFT_CONSTANTFORCE) 1194 && test_bit(This->joydev->ffbits, FF_CONSTANT)) { 1195 IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_ConstantForce); 1196 (*lpCallback)(&dei, pvRef); 1197 } 1198 1199 if ((type == DIEFT_ALL || type == DIEFT_PERIODIC) 1200 && test_bit(This->joydev->ffbits, FF_PERIODIC)) { 1201 if (test_bit(This->joydev->ffbits, FF_SQUARE)) { 1202 IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Square); 1203 (*lpCallback)(&dei, pvRef); 1204 } 1205 if (test_bit(This->joydev->ffbits, FF_SINE)) { 1206 IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Sine); 1207 (*lpCallback)(&dei, pvRef); 1208 } 1209 if (test_bit(This->joydev->ffbits, FF_TRIANGLE)) { 1210 IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Triangle); 1211 (*lpCallback)(&dei, pvRef); 1212 } 1213 if (test_bit(This->joydev->ffbits, FF_SAW_UP)) { 1214 IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_SawtoothUp); 1215 (*lpCallback)(&dei, pvRef); 1216 } 1217 if (test_bit(This->joydev->ffbits, FF_SAW_DOWN)) { 1218 IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_SawtoothDown); 1219 (*lpCallback)(&dei, pvRef); 1220 } 1221 } 1222 1223 if ((type == DIEFT_ALL || type == DIEFT_RAMPFORCE) 1224 && test_bit(This->joydev->ffbits, FF_RAMP)) { 1225 IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_RampForce); 1226 (*lpCallback)(&dei, pvRef); 1227 } 1228 1229 if (type == DIEFT_ALL || type == DIEFT_CONDITION) { 1230 if (test_bit(This->joydev->ffbits, FF_SPRING)) { 1231 IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Spring); 1232 (*lpCallback)(&dei, pvRef); 1233 } 1234 if (test_bit(This->joydev->ffbits, FF_DAMPER)) { 1235 IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Damper); 1236 (*lpCallback)(&dei, pvRef); 1237 } 1238 if (test_bit(This->joydev->ffbits, FF_INERTIA)) { 1239 IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Inertia); 1240 (*lpCallback)(&dei, pvRef); 1241 } 1242 if (test_bit(This->joydev->ffbits, FF_FRICTION)) { 1243 IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Friction); 1244 (*lpCallback)(&dei, pvRef); 1245 } 1246 } 1247 1248 /* return to unacquired state if that's where it was */ 1249 if (xfd == -1) 1250 IDirectInputDevice8_Unacquire(iface); 1251 #endif 1252 1253 return DI_OK; 1254 } 1255 1256 /******************************************************************************* 1257 * GetEffectInfo - Get information about a particular effect 1258 */ 1259 static HRESULT WINAPI JoystickAImpl_GetEffectInfo(LPDIRECTINPUTDEVICE8A iface, 1260 LPDIEFFECTINFOA pdei, 1261 REFGUID guid) 1262 { 1263 JoystickImpl* This = impl_from_IDirectInputDevice8A(iface); 1264 1265 TRACE("(this=%p,%p,%s)\n", This, pdei, _dump_dinput_GUID(guid)); 1266 1267 #ifdef HAVE_STRUCT_FF_EFFECT_DIRECTION 1268 return linuxinput_get_info_A(This->joyfd, guid, pdei); 1269 #else 1270 return DI_OK; 1271 #endif 1272 } 1273 1274 static HRESULT WINAPI JoystickWImpl_GetEffectInfo(LPDIRECTINPUTDEVICE8W iface, 1275 LPDIEFFECTINFOW pdei, 1276 REFGUID guid) 1277 { 1278 JoystickImpl* This = impl_from_IDirectInputDevice8W(iface); 1279 1280 TRACE("(this=%p,%p,%s)\n", This, pdei, _dump_dinput_GUID(guid)); 1281 1282 #ifdef HAVE_STRUCT_FF_EFFECT_DIRECTION 1283 return linuxinput_get_info_W(This->joyfd, guid, pdei); 1284 #else 1285 return DI_OK; 1286 #endif 1287 } 1288 1289 /******************************************************************************* 1290 * GetForceFeedbackState - Get information about the device's FF state 1291 */ 1292 static HRESULT WINAPI JoystickWImpl_GetForceFeedbackState(LPDIRECTINPUTDEVICE8W iface, LPDWORD pdwOut) 1293 { 1294 JoystickImpl* This = impl_from_IDirectInputDevice8W(iface); 1295 1296 TRACE("(this=%p,%p)\n", This, pdwOut); 1297 1298 (*pdwOut) = 0; 1299 1300 #ifdef HAVE_STRUCT_FF_EFFECT_DIRECTION 1301 /* DIGFFS_STOPPED is the only mandatory flag to report */ 1302 if (This->ff_state == FF_STATUS_STOPPED) 1303 (*pdwOut) |= DIGFFS_STOPPED; 1304 #endif 1305 1306 return DI_OK; 1307 } 1308 1309 static HRESULT WINAPI JoystickAImpl_GetForceFeedbackState(LPDIRECTINPUTDEVICE8A iface, LPDWORD pdwOut) 1310 { 1311 JoystickImpl *This = impl_from_IDirectInputDevice8A(iface); 1312 return JoystickWImpl_GetForceFeedbackState(IDirectInputDevice8W_from_impl(This), pdwOut); 1313 } 1314 1315 /******************************************************************************* 1316 * SendForceFeedbackCommand - Send a command to the device's FF system 1317 */ 1318 static HRESULT WINAPI JoystickWImpl_SendForceFeedbackCommand(LPDIRECTINPUTDEVICE8W iface, DWORD dwFlags) 1319 { 1320 JoystickImpl* This = impl_from_IDirectInputDevice8W(iface); 1321 TRACE("(this=%p,%d)\n", This, dwFlags); 1322 1323 #ifdef HAVE_STRUCT_FF_EFFECT_DIRECTION 1324 switch (dwFlags) 1325 { 1326 case DISFFC_STOPALL: 1327 { 1328 effect_list_item *itr; 1329 1330 /* Stop all effects */ 1331 LIST_FOR_EACH_ENTRY(itr, &This->ff_effects, effect_list_item, entry) 1332 IDirectInputEffect_Stop(itr->ref); 1333 break; 1334 } 1335 1336 case DISFFC_RESET: 1337 { 1338 effect_list_item *itr; 1339 1340 /* Stop and unload all effects. It is not true that effects are released */ 1341 LIST_FOR_EACH_ENTRY(itr, &This->ff_effects, effect_list_item, entry) 1342 { 1343 IDirectInputEffect_Stop(itr->ref); 1344 IDirectInputEffect_Unload(itr->ref); 1345 } 1346 break; 1347 } 1348 case DISFFC_PAUSE: 1349 case DISFFC_CONTINUE: 1350 FIXME("No support for Pause or Continue in linux\n"); 1351 break; 1352 1353 case DISFFC_SETACTUATORSOFF: 1354 case DISFFC_SETACTUATORSON: 1355 FIXME("No direct actuator control in linux\n"); 1356 break; 1357 1358 default: 1359 WARN("Unknown Force Feedback Command %u!\n", dwFlags); 1360 return DIERR_INVALIDPARAM; 1361 } 1362 return DI_OK; 1363 #else 1364 return DIERR_UNSUPPORTED; 1365 #endif 1366 } 1367 1368 static HRESULT WINAPI JoystickAImpl_SendForceFeedbackCommand(LPDIRECTINPUTDEVICE8A iface, DWORD dwFlags) 1369 { 1370 JoystickImpl *This = impl_from_IDirectInputDevice8A(iface); 1371 return JoystickWImpl_SendForceFeedbackCommand(IDirectInputDevice8W_from_impl(This), dwFlags); 1372 } 1373 1374 /******************************************************************************* 1375 * EnumCreatedEffectObjects - Enumerate all the effects that have been 1376 * created for this device. 1377 */ 1378 static HRESULT WINAPI JoystickWImpl_EnumCreatedEffectObjects(LPDIRECTINPUTDEVICE8W iface, 1379 LPDIENUMCREATEDEFFECTOBJECTSCALLBACK lpCallback, 1380 LPVOID pvRef, DWORD dwFlags) 1381 { 1382 /* this function is safe to call on non-ff-enabled builds */ 1383 JoystickImpl* This = impl_from_IDirectInputDevice8W(iface); 1384 effect_list_item *itr, *ptr; 1385 1386 TRACE("(this=%p,%p,%p,%d)\n", This, lpCallback, pvRef, dwFlags); 1387 1388 if (!lpCallback) 1389 return DIERR_INVALIDPARAM; 1390 1391 if (dwFlags != 0) 1392 FIXME("Flags specified, but no flags exist yet (DX9)!\n"); 1393 1394 LIST_FOR_EACH_ENTRY_SAFE(itr, ptr, &This->ff_effects, effect_list_item, entry) 1395 (*lpCallback)(itr->ref, pvRef); 1396 1397 return DI_OK; 1398 } 1399 1400 static HRESULT WINAPI JoystickAImpl_EnumCreatedEffectObjects(LPDIRECTINPUTDEVICE8A iface, 1401 LPDIENUMCREATEDEFFECTOBJECTSCALLBACK lpCallback, 1402 LPVOID pvRef, DWORD dwFlags) 1403 { 1404 JoystickImpl *This = impl_from_IDirectInputDevice8A(iface); 1405 return JoystickWImpl_EnumCreatedEffectObjects(IDirectInputDevice8W_from_impl(This), lpCallback, pvRef, dwFlags); 1406 } 1407 1408 /****************************************************************************** 1409 * GetDeviceInfo : get information about a device's identity 1410 */ 1411 static HRESULT WINAPI JoystickAImpl_GetDeviceInfo(LPDIRECTINPUTDEVICE8A iface, 1412 LPDIDEVICEINSTANCEA pdidi) 1413 { 1414 JoystickImpl *This = impl_from_IDirectInputDevice8A(iface); 1415 1416 TRACE("(%p) %p\n", This, pdidi); 1417 1418 if (pdidi == NULL) return E_POINTER; 1419 if ((pdidi->dwSize != sizeof(DIDEVICEINSTANCE_DX3A)) && 1420 (pdidi->dwSize != sizeof(DIDEVICEINSTANCEA))) 1421 return DIERR_INVALIDPARAM; 1422 1423 fill_joystick_dideviceinstanceA(pdidi, This->generic.base.dinput->dwVersion, 1424 get_joystick_index(&This->generic.base.guid)); 1425 return DI_OK; 1426 } 1427 1428 static HRESULT WINAPI JoystickWImpl_GetDeviceInfo(LPDIRECTINPUTDEVICE8W iface, 1429 LPDIDEVICEINSTANCEW pdidi) 1430 { 1431 JoystickImpl *This = impl_from_IDirectInputDevice8W(iface); 1432 1433 TRACE("(%p) %p\n", This, pdidi); 1434 1435 if (pdidi == NULL) return E_POINTER; 1436 if ((pdidi->dwSize != sizeof(DIDEVICEINSTANCE_DX3W)) && 1437 (pdidi->dwSize != sizeof(DIDEVICEINSTANCEW))) 1438 return DIERR_INVALIDPARAM; 1439 1440 fill_joystick_dideviceinstanceW(pdidi, This->generic.base.dinput->dwVersion, 1441 get_joystick_index(&This->generic.base.guid)); 1442 return DI_OK; 1443 } 1444 1445 static const IDirectInputDevice8AVtbl JoystickAvt = 1446 { 1447 IDirectInputDevice2AImpl_QueryInterface, 1448 IDirectInputDevice2AImpl_AddRef, 1449 IDirectInputDevice2AImpl_Release, 1450 JoystickAGenericImpl_GetCapabilities, 1451 IDirectInputDevice2AImpl_EnumObjects, 1452 JoystickAImpl_GetProperty, 1453 JoystickAImpl_SetProperty, 1454 JoystickAImpl_Acquire, 1455 JoystickAImpl_Unacquire, 1456 JoystickAGenericImpl_GetDeviceState, 1457 IDirectInputDevice2AImpl_GetDeviceData, 1458 IDirectInputDevice2AImpl_SetDataFormat, 1459 IDirectInputDevice2AImpl_SetEventNotification, 1460 IDirectInputDevice2AImpl_SetCooperativeLevel, 1461 JoystickAGenericImpl_GetObjectInfo, 1462 JoystickAImpl_GetDeviceInfo, 1463 IDirectInputDevice2AImpl_RunControlPanel, 1464 IDirectInputDevice2AImpl_Initialize, 1465 JoystickAImpl_CreateEffect, 1466 JoystickAImpl_EnumEffects, 1467 JoystickAImpl_GetEffectInfo, 1468 JoystickAImpl_GetForceFeedbackState, 1469 JoystickAImpl_SendForceFeedbackCommand, 1470 JoystickAImpl_EnumCreatedEffectObjects, 1471 IDirectInputDevice2AImpl_Escape, 1472 JoystickAGenericImpl_Poll, 1473 IDirectInputDevice2AImpl_SendDeviceData, 1474 IDirectInputDevice7AImpl_EnumEffectsInFile, 1475 IDirectInputDevice7AImpl_WriteEffectToFile, 1476 JoystickAGenericImpl_BuildActionMap, 1477 JoystickAGenericImpl_SetActionMap, 1478 IDirectInputDevice8AImpl_GetImageInfo 1479 }; 1480 1481 static const IDirectInputDevice8WVtbl JoystickWvt = 1482 { 1483 IDirectInputDevice2WImpl_QueryInterface, 1484 IDirectInputDevice2WImpl_AddRef, 1485 IDirectInputDevice2WImpl_Release, 1486 JoystickWGenericImpl_GetCapabilities, 1487 IDirectInputDevice2WImpl_EnumObjects, 1488 JoystickWImpl_GetProperty, 1489 JoystickWImpl_SetProperty, 1490 JoystickWImpl_Acquire, 1491 JoystickWImpl_Unacquire, 1492 JoystickWGenericImpl_GetDeviceState, 1493 IDirectInputDevice2WImpl_GetDeviceData, 1494 IDirectInputDevice2WImpl_SetDataFormat, 1495 IDirectInputDevice2WImpl_SetEventNotification, 1496 IDirectInputDevice2WImpl_SetCooperativeLevel, 1497 JoystickWGenericImpl_GetObjectInfo, 1498 JoystickWImpl_GetDeviceInfo, 1499 IDirectInputDevice2WImpl_RunControlPanel, 1500 IDirectInputDevice2WImpl_Initialize, 1501 JoystickWImpl_CreateEffect, 1502 JoystickWImpl_EnumEffects, 1503 JoystickWImpl_GetEffectInfo, 1504 JoystickWImpl_GetForceFeedbackState, 1505 JoystickWImpl_SendForceFeedbackCommand, 1506 JoystickWImpl_EnumCreatedEffectObjects, 1507 IDirectInputDevice2WImpl_Escape, 1508 JoystickWGenericImpl_Poll, 1509 IDirectInputDevice2WImpl_SendDeviceData, 1510 IDirectInputDevice7WImpl_EnumEffectsInFile, 1511 IDirectInputDevice7WImpl_WriteEffectToFile, 1512 JoystickWGenericImpl_BuildActionMap, 1513 JoystickWGenericImpl_SetActionMap, 1514 IDirectInputDevice8WImpl_GetImageInfo 1515 }; 1516 1517 #else /* HAS_PROPER_HEADER */ 1518 1519 const struct dinput_device joystick_linuxinput_device = { 1520 "Wine Linux-input joystick driver", 1521 NULL, 1522 NULL, 1523 NULL 1524 }; 1525 1526 #endif /* HAS_PROPER_HEADER */ 1527