Sign in to follow this  
rai_chu

leaving window area question - SDL_Mouse

Recommended Posts

rai_chu    128
could any SDL expert out there tell, how to detect the event when player move mouse(cursor) out of window area in window-mode? I want to hide my custom-made cursor image when that happen, (so it work similar to SDL system mouse behavior) thank you in advance. PS. I try detected X,Y position (using getMouseState & getRelativeMouseState) and it doesn't work, the last update isn't edge position of screen when player quickly move mouse out of screen/window area.

Share this post


Link to post
Share on other sites
Drew_Benton    1861
With SDL itself, this is not possible, but if you are using a Win32 environment, this is possible. I have made you a little test program showing it. I took the Cone3D tutorial and modded it so when you move the cursor out of the window, nothing is drawn. If you follow what I did, you should be able to do the same with your project. If you have any questions on what I did, feel free to ask.

This is just a proof of concept example, a simple console. You can copy and paste into a new project and it will compile correctly. All you will have to do is make sure you change the runtime settings to MultiThreaded DLL though, as required for SDL apps. Test it out first before trying to move it to your program so you can see how it works.


#include <stdio.h>
#include <stdlib.h>
#include <windows.h>

#include <SDL/SDL.h>

#pragma comment(lib,"SDLmain.lib")
#pragma comment(lib,"SDL.lib")

void Slock(SDL_Surface *screen);
void Sulock(SDL_Surface *screen);
void DrawPixel(SDL_Surface *screen, int x, int y, Uint8 R, Uint8 G, Uint8 B);

SDL_Surface *screen;

HWND hwnd = 0;
RECT rect;
POINT point;
const char* windowclass = "SDL_app";
const char* windowtitle = "SDL_app";
int x, y;

void DrawScene(SDL_Surface *screen)
{
SDL_FillRect( screen,0,0);
static bool cursor = 1;
if( !hwnd )
{
hwnd = ::FindWindow( windowclass, windowtitle );
}

if( hwnd )
{
// Get window info
::GetWindowRect(hwnd,&rect);

// Get window cursor pos
::GetCursorPos(&point);

// Get SDL mouse post
SDL_GetMouseState(&x,&y);

// Now see if the mouse is in there
if(
// If it is to the left of the window
( point.x < rect.left ) ||
// If it is to the right of the window
( point.x > rect.right ) ||
// If it is to the top of the window
( point.y < rect.top ) ||
// If it is to the bottom of the window
( point.y > rect.bottom ) )
{
cursor = 0;
}
else
cursor = 1;
}

if( !cursor )
{
SDL_Flip(screen);
return;
}

Slock(screen);
for(x=0;x<640;x++)
{
for(int y=0;y<480;y++)
{
DrawPixel(screen, x,y,y/2,y/2,x/3);
}
}
Sulock(screen);
SDL_Flip(screen);
}

int main(int argc, char *argv[])
{

if ( SDL_Init(SDL_INIT_AUDIO|SDL_INIT_VIDEO) < 0 )
{
printf("Unable to init SDL: %s\n", SDL_GetError());
exit(1);
}
atexit(SDL_Quit);

screen=SDL_SetVideoMode(640,480,32,SDL_HWSURFACE|SDL_DOUBLEBUF);
if ( screen == NULL )
{
printf("Unable to set 640x480 video: %s\n", SDL_GetError());
exit(1);
}
int done=0;

while(done == 0)
{
SDL_Event event;

while ( SDL_PollEvent(&event) )
{
if ( event.type == SDL_QUIT ) { done = 1; }

if ( event.type == SDL_KEYDOWN )
{
if ( event.key.keysym.sym == SDLK_ESCAPE ) { done = 1; }
}
}

DrawScene(screen);
}

return 0;
}

void Slock(SDL_Surface *screen)
{
if ( SDL_MUSTLOCK(screen) )
{
if ( SDL_LockSurface(screen) < 0 )
{
return;
}
}
}

void Sulock(SDL_Surface *screen)
{
if ( SDL_MUSTLOCK(screen) )
{
SDL_UnlockSurface(screen);
}
}

void DrawPixel(SDL_Surface *screen, int x, int y,
Uint8 R, Uint8 G, Uint8 B)
{
Uint32 color = SDL_MapRGB(screen->format, R, G, B);
switch (screen->format->BytesPerPixel)
{
case 1: // Assuming 8-bpp
{
Uint8 *bufp;
bufp = (Uint8 *)screen->pixels + y*screen->pitch + x;
*bufp = color;
}
break;
case 2: // Probably 15-bpp or 16-bpp
{
Uint16 *bufp;
bufp = (Uint16 *)screen->pixels + y*screen->pitch/2 + x;
*bufp = color;
}
break;
case 3: // Slow 24-bpp mode, usually not used
{
Uint8 *bufp;
bufp = (Uint8 *)screen->pixels + y*screen->pitch + x * 3;
if(SDL_BYTEORDER == SDL_LIL_ENDIAN)
{
bufp[0] = color;
bufp[1] = color >> 8;
bufp[2] = color >> 16;
} else {
bufp[2] = color;
bufp[1] = color >> 8;
bufp[0] = color >> 16;
}
}
break;
case 4: // Probably 32-bpp
{
Uint32 *bufp;
bufp = (Uint32 *)screen->pixels + y*screen->pitch/4 + x;
*bufp = color;
}
break;
}
}



- Drew Benton

Share this post


Link to post
Share on other sites
rai_chu    128
thank you very much for your answer and efforts "Drew Benton", I would like to added that while waiting for reply, I found the solution to the question myself, and would like to share with you guys who might curious. :)

void update() // cMouse::update()
{
SDL_GetRelativeMouseState(&dX,&dY);

if (dX < 0)
{ x = ((x+dX) < 0) ? 0 : x+dX;}
else if (dX > 0)
{ x = ((x+dX) > WINDOW_WIDTH-1) ? WINDOW_WIDTH-1 : x+dX; }

if (dY < 0)
{ y = ((y+dY) < 0) ? 0 : y+dY; }
else if (dY > 0)
{ y = ((y+dY) > WINDOW_HEIGHT-1) ? WINDOW_HEIGHT-1 : y+dY; }

if ((x == 0) || (x == WINDOW_WIDTH-1) || (y == 0) || (y == WINDOW_HEIGHT-1))
{ SDL_WM_GrabInput(SDL_GRAB_OFF); setVisible(false); }
else
{ SDL_WM_GrabInput(SDL_GRAB_ON); setVisible(true); }

}

this code emulate behavior exactly as I wanted!, so the problem solved, :)

Share this post


Link to post
Share on other sites
rai_chu    128
heh :),

it's a kind of trick I recognized after reading this,

"If the cursor is hidden (SDL_ShowCursor(0)) and the input is grabbed (SDL_WM_GrabInput(SDL_GRAB_ON)), then the mouse will give relative motion events even when the cursor reaches the edge of the screen. This is currently only implemented on Windows and Linux/Unix-alikes." from http://www.libsdl.org/cgi/docwiki.cgi/SDL_5fMouseMotionEvent

so basically what it does is, first grab the input so that even if player move cursor out of window, it still in window knocking to the edge (aka. perform similar to full screen app or exclusive mode), once the edge is detected, just simply hide them at the same time "release" the grabInput. When player move mouse within window area again, show the mouse & reGrabInput.

Hope this could be helpful explaination.

Share this post


Link to post
Share on other sites
rai_chu    128
well, it seem like the grabing input methods still does not perform exactly as system cursor/mouse.

When there is another app window on top of sdl window, there are two behaviors I found incorrect,

a. when navigate mouse from sdl window into another window zone the mouse isn't come on top of another window right away, it only appear after leaving sdl window

b. if anothor window is totally inside sdl window (ie. open window calculator and drag it on top of sdl window) after that navigate mouse back and forth, it seem to me that the sdl app does not get any mouse move message, as when cursor move inside sdl window it go to calculator app and when move out of calculator window, the cursor just move out of sdl window.

I would be glad if anyone could come up with the ways to emulate exactly as system mouse behavior by using sdl for custom-made cursor image. thanks

Share this post


Link to post
Share on other sites
rai_chu    128
wow! finally, I found it!, nice, clean and easy :)

if(SDL_GetAppState()&SDL_APPMOUSEFOCUS)
{ pMouse->setVisible(true); }
else
{ pMouse->setVisible(false); }

hope this is useful,

PS. I was thinking while in search for the way to overcome this problem, that the answer to this question should be obvious, and it should also be asked many times before, how come I cann't find it?

Does it matter leaving mouse drawn in sdl window, when user already focus something else? or that usually sdl app are made in fullscreen mode?.. heh.. blah blah blah..

Share this post


Link to post
Share on other sites
Rhaal    754
Quote:
Original post by Drew_Benton
Very intresting! I will have to take a look at that later. I guess I was wrong about it not being able to be done by itself with SDL [embarrass]. Good luck with your program!

- Drew

Well, if it's any condolence, your answer was very l33t.

Share this post


Link to post
Share on other sites
Drew_Benton    1861
[lol] Thanks. [smile] My main gripe with SDL is the fact that it lacks the window features that it *should* have. I mean they have on there audio, timers, threads, heck they even have CD-ROM support. Yet they do not have any simple functions to set and get the window position...very unfortuante. If you guys are intrested in setting the window position, I just use something along the same lines as my first post - get the hwnd, then use the move window function of the Win32 API.

- Drew

Share this post


Link to post
Share on other sites
Drew_Benton    1861
Quote:
Original post by rai_chu
just a quick qestion, is SDL still portable (ie. port to Mac), if we include "window.h"?


Nope [smile] You will have to use another OS header file for a specific functionality. You can add in like:


#ifdef _WIN32
#include <windows.h>
...
HWND hwnd;
...
#endif

#ifdef _MACDEFINE
#include <mac.h>
...
MacHWND hwnd;
...
#endif
etc...


Those are not the real defines though, you will have to look them up.

- Drew

[Edited by - Drew_Benton on February 17, 2005 8:32:32 PM]

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this