Mouse too fast for PureBasic?

Just starting out? Need help? Post your questions and find answers here.
jerico2day
User
User
Posts: 37
Joined: Mon Jul 13, 2009 5:41 pm

Re: Mouse too fast for PureBasic?

Post by jerico2day »

That's a good point. Perhaps the simplest method would be to keep the mouse in a fixed position, then find out where the mouse is at on every frame, reset the mouse to it's fixed position, and calculate how far the mouse moved since the last frame.

With this method, the mouse cannot move faster than the edge of the screen on any frame (usually not an issue), and you don't need to poll a thousand times a second, just 60 times a second (or whatever you want, really), and you can use the built in mouse commands to do this, I believe. I'm a newb to pb, so perhaps this won't work, or has already been suggested. I didn't reread this thread :P
User avatar
Rescator
Addict
Addict
Posts: 1769
Joined: Sat Feb 19, 2005 5:05 pm
Location: Norway

Re: Mouse too fast for PureBasic?

Post by Rescator »

jerico2day wrote:That's a good point. Perhaps the simplest method would be to keep the mouse in a fixed position, then find out where the mouse is at on every frame, reset the mouse to it's fixed position, and calculate how far the mouse moved since the last frame.
Hmm! I believe that is how Valve said they do things with "Counter Strike: Source" and it did cause some issues with either high sensitivity and large movements or low sensitivity and large movements (forgot which). so you should test this extensively in that case.

One thing for sure, the mouse should not change behavior depending on whether Vsync is on or not. (too many games does sadly),
which is silly as vsync is display/refresh related and should have nothing to do with input or other timing really.
AndyMK
Enthusiast
Enthusiast
Posts: 582
Joined: Wed Jul 12, 2006 4:38 pm
Location: UK

Re: Mouse too fast for PureBasic?

Post by AndyMK »

Rescator wrote:One thing for sure, the mouse should not change behavior depending on whether Vsync is on or not. (too many games does sadly),
which is silly as vsync is display/refresh related and should have nothing to do with input or other timing really.
I recently made a post about this and there is not much that can be done. Many games suffer with what seems to be mouse lag when vsync is enabled, i presume this is what you are talking about. The problem is, DX9 defaults to 3 pre rendered frames before screen output so you effectively get 50ms of delay @ 60fps before you see the result of your mouse input. Some games are programmed to override this and some GPU drivers also have an option to tweak this.
User avatar
Rescator
Addict
Addict
Posts: 1769
Joined: Sat Feb 19, 2005 5:05 pm
Location: Norway

Re: Mouse too fast for PureBasic?

Post by Rescator »

In which case the input might need to be checked at 3 times that. Which is 180hz or (1000/180=) 5.55555....ms
(hmm, is this why Windows Mediaplayer devs. ended up using timeBeginPeriod(5) maybe?)
krensauce
User
User
Posts: 18
Joined: Sun Nov 05, 2006 10:24 pm

Re: Mouse too fast for PureBasic?

Post by krensauce »

Rescator wrote:

Code: Select all

InitSprite()
InitMouse()

OpenWindow(0, 0, 0, 640, 480, "Crap Mouse Movement", #PB_Window_MinimizeGadget | #PB_Window_ScreenCentered | #PB_Window_BorderLess)
OpenWindowedScreen(WindowID(0), 0, 0, 640, 480, 0, 0, 0, #PB_Screen_SmartSynchronization)

CreateSprite(0, 32, 32)
StartDrawing(SpriteOutput(0))
Box(0, 0, 32, 32, #Blue)
StopDrawing()

Global mousex.i,mousey.i

Procedure mousethread(flag.i)
	Static quit.i
	If flag
		Repeat
		   ExamineMouse()
		   mousex=MouseX()
		   mousey=MouseY()
			Delay(1)
		Until quit
		quit=#False
	Else
		If Not flag
			quit=#True
			While quit
				Delay(1)
			Wend
		EndIf
	EndIF
EndProcedure

CreateThread(@mousethread(),#True)
Repeat
   Repeat
      Event = WindowEvent()
      Select Event
         Case #PB_Event_CloseWindow
            Quit = 1
      EndSelect
   Until Event = 0
   
   ClearScreen(#Black)
   DisplaySprite(0, mousex, mousey)
   FlipBuffers()
   Delay(10)
Until  Quit Or (GetKeyState_(#VK_ESCAPE)&%10000000 And GetActiveWindow() = pWnd)
mousethread(#False)
CloseScreen()
End
Hi I have the same problem. Well, not really myself but a friend of mine, so this is very hard to both catch and fix.
Anyway, the code above seems to fix the problem (so thanks for it), but there must be a bug in PB or something that makes that effort kinda wasted, and it's the fact that, for some reason, the system pointer is placed on top of the used sprite, no matter what you do, and only if the ExamineSprite() is put into a thread.
I'm using PB 4.51 x86 btw.

I managed to fix it by adding an ExamineThread() right before the CreateThread(@mousethread(),#True), but then, if you alt-tab out of the window and then go back, the pointer is there again.

I tried everything really, even killing the thread when IsScreenActive()=#False, and then doing the ExamineMouse()->CreateThread() "trick" when you go back to the game's window, but it doesn't work anymore, seems to work only 1st time you do it.

So I'm wondering if there's a way to fix that (it doesn't look well to have the system pointer on top of my own sprite), or if I'll simply have to not put ExamineMouse() into a thread and change the rest of the code instead (so that ExamineMouse() will get executed every ms, but the rest of the code will get executed less often).
I'd like to have it on a thread though.

P.S.
that system pointer bug is showing on both mine and my friend's system, which are very different too. Mine's XP32 SP3, and his one is win7/64.
User avatar
Rescator
Addict
Addict
Posts: 1769
Joined: Sat Feb 19, 2005 5:05 pm
Location: Norway

Re: Mouse too fast for PureBasic?

Post by Rescator »

Hmm. FlipBuffers() updates various states. It's possible that ExamineMouse kinda relies on that too.
Full screen and windowed screen also behave slightly different.

So yeah it seems that the mousethread kinda messes up the hiding of the mouse.
I guess you could report that as a bug and see what the PureBasic team thinks of it.
Ideally it should be possible to do this properly (i.e. the mouse hiding as it should when input and GUI/drawing is in the same thread)
as having input and output asyncronous avoids the input/output lag that many hate in "mouse" games.

You could try the following (same code as in your post with some minor tweaks), it's all kinda quick'n dirty, but hopefully shows you how to do it.

Code: Select all

InitSprite()
InitMouse()

OpenWindow(0, 0, 0, 640, 480, "Crap Mouse Movement", #PB_Window_MinimizeGadget | #PB_Window_ScreenCentered | #PB_Window_BorderLess)
OpenWindowedScreen(WindowID(0), 0, 0, 640, 480, 0, 0, 0, #PB_Screen_SmartSynchronization)

CreateSprite(0, 32, 32)
StartDrawing(SpriteOutput(0))
Box(0, 0, 32, 32, #Blue)
StopDrawing()

Global mousex.i,mousey.i,screenactive.i

Procedure mousethread(flag.i)
   Static quit.i
   If flag
      Repeat
         If ExamineMouse()
            mousex=MouseX()
            mousey=MouseY()
         EndIf
         Delay(1)
      Until quit
      quit=#False
   Else
      If Not flag
         quit=#True
         While quit
            Delay(1)
         Wend
      EndIf
   EndIF
EndProcedure

Define testscreenactive.i=#True
CreateThread(@mousethread(),#True)
Repeat
   Repeat
      Event = WindowEvent()
      Select Event
         Case #PB_Event_CloseWindow
            Quit = 1
      EndSelect
   Until Event = 0
   
   ClearScreen(#Black)
   DisplaySprite(0, mousex, mousey)

   FlipBuffers()
   testscreenactive=IsScreenActive()
   If testscreenactive<>screenactive
      screenactive=testscreenactive
   	If screenactive=1
   		ReleaseMouse(#False)
   		ShowCursor_(#False)
   	Else
   		ReleaseMouse(#True)
   		ShowCursor_(#True)
   	EndIf
   EndIf

   Delay(10)
Until  Quit Or (GetKeyState_(#VK_ESCAPE)&%10000000 And GetActiveWindow() = pWnd)
mousethread(#False)
CloseScreen()
End
krensauce
User
User
Posts: 18
Joined: Sun Nov 05, 2006 10:24 pm

Re: Mouse too fast for PureBasic?

Post by krensauce »

I've been playing alot with this stuff but didn't have time to post earlier.

I came to your same conclusion, that using ShowCursor_() is the only way to fix it.

But then I found out another problem.
Seems like putting the ExamineMouse() in a thread gives many more problems than it solves. This is actually the only working (and easy to implement) solution I've found for the mouse sensitivity problem, but it basically breaks the fullscreen mode.

Not only it breaks the mouse pointer hiding, but (and this is even more important), it breaks IsScreenActive(), but only if your screen is fullscreen, while it seems to be working fine in windowedscreen mode.

To check this, I have modified Dobro's great solution to the alt-tab problem of the fullscreen mode:

Code: Select all

; Purebasic 4.41
;By Dobro
; exemple de l'utilisation de IsScreenActive()

; quittez le pseudo jeux avec Alt+TAB
; on retourne dans le jeux d'un clique sur la fenetre en barre des taches

#threadedmouse=1  ;set to 0 to disable mousethread(), 1 to enable it

InitSprite ()
InitMouse ()
InitKeyboard ()
Enumeration
         #sprite
EndEnumeration
Structure sprite
        x.i
        y.i
        pas_x.i
        pas_y.i
EndStructure
Dim sprite.sprite(1)
ExamineDesktops ()
x_screen= DesktopWidth (0) ; je recup la rez de l'ecran
y_screen= DesktopHeight (0)
flag=0

CompilerIf #threadedmouse=1
firstrun=1
Global mousex.i,mousey.i

Procedure mousethread(flag.i)
Static quit.i
If flag
  Repeat
      ExamineMouse()
      mousex=MouseX()
      mousey=MouseY()
      Delay(1)
  Until quit
  quit=#False
Else
  If Not flag
    quit=#True
    While quit
      Delay(1)
    Wend
  EndIf
EndIf
EndProcedure
CompilerEndIf

debut: ; le label qui permet le retour dans le jeux !!
OpenScreen (x_screen, y_screen, 32, "Fullscreen + ALT-TAB démo" )
ReleaseMouse (0)
CompilerIf #threadedmouse=1
If firstrun=1
  CreateThread(@mousethread(),#True)
  firstrun=0
EndIf
CompilerEndIf

CreateSprite ( #sprite , 64, 64)
StartDrawing ( SpriteOutput ( #sprite ))
         Box (0,0,64,64, RGB (255,13,40))
StopDrawing ()


;********* initialisation du sprite **********
If flag=0 ; le joueur n'est jamais sorti du jeu , s'il est sorti on ne fais pas ce bloc de code !!
sprite(1)\x=x_screen/2 ; on place le sprite au centre
sprite(1)\y=y_screen/2 ; on place le sprite au centre
sprite(1)\pas_x=2 ; on donne une vitesse de deplacement a notre sprite
sprite(1)\pas_y=2 ; on donne une vitesse de deplacement a notre sprite
EndIf

Repeat
         ExamineKeyboard () ; ne sert que pour quitter le prg avec la touche esc
    
         ; ************* gere le deplacement du sprite ***************
        sprite(1)\x=sprite(1)\x+sprite(1)\pas_x
        sprite(1)\y=sprite(1)\y+sprite(1)\pas_y
                 ; ----------------------------------------------------------------------------
         If sprite(1)\x+64>=x_screen:sprite(1)\pas_x=-sprite(1)\pas_x: EndIf
         If sprite(1)\y+64>=y_screen:sprite(1)\pas_y=-sprite(1)\pas_y: EndIf
         ; ----------------------------------------------------------------------------
         If sprite(1)\x<=0:sprite(1)\pas_x=-sprite(1)\pas_x: EndIf
         If sprite(1)\y<=0:sprite(1)\pas_y=-sprite(1)\pas_y: EndIf
         ; *******************************************************
        
        
         ; ********** affichage du sprite *********************
         DisplayTransparentSprite ( #sprite , sprite(1)\x, sprite(1)\y)
        
         FlipBuffers ()
         ClearScreen (0)
        
         ; *************** attention toute l'astuce est la !! *******************
         If IsScreenActive () = 0 ; le joueur a quitter le jeu (Alt-tab)
                 ReleaseMouse (1) ; je libere la souris ... inutile ici mais bon
                flag=1 ; on note que l'utilisateur est sorti du jeux
                 CloseScreen () ; on ferme l'ecran
                
                 ; ******* la ruse de guerre !! ****************************
                 OpenWindow (1,1,1,1,1, "toto le jeu " , #PB_Window_Minimize ) ; j'ouvre une fenetre que je minimise en bar des taches
                 Repeat :Event= WaitWindowEvent (2): Until Event= #PB_Event_ActivateWindow ; j'attend qu'on clique sur la fenetre
                 CloseWindow (1) ; je ferme la fenetre
                 Goto debut ; je retourne dans le jeux sans réinitialiser les variables de déplacement (on reprends ou on en etait! !!! )
     EndIf
Until KeyboardPushed ( #PB_Key_Escape ) ; là , on veux vraiment quitter le jeux LOL
End 
In the example above, activating the mousethread will break IsScreenActive() as it will not report any status change in that case.
In my game I'm trying to support both windowedscreen and fullscreen modes, and that code works fine when in windowedscreen, but not in fullscreen mode.

What's worse, is another problem I found. After some compiles of my code, both the windowedscreen and fullscreen modes gets broken so much that they either shows a black screen and nothing else (the debugger reports no error but Stop doesn't work anymore), or the debugger (and the executable) quits by themselves without reporting anything wrong when you alt-tab.
The only solution is to reboot the system, but then the problem reappears again after some compiles.
What's weird, is that this problem also affects executables I compiled (and tested to be working fine) days or weeks ago (but that contains the same mousethread() handling), but ALT-TAB still works fine on executables which doesn't use that thread.
Even compiling a game or 2D example which uses alt-tab works in this state, as long as you don't use the mousethread(). It's like something in memory gets corrupted, but only affects programs made with that same thread (which should be recreated anew everytime you run another executable I think, but it's like in this case the system keeps using the same one).

I have tried debugging the mousethread() address and it looks like it's always the same unless you restart PB, in which case it changes but the game is still broken.
I'm not sure if it happens also in that example above, but you can try recompiling it for some times (10 or more), until alttabbing out doesn't work anymore (the window in the taskbar will no longer show "toto le jeu" but will have the screen name, "Fullscreen + ALT-TAB démo"). What I am sure of is that when my game doesn't work anymore, that example doesn't work aswell, and the only way to fix it is to compile without the mousethread().

I wonder if not quitting the thread manually (with mousethread(#false)) might be the culprit, I'll check it myself but I need to reboot before, but anyway shouldn't the thread be closed by PB itself at End?

This stuff is really weird, and all of these problems took me more time than coding the game itself :/
krensauce
User
User
Posts: 18
Joined: Sun Nov 05, 2006 10:24 pm

Re: Mouse too fast for PureBasic?

Post by krensauce »

Ok I've been playing some more and I've found a better working solution, though some bugs still remains.

I'd like to make this work and then post it in tricks'n'tips section, or what else is a right section for a temporary solution for problems like the high DPI mouse handling and all needed PB's bugs workarounds (but also in the bugs section).

The windowedscreen mode has no problems at all. I'm able to use it in my own game without any problems, but the fullscreen mode is the one that's giving me headaches, so I'm only posting about it now, then, when a fully working workaround is found, I'll post a working solution for both modes, so that 2D game coders can have a working skeleton for their games, to support both screen modes with the same source.

This new source has a seemingly working ALT-TAB plus mousethread(), but when you get back into the screen, the mouse seems to be laggy, slower than usual and the system busy pointer is shown aswell. ShowCursor_() seems to have no effect on fullscreen, while it successfully fixes this system pointer problem in windowed mode.
I've edited the source to make it as small as possible, and rewrote comments in english:

Code: Select all

#threadedmouse=1  ;set to 0 to disable mousethread(), 1 to enable it

InitSprite()
InitMouse()
InitKeyboard()

#sprite=0

Define spritex.i,spritey.i

ExamineDesktops()
x_screen=DesktopWidth(0)  ;Using desktop resolution for our screen
y_screen=DesktopHeight(0)

CompilerIf #threadedmouse=1
Global mousex.i,mousey.i,mthread.l

Procedure mousethread(flag.i)
Static quit.i
If flag
  Repeat
      ExamineMouse()
      mousex=MouseX()
      mousey=MouseY()
      Delay(1)
  Until quit
  quit=#False
Else
  If Not flag
    quit=#True
    While quit
      Delay(1)
    Wend
  EndIf
EndIf
EndProcedure
mousestatus=1
CompilerEndIf

debut:  ;this label allows us to return to our game and reload the needed data
OpenScreen(x_screen,y_screen,32,"Fullscreen + ALT-TAB demo")
ReleaseMouse(0)
ShowCursor_(0)  ;this fixes windowedscreen system mouse pointer showing up on top of your Sprite
CompilerIf #threadedmouse=1
If mousestatus=1
  mthread.l=CreateThread(@mousethread(),#True)
  mousestatus=0
EndIf
CompilerEndIf

CreateSprite(#sprite,64,64)
StartDrawing(SpriteOutput(#sprite))
Box(0,0,64,64,RGB(255,13,40))
StopDrawing()

Repeat
    ExamineKeyboard() ;we examine the keyboard to handle the Esc key, used to quit
    
    CompilerIf #threadedmouse=0
    ExamineMouse()
    spritex=MouseX()
    spritey=MouseY()
    CompilerElse
    spritex=mousex
    spritey=mousey
    CompilerEndIf
    
    DisplayTransparentSprite(#sprite,spritex,spritey)
    
    FlipBuffers()
    ClearScreen(0)
    
    If IsScreenActive()=0  ;the game lost focus, aka the user pressed ALT-TAB
      ReleaseMouse(1)
      ShowCursor_(1)
      CompilerIf #threadedmouse=1
      mousethread(#False)  ;need to close the mousethread in fullscreen mode or the game won't be able to alt-tab
                           ;note that this is not needed in case of a windowedscreen
      WaitThread(mthread)
      mousestatus=1
      CompilerEndIf
      CloseScreen()  ;closing screen
      
      ;ALT-TAB handling for fullscreen mode
      OpenWindow(1,1,1,1,1,"return to game",#PB_Window_Minimize)  ;we need to open a dummy window, used to handle user click on the taskbar or alt-tab back in game
      Repeat:Event=WaitWindowEvent(2):Until Event=#PB_Event_ActivateWindow  ;waiting for the user to activate the window
      CloseWindow(1)  ;the user wants to get back into game, the window is not needed anymore so we can close it
      Goto debut  ;let's get back in game. we need to reopen the screen and reload the sprites
    EndIf
    
Until KeyboardPushed(#PB_Key_Escape)  ;Esc is used to exit the game
CompilerIf #threadedmouse=1
If IsThread(mthread)
  mousethread(#False)
EndIf
CompilerEndIf
End
As you can see, I managed to fix the alt-tab problem by closing the mousethread before closing the screen, and then restarting it when the screen is reopened.
The "mousestatus" variable is just an additional check to prevent running the thread more than once. It can be removed with this implementation.

So yeah, I'll keep playing with this because my game is on hold until I can find a solution to all the problems. If anyone has an idea please post.
Ruuttu
New User
New User
Posts: 8
Joined: Tue Jun 28, 2011 5:47 pm

Re: Mouse too fast for PureBasic?

Post by Ruuttu »

Is there still a fix or workaround for this problem?

- Due to high pollrate of my mouse, ExamineMouse() needs to be called in a separate thread.
- Due to it being in a separate thread, when alt-tabbing out and back into the program the mouse cursor is now permanently visible on top of the fullscreen application.
~Rudolf Enberg
PMV
Enthusiast
Enthusiast
Posts: 727
Joined: Sat Feb 24, 2007 3:15 pm
Location: Germany

Re: Mouse too fast for PureBasic?

Post by PMV »

After i found this thread again ... it could be interesting for some people:
If you call ShowCursor_(0) twice, my mouse is hidden. I have copied the
call after ReleaseMouse(0) and added it before OpenScreen() :)
Post Reply