src/video/windows/SDL_windowsmouse.c
author Sam Lantinga <slouken@libsdl.org>
Sun, 02 Feb 2014 00:53:27 -0800
changeset 8149 681eb46b8ac4
parent 8093 b43765095a6f
child 8252 3e4846dc97b1
permissions -rw-r--r--
Fixed bug 2374 - Update copyright for 2014...

Is it that time already??
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2014 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_internal.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     /* msdn says cursor mask has to be padded out to word alignment. Not sure
    53         if that means machine word or WORD, but this handles either case. */
    54     const size_t pad = (sizeof (size_t) * 8);  /* 32 or 64, or whatever. */
    55     SDL_Cursor *cursor;
    56     HICON hicon;
    57     HDC hdc;
    58     BITMAPV4HEADER bmh;
    59     LPVOID pixels;
    60     LPVOID maskbits;
    61     size_t maskbitslen;
    62     ICONINFO ii;
    63 
    64     SDL_zero(bmh);
    65     bmh.bV4Size = sizeof(bmh);
    66     bmh.bV4Width = surface->w;
    67     bmh.bV4Height = -surface->h; /* Invert the image */
    68     bmh.bV4Planes = 1;
    69     bmh.bV4BitCount = 32;
    70     bmh.bV4V4Compression = BI_BITFIELDS;
    71     bmh.bV4AlphaMask = 0xFF000000;
    72     bmh.bV4RedMask   = 0x00FF0000;
    73     bmh.bV4GreenMask = 0x0000FF00;
    74     bmh.bV4BlueMask  = 0x000000FF;
    75 
    76     maskbitslen = ((surface->w + (pad - (surface->w % pad))) / 8) * surface->h;
    77     maskbits = SDL_stack_alloc(Uint8,maskbitslen);
    78     if (maskbits == NULL) {
    79         SDL_OutOfMemory();
    80         return NULL;
    81     }
    82 
    83     /* AND the cursor against full bits: no change. We already have alpha. */
    84     SDL_memset(maskbits, 0xFF, maskbitslen);
    85 
    86     hdc = GetDC(NULL);
    87     SDL_zero(ii);
    88     ii.fIcon = FALSE;
    89     ii.xHotspot = (DWORD)hot_x;
    90     ii.yHotspot = (DWORD)hot_y;
    91     ii.hbmColor = CreateDIBSection(hdc, (BITMAPINFO*)&bmh, DIB_RGB_COLORS, &pixels, NULL, 0);
    92     ii.hbmMask = CreateBitmap(surface->w, surface->h, 1, 1, maskbits);
    93     ReleaseDC(NULL, hdc);
    94     SDL_stack_free(maskbits);
    95 
    96     SDL_assert(surface->format->format == SDL_PIXELFORMAT_ARGB8888);
    97     SDL_assert(surface->pitch == surface->w * 4);
    98     SDL_memcpy(pixels, surface->pixels, surface->h * surface->pitch);
    99 
   100     hicon = CreateIconIndirect(&ii);
   101 
   102     DeleteObject(ii.hbmColor);
   103     DeleteObject(ii.hbmMask);
   104 
   105     if (!hicon) {
   106         WIN_SetError("CreateIconIndirect()");
   107         return NULL;
   108     }
   109 
   110     cursor = SDL_calloc(1, sizeof(*cursor));
   111     if (cursor) {
   112         cursor->driverdata = hicon;
   113     } else {
   114         DestroyIcon(hicon);
   115         SDL_OutOfMemory();
   116     }
   117 
   118     return cursor;
   119 }
   120 
   121 static SDL_Cursor *
   122 WIN_CreateSystemCursor(SDL_SystemCursor id)
   123 {
   124     SDL_Cursor *cursor;
   125     LPCTSTR name;
   126 
   127     switch(id)
   128     {
   129     default:
   130         SDL_assert(0);
   131         return NULL;
   132     case SDL_SYSTEM_CURSOR_ARROW:     name = IDC_ARROW; break;
   133     case SDL_SYSTEM_CURSOR_IBEAM:     name = IDC_IBEAM; break;
   134     case SDL_SYSTEM_CURSOR_WAIT:      name = IDC_WAIT; break;
   135     case SDL_SYSTEM_CURSOR_CROSSHAIR: name = IDC_CROSS; break;
   136     case SDL_SYSTEM_CURSOR_WAITARROW: name = IDC_WAIT; break;
   137     case SDL_SYSTEM_CURSOR_SIZENWSE:  name = IDC_SIZENWSE; break;
   138     case SDL_SYSTEM_CURSOR_SIZENESW:  name = IDC_SIZENESW; break;
   139     case SDL_SYSTEM_CURSOR_SIZEWE:    name = IDC_SIZEWE; break;
   140     case SDL_SYSTEM_CURSOR_SIZENS:    name = IDC_SIZENS; break;
   141     case SDL_SYSTEM_CURSOR_SIZEALL:   name = IDC_SIZEALL; break;
   142     case SDL_SYSTEM_CURSOR_NO:        name = IDC_NO; break;
   143     case SDL_SYSTEM_CURSOR_HAND:      name = IDC_HAND; break;
   144     }
   145 
   146     cursor = SDL_calloc(1, sizeof(*cursor));
   147     if (cursor) {
   148         HICON hicon;
   149 
   150         hicon = LoadCursor(NULL, name);
   151 
   152         cursor->driverdata = hicon;
   153     } else {
   154         SDL_OutOfMemory();
   155     }
   156 
   157     return cursor;
   158 }
   159 
   160 static void
   161 WIN_FreeCursor(SDL_Cursor * cursor)
   162 {
   163     HICON hicon = (HICON)cursor->driverdata;
   164 
   165     DestroyIcon(hicon);
   166     SDL_free(cursor);
   167 }
   168 
   169 static int
   170 WIN_ShowCursor(SDL_Cursor * cursor)
   171 {
   172     if (cursor) {
   173         SDL_cursor = (HCURSOR)cursor->driverdata;
   174     } else {
   175         SDL_cursor = NULL;
   176     }
   177     if (SDL_GetMouseFocus() != NULL) {
   178         SetCursor(SDL_cursor);
   179     }
   180     return 0;
   181 }
   182 
   183 static void
   184 WIN_WarpMouse(SDL_Window * window, int x, int y)
   185 {
   186     HWND hwnd = ((SDL_WindowData *) window->driverdata)->hwnd;
   187     POINT pt;
   188 
   189     pt.x = x;
   190     pt.y = y;
   191     ClientToScreen(hwnd, &pt);
   192     SetCursorPos(pt.x, pt.y);
   193 }
   194 
   195 static int
   196 WIN_SetRelativeMouseMode(SDL_bool enabled)
   197 {
   198     RAWINPUTDEVICE rawMouse = { 0x01, 0x02, 0, NULL }; /* Mouse: UsagePage = 1, Usage = 2 */
   199     HWND hWnd;
   200     hWnd = GetActiveWindow();
   201 
   202     rawMouse.hwndTarget = hWnd;
   203     if(!enabled) {
   204         rawMouse.dwFlags |= RIDEV_REMOVE;
   205         rawMouse.hwndTarget = NULL;
   206     }
   207 
   208 
   209     /* (Un)register raw input for mice */
   210     if (RegisterRawInputDevices(&rawMouse, 1, sizeof(RAWINPUTDEVICE)) == FALSE) {
   211 
   212         /* Only return an error when registering. If we unregister and fail, then
   213         it's probably that we unregistered twice. That's OK. */
   214         if(enabled) {
   215             return SDL_Unsupported();
   216         }
   217     }
   218 
   219     if (enabled) {
   220         LONG cx, cy;
   221         RECT rect;
   222         GetWindowRect(hWnd, &rect);
   223 
   224         cx = (rect.left + rect.right) / 2;
   225         cy = (rect.top + rect.bottom) / 2;
   226 
   227         /* Make an absurdly small clip rect */
   228         rect.left = cx-1;
   229         rect.right = cx+1;
   230         rect.top = cy-1;
   231         rect.bottom = cy+1;
   232 
   233         ClipCursor(&rect);
   234     } else {
   235         ClipCursor(NULL);
   236     }
   237     return 0;
   238 }
   239 
   240 void
   241 WIN_InitMouse(_THIS)
   242 {
   243     SDL_Mouse *mouse = SDL_GetMouse();
   244 
   245     mouse->CreateCursor = WIN_CreateCursor;
   246     mouse->CreateSystemCursor = WIN_CreateSystemCursor;
   247     mouse->ShowCursor = WIN_ShowCursor;
   248     mouse->FreeCursor = WIN_FreeCursor;
   249     mouse->WarpMouse = WIN_WarpMouse;
   250     mouse->SetRelativeMouseMode = WIN_SetRelativeMouseMode;
   251 
   252     SDL_SetDefaultCursor(WIN_CreateDefaultCursor());
   253 
   254     SDL_SetDoubleClickTime(GetDoubleClickTime());
   255 }
   256 
   257 void
   258 WIN_QuitMouse(_THIS)
   259 {
   260     SDL_Mouse *mouse = SDL_GetMouse();
   261     if ( mouse->def_cursor ) {
   262         SDL_free(mouse->def_cursor);
   263         mouse->def_cursor = NULL;
   264         mouse->cur_cursor = NULL;
   265     }
   266 }
   267 
   268 #endif /* SDL_VIDEO_DRIVER_WINDOWS */
   269 
   270 /* vi: set ts=4 sw=4 expandtab: */