src/video/windows/SDL_windowsmouse.c
author Sam Lantinga <slouken@libsdl.org>
Mon, 07 Jul 2014 10:26:28 -0700
changeset 8976 1a5d959d7b32
parent 8956 a99e30f2bf0a
child 9619 b94b6d0bff0f
permissions -rw-r--r--
Fixed mingw64 build and warnings
     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 static int rawInputEnableCount = 0;
    34 
    35 static int 
    36 ToggleRawInput(SDL_bool enabled)
    37 {
    38     RAWINPUTDEVICE rawMouse = { 0x01, 0x02, 0, NULL }; /* Mouse: UsagePage = 1, Usage = 2 */
    39 
    40     if (enabled) {
    41         rawInputEnableCount++;
    42         if (rawInputEnableCount > 1) {
    43             return 0;  /* already done. */
    44         }
    45     } else {
    46         if (rawInputEnableCount == 0) {
    47             return 0;  /* already done. */
    48         }
    49         rawInputEnableCount--;
    50         if (rawInputEnableCount > 0) {
    51             return 0;  /* not time to disable yet */
    52         }
    53     }
    54 
    55     if (!enabled) {
    56         rawMouse.dwFlags |= RIDEV_REMOVE;
    57     }
    58 
    59     /* (Un)register raw input for mice */
    60     if (RegisterRawInputDevices(&rawMouse, 1, sizeof(RAWINPUTDEVICE)) == FALSE) {
    61 
    62         /* Only return an error when registering. If we unregister and fail,
    63            then it's probably that we unregistered twice. That's OK. */
    64         if (enabled) {
    65             return SDL_Unsupported();
    66         }
    67     }
    68     return 0;
    69 }
    70 
    71 
    72 static SDL_Cursor *
    73 WIN_CreateDefaultCursor()
    74 {
    75     SDL_Cursor *cursor;
    76 
    77     cursor = SDL_calloc(1, sizeof(*cursor));
    78     if (cursor) {
    79         cursor->driverdata = LoadCursor(NULL, IDC_ARROW);
    80     } else {
    81         SDL_OutOfMemory();
    82     }
    83 
    84     return cursor;
    85 }
    86 
    87 static SDL_Cursor *
    88 WIN_CreateCursor(SDL_Surface * surface, int hot_x, int hot_y)
    89 {
    90     /* msdn says cursor mask has to be padded out to word alignment. Not sure
    91         if that means machine word or WORD, but this handles either case. */
    92     const size_t pad = (sizeof (size_t) * 8);  /* 32 or 64, or whatever. */
    93     SDL_Cursor *cursor;
    94     HICON hicon;
    95     HDC hdc;
    96     BITMAPV4HEADER bmh;
    97     LPVOID pixels;
    98     LPVOID maskbits;
    99     size_t maskbitslen;
   100     ICONINFO ii;
   101 
   102     SDL_zero(bmh);
   103     bmh.bV4Size = sizeof(bmh);
   104     bmh.bV4Width = surface->w;
   105     bmh.bV4Height = -surface->h; /* Invert the image */
   106     bmh.bV4Planes = 1;
   107     bmh.bV4BitCount = 32;
   108     bmh.bV4V4Compression = BI_BITFIELDS;
   109     bmh.bV4AlphaMask = 0xFF000000;
   110     bmh.bV4RedMask   = 0x00FF0000;
   111     bmh.bV4GreenMask = 0x0000FF00;
   112     bmh.bV4BlueMask  = 0x000000FF;
   113 
   114     maskbitslen = ((surface->w + (pad - (surface->w % pad))) / 8) * surface->h;
   115     maskbits = SDL_stack_alloc(Uint8,maskbitslen);
   116     if (maskbits == NULL) {
   117         SDL_OutOfMemory();
   118         return NULL;
   119     }
   120 
   121     /* AND the cursor against full bits: no change. We already have alpha. */
   122     SDL_memset(maskbits, 0xFF, maskbitslen);
   123 
   124     hdc = GetDC(NULL);
   125     SDL_zero(ii);
   126     ii.fIcon = FALSE;
   127     ii.xHotspot = (DWORD)hot_x;
   128     ii.yHotspot = (DWORD)hot_y;
   129     ii.hbmColor = CreateDIBSection(hdc, (BITMAPINFO*)&bmh, DIB_RGB_COLORS, &pixels, NULL, 0);
   130     ii.hbmMask = CreateBitmap(surface->w, surface->h, 1, 1, maskbits);
   131     ReleaseDC(NULL, hdc);
   132     SDL_stack_free(maskbits);
   133 
   134     SDL_assert(surface->format->format == SDL_PIXELFORMAT_ARGB8888);
   135     SDL_assert(surface->pitch == surface->w * 4);
   136     SDL_memcpy(pixels, surface->pixels, surface->h * surface->pitch);
   137 
   138     hicon = CreateIconIndirect(&ii);
   139 
   140     DeleteObject(ii.hbmColor);
   141     DeleteObject(ii.hbmMask);
   142 
   143     if (!hicon) {
   144         WIN_SetError("CreateIconIndirect()");
   145         return NULL;
   146     }
   147 
   148     cursor = SDL_calloc(1, sizeof(*cursor));
   149     if (cursor) {
   150         cursor->driverdata = hicon;
   151     } else {
   152         DestroyIcon(hicon);
   153         SDL_OutOfMemory();
   154     }
   155 
   156     return cursor;
   157 }
   158 
   159 static SDL_Cursor *
   160 WIN_CreateSystemCursor(SDL_SystemCursor id)
   161 {
   162     SDL_Cursor *cursor;
   163     LPCTSTR name;
   164 
   165     switch(id)
   166     {
   167     default:
   168         SDL_assert(0);
   169         return NULL;
   170     case SDL_SYSTEM_CURSOR_ARROW:     name = IDC_ARROW; break;
   171     case SDL_SYSTEM_CURSOR_IBEAM:     name = IDC_IBEAM; break;
   172     case SDL_SYSTEM_CURSOR_WAIT:      name = IDC_WAIT; break;
   173     case SDL_SYSTEM_CURSOR_CROSSHAIR: name = IDC_CROSS; break;
   174     case SDL_SYSTEM_CURSOR_WAITARROW: name = IDC_WAIT; break;
   175     case SDL_SYSTEM_CURSOR_SIZENWSE:  name = IDC_SIZENWSE; break;
   176     case SDL_SYSTEM_CURSOR_SIZENESW:  name = IDC_SIZENESW; break;
   177     case SDL_SYSTEM_CURSOR_SIZEWE:    name = IDC_SIZEWE; break;
   178     case SDL_SYSTEM_CURSOR_SIZENS:    name = IDC_SIZENS; break;
   179     case SDL_SYSTEM_CURSOR_SIZEALL:   name = IDC_SIZEALL; break;
   180     case SDL_SYSTEM_CURSOR_NO:        name = IDC_NO; break;
   181     case SDL_SYSTEM_CURSOR_HAND:      name = IDC_HAND; break;
   182     }
   183 
   184     cursor = SDL_calloc(1, sizeof(*cursor));
   185     if (cursor) {
   186         HICON hicon;
   187 
   188         hicon = LoadCursor(NULL, name);
   189 
   190         cursor->driverdata = hicon;
   191     } else {
   192         SDL_OutOfMemory();
   193     }
   194 
   195     return cursor;
   196 }
   197 
   198 static void
   199 WIN_FreeCursor(SDL_Cursor * cursor)
   200 {
   201     HICON hicon = (HICON)cursor->driverdata;
   202 
   203     DestroyIcon(hicon);
   204     SDL_free(cursor);
   205 }
   206 
   207 static int
   208 WIN_ShowCursor(SDL_Cursor * cursor)
   209 {
   210     if (cursor) {
   211         SDL_cursor = (HCURSOR)cursor->driverdata;
   212     } else {
   213         SDL_cursor = NULL;
   214     }
   215     if (SDL_GetMouseFocus() != NULL) {
   216         SetCursor(SDL_cursor);
   217     }
   218     return 0;
   219 }
   220 
   221 static void
   222 WIN_WarpMouse(SDL_Window * window, int x, int y)
   223 {
   224     SDL_WindowData *data = (SDL_WindowData *)window->driverdata;
   225     HWND hwnd = data->hwnd;
   226     POINT pt;
   227 
   228     /* Don't warp the mouse while we're doing a modal interaction */
   229     if (data->in_title_click || data->focus_click_pending) {
   230         return;
   231     }
   232 
   233     pt.x = x;
   234     pt.y = y;
   235     ClientToScreen(hwnd, &pt);
   236     SetCursorPos(pt.x, pt.y);
   237 }
   238 
   239 static void
   240 WIN_WarpMouseGlobal(int x, int y)
   241 {
   242     POINT pt;
   243 
   244     pt.x = x;
   245     pt.y = y;
   246     SetCursorPos(pt.x, pt.y);
   247 }
   248 
   249 static int
   250 WIN_SetRelativeMouseMode(SDL_bool enabled)
   251 {
   252     return ToggleRawInput(enabled);
   253 }
   254 
   255 static int
   256 WIN_CaptureMouse(SDL_Window *window)
   257 {
   258     if (!window) {
   259         SDL_Window *focusWin = SDL_GetKeyboardFocus();
   260         if (focusWin) {
   261             WIN_OnWindowEnter(SDL_GetVideoDevice(), focusWin);  /* make sure WM_MOUSELEAVE messages are (re)enabled. */
   262         }
   263     }
   264 
   265     /* While we were thinking of SetCapture() when designing this API in SDL,
   266        we didn't count on the fact that SetCapture() only tracks while the
   267        left mouse button is held down! Instead, we listen for raw mouse input
   268        and manually query the mouse when it leaves the window. :/ */
   269     return ToggleRawInput(window != NULL);
   270 }
   271 
   272 static Uint32
   273 WIN_GetGlobalMouseState(int *x, int *y)
   274 {
   275     Uint32 retval = 0;
   276     POINT pt = { 0, 0 };
   277     GetCursorPos(&pt);
   278     *x = (int) pt.x;
   279     *y = (int) pt.y;
   280 
   281     retval |= GetAsyncKeyState(VK_LBUTTON) & 0x8000 ? SDL_BUTTON_LMASK : 0;
   282     retval |= GetAsyncKeyState(VK_RBUTTON) & 0x8000 ? SDL_BUTTON_RMASK : 0;
   283     retval |= GetAsyncKeyState(VK_MBUTTON) & 0x8000 ? SDL_BUTTON_MMASK : 0;
   284     retval |= GetAsyncKeyState(VK_XBUTTON1) & 0x8000 ? SDL_BUTTON_X1MASK : 0;
   285     retval |= GetAsyncKeyState(VK_XBUTTON2) & 0x8000 ? SDL_BUTTON_X2MASK : 0;
   286 
   287     return retval;
   288 }
   289 
   290 void
   291 WIN_InitMouse(_THIS)
   292 {
   293     SDL_Mouse *mouse = SDL_GetMouse();
   294 
   295     mouse->CreateCursor = WIN_CreateCursor;
   296     mouse->CreateSystemCursor = WIN_CreateSystemCursor;
   297     mouse->ShowCursor = WIN_ShowCursor;
   298     mouse->FreeCursor = WIN_FreeCursor;
   299     mouse->WarpMouse = WIN_WarpMouse;
   300     mouse->WarpMouseGlobal = WIN_WarpMouseGlobal;
   301     mouse->SetRelativeMouseMode = WIN_SetRelativeMouseMode;
   302     mouse->CaptureMouse = WIN_CaptureMouse;
   303     mouse->GetGlobalMouseState = WIN_GetGlobalMouseState;
   304 
   305     SDL_SetDefaultCursor(WIN_CreateDefaultCursor());
   306 
   307     SDL_SetDoubleClickTime(GetDoubleClickTime());
   308 }
   309 
   310 void
   311 WIN_QuitMouse(_THIS)
   312 {
   313     SDL_Mouse *mouse = SDL_GetMouse();
   314     if ( mouse->def_cursor ) {
   315         SDL_free(mouse->def_cursor);
   316         mouse->def_cursor = NULL;
   317         mouse->cur_cursor = NULL;
   318     }
   319 
   320     if (rawInputEnableCount) {  /* force RAWINPUT off here. */
   321         rawInputEnableCount = 1;
   322         ToggleRawInput(SDL_FALSE);
   323     }
   324 }
   325 
   326 #endif /* SDL_VIDEO_DRIVER_WINDOWS */
   327 
   328 /* vi: set ts=4 sw=4 expandtab: */