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