1 /* DirectInput Mouse device 2 * 3 * Copyright 1998 Marcus Meissner 4 * Copyright 1998,1999 Lionel Ulmer 5 * Copyright 2000-2001 TransGaming Technologies Inc. 6 * 7 * This library is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU Lesser General Public 9 * License as published by the Free Software Foundation; either 10 * version 2.1 of the License, or (at your option) any later version. 11 * 12 * This library is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * Lesser General Public License for more details. 16 * 17 * You should have received a copy of the GNU Lesser General Public 18 * License along with this library; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 20 */ 21 22 #include "config.h" 23 #include "wine/port.h" 24 25 #include <stdarg.h> 26 #include <string.h> 27 28 #include "windef.h" 29 #include "winbase.h" 30 #include "wingdi.h" 31 #include "winuser.h" 32 #include "winerror.h" 33 #include "winreg.h" 34 #include "dinput.h" 35 36 #include "dinput_private.h" 37 #include "device_private.h" 38 #include "wine/debug.h" 39 #include "wine/unicode.h" 40 41 WINE_DEFAULT_DEBUG_CHANNEL(dinput); 42 43 /* Wine mouse driver object instances */ 44 #define WINE_MOUSE_X_AXIS_INSTANCE 0 45 #define WINE_MOUSE_Y_AXIS_INSTANCE 1 46 #define WINE_MOUSE_Z_AXIS_INSTANCE 2 47 #define WINE_MOUSE_BUTTONS_INSTANCE 3 48 49 static const IDirectInputDevice8AVtbl SysMouseAvt; 50 static const IDirectInputDevice8WVtbl SysMouseWvt; 51 52 typedef struct SysMouseImpl SysMouseImpl; 53 54 typedef enum 55 { 56 WARP_DEFAULT, 57 WARP_DISABLE, 58 WARP_FORCE_ON 59 } WARP_MOUSE; 60 61 struct SysMouseImpl 62 { 63 struct IDirectInputDeviceImpl base; 64 65 /* SysMouseAImpl */ 66 /* These are used in case of relative -> absolute transitions */ 67 POINT org_coords; 68 BOOL clipped; 69 /* warping: whether we need to move mouse back to middle once we 70 * reach window borders (for e.g. shooters, "surface movement" games) */ 71 BOOL need_warp; 72 DWORD last_warped; 73 74 /* This is for mouse reporting. */ 75 DIMOUSESTATE2 m_state; 76 77 WARP_MOUSE warp_override; 78 }; 79 80 static inline SysMouseImpl *impl_from_IDirectInputDevice8A(IDirectInputDevice8A *iface) 81 { 82 return CONTAINING_RECORD(CONTAINING_RECORD(iface, IDirectInputDeviceImpl, IDirectInputDevice8A_iface), SysMouseImpl, base); 83 } 84 static inline SysMouseImpl *impl_from_IDirectInputDevice8W(IDirectInputDevice8W *iface) 85 { 86 return CONTAINING_RECORD(CONTAINING_RECORD(iface, IDirectInputDeviceImpl, IDirectInputDevice8W_iface), SysMouseImpl, base); 87 } 88 89 static inline IDirectInputDevice8W *IDirectInputDevice8W_from_impl(SysMouseImpl *This) 90 { 91 return &This->base.IDirectInputDevice8W_iface; 92 } 93 94 static int dinput_mouse_hook( LPDIRECTINPUTDEVICE8A iface, WPARAM wparam, LPARAM lparam ); 95 96 const GUID DInput_Wine_Mouse_GUID = { /* 9e573ed8-7734-11d2-8d4a-23903fb6bdf7 */ 97 0x9e573ed8, 0x7734, 0x11d2, {0x8d, 0x4a, 0x23, 0x90, 0x3f, 0xb6, 0xbd, 0xf7} 98 }; 99 100 static void _dump_mouse_state(const DIMOUSESTATE2 *m_state) 101 { 102 int i; 103 104 if (!TRACE_ON(dinput)) return; 105 106 TRACE("(X: %d Y: %d Z: %d", m_state->lX, m_state->lY, m_state->lZ); 107 for (i = 0; i < 5; i++) TRACE(" B%d: %02x", i, m_state->rgbButtons[i]); 108 TRACE(")\n"); 109 } 110 111 static void fill_mouse_dideviceinstanceA(LPDIDEVICEINSTANCEA lpddi, DWORD version) { 112 DWORD dwSize; 113 DIDEVICEINSTANCEA ddi; 114 115 dwSize = lpddi->dwSize; 116 117 TRACE("%d %p\n", dwSize, lpddi); 118 119 memset(lpddi, 0, dwSize); 120 memset(&ddi, 0, sizeof(ddi)); 121 122 ddi.dwSize = dwSize; 123 ddi.guidInstance = GUID_SysMouse;/* DInput's GUID */ 124 ddi.guidProduct = DInput_Wine_Mouse_GUID; /* Vendor's GUID */ 125 if (version >= 0x0800) 126 ddi.dwDevType = DI8DEVTYPE_MOUSE | (DI8DEVTYPEMOUSE_TRADITIONAL << 8); 127 else 128 ddi.dwDevType = DIDEVTYPE_MOUSE | (DIDEVTYPEMOUSE_TRADITIONAL << 8); 129 strcpy(ddi.tszInstanceName, "Mouse"); 130 strcpy(ddi.tszProductName, "Wine Mouse"); 131 132 memcpy(lpddi, &ddi, (dwSize < sizeof(ddi) ? dwSize : sizeof(ddi))); 133 } 134 135 static void fill_mouse_dideviceinstanceW(LPDIDEVICEINSTANCEW lpddi, DWORD version) { 136 DWORD dwSize; 137 DIDEVICEINSTANCEW ddi; 138 139 dwSize = lpddi->dwSize; 140 141 TRACE("%d %p\n", dwSize, lpddi); 142 143 memset(lpddi, 0, dwSize); 144 memset(&ddi, 0, sizeof(ddi)); 145 146 ddi.dwSize = dwSize; 147 ddi.guidInstance = GUID_SysMouse;/* DInput's GUID */ 148 ddi.guidProduct = DInput_Wine_Mouse_GUID; /* Vendor's GUID */ 149 if (version >= 0x0800) 150 ddi.dwDevType = DI8DEVTYPE_MOUSE | (DI8DEVTYPEMOUSE_TRADITIONAL << 8); 151 else 152 ddi.dwDevType = DIDEVTYPE_MOUSE | (DIDEVTYPEMOUSE_TRADITIONAL << 8); 153 MultiByteToWideChar(CP_ACP, 0, "Mouse", -1, ddi.tszInstanceName, MAX_PATH); 154 MultiByteToWideChar(CP_ACP, 0, "Wine Mouse", -1, ddi.tszProductName, MAX_PATH); 155 156 memcpy(lpddi, &ddi, (dwSize < sizeof(ddi) ? dwSize : sizeof(ddi))); 157 } 158 159 static HRESULT mousedev_enum_deviceA(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEA lpddi, DWORD version, int id) 160 { 161 if (id != 0) 162 return E_FAIL; 163 164 if ((dwDevType == 0) || 165 ((dwDevType == DIDEVTYPE_MOUSE) && (version < 0x0800)) || 166 (((dwDevType == DI8DEVCLASS_POINTER) || (dwDevType == DI8DEVTYPE_MOUSE)) && (version >= 0x0800))) { 167 TRACE("Enumerating the mouse device\n"); 168 169 fill_mouse_dideviceinstanceA(lpddi, version); 170 171 return S_OK; 172 } 173 174 return S_FALSE; 175 } 176 177 static HRESULT mousedev_enum_deviceW(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEW lpddi, DWORD version, int id) 178 { 179 if (id != 0) 180 return E_FAIL; 181 182 if ((dwDevType == 0) || 183 ((dwDevType == DIDEVTYPE_MOUSE) && (version < 0x0800)) || 184 (((dwDevType == DI8DEVCLASS_POINTER) || (dwDevType == DI8DEVTYPE_MOUSE)) && (version >= 0x0800))) { 185 TRACE("Enumerating the mouse device\n"); 186 187 fill_mouse_dideviceinstanceW(lpddi, version); 188 189 return S_OK; 190 } 191 192 return S_FALSE; 193 } 194 195 static SysMouseImpl *alloc_device(REFGUID rguid, IDirectInputImpl *dinput) 196 { 197 SysMouseImpl* newDevice; 198 LPDIDATAFORMAT df = NULL; 199 unsigned i; 200 char buffer[20]; 201 HKEY hkey, appkey; 202 203 newDevice = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(SysMouseImpl)); 204 if (!newDevice) return NULL; 205 newDevice->base.IDirectInputDevice8A_iface.lpVtbl = &SysMouseAvt; 206 newDevice->base.IDirectInputDevice8W_iface.lpVtbl = &SysMouseWvt; 207 newDevice->base.ref = 1; 208 newDevice->base.dwCoopLevel = DISCL_NONEXCLUSIVE | DISCL_BACKGROUND; 209 newDevice->base.guid = *rguid; 210 InitializeCriticalSection(&newDevice->base.crit); 211 newDevice->base.crit.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": SysMouseImpl*->base.crit"); 212 newDevice->base.dinput = dinput; 213 newDevice->base.event_proc = dinput_mouse_hook; 214 215 get_app_key(&hkey, &appkey); 216 if (!get_config_key(hkey, appkey, "MouseWarpOverride", buffer, sizeof(buffer))) 217 { 218 if (!strcasecmp(buffer, "disable")) 219 newDevice->warp_override = WARP_DISABLE; 220 else if (!strcasecmp(buffer, "force")) 221 newDevice->warp_override = WARP_FORCE_ON; 222 } 223 if (appkey) RegCloseKey(appkey); 224 if (hkey) RegCloseKey(hkey); 225 226 /* Create copy of default data format */ 227 if (!(df = HeapAlloc(GetProcessHeap(), 0, c_dfDIMouse2.dwSize))) goto failed; 228 memcpy(df, &c_dfDIMouse2, c_dfDIMouse2.dwSize); 229 if (!(df->rgodf = HeapAlloc(GetProcessHeap(), 0, df->dwNumObjs * df->dwObjSize))) goto failed; 230 memcpy(df->rgodf, c_dfDIMouse2.rgodf, df->dwNumObjs * df->dwObjSize); 231 232 /* Because we don't do any detection yet just modify instance and type */ 233 for (i = 0; i < df->dwNumObjs; i++) 234 if (DIDFT_GETTYPE(df->rgodf[i].dwType) & DIDFT_AXIS) 235 df->rgodf[i].dwType = DIDFT_MAKEINSTANCE(i) | DIDFT_RELAXIS; 236 else 237 df->rgodf[i].dwType = DIDFT_MAKEINSTANCE(i) | DIDFT_PSHBUTTON; 238 239 newDevice->base.data_format.wine_df = df; 240 IDirectInput_AddRef(&newDevice->base.dinput->IDirectInput7A_iface); 241 242 EnterCriticalSection(&dinput->crit); 243 list_add_tail(&dinput->devices_list, &newDevice->base.entry); 244 LeaveCriticalSection(&dinput->crit); 245 246 return newDevice; 247 248 failed: 249 if (df) HeapFree(GetProcessHeap(), 0, df->rgodf); 250 HeapFree(GetProcessHeap(), 0, df); 251 HeapFree(GetProcessHeap(), 0, newDevice); 252 return NULL; 253 } 254 255 static HRESULT mousedev_create_device(IDirectInputImpl *dinput, REFGUID rguid, REFIID riid, LPVOID *pdev, int unicode) 256 { 257 TRACE("%p %s %s %p %i\n", dinput, debugstr_guid(rguid), debugstr_guid(riid), pdev, unicode); 258 *pdev = NULL; 259 260 if (IsEqualGUID(&GUID_SysMouse, rguid) || /* Generic Mouse */ 261 IsEqualGUID(&DInput_Wine_Mouse_GUID, rguid)) /* Wine Mouse */ 262 { 263 SysMouseImpl *This; 264 265 if (riid == NULL) 266 ;/* nothing */ 267 else if (IsEqualGUID(&IID_IDirectInputDeviceA, riid) || 268 IsEqualGUID(&IID_IDirectInputDevice2A, riid) || 269 IsEqualGUID(&IID_IDirectInputDevice7A, riid) || 270 IsEqualGUID(&IID_IDirectInputDevice8A, riid)) 271 { 272 unicode = 0; 273 } 274 else if (IsEqualGUID(&IID_IDirectInputDeviceW, riid) || 275 IsEqualGUID(&IID_IDirectInputDevice2W, riid) || 276 IsEqualGUID(&IID_IDirectInputDevice7W, riid) || 277 IsEqualGUID(&IID_IDirectInputDevice8W, riid)) 278 { 279 unicode = 1; 280 } 281 else 282 { 283 WARN("no interface\n"); 284 return DIERR_NOINTERFACE; 285 } 286 287 This = alloc_device(rguid, dinput); 288 TRACE("Created a Mouse device (%p)\n", This); 289 290 if (!This) return DIERR_OUTOFMEMORY; 291 292 if (unicode) 293 *pdev = &This->base.IDirectInputDevice8W_iface; 294 else 295 *pdev = &This->base.IDirectInputDevice8A_iface; 296 297 return DI_OK; 298 } 299 300 return DIERR_DEVICENOTREG; 301 } 302 303 const struct dinput_device mouse_device = { 304 "Wine mouse driver", 305 mousedev_enum_deviceA, 306 mousedev_enum_deviceW, 307 mousedev_create_device 308 }; 309 310 /****************************************************************************** 311 * SysMouseA (DInput Mouse support) 312 */ 313 314 /* low-level mouse hook */ 315 static int dinput_mouse_hook( LPDIRECTINPUTDEVICE8A iface, WPARAM wparam, LPARAM lparam ) 316 { 317 MSLLHOOKSTRUCT *hook = (MSLLHOOKSTRUCT *)lparam; 318 SysMouseImpl* This = impl_from_IDirectInputDevice8A(iface); 319 int wdata = 0, inst_id = -1, ret = 0; 320 321 TRACE("msg %lx @ (%d %d)\n", wparam, hook->pt.x, hook->pt.y); 322 323 EnterCriticalSection(&This->base.crit); 324 325 switch(wparam) { 326 case WM_MOUSEMOVE: 327 { 328 POINT pt, pt1; 329 330 GetCursorPos(&pt); 331 This->m_state.lX += pt.x = hook->pt.x - pt.x; 332 This->m_state.lY += pt.y = hook->pt.y - pt.y; 333 334 if (This->base.data_format.user_df->dwFlags & DIDF_ABSAXIS) 335 { 336 pt1.x = This->m_state.lX; 337 pt1.y = This->m_state.lY; 338 } else 339 pt1 = pt; 340 341 if (pt.x) 342 { 343 inst_id = DIDFT_MAKEINSTANCE(WINE_MOUSE_X_AXIS_INSTANCE) | DIDFT_RELAXIS; 344 wdata = pt1.x; 345 } 346 if (pt.y) 347 { 348 /* Already have X, need to queue it */ 349 if (inst_id != -1) 350 queue_event(iface, inst_id, 351 wdata, GetCurrentTime(), This->base.dinput->evsequence); 352 inst_id = DIDFT_MAKEINSTANCE(WINE_MOUSE_Y_AXIS_INSTANCE) | DIDFT_RELAXIS; 353 wdata = pt1.y; 354 } 355 356 if (pt.x || pt.y) 357 { 358 if ((This->warp_override == WARP_FORCE_ON) || 359 (This->warp_override != WARP_DISABLE && (This->base.dwCoopLevel & DISCL_EXCLUSIVE))) 360 This->need_warp = TRUE; 361 } 362 break; 363 } 364 case WM_MOUSEWHEEL: 365 inst_id = DIDFT_MAKEINSTANCE(WINE_MOUSE_Z_AXIS_INSTANCE) | DIDFT_RELAXIS; 366 This->m_state.lZ += wdata = (short)HIWORD(hook->mouseData); 367 /* FarCry crashes if it gets a mouse wheel message */ 368 /* FIXME: should probably filter out other messages too */ 369 ret = This->clipped; 370 break; 371 case WM_LBUTTONDOWN: 372 inst_id = DIDFT_MAKEINSTANCE(WINE_MOUSE_BUTTONS_INSTANCE + 0) | DIDFT_PSHBUTTON; 373 This->m_state.rgbButtons[0] = wdata = 0x80; 374 break; 375 case WM_LBUTTONUP: 376 inst_id = DIDFT_MAKEINSTANCE(WINE_MOUSE_BUTTONS_INSTANCE + 0) | DIDFT_PSHBUTTON; 377 This->m_state.rgbButtons[0] = wdata = 0x00; 378 break; 379 case WM_RBUTTONDOWN: 380 inst_id = DIDFT_MAKEINSTANCE(WINE_MOUSE_BUTTONS_INSTANCE + 1) | DIDFT_PSHBUTTON; 381 This->m_state.rgbButtons[1] = wdata = 0x80; 382 break; 383 case WM_RBUTTONUP: 384 inst_id = DIDFT_MAKEINSTANCE(WINE_MOUSE_BUTTONS_INSTANCE + 1) | DIDFT_PSHBUTTON; 385 This->m_state.rgbButtons[1] = wdata = 0x00; 386 break; 387 case WM_MBUTTONDOWN: 388 inst_id = DIDFT_MAKEINSTANCE(WINE_MOUSE_BUTTONS_INSTANCE + 2) | DIDFT_PSHBUTTON; 389 This->m_state.rgbButtons[2] = wdata = 0x80; 390 break; 391 case WM_MBUTTONUP: 392 inst_id = DIDFT_MAKEINSTANCE(WINE_MOUSE_BUTTONS_INSTANCE + 2) | DIDFT_PSHBUTTON; 393 This->m_state.rgbButtons[2] = wdata = 0x00; 394 break; 395 case WM_XBUTTONDOWN: 396 inst_id = DIDFT_MAKEINSTANCE(WINE_MOUSE_BUTTONS_INSTANCE + 2 + HIWORD(hook->mouseData)) | DIDFT_PSHBUTTON; 397 This->m_state.rgbButtons[2 + HIWORD(hook->mouseData)] = wdata = 0x80; 398 break; 399 case WM_XBUTTONUP: 400 inst_id = DIDFT_MAKEINSTANCE(WINE_MOUSE_BUTTONS_INSTANCE + 2 + HIWORD(hook->mouseData)) | DIDFT_PSHBUTTON; 401 This->m_state.rgbButtons[2 + HIWORD(hook->mouseData)] = wdata = 0x00; 402 break; 403 } 404 405 406 if (inst_id != -1) 407 { 408 _dump_mouse_state(&This->m_state); 409 queue_event(iface, inst_id, 410 wdata, GetCurrentTime(), This->base.dinput->evsequence++); 411 } 412 413 LeaveCriticalSection(&This->base.crit); 414 return ret; 415 } 416 417 static void warp_check( SysMouseImpl* This, BOOL force ) 418 { 419 DWORD now = GetCurrentTime(); 420 const DWORD interval = This->clipped ? 500 : 10; 421 422 if (force || (This->need_warp && (now - This->last_warped > interval))) 423 { 424 RECT rect, new_rect; 425 POINT mapped_center; 426 427 This->last_warped = now; 428 This->need_warp = FALSE; 429 if (!GetClientRect(This->base.win, &rect)) return; 430 MapWindowPoints( This->base.win, 0, (POINT *)&rect, 2 ); 431 if (!This->clipped) 432 { 433 mapped_center.x = (rect.left + rect.right) / 2; 434 mapped_center.y = (rect.top + rect.bottom) / 2; 435 TRACE("Warping mouse to %d - %d\n", mapped_center.x, mapped_center.y); 436 SetCursorPos( mapped_center.x, mapped_center.y ); 437 } 438 if (This->base.dwCoopLevel & DISCL_EXCLUSIVE) 439 { 440 /* make sure we clip even if the window covers the whole screen */ 441 rect.left = max( rect.left, GetSystemMetrics( SM_XVIRTUALSCREEN ) + 1 ); 442 rect.top = max( rect.top, GetSystemMetrics( SM_YVIRTUALSCREEN ) + 1 ); 443 rect.right = min( rect.right, rect.left + GetSystemMetrics( SM_CXVIRTUALSCREEN ) - 2 ); 444 rect.bottom = min( rect.bottom, rect.top + GetSystemMetrics( SM_CYVIRTUALSCREEN ) - 2 ); 445 TRACE("Clipping mouse to %s\n", wine_dbgstr_rect( &rect )); 446 ClipCursor( &rect ); 447 This->clipped = GetClipCursor( &new_rect ) && EqualRect( &rect, &new_rect ); 448 } 449 } 450 } 451 452 453 /****************************************************************************** 454 * Acquire : gets exclusive control of the mouse 455 */ 456 static HRESULT WINAPI SysMouseWImpl_Acquire(LPDIRECTINPUTDEVICE8W iface) 457 { 458 SysMouseImpl *This = impl_from_IDirectInputDevice8W(iface); 459 POINT point; 460 HRESULT res; 461 462 TRACE("(this=%p)\n",This); 463 464 if ((res = IDirectInputDevice2WImpl_Acquire(iface)) != DI_OK) return res; 465 466 /* Init the mouse state */ 467 GetCursorPos( &point ); 468 if (This->base.data_format.user_df->dwFlags & DIDF_ABSAXIS) 469 { 470 This->m_state.lX = point.x; 471 This->m_state.lY = point.y; 472 } else { 473 This->m_state.lX = 0; 474 This->m_state.lY = 0; 475 This->org_coords = point; 476 } 477 This->m_state.lZ = 0; 478 This->m_state.rgbButtons[0] = GetKeyState(VK_LBUTTON) & 0x80; 479 This->m_state.rgbButtons[1] = GetKeyState(VK_RBUTTON) & 0x80; 480 This->m_state.rgbButtons[2] = GetKeyState(VK_MBUTTON) & 0x80; 481 482 if (This->base.dwCoopLevel & DISCL_EXCLUSIVE) 483 { 484 ShowCursor(FALSE); /* hide cursor */ 485 warp_check( This, TRUE ); 486 } 487 else if (This->warp_override == WARP_FORCE_ON) 488 { 489 /* Need a window to warp mouse in. */ 490 if (!This->base.win) This->base.win = GetDesktopWindow(); 491 warp_check( This, TRUE ); 492 } 493 else if (This->clipped) 494 { 495 ClipCursor( NULL ); 496 This->clipped = FALSE; 497 } 498 499 return DI_OK; 500 } 501 502 static HRESULT WINAPI SysMouseAImpl_Acquire(LPDIRECTINPUTDEVICE8A iface) 503 { 504 SysMouseImpl *This = impl_from_IDirectInputDevice8A(iface); 505 return SysMouseWImpl_Acquire(IDirectInputDevice8W_from_impl(This)); 506 } 507 508 /****************************************************************************** 509 * Unacquire : frees the mouse 510 */ 511 static HRESULT WINAPI SysMouseWImpl_Unacquire(LPDIRECTINPUTDEVICE8W iface) 512 { 513 SysMouseImpl *This = impl_from_IDirectInputDevice8W(iface); 514 HRESULT res; 515 516 TRACE("(this=%p)\n",This); 517 518 if ((res = IDirectInputDevice2WImpl_Unacquire(iface)) != DI_OK) return res; 519 520 if (This->base.dwCoopLevel & DISCL_EXCLUSIVE) 521 { 522 ClipCursor(NULL); 523 ShowCursor(TRUE); /* show cursor */ 524 This->clipped = FALSE; 525 } 526 527 /* And put the mouse cursor back where it was at acquire time */ 528 if (This->base.dwCoopLevel & DISCL_EXCLUSIVE || This->warp_override == WARP_FORCE_ON) 529 { 530 TRACE("warping mouse back to %s\n", wine_dbgstr_point(&This->org_coords)); 531 SetCursorPos(This->org_coords.x, This->org_coords.y); 532 } 533 534 return DI_OK; 535 } 536 537 static HRESULT WINAPI SysMouseAImpl_Unacquire(LPDIRECTINPUTDEVICE8A iface) 538 { 539 SysMouseImpl *This = impl_from_IDirectInputDevice8A(iface); 540 return SysMouseWImpl_Unacquire(IDirectInputDevice8W_from_impl(This)); 541 } 542 543 /****************************************************************************** 544 * GetDeviceState : returns the "state" of the mouse. 545 * 546 * For the moment, only the "standard" return structure (DIMOUSESTATE) is 547 * supported. 548 */ 549 static HRESULT WINAPI SysMouseWImpl_GetDeviceState(LPDIRECTINPUTDEVICE8W iface, DWORD len, LPVOID ptr) 550 { 551 SysMouseImpl *This = impl_from_IDirectInputDevice8W(iface); 552 TRACE("(%p)->(%u,%p)\n", This, len, ptr); 553 554 if(This->base.acquired == 0) return DIERR_NOTACQUIRED; 555 556 check_dinput_events(); 557 558 EnterCriticalSection(&This->base.crit); 559 _dump_mouse_state(&This->m_state); 560 561 /* Copy the current mouse state */ 562 fill_DataFormat(ptr, len, &This->m_state, &This->base.data_format); 563 564 /* Initialize the buffer when in relative mode */ 565 if (!(This->base.data_format.user_df->dwFlags & DIDF_ABSAXIS)) 566 { 567 This->m_state.lX = 0; 568 This->m_state.lY = 0; 569 This->m_state.lZ = 0; 570 } 571 LeaveCriticalSection(&This->base.crit); 572 573 warp_check( This, FALSE ); 574 return DI_OK; 575 } 576 577 static HRESULT WINAPI SysMouseAImpl_GetDeviceState(LPDIRECTINPUTDEVICE8A iface, DWORD len, LPVOID ptr) 578 { 579 SysMouseImpl *This = impl_from_IDirectInputDevice8A(iface); 580 return SysMouseWImpl_GetDeviceState(IDirectInputDevice8W_from_impl(This), len, ptr); 581 } 582 583 /****************************************************************************** 584 * GetDeviceData : gets buffered input data. 585 */ 586 static HRESULT WINAPI SysMouseWImpl_GetDeviceData(LPDIRECTINPUTDEVICE8W iface, 587 DWORD dodsize, LPDIDEVICEOBJECTDATA dod, LPDWORD entries, DWORD flags) 588 { 589 SysMouseImpl *This = impl_from_IDirectInputDevice8W(iface); 590 HRESULT res; 591 592 res = IDirectInputDevice2WImpl_GetDeviceData(iface, dodsize, dod, entries, flags); 593 if (SUCCEEDED(res)) warp_check( This, FALSE ); 594 return res; 595 } 596 597 static HRESULT WINAPI SysMouseAImpl_GetDeviceData(LPDIRECTINPUTDEVICE8A iface, 598 DWORD dodsize, LPDIDEVICEOBJECTDATA dod, LPDWORD entries, DWORD flags) 599 { 600 SysMouseImpl *This = impl_from_IDirectInputDevice8A(iface); 601 return SysMouseWImpl_GetDeviceData(IDirectInputDevice8W_from_impl(This), dodsize, dod, entries, flags); 602 } 603 604 /****************************************************************************** 605 * GetProperty : get input device properties 606 */ 607 static HRESULT WINAPI SysMouseWImpl_GetProperty(LPDIRECTINPUTDEVICE8W iface, REFGUID rguid, LPDIPROPHEADER pdiph) 608 { 609 SysMouseImpl *This = impl_from_IDirectInputDevice8W(iface); 610 611 TRACE("(%p) %s,%p\n", This, debugstr_guid(rguid), pdiph); 612 _dump_DIPROPHEADER(pdiph); 613 614 if (IS_DIPROP(rguid)) { 615 switch (LOWORD(rguid)) { 616 case (DWORD_PTR) DIPROP_GRANULARITY: { 617 LPDIPROPDWORD pr = (LPDIPROPDWORD) pdiph; 618 619 /* We'll just assume that the app asks about the Z axis */ 620 pr->dwData = WHEEL_DELTA; 621 622 break; 623 } 624 625 case (DWORD_PTR) DIPROP_RANGE: { 626 LPDIPROPRANGE pr = (LPDIPROPRANGE) pdiph; 627 628 if ((pdiph->dwHow == DIPH_BYID) && 629 ((pdiph->dwObj == (DIDFT_MAKEINSTANCE(WINE_MOUSE_X_AXIS_INSTANCE) | DIDFT_RELAXIS)) || 630 (pdiph->dwObj == (DIDFT_MAKEINSTANCE(WINE_MOUSE_Y_AXIS_INSTANCE) | DIDFT_RELAXIS)))) { 631 /* Querying the range of either the X or the Y axis. As I do 632 not know the range, do as if the range were 633 unrestricted...*/ 634 pr->lMin = DIPROPRANGE_NOMIN; 635 pr->lMax = DIPROPRANGE_NOMAX; 636 } 637 638 break; 639 } 640 641 default: 642 return IDirectInputDevice2WImpl_GetProperty(iface, rguid, pdiph); 643 } 644 } 645 646 return DI_OK; 647 } 648 649 static HRESULT WINAPI SysMouseAImpl_GetProperty(LPDIRECTINPUTDEVICE8A iface, REFGUID rguid, LPDIPROPHEADER pdiph) 650 { 651 SysMouseImpl *This = impl_from_IDirectInputDevice8A(iface); 652 return SysMouseWImpl_GetProperty(IDirectInputDevice8W_from_impl(This), rguid, pdiph); 653 } 654 655 /****************************************************************************** 656 * GetCapabilities : get the device capabilities 657 */ 658 static HRESULT WINAPI SysMouseWImpl_GetCapabilities(LPDIRECTINPUTDEVICE8W iface, LPDIDEVCAPS lpDIDevCaps) 659 { 660 SysMouseImpl *This = impl_from_IDirectInputDevice8W(iface); 661 DIDEVCAPS devcaps; 662 663 TRACE("(this=%p,%p)\n",This,lpDIDevCaps); 664 665 if ((lpDIDevCaps->dwSize != sizeof(DIDEVCAPS)) && (lpDIDevCaps->dwSize != sizeof(DIDEVCAPS_DX3))) { 666 WARN("invalid parameter\n"); 667 return DIERR_INVALIDPARAM; 668 } 669 670 devcaps.dwSize = lpDIDevCaps->dwSize; 671 devcaps.dwFlags = DIDC_ATTACHED | DIDC_EMULATED; 672 if (This->base.dinput->dwVersion >= 0x0800) 673 devcaps.dwDevType = DI8DEVTYPE_MOUSE | (DI8DEVTYPEMOUSE_TRADITIONAL << 8); 674 else 675 devcaps.dwDevType = DIDEVTYPE_MOUSE | (DIDEVTYPEMOUSE_TRADITIONAL << 8); 676 devcaps.dwAxes = 3; 677 devcaps.dwButtons = 8; 678 devcaps.dwPOVs = 0; 679 devcaps.dwFFSamplePeriod = 0; 680 devcaps.dwFFMinTimeResolution = 0; 681 devcaps.dwFirmwareRevision = 100; 682 devcaps.dwHardwareRevision = 100; 683 devcaps.dwFFDriverVersion = 0; 684 685 memcpy(lpDIDevCaps, &devcaps, lpDIDevCaps->dwSize); 686 687 return DI_OK; 688 } 689 690 static HRESULT WINAPI SysMouseAImpl_GetCapabilities(LPDIRECTINPUTDEVICE8A iface, LPDIDEVCAPS lpDIDevCaps) 691 { 692 SysMouseImpl *This = impl_from_IDirectInputDevice8A(iface); 693 return SysMouseWImpl_GetCapabilities(IDirectInputDevice8W_from_impl(This), lpDIDevCaps); 694 } 695 696 /****************************************************************************** 697 * GetObjectInfo : get information about a device object such as a button 698 * or axis 699 */ 700 static HRESULT WINAPI SysMouseWImpl_GetObjectInfo(LPDIRECTINPUTDEVICE8W iface, 701 LPDIDEVICEOBJECTINSTANCEW pdidoi, DWORD dwObj, DWORD dwHow) 702 { 703 static const WCHAR x_axisW[] = {'X','-','A','x','i','s',0}; 704 static const WCHAR y_axisW[] = {'Y','-','A','x','i','s',0}; 705 static const WCHAR wheelW[] = {'W','h','e','e','l',0}; 706 static const WCHAR buttonW[] = {'B','u','t','t','o','n',' ','%','d',0}; 707 HRESULT res; 708 709 res = IDirectInputDevice2WImpl_GetObjectInfo(iface, pdidoi, dwObj, dwHow); 710 if (res != DI_OK) return res; 711 712 if (IsEqualGUID(&pdidoi->guidType, &GUID_XAxis)) strcpyW(pdidoi->tszName, x_axisW); 713 else if (IsEqualGUID(&pdidoi->guidType, &GUID_YAxis)) strcpyW(pdidoi->tszName, y_axisW); 714 else if (IsEqualGUID(&pdidoi->guidType, &GUID_ZAxis)) strcpyW(pdidoi->tszName, wheelW); 715 else if (pdidoi->dwType & DIDFT_BUTTON) 716 wsprintfW(pdidoi->tszName, buttonW, DIDFT_GETINSTANCE(pdidoi->dwType) - 3); 717 718 _dump_OBJECTINSTANCEW(pdidoi); 719 return res; 720 } 721 722 static HRESULT WINAPI SysMouseAImpl_GetObjectInfo(LPDIRECTINPUTDEVICE8A iface, 723 LPDIDEVICEOBJECTINSTANCEA pdidoi, DWORD dwObj, DWORD dwHow) 724 { 725 SysMouseImpl *This = impl_from_IDirectInputDevice8A(iface); 726 HRESULT res; 727 DIDEVICEOBJECTINSTANCEW didoiW; 728 DWORD dwSize = pdidoi->dwSize; 729 730 didoiW.dwSize = sizeof(didoiW); 731 res = SysMouseWImpl_GetObjectInfo(IDirectInputDevice8W_from_impl(This), &didoiW, dwObj, dwHow); 732 if (res != DI_OK) return res; 733 734 memset(pdidoi, 0, pdidoi->dwSize); 735 memcpy(pdidoi, &didoiW, FIELD_OFFSET(DIDEVICEOBJECTINSTANCEW, tszName)); 736 pdidoi->dwSize = dwSize; 737 WideCharToMultiByte(CP_ACP, 0, didoiW.tszName, -1, pdidoi->tszName, 738 sizeof(pdidoi->tszName), NULL, NULL); 739 740 return res; 741 } 742 743 /****************************************************************************** 744 * GetDeviceInfo : get information about a device's identity 745 */ 746 static HRESULT WINAPI SysMouseAImpl_GetDeviceInfo( 747 LPDIRECTINPUTDEVICE8A iface, 748 LPDIDEVICEINSTANCEA pdidi) 749 { 750 SysMouseImpl *This = impl_from_IDirectInputDevice8A(iface); 751 TRACE("(this=%p,%p)\n", This, pdidi); 752 753 if (pdidi->dwSize != sizeof(DIDEVICEINSTANCEA)) { 754 WARN(" dinput3 not supported yet...\n"); 755 return DI_OK; 756 } 757 758 fill_mouse_dideviceinstanceA(pdidi, This->base.dinput->dwVersion); 759 760 return DI_OK; 761 } 762 763 static HRESULT WINAPI SysMouseWImpl_GetDeviceInfo(LPDIRECTINPUTDEVICE8W iface, LPDIDEVICEINSTANCEW pdidi) 764 { 765 SysMouseImpl *This = impl_from_IDirectInputDevice8W(iface); 766 TRACE("(this=%p,%p)\n", This, pdidi); 767 768 if (pdidi->dwSize != sizeof(DIDEVICEINSTANCEW)) { 769 WARN(" dinput3 not supported yet...\n"); 770 return DI_OK; 771 } 772 773 fill_mouse_dideviceinstanceW(pdidi, This->base.dinput->dwVersion); 774 775 return DI_OK; 776 } 777 778 static HRESULT WINAPI SysMouseWImpl_BuildActionMap(LPDIRECTINPUTDEVICE8W iface, 779 LPDIACTIONFORMATW lpdiaf, 780 LPCWSTR lpszUserName, 781 DWORD dwFlags) 782 { 783 FIXME("(%p)->(%p,%s,%08x): semi-stub !\n", iface, lpdiaf, debugstr_w(lpszUserName), dwFlags); 784 785 return _build_action_map(iface, lpdiaf, lpszUserName, dwFlags, DIMOUSE_MASK, &c_dfDIMouse2); 786 } 787 788 static HRESULT WINAPI SysMouseAImpl_BuildActionMap(LPDIRECTINPUTDEVICE8A iface, 789 LPDIACTIONFORMATA lpdiaf, 790 LPCSTR lpszUserName, 791 DWORD dwFlags) 792 { 793 SysMouseImpl *This = impl_from_IDirectInputDevice8A(iface); 794 DIACTIONFORMATW diafW; 795 HRESULT hr; 796 WCHAR *lpszUserNameW = NULL; 797 int username_size; 798 799 diafW.rgoAction = HeapAlloc(GetProcessHeap(), 0, sizeof(DIACTIONW)*lpdiaf->dwNumActions); 800 _copy_diactionformatAtoW(&diafW, lpdiaf); 801 802 if (lpszUserName != NULL) 803 { 804 username_size = MultiByteToWideChar(CP_ACP, 0, lpszUserName, -1, NULL, 0); 805 lpszUserNameW = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR)*username_size); 806 MultiByteToWideChar(CP_ACP, 0, lpszUserName, -1, lpszUserNameW, username_size); 807 } 808 809 hr = SysMouseWImpl_BuildActionMap(&This->base.IDirectInputDevice8W_iface, &diafW, lpszUserNameW, dwFlags); 810 811 _copy_diactionformatWtoA(lpdiaf, &diafW); 812 HeapFree(GetProcessHeap(), 0, diafW.rgoAction); 813 HeapFree(GetProcessHeap(), 0, lpszUserNameW); 814 815 return hr; 816 } 817 818 static HRESULT WINAPI SysMouseWImpl_SetActionMap(LPDIRECTINPUTDEVICE8W iface, 819 LPDIACTIONFORMATW lpdiaf, 820 LPCWSTR lpszUserName, 821 DWORD dwFlags) 822 { 823 FIXME("(%p)->(%p,%s,%08x): semi-stub !\n", iface, lpdiaf, debugstr_w(lpszUserName), dwFlags); 824 825 return _set_action_map(iface, lpdiaf, lpszUserName, dwFlags, &c_dfDIMouse2); 826 } 827 828 static HRESULT WINAPI SysMouseAImpl_SetActionMap(LPDIRECTINPUTDEVICE8A iface, 829 LPDIACTIONFORMATA lpdiaf, 830 LPCSTR lpszUserName, 831 DWORD dwFlags) 832 { 833 SysMouseImpl *This = impl_from_IDirectInputDevice8A(iface); 834 DIACTIONFORMATW diafW; 835 HRESULT hr; 836 WCHAR *lpszUserNameW = NULL; 837 int username_size; 838 839 diafW.rgoAction = HeapAlloc(GetProcessHeap(), 0, sizeof(DIACTIONW)*lpdiaf->dwNumActions); 840 _copy_diactionformatAtoW(&diafW, lpdiaf); 841 842 if (lpszUserName != NULL) 843 { 844 username_size = MultiByteToWideChar(CP_ACP, 0, lpszUserName, -1, NULL, 0); 845 lpszUserNameW = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR)*username_size); 846 MultiByteToWideChar(CP_ACP, 0, lpszUserName, -1, lpszUserNameW, username_size); 847 } 848 849 hr = SysMouseWImpl_SetActionMap(&This->base.IDirectInputDevice8W_iface, &diafW, lpszUserNameW, dwFlags); 850 851 HeapFree(GetProcessHeap(), 0, diafW.rgoAction); 852 HeapFree(GetProcessHeap(), 0, lpszUserNameW); 853 854 return hr; 855 } 856 857 static const IDirectInputDevice8AVtbl SysMouseAvt = 858 { 859 IDirectInputDevice2AImpl_QueryInterface, 860 IDirectInputDevice2AImpl_AddRef, 861 IDirectInputDevice2AImpl_Release, 862 SysMouseAImpl_GetCapabilities, 863 IDirectInputDevice2AImpl_EnumObjects, 864 SysMouseAImpl_GetProperty, 865 IDirectInputDevice2AImpl_SetProperty, 866 SysMouseAImpl_Acquire, 867 SysMouseAImpl_Unacquire, 868 SysMouseAImpl_GetDeviceState, 869 SysMouseAImpl_GetDeviceData, 870 IDirectInputDevice2AImpl_SetDataFormat, 871 IDirectInputDevice2AImpl_SetEventNotification, 872 IDirectInputDevice2AImpl_SetCooperativeLevel, 873 SysMouseAImpl_GetObjectInfo, 874 SysMouseAImpl_GetDeviceInfo, 875 IDirectInputDevice2AImpl_RunControlPanel, 876 IDirectInputDevice2AImpl_Initialize, 877 IDirectInputDevice2AImpl_CreateEffect, 878 IDirectInputDevice2AImpl_EnumEffects, 879 IDirectInputDevice2AImpl_GetEffectInfo, 880 IDirectInputDevice2AImpl_GetForceFeedbackState, 881 IDirectInputDevice2AImpl_SendForceFeedbackCommand, 882 IDirectInputDevice2AImpl_EnumCreatedEffectObjects, 883 IDirectInputDevice2AImpl_Escape, 884 IDirectInputDevice2AImpl_Poll, 885 IDirectInputDevice2AImpl_SendDeviceData, 886 IDirectInputDevice7AImpl_EnumEffectsInFile, 887 IDirectInputDevice7AImpl_WriteEffectToFile, 888 SysMouseAImpl_BuildActionMap, 889 SysMouseAImpl_SetActionMap, 890 IDirectInputDevice8AImpl_GetImageInfo 891 }; 892 893 static const IDirectInputDevice8WVtbl SysMouseWvt = 894 { 895 IDirectInputDevice2WImpl_QueryInterface, 896 IDirectInputDevice2WImpl_AddRef, 897 IDirectInputDevice2WImpl_Release, 898 SysMouseWImpl_GetCapabilities, 899 IDirectInputDevice2WImpl_EnumObjects, 900 SysMouseWImpl_GetProperty, 901 IDirectInputDevice2WImpl_SetProperty, 902 SysMouseWImpl_Acquire, 903 SysMouseWImpl_Unacquire, 904 SysMouseWImpl_GetDeviceState, 905 SysMouseWImpl_GetDeviceData, 906 IDirectInputDevice2WImpl_SetDataFormat, 907 IDirectInputDevice2WImpl_SetEventNotification, 908 IDirectInputDevice2WImpl_SetCooperativeLevel, 909 SysMouseWImpl_GetObjectInfo, 910 SysMouseWImpl_GetDeviceInfo, 911 IDirectInputDevice2WImpl_RunControlPanel, 912 IDirectInputDevice2WImpl_Initialize, 913 IDirectInputDevice2WImpl_CreateEffect, 914 IDirectInputDevice2WImpl_EnumEffects, 915 IDirectInputDevice2WImpl_GetEffectInfo, 916 IDirectInputDevice2WImpl_GetForceFeedbackState, 917 IDirectInputDevice2WImpl_SendForceFeedbackCommand, 918 IDirectInputDevice2WImpl_EnumCreatedEffectObjects, 919 IDirectInputDevice2WImpl_Escape, 920 IDirectInputDevice2WImpl_Poll, 921 IDirectInputDevice2WImpl_SendDeviceData, 922 IDirectInputDevice7WImpl_EnumEffectsInFile, 923 IDirectInputDevice7WImpl_WriteEffectToFile, 924 SysMouseWImpl_BuildActionMap, 925 SysMouseWImpl_SetActionMap, 926 IDirectInputDevice8WImpl_GetImageInfo 927 }; 928