mouse.c 32.1 KB
Newer Older
Lionel Ulmer's avatar
Lionel Ulmer committed
1 2 3 4
/*		DirectInput Mouse device
 *
 * Copyright 1998 Marcus Meissner
 * Copyright 1998,1999 Lionel Ulmer
5
 * Copyright 2000-2001 TransGaming Technologies Inc.
Lionel Ulmer's avatar
Lionel Ulmer committed
6
 *
7 8 9 10 11 12 13 14 15 16 17 18
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * 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
Lionel Ulmer's avatar
Lionel Ulmer committed
20 21 22
 */

#include "config.h"
23 24
#include "wine/port.h"

25
#include <stdarg.h>
Lionel Ulmer's avatar
Lionel Ulmer committed
26 27
#include <string.h>

28
#include "windef.h"
Lionel Ulmer's avatar
Lionel Ulmer committed
29 30 31
#include "winbase.h"
#include "wingdi.h"
#include "winuser.h"
32
#include "winerror.h"
33
#include "winreg.h"
Lionel Ulmer's avatar
Lionel Ulmer committed
34 35 36 37
#include "dinput.h"

#include "dinput_private.h"
#include "device_private.h"
38
#include "wine/debug.h"
39
#include "wine/unicode.h"
Lionel Ulmer's avatar
Lionel Ulmer committed
40

41
WINE_DEFAULT_DEBUG_CHANNEL(dinput);
Lionel Ulmer's avatar
Lionel Ulmer committed
42 43

/* Wine mouse driver object instances */
44 45
#define WINE_MOUSE_X_AXIS_INSTANCE   0
#define WINE_MOUSE_Y_AXIS_INSTANCE   1
46 47
#define WINE_MOUSE_Z_AXIS_INSTANCE   2
#define WINE_MOUSE_BUTTONS_INSTANCE  3
Lionel Ulmer's avatar
Lionel Ulmer committed
48

49 50
static const IDirectInputDevice8AVtbl SysMouseAvt;
static const IDirectInputDevice8WVtbl SysMouseWvt;
51 52

typedef struct SysMouseImpl SysMouseImpl;
Lionel Ulmer's avatar
Lionel Ulmer committed
53

54 55 56 57 58 59 60
typedef enum
{
    WARP_DEFAULT,
    WARP_DISABLE,
    WARP_FORCE_ON
} WARP_MOUSE;

61
struct SysMouseImpl
Lionel Ulmer's avatar
Lionel Ulmer committed
62
{
63 64
    struct IDirectInputDeviceImpl   base;

65 66 67
    /* SysMouseAImpl */
    /* These are used in case of relative -> absolute transitions */
    POINT                           org_coords;
68
    BOOL                            clipped;
69 70
    /* warping: whether we need to move mouse back to middle once we
     * 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;
Lionel Ulmer's avatar
Lionel Ulmer committed
78 79
};

80 81
static inline SysMouseImpl *impl_from_IDirectInputDevice8A(IDirectInputDevice8A *iface)
{
82
    return CONTAINING_RECORD(CONTAINING_RECORD(iface, IDirectInputDeviceImpl, IDirectInputDevice8A_iface), SysMouseImpl, base);
83 84 85
}
static inline SysMouseImpl *impl_from_IDirectInputDevice8W(IDirectInputDevice8W *iface)
{
86
    return CONTAINING_RECORD(CONTAINING_RECORD(iface, IDirectInputDeviceImpl, IDirectInputDevice8W_iface), SysMouseImpl, base);
87
}
88 89
static inline IDirectInputDevice8A *IDirectInputDevice8A_from_impl(SysMouseImpl *This)
{
90
    return &This->base.IDirectInputDevice8A_iface;
91 92 93
}
static inline IDirectInputDevice8W *IDirectInputDevice8W_from_impl(SysMouseImpl *This)
{
94
    return &This->base.IDirectInputDevice8W_iface;
95
}
96

97
static int dinput_mouse_hook( LPDIRECTINPUTDEVICE8A iface, WPARAM wparam, LPARAM lparam );
98

99 100
const GUID DInput_Wine_Mouse_GUID = { /* 9e573ed8-7734-11d2-8d4a-23903fb6bdf7 */
    0x9e573ed8, 0x7734, 0x11d2, {0x8d, 0x4a, 0x23, 0x90, 0x3f, 0xb6, 0xbd, 0xf7}
Lionel Ulmer's avatar
Lionel Ulmer committed
101 102
};

103
static void _dump_mouse_state(const DIMOUSESTATE2 *m_state)
104 105 106 107 108 109 110 111 112 113
{
    int i;

    if (!TRACE_ON(dinput)) return;

    TRACE("(X: %d Y: %d Z: %d", m_state->lX, m_state->lY, m_state->lZ);
    for (i = 0; i < 5; i++) TRACE(" B%d: %02x", i, m_state->rgbButtons[i]);
    TRACE(")\n");
}

114
static void fill_mouse_dideviceinstanceA(LPDIDEVICEINSTANCEA lpddi, DWORD version) {
115 116 117 118 119
    DWORD dwSize;
    DIDEVICEINSTANCEA ddi;
    
    dwSize = lpddi->dwSize;

120
    TRACE("%d %p\n", dwSize, lpddi);
121 122 123 124 125 126 127
    
    memset(lpddi, 0, dwSize);
    memset(&ddi, 0, sizeof(ddi));

    ddi.dwSize = dwSize;
    ddi.guidInstance = GUID_SysMouse;/* DInput's GUID */
    ddi.guidProduct = DInput_Wine_Mouse_GUID; /* Vendor's GUID */
128
    if (version >= 0x0800)
129 130 131
        ddi.dwDevType = DI8DEVTYPE_MOUSE | (DI8DEVTYPEMOUSE_TRADITIONAL << 8);
    else
        ddi.dwDevType = DIDEVTYPE_MOUSE | (DIDEVTYPEMOUSE_TRADITIONAL << 8);
132 133 134 135 136
    strcpy(ddi.tszInstanceName, "Mouse");
    strcpy(ddi.tszProductName, "Wine Mouse");

    memcpy(lpddi, &ddi, (dwSize < sizeof(ddi) ? dwSize : sizeof(ddi)));
}
Lionel Ulmer's avatar
Lionel Ulmer committed
137

138
static void fill_mouse_dideviceinstanceW(LPDIDEVICEINSTANCEW lpddi, DWORD version) {
139 140 141 142 143
    DWORD dwSize;
    DIDEVICEINSTANCEW ddi;
    
    dwSize = lpddi->dwSize;

144
    TRACE("%d %p\n", dwSize, lpddi);
145 146 147 148 149 150 151
    
    memset(lpddi, 0, dwSize);
    memset(&ddi, 0, sizeof(ddi));

    ddi.dwSize = dwSize;
    ddi.guidInstance = GUID_SysMouse;/* DInput's GUID */
    ddi.guidProduct = DInput_Wine_Mouse_GUID; /* Vendor's GUID */
152
    if (version >= 0x0800)
153 154 155 156 157 158 159 160 161
        ddi.dwDevType = DI8DEVTYPE_MOUSE | (DI8DEVTYPEMOUSE_TRADITIONAL << 8);
    else
        ddi.dwDevType = DIDEVTYPE_MOUSE | (DIDEVTYPEMOUSE_TRADITIONAL << 8);
    MultiByteToWideChar(CP_ACP, 0, "Mouse", -1, ddi.tszInstanceName, MAX_PATH);
    MultiByteToWideChar(CP_ACP, 0, "Wine Mouse", -1, ddi.tszProductName, MAX_PATH);

    memcpy(lpddi, &ddi, (dwSize < sizeof(ddi) ? dwSize : sizeof(ddi)));
}

162
static BOOL mousedev_enum_deviceA(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEA lpddi, DWORD version, int id)
163
{
164 165 166
    if (id != 0)
        return FALSE;

167
    if ((dwDevType == 0) ||
168 169
	((dwDevType == DIDEVTYPE_MOUSE) && (version < 0x0800)) ||
	(((dwDevType == DI8DEVCLASS_POINTER) || (dwDevType == DI8DEVTYPE_MOUSE)) && (version >= 0x0800))) {
170 171 172 173 174 175 176 177
	TRACE("Enumerating the mouse device\n");
	
	fill_mouse_dideviceinstanceA(lpddi, version);
	
	return TRUE;
    }
    
    return FALSE;
178 179
}

180
static BOOL mousedev_enum_deviceW(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEW lpddi, DWORD version, int id)
Lionel Ulmer's avatar
Lionel Ulmer committed
181
{
182 183 184
    if (id != 0)
        return FALSE;

185
    if ((dwDevType == 0) ||
186 187
	((dwDevType == DIDEVTYPE_MOUSE) && (version < 0x0800)) ||
	(((dwDevType == DI8DEVCLASS_POINTER) || (dwDevType == DI8DEVTYPE_MOUSE)) && (version >= 0x0800))) {
188 189 190 191 192 193 194 195
	TRACE("Enumerating the mouse device\n");
	
	fill_mouse_dideviceinstanceW(lpddi, version);
	
	return TRUE;
    }
    
    return FALSE;
Lionel Ulmer's avatar
Lionel Ulmer committed
196 197
}

198
static SysMouseImpl *alloc_device(REFGUID rguid, IDirectInputImpl *dinput)
Lionel Ulmer's avatar
Lionel Ulmer committed
199
{
200
    SysMouseImpl* newDevice;
201
    LPDIDATAFORMAT df = NULL;
202
    unsigned i;
203 204
    char buffer[20];
    HKEY hkey, appkey;
205

206
    newDevice = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(SysMouseImpl));
207
    if (!newDevice) return NULL;
208 209
    newDevice->base.IDirectInputDevice8A_iface.lpVtbl = &SysMouseAvt;
    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;
Lionel Ulmer's avatar
Lionel Ulmer committed
217

218 219 220 221 222 223 224 225 226 227 228
    get_app_key(&hkey, &appkey);
    if (!get_config_key(hkey, appkey, "MouseWarpOverride", buffer, sizeof(buffer)))
    {
        if (!strcasecmp(buffer, "disable"))
            newDevice->warp_override = WARP_DISABLE;
        else if (!strcasecmp(buffer, "force"))
            newDevice->warp_override = WARP_FORCE_ON;
    }
    if (appkey) RegCloseKey(appkey);
    if (hkey) RegCloseKey(hkey);

229 230 231 232 233 234 235 236 237 238 239 240 241 242
    /* Create copy of default data format */
    if (!(df = HeapAlloc(GetProcessHeap(), 0, c_dfDIMouse2.dwSize))) goto failed;
    memcpy(df, &c_dfDIMouse2, c_dfDIMouse2.dwSize);
    if (!(df->rgodf = HeapAlloc(GetProcessHeap(), 0, df->dwNumObjs * df->dwObjSize))) goto failed;
    memcpy(df->rgodf, c_dfDIMouse2.rgodf, df->dwNumObjs * df->dwObjSize);

    /* Because we don't do any detection yet just modify instance and type */
    for (i = 0; i < df->dwNumObjs; i++)
        if (DIDFT_GETTYPE(df->rgodf[i].dwType) & DIDFT_AXIS)
            df->rgodf[i].dwType = DIDFT_MAKEINSTANCE(i) | DIDFT_RELAXIS;
        else
            df->rgodf[i].dwType = DIDFT_MAKEINSTANCE(i) | DIDFT_PSHBUTTON;

    newDevice->base.data_format.wine_df = df;
243
    IDirectInput_AddRef(&newDevice->base.dinput->IDirectInput7A_iface);
244 245 246 247 248

    EnterCriticalSection(&dinput->crit);
    list_add_tail(&dinput->devices_list, &newDevice->base.entry);
    LeaveCriticalSection(&dinput->crit);

249
    return newDevice;
250

251 252 253
failed:
    if (df) HeapFree(GetProcessHeap(), 0, df->rgodf);
    HeapFree(GetProcessHeap(), 0, df);
254
    HeapFree(GetProcessHeap(), 0, newDevice);
255
    return NULL;
Lionel Ulmer's avatar
Lionel Ulmer committed
256 257
}

258
static HRESULT mousedev_create_device(IDirectInputImpl *dinput, REFGUID rguid, REFIID riid, LPVOID *pdev, int unicode)
Lionel Ulmer's avatar
Lionel Ulmer committed
259
{
260 261
    TRACE("%p %s %s %p %i\n", dinput, debugstr_guid(rguid), debugstr_guid(riid), pdev, unicode);
    *pdev = NULL;
Lionel Ulmer's avatar
Lionel Ulmer committed
262

263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300
    if (IsEqualGUID(&GUID_SysMouse, rguid) ||        /* Generic Mouse */
        IsEqualGUID(&DInput_Wine_Mouse_GUID, rguid)) /* Wine Mouse */
    {
        SysMouseImpl *This;

        if (riid == NULL)
            ;/* nothing */
        else if (IsEqualGUID(&IID_IDirectInputDeviceA,  riid) ||
                 IsEqualGUID(&IID_IDirectInputDevice2A, riid) ||
                 IsEqualGUID(&IID_IDirectInputDevice7A, riid) ||
                 IsEqualGUID(&IID_IDirectInputDevice8A, riid))
        {
            unicode = 0;
        }
        else if (IsEqualGUID(&IID_IDirectInputDeviceW,  riid) ||
                 IsEqualGUID(&IID_IDirectInputDevice2W, riid) ||
                 IsEqualGUID(&IID_IDirectInputDevice7W, riid) ||
                 IsEqualGUID(&IID_IDirectInputDevice8W, riid))
        {
            unicode = 1;
        }
        else
        {
            WARN("no interface\n");
            return DIERR_NOINTERFACE;
        }

        This = alloc_device(rguid, dinput);
        TRACE("Created a Mouse device (%p)\n", This);

        if (!This) return DIERR_OUTOFMEMORY;

        if (unicode)
            *pdev = &This->base.IDirectInputDevice8W_iface;
        else
            *pdev = &This->base.IDirectInputDevice8A_iface;

        return DI_OK;
301
    }
302

303
    return DIERR_DEVICENOTREG;
304
}
305 306

const struct dinput_device mouse_device = {
307
    "Wine mouse driver",
308 309
    mousedev_enum_deviceA,
    mousedev_enum_deviceW,
310
    mousedev_create_device
Lionel Ulmer's avatar
Lionel Ulmer committed
311 312 313 314 315 316
};

/******************************************************************************
 *	SysMouseA (DInput Mouse support)
 */

317
/* low-level mouse hook */
318
static int dinput_mouse_hook( LPDIRECTINPUTDEVICE8A iface, WPARAM wparam, LPARAM lparam )
Lionel Ulmer's avatar
Lionel Ulmer committed
319
{
320
    MSLLHOOKSTRUCT *hook = (MSLLHOOKSTRUCT *)lparam;
321
    SysMouseImpl* This = impl_from_IDirectInputDevice8A(iface);
322
    int wdata = 0, inst_id = -1, ret = 0;
323

324 325
    TRACE("msg %lx @ (%d %d)\n", wparam, hook->pt.x, hook->pt.y);

326
    EnterCriticalSection(&This->base.crit);
327

328 329 330 331 332
    switch(wparam) {
        case WM_MOUSEMOVE:
        {
            POINT pt, pt1;

333
            GetCursorPos(&pt);
334 335 336 337 338 339 340 341 342 343 344
            This->m_state.lX += pt.x = hook->pt.x - pt.x;
            This->m_state.lY += pt.y = hook->pt.y - pt.y;

            if (This->base.data_format.user_df->dwFlags & DIDF_ABSAXIS)
            {
                pt1.x = This->m_state.lX;
                pt1.y = This->m_state.lY;
            } else
                pt1 = pt;

            if (pt.x)
345 346 347 348
            {
                inst_id = DIDFT_MAKEINSTANCE(WINE_MOUSE_X_AXIS_INSTANCE) | DIDFT_RELAXIS;
                wdata = pt1.x;
            }
349
            if (pt.y)
350
            {
351 352
                /* Already have X, need to queue it */
                if (inst_id != -1)
353
                    queue_event(iface, inst_id,
354
                                wdata, GetCurrentTime(), This->base.dinput->evsequence);
355 356 357
                inst_id = DIDFT_MAKEINSTANCE(WINE_MOUSE_Y_AXIS_INSTANCE) | DIDFT_RELAXIS;
                wdata = pt1.y;
            }
358

359 360 361 362 363 364
            if (pt.x || pt.y)
            {
                if ((This->warp_override == WARP_FORCE_ON) ||
                    (This->warp_override != WARP_DISABLE && (This->base.dwCoopLevel & DISCL_EXCLUSIVE)))
                    This->need_warp = TRUE;
            }
365 366
            break;
        }
367 368 369
        case WM_MOUSEWHEEL:
            inst_id = DIDFT_MAKEINSTANCE(WINE_MOUSE_Z_AXIS_INSTANCE) | DIDFT_RELAXIS;
            This->m_state.lZ += wdata = (short)HIWORD(hook->mouseData);
370 371 372
            /* FarCry crashes if it gets a mouse wheel message */
            /* FIXME: should probably filter out other messages too */
            ret = This->clipped;
373
            break;
374
        case WM_LBUTTONDOWN:
375 376
            inst_id = DIDFT_MAKEINSTANCE(WINE_MOUSE_BUTTONS_INSTANCE + 0) | DIDFT_PSHBUTTON;
            This->m_state.rgbButtons[0] = wdata = 0x80;
377 378
	    break;
	case WM_LBUTTONUP:
379 380
            inst_id = DIDFT_MAKEINSTANCE(WINE_MOUSE_BUTTONS_INSTANCE + 0) | DIDFT_PSHBUTTON;
            This->m_state.rgbButtons[0] = wdata = 0x00;
381 382
	    break;
	case WM_RBUTTONDOWN:
383 384
            inst_id = DIDFT_MAKEINSTANCE(WINE_MOUSE_BUTTONS_INSTANCE + 1) | DIDFT_PSHBUTTON;
            This->m_state.rgbButtons[1] = wdata = 0x80;
385 386
	    break;
	case WM_RBUTTONUP:
387 388
            inst_id = DIDFT_MAKEINSTANCE(WINE_MOUSE_BUTTONS_INSTANCE + 1) | DIDFT_PSHBUTTON;
            This->m_state.rgbButtons[1] = wdata = 0x00;
389 390
	    break;
	case WM_MBUTTONDOWN:
391 392
            inst_id = DIDFT_MAKEINSTANCE(WINE_MOUSE_BUTTONS_INSTANCE + 2) | DIDFT_PSHBUTTON;
            This->m_state.rgbButtons[2] = wdata = 0x80;
393 394
	    break;
	case WM_MBUTTONUP:
395 396
            inst_id = DIDFT_MAKEINSTANCE(WINE_MOUSE_BUTTONS_INSTANCE + 2) | DIDFT_PSHBUTTON;
            This->m_state.rgbButtons[2] = wdata = 0x00;
397
	    break;
398 399 400 401 402 403 404 405
        case WM_XBUTTONDOWN:
            inst_id = DIDFT_MAKEINSTANCE(WINE_MOUSE_BUTTONS_INSTANCE + 2 + HIWORD(hook->mouseData)) | DIDFT_PSHBUTTON;
            This->m_state.rgbButtons[2 + HIWORD(hook->mouseData)] = wdata = 0x80;
            break;
        case WM_XBUTTONUP:
            inst_id = DIDFT_MAKEINSTANCE(WINE_MOUSE_BUTTONS_INSTANCE + 2 + HIWORD(hook->mouseData)) | DIDFT_PSHBUTTON;
            This->m_state.rgbButtons[2 + HIWORD(hook->mouseData)] = wdata = 0x00;
            break;
406
    }
407 408


409
    if (inst_id != -1)
410 411
    {
        _dump_mouse_state(&This->m_state);
412
        queue_event(iface, inst_id,
413
                    wdata, GetCurrentTime(), This->base.dinput->evsequence++);
414
    }
415

416
    LeaveCriticalSection(&This->base.crit);
417
    return ret;
Lionel Ulmer's avatar
Lionel Ulmer committed
418 419
}

420
static void warp_check( SysMouseImpl* This, BOOL force )
421 422
{
    DWORD now = GetCurrentTime();
423
    const DWORD interval = This->clipped ? 500 : 10;
424

425
    if (force || (This->need_warp && (now - This->last_warped > interval)))
426
    {
427
        RECT rect, new_rect;
428
        POINT mapped_center;
429

430 431
        This->last_warped = now;
        This->need_warp = FALSE;
432 433
        if (!GetClientRect(This->base.win, &rect)) return;
        MapWindowPoints( This->base.win, 0, (POINT *)&rect, 2 );
434 435
        if (!This->clipped)
        {
436 437 438 439
            mapped_center.x = (rect.left + rect.right) / 2;
            mapped_center.y = (rect.top + rect.bottom) / 2;
            TRACE("Warping mouse to %d - %d\n", mapped_center.x, mapped_center.y);
            SetCursorPos( mapped_center.x, mapped_center.y );
440
        }
441 442
        if (This->base.dwCoopLevel & DISCL_EXCLUSIVE)
        {
443 444 445 446 447
            /* make sure we clip even if the window covers the whole screen */
            rect.left = max( rect.left, GetSystemMetrics( SM_XVIRTUALSCREEN ) + 1 );
            rect.top = max( rect.top, GetSystemMetrics( SM_YVIRTUALSCREEN ) + 1 );
            rect.right = min( rect.right, rect.left + GetSystemMetrics( SM_CXVIRTUALSCREEN ) - 2 );
            rect.bottom = min( rect.bottom, rect.top + GetSystemMetrics( SM_CYVIRTUALSCREEN ) - 2 );
448
            TRACE("Clipping mouse to %s\n", wine_dbgstr_rect( &rect ));
449 450
            ClipCursor( &rect );
            This->clipped = GetClipCursor( &new_rect ) && EqualRect( &rect, &new_rect );
451
        }
452 453 454
    }
}

455

Lionel Ulmer's avatar
Lionel Ulmer committed
456 457 458
/******************************************************************************
  *     Acquire : gets exclusive control of the mouse
  */
459
static HRESULT WINAPI SysMouseWImpl_Acquire(LPDIRECTINPUTDEVICE8W iface)
Lionel Ulmer's avatar
Lionel Ulmer committed
460
{
461
    SysMouseImpl *This = impl_from_IDirectInputDevice8W(iface);
462
    POINT point;
463
    HRESULT res;
464

465
    TRACE("(this=%p)\n",This);
466

467
    if ((res = IDirectInputDevice2WImpl_Acquire(iface)) != DI_OK) return res;
468 469 470

    /* Init the mouse state */
    GetCursorPos( &point );
471 472
    if (This->base.data_format.user_df->dwFlags & DIDF_ABSAXIS)
    {
473 474 475 476 477 478 479 480
      This->m_state.lX = point.x;
      This->m_state.lY = point.y;
    } else {
      This->m_state.lX = 0;
      This->m_state.lY = 0;
      This->org_coords = point;
    }
    This->m_state.lZ = 0;
481 482 483
    This->m_state.rgbButtons[0] = GetKeyState(VK_LBUTTON) & 0x80;
    This->m_state.rgbButtons[1] = GetKeyState(VK_RBUTTON) & 0x80;
    This->m_state.rgbButtons[2] = GetKeyState(VK_MBUTTON) & 0x80;
484

485
    if (This->base.dwCoopLevel & DISCL_EXCLUSIVE)
486
    {
487 488
        ShowCursor(FALSE); /* hide cursor */
        warp_check( This, TRUE );
489
    }
490
    else if (This->warp_override == WARP_FORCE_ON)
491
    {
492 493 494
        /* Need a window to warp mouse in. */
        if (!This->base.win) This->base.win = GetDesktopWindow();
        warp_check( This, TRUE );
Lionel Ulmer's avatar
Lionel Ulmer committed
495
    }
496 497 498 499 500
    else if (This->clipped)
    {
        ClipCursor( NULL );
        This->clipped = FALSE;
    }
501

502
    return DI_OK;
Lionel Ulmer's avatar
Lionel Ulmer committed
503 504
}

505 506 507 508 509 510
static HRESULT WINAPI SysMouseAImpl_Acquire(LPDIRECTINPUTDEVICE8A iface)
{
    SysMouseImpl *This = impl_from_IDirectInputDevice8A(iface);
    return SysMouseWImpl_Acquire(IDirectInputDevice8W_from_impl(This));
}

Lionel Ulmer's avatar
Lionel Ulmer committed
511 512 513
/******************************************************************************
  *     Unacquire : frees the mouse
  */
514
static HRESULT WINAPI SysMouseWImpl_Unacquire(LPDIRECTINPUTDEVICE8W iface)
Lionel Ulmer's avatar
Lionel Ulmer committed
515
{
516
    SysMouseImpl *This = impl_from_IDirectInputDevice8W(iface);
517
    HRESULT res;
518

Lionel Ulmer's avatar
Lionel Ulmer committed
519
    TRACE("(this=%p)\n",This);
520

521
    if ((res = IDirectInputDevice2WImpl_Unacquire(iface)) != DI_OK) return res;
522

523
    if (This->base.dwCoopLevel & DISCL_EXCLUSIVE)
524 525
    {
        ClipCursor(NULL);
526
        ShowCursor(TRUE); /* show cursor */
527
        This->clipped = FALSE;
528
    }
529

530
    /* And put the mouse cursor back where it was at acquire time */
531
    if (This->base.dwCoopLevel & DISCL_EXCLUSIVE || This->warp_override == WARP_FORCE_ON)
532
    {
533 534
        TRACE("warping mouse back to %s\n", wine_dbgstr_point(&This->org_coords));
        SetCursorPos(This->org_coords.x, This->org_coords.y);
535
    }
536

Lionel Ulmer's avatar
Lionel Ulmer committed
537 538 539
    return DI_OK;
}

540 541 542 543 544 545
static HRESULT WINAPI SysMouseAImpl_Unacquire(LPDIRECTINPUTDEVICE8A iface)
{
    SysMouseImpl *This = impl_from_IDirectInputDevice8A(iface);
    return SysMouseWImpl_Unacquire(IDirectInputDevice8W_from_impl(This));
}

Lionel Ulmer's avatar
Lionel Ulmer committed
546 547 548 549 550 551
/******************************************************************************
  *     GetDeviceState : returns the "state" of the mouse.
  *
  *   For the moment, only the "standard" return structure (DIMOUSESTATE) is
  *   supported.
  */
552 553 554
static HRESULT WINAPI SysMouseWImpl_GetDeviceState(LPDIRECTINPUTDEVICE8W iface, DWORD len, LPVOID ptr)
{
    SysMouseImpl *This = impl_from_IDirectInputDevice8W(iface);
555

556
    if(This->base.acquired == 0) return DIERR_NOTACQUIRED;
557

558
    TRACE("(this=%p,0x%08x,%p):\n", This, len, ptr);
559
    _dump_mouse_state(&This->m_state);
560 561

    EnterCriticalSection(&This->base.crit);
562
    /* Copy the current mouse state */
563
    fill_DataFormat(ptr, len, &This->m_state, &This->base.data_format);
564

565
    /* Initialize the buffer when in relative mode */
566 567
    if (!(This->base.data_format.user_df->dwFlags & DIDF_ABSAXIS))
    {
568 569 570 571
	This->m_state.lX = 0;
	This->m_state.lY = 0;
	This->m_state.lZ = 0;
    }
572
    LeaveCriticalSection(&This->base.crit);
573

574 575
    warp_check( This, FALSE );
    return DI_OK;
Lionel Ulmer's avatar
Lionel Ulmer committed
576 577
}

578 579 580 581 582 583
static HRESULT WINAPI SysMouseAImpl_GetDeviceState(LPDIRECTINPUTDEVICE8A iface, DWORD len, LPVOID ptr)
{
    SysMouseImpl *This = impl_from_IDirectInputDevice8A(iface);
    return SysMouseWImpl_GetDeviceState(IDirectInputDevice8W_from_impl(This), len, ptr);
}

Lionel Ulmer's avatar
Lionel Ulmer committed
584
/******************************************************************************
585
  *     GetDeviceData : gets buffered input data.
Lionel Ulmer's avatar
Lionel Ulmer committed
586
  */
587
static HRESULT WINAPI SysMouseWImpl_GetDeviceData(LPDIRECTINPUTDEVICE8W iface,
588 589
        DWORD dodsize, LPDIDEVICEOBJECTDATA dod, LPDWORD entries, DWORD flags)
{
590
    SysMouseImpl *This = impl_from_IDirectInputDevice8W(iface);
591
    HRESULT res;
592

593
    res = IDirectInputDevice2WImpl_GetDeviceData(iface, dodsize, dod, entries, flags);
594
    if (SUCCEEDED(res)) warp_check( This, FALSE );
595
    return res;
Lionel Ulmer's avatar
Lionel Ulmer committed
596 597
}

598 599 600 601 602 603 604
static HRESULT WINAPI SysMouseAImpl_GetDeviceData(LPDIRECTINPUTDEVICE8A iface,
        DWORD dodsize, LPDIDEVICEOBJECTDATA dod, LPDWORD entries, DWORD flags)
{
    SysMouseImpl *This = impl_from_IDirectInputDevice8A(iface);
    return SysMouseWImpl_GetDeviceData(IDirectInputDevice8W_from_impl(This), dodsize, dod, entries, flags);
}

Lionel Ulmer's avatar
Lionel Ulmer committed
605 606 607
/******************************************************************************
  *     GetProperty : get input device properties
  */
608
static HRESULT WINAPI SysMouseWImpl_GetProperty(LPDIRECTINPUTDEVICE8W iface, REFGUID rguid, LPDIPROPHEADER pdiph)
Lionel Ulmer's avatar
Lionel Ulmer committed
609
{
610
    SysMouseImpl *This = impl_from_IDirectInputDevice8W(iface);
611

612 613
    TRACE("(%p) %s,%p\n", This, debugstr_guid(rguid), pdiph);
    _dump_DIPROPHEADER(pdiph);
614

615
    if (IS_DIPROP(rguid)) {
616
	switch (LOWORD(rguid)) {
617
	    case (DWORD_PTR) DIPROP_GRANULARITY: {
618 619 620 621 622 623 624 625
		LPDIPROPDWORD pr = (LPDIPROPDWORD) pdiph;
		
		/* We'll just assume that the app asks about the Z axis */
		pr->dwData = WHEEL_DELTA;
		
		break;
	    }
	      
626
	    case (DWORD_PTR) DIPROP_RANGE: {
627 628 629 630 631 632 633 634 635 636 637 638 639 640
		LPDIPROPRANGE pr = (LPDIPROPRANGE) pdiph;
		
		if ((pdiph->dwHow == DIPH_BYID) &&
		    ((pdiph->dwObj == (DIDFT_MAKEINSTANCE(WINE_MOUSE_X_AXIS_INSTANCE) | DIDFT_RELAXIS)) ||
		     (pdiph->dwObj == (DIDFT_MAKEINSTANCE(WINE_MOUSE_Y_AXIS_INSTANCE) | DIDFT_RELAXIS)))) {
		    /* Querying the range of either the X or the Y axis.  As I do
		       not know the range, do as if the range were
		       unrestricted...*/
		    pr->lMin = DIPROPRANGE_NOMIN;
		    pr->lMax = DIPROPRANGE_NOMAX;
		}
		
		break;
	    }
641

642
	    default:
643
                return IDirectInputDevice2WImpl_GetProperty(iface, rguid, pdiph);
644 645
        }
    }
646

647
    return DI_OK;
Lionel Ulmer's avatar
Lionel Ulmer committed
648 649
}

650 651 652 653 654 655
static HRESULT WINAPI SysMouseAImpl_GetProperty(LPDIRECTINPUTDEVICE8A iface, REFGUID rguid, LPDIPROPHEADER pdiph)
{
    SysMouseImpl *This = impl_from_IDirectInputDevice8A(iface);
    return SysMouseWImpl_GetProperty(IDirectInputDevice8W_from_impl(This), rguid, pdiph);
}

Lionel Ulmer's avatar
Lionel Ulmer committed
656
/******************************************************************************
Austin English's avatar
Austin English committed
657
  *     GetCapabilities : get the device capabilities
Lionel Ulmer's avatar
Lionel Ulmer committed
658
  */
659
static HRESULT WINAPI SysMouseWImpl_GetCapabilities(LPDIRECTINPUTDEVICE8W iface, LPDIDEVCAPS lpDIDevCaps)
Lionel Ulmer's avatar
Lionel Ulmer committed
660
{
661
    SysMouseImpl *This = impl_from_IDirectInputDevice8W(iface);
662 663
    DIDEVCAPS devcaps;

664
    TRACE("(this=%p,%p)\n",This,lpDIDevCaps);
665 666

    if ((lpDIDevCaps->dwSize != sizeof(DIDEVCAPS)) && (lpDIDevCaps->dwSize != sizeof(DIDEVCAPS_DX3))) {
Robert Reif's avatar
Robert Reif committed
667 668
        WARN("invalid parameter\n");
        return DIERR_INVALIDPARAM;
669
    }
670 671

    devcaps.dwSize = lpDIDevCaps->dwSize;
672
    devcaps.dwFlags = DIDC_ATTACHED | DIDC_EMULATED;
673
    if (This->base.dinput->dwVersion >= 0x0800)
674 675 676 677
	devcaps.dwDevType = DI8DEVTYPE_MOUSE | (DI8DEVTYPEMOUSE_TRADITIONAL << 8);
    else
	devcaps.dwDevType = DIDEVTYPE_MOUSE | (DIDEVTYPEMOUSE_TRADITIONAL << 8);
    devcaps.dwAxes = 3;
678
    devcaps.dwButtons = 8;
679 680 681 682 683 684 685 686
    devcaps.dwPOVs = 0;
    devcaps.dwFFSamplePeriod = 0;
    devcaps.dwFFMinTimeResolution = 0;
    devcaps.dwFirmwareRevision = 100;
    devcaps.dwHardwareRevision = 100;
    devcaps.dwFFDriverVersion = 0;

    memcpy(lpDIDevCaps, &devcaps, lpDIDevCaps->dwSize);
687

688
    return DI_OK;
Lionel Ulmer's avatar
Lionel Ulmer committed
689 690
}

691 692 693 694 695 696
static HRESULT WINAPI SysMouseAImpl_GetCapabilities(LPDIRECTINPUTDEVICE8A iface, LPDIDEVCAPS lpDIDevCaps)
{
    SysMouseImpl *This = impl_from_IDirectInputDevice8A(iface);
    return SysMouseWImpl_GetCapabilities(IDirectInputDevice8W_from_impl(This), lpDIDevCaps);
}

697 698 699 700 701 702 703 704
/******************************************************************************
  *     GetObjectInfo : get information about a device object such as a button
  *                     or axis
  */
static HRESULT WINAPI SysMouseWImpl_GetObjectInfo(LPDIRECTINPUTDEVICE8W iface,
        LPDIDEVICEOBJECTINSTANCEW pdidoi, DWORD dwObj, DWORD dwHow)
{
    static const WCHAR x_axisW[] = {'X','-','A','x','i','s',0};
705
    static const WCHAR y_axisW[] = {'Y','-','A','x','i','s',0};
706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725
    static const WCHAR wheelW[] = {'W','h','e','e','l',0};
    static const WCHAR buttonW[] = {'B','u','t','t','o','n',' ','%','d',0};
    HRESULT res;

    res = IDirectInputDevice2WImpl_GetObjectInfo(iface, pdidoi, dwObj, dwHow);
    if (res != DI_OK) return res;

    if      (IsEqualGUID(&pdidoi->guidType, &GUID_XAxis)) strcpyW(pdidoi->tszName, x_axisW);
    else if (IsEqualGUID(&pdidoi->guidType, &GUID_YAxis)) strcpyW(pdidoi->tszName, y_axisW);
    else if (IsEqualGUID(&pdidoi->guidType, &GUID_ZAxis)) strcpyW(pdidoi->tszName, wheelW);
    else if (pdidoi->dwType & DIDFT_BUTTON)
        wsprintfW(pdidoi->tszName, buttonW, DIDFT_GETINSTANCE(pdidoi->dwType) - 3);

    _dump_OBJECTINSTANCEW(pdidoi);
    return res;
}

static HRESULT WINAPI SysMouseAImpl_GetObjectInfo(LPDIRECTINPUTDEVICE8A iface,
        LPDIDEVICEOBJECTINSTANCEA pdidoi, DWORD dwObj, DWORD dwHow)
{
726
    SysMouseImpl *This = impl_from_IDirectInputDevice8A(iface);
727 728 729 730 731
    HRESULT res;
    DIDEVICEOBJECTINSTANCEW didoiW;
    DWORD dwSize = pdidoi->dwSize;

    didoiW.dwSize = sizeof(didoiW);
732
    res = SysMouseWImpl_GetObjectInfo(IDirectInputDevice8W_from_impl(This), &didoiW, dwObj, dwHow);
733 734 735 736 737 738 739 740 741 742
    if (res != DI_OK) return res;

    memset(pdidoi, 0, pdidoi->dwSize);
    memcpy(pdidoi, &didoiW, FIELD_OFFSET(DIDEVICEOBJECTINSTANCEW, tszName));
    pdidoi->dwSize = dwSize;
    WideCharToMultiByte(CP_ACP, 0, didoiW.tszName, -1, pdidoi->tszName,
                        sizeof(pdidoi->tszName), NULL, NULL);

    return res;
}
Lionel Ulmer's avatar
Lionel Ulmer committed
743

744 745 746 747 748 749 750
/******************************************************************************
  *     GetDeviceInfo : get information about a device's identity
  */
static HRESULT WINAPI SysMouseAImpl_GetDeviceInfo(
	LPDIRECTINPUTDEVICE8A iface,
	LPDIDEVICEINSTANCEA pdidi)
{
751
    SysMouseImpl *This = impl_from_IDirectInputDevice8A(iface);
752 753 754
    TRACE("(this=%p,%p)\n", This, pdidi);

    if (pdidi->dwSize != sizeof(DIDEVICEINSTANCEA)) {
755
        WARN(" dinput3 not supported yet...\n");
756 757 758
	return DI_OK;
    }

759
    fill_mouse_dideviceinstanceA(pdidi, This->base.dinput->dwVersion);
760 761 762
    
    return DI_OK;
}
Lionel Ulmer's avatar
Lionel Ulmer committed
763

764 765
static HRESULT WINAPI SysMouseWImpl_GetDeviceInfo(LPDIRECTINPUTDEVICE8W iface, LPDIDEVICEINSTANCEW pdidi)
{
766
    SysMouseImpl *This = impl_from_IDirectInputDevice8W(iface);
767 768 769
    TRACE("(this=%p,%p)\n", This, pdidi);

    if (pdidi->dwSize != sizeof(DIDEVICEINSTANCEW)) {
770
        WARN(" dinput3 not supported yet...\n");
771 772 773
	return DI_OK;
    }

774
    fill_mouse_dideviceinstanceW(pdidi, This->base.dinput->dwVersion);
775 776 777 778
    
    return DI_OK;
}

779 780 781 782 783
static HRESULT WINAPI SysMouseWImpl_BuildActionMap(LPDIRECTINPUTDEVICE8W iface,
                                                   LPDIACTIONFORMATW lpdiaf,
                                                   LPCWSTR lpszUserName,
                                                   DWORD dwFlags)
{
784
    FIXME("(%p)->(%p,%s,%08x): semi-stub !\n", iface, lpdiaf, debugstr_w(lpszUserName), dwFlags);
785

786
    return _build_action_map(iface, lpdiaf, lpszUserName, dwFlags, DIMOUSE_MASK, &c_dfDIMouse2);
787 788 789 790 791 792 793 794 795 796
}

static HRESULT WINAPI SysMouseAImpl_BuildActionMap(LPDIRECTINPUTDEVICE8A iface,
                                                   LPDIACTIONFORMATA lpdiaf,
                                                   LPCSTR lpszUserName,
                                                   DWORD dwFlags)
{
    SysMouseImpl *This = impl_from_IDirectInputDevice8A(iface);
    DIACTIONFORMATW diafW;
    HRESULT hr;
797 798
    WCHAR *lpszUserNameW = NULL;
    int username_size;
799 800 801 802

    diafW.rgoAction = HeapAlloc(GetProcessHeap(), 0, sizeof(DIACTIONW)*lpdiaf->dwNumActions);
    _copy_diactionformatAtoW(&diafW, lpdiaf);

803 804 805 806 807 808 809 810
    if (lpszUserName != NULL)
    {
        username_size = MultiByteToWideChar(CP_ACP, 0, lpszUserName, -1, NULL, 0);
        lpszUserNameW = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR)*username_size);
        MultiByteToWideChar(CP_ACP, 0, lpszUserName, -1, lpszUserNameW, username_size);
    }

    hr = SysMouseWImpl_BuildActionMap(&This->base.IDirectInputDevice8W_iface, &diafW, lpszUserNameW, dwFlags);
811 812 813

    _copy_diactionformatWtoA(lpdiaf, &diafW);
    HeapFree(GetProcessHeap(), 0, diafW.rgoAction);
814
    HeapFree(GetProcessHeap(), 0, lpszUserNameW);
815 816 817

    return hr;
}
818

819 820 821 822 823
static HRESULT WINAPI SysMouseWImpl_SetActionMap(LPDIRECTINPUTDEVICE8W iface,
                                                 LPDIACTIONFORMATW lpdiaf,
                                                 LPCWSTR lpszUserName,
                                                 DWORD dwFlags)
{
824
    FIXME("(%p)->(%p,%s,%08x): semi-stub !\n", iface, lpdiaf, debugstr_w(lpszUserName), dwFlags);
825

826
    return _set_action_map(iface, lpdiaf, lpszUserName, dwFlags, &c_dfDIMouse2);
827 828 829 830 831 832 833 834 835 836
}

static HRESULT WINAPI SysMouseAImpl_SetActionMap(LPDIRECTINPUTDEVICE8A iface,
                                                 LPDIACTIONFORMATA lpdiaf,
                                                 LPCSTR lpszUserName,
                                                 DWORD dwFlags)
{
    SysMouseImpl *This = impl_from_IDirectInputDevice8A(iface);
    DIACTIONFORMATW diafW;
    HRESULT hr;
837 838
    WCHAR *lpszUserNameW = NULL;
    int username_size;
839 840 841 842

    diafW.rgoAction = HeapAlloc(GetProcessHeap(), 0, sizeof(DIACTIONW)*lpdiaf->dwNumActions);
    _copy_diactionformatAtoW(&diafW, lpdiaf);

843 844 845 846 847 848 849 850
    if (lpszUserName != NULL)
    {
        username_size = MultiByteToWideChar(CP_ACP, 0, lpszUserName, -1, NULL, 0);
        lpszUserNameW = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR)*username_size);
        MultiByteToWideChar(CP_ACP, 0, lpszUserName, -1, lpszUserNameW, username_size);
    }

    hr = SysMouseWImpl_SetActionMap(&This->base.IDirectInputDevice8W_iface, &diafW, lpszUserNameW, dwFlags);
851 852

    HeapFree(GetProcessHeap(), 0, diafW.rgoAction);
853
    HeapFree(GetProcessHeap(), 0, lpszUserNameW);
854 855 856 857

    return hr;
}

858
static const IDirectInputDevice8AVtbl SysMouseAvt =
Lionel Ulmer's avatar
Lionel Ulmer committed
859
{
860 861
    IDirectInputDevice2AImpl_QueryInterface,
    IDirectInputDevice2AImpl_AddRef,
862
    IDirectInputDevice2AImpl_Release,
863
    SysMouseAImpl_GetCapabilities,
864
    IDirectInputDevice2AImpl_EnumObjects,
865
    SysMouseAImpl_GetProperty,
866
    IDirectInputDevice2AImpl_SetProperty,
867 868 869 870
    SysMouseAImpl_Acquire,
    SysMouseAImpl_Unacquire,
    SysMouseAImpl_GetDeviceState,
    SysMouseAImpl_GetDeviceData,
871
    IDirectInputDevice2AImpl_SetDataFormat,
872
    IDirectInputDevice2AImpl_SetEventNotification,
873
    IDirectInputDevice2AImpl_SetCooperativeLevel,
874
    SysMouseAImpl_GetObjectInfo,
875 876 877 878 879 880 881 882 883 884 885 886 887 888
    SysMouseAImpl_GetDeviceInfo,
    IDirectInputDevice2AImpl_RunControlPanel,
    IDirectInputDevice2AImpl_Initialize,
    IDirectInputDevice2AImpl_CreateEffect,
    IDirectInputDevice2AImpl_EnumEffects,
    IDirectInputDevice2AImpl_GetEffectInfo,
    IDirectInputDevice2AImpl_GetForceFeedbackState,
    IDirectInputDevice2AImpl_SendForceFeedbackCommand,
    IDirectInputDevice2AImpl_EnumCreatedEffectObjects,
    IDirectInputDevice2AImpl_Escape,
    IDirectInputDevice2AImpl_Poll,
    IDirectInputDevice2AImpl_SendDeviceData,
    IDirectInputDevice7AImpl_EnumEffectsInFile,
    IDirectInputDevice7AImpl_WriteEffectToFile,
889
    SysMouseAImpl_BuildActionMap,
890
    SysMouseAImpl_SetActionMap,
891
    IDirectInputDevice8AImpl_GetImageInfo
Lionel Ulmer's avatar
Lionel Ulmer committed
892
};
893

894
static const IDirectInputDevice8WVtbl SysMouseWvt =
895
{
896
    IDirectInputDevice2WImpl_QueryInterface,
897 898
    IDirectInputDevice2WImpl_AddRef,
    IDirectInputDevice2WImpl_Release,
899
    SysMouseWImpl_GetCapabilities,
900
    IDirectInputDevice2WImpl_EnumObjects,
901
    SysMouseWImpl_GetProperty,
902
    IDirectInputDevice2WImpl_SetProperty,
903 904 905 906
    SysMouseWImpl_Acquire,
    SysMouseWImpl_Unacquire,
    SysMouseWImpl_GetDeviceState,
    SysMouseWImpl_GetDeviceData,
907 908 909
    IDirectInputDevice2WImpl_SetDataFormat,
    IDirectInputDevice2WImpl_SetEventNotification,
    IDirectInputDevice2WImpl_SetCooperativeLevel,
910
    SysMouseWImpl_GetObjectInfo,
911
    SysMouseWImpl_GetDeviceInfo,
912 913 914
    IDirectInputDevice2WImpl_RunControlPanel,
    IDirectInputDevice2WImpl_Initialize,
    IDirectInputDevice2WImpl_CreateEffect,
915 916
    IDirectInputDevice2WImpl_EnumEffects,
    IDirectInputDevice2WImpl_GetEffectInfo,
917 918 919 920 921 922
    IDirectInputDevice2WImpl_GetForceFeedbackState,
    IDirectInputDevice2WImpl_SendForceFeedbackCommand,
    IDirectInputDevice2WImpl_EnumCreatedEffectObjects,
    IDirectInputDevice2WImpl_Escape,
    IDirectInputDevice2WImpl_Poll,
    IDirectInputDevice2WImpl_SendDeviceData,
923 924
    IDirectInputDevice7WImpl_EnumEffectsInFile,
    IDirectInputDevice7WImpl_WriteEffectToFile,
925
    SysMouseWImpl_BuildActionMap,
926
    SysMouseWImpl_SetActionMap,
927
    IDirectInputDevice8WImpl_GetImageInfo
928
};