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