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 if ( 620 ((pdiph->dwHow == DIPH_BYOFFSET) && 621 ((pdiph->dwObj == DIMOFS_X) || 622 (pdiph->dwObj == DIMOFS_Y))) 623 || 624 ((pdiph->dwHow == DIPH_BYID) && 625 ((pdiph->dwObj == (DIDFT_MAKEINSTANCE(WINE_MOUSE_X_AXIS_INSTANCE) | DIDFT_RELAXIS)) || 626 (pdiph->dwObj == (DIDFT_MAKEINSTANCE(WINE_MOUSE_Y_AXIS_INSTANCE) | DIDFT_RELAXIS)))) 627 ){ 628 /* Set granularity of X/Y Axis to 1. See MSDN on DIPROP_GRANULARITY */ 629 pr->dwData = 1; 630 } else { 631 /* We'll just assume that the app asks about the Z axis */ 632 pr->dwData = WHEEL_DELTA; 633 } 634 635 break; 636 } 637 638 case (DWORD_PTR) DIPROP_RANGE: { 639 LPDIPROPRANGE pr = (LPDIPROPRANGE) pdiph; 640 641 if ((pdiph->dwHow == DIPH_BYID) && 642 ((pdiph->dwObj == (DIDFT_MAKEINSTANCE(WINE_MOUSE_X_AXIS_INSTANCE) | DIDFT_RELAXIS)) || 643 (pdiph->dwObj == (DIDFT_MAKEINSTANCE(WINE_MOUSE_Y_AXIS_INSTANCE) | DIDFT_RELAXIS)))) { 644 /* Querying the range of either the X or the Y axis. As I do 645 not know the range, do as if the range were 646 unrestricted...*/ 647 pr->lMin = DIPROPRANGE_NOMIN; 648 pr->lMax = DIPROPRANGE_NOMAX; 649 } 650 651 break; 652 } 653 654 default: 655 return IDirectInputDevice2WImpl_GetProperty(iface, rguid, pdiph); 656 } 657 } 658 659 return DI_OK; 660 } 661 662 static HRESULT WINAPI SysMouseAImpl_GetProperty(LPDIRECTINPUTDEVICE8A iface, REFGUID rguid, LPDIPROPHEADER pdiph) 663 { 664 SysMouseImpl *This = impl_from_IDirectInputDevice8A(iface); 665 return SysMouseWImpl_GetProperty(IDirectInputDevice8W_from_impl(This), rguid, pdiph); 666 } 667 668 /****************************************************************************** 669 * GetCapabilities : get the device capabilities 670 */ 671 static HRESULT WINAPI SysMouseWImpl_GetCapabilities(LPDIRECTINPUTDEVICE8W iface, LPDIDEVCAPS lpDIDevCaps) 672 { 673 SysMouseImpl *This = impl_from_IDirectInputDevice8W(iface); 674 DIDEVCAPS devcaps; 675 676 TRACE("(this=%p,%p)\n",This,lpDIDevCaps); 677 678 if ((lpDIDevCaps->dwSize != sizeof(DIDEVCAPS)) && (lpDIDevCaps->dwSize != sizeof(DIDEVCAPS_DX3))) { 679 WARN("invalid parameter\n"); 680 return DIERR_INVALIDPARAM; 681 } 682 683 devcaps.dwSize = lpDIDevCaps->dwSize; 684 devcaps.dwFlags = DIDC_ATTACHED | DIDC_EMULATED; 685 if (This->base.dinput->dwVersion >= 0x0800) 686 devcaps.dwDevType = DI8DEVTYPE_MOUSE | (DI8DEVTYPEMOUSE_TRADITIONAL << 8); 687 else 688 devcaps.dwDevType = DIDEVTYPE_MOUSE | (DIDEVTYPEMOUSE_TRADITIONAL << 8); 689 devcaps.dwAxes = 3; 690 devcaps.dwButtons = 8; 691 devcaps.dwPOVs = 0; 692 devcaps.dwFFSamplePeriod = 0; 693 devcaps.dwFFMinTimeResolution = 0; 694 devcaps.dwFirmwareRevision = 100; 695 devcaps.dwHardwareRevision = 100; 696 devcaps.dwFFDriverVersion = 0; 697 698 memcpy(lpDIDevCaps, &devcaps, lpDIDevCaps->dwSize); 699 700 return DI_OK; 701 } 702 703 static HRESULT WINAPI SysMouseAImpl_GetCapabilities(LPDIRECTINPUTDEVICE8A iface, LPDIDEVCAPS lpDIDevCaps) 704 { 705 SysMouseImpl *This = impl_from_IDirectInputDevice8A(iface); 706 return SysMouseWImpl_GetCapabilities(IDirectInputDevice8W_from_impl(This), lpDIDevCaps); 707 } 708 709 /****************************************************************************** 710 * GetObjectInfo : get information about a device object such as a button 711 * or axis 712 */ 713 static HRESULT WINAPI SysMouseWImpl_GetObjectInfo(LPDIRECTINPUTDEVICE8W iface, 714 LPDIDEVICEOBJECTINSTANCEW pdidoi, DWORD dwObj, DWORD dwHow) 715 { 716 static const WCHAR x_axisW[] = {'X','-','A','x','i','s',0}; 717 static const WCHAR y_axisW[] = {'Y','-','A','x','i','s',0}; 718 static const WCHAR wheelW[] = {'W','h','e','e','l',0}; 719 static const WCHAR buttonW[] = {'B','u','t','t','o','n',' ','%','d',0}; 720 HRESULT res; 721 722 res = IDirectInputDevice2WImpl_GetObjectInfo(iface, pdidoi, dwObj, dwHow); 723 if (res != DI_OK) return res; 724 725 if (IsEqualGUID(&pdidoi->guidType, &GUID_XAxis)) strcpyW(pdidoi->tszName, x_axisW); 726 else if (IsEqualGUID(&pdidoi->guidType, &GUID_YAxis)) strcpyW(pdidoi->tszName, y_axisW); 727 else if (IsEqualGUID(&pdidoi->guidType, &GUID_ZAxis)) strcpyW(pdidoi->tszName, wheelW); 728 else if (pdidoi->dwType & DIDFT_BUTTON) 729 wsprintfW(pdidoi->tszName, buttonW, DIDFT_GETINSTANCE(pdidoi->dwType) - 3); 730 731 _dump_OBJECTINSTANCEW(pdidoi); 732 return res; 733 } 734 735 static HRESULT WINAPI SysMouseAImpl_GetObjectInfo(LPDIRECTINPUTDEVICE8A iface, 736 LPDIDEVICEOBJECTINSTANCEA pdidoi, DWORD dwObj, DWORD dwHow) 737 { 738 SysMouseImpl *This = impl_from_IDirectInputDevice8A(iface); 739 HRESULT res; 740 DIDEVICEOBJECTINSTANCEW didoiW; 741 DWORD dwSize = pdidoi->dwSize; 742 743 didoiW.dwSize = sizeof(didoiW); 744 res = SysMouseWImpl_GetObjectInfo(IDirectInputDevice8W_from_impl(This), &didoiW, dwObj, dwHow); 745 if (res != DI_OK) return res; 746 747 memset(pdidoi, 0, pdidoi->dwSize); 748 memcpy(pdidoi, &didoiW, FIELD_OFFSET(DIDEVICEOBJECTINSTANCEW, tszName)); 749 pdidoi->dwSize = dwSize; 750 WideCharToMultiByte(CP_ACP, 0, didoiW.tszName, -1, pdidoi->tszName, 751 sizeof(pdidoi->tszName), NULL, NULL); 752 753 return res; 754 } 755 756 /****************************************************************************** 757 * GetDeviceInfo : get information about a device's identity 758 */ 759 static HRESULT WINAPI SysMouseAImpl_GetDeviceInfo( 760 LPDIRECTINPUTDEVICE8A iface, 761 LPDIDEVICEINSTANCEA pdidi) 762 { 763 SysMouseImpl *This = impl_from_IDirectInputDevice8A(iface); 764 TRACE("(this=%p,%p)\n", This, pdidi); 765 766 if (pdidi->dwSize != sizeof(DIDEVICEINSTANCEA)) { 767 WARN(" dinput3 not supported yet...\n"); 768 return DI_OK; 769 } 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 FIXME("(%p)->(%p,%s,%08x): semi-stub !\n", iface, lpdiaf, debugstr_w(lpszUserName), dwFlags); 837 838 return _set_action_map(iface, lpdiaf, lpszUserName, dwFlags, &c_dfDIMouse2); 839 } 840 841 static HRESULT WINAPI SysMouseAImpl_SetActionMap(LPDIRECTINPUTDEVICE8A iface, 842 LPDIACTIONFORMATA lpdiaf, 843 LPCSTR lpszUserName, 844 DWORD dwFlags) 845 { 846 SysMouseImpl *This = impl_from_IDirectInputDevice8A(iface); 847 DIACTIONFORMATW diafW; 848 HRESULT hr; 849 WCHAR *lpszUserNameW = NULL; 850 int username_size; 851 852 diafW.rgoAction = HeapAlloc(GetProcessHeap(), 0, sizeof(DIACTIONW)*lpdiaf->dwNumActions); 853 _copy_diactionformatAtoW(&diafW, lpdiaf); 854 855 if (lpszUserName != NULL) 856 { 857 username_size = MultiByteToWideChar(CP_ACP, 0, lpszUserName, -1, NULL, 0); 858 lpszUserNameW = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR)*username_size); 859 MultiByteToWideChar(CP_ACP, 0, lpszUserName, -1, lpszUserNameW, username_size); 860 } 861 862 hr = SysMouseWImpl_SetActionMap(&This->base.IDirectInputDevice8W_iface, &diafW, lpszUserNameW, dwFlags); 863 864 HeapFree(GetProcessHeap(), 0, diafW.rgoAction); 865 HeapFree(GetProcessHeap(), 0, lpszUserNameW); 866 867 return hr; 868 } 869 870 static const IDirectInputDevice8AVtbl SysMouseAvt = 871 { 872 IDirectInputDevice2AImpl_QueryInterface, 873 IDirectInputDevice2AImpl_AddRef, 874 IDirectInputDevice2AImpl_Release, 875 SysMouseAImpl_GetCapabilities, 876 IDirectInputDevice2AImpl_EnumObjects, 877 SysMouseAImpl_GetProperty, 878 IDirectInputDevice2AImpl_SetProperty, 879 SysMouseAImpl_Acquire, 880 SysMouseAImpl_Unacquire, 881 SysMouseAImpl_GetDeviceState, 882 SysMouseAImpl_GetDeviceData, 883 IDirectInputDevice2AImpl_SetDataFormat, 884 IDirectInputDevice2AImpl_SetEventNotification, 885 IDirectInputDevice2AImpl_SetCooperativeLevel, 886 SysMouseAImpl_GetObjectInfo, 887 SysMouseAImpl_GetDeviceInfo, 888 IDirectInputDevice2AImpl_RunControlPanel, 889 IDirectInputDevice2AImpl_Initialize, 890 IDirectInputDevice2AImpl_CreateEffect, 891 IDirectInputDevice2AImpl_EnumEffects, 892 IDirectInputDevice2AImpl_GetEffectInfo, 893 IDirectInputDevice2AImpl_GetForceFeedbackState, 894 IDirectInputDevice2AImpl_SendForceFeedbackCommand, 895 IDirectInputDevice2AImpl_EnumCreatedEffectObjects, 896 IDirectInputDevice2AImpl_Escape, 897 IDirectInputDevice2AImpl_Poll, 898 IDirectInputDevice2AImpl_SendDeviceData, 899 IDirectInputDevice7AImpl_EnumEffectsInFile, 900 IDirectInputDevice7AImpl_WriteEffectToFile, 901 SysMouseAImpl_BuildActionMap, 902 SysMouseAImpl_SetActionMap, 903 IDirectInputDevice8AImpl_GetImageInfo 904 }; 905 906 static const IDirectInputDevice8WVtbl SysMouseWvt = 907 { 908 IDirectInputDevice2WImpl_QueryInterface, 909 IDirectInputDevice2WImpl_AddRef, 910 IDirectInputDevice2WImpl_Release, 911 SysMouseWImpl_GetCapabilities, 912 IDirectInputDevice2WImpl_EnumObjects, 913 SysMouseWImpl_GetProperty, 914 IDirectInputDevice2WImpl_SetProperty, 915 SysMouseWImpl_Acquire, 916 SysMouseWImpl_Unacquire, 917 SysMouseWImpl_GetDeviceState, 918 SysMouseWImpl_GetDeviceData, 919 IDirectInputDevice2WImpl_SetDataFormat, 920 IDirectInputDevice2WImpl_SetEventNotification, 921 IDirectInputDevice2WImpl_SetCooperativeLevel, 922 SysMouseWImpl_GetObjectInfo, 923 SysMouseWImpl_GetDeviceInfo, 924 IDirectInputDevice2WImpl_RunControlPanel, 925 IDirectInputDevice2WImpl_Initialize, 926 IDirectInputDevice2WImpl_CreateEffect, 927 IDirectInputDevice2WImpl_EnumEffects, 928 IDirectInputDevice2WImpl_GetEffectInfo, 929 IDirectInputDevice2WImpl_GetForceFeedbackState, 930 IDirectInputDevice2WImpl_SendForceFeedbackCommand, 931 IDirectInputDevice2WImpl_EnumCreatedEffectObjects, 932 IDirectInputDevice2WImpl_Escape, 933 IDirectInputDevice2WImpl_Poll, 934 IDirectInputDevice2WImpl_SendDeviceData, 935 IDirectInputDevice7WImpl_EnumEffectsInFile, 936 IDirectInputDevice7WImpl_WriteEffectToFile, 937 SysMouseWImpl_BuildActionMap, 938 SysMouseWImpl_SetActionMap, 939 IDirectInputDevice8WImpl_GetImageInfo 940 }; 941