Atlas - testmanymouse.c

Home / ext / SDL / test Lines: 1 | Size: 16673 bytes [Download] [Show on GitHub] [Search similar files] [Raw] [Raw (proxy)]
[FILE BEGIN]
1/* 2 Copyright (C) 1997-2025 Sam Lantinga <[email protected]> 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} 552
[FILE END]
(C) 2025 0x4248 (C) 2025 4248 Media and 4248 Systems, All part of 0x4248 See LICENCE files for more information. Not all files are by 0x4248 always check Licencing.