src/video/windows/SDL_windowsmouse.c
author Gabriel Jacobo <gabomdq@gmail.com>
Wed, 24 Apr 2013 12:22:08 -0300
changeset 7103 9d146930d4f2
parent 7037 3fedf1f25b94
child 7191 75360622e65f
permissions -rw-r--r--
Bug 1787 - memory leak in WIN_InitMouse() by Marcel Bakker
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2013 Sam Lantinga <slouken@libsdl.org>
     4 
     5   This software is provided 'as-is', without any express or implied
     6   warranty.  In no event will the authors be held liable for any damages
     7   arising from the use of this software.
     8 
     9   Permission is granted to anyone to use this software for any purpose,
    10   including commercial applications, and to alter it and redistribute it
    11   freely, subject to the following restrictions:
    12 
    13   1. The origin of this software must not be misrepresented; you must not
    14      claim that you wrote the original software. If you use this software
    15      in a product, an acknowledgment in the product documentation would be
    16      appreciated but is not required.
    17   2. Altered source versions must be plainly marked as such, and must not be
    18      misrepresented as being the original software.
    19   3. This notice may not be removed or altered from any source distribution.
    20 */
    21 #include "SDL_config.h"
    22 
    23 #if SDL_VIDEO_DRIVER_WINDOWS
    24 
    25 #include "SDL_assert.h"
    26 #include "SDL_windowsvideo.h"
    27 
    28 #include "../../events/SDL_mouse_c.h"
    29 
    30 
    31 HCURSOR SDL_cursor = NULL;
    32 
    33 
    34 static SDL_Cursor *
    35 WIN_CreateDefaultCursor()
    36 {
    37     SDL_Cursor *cursor;
    38 
    39     cursor = SDL_calloc(1, sizeof(*cursor));
    40     if (cursor) {
    41         cursor->driverdata = LoadCursor(NULL, IDC_ARROW);
    42     } else {
    43         SDL_OutOfMemory();
    44     }
    45 
    46     return cursor;
    47 }
    48 
    49 static SDL_Cursor *
    50 WIN_CreateCursor(SDL_Surface * surface, int hot_x, int hot_y)
    51 {
    52     SDL_Cursor *cursor;
    53     HICON hicon;
    54     HDC hdc;
    55     BITMAPV4HEADER bmh;
    56     LPVOID pixels;
    57     ICONINFO ii;
    58 
    59     SDL_zero(bmh);
    60     bmh.bV4Size = sizeof(bmh);
    61     bmh.bV4Width = surface->w;
    62     bmh.bV4Height = -surface->h; /* Invert the image */
    63     bmh.bV4Planes = 1;
    64     bmh.bV4BitCount = 32;
    65     bmh.bV4V4Compression = BI_BITFIELDS;
    66     bmh.bV4AlphaMask = 0xFF000000;
    67     bmh.bV4RedMask   = 0x00FF0000;
    68     bmh.bV4GreenMask = 0x0000FF00;
    69     bmh.bV4BlueMask  = 0x000000FF;
    70 
    71     hdc = GetDC(NULL);
    72     SDL_zero(ii);
    73     ii.fIcon = FALSE;
    74     ii.xHotspot = (DWORD)hot_x;
    75     ii.yHotspot = (DWORD)hot_y;
    76     ii.hbmColor = CreateDIBSection(hdc, (BITMAPINFO*)&bmh, DIB_RGB_COLORS, &pixels, NULL, 0);
    77     ii.hbmMask = CreateBitmap(surface->w, surface->h, 1, 1, NULL);
    78     ReleaseDC(NULL, hdc);
    79 
    80     SDL_assert(surface->format->format == SDL_PIXELFORMAT_ARGB8888);
    81     SDL_assert(surface->pitch == surface->w * 4);
    82     SDL_memcpy(pixels, surface->pixels, surface->h * surface->pitch);
    83 
    84     hicon = CreateIconIndirect(&ii);
    85 
    86     DeleteObject(ii.hbmColor);
    87     DeleteObject(ii.hbmMask);
    88 
    89     if (!hicon) {
    90         WIN_SetError("CreateIconIndirect()");
    91         return NULL;
    92     }
    93 
    94     cursor = SDL_calloc(1, sizeof(*cursor));
    95     if (cursor) {
    96         cursor->driverdata = hicon;
    97     } else {
    98         DestroyIcon(hicon);
    99         SDL_OutOfMemory();
   100     }
   101 
   102     return cursor;
   103 }
   104 
   105 static SDL_Cursor *
   106 WIN_CreateSystemCursor(SDL_SystemCursor id)
   107 {
   108     SDL_Cursor *cursor;
   109     LPCTSTR name;
   110 
   111     switch(id)
   112     {
   113     default:
   114         SDL_assert(0);
   115         return NULL;
   116     case SDL_SYSTEM_CURSOR_ARROW:     name = IDC_ARROW; break;
   117     case SDL_SYSTEM_CURSOR_IBEAM:     name = IDC_IBEAM; break;
   118     case SDL_SYSTEM_CURSOR_WAIT:      name = IDC_WAIT; break;
   119     case SDL_SYSTEM_CURSOR_CROSSHAIR: name = IDC_CROSS; break;
   120     case SDL_SYSTEM_CURSOR_WAITARROW: name = IDC_WAIT; break;
   121     case SDL_SYSTEM_CURSOR_SIZENWSE:  name = IDC_SIZENWSE; break;
   122     case SDL_SYSTEM_CURSOR_SIZENESW:  name = IDC_SIZENESW; break;
   123     case SDL_SYSTEM_CURSOR_SIZEWE:    name = IDC_SIZEWE; break;
   124     case SDL_SYSTEM_CURSOR_SIZENS:    name = IDC_SIZENS; break;
   125     case SDL_SYSTEM_CURSOR_SIZEALL:   name = IDC_SIZEALL; break;
   126     case SDL_SYSTEM_CURSOR_NO:        name = IDC_NO; break;
   127     case SDL_SYSTEM_CURSOR_HAND:      name = IDC_HAND; break;
   128     }
   129 
   130     cursor = SDL_calloc(1, sizeof(*cursor));
   131     if (cursor) {
   132         HICON hicon;
   133 
   134         hicon = LoadCursor(NULL, name);
   135 
   136         cursor->driverdata = hicon;
   137     } else {
   138         SDL_OutOfMemory();
   139     }
   140 
   141     return cursor;
   142 }
   143 
   144 static void
   145 WIN_FreeCursor(SDL_Cursor * cursor)
   146 {
   147     HICON hicon = (HICON)cursor->driverdata;
   148 
   149     DestroyIcon(hicon);
   150     SDL_free(cursor);
   151 }
   152 
   153 static int
   154 WIN_ShowCursor(SDL_Cursor * cursor)
   155 {
   156     if (cursor) {
   157         SDL_cursor = (HCURSOR)cursor->driverdata;
   158     } else {
   159         SDL_cursor = NULL;
   160     }
   161     if (SDL_GetMouseFocus() != NULL) {
   162         SetCursor(SDL_cursor);
   163     }
   164     return 0;
   165 }
   166 
   167 static void
   168 WIN_WarpMouse(SDL_Window * window, int x, int y)
   169 {
   170     HWND hwnd = ((SDL_WindowData *) window->driverdata)->hwnd;
   171     POINT pt;
   172 
   173     pt.x = x;
   174     pt.y = y;
   175     ClientToScreen(hwnd, &pt);
   176     SetCursorPos(pt.x, pt.y);
   177 }
   178 
   179 static int
   180 WIN_SetRelativeMouseMode(SDL_bool enabled)
   181 {
   182     RAWINPUTDEVICE rawMouse = { 0x01, 0x02, 0, NULL }; /* Mouse: UsagePage = 1, Usage = 2 */
   183 	HWND hWnd;
   184 	hWnd = GetActiveWindow();
   185 
   186 	rawMouse.hwndTarget = hWnd;
   187 	if(!enabled) {
   188 		rawMouse.dwFlags |= RIDEV_REMOVE;
   189 		rawMouse.hwndTarget = NULL;
   190 	}
   191 
   192 
   193 	/* (Un)register raw input for mice */
   194 	if(RegisterRawInputDevices(&rawMouse, 1, sizeof(RAWINPUTDEVICE)) == FALSE) {
   195 
   196 		/* Only return an error when registering. If we unregister and fail, then
   197 		it's probably that we unregistered twice. That's OK. */
   198 		if(enabled) {
   199 			return SDL_Unsupported();
   200 		}
   201 	}
   202 
   203 	if(enabled) {
   204 		LONG cx, cy;
   205 		RECT rect;
   206 		GetWindowRect(hWnd, &rect);
   207 
   208 		cx = (rect.left + rect.right) / 2;
   209 		cy = (rect.top + rect.bottom) / 2;
   210 
   211 		/* Make an absurdly small clip rect */
   212 		rect.left = cx-1;
   213 		rect.right = cx+1;
   214 		rect.top = cy-1;
   215 		rect.bottom = cy+1;
   216 
   217 		ClipCursor(&rect);
   218 	}
   219 	else
   220 		ClipCursor(NULL);
   221 
   222     return 0;
   223 }
   224 
   225 void
   226 WIN_InitMouse(_THIS)
   227 {
   228     SDL_Mouse *mouse = SDL_GetMouse();
   229 
   230     mouse->CreateCursor = WIN_CreateCursor;
   231 	mouse->CreateSystemCursor = WIN_CreateSystemCursor;
   232     mouse->ShowCursor = WIN_ShowCursor;
   233     mouse->FreeCursor = WIN_FreeCursor;
   234     mouse->WarpMouse = WIN_WarpMouse;
   235     mouse->SetRelativeMouseMode = WIN_SetRelativeMouseMode;
   236 
   237     SDL_SetDefaultCursor(WIN_CreateDefaultCursor());
   238 }
   239 
   240 void
   241 WIN_QuitMouse(_THIS)
   242 {
   243     SDL_Mouse *mouse = SDL_GetMouse();
   244     if ( mouse->def_cursor ) {
   245         SDL_free(mouse->def_cursor);
   246         mouse->def_cursor = NULL;
   247         mouse->cur_cursor = NULL;
   248     }
   249 }
   250 
   251 #endif /* SDL_VIDEO_DRIVER_WINDOWS */
   252 
   253 /* vi: set ts=4 sw=4 expandtab: */