Cursor control problems with SDL

Hi all.

I’m having problems with my cursor control modules. I’ve decided that my engine
will take over cursor processing when ever it is instansiated. The reasons for
this is that SDL (my API of choice at the moment) doesn’t automatically provide
cursor processing in fullscreen mode.

Anyway. I’ve got a cursor class that is dervived from my base sprite class. I’m
calling the cursor control during each iteration of the game loop, clearing the
old position, calling pumpevents and the SDL_GetRelativeMouseState() for the X
and Y deltas, adding the new X and Y to the current X and Y values and then
redrawing the cursor sprite.

The old position of the cursor isn’t being removed, the new cursors Y
coordinates doesn’t seem to change and the cursor movement isn’t smooth at all.
I’ve also noticed that if something is happening on screen, ie. I’m drawing
something else, then that stops while the cursor is being moved. I’m assuming
that the get mouse state functions wait until there is no mouse movement/action
before returning?

Does anyone know of any tutorials regarding SDL and cursor controls. The SDL
documentation is pretty scant for this?

I’m using SDL on windows with C++.

Gary,
I’ll bet you’ve got your GetRelativeMouseState inside your event loop.
Moving the mouse creates an amazing number of events, and it is getting
"trapped" inside the event loop until you stop moving the mouse. My
suggestion is that you only read the relative mouse position(or absolute for
that matter) BEFORE or AFTER the event processing loop, and before your
screen drawing routine, so that the mouse position is only updated once per
video frame drawn. If you have a mouse button click event, you can also poll
the cursor location in the code for the click event, for extra precision.
If you post a little bit of your code, it would probably be clear to the
gurus around here(of which I am not!) exactly what’s happening.
-Dave> ----- Original Message -----

From: fleck12jobs@hotmail.com (Gary Fletcher)
To:
Sent: Monday, May 23, 2005 12:36 AM
Subject: [SDL] Cursor control problems with SDL

Hi all.

I’m having problems with my cursor control modules. I’ve decided that my
engine
will take over cursor processing when ever it is instansiated. The reasons
for
this is that SDL (my API of choice at the moment) doesn’t automatically
provide
cursor processing in fullscreen mode.

Anyway. I’ve got a cursor class that is dervived from my base sprite
class. I’m
calling the cursor control during each iteration of the game loop,
clearing the
old position, calling pumpevents and the SDL_GetRelativeMouseState() for
the X
and Y deltas, adding the new X and Y to the current X and Y values and
then
redrawing the cursor sprite.

The old position of the cursor isn’t being removed, the new cursors Y
coordinates doesn’t seem to change and the cursor movement isn’t smooth at
all.
I’ve also noticed that if something is happening on screen, ie. I’m
drawing
something else, then that stops while the cursor is being moved. I’m
assuming
that the get mouse state functions wait until there is no mouse
movement/action
before returning?

Does anyone know of any tutorials regarding SDL and cursor controls. The
SDL
documentation is pretty scant for this?

I’m using SDL on windows with C++.


SDL mailing list
SDL at libsdl.org
http://www.libsdl.org/mailman/listinfo/sdl

David Olsen <jolynsbass hotmail.com> writes:>

Gary,
I’ll bet you’ve got your GetRelativeMouseState inside your event loop.
Moving the mouse creates an amazing number of events, and it is getting
"trapped" inside the event loop until you stop moving the mouse. My
suggestion is that you only read the relative mouse position(or absolute for
that matter) BEFORE or AFTER the event processing loop, and before your
screen drawing routine, so that the mouse position is only updated once per
video frame drawn. If you have a mouse button click event, you can also poll
the cursor location in the code for the click event, for extra precision.
If you post a little bit of your code, it would probably be clear to the
gurus around here(of which I am not!) exactly what’s happening.
-Dave

----- Original Message -----
From: “Gary Fletcher” <fleck12jobs hotmail.com>
To: <sdl libsdl.org>
Sent: Monday, May 23, 2005 12:36 AM
Subject: [SDL] Cursor control problems with SDL

Hi all.

I’m having problems with my cursor control modules. I’ve decided that my
engine
will take over cursor processing when ever it is instansiated. The reasons
for
this is that SDL (my API of choice at the moment) doesn’t automatically
provide
cursor processing in fullscreen mode.

Anyway. I’ve got a cursor class that is dervived from my base sprite
class. I’m
calling the cursor control during each iteration of the game loop,
clearing the
old position, calling pumpevents and the SDL_GetRelativeMouseState() for
the X
and Y deltas, adding the new X and Y to the current X and Y values and
then
redrawing the cursor sprite.

The old position of the cursor isn’t being removed, the new cursors Y
coordinates doesn’t seem to change and the cursor movement isn’t smooth at
all.
I’ve also noticed that if something is happening on screen, ie. I’m
drawing
something else, then that stops while the cursor is being moved. I’m
assuming
that the get mouse state functions wait until there is no mouse
movement/action
before returning?

Does anyone know of any tutorials regarding SDL and cursor controls. The
SDL
documentation is pretty scant for this?

I’m using SDL on windows with C++.


SDL mailing list
SDL libsdl.org
http://www.libsdl.org/mailman/listinfo/sdl

David.

You’re right I am. I’m not too hot with the SDL cursor event stuff so I’ll post
some code if thats okay, it’s missing some inherited stuff and animation stuff
and a few other bits but hope it’s enough.

Loop that’s calling cursor:

void SiSE::m_gameLoop(void)
{
/* The game loop. Loop until the game stack is empty /
while(!m_StateStack.empty())
{
if ((SDL_GetTicks() - m_Timer) >= FRAME_RATE)
{
/
In order to use the function pointed to on top of the stack
/
/
it needs to be called with an object of the appropriate type
/
/
In this case a SiSE object. Pass the function pointer /
/
to a member function that will execute it as (this->*funcPtr)()
*/
ExecuteFunc(m_StateStack.top().funcPtr);

        // Do cursor processing
        cerr <<  "About to process cursor" << endl;
        cursor->mProcessCursor();
        cerr << "Cursor processed" << endl;
        
        m_Timer = SDL_GetTicks();
    }
}

return;

}

Cursor class:

#ifndef INCLUDE_CURSOR_H
#define INCLUDE_CURSOR_H

#include “SiSEBaseSprite.h”
#include “SiSEVector2D.h”

const std::string CURSKEY = “CURSKEY”;
const std::string CLEARKEY = “CURSCLEARKEY”;

class SiSECursor : public SiSEBaseSprite
{
public:
SiSECursor(SDL_Surface *screen, float x = 0.0f, float y = 0.0f, float
speed = 0.0f);
~SiSECursor();
void mProcessCursor(void);
inline void mEnableCurs(void){mEnabled = true;}
inline void mDisableCurs(void){mEnabled = false;}
inline void mToggleCurs(void){mEnabled = !mEnabled;}
inline bool mIsEnabled(void){return mEnabled;}
inline void mSetClearKey(std::string& clrKey){mClearKey = clrKey;}
inline void mSetCursKey(std::string& cursKey){mCursAnimKey = cursKey;}
inline void mSetDefaults(void){mClearKey = CLEARKEY; mCursAnimKey =
CLEARKEY;}

private:
    void mSetCursPos(void);
    void mAddRelCursPos(void);
    void mGetCursPos(void);
    bool mEnabled;
    int mouseAX;
    int mouseAY;
    int mouseRX;
    int mouseRY;
    int button;
    std::string mClearKey;
    std::string mCursAnimKey;

};

#endif

#include “SiSECursor.h”
#include “SDL/SDL.h”

enum MBUTTONS{NONPRESSED,LPRESSED,RPRESSED};

SiSECursor::SiSECursor(SDL_Surface *screen, float x, float y, float speed) :
SiSEBaseSprite(screen,x,y,speed)
{
SDL_ShowCursor(SDL_DISABLE);

mEnabled = true;

mouseAX=0;
mouseAY=0;
mouseRX=0;
mouseRY=0;
button=NONPRESSED;
mCursAnimKey = CURSKEY;
mClearKey = CLEARKEY;

}

SiSECursor::~SiSECursor()
{
mEnabled = false;

SDL_ShowCursor(SDL_ENABLE);

}

void SiSECursor::mProcessCursor()
{

if (mEnabled)
{
    mGetCursPos();
    mAddRelCursPos();
    mAnimKey = mClearKey;
    clearBG();
    mAnimKey = mCursAnimKey;
    draw();
}

return;

}

void SiSECursor::mAddRelCursPos()
{
std::cerr << "mAddRelCursPos() - mouseRX: " << mouseRX << std::endl;
std::cerr << "mAddRelCursPos() - mouseRY: " << mouseRY << std::endl;

xyAdd(mouseRX,mouseRY);

}

void SiSECursor::mSetCursPos()
{
xySet(mouseAX,mouseAY);
}

void SiSECursor::mGetCursPos()
{
mouseAX=0;
mouseAY=0;
mouseRX=0;
mouseRY=0;
button=NONPRESSED;

int height = GetHeight();
int width = GetWidth();

SDL_PumpEvents();

SDL_GetMouseState(&mouseAX,&mouseAY);

if (mouseAX < 0)
{
    mouseAX = 0;
}
else if (mouseAX > height)
{
    mouseAX = height;
}
    
if (mouseAY < 0)
{
    mouseAY = 0;
}
else if (mouseAY > width)
{
    mouseAY = width;   
}

SDL_PumpEvents();

SDL_GetRelativeMouseState(&mouseRX,&mouseRY);

if (SDL_GetMouseState(NULL,NULL)&SDL_BUTTON(SDL_BUTTON_LEFT))
{
    button = LPRESSED;
}
else if (SDL_GetMouseState(NULL,NULL)&SDL_BUTTON(SDL_BUTTON_RIGHT))
{
    button = RPRESSED;
}

}

Almost complete. I have just one issue.

While I’m capturing mouse motion the rest of the game engine lags. Is there any
way to limit the length of time that the SDL_GetMouseState() functions runs for?

Gary,
In your code…

void SiSECursor::mGetCursPos()
{
mouseAX=0;
mouseAY=0;
mouseRX=0;
mouseRY=0;
button=NONPRESSED;

int height = GetHeight();
int width = GetWidth();

SDL_PumpEvents();

SDL_GetMouseState(&mouseAX,&mouseAY);

if (mouseAX < 0)
{
    mouseAX = 0;
}
else if (mouseAX > height)
{
    mouseAX = height;
}

if (mouseAY < 0)
{
    mouseAY = 0;
}
else if (mouseAY > width)
{
    mouseAY = width;
}

SDL_PumpEvents();

SDL_GetRelativeMouseState(&mouseRX,&mouseRY);

if (SDL_GetMouseState(NULL,NULL)&SDL_BUTTON(SDL_BUTTON_LEFT))
{
    button = LPRESSED;
}
else if (SDL_GetMouseState(NULL,NULL)&SDL_BUTTON(SDL_BUTTON_RIGHT))
{
    button = RPRESSED;
}

}
You seem to be doing some extra, unneccesary things. You’re pumping the
event queue(sp?) twice - I don’t think you even need to pump it once in
order to ask for the MouseState, relative or otherwise(and it will be
updated when your main game loop calls PollEvents… Well, if you don’t poll
events in your main loop, then maybe you’ll need one of these PumpEvents…)
You could combine the several SDL_GetMouseState’s into two commands, which
will both give you the value of the button being pressed, if any, and
simultaneously give you the absolute mouse coord values. e.g. :

(set your variables, then PumpEvents before this, if it is actually
needed…)
if (SDL_GetMouseState((&mouseAX,&mouseAY)&SDL_BUTTON(SDL_BUTTON_LEFT))
{
button = LPRESSED;
}
else if
(SDL_GetRelativeMouseState(&mouseRX,&mouseRY)&SDL_BUTTON(SDL_BUTTON_RIGHT))
{
button = RPRESSED;
}
after which do you bounds checking on cursor position (x<0, etc.)
This will save you a couple of unneeded mouse position calls. Let me know if
this speeds things up at all (and whether removing both Pumpevents makes
your mouse position inaccurate/out-dated)
-David> ----- Original Message -----

From: fleck12jobs@hotmail.com (Gary Fletcher)
To:
Sent: Monday, May 23, 2005 5:47 PM
Subject: [SDL] Re: Cursor control problems with SDL

Almost complete. I have just one issue.

While I’m capturing mouse motion the rest of the game engine lags. Is
there any
way to limit the length of time that the SDL_GetMouseState() functions
runs for?


SDL mailing list
SDL at libsdl.org
http://www.libsdl.org/mailman/listinfo/sdl

David.

I’ve changed the code quite a lot since I posted. It now looks like:

void SiSECursor::mGetCursPos()
{
SDL_Event event;

button = NONPRESSED;

if (SDL_PollEvent(&event))
{
    if (event.type == SDL_MOUSEMOTION ) 
    {
        SDL_GetMouseState(&mouseAX,&mouseAY);
    }
    else if  (event.type == SDL_MOUSEBUTTONDOWN )
    {
        if (SDL_GetMouseState(NULL,NULL)&SDL_BUTTON(SDL_BUTTON_LEFT))
        {
            button = LPRESSED;
        }
        else if (SDL_GetMouseState(NULL,NULL)&SDL_BUTTON(SDL_BUTTON_RIGHT))
        {
            button = RPRESSED;
        }
    }
}

}

Which is very much simplfied and works a treat for what I need. I do have a
problem with the rest of the system slowing down while I’m moving the mouse
around in my window. Is there anyway to minimise the amount of time the
SDL_GetMosueState() functions revieve input?

David.

I’ve changed the code quite a lot since I posted. It now looks like:

void SiSECursor::mGetCursPos()
{
SDL_Event event;

button = NONPRESSED;

if (SDL_PollEvent(&event))
{

Why not “while (SDL_PollEvent(&event))”, so it eats up the events
all at once, rather than having to come in here (mGetCursPos()) for every
tiny change during a mouse movement?

    if (event.type == SDL_MOUSEMOTION ) 
    {
        SDL_GetMouseState(&mouseAX,&mouseAY);
    }
    else if  (event.type == SDL_MOUSEBUTTONDOWN )
    {
        if (SDL_GetMouseState(NULL,NULL)&SDL_BUTTON(SDL_BUTTON_LEFT))
        {

And here, since you already have “event.type == SDL_MOUSEBUTTONDOWN”,
why not just check “event.button.button” to see which button it was?
(Rather than call “SDL_GetMouseState()”?)

Good luck!On Tue, May 24, 2005 at 05:37:05AM +0000, Gary Fletcher wrote:


-bill!
bill at newbreedsoftware.com
http://newbreedsoftware.com/

I agree with Bill. Now that you have an SDL_event to reference, just use
event.button.button to get which button was pressed(unless you need to
capture the actual “state” of the button - e.g. to drag something, versus
just when the user clicks…).
I’m not sure why you are getting a slowdown though… The GetMouseState
should return very quickly. I’ve never had problems with it slowing things
down. I’m going to assume that it is actually something else slowing you
down - try Bill’s idea of while(SDL_PollEvent(&event)) . Let us know if
things improve…
-David> ----- Original Message -----

From: nbs@sonic.net (Bill Kendrick)
To: "A list for developers using the SDL library. (includes SDL-announce)"

Sent: Tuesday, May 24, 2005 3:19 AM
Subject: Re: [SDL] Re: Cursor control problems with SDL

On Tue, May 24, 2005 at 05:37:05AM +0000, Gary Fletcher wrote:

David.

I’ve changed the code quite a lot since I posted. It now looks like:

void SiSECursor::mGetCursPos()
{
SDL_Event event;

button = NONPRESSED;

if (SDL_PollEvent(&event))
{

Why not “while (SDL_PollEvent(&event))”, so it eats up the events
all at once, rather than having to come in here (mGetCursPos()) for every
tiny change during a mouse movement?

    if (event.type == SDL_MOUSEMOTION )
    {
        SDL_GetMouseState(&mouseAX,&mouseAY);
    }
    else if  (event.type == SDL_MOUSEBUTTONDOWN )
    {
        if (SDL_GetMouseState(NULL,NULL)&SDL_BUTTON(SDL_BUTTON_LEFT))
        {

And here, since you already have “event.type == SDL_MOUSEBUTTONDOWN”,
why not just check “event.button.button” to see which button it was?
(Rather than call “SDL_GetMouseState()”?)

Good luck!


-bill!
bill at newbreedsoftware.com
http://newbreedsoftware.com/


SDL mailing list
SDL at libsdl.org
http://www.libsdl.org/mailman/listinfo/sdl

why not

void SiSECursor::mGetCursPos()
{
button = NONPRESSED;

       SDL_GetMouseState(&mouseAX,&mouseAY);
   }
   else if  (event.type == SDL_MOUSEBUTTONDOWN )
   {
       if (SDL_GetMouseState(NULL,NULL)&SDL_BUTTON(SDL_BUTTON_LEFT))
       {
           button = LPRESSED;
       }
       else if (SDL_GetMouseState(NULL,NULL)&SDL_BUTTON(SDL_BUTTON_RIGHT))
       {
           button = RPRESSED;
       }
   }

}
}

woops, some shortcut command sent it before i was doen, anyway…

void SiSECursor::mGetCursPos()
{
button = NONPRESSED;

Uint8 b = SDL_GetMouseState( &x, &y )

if( b & SDL_BUTTON(1) )
button = LBUTTON;
else if( b & SDL_BUTTON(2) )
button = RBUTTON;

/*
optionally DEFINE LBUTTON SDL_BUTTON(1)
and RBUTTON … and say
button = SDL_GetMouseState(…);
*/
}

with an optional SDL_PumpEvents() if you need it.

wouldn’t polling events here not drop all the events you don’t check(
e.g.) losing SDL_QUIT or keyboard events…?

Guy’s I really appreciate all the help on this.

I’ve changed the code again so it looks like this:

button = NONPRESSED;

Uint8 state = SDL_GetMouseState(&mouseAX,&mouseAY);

if (state & SDL_BUTTON(SDL_BUTTON_LEFT))
{
    button = LPRESSED;
}
else if (state & SDL_BUTTON(SDL_BUTTON_RIGHT))
{
    button = RPRESSED;
}

It works, ie. I still am able to disply the cursor, but I still get lag while
the mouse is moving… Maybe It’d help if I showed you how I’ve got the game loop:

void SiSE::m_gameLoop(void)
{
/* The game loop. Loop until the game stack is empty */
while(!m_StateStack.empty())
{
// Do cursor processing
cursor->mProcessCursor();

    if ((SDL_GetTicks() - m_Timer) >= FRAME_RATE)
    {    
        /* In order to use the function pointed to on top of the stack      */
        /* it needs to be called with an object of the appropriate type     */
        /* In this case a SiSE object. Pass the function pointer      */
        /* to a member function that will execute it as (this->*funcPtr)()  */
        ExecuteFunc(m_StateStack.top().funcPtr);
        
        m_Timer = SDL_GetTicks();
    }
    
}
    
return;

}

Any thoughts?

Question for you Gary, and I can’t really tell from the examples that you’ve
got in your email. Is your code set up in a way that it would redraw the
screen after each mouse motion? I remember in my earlier SDL experiments, I
did something like that, and it would crawl when I moved to mouse, because
for every mouse motion event it would redraw the screen before processing
the next mouse motion event(and LOTS are generated just by moving the mouse
even a little bit.) So, if you rearrange things so that the mouse is not
connected with the screen drawing routine, maybe it will help(I’m grasping
at straws). Also, this just occured to me - Are you using a Hardware surface
for your video surface? Reading from the video buffer is notoriously slow,
so when you read the background info, it might be that that is slowing you
down… Try it in a software surface, and also windowed vs. fullscreen and
see if your results are consistent.
Sorry for the lack of real help.
-David> ----- Original Message -----

From: fleck12jobs@hotmail.com (Gary Fletcher)
To:
Sent: Tuesday, May 24, 2005 12:26 PM
Subject: [SDL] Re: Cursor control problems with SDL

Guy’s I really appreciate all the help on this.

I’ve changed the code again so it looks like this:

button = NONPRESSED;

Uint8 state = SDL_GetMouseState(&mouseAX,&mouseAY);

if (state & SDL_BUTTON(SDL_BUTTON_LEFT))
{
button = LPRESSED;
}
else if (state & SDL_BUTTON(SDL_BUTTON_RIGHT))
{
button = RPRESSED;
}

It works, ie. I still am able to disply the cursor, but I still get lag
while
the mouse is moving… Maybe It’d help if I showed you how I’ve got the
game loop:

void SiSE::m_gameLoop(void)
{
/* The game loop. Loop until the game stack is empty */
while(!m_StateStack.empty())
{
// Do cursor processing
cursor->mProcessCursor();

   if ((SDL_GetTicks() - m_Timer) >= FRAME_RATE)
   {
       /* In order to use the function pointed to on top of the stack 

/
/
it needs to be called with an object of the appropriate type
/
/
In this case a SiSE object. Pass the function pointer
/
/
to a member function that will execute it as
(this->*funcPtr)() */
ExecuteFunc(m_StateStack.top().funcPtr);

       m_Timer = SDL_GetTicks();
   }

}

return;

}

Any thoughts?


SDL mailing list
SDL at libsdl.org
http://www.libsdl.org/mailman/listinfo/sdl

It works, ie. I still am able to disply the cursor, but I still get lag while
the mouse is moving… Maybe It’d help if I showed you how I’ve got the game loop:
void SiSE::m_gameLoop(void)
{
/* The game loop. Loop until the game stack is empty */
while(!m_StateStack.empty())
{
// Do cursor processing
cursor->mProcessCursor();

   if ((SDL_GetTicks() - m_Timer) >= FRAME_RATE)
   {
       /* In order to use the function pointed to on top of the stack      */
       /* it needs to be called with an object of the appropriate type     */
       /* In this case a SiSE object. Pass the function pointer      */
       /* to a member function that will execute it as (this->*funcPtr)()  */
       ExecuteFunc(m_StateStack.top().funcPtr);

       m_Timer = SDL_GetTicks();
   }

}

return;

}

you dont have an SDL_Flip or whatever in your loop. is this called as
one of your function pointers, or do you call the
m_gameLoop() function and draw afterwards.

if the former, you will be processing the mouse multiple times
between frames. how often do you process input events.

a
while( SDL_PollEvent( &event ) {…


}

that is called multiple times beween frames will also slow it down,
but not by much, as mouse events will be passed into the loop,
although how you lag noticably puzz;
es me.

try profiling your code, you could even be on the wrong track as to
what is slowing this down…( not the mouse itself , but what effects
the mouse updates cause )

without more code it is really hard to say

also, if your draw routines or whatever are called by the function
pointers, check how often they are called vs how often you expect they
are called