This repository has been archived by the owner on Feb 11, 2021. It is now read-only.
/
SDL_mouse.c
523 lines (440 loc) · 11.9 KB
1
2
/*
SDL - Simple DirectMedia Layer
3
Copyright (C) 1997-2010 Sam Lantinga
4
5
This library is free software; you can redistribute it and/or
6
modify it under the terms of the GNU Lesser General Public
7
License as published by the Free Software Foundation; either
8
version 2.1 of the License, or (at your option) any later version.
9
10
11
12
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
Lesser General Public License for more details.
14
15
16
17
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18
19
Sam Lantinga
20
slouken@libsdl.org
21
*/
22
#include "SDL_config.h"
23
24
25
26
27
/* General mouse handling code for SDL */
#include "SDL_events.h"
#include "SDL_events_c.h"
28
#include "default_cursor.h"
29
#include "../video/SDL_sysvideo.h"
30
31
32
/* Global mouse information */
33
34
typedef struct SDL_Mouse SDL_Mouse;
35
36
struct SDL_Mouse
37
{
38
39
/* Create a cursor from a surface */
SDL_Cursor *(*CreateCursor) (SDL_Surface * surface, int hot_x, int hot_y);
40
41
42
/* Show the specified cursor, or hide if cursor is NULL */
int (*ShowCursor) (SDL_Cursor * cursor);
43
44
45
/* This is called when a mouse motion event occurs */
void (*MoveCursor) (SDL_Cursor * cursor);
46
47
48
/* Free a window manager cursor */
void (*FreeCursor) (SDL_Cursor * cursor);
49
50
51
/* Warp the mouse to (x,y) */
void (*WarpMouse) (SDL_Mouse * mouse, SDL_Window * window, int x, int y);
52
53
54
55
56
57
58
59
60
61
/* Data common to all mice */
SDL_Window *focus;
int x;
int y;
int xdelta;
int ydelta;
int last_x, last_y; /* the last reported x and y coordinates */
Uint8 buttonstate;
SDL_bool relative_mode;
62
63
64
65
66
67
SDL_Cursor *cursors;
SDL_Cursor *def_cursor;
SDL_Cursor *cur_cursor;
SDL_bool cursor_shown;
};
68
69
static SDL_Mouse SDL_mouse;
70
71
72
/* Public functions */
73
int
74
SDL_MouseInit(void)
75
{
76
return (0);
77
78
}
79
80
void
SDL_ResetMouse(void)
81
{
82
/* FIXME */
83
}
84
85
SDL_Window *
86
SDL_GetMouseFocus(void)
87
{
88
SDL_Mouse *mouse = &SDL_mouse;
89
90
return mouse->focus;
91
92
}
93
void
94
SDL_SetMouseFocus(SDL_Window * window)
95
{
96
SDL_Mouse *mouse = &SDL_mouse;
97
98
if (mouse->focus == window) {
99
100
101
102
103
return;
}
/* See if the current window has lost focus */
if (mouse->focus) {
104
SDL_SendWindowEvent(mouse->focus, SDL_WINDOWEVENT_LEAVE, 0, 0);
105
106
}
107
mouse->focus = window;
108
109
if (mouse->focus) {
110
SDL_SendWindowEvent(mouse->focus, SDL_WINDOWEVENT_ENTER, 0, 0);
111
112
113
114
}
}
int
115
SDL_SendMouseMotion(SDL_Window * window, int relative, int x, int y)
116
{
117
SDL_Mouse *mouse = &SDL_mouse;
118
119
120
int posted;
int xrel;
int yrel;
121
int x_max = 0, y_max = 0;
122
123
124
125
126
if (window) {
SDL_SetMouseFocus(window);
}
127
/* the relative motion is calculated regarding the system cursor last position */
128
129
130
if (relative) {
xrel = x;
yrel = y;
131
132
x = (mouse->last_x + x);
y = (mouse->last_y + y);
133
} else {
134
135
xrel = x - mouse->last_x;
yrel = y - mouse->last_y;
136
}
137
138
139
/* Drop events that don't change state */
if (!xrel && !yrel) {
140
#if 0
141
printf("Mouse event didn't change state - dropped!\n");
142
#endif
143
144
145
return 0;
}
146
147
/* Update internal mouse coordinates */
if (mouse->relative_mode == SDL_FALSE) {
148
149
mouse->x = x;
mouse->y = y;
150
} else {
151
152
153
mouse->x += xrel;
mouse->y += yrel;
}
154
155
SDL_GetWindowSize(mouse->focus, &x_max, &y_max);
156
157
158
159
160
161
162
163
164
165
166
167
168
/* make sure that the pointers find themselves inside the windows */
/* only check if mouse->xmax is set ! */
if (x_max && mouse->x > x_max) {
mouse->x = x_max;
} else if (mouse->x < 0) {
mouse->x = 0;
}
if (y_max && mouse->y > y_max) {
mouse->y = y_max;
} else if (mouse->y < 0) {
mouse->y = 0;
169
}
170
171
172
173
mouse->xdelta += xrel;
mouse->ydelta += yrel;
174
#if 0 /* FIXME */
175
176
177
178
179
/* Move the mouse cursor, if needed */
if (mouse->cursor_shown && !mouse->relative_mode &&
mouse->MoveCursor && mouse->cur_cursor) {
mouse->MoveCursor(mouse->cur_cursor);
}
180
#endif
181
182
183
/* Post the event, if desired */
posted = 0;
184
if (SDL_GetEventState(SDL_MOUSEMOTION) == SDL_ENABLE) {
185
186
SDL_Event event;
event.motion.type = SDL_MOUSEMOTION;
187
event.motion.windowID = mouse->focus ? mouse->focus->id : 0;
188
189
190
event.motion.state = mouse->buttonstate;
event.motion.x = mouse->x;
event.motion.y = mouse->y;
191
192
event.motion.xrel = xrel;
event.motion.yrel = yrel;
193
194
posted = (SDL_PushEvent(&event) > 0);
}
195
196
mouse->last_x = mouse->x;
mouse->last_y = mouse->y;
197
198
199
200
return posted;
}
int
201
SDL_SendMouseButton(SDL_Window * window, Uint8 state, Uint8 button)
202
{
203
SDL_Mouse *mouse = &SDL_mouse;
204
int posted;
205
Uint32 type;
206
207
208
209
210
if (window) {
SDL_SetMouseFocus(window);
}
211
212
213
214
215
216
217
218
219
220
221
/* Figure out which event to perform */
switch (state) {
case SDL_PRESSED:
if (mouse->buttonstate & SDL_BUTTON(button)) {
/* Ignore this event, no state change */
return 0;
}
type = SDL_MOUSEBUTTONDOWN;
mouse->buttonstate |= SDL_BUTTON(button);
break;
case SDL_RELEASED:
222
if (!(mouse->buttonstate & SDL_BUTTON(button))) {
223
224
225
/* Ignore this event, no state change */
return 0;
}
226
227
228
229
230
231
232
233
234
235
type = SDL_MOUSEBUTTONUP;
mouse->buttonstate &= ~SDL_BUTTON(button);
break;
default:
/* Invalid state -- bail */
return 0;
}
/* Post the event, if desired */
posted = 0;
236
if (SDL_GetEventState(type) == SDL_ENABLE) {
237
238
239
240
241
242
SDL_Event event;
event.type = type;
event.button.state = state;
event.button.button = button;
event.button.x = mouse->x;
event.button.y = mouse->y;
243
event.button.windowID = mouse->focus ? mouse->focus->id : 0;
244
245
246
247
248
249
posted = (SDL_PushEvent(&event) > 0);
}
return posted;
}
int
250
SDL_SendMouseWheel(SDL_Window * window, int x, int y)
251
{
252
SDL_Mouse *mouse = &SDL_mouse;
253
254
int posted;
255
256
257
258
if (window) {
SDL_SetMouseFocus(window);
}
259
if (!x && !y) {
260
261
262
263
264
return 0;
}
/* Post the event, if desired */
posted = 0;
265
if (SDL_GetEventState(SDL_MOUSEWHEEL) == SDL_ENABLE) {
266
267
SDL_Event event;
event.type = SDL_MOUSEWHEEL;
268
event.wheel.windowID = mouse->focus ? mouse->focus->id : 0;
269
270
event.wheel.x = x;
event.wheel.y = y;
271
272
273
274
275
276
posted = (SDL_PushEvent(&event) > 0);
}
return posted;
}
void
277
SDL_MouseQuit(void)
278
{
279
}
280
281
282
283
284
285
286
287
288
289
290
Uint8
SDL_GetMouseState(int *x, int *y)
{
SDL_Mouse *mouse = &SDL_mouse;
if (x) {
*x = mouse->x;
}
if (y) {
*y = mouse->y;
291
}
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
return mouse->buttonstate;
}
Uint8
SDL_GetRelativeMouseState(int *x, int *y)
{
SDL_Mouse *mouse = &SDL_mouse;
if (x) {
*x = mouse->xdelta;
}
if (y) {
*y = mouse->ydelta;
}
mouse->xdelta = 0;
mouse->ydelta = 0;
return mouse->buttonstate;
}
void
SDL_WarpMouseInWindow(SDL_Window * window, int x, int y)
{
SDL_Mouse *mouse = &SDL_mouse;
315
316
if (mouse->WarpMouse) {
317
mouse->WarpMouse(mouse, window, x, y);
318
} else {
319
SDL_SendMouseMotion(window, 0, x, y);
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
}
}
int
SDL_SetRelativeMouseMode(SDL_bool enabled)
{
SDL_Mouse *mouse = &SDL_mouse;
/* Flush pending mouse motion */
SDL_FlushEvent(SDL_MOUSEMOTION);
/* Set the relative mode */
mouse->relative_mode = enabled;
if (!enabled) {
/* Restore the expected mouse position */
SDL_WarpMouseInWindow(mouse->focus, mouse->x, mouse->y);
337
}
338
339
340
341
342
343
344
345
346
347
348
349
350
/* Update cursor visibility */
SDL_SetCursor(NULL);
return 0;
}
SDL_bool
SDL_GetRelativeMouseMode()
{
SDL_Mouse *mouse = &SDL_mouse;
return mouse->relative_mode;
351
352
353
354
355
356
}
SDL_Cursor *
SDL_CreateCursor(const Uint8 * data, const Uint8 * mask,
int w, int h, int hot_x, int hot_y)
{
357
SDL_Mouse *mouse = &SDL_mouse;
358
359
360
361
SDL_Surface *surface;
SDL_Cursor *cursor;
int x, y;
Uint32 *pixel;
362
Uint8 datab = 0, maskb = 0;
363
364
365
366
367
const Uint32 black = 0xFF000000;
const Uint32 white = 0xFFFFFFFF;
const Uint32 transparent = 0x00000000;
if (!mouse->CreateCursor) {
368
SDL_SetError("Cursors are not currently supported");
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
return NULL;
}
/* Sanity check the hot spot */
if ((hot_x < 0) || (hot_y < 0) || (hot_x >= w) || (hot_y >= h)) {
SDL_SetError("Cursor hot spot doesn't lie within cursor");
return NULL;
}
/* Make sure the width is a multiple of 8 */
w = ((w + 7) & ~7);
/* Create the surface from a bitmap */
surface =
SDL_CreateRGBSurface(0, w, h, 32, 0x00FF0000, 0x0000FF00, 0x000000FF,
0xFF000000);
if (!surface) {
return NULL;
}
for (y = 0; y < h; ++y) {
pixel = (Uint32 *) ((Uint8 *) surface->pixels + y * surface->pitch);
for (x = 0; x < w; ++x) {
if ((x % 8) == 0) {
datab = *data++;
maskb = *mask++;
}
if (maskb & 0x80) {
*pixel++ = (datab & 0x80) ? black : white;
} else {
*pixel++ = (datab & 0x80) ? black : transparent;
}
datab <<= 1;
maskb <<= 1;
}
}
cursor = mouse->CreateCursor(surface, hot_x, hot_y);
if (cursor) {
cursor->next = mouse->cursors;
mouse->cursors = cursor;
}
SDL_FreeSurface(surface);
return cursor;
}
/* SDL_SetCursor(NULL) can be used to force the cursor redraw,
if this is desired for any reason. This is used when setting
the video mode and when the SDL window gains the mouse focus.
*/
void
SDL_SetCursor(SDL_Cursor * cursor)
{
423
SDL_Mouse *mouse = &SDL_mouse;
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
/* Set the new cursor */
if (cursor) {
/* Make sure the cursor is still valid for this mouse */
SDL_Cursor *found;
for (found = mouse->cursors; found; found = found->next) {
if (found == cursor) {
break;
}
}
if (!found) {
SDL_SetError("Cursor not associated with the current mouse");
return;
}
mouse->cur_cursor = cursor;
} else {
cursor = mouse->cur_cursor;
}
if (cursor && mouse->cursor_shown && !mouse->relative_mode) {
if (mouse->ShowCursor) {
mouse->ShowCursor(cursor);
}
} else {
if (mouse->ShowCursor) {
mouse->ShowCursor(NULL);
}
}
}
SDL_Cursor *
SDL_GetCursor(void)
{
457
SDL_Mouse *mouse = &SDL_mouse;
458
459
460
461
462
463
464
465
466
467
if (!mouse) {
return NULL;
}
return mouse->cur_cursor;
}
void
SDL_FreeCursor(SDL_Cursor * cursor)
{
468
SDL_Mouse *mouse = &SDL_mouse;
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
SDL_Cursor *curr, *prev;
if (!cursor) {
return;
}
if (cursor == mouse->def_cursor) {
return;
}
if (cursor == mouse->cur_cursor) {
SDL_SetCursor(mouse->def_cursor);
}
for (prev = NULL, curr = mouse->cursors; curr;
prev = curr, curr = curr->next) {
if (curr == cursor) {
if (prev) {
prev->next = curr->next;
} else {
mouse->cursors = curr->next;
}
if (mouse->FreeCursor) {
mouse->FreeCursor(curr);
}
return;
}
}
497
498
}
499
500
int
SDL_ShowCursor(int toggle)
501
{
502
SDL_Mouse *mouse = &SDL_mouse;
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
SDL_bool shown;
if (!mouse) {
return 0;
}
shown = mouse->cursor_shown;
if (toggle >= 0) {
if (toggle) {
mouse->cursor_shown = SDL_TRUE;
} else {
mouse->cursor_shown = SDL_FALSE;
}
if (mouse->cursor_shown != shown) {
SDL_SetCursor(NULL);
}
}
return shown;
521
522
}
523
/* vi: set ts=4 sw=4 expandtab: */