summaryrefslogtreecommitdiff
path: root/src/contrib/SDL-3.2.20/test/testmanymouse.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/contrib/SDL-3.2.20/test/testmanymouse.c')
-rw-r--r--src/contrib/SDL-3.2.20/test/testmanymouse.c551
1 files changed, 551 insertions, 0 deletions
diff --git a/src/contrib/SDL-3.2.20/test/testmanymouse.c b/src/contrib/SDL-3.2.20/test/testmanymouse.c
new file mode 100644
index 0000000..d4a7efa
--- /dev/null
+++ b/src/contrib/SDL-3.2.20/test/testmanymouse.c
@@ -0,0 +1,551 @@
1/*
2 Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
3
4 This software is provided 'as-is', without any express or implied
5 warranty. In no event will the authors be held liable for any damages
6 arising from the use of this software.
7
8 Permission is granted to anyone to use this software for any purpose,
9 including commercial applications, and to alter it and redistribute it
10 freely.
11*/
12
13#include <SDL3/SDL_test_common.h>
14#include <SDL3/SDL_main.h>
15
16/* Stolen from the mailing list */
17/* Creates a new mouse cursor from an XPM */
18
19/* XPM */
20static const char *arrow[] = {
21 /* width height num_colors chars_per_pixel */
22 " 32 32 3 1",
23 /* colors */
24 "X c #000000",
25 ". c #ffffff",
26 " c None",
27 /* pixels */
28 "X ",
29 "XX ",
30 "X.X ",
31 "X..X ",
32 "X...X ",
33 "X....X ",
34 "X.....X ",
35 "X......X ",
36 "X.......X ",
37 "X........X ",
38 "X.....XXXXX ",
39 "X..X..X ",
40 "X.X X..X ",
41 "XX X..X ",
42 "X X..X ",
43 " X..X ",
44 " X..X ",
45 " X..X ",
46 " XX ",
47 " ",
48 " ",
49 " ",
50 " ",
51 " ",
52 " ",
53 " ",
54 " ",
55 " ",
56 " ",
57 " ",
58 " ",
59 " ",
60 "0,0"
61};
62
63static const char *cross[] = {
64 /* width height num_colors chars_per_pixel */
65 " 32 32 3 1",
66 /* colors */
67 "o c #ffffff",
68 ". c #000000",
69 " c None",
70 /* pixels */
71 " ",
72 " ",
73 " ",
74 " ",
75 " oo ",
76 " oo ",
77 " oo ",
78 " oo ",
79 " oo ",
80 " oo ",
81 " oo ",
82 " oo ",
83 " oo ",
84 " oo ",
85 " oo ",
86 " oooooooooooooooooooooooo ",
87 " oooooooooooooooooooooooo ",
88 " oo ",
89 " oo ",
90 " oo ",
91 " oo ",
92 " oo ",
93 " oo ",
94 " oo ",
95 " oo ",
96 " oo ",
97 " oo ",
98 " oo ",
99 " ",
100 " ",
101 " ",
102 " ",
103 "0,0"
104};
105
106static SDLTest_CommonState *state;
107static int done;
108
109#define PROP_ARROW_CURSOR_TEXTURE "arrow_cursor_texture"
110#define PROP_CROSS_CURSOR_TEXTURE "cross_cursor_texture"
111#define MAX_MICE 3
112#define MAX_KEYBOARDS 3
113#define CURSOR_SIZE 48.0f
114#define MAX_TRAIL 500
115#define TRAIL_SIZE 8.0f
116
117static SDL_Color colors[] = {
118 { 0, 255, 255, 255 }, /* mouse 1, cyan */
119 { 255, 0, 255, 255 }, /* mouse 2, magenta */
120 { 255, 255, 0, 255 }, /* mouse 3, yellow */
121};
122SDL_COMPILE_TIME_ASSERT(mouse_colors, SDL_arraysize(colors) == MAX_MICE);
123SDL_COMPILE_TIME_ASSERT(keyboard_colors, SDL_arraysize(colors) == MAX_KEYBOARDS);
124
125typedef struct
126{
127 SDL_MouseID instance_id;
128 bool active;
129 Uint8 button_state;
130 SDL_FPoint position;
131 int trail_head;
132 int trail_length;
133 SDL_FPoint trail[MAX_TRAIL];
134} MouseState;
135
136static MouseState mice[MAX_MICE];
137
138typedef struct
139{
140 SDL_KeyboardID instance_id;
141 bool active;
142 Uint8 button_state;
143 SDL_FPoint position;
144} KeyboardState;
145
146static KeyboardState keyboards[MAX_KEYBOARDS];
147
148static SDL_Texture *CreateTexture(const char *image[], SDL_Renderer *renderer)
149{
150 SDL_Surface *surface;
151 SDL_Palette *palette;
152 SDL_Texture *texture;
153 int row;
154
155 surface = SDL_CreateSurface(32, 32, SDL_PIXELFORMAT_INDEX8);
156 for (row = 0; row < surface->h; ++row) {
157 SDL_memcpy((Uint8 *)surface->pixels + row * surface->pitch, image[4 + row], surface->w);
158 }
159
160 palette = SDL_CreateSurfacePalette(surface);
161 if (!palette) {
162 SDL_DestroySurface(surface);
163 return NULL;
164 }
165 palette->colors['.'].r = 0xFF;
166 palette->colors['.'].g = 0xFF;
167 palette->colors['.'].b = 0xFF;
168 palette->colors['o'].r = 0xFF;
169 palette->colors['o'].g = 0xFF;
170 palette->colors['o'].b = 0xFF;
171 palette->colors['X'].r = 0x00;
172 palette->colors['X'].g = 0x00;
173 palette->colors['X'].b = 0x00;
174
175 SDL_SetSurfaceColorKey(surface, true, ' ');
176
177 texture = SDL_CreateTextureFromSurface(renderer, surface);
178 SDL_DestroySurface(surface);
179 return texture;
180}
181
182static void HandleMouseAdded(SDL_MouseID instance_id)
183{
184 SDL_Window *window = state->windows[0];
185 int i, w = 0, h = 0;
186
187 SDL_GetWindowSizeInPixels(window, &w, &h);
188
189 for (i = 0; i < SDL_arraysize(mice); ++i) {
190 MouseState *mouse_state = &mice[i];
191 if (!mouse_state->active) {
192 mouse_state->instance_id = instance_id;
193 mouse_state->active = true;
194 mouse_state->position.x = w * 0.5f;
195 mouse_state->position.y = h * 0.5f;
196 return;
197 }
198 }
199}
200
201static void HandleMouseRemoved(SDL_MouseID instance_id)
202{
203 int i;
204
205 for (i = 0; i < SDL_arraysize(mice); ++i) {
206 MouseState *mouse_state = &mice[i];
207 if (instance_id == mouse_state->instance_id) {
208 SDL_zerop(mouse_state);
209 return;
210 }
211 }
212}
213
214static void ActivateMouse(SDL_MouseID instance_id)
215{
216 int i;
217
218 for (i = 0; i < SDL_arraysize(mice); ++i) {
219 MouseState *mouse_state = &mice[i];
220 if (mouse_state->active && instance_id == mouse_state->instance_id) {
221 return;
222 }
223 }
224
225 HandleMouseAdded(instance_id);
226}
227
228static void HandleMouseMotion(SDL_MouseMotionEvent *event)
229{
230 SDL_Window *window = state->windows[0];
231 int i, w = 0, h = 0;
232
233 if (event->which == 0) {
234 /* The system pointer, not a distinct mouse device */
235 return;
236 }
237
238 ActivateMouse(event->which);
239
240 SDL_GetWindowSizeInPixels(window, &w, &h);
241
242 for (i = 0; i < SDL_arraysize(mice); ++i) {
243 MouseState *mouse_state = &mice[i];
244 if (!mouse_state->active) {
245 continue;
246 }
247 if (event->which == mouse_state->instance_id) {
248 float x = (mouse_state->position.x + event->xrel);
249 float y = (mouse_state->position.y + event->yrel);
250
251 x = SDL_clamp(x, 0.0f, (float)w);
252 y = SDL_clamp(y, 0.0f, (float)h);
253
254 mouse_state->position.x = x;
255 mouse_state->position.y = y;
256
257 if (mouse_state->button_state) {
258 /* Add a spot to the mouse trail */
259 SDL_FPoint *spot = &mouse_state->trail[mouse_state->trail_head];
260 spot->x = x - TRAIL_SIZE * 0.5f;
261 spot->y = y - TRAIL_SIZE * 0.5f;
262 if (mouse_state->trail_length < MAX_TRAIL) {
263 ++mouse_state->trail_length;
264 }
265 mouse_state->trail_head = (mouse_state->trail_head + 1) % MAX_TRAIL;
266 }
267 }
268 }
269}
270
271static void HandleMouseButton(SDL_MouseButtonEvent *event)
272{
273 int i;
274
275 if (event->which == 0) {
276 /* The system pointer, not a distinct mouse device */
277 return;
278 }
279
280 ActivateMouse(event->which);
281
282 for (i = 0; i < SDL_arraysize(mice); ++i) {
283 MouseState *mouse_state = &mice[i];
284 if (!mouse_state->active) {
285 continue;
286 }
287 if (event->which == mouse_state->instance_id) {
288 if (event->down) {
289 mouse_state->button_state |= SDL_BUTTON_MASK(event->button);
290 } else {
291 mouse_state->button_state &= ~SDL_BUTTON_MASK(event->button);
292 }
293 }
294 }
295}
296
297static void DrawMouseState(SDL_Window *window, SDL_Renderer *renderer, MouseState *mouse_state, SDL_Texture *cursor, SDL_Color *color)
298{
299 SDL_FRect rect;
300
301 if (!mouse_state->active) {
302 return;
303 }
304
305 if (mouse_state->trail_length > 0) {
306 int i;
307 int spot = mouse_state->trail_head - mouse_state->trail_length;
308 if (spot < 0) {
309 spot += MAX_TRAIL;
310 }
311
312 rect.w = TRAIL_SIZE;
313 rect.h = TRAIL_SIZE;
314 SDL_SetRenderDrawColor(renderer, color->r, color->g, color->b, color->a);
315 for (i = 0; i < mouse_state->trail_length; ++i) {
316 rect.x = mouse_state->trail[spot].x;
317 rect.y = mouse_state->trail[spot].y;
318 SDL_RenderFillRect(renderer, &rect);
319 spot = (spot + 1) % MAX_TRAIL;
320 }
321 }
322
323 rect.x = mouse_state->position.x;
324 rect.y = mouse_state->position.y;
325 rect.w = CURSOR_SIZE;
326 rect.h = CURSOR_SIZE;
327 SDL_SetTextureColorMod(cursor, color->r, color->g, color->b);
328 SDL_RenderTexture(renderer, cursor, NULL, &rect);
329}
330
331static void HandleKeyboardAdded(SDL_KeyboardID instance_id)
332{
333 SDL_Window *window = state->windows[0];
334 int i, w = 0, h = 0;
335
336 SDL_GetWindowSize(window, &w, &h);
337
338 for (i = 0; i < SDL_arraysize(keyboards); ++i) {
339 KeyboardState *keyboard_state = &keyboards[i];
340 if (!keyboard_state->active) {
341 keyboard_state->instance_id = instance_id;
342 keyboard_state->active = true;
343 keyboard_state->position.x = w * 0.5f;
344 keyboard_state->position.y = h * 0.5f;
345 return;
346 }
347 }
348}
349
350static void HandleKeyboardRemoved(SDL_KeyboardID instance_id)
351{
352 int i;
353
354 for (i = 0; i < SDL_arraysize(keyboards); ++i) {
355 KeyboardState *keyboard_state = &keyboards[i];
356 if (instance_id == keyboard_state->instance_id) {
357 SDL_zerop(keyboard_state);
358 return;
359 }
360 }
361}
362
363static void ActivateKeyboard(SDL_KeyboardID instance_id)
364{
365 int i;
366
367 for (i = 0; i < SDL_arraysize(keyboards); ++i) {
368 KeyboardState *keyboard_state = &keyboards[i];
369 if (keyboard_state->active && instance_id == keyboard_state->instance_id) {
370 return;
371 }
372 }
373
374 HandleKeyboardAdded(instance_id);
375}
376
377static void HandleKeyboardKeyDown(SDL_KeyboardEvent *event)
378{
379 SDL_Window *window = state->windows[0];
380 int i, w = 0, h = 0;
381
382 SDL_GetWindowSize(window, &w, &h);
383
384 ActivateKeyboard(event->which);
385
386 for (i = 0; i < SDL_arraysize(keyboards); ++i) {
387 KeyboardState *keyboard_state = &keyboards[i];
388 if (!keyboard_state->active) {
389 continue;
390 }
391 if (event->which == keyboard_state->instance_id) {
392 switch (event->key) {
393 case SDLK_LEFT:
394 keyboard_state->position.x -= CURSOR_SIZE;
395 if (keyboard_state->position.x < 0.0f) {
396 keyboard_state->position.x = 0.0f;
397 }
398 break;
399 case SDLK_RIGHT:
400 keyboard_state->position.x += CURSOR_SIZE;
401 if (keyboard_state->position.x > w) {
402 keyboard_state->position.x = (float)w;
403 }
404 break;
405 case SDLK_UP:
406 keyboard_state->position.y -= CURSOR_SIZE;
407 if (keyboard_state->position.y < 0.0f) {
408 keyboard_state->position.y = 0.0f;
409 }
410 break;
411 case SDLK_DOWN:
412 keyboard_state->position.y += CURSOR_SIZE;
413 if (keyboard_state->position.y > h) {
414 keyboard_state->position.y = (float)h;
415 }
416 break;
417 default:
418 break;
419 }
420 }
421 }
422}
423
424static void DrawKeyboardState(SDL_Window *window, SDL_Renderer *renderer, KeyboardState *keyboard_state, SDL_Texture *cursor, SDL_Color *color)
425{
426 SDL_FRect rect;
427
428 if (!keyboard_state->active) {
429 return;
430 }
431
432 rect.x = keyboard_state->position.x - CURSOR_SIZE / 2;
433 rect.y = keyboard_state->position.y - CURSOR_SIZE / 2;
434 rect.w = CURSOR_SIZE;
435 rect.h = CURSOR_SIZE;
436 SDL_SetTextureColorMod(cursor, color->r, color->g, color->b);
437 SDL_RenderTexture(renderer, cursor, NULL, &rect);
438}
439
440static void loop(void)
441{
442 int i, j;
443 SDL_Event event;
444
445 /* Check for events */
446 while (SDL_PollEvent(&event)) {
447 SDLTest_CommonEvent(state, &event, &done);
448
449 switch (event.type) {
450 case SDL_EVENT_KEYBOARD_ADDED:
451 /* Wait for events before activating this keyboard */
452 break;
453 case SDL_EVENT_KEYBOARD_REMOVED:
454 HandleKeyboardRemoved(event.kdevice.which);
455 break;
456 case SDL_EVENT_KEY_DOWN:
457 HandleKeyboardKeyDown(&event.key);
458 break;
459 case SDL_EVENT_MOUSE_ADDED:
460 /* Wait for events before activating this mouse */
461 break;
462 case SDL_EVENT_MOUSE_REMOVED:
463 HandleMouseRemoved(event.mdevice.which);
464 break;
465 case SDL_EVENT_MOUSE_MOTION:
466 HandleMouseMotion(&event.motion);
467 break;
468 case SDL_EVENT_MOUSE_BUTTON_DOWN:
469 case SDL_EVENT_MOUSE_BUTTON_UP:
470 HandleMouseButton(&event.button);
471 break;
472 default:
473 break;
474 }
475 }
476
477 for (i = 0; i < state->num_windows; ++i) {
478 SDL_Window *window = state->windows[i];
479 SDL_Renderer *renderer = state->renderers[i];
480 SDL_Texture *arrow_cursor = (SDL_Texture *)SDL_GetPointerProperty(SDL_GetRendererProperties(renderer), PROP_ARROW_CURSOR_TEXTURE, NULL);
481 SDL_Texture *cross_cursor = (SDL_Texture *)SDL_GetPointerProperty(SDL_GetRendererProperties(renderer), PROP_CROSS_CURSOR_TEXTURE, NULL);
482
483 SDL_SetRenderDrawColor(renderer, 128, 128, 128, 255);
484 SDL_RenderClear(renderer);
485
486 for (j = 0; j < SDL_arraysize(mice); ++j) {
487 DrawMouseState(window, renderer, &mice[j], arrow_cursor, &colors[j]);
488 }
489
490 for (j = 0; j < SDL_arraysize(keyboards); ++j) {
491 DrawKeyboardState(window, renderer, &keyboards[j], cross_cursor, &colors[j]);
492 }
493
494 SDL_RenderPresent(renderer);
495 }
496}
497
498int main(int argc, char *argv[])
499{
500 int i;
501
502 /* Log all events, including mouse motion */
503 SDL_SetHint(SDL_HINT_EVENT_LOGGING, "2");
504
505 /* Support for multiple keyboards requires raw keyboard events on Windows */
506 SDL_SetHint(SDL_HINT_WINDOWS_RAW_KEYBOARD, "1");
507
508 /* Initialize test framework */
509 state = SDLTest_CommonCreateState(argv, SDL_INIT_VIDEO);
510 if (!state) {
511 return 1;
512 }
513 for (i = 1; i < argc;) {
514 int consumed;
515
516 consumed = SDLTest_CommonArg(state, i);
517 if (consumed < 0) {
518 SDLTest_CommonLogUsage(state, argv[0], NULL);
519 SDLTest_CommonQuit(state);
520 return 1;
521 }
522 i += consumed;
523 }
524
525 if (!SDLTest_CommonInit(state)) {
526 SDLTest_CommonQuit(state);
527 return 2;
528 }
529
530 /* Create the cursor textures */
531 for (i = 0; i < state->num_windows; ++i) {
532 SDL_Renderer *renderer = state->renderers[i];
533 SDL_Texture *cursor_arrow = CreateTexture(arrow, renderer);
534 SDL_Texture *cursor_cross = CreateTexture(cross, renderer);
535
536 SDL_SetPointerProperty(SDL_GetRendererProperties(renderer), PROP_ARROW_CURSOR_TEXTURE, cursor_arrow);
537 SDL_SetPointerProperty(SDL_GetRendererProperties(renderer), PROP_CROSS_CURSOR_TEXTURE, cursor_cross);
538
539 /* We only get mouse motion for distinct devices when relative mode is enabled */
540 SDL_SetWindowRelativeMouseMode(state->windows[i], true);
541 }
542
543 /* Main render loop */
544 done = 0;
545 while (!done) {
546 loop();
547 }
548
549 SDLTest_CommonQuit(state);
550 return 0;
551}