Mercurial > sdl-ios-xcode
diff src/events/SDL_mouse.c @ 1895:c121d94672cb
SDL 1.2 is moving to a branch, and SDL 1.3 is becoming the head.
author | Sam Lantinga <slouken@libsdl.org> |
---|---|
date | Mon, 10 Jul 2006 21:04:37 +0000 |
parents | 23a347cfbed8 |
children | 5f6550e5184f |
line wrap: on
line diff
--- a/src/events/SDL_mouse.c Thu Jul 06 18:01:37 2006 +0000 +++ b/src/events/SDL_mouse.c Mon Jul 10 21:04:37 2006 +0000 @@ -25,239 +25,627 @@ #include "SDL_events.h" #include "SDL_events_c.h" -#include "../video/SDL_cursor_c.h" -#include "../video/SDL_sysvideo.h" +#include "default_cursor.h" -/* These are static for our mouse handling code */ -static Sint16 SDL_MouseX = 0; -static Sint16 SDL_MouseY = 0; -static Sint16 SDL_DeltaX = 0; -static Sint16 SDL_DeltaY = 0; -static Uint8 SDL_ButtonState = 0; +static int SDL_num_mice; +static int SDL_current_mouse; +static SDL_Mouse **SDL_mice; /* Public functions */ -int SDL_MouseInit(void) +int +SDL_MouseInit(void) +{ + return (0); +} + +SDL_Mouse * +SDL_GetMouse(int index) +{ + if (index < 0 || index >= SDL_num_mice) { + return NULL; + } + return SDL_mice[index]; +} + +int +SDL_AddMouse(const SDL_Mouse * mouse, int index) { - /* The mouse is at (0,0) */ - SDL_MouseX = 0; - SDL_MouseY = 0; - SDL_DeltaX = 0; - SDL_DeltaY = 0; - SDL_ButtonState = 0; + SDL_Mouse **mice; + int selected_mouse; + + /* Add the mouse to the list of mice */ + if (index < 0 || index >= SDL_num_mice || SDL_mice[index]) { + mice = + (SDL_Mouse **) SDL_realloc(SDL_mice, + (SDL_num_mice + 1) * sizeof(*mice)); + if (!mice) { + SDL_OutOfMemory(); + return -1; + } - /* That's it! */ - return(0); -} -void SDL_MouseQuit(void) -{ + SDL_mice = mice; + index = SDL_num_mice++; + } + SDL_mice[index] = (SDL_Mouse *) SDL_malloc(sizeof(*SDL_mice[index])); + if (!SDL_mice[index]) { + SDL_OutOfMemory(); + return -1; + } + *SDL_mice[index] = *mouse; + + /* Create the default cursor for the mouse */ + SDL_mice[index]->cursor_shown = SDL_TRUE; + selected_mouse = SDL_SelectMouse(index); + SDL_mice[index]->cur_cursor = NULL; + SDL_mice[index]->def_cursor = + SDL_CreateCursor(default_cdata, default_cmask, DEFAULT_CWIDTH, + DEFAULT_CHEIGHT, DEFAULT_CHOTX, DEFAULT_CHOTY); + SDL_SetCursor(SDL_mice[index]->def_cursor); + SDL_SelectMouse(selected_mouse); + + return index; } -/* We lost the mouse, so post button up messages for all pressed buttons */ -void SDL_ResetMouse(void) +void +SDL_DelMouse(int index) +{ + SDL_Mouse *mouse = SDL_GetMouse(index); + + if (!mouse) { + return; + } + + mouse->def_cursor = NULL; + while (mouse->cursors) { + SDL_FreeCursor(mouse->cursors); + } + + if (mouse->FreeMouse) { + mouse->FreeMouse(mouse); + } + SDL_free(mouse); + + SDL_mice[index] = NULL; +} + +void +SDL_ResetMouse(int index) +{ + SDL_Mouse *mouse = SDL_GetMouse(index); + + if (!mouse) { + return; + } + + /* FIXME */ +} + +void +SDL_MouseQuit(void) { - Uint8 i; - for ( i = 0; i < sizeof(SDL_ButtonState)*8; ++i ) { - if ( SDL_ButtonState & SDL_BUTTON(i) ) { - SDL_PrivateMouseButton(SDL_RELEASED, i, 0, 0); - } - } + int i; + + for (i = 0; i < SDL_num_mice; ++i) { + SDL_DelMouse(i); + } + SDL_num_mice = 0; + SDL_current_mouse = 0; + + if (SDL_mice) { + SDL_free(SDL_mice); + SDL_mice = NULL; + } +} + +int +SDL_GetNumMice(void) +{ + return SDL_num_mice; +} + +int +SDL_SelectMouse(int index) +{ + if (index >= 0 && index < SDL_num_mice) { + SDL_current_mouse = index; + } + return SDL_current_mouse; +} + +SDL_WindowID +SDL_GetMouseFocusWindow() +{ + SDL_Mouse *mouse = SDL_GetMouse(SDL_current_mouse); + + if (!mouse) { + return 0; + } + return mouse->focus; } -Uint8 SDL_GetMouseState (int *x, int *y) +static int +FlushMouseMotion(void *param, SDL_Event * event) +{ + if (event->type == SDL_MOUSEMOTION + && event->motion.which == (Uint8) SDL_current_mouse) { + return 0; + } else { + return 1; + } +} + +int +SDL_SetRelativeMouseMode(SDL_bool enabled) { - if ( x ) { - *x = SDL_MouseX; - } - if ( y ) { - *y = SDL_MouseY; - } - return(SDL_ButtonState); + SDL_Mouse *mouse = SDL_GetMouse(SDL_current_mouse); + + if (!mouse) { + return -1; + } + + /* Flush pending mouse motion */ + mouse->flush_motion = SDL_TRUE; + SDL_PumpEvents(); + mouse->flush_motion = SDL_FALSE; + SDL_FilterEvents(FlushMouseMotion, mouse); + + /* Set the relative mode */ + mouse->relative_mode = enabled; + + /* Update cursor visibility */ + SDL_SetCursor(NULL); + + if (!enabled) { + /* Restore the expected mouse position */ + SDL_WarpMouseInWindow(mouse->focus, mouse->x, mouse->y); + } + return 0; +} + +SDL_bool +SDL_GetRelativeMouseMode() +{ + SDL_Mouse *mouse = SDL_GetMouse(SDL_current_mouse); + + if (!mouse) { + return SDL_FALSE; + } + return mouse->relative_mode; +} + +Uint8 +SDL_GetMouseState(int *x, int *y) +{ + SDL_Mouse *mouse = SDL_GetMouse(SDL_current_mouse); + + if (!mouse) { + if (x) { + *x = 0; + } + if (y) { + *y = 0; + } + return 0; + } + + if (x) { + *x = mouse->x; + } + if (y) { + *y = mouse->y; + } + return mouse->buttonstate; } -Uint8 SDL_GetRelativeMouseState (int *x, int *y) +Uint8 +SDL_GetRelativeMouseState(int *x, int *y) { - if ( x ) - *x = SDL_DeltaX; - if ( y ) - *y = SDL_DeltaY; - SDL_DeltaX = 0; - SDL_DeltaY = 0; - return(SDL_ButtonState); + SDL_Mouse *mouse = SDL_GetMouse(SDL_current_mouse); + + if (!mouse) { + if (x) { + *x = 0; + } + if (y) { + *y = 0; + } + return 0; + } + + if (x) { + *x = mouse->xdelta; + } + if (y) { + *y = mouse->ydelta; + } + mouse->xdelta = 0; + mouse->ydelta = 0; + return mouse->buttonstate; } -static void ClipOffset(Sint16 *x, Sint16 *y) +void +SDL_SetMouseFocus(int index, SDL_WindowID windowID) { - /* This clips absolute mouse coordinates when the apparent - display surface is smaller than the real display surface. - */ - if ( SDL_VideoSurface->offset ) { - *y -= SDL_VideoSurface->offset/SDL_VideoSurface->pitch; - *x -= (SDL_VideoSurface->offset%SDL_VideoSurface->pitch)/ - SDL_VideoSurface->format->BytesPerPixel; - } + SDL_Mouse *mouse = SDL_GetMouse(index); + int i; + SDL_bool focus; + + if (!mouse || (mouse->focus == windowID)) { + return; + } + + /* See if the current window has lost focus */ + if (mouse->focus) { + focus = SDL_FALSE; + for (i = 0; i < SDL_num_mice; ++i) { + SDL_Mouse *check; + if (i != index) { + check = SDL_GetMouse(i); + if (check && check->focus == mouse->focus) { + focus = SDL_TRUE; + break; + } + } + } + if (!focus) { + SDL_SendWindowEvent(mouse->focus, SDL_WINDOWEVENT_LEAVE, 0, 0); + } + } + + mouse->focus = windowID; + + if (mouse->focus) { + focus = SDL_FALSE; + for (i = 0; i < SDL_num_mice; ++i) { + SDL_Mouse *check; + if (i != index) { + check = SDL_GetMouse(i); + if (check && check->focus == mouse->focus) { + focus = SDL_TRUE; + break; + } + } + } + if (!focus) { + SDL_SendWindowEvent(mouse->focus, SDL_WINDOWEVENT_ENTER, 0, 0); + } + } } -/* These are global for SDL_eventloop.c */ -int SDL_PrivateMouseMotion(Uint8 buttonstate, int relative, Sint16 x, Sint16 y) +int +SDL_SendMouseMotion(int index, int relative, int x, int y) { - int posted; - Uint16 X, Y; - Sint16 Xrel; - Sint16 Yrel; + SDL_Mouse *mouse = SDL_GetMouse(index); + int posted; + int xrel; + int yrel; + + if (!mouse || mouse->flush_motion) { + return 0; + } - /* Don't handle mouse motion if there's no cursor surface */ - if ( SDL_VideoSurface == NULL ) { - return(0); - } + if (relative) { + /* Push the cursor around */ + xrel = x; + yrel = y; + x = (mouse->x + xrel); + y = (mouse->y + yrel); + } else { + xrel = x - mouse->x; + yrel = y - mouse->y; + } - /* Default buttonstate is the current one */ - if ( ! buttonstate ) { - buttonstate = SDL_ButtonState; - } + /* Drop events that don't change state */ + if (!xrel && !yrel) { +#if 0 + printf("Mouse event didn't change state - dropped!\n"); +#endif + return 0; + } - Xrel = x; - Yrel = y; - if ( relative ) { - /* Push the cursor around */ - x = (SDL_MouseX+x); - y = (SDL_MouseY+y); - } else { - /* Do we need to clip {x,y} ? */ - ClipOffset(&x, &y); - } + /* Update internal mouse state */ + if (!mouse->relative_mode) { + mouse->x = x; + mouse->y = y; + } + mouse->xdelta += xrel; + mouse->ydelta += yrel; + + /* Move the mouse cursor, if needed */ + if (mouse->cursor_shown && !mouse->relative_mode && + mouse->MoveCursor && mouse->cur_cursor) { + mouse->MoveCursor(mouse->cur_cursor); + } - /* Mouse coordinates range from 0 - width-1 and 0 - height-1 */ - if ( x < 0 ) - X = 0; - else - if ( x >= SDL_VideoSurface->w ) - X = SDL_VideoSurface->w-1; - else - X = (Uint16)x; + /* Post the event, if desired */ + posted = 0; + if (SDL_ProcessEvents[SDL_MOUSEMOTION] == SDL_ENABLE) { + SDL_Event event; + event.motion.type = SDL_MOUSEMOTION; + event.motion.which = (Uint8) index; + event.motion.state = mouse->buttonstate; + event.motion.x = mouse->x; + event.motion.y = mouse->y; + event.motion.xrel = xrel; + event.motion.yrel = yrel; + event.motion.windowID = mouse->focus; + posted = (SDL_PushEvent(&event) > 0); + } + return posted; +} + +int +SDL_SendMouseButton(int index, Uint8 state, Uint8 button) +{ + SDL_Mouse *mouse = SDL_GetMouse(index); + int posted; + Uint8 type; + + if (!mouse) { + return 0; + } - if ( y < 0 ) - Y = 0; - else - if ( y >= SDL_VideoSurface->h ) - Y = SDL_VideoSurface->h-1; - else - Y = (Uint16)y; + /* Figure out which event to perform */ + switch (state) { + case SDL_PRESSED: + if (mouse->buttonstate & SDL_BUTTON(button)) { + /* Ignore this event, no state change */ + return 0; + } + type = SDL_MOUSEBUTTONDOWN; + mouse->buttonstate |= SDL_BUTTON(button); + break; + case SDL_RELEASED: + if (!(mouse->buttonstate & SDL_BUTTON(button))) { + /* Ignore this event, no state change */ + return 0; + } + type = SDL_MOUSEBUTTONUP; + mouse->buttonstate &= ~SDL_BUTTON(button); + break; + default: + /* Invalid state -- bail */ + return 0; + } - /* If not relative mode, generate relative motion from clamped X/Y. - This prevents lots of extraneous large delta relative motion when - the screen is windowed mode and the mouse is outside the window. - */ - if ( ! relative ) { - Xrel = X-SDL_MouseX; - Yrel = Y-SDL_MouseY; - } - - /* Drop events that don't change state */ - if ( ! Xrel && ! Yrel ) { -#if 0 -printf("Mouse event didn't change state - dropped!\n"); -#endif - return(0); - } + /* Post the event, if desired */ + posted = 0; + if (SDL_ProcessEvents[type] == SDL_ENABLE) { + SDL_Event event; + event.type = type; + event.button.which = (Uint8) index; + event.button.state = state; + event.button.button = button; + event.button.x = mouse->x; + event.button.y = mouse->y; + event.button.windowID = mouse->focus; + posted = (SDL_PushEvent(&event) > 0); + } + return posted; +} - /* Update internal mouse state */ - SDL_ButtonState = buttonstate; - SDL_MouseX = X; - SDL_MouseY = Y; - SDL_DeltaX += Xrel; - SDL_DeltaY += Yrel; - SDL_MoveCursor(SDL_MouseX, SDL_MouseY); +int +SDL_SendMouseWheel(int index, int motion) +{ + SDL_Mouse *mouse = SDL_GetMouse(index); + int posted; + + if (!mouse || !motion) { + return 0; + } - /* Post the event, if desired */ - posted = 0; - if ( SDL_ProcessEvents[SDL_MOUSEMOTION] == SDL_ENABLE ) { - SDL_Event event; - SDL_memset(&event, 0, sizeof(event)); - event.type = SDL_MOUSEMOTION; - event.motion.state = buttonstate; - event.motion.x = X; - event.motion.y = Y; - event.motion.xrel = Xrel; - event.motion.yrel = Yrel; - if ( (SDL_EventOK == NULL) || (*SDL_EventOK)(&event) ) { - posted = 1; - SDL_PushEvent(&event); - } - } - return(posted); + /* Post the event, if desired */ + posted = 0; + if (SDL_ProcessEvents[SDL_MOUSEWHEEL] == SDL_ENABLE) { + SDL_Event event; + event.type = SDL_MOUSEWHEEL; + event.wheel.which = (Uint8) index; + event.wheel.motion = motion; + event.wheel.windowID = mouse->focus; + posted = (SDL_PushEvent(&event) > 0); + } + return posted; +} + +void +SDL_WarpMouseInWindow(SDL_WindowID windowID, int x, int y) +{ + SDL_Mouse *mouse = SDL_GetMouse(SDL_current_mouse); + + if (!mouse) { + return; + } + + if (mouse->WarpMouse) { + mouse->WarpMouse(mouse, windowID, x, y); + } else { + SDL_SetMouseFocus(SDL_current_mouse, windowID); + SDL_SendMouseMotion(SDL_current_mouse, 0, x, y); + } } -int SDL_PrivateMouseButton(Uint8 state, Uint8 button, Sint16 x, Sint16 y) +SDL_Cursor * +SDL_CreateCursor(const Uint8 * data, const Uint8 * mask, + int w, int h, int hot_x, int hot_y) { - SDL_Event event; - int posted; - int move_mouse; - Uint8 buttonstate; - - SDL_memset(&event, 0, sizeof(event)); + SDL_Mouse *mouse = SDL_GetMouse(SDL_current_mouse); + SDL_Surface *surface; + SDL_Cursor *cursor; + int x, y; + Uint32 *pixel; + Uint8 datab, maskb; + const Uint32 black = 0xFF000000; + const Uint32 white = 0xFFFFFFFF; + const Uint32 transparent = 0x00000000; - /* Check parameters */ - if ( x || y ) { - ClipOffset(&x, &y); - move_mouse = 1; - /* Mouse coordinates range from 0 - width-1 and 0 - height-1 */ - if ( x < 0 ) - x = 0; - else - if ( x >= SDL_VideoSurface->w ) - x = SDL_VideoSurface->w-1; + if (!mouse) { + SDL_SetError("No mice are initialized"); + return NULL; + } - if ( y < 0 ) - y = 0; - else - if ( y >= SDL_VideoSurface->h ) - y = SDL_VideoSurface->h-1; - } else { - move_mouse = 0; - } - if ( ! x ) - x = SDL_MouseX; - if ( ! y ) - y = SDL_MouseY; + if (!mouse->CreateCursor) { + SDL_SetError("Current mouse doesn't have cursor support"); + return NULL; + } + + /* Sanity check the hot spot */ + if ((hot_x < 0) || (hot_y < 0) || (hot_x >= w) || (hot_y >= h)) { + SDL_SetError("Cursor hot spot doesn't lie within cursor"); + return NULL; + } + + /* Make sure the width is a multiple of 8 */ + w = ((w + 7) & ~7); - /* Figure out which event to perform */ - buttonstate = SDL_ButtonState; - switch ( state ) { - case SDL_PRESSED: - event.type = SDL_MOUSEBUTTONDOWN; - buttonstate |= SDL_BUTTON(button); - break; - case SDL_RELEASED: - event.type = SDL_MOUSEBUTTONUP; - buttonstate &= ~SDL_BUTTON(button); - break; - default: - /* Invalid state -- bail */ - return(0); - } + /* Create the surface from a bitmap */ + surface = + SDL_CreateRGBSurface(0, w, h, 32, 0x00FF0000, 0x0000FF00, 0x000000FF, + 0xFF000000); + if (!surface) { + return NULL; + } + for (y = 0; y < h; ++y) { + pixel = (Uint32 *) ((Uint8 *) surface->pixels + y * surface->pitch); + for (x = 0; x < w; ++x) { + if ((x % 8) == 0) { + datab = *data++; + maskb = *mask++; + } + if (maskb & 0x80) { + *pixel++ = (datab & 0x80) ? black : white; + } else { + *pixel++ = (datab & 0x80) ? black : transparent; + } + datab <<= 1; + maskb <<= 1; + } + } - /* Update internal mouse state */ - SDL_ButtonState = buttonstate; - if ( move_mouse ) { - SDL_MouseX = x; - SDL_MouseY = y; - SDL_MoveCursor(SDL_MouseX, SDL_MouseY); - } + cursor = mouse->CreateCursor(surface, hot_x, hot_y); + if (cursor) { + cursor->mouse = mouse; + cursor->next = mouse->cursors; + mouse->cursors = cursor; + } - /* Post the event, if desired */ - posted = 0; - if ( SDL_ProcessEvents[event.type] == SDL_ENABLE ) { - event.button.state = state; - event.button.button = button; - event.button.x = x; - event.button.y = y; - if ( (SDL_EventOK == NULL) || (*SDL_EventOK)(&event) ) { - posted = 1; - SDL_PushEvent(&event); - } - } - return(posted); + SDL_FreeSurface(surface); + + return cursor; } +/* SDL_SetCursor(NULL) can be used to force the cursor redraw, + if this is desired for any reason. This is used when setting + the video mode and when the SDL window gains the mouse focus. + */ +void +SDL_SetCursor(SDL_Cursor * cursor) +{ + SDL_Mouse *mouse = SDL_GetMouse(SDL_current_mouse); + + if (!mouse) { + SDL_SetError("No mice are initialized"); + return; + } + + /* Set the new cursor */ + if (cursor) { + /* Make sure the cursor is still valid for this mouse */ + SDL_Cursor *found; + for (found = mouse->cursors; found; found = found->next) { + if (found == cursor) { + break; + } + } + if (!found) { + SDL_SetError("Cursor not associated with the current mouse"); + return; + } + mouse->cur_cursor = cursor; + } else { + cursor = mouse->cur_cursor; + } + + if (cursor && mouse->cursor_shown && !mouse->relative_mode) { + if (mouse->ShowCursor) { + mouse->ShowCursor(cursor); + } + } else { + if (mouse->ShowCursor) { + mouse->ShowCursor(NULL); + } + } +} + +SDL_Cursor * +SDL_GetCursor(void) +{ + SDL_Mouse *mouse = SDL_GetMouse(SDL_current_mouse); + + if (!mouse) { + return NULL; + } + return mouse->cur_cursor; +} + +void +SDL_FreeCursor(SDL_Cursor * cursor) +{ + SDL_Mouse *mouse; + SDL_Cursor *curr, *prev; + + if (!cursor) { + return; + } + mouse = cursor->mouse; + + if (cursor == mouse->def_cursor) { + return; + } + if (cursor == mouse->cur_cursor) { + SDL_SetCursor(mouse->def_cursor); + } + + for (prev = NULL, curr = mouse->cursors; curr; + prev = curr, curr = curr->next) { + if (curr == cursor) { + if (prev) { + prev->next = curr->next; + } else { + mouse->cursors = curr->next; + } + + if (mouse->FreeCursor) { + mouse->FreeCursor(curr); + } + return; + } + } +} + +int +SDL_ShowCursor(int toggle) +{ + SDL_Mouse *mouse = SDL_GetMouse(SDL_current_mouse); + SDL_bool shown; + + if (!mouse) { + return 0; + } + + shown = mouse->cursor_shown; + if (toggle >= 0) { + if (toggle) { + mouse->cursor_shown = SDL_TRUE; + } else { + mouse->cursor_shown = SDL_FALSE; + } + if (mouse->cursor_shown != shown) { + SDL_SetCursor(NULL); + } + } + return shown; +} + +/* vi: set ts=4 sw=4 expandtab: */