Refactor mouse movement handling
authorWuzzy <Wuzzy2@mail.ru>
Thu, 18 Apr 2019 19:44:25 +0200
changeset 14813 9443dc6663ba
parent 14812 b2beb784e4b5
child 14814 c2793ff4e887
Refactor mouse movement handling
hedgewars/SDLh.pas
hedgewars/hwengine.pas
hedgewars/uCursor.pas
hedgewars/uInputHandler.pas
hedgewars/uMisc.pas
hedgewars/uVariables.pas
hedgewars/uWorld.pas
--- a/hedgewars/SDLh.pas	Tue Apr 16 00:07:15 2019 +0300
+++ b/hedgewars/SDLh.pas	Thu Apr 18 19:44:25 2019 +0200
@@ -109,6 +109,10 @@
     SDL_BUTTON_X1        = 4;
     SDL_BUTTON_X2        = 5;
 
+    // SDL_ShowCursor consts
+    SDL_QUERY = -1;
+    SDL_DISABLE = 0;
+    SDL_ENABLE = 1;
 
     SDL_TEXTEDITINGEVENT_TEXT_SIZE = 32;
     SDL_TEXTINPUTEVENT_TEXT_SIZE   = 32;
@@ -554,6 +558,7 @@
     TSDL_Keycode = LongInt;
     TSDL_Scancode = LongInt;
     TSDL_JoystickID = LongInt;
+    TSDL_bool = LongInt;
 
     TSDL_eventaction = (SDL_ADDEVENT, SDL_PEEPEVENT, SDL_GETEVENT);
 
@@ -1107,6 +1112,7 @@
 function  SDL_RenderReadPixels(renderer: PSDL_Renderer; rect: PSDL_Rect; format: LongInt; pixels: Pointer; pitch: LongInt): LongInt; cdecl; external SDLLibName;
 function  SDL_RenderSetViewport(window: PSDL_Window; rect: PSDL_Rect): LongInt; cdecl; external SDLLibName;
 
+function  SDL_SetRelativeMouseMode(enabled: TSDL_bool): LongInt; cdecl; external SDLLibName;
 function  SDL_GetRelativeMouseState(x, y: PLongInt): Byte; cdecl; external SDLLibName;
 function  SDL_PixelFormatEnumToMasks(format: TSDL_ArrayByteOrder; bpp: PLongInt; Rmask, Gmask, Bmask, Amask: PLongInt): Boolean; cdecl; external SDLLibName;
 
--- a/hedgewars/hwengine.pas	Tue Apr 16 00:07:15 2019 +0300
+++ b/hedgewars/hwengine.pas	Thu Apr 18 19:44:25 2019 +0200
@@ -254,14 +254,17 @@
                 SDL_FINGERUP:
                     onTouchUp(event.tfinger.x, event.tfinger.y, event.tfinger.fingerId);
 {$ELSE}
+                SDL_MOUSEMOTION:
+                    ProcessMouseMotion(event.motion.xrel, event.motion.yrel);
+
                 SDL_MOUSEBUTTONDOWN:
                     if GameState = gsConfirm then
                         ParseCommand('quit', true)
                     else
-                        if (GameState >= gsGame) then ProcessMouse(event.button, true);
+                        if (GameState >= gsGame) then ProcessMouseButton(event.button, true);
 
                 SDL_MOUSEBUTTONUP:
-                    if (GameState >= gsGame) then ProcessMouse(event.button, false);
+                    if (GameState >= gsGame) then ProcessMouseButton(event.button, false);
 
                 SDL_MOUSEWHEEL:
                     begin
@@ -383,8 +386,8 @@
         end;
 
     if not allOK then exit;
-    SDL_ShowCursor(0);
 
+    SDL_ShowCursor(SDL_DISABLE);
 
 {$IFDEF USE_VIDEO_RECORDING}
     if GameType = gmtRecord then
--- a/hedgewars/uCursor.pas	Tue Apr 16 00:07:15 2019 +0300
+++ b/hedgewars/uCursor.pas	Thu Apr 18 19:44:25 2019 +0200
@@ -4,7 +4,9 @@
 
 procedure init;
 procedure resetPosition;
-procedure updatePosition;
+procedure resetPositionDelta();
+procedure updatePositionDelta(xrel, yrel: LongInt);
+procedure updatePosition();
 procedure handlePositionUpdate(x, y: LongInt);
 
 implementation
@@ -13,38 +15,35 @@
 
 procedure init;
 begin
+    SDL_ShowCursor(SDL_DISABLE);
     resetPosition();
+    SDL_SetRelativeMouseMode(SDL_TRUE);
 end;
 
 procedure resetPosition;
 begin
     if GameType = gmtRecord then
         exit;
-    // Move curser by 1px in case it's already centered.
-    // The game camera in the Alpha for 0.9.23 screwed up if
-    // the game started with the mouse already being centered.
-    // This fixes it, but we might have overlooked a related
-    // bug somewhere else.
-    // No big deal since this function is (so far) only called once.
-    SDL_WarpMouse((cScreenWidth div 2) + 1, cScreenHeight div 2);
     SDL_WarpMouse(cScreenWidth div 2, cScreenHeight div 2);
+    resetPositionDelta();
+end;
+
+procedure resetPositionDelta();
+begin
+    CursorPointDelta.X:= 0;
+    CursorPointDelta.Y:= 0;
 end;
 
-procedure updatePosition;
-var x, y: LongInt;
+procedure updatePositionDelta(xrel, yrel: LongInt);
 begin
-	x:= cScreenWidth div 2;
-	y:= cScreenHeight div 2;
-    if GameType <> gmtRecord then
-        SDL_GetMouseState(@x, @y);
+    CursorPointDelta.X:= CursorPointDelta.X + xrel;
+    CursorPointDelta.Y:= CursorPointDelta.Y + yrel;
+end;
 
-    if(x <> cScreenWidth div 2) or (y <> cScreenHeight div 2) then
-    begin
-        handlePositionUpdate(x - cScreenWidth div 2, y - cScreenHeight div 2);
-
-        if cHasFocus and (GameType <> gmtRecord) then
-            SDL_WarpMouse(cScreenWidth div 2, cScreenHeight div 2);
-    end
+procedure updatePosition();
+begin
+    handlePositionUpdate(CursorPointDelta.X, CursorPointDelta.Y);
+    resetPositionDelta();
 end;
 
 procedure handlePositionUpdate(x, y: LongInt);
--- a/hedgewars/uInputHandler.pas	Tue Apr 16 00:07:15 2019 +0300
+++ b/hedgewars/uInputHandler.pas	Thu Apr 18 19:44:25 2019 +0200
@@ -32,7 +32,8 @@
 function  KeyBindToName(bind: shortstring): shortstring;
 //procedure MaskModifier(var code: LongInt; modifier: LongWord);
 procedure MaskModifier(Modifier: shortstring; var code: LongInt);
-procedure ProcessMouse(event: TSDL_MouseButtonEvent; ButtonDown: boolean);
+procedure ProcessMouseButton(event: TSDL_MouseButtonEvent; ButtonDown: boolean);
+procedure ProcessMouseMotion(xrel, yrel: LongInt);
 //procedure ProcessMouseWheel(x, y: LongInt);
 procedure ProcessMouseWheel(y: LongInt);
 procedure ProcessKey(event: TSDL_KeyboardEvent); inline;
@@ -59,7 +60,7 @@
 procedure ControllerButtonEvent(joy, button: Byte; pressed: Boolean);
 
 implementation
-uses uConsole, uCommands, uVariables, uConsts, uUtils, uDebug, uPhysFSLayer;
+uses uConsole, uCommands, uVariables, uConsts, uUtils, uDebug, uPhysFSLayer, uCursor;
 
 const
     LSHIFT = $0200;
@@ -278,7 +279,7 @@
     ProcessKey(code, event.type_ = SDL_KEYDOWN);
 end;
 
-procedure ProcessMouse(event: TSDL_MouseButtonEvent; ButtonDown: boolean);
+procedure ProcessMouseButton(event: TSDL_MouseButtonEvent; ButtonDown: boolean);
 begin
     //writelntoconsole('[MOUSE] '+inttostr(event.button));
     case event.button of
@@ -291,6 +292,11 @@
         end;
 end;
 
+procedure ProcessMouseMotion(xrel, yrel: LongInt);
+begin
+    uCursor.updatePositionDelta(xrel, yrel);
+end;
+
 var mwheelupCode, mwheeldownCode: Integer;
 
 //procedure ProcessMouseWheel(x, y: LongInt);
--- a/hedgewars/uMisc.pas	Tue Apr 16 00:07:15 2019 +0300
+++ b/hedgewars/uMisc.pas	Thu Apr 18 19:44:25 2019 +0200
@@ -26,7 +26,6 @@
 procedure initModule;
 procedure freeModule;
 
-procedure movecursor(dx, dy: LongInt);
 function  doSurfaceConversion(tmpsurf: PSDL_Surface): PSDL_Surface;
 function MakeScreenshot(filename: shortstring; k: LongInt; dump: LongWord): boolean;
 function  GetTeamStatString(p: PTeam): shortstring;
@@ -46,17 +45,6 @@
 
 var conversionFormat : PSDL_PixelFormat;
 
-procedure movecursor(dx, dy: LongInt);
-var x, y: LongInt;
-begin
-if (dx = 0) and (dy = 0) then exit;
-
-SDL_GetMouseState(@x, @y);
-Inc(x, dx);
-Inc(y, dy);
-SDL_WarpMouse(x, y);
-end;
-
 {$IFDEF PNG_SCREENSHOTS}
 // this funtion will be executed in separate thread
 function SaveScreenshot(screenshot: pointer): LongInt; cdecl; export;
--- a/hedgewars/uVariables.pas	Tue Apr 16 00:07:15 2019 +0300
+++ b/hedgewars/uVariables.pas	Thu Apr 18 19:44:25 2019 +0200
@@ -234,6 +234,7 @@
 
     TargetCursorPoint     : TPoint;
     CursorPoint           : TPoint;
+    CursorPointDelta      : TPoint;
     TargetPoint           : TPoint;
 
     ScreenFade      : TScreenFade;
--- a/hedgewars/uWorld.pas	Tue Apr 16 00:07:15 2019 +0300
+++ b/hedgewars/uWorld.pas	Thu Apr 18 19:44:25 2019 +0200
@@ -1974,7 +1974,6 @@
     if CursorPoint.Y < cScreenHeight - (AmmoRect.y + AmmoRect.h - AMSlotSize - 5) then//check bottom
         CursorPoint.Y:= cScreenHeight - (AmmoRect.y + AmmoRect.h - AMSlotSize - 5);
     prevPoint:= CursorPoint;
-    //if cHasFocus then SDL_WarpMouse(CursorPoint.X + cScreenWidth div 2, cScreenHeight - CursorPoint.Y);
     exit
 end;
 
@@ -2030,7 +2029,6 @@
 
 // this moves the camera according to CursorPoint X and Y
 prevPoint:= CursorPoint;
-//if cHasFocus then SDL_WarpMouse(CursorPoint.X + (cScreenWidth shr 1), cScreenHeight - CursorPoint.Y);
 if WorldDy > LAND_HEIGHT + 1024 then
     WorldDy:= LAND_HEIGHT + 1024;
 if WorldDy < wdy then
@@ -2148,10 +2146,21 @@
 
 procedure updateCursorVisibility;
 begin
-    if isPaused or isAFK then
-        SDL_ShowCursor(1)
+    if isPaused or isAFK or (GameState = gsConfirm) then
+        begin
+        SDL_SetRelativeMouseMode(SDL_FALSE);
+        if SDL_ShowCursor(SDL_QUERY) = SDL_DISABLE then
+            begin
+            uCursor.resetPosition;
+            SDL_ShowCursor(SDL_ENABLE);
+            end;
+        end
     else
-        SDL_ShowCursor(ord(GameState = gsConfirm))
+        begin
+        uCursor.resetPositionDelta;
+        SDL_ShowCursor(SDL_DISABLE);
+        SDL_SetRelativeMouseMode(SDL_TRUE);
+        end;
 end;
 
 procedure updateTouchWidgets(ammoType: TAmmoType);