SDL  2.0
SDL_windowsmouse.c
Go to the documentation of this file.
1 /*
2  Simple DirectMedia Layer
3  Copyright (C) 1997-2020 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_windowsvideo.h"
26 
27 #include "../../events/SDL_mouse_c.h"
28 
29 
30 HCURSOR SDL_cursor = NULL;
31 
32 static int rawInputEnableCount = 0;
33 
34 static int
35 ToggleRawInput(SDL_bool enabled)
36 {
37  RAWINPUTDEVICE rawMouse = { 0x01, 0x02, 0, NULL }; /* Mouse: UsagePage = 1, Usage = 2 */
38 
39  if (enabled) {
40  rawInputEnableCount++;
41  if (rawInputEnableCount > 1) {
42  return 0; /* already done. */
43  }
44  } else {
45  if (rawInputEnableCount == 0) {
46  return 0; /* already done. */
47  }
48  rawInputEnableCount--;
49  if (rawInputEnableCount > 0) {
50  return 0; /* not time to disable yet */
51  }
52  }
53 
54  if (!enabled) {
55  rawMouse.dwFlags |= RIDEV_REMOVE;
56  }
57 
58  /* (Un)register raw input for mice */
59  if (RegisterRawInputDevices(&rawMouse, 1, sizeof(RAWINPUTDEVICE)) == FALSE) {
60 
61  /* Only return an error when registering. If we unregister and fail,
62  then it's probably that we unregistered twice. That's OK. */
63  if (enabled) {
64  return SDL_Unsupported();
65  }
66  }
67  return 0;
68 }
69 
70 
71 static SDL_Cursor *
72 WIN_CreateDefaultCursor()
73 {
75 
76  cursor = SDL_calloc(1, sizeof(*cursor));
77  if (cursor) {
78  cursor->driverdata = LoadCursor(NULL, IDC_ARROW);
79  } else {
81  }
82 
83  return cursor;
84 }
85 
86 static SDL_Cursor *
87 WIN_CreateCursor(SDL_Surface * surface, int hot_x, int hot_y)
88 {
89  /* msdn says cursor mask has to be padded out to word alignment. Not sure
90  if that means machine word or WORD, but this handles either case. */
91  const size_t pad = (sizeof (size_t) * 8); /* 32 or 64, or whatever. */
93  HICON hicon;
94  HDC hdc;
95  BITMAPV4HEADER bmh;
96  LPVOID pixels;
97  LPVOID maskbits;
98  size_t maskbitslen;
99  SDL_bool isstack;
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_small_alloc(Uint8, maskbitslen, &isstack);
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_small_free(maskbits, isstack);
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 {
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 int
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  return 0;
248 }
249 
250 static int
251 WIN_SetRelativeMouseMode(SDL_bool enabled)
252 {
253  return ToggleRawInput(enabled);
254 }
255 
256 static int
257 WIN_CaptureMouse(SDL_Window *window)
258 {
259  if (!window) {
260  SDL_Window *focusWin = SDL_GetKeyboardFocus();
261  if (focusWin) {
262  WIN_OnWindowEnter(SDL_GetVideoDevice(), focusWin); /* make sure WM_MOUSELEAVE messages are (re)enabled. */
263  }
264  }
265 
266  /* While we were thinking of SetCapture() when designing this API in SDL,
267  we didn't count on the fact that SetCapture() only tracks while the
268  left mouse button is held down! Instead, we listen for raw mouse input
269  and manually query the mouse when it leaves the window. :/ */
270  return ToggleRawInput(window != NULL);
271 }
272 
273 static Uint32
274 WIN_GetGlobalMouseState(int *x, int *y)
275 {
276  Uint32 retval = 0;
277  POINT pt = { 0, 0 };
278  SDL_bool swapButtons = GetSystemMetrics(SM_SWAPBUTTON) != 0;
279 
280  GetCursorPos(&pt);
281  *x = (int) pt.x;
282  *y = (int) pt.y;
283 
284  retval |= GetAsyncKeyState(!swapButtons ? VK_LBUTTON : VK_RBUTTON) & 0x8000 ? SDL_BUTTON_LMASK : 0;
285  retval |= GetAsyncKeyState(!swapButtons ? VK_RBUTTON : VK_LBUTTON) & 0x8000 ? SDL_BUTTON_RMASK : 0;
286  retval |= GetAsyncKeyState(VK_MBUTTON) & 0x8000 ? SDL_BUTTON_MMASK : 0;
287  retval |= GetAsyncKeyState(VK_XBUTTON1) & 0x8000 ? SDL_BUTTON_X1MASK : 0;
288  retval |= GetAsyncKeyState(VK_XBUTTON2) & 0x8000 ? SDL_BUTTON_X2MASK : 0;
289 
290  return retval;
291 }
292 
293 void
295 {
296  SDL_Mouse *mouse = SDL_GetMouse();
297 
298  mouse->CreateCursor = WIN_CreateCursor;
299  mouse->CreateSystemCursor = WIN_CreateSystemCursor;
300  mouse->ShowCursor = WIN_ShowCursor;
301  mouse->FreeCursor = WIN_FreeCursor;
302  mouse->WarpMouse = WIN_WarpMouse;
303  mouse->WarpMouseGlobal = WIN_WarpMouseGlobal;
304  mouse->SetRelativeMouseMode = WIN_SetRelativeMouseMode;
305  mouse->CaptureMouse = WIN_CaptureMouse;
306  mouse->GetGlobalMouseState = WIN_GetGlobalMouseState;
307 
308  SDL_SetDefaultCursor(WIN_CreateDefaultCursor());
309 }
310 
311 void
313 {
314  if (rawInputEnableCount) { /* force RAWINPUT off here. */
315  rawInputEnableCount = 1;
316  ToggleRawInput(SDL_FALSE);
317  }
318 }
319 
320 #endif /* SDL_VIDEO_DRIVER_WINDOWS */
321 
322 /* vi: set ts=4 sw=4 expandtab: */
#define _THIS
#define SDL_assert(condition)
Definition: SDL_assert.h:171
#define BI_BITFIELDS
Definition: SDL_bmp.c:47
unsigned int size_t
#define SDL_memset
#define SDL_GetKeyboardFocus
#define SDL_free
#define SDL_GetMouseFocus
#define SDL_memcpy
#define SDL_calloc
#define SDL_OutOfMemory()
Definition: SDL_error.h:88
#define SDL_Unsupported()
Definition: SDL_error.h:89
#define SDL_small_alloc(type, count, pisstack)
Definition: SDL_internal.h:39
#define SDL_small_free(ptr, isstack)
Definition: SDL_internal.h:40
int uint32_t uint32_t uint32_t uint32_t uint32_t int drmModeModeInfoPtr mode int uint32_t uint32_t uint32_t uint32_t int32_t hot_x
SDL_Mouse * SDL_GetMouse(void)
Definition: SDL_mouse.c:175
void SDL_SetDefaultCursor(SDL_Cursor *cursor)
Definition: SDL_mouse.c:164
SDL_SystemCursor
Cursor types for SDL_CreateSystemCursor().
Definition: SDL_mouse.h:47
@ SDL_SYSTEM_CURSOR_SIZENS
Definition: SDL_mouse.h:56
@ SDL_SYSTEM_CURSOR_HAND
Definition: SDL_mouse.h:59
@ SDL_SYSTEM_CURSOR_ARROW
Definition: SDL_mouse.h:48
@ SDL_SYSTEM_CURSOR_SIZENWSE
Definition: SDL_mouse.h:53
@ SDL_SYSTEM_CURSOR_SIZENESW
Definition: SDL_mouse.h:54
@ SDL_SYSTEM_CURSOR_IBEAM
Definition: SDL_mouse.h:49
@ SDL_SYSTEM_CURSOR_NO
Definition: SDL_mouse.h:58
@ SDL_SYSTEM_CURSOR_WAITARROW
Definition: SDL_mouse.h:52
@ SDL_SYSTEM_CURSOR_SIZEALL
Definition: SDL_mouse.h:57
@ SDL_SYSTEM_CURSOR_WAIT
Definition: SDL_mouse.h:50
@ SDL_SYSTEM_CURSOR_SIZEWE
Definition: SDL_mouse.h:55
@ SDL_SYSTEM_CURSOR_CROSSHAIR
Definition: SDL_mouse.h:51
#define SDL_BUTTON_MMASK
Definition: SDL_mouse.h:288
#define SDL_BUTTON_LMASK
Definition: SDL_mouse.h:287
#define SDL_BUTTON_X1MASK
Definition: SDL_mouse.h:290
#define SDL_BUTTON_RMASK
Definition: SDL_mouse.h:289
#define SDL_BUTTON_X2MASK
Definition: SDL_mouse.h:291
GLint GLint GLint GLint GLint GLint y
Definition: SDL_opengl.h:1574
GLint GLint GLsizei GLsizei GLsizei GLint GLenum GLenum const GLvoid * pixels
Definition: SDL_opengl.h:1572
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: SDL_opengl.h:1974
GLint GLint GLint GLint GLint x
Definition: SDL_opengl.h:1574
GLenum GLenum GLsizei const GLuint GLboolean enabled
GLuint const GLchar * name
@ SDL_PIXELFORMAT_ARGB8888
Definition: SDL_pixels.h:257
#define SDL_zero(x)
Definition: SDL_stdinc.h:426
SDL_bool
Definition: SDL_stdinc.h:168
@ SDL_FALSE
Definition: SDL_stdinc.h:169
uint8_t Uint8
Definition: SDL_stdinc.h:185
uint32_t Uint32
Definition: SDL_stdinc.h:209
SDL_VideoDevice * SDL_GetVideoDevice(void)
Definition: SDL_video.c:587
int WIN_SetError(const char *prefix)
HCURSOR SDL_cursor
void WIN_InitMouse(_THIS)
void WIN_QuitMouse(_THIS)
void WIN_OnWindowEnter(_THIS, SDL_Window *window)
#define NULL
Definition: begin_code.h:163
#define FALSE
Definition: edid-parse.c:34
EGLSurface surface
Definition: eglext.h:248
EGLSurface EGLNativeWindowType * window
Definition: eglext.h:1025
set set set set set set set macro pixldst1 abits if abits op else op endif endm macro pixldst2 abits if abits op else op endif endm macro pixldst4 abits if abits op else op endif endm macro pixldst0 abits op endm macro pixldst3 mem_operand op endm macro pixldst30 mem_operand op endm macro pixldst abits if abits elseif abits elseif abits elseif abits elseif abits pixldst0 abits else pixldst0 abits pixldst0 abits pixldst0 abits pixldst0 abits endif elseif abits else pixldst0 abits pixldst0 abits endif elseif abits else error unsupported bpp *numpix else pixst endif endm macro pixld1_s mem_operand if asr adds SRC_WIDTH_FIXED bpl add asl mov asr adds SRC_WIDTH_FIXED bpl add asl mov asr adds SRC_WIDTH_FIXED bpl add asl mov asr adds SRC_WIDTH_FIXED bpl add asl elseif asr adds SRC_WIDTH_FIXED bpl add asl mov asr adds SRC_WIDTH_FIXED bpl add asl else error unsupported endif endm macro pixld2_s mem_operand if mov asr add asl add asl mov asr sub UNIT_X add asl mov asr add asl add asl mov asr add UNIT_X add asl else pixld1_s mem_operand pixld1_s mem_operand endif endm macro pixld0_s mem_operand if asr adds SRC_WIDTH_FIXED bpl add asl elseif asr adds SRC_WIDTH_FIXED bpl add asl endif endm macro pixld_s_internal mem_operand if mem_operand pixld2_s mem_operand pixdeinterleave basereg elseif mem_operand elseif mem_operand elseif mem_operand elseif mem_operand pixld0_s mem_operand else pixld0_s mem_operand pixld0_s mem_operand pixld0_s mem_operand pixld0_s mem_operand endif elseif mem_operand else pixld0_s mem_operand pixld0_s mem_operand endif elseif mem_operand else error unsupported mem_operand if bpp mem_operand endif endm macro vuzp8 reg2 vuzp d d &reg2 endm macro vzip8 reg2 vzip d d &reg2 endm macro pixdeinterleave basereg basereg basereg basereg basereg endif endm macro pixinterleave basereg basereg basereg basereg basereg endif endm macro PF boost_increment endif if endif PF tst PF addne PF subne PF cmp ORIG_W if endif if endif if endif PF subge ORIG_W PF subges if endif if endif if endif endif endm macro cache_preload_simple endif if dst_r_bpp pld[DST_R, #(PREFETCH_DISTANCE_SIMPLE *dst_r_bpp/8)] endif if mask_bpp pld if[MASK, #(PREFETCH_DISTANCE_SIMPLE *mask_bpp/8)] endif endif endm macro fetch_mask_pixblock pixld mask_basereg pixblock_size MASK endm macro ensure_destination_ptr_alignment process_pixblock_tail_head if beq irp skip1(dst_w_bpp<=(lowbit *8)) &&((lowbit *8)<(pixblock_size *dst_w_bpp)) .if lowbit< 16 tst DST_R
void * driverdata
Definition: SDL_mouse_c.h:33
int(* SetRelativeMouseMode)(SDL_bool enabled)
Definition: SDL_mouse_c.h:67
void(* WarpMouse)(SDL_Window *window, int x, int y)
Definition: SDL_mouse_c.h:61
SDL_Cursor *(* CreateCursor)(SDL_Surface *surface, int hot_x, int hot_y)
Definition: SDL_mouse_c.h:46
void(* FreeCursor)(SDL_Cursor *cursor)
Definition: SDL_mouse_c.h:58
int(* ShowCursor)(SDL_Cursor *cursor)
Definition: SDL_mouse_c.h:52
int(* WarpMouseGlobal)(int x, int y)
Definition: SDL_mouse_c.h:64
SDL_Cursor *(* CreateSystemCursor)(SDL_SystemCursor id)
Definition: SDL_mouse_c.h:49
Uint32(* GetGlobalMouseState)(int *x, int *y)
Definition: SDL_mouse_c.h:73
int(* CaptureMouse)(SDL_Window *window)
Definition: SDL_mouse_c.h:70
A collection of pixels used in software blitting.
Definition: SDL_surface.h:71
The type used to identify a window.
Definition: SDL_sysvideo.h:75
SDL_bool retval
SDL_Cursor * cursor
Definition: testwm2.c:40
typedef int(__stdcall *FARPROC)()