We are currently migrating Bugzilla to GitHub issues.
Any changes made to the bug tracker now will be lost, so please do not post new bugs or make changes to them.
When we're done, all bug URLs will redirect to their equivalent location on the new bug tracker.

Bug 1174 - Please implement relative mouse mode
Summary: Please implement relative mouse mode
Status: RESOLVED FIXED
Alias: None
Product: SDL
Classification: Unclassified
Component: video (show other bugs)
Version: HG 2.0
Hardware: All All
: P2 blocker
Assignee: Forest Hale
QA Contact: Sam Lantinga
URL:
Keywords:
Depends on:
Blocks: 1052
  Show dependency treegraph
 
Reported: 2011-03-21 14:23 UTC by Sam Lantinga
Modified: 2013-05-21 02:31 UTC (History)
0 users

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Sam Lantinga 2011-03-21 14:23:06 UTC
Relative mouse mode is not implemented on Windows or Linux.  This is a required feature for the next release.
Comment 1 Sam Lantinga 2011-03-21 14:24:21 UTC
Notes from LordHavoc, who volunteered to implement this:

Here are my main notes on Win32:
The windows Raw Input API is ideal for relative mode on XP or above, it is an alternative to DirectInput and highly recommended, QuakeLive makes use of it, among others, its chief feature is extremely low latencies (which gamers love, naturally).
http://msdn.microsoft.com/en-us/library/ms645543%28v=vs.85%29.aspx

... But I don't yet use it, with GDI mouse events there is a technique for disabling mouse acceleration, and its values differ on XP or above vs older windows versions...  Currently in darkplaces I use:
int newmouseparms[3];
newmouseparms[0] = 0; // threshold to double movement (only if accel level is >= 1)
newmouseparms[1] = 0; // threshold to quadruple movement (only if accel level is >= 2)
newmouseparms[2] = 0; // maximum level of acceleration (0 = off)
restore_spi = SystemParametersInfo (SPI_SETMOUSE, 0, newmouseparms, 0) != FALSE;
http://msdn.microsoft.com/en-us/library/ms724947%28v=vs.85%29.aspx
The basic setup is of course the expected:
SetCursorPos (vid.width / 2, vid.height / 2);
SetCapture (mainwindow);
ClipCursor (&window_rect);
cl_ignoremousemoves = 2;

Here are my main notes on X11:
I know nothing about XInput2 at this point so I can't speak to that, what I use in darkplaces is some interesting standard tricks:
Setup:
XGetPointerControl(vidx11_display, &originalmouseparms_num, &originalmouseparms_denom, &originalmouseparms_threshold);
XChangePointerControl (vidx11_display, true, false, 1, 1, -1); // TODO maybe change threshold here, or remove this comment
cl_ignoremousemoves = 2;
XDefineCursor(vidx11_display, win, CreateNullCursor(vidx11_display, win));

Each frame:
case MotionNotify:
if (!event.xmotion.send_event)
{
   in_mouse_x += event.xmotion.x - in_windowmouse_x;
   in_mouse_y += event.xmotion.y - in_windowmouse_y;
   if (vid_stick_mouse.integer || abs(vid.width/2 - event.xmotion.x) > vid.width / 4 || abs(vid.height/2 - event.xmotion.y) > vid.height / 4)
       dowarp = true;
}
in_windowmouse_x = event.xmotion.x;
in_windowmouse_y = event.xmotion.y;
break;

After the events are parsed:
if (dowarp)
{
   /* move the mouse to the window center again */
   // we'll catch the warp motion by its send_event flag, updating the
   // stored mouse position without adding any delta motion
   XEvent event;
   event.type = MotionNotify;
   event.xmotion.display = vidx11_display;
   event.xmotion.window = win;
   event.xmotion.x = vid.width / 2;
   event.xmotion.y = vid.height / 2;
   XSendEvent(vidx11_display, win, False, PointerMotionMask, &event);
   XWarpPointer(vidx11_display, None, win, 0, 0, 0, 0, vid.width / 2, vid.height / 2);
}

This relies on a clever trick - by sending a fake MotionNotify that updates the internal position, when the real MotionNotify occurs it will correctly detect the accumulated relative motion that has occurred during the roundtrip for the XWarpPointer, I.E. this properly streams over the network socket (which matters because of latencies in Xorg, even on a local machine).

I don't know where this trick came from - could be from SDL for all I know :)