src/video/windows/SDL_windowsmouse.c
author Sam Lantinga <slouken@libsdl.org>
Tue, 03 Jul 2012 23:52:02 -0400
changeset 6350 19545983ac76
parent 6138 4c64952a58fb
child 6675 20f3cdea0fd2
permissions -rwxr-xr-x
Patrick Baggett implemented relative mouse mode on Win32

Here is my first rough attempt. "testrelative" feels right to me, but I'd like it someone else tested this, especially compared to Linux/OSX. The "Ctrl+r" to switch between relative and normal mouse movements seems to work flawlessly. With relative mouse movement, the only way to change focus is via keyboard. I'm not sure if that is the correct approach, but that would seem to be the most useful mode for games. Still, if my assumption is wrong, I can fix that no problem.
slouken@1895
     1
/*
slouken@5535
     2
  Simple DirectMedia Layer
slouken@6138
     3
  Copyright (C) 1997-2012 Sam Lantinga <slouken@libsdl.org>
slouken@1895
     4
slouken@5535
     5
  This software is provided 'as-is', without any express or implied
slouken@5535
     6
  warranty.  In no event will the authors be held liable for any damages
slouken@5535
     7
  arising from the use of this software.
slouken@1895
     8
slouken@5535
     9
  Permission is granted to anyone to use this software for any purpose,
slouken@5535
    10
  including commercial applications, and to alter it and redistribute it
slouken@5535
    11
  freely, subject to the following restrictions:
slouken@1895
    12
slouken@5535
    13
  1. The origin of this software must not be misrepresented; you must not
slouken@5535
    14
     claim that you wrote the original software. If you use this software
slouken@5535
    15
     in a product, an acknowledgment in the product documentation would be
slouken@5535
    16
     appreciated but is not required.
slouken@5535
    17
  2. Altered source versions must be plainly marked as such, and must not be
slouken@5535
    18
     misrepresented as being the original software.
slouken@5535
    19
  3. This notice may not be removed or altered from any source distribution.
slouken@1895
    20
*/
slouken@6044
    21
#include "SDL_config.h"
slouken@2710
    22
slouken@6044
    23
#if SDL_VIDEO_DRIVER_WINDOWS
slouken@1895
    24
slouken@5472
    25
#include "SDL_assert.h"
slouken@5062
    26
#include "SDL_windowsvideo.h"
slouken@1895
    27
slouken@5421
    28
#include "../../events/SDL_mouse_c.h"
slouken@5421
    29
slouken@5421
    30
slouken@5421
    31
HCURSOR SDL_cursor = NULL;
slouken@5421
    32
slouken@5421
    33
slouken@5421
    34
static SDL_Cursor *
slouken@5421
    35
WIN_CreateDefaultCursor()
slouken@5421
    36
{
slouken@5421
    37
    SDL_Cursor *cursor;
slouken@5421
    38
slouken@5421
    39
    cursor = SDL_calloc(1, sizeof(*cursor));
slouken@5421
    40
    if (cursor) {
slouken@5421
    41
        cursor->driverdata = LoadCursor(NULL, IDC_ARROW);
slouken@5421
    42
    } else {
slouken@5421
    43
        SDL_OutOfMemory();
slouken@5421
    44
    }
slouken@5421
    45
slouken@5421
    46
    return cursor;
slouken@5421
    47
}
slouken@5421
    48
slouken@5421
    49
static SDL_Cursor *
slouken@5421
    50
WIN_CreateCursor(SDL_Surface * surface, int hot_x, int hot_y)
slouken@5421
    51
{
slouken@5421
    52
    SDL_Cursor *cursor;
slouken@5421
    53
    HICON hicon;
slouken@5421
    54
    HDC hdc;
slouken@5421
    55
    BITMAPV4HEADER bmh;
slouken@5421
    56
    LPVOID pixels;
slouken@5421
    57
    ICONINFO ii;
slouken@5421
    58
slouken@5421
    59
    SDL_zero(bmh);
slouken@5421
    60
    bmh.bV4Size = sizeof(bmh);
slouken@5421
    61
    bmh.bV4Width = surface->w;
slouken@5421
    62
    bmh.bV4Height = -surface->h; /* Invert the image */
slouken@5421
    63
    bmh.bV4Planes = 1;
slouken@5421
    64
    bmh.bV4BitCount = 32;
slouken@5421
    65
    bmh.bV4V4Compression = BI_BITFIELDS;
slouken@5421
    66
    bmh.bV4AlphaMask = 0xFF000000;
slouken@5421
    67
    bmh.bV4RedMask   = 0x00FF0000;
slouken@5421
    68
    bmh.bV4GreenMask = 0x0000FF00;
slouken@5421
    69
    bmh.bV4BlueMask  = 0x000000FF;
slouken@5421
    70
slouken@5421
    71
    hdc = GetDC(NULL);
slouken@5421
    72
    SDL_zero(ii);
slouken@5421
    73
    ii.fIcon = FALSE;
slouken@5421
    74
    ii.xHotspot = (DWORD)hot_x;
slouken@5421
    75
    ii.yHotspot = (DWORD)hot_y;
slouken@5421
    76
    ii.hbmColor = CreateDIBSection(hdc, (BITMAPINFO*)&bmh, DIB_RGB_COLORS, &pixels, NULL, 0);
slouken@5421
    77
    ii.hbmMask = CreateBitmap(surface->w, surface->h, 1, 1, NULL);
slouken@5421
    78
    ReleaseDC(NULL, hdc);
slouken@5421
    79
slouken@5472
    80
    SDL_assert(surface->format->format == SDL_PIXELFORMAT_ARGB8888);
slouken@5472
    81
    SDL_assert(surface->pitch == surface->w * 4);
slouken@5472
    82
    SDL_memcpy(pixels, surface->pixels, surface->h * surface->pitch);
slouken@5421
    83
slouken@5421
    84
    hicon = CreateIconIndirect(&ii);
slouken@5421
    85
slouken@5421
    86
    DeleteObject(ii.hbmColor);
slouken@5421
    87
    DeleteObject(ii.hbmMask);
slouken@5421
    88
slouken@5421
    89
    if (!hicon) {
slouken@5421
    90
        WIN_SetError("CreateIconIndirect()");
slouken@5421
    91
        return NULL;
slouken@5421
    92
    }
slouken@5421
    93
slouken@5421
    94
    cursor = SDL_calloc(1, sizeof(*cursor));
slouken@5421
    95
    if (cursor) {
slouken@5421
    96
        cursor->driverdata = hicon;
slouken@5421
    97
    } else {
slouken@5421
    98
        DestroyIcon(hicon);
slouken@5421
    99
        SDL_OutOfMemory();
slouken@5421
   100
    }
slouken@5421
   101
slouken@5421
   102
    return cursor;
slouken@5421
   103
}
slouken@5421
   104
slouken@5421
   105
static void
slouken@5421
   106
WIN_FreeCursor(SDL_Cursor * cursor)
slouken@5421
   107
{
slouken@5421
   108
    HICON hicon = (HICON)cursor->driverdata;
slouken@5421
   109
slouken@5421
   110
    DestroyIcon(hicon);
slouken@5421
   111
    SDL_free(cursor);
slouken@5421
   112
}
slouken@5421
   113
slouken@5421
   114
static int
slouken@5421
   115
WIN_ShowCursor(SDL_Cursor * cursor)
slouken@5421
   116
{
slouken@5421
   117
    if (cursor) {
slouken@5421
   118
        SDL_cursor = (HCURSOR)cursor->driverdata;
slouken@5421
   119
    } else {
slouken@5421
   120
        SDL_cursor = NULL;
slouken@5421
   121
    }
slouken@5421
   122
    if (SDL_GetMouseFocus() != NULL) {
slouken@5421
   123
        SetCursor(SDL_cursor);
slouken@5421
   124
    }
slouken@5421
   125
    return 0;
slouken@5421
   126
}
slouken@5421
   127
slouken@5421
   128
static void
slouken@5421
   129
WIN_WarpMouse(SDL_Window * window, int x, int y)
slouken@5421
   130
{
slouken@5421
   131
    HWND hwnd = ((SDL_WindowData *) window->driverdata)->hwnd;
slouken@5421
   132
    POINT pt;
slouken@5421
   133
slouken@5421
   134
    pt.x = x;
slouken@5421
   135
    pt.y = y;
slouken@5421
   136
    ClientToScreen(hwnd, &pt);
slouken@5421
   137
    SetCursorPos(pt.x, pt.y);
slouken@5421
   138
}
slouken@5421
   139
slouken@5421
   140
static int
slouken@5421
   141
WIN_SetRelativeMouseMode(SDL_bool enabled)
slouken@5421
   142
{
slouken@6350
   143
    RAWINPUTDEVICE rawMouse = { 0x01, 0x02, 0, NULL }; /* Mouse: UsagePage = 1, Usage = 2 */
slouken@6350
   144
	HWND hWnd;
slouken@6350
   145
	hWnd = GetActiveWindow();
slouken@6350
   146
slouken@6350
   147
	rawMouse.hwndTarget = hWnd;
slouken@6350
   148
	if(!enabled) {
slouken@6350
   149
		rawMouse.dwFlags |= RIDEV_REMOVE;
slouken@6350
   150
		rawMouse.hwndTarget = NULL;
slouken@6350
   151
	}
slouken@6350
   152
slouken@6350
   153
slouken@6350
   154
	/* (Un)register raw input for mice */
slouken@6350
   155
	if(RegisterRawInputDevices(&rawMouse, 1, sizeof(RAWINPUTDEVICE)) == FALSE) {
slouken@6350
   156
slouken@6350
   157
		/* Only return an error when registering. If we unregister and fail, then
slouken@6350
   158
		it's probably that we unregistered twice. That's OK. */
slouken@6350
   159
		if(enabled) {
slouken@6350
   160
			SDL_Unsupported();
slouken@6350
   161
			return -1;
slouken@6350
   162
		}
slouken@6350
   163
	}
slouken@6350
   164
slouken@6350
   165
	if(enabled) {
slouken@6350
   166
		LONG cx, cy;
slouken@6350
   167
		RECT rect;
slouken@6350
   168
		GetWindowRect(hWnd, &rect);
slouken@6350
   169
slouken@6350
   170
		cx = (rect.left + rect.right) / 2;
slouken@6350
   171
		cy = (rect.top + rect.bottom) / 2;
slouken@6350
   172
slouken@6350
   173
		/* Make an absurdly small clip rect */
slouken@6350
   174
		rect.left = cx-1;
slouken@6350
   175
		rect.right = cx+1;
slouken@6350
   176
		rect.top = cy-1;
slouken@6350
   177
		rect.bottom = cy+1;
slouken@6350
   178
slouken@6350
   179
		ClipCursor(&rect);
slouken@6350
   180
	}
slouken@6350
   181
	else
slouken@6350
   182
		ClipCursor(NULL);
slouken@6350
   183
slouken@6350
   184
    return 0;
slouken@5421
   185
}
slouken@5421
   186
slouken@1895
   187
void
slouken@1895
   188
WIN_InitMouse(_THIS)
slouken@1895
   189
{
slouken@5421
   190
    SDL_Mouse *mouse = SDL_GetMouse();
slouken@5421
   191
slouken@5421
   192
    mouse->CreateCursor = WIN_CreateCursor;
slouken@5421
   193
    mouse->ShowCursor = WIN_ShowCursor;
slouken@5421
   194
    mouse->FreeCursor = WIN_FreeCursor;
slouken@5421
   195
    mouse->WarpMouse = WIN_WarpMouse;
slouken@5421
   196
    mouse->SetRelativeMouseMode = WIN_SetRelativeMouseMode;
slouken@5421
   197
slouken@5421
   198
    SDL_SetDefaultCursor(WIN_CreateDefaultCursor());
slouken@1895
   199
}
slouken@1895
   200
slouken@1895
   201
void
slouken@1895
   202
WIN_QuitMouse(_THIS)
slouken@1895
   203
{
slouken@1895
   204
}
slouken@1895
   205
slouken@6044
   206
#endif /* SDL_VIDEO_DRIVER_WINDOWS */
slouken@6044
   207
slouken@1895
   208
/* vi: set ts=4 sw=4 expandtab: */