SDL_windowsmouse.c (8959B)
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 31HCURSOR SDL_cursor = NULL; 32 33static int rawInputEnableCount = 0; 34 35static int 36ToggleRawInput(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 72static SDL_Cursor * 73WIN_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 87static SDL_Cursor * 88WIN_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 159static SDL_Cursor * 160WIN_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 198static void 199WIN_FreeCursor(SDL_Cursor * cursor) 200{ 201 HICON hicon = (HICON)cursor->driverdata; 202 203 DestroyIcon(hicon); 204 SDL_free(cursor); 205} 206 207static int 208WIN_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 221static void 222WIN_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 239static void 240WIN_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 249static int 250WIN_SetRelativeMouseMode(SDL_bool enabled) 251{ 252 return ToggleRawInput(enabled); 253} 254 255static int 256WIN_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 272static Uint32 273WIN_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 290void 291WIN_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 310void 311WIN_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: */