Skip to content

Instantly share code, notes, and snippets.

@DanielGibson
Last active December 6, 2017 16:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save DanielGibson/f357c2f86734f8be39c8a758b1f900e3 to your computer and use it in GitHub Desktop.
Save DanielGibson/f357c2f86734f8be39c8a758b1f900e3 to your computer and use it in GitHub Desktop.
test sdl relative mouse input with mouse warping
// gcc -Wall -o warptest `sdl2-config --cflags` sdl-warptest.c `sdl2-config --libs`
#include <stdio.h>
#include <SDL.h>
// set to 1 to use SDL_GetMouseState() and SDL_WarpMouseInWindow() for custom relative mode
// 0 uses SDL2s relative mode, while enforcing SDL2's internal warping with SDL_HINT_MOUSE_RELATIVE_MODE_WARP
#define DO_WARP_YOURSELF 0
static FILE* outfile = NULL;
static void UpdateWinTitle(int accumX, int accumY, SDL_Window* win)
{
char buf[128];
snprintf(buf, 128, "Accumulated: X: %d Y: %d\n", accumX, accumY);
SDL_SetWindowTitle(win, buf);
}
static void my_SDL_LogOutputFunction(void* userdata,
int category,
SDL_LogPriority priority,
const char* message)
{
fprintf(outfile, "#SDL: %s\n", message);
fflush(outfile);
}
int main(int argc, char** argv)
{
outfile = stdout; // if you can't use stdout on windows, you could fopen() a text file here for logging
SDL_version ver;
SDL_GetVersion(&ver);
fprintf(outfile, "SDL Version: %d.%d.%d\n", (int)ver.major, (int)ver.minor, (int)ver.patch);
SDL_LogSetOutputFunction(my_SDL_LogOutputFunction, NULL);
SDL_Init(SDL_INIT_VIDEO);
SDL_Window* win = SDL_CreateWindow("Move your mouse!", 100, 100, 640, 480, SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE);
//SDL_SetWindowGrab(win, 1);
SDL_Surface* winSurf = SDL_GetWindowSurface(win);
Uint32 grey = SDL_MapRGB(winSurf->format, 127, 127, 127);
// accum* holds the sum of all relative movements and is shown in window title
int accumX = 0, accumY = 0;
#if DO_WARP_YOURSELF
SDL_WarpMouseInWindow(win, 320, 240);
#else
SDL_SetHint(SDL_HINT_MOUSE_RELATIVE_MODE_WARP, "1");
SDL_SetRelativeMouseMode(1);
#endif
int keepRunning = 1;
while(keepRunning) {
winSurf = SDL_GetWindowSurface(win);
SDL_FillRect(winSurf, NULL, grey);
SDL_UpdateWindowSurface(win);
SDL_Delay(10);
SDL_Event ev;
while(SDL_PollEvent(&ev)) {
switch(ev.type) {
case SDL_KEYDOWN:
if(ev.key.keysym.sym == SDLK_q || ev.key.keysym.sym == SDLK_ESCAPE) {
fprintf(outfile, "You pressed Q or Esc - bye!\n");
keepRunning = 0;
}
break;
case SDL_MOUSEMOTION:
if(ev.motion.xrel > 0)
fprintf(outfile, "> Mouse motion: rel: %d %d pos: %d %d\n", (int)ev.motion.xrel, (int)ev.motion.yrel, (int)ev.motion.x, (int)ev.motion.y);
else
fprintf(outfile, "<<< Mouse motion: rel: %d %d pos: %d %d\n", (int)ev.motion.xrel, (int)ev.motion.yrel, (int)ev.motion.x, (int)ev.motion.y);
fflush(outfile);
#if ! DO_WARP_YOURSELF
accumX += ev.motion.xrel;
accumY += ev.motion.yrel;
UpdateWinTitle(accumX, accumY, win);
#endif
break;
}
}
#if DO_WARP_YOURSELF
int x,y, w,h;
SDL_GetMouseState(&x, &y);
SDL_GetWindowSize(win, &w, &h);
x -= w/2;
y -= h/2;
SDL_WarpMouseInWindow(win, w/2, h/2);
fprintf(outfile, "rel Mouse Position: %d %d\n", x, y);
if(x != 0 || y != 0) {
accumX += x;
accumY += y;
UpdateWinTitle(accumX, accumY, win);
}
#endif
fprintf(outfile, "### end of frame ###\n");
fflush(outfile);
}
SDL_DestroyWindow(win);
SDL_Quit();
return 0;
}
// in src/events/SDL_mouse.c added some SDL_Log() calls to SDL_PrivateSendMouseMotion():
#include "SDL_log.h"
static int
SDL_PrivateSendMouseMotion(SDL_Window * window, SDL_MouseID mouseID, int relative, int x, int y)
{
SDL_Mouse *mouse = SDL_GetMouse();
int posted;
int xrel;
int yrel;
if (mouseID == SDL_TOUCH_MOUSEID && !mouse->touch_mouse_events) {
return 0;
}
if (mouseID != SDL_TOUCH_MOUSEID && mouse->relative_mode_warp) {
int center_x = 0, center_y = 0;
SDL_GetWindowSize(window, &center_x, &center_y);
center_x /= 2;
center_y /= 2;
if (x == center_x && y == center_y) {
SDL_Log("## Resetting mouse->last* to %d %d\n", center_x, center_y);
mouse->last_x = center_x; // possible fix for the issue: move this ..
mouse->last_y = center_y; // and this line before the if(x == center_x && y == center_y)
return 0;
}
SDL_Log("## Warping mouse to %d %d\n", center_x, center_y);
SDL_WarpMouseInWindow(window, center_x, center_y);
}
if (relative) {
if (mouse->relative_mode) {
x = GetScaledMouseDelta(mouse->relative_speed_scale, x, &mouse->scale_accum_x);
y = GetScaledMouseDelta(mouse->relative_speed_scale, y, &mouse->scale_accum_y);
} else {
x = GetScaledMouseDelta(mouse->normal_speed_scale, x, &mouse->scale_accum_x);
y = GetScaledMouseDelta(mouse->normal_speed_scale, y, &mouse->scale_accum_y);
}
xrel = x;
yrel = y;
x = (mouse->last_x + xrel);
y = (mouse->last_y + yrel);
} else {
xrel = x - mouse->last_x;
yrel = y - mouse->last_y;
}
SDL_Log("# x,y: %d/%d rel: %d/%d, last: %d/%d\n", x, y, xrel, yrel, mouse->last_x, mouse->last_y);
SDL_Log("# relative: %d mouse->relative_mode: %d\n", relative, mouse->relative_mode);
/* Drop events that don't change state */
if (!xrel && !yrel) {
#ifdef DEBUG_MOUSE
printf("Mouse event didn't change state - dropped!\n");
#endif
return 0;
}
/* Ignore relative motion when first positioning the mouse */
if (!mouse->has_position) {
xrel = 0;
yrel = 0;
mouse->has_position = SDL_TRUE;
}
/* Ignore relative motion positioning the first touch */
if (mouseID == SDL_TOUCH_MOUSEID && !mouse->buttonstate) {
xrel = 0;
yrel = 0;
}
/* Update internal mouse coordinates */
if (!mouse->relative_mode) {
mouse->x = x;
mouse->y = y;
} else {
mouse->x += xrel;
mouse->y += yrel;
}
/* make sure that the pointers find themselves inside the windows,
unless we have the mouse captured. */
if (window && ((window->flags & SDL_WINDOW_MOUSE_CAPTURE) == 0)) {
int x_max = 0, y_max = 0;
/* !!! FIXME: shouldn't this be (window) instead of (mouse->focus)? */
SDL_GetWindowSize(mouse->focus, &x_max, &y_max);
--x_max;
--y_max;
if (mouse->x > x_max) {
mouse->x = x_max;
}
if (mouse->x < 0) {
mouse->x = 0;
}
if (mouse->y > y_max) {
mouse->y = y_max;
}
if (mouse->y < 0) {
mouse->y = 0;
}
}
mouse->xdelta += xrel;
mouse->ydelta += yrel;
/* Move the mouse cursor, if needed */
if (mouse->cursor_shown && !mouse->relative_mode &&
mouse->MoveCursor && mouse->cur_cursor) {
mouse->MoveCursor(mouse->cur_cursor);
}
/* Post the event, if desired */
posted = 0;
if (SDL_GetEventState(SDL_MOUSEMOTION) == SDL_ENABLE) {
SDL_Event event;
event.motion.type = SDL_MOUSEMOTION;
event.motion.windowID = mouse->focus ? mouse->focus->id : 0;
event.motion.which = mouseID;
event.motion.state = mouse->buttonstate;
event.motion.x = mouse->x;
event.motion.y = mouse->y;
event.motion.xrel = xrel;
event.motion.yrel = yrel;
posted = (SDL_PushEvent(&event) > 0);
}
if (relative) {
mouse->last_x = mouse->x;
mouse->last_y = mouse->y;
} else {
/* Use unclamped values if we're getting events outside the window */
mouse->last_x = x;
mouse->last_y = y;
}
return posted;
}
// ...
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment