src/events/SDL_mouse.c
author Sam Lantinga
Mon, 21 Feb 2011 17:15:50 -0800
changeset 5376 183ec2d4485c
parent 5371 fc3d3d580777
child 5405 64fa8526e1ce
permissions -rw-r--r--
Implemented cursor support and SDL_WarpMouseInWindow() on Mac OS X
     1 /*
     2     SDL - Simple DirectMedia Layer
     3     Copyright (C) 1997-2011 Sam Lantinga
     4 
     5     This library is free software; you can redistribute it and/or
     6     modify it under the terms of the GNU Lesser General Public
     7     License as published by the Free Software Foundation; either
     8     version 2.1 of the License, or (at your option) any later version.
     9 
    10     This library is distributed in the hope that it will be useful,
    11     but WITHOUT ANY WARRANTY; without even the implied warranty of
    12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    13     Lesser General Public License for more details.
    14 
    15     You should have received a copy of the GNU Lesser General Public
    16     License along with this library; if not, write to the Free Software
    17     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
    18 
    19     Sam Lantinga
    20     slouken@libsdl.org
    21 */
    22 #include "SDL_config.h"
    23 
    24 /* General mouse handling code for SDL */
    25 
    26 #include "SDL_events.h"
    27 #include "SDL_events_c.h"
    28 #include "default_cursor.h"
    29 #include "../video/SDL_sysvideo.h"
    30 
    31 
    32 /* The mouse state */
    33 static SDL_Mouse SDL_mouse;
    34 
    35 
    36 /* Public functions */
    37 int
    38 SDL_MouseInit(void)
    39 {
    40     SDL_Mouse *mouse = SDL_GetMouse();
    41 
    42     mouse->cursor_shown = SDL_TRUE;
    43 
    44     return (0);
    45 }
    46 
    47 SDL_Mouse *
    48 SDL_GetMouse(void)
    49 {
    50     return &SDL_mouse;
    51 }
    52 
    53 SDL_Window *
    54 SDL_GetMouseFocus(void)
    55 {
    56     SDL_Mouse *mouse = SDL_GetMouse();
    57 
    58     return mouse->focus;
    59 }
    60 
    61 void
    62 SDL_SetMouseFocus(SDL_Window * window)
    63 {
    64     SDL_Mouse *mouse = SDL_GetMouse();
    65 
    66     if (mouse->focus == window) {
    67         return;
    68     }
    69 
    70     /* See if the current window has lost focus */
    71     if (mouse->focus) {
    72         SDL_SendWindowEvent(mouse->focus, SDL_WINDOWEVENT_LEAVE, 0, 0);
    73     }
    74 
    75     mouse->focus = window;
    76 
    77     if (mouse->focus) {
    78         SDL_SendWindowEvent(mouse->focus, SDL_WINDOWEVENT_ENTER, 0, 0);
    79     }
    80 }
    81 
    82 int
    83 SDL_SendMouseMotion(SDL_Window * window, int relative, int x, int y)
    84 {
    85     SDL_Mouse *mouse = SDL_GetMouse();
    86     int posted;
    87     int xrel;
    88     int yrel;
    89     int x_max = 0, y_max = 0;
    90 
    91     if (window) {
    92         SDL_SetMouseFocus(window);
    93     }
    94 
    95     /* the relative motion is calculated regarding the system cursor last position */
    96     if (relative) {
    97         xrel = x;
    98         yrel = y;
    99         x = (mouse->last_x + x);
   100         y = (mouse->last_y + y);
   101     } else {
   102         xrel = x - mouse->last_x;
   103         yrel = y - mouse->last_y;
   104     }
   105 
   106     /* Drop events that don't change state */
   107     if (!xrel && !yrel) {
   108 #if 0
   109         printf("Mouse event didn't change state - dropped!\n");
   110 #endif
   111         return 0;
   112     }
   113 
   114     /* Update internal mouse coordinates */
   115     if (mouse->relative_mode == SDL_FALSE) {
   116         mouse->x = x;
   117         mouse->y = y;
   118     } else {
   119         mouse->x += xrel;
   120         mouse->y += yrel;
   121     }
   122 
   123     SDL_GetWindowSize(mouse->focus, &x_max, &y_max);
   124     --x_max;
   125     --y_max;
   126 
   127     /* make sure that the pointers find themselves inside the windows */
   128     /* only check if mouse->xmax is set ! */
   129     if (mouse->x > x_max) {
   130         mouse->x = x_max;
   131     }
   132     if (mouse->x < 0) {
   133         mouse->x = 0;
   134     }
   135 
   136     if (mouse->y > y_max) {
   137         mouse->y = y_max;
   138     }
   139     if (mouse->y < 0) {
   140         mouse->y = 0;
   141     }
   142 
   143     mouse->xdelta += xrel;
   144     mouse->ydelta += yrel;
   145 
   146 #if 0 /* FIXME */
   147     /* Move the mouse cursor, if needed */
   148     if (mouse->cursor_shown && !mouse->relative_mode &&
   149         mouse->MoveCursor && mouse->cur_cursor) {
   150         mouse->MoveCursor(mouse->cur_cursor);
   151     }
   152 #endif
   153 
   154     /* Post the event, if desired */
   155     posted = 0;
   156     if (SDL_GetEventState(SDL_MOUSEMOTION) == SDL_ENABLE) {
   157         SDL_Event event;
   158         event.motion.type = SDL_MOUSEMOTION;
   159         event.motion.windowID = mouse->focus ? mouse->focus->id : 0;
   160         event.motion.state = mouse->buttonstate;
   161         event.motion.x = mouse->x;
   162         event.motion.y = mouse->y;
   163         event.motion.xrel = xrel;
   164         event.motion.yrel = yrel;
   165         posted = (SDL_PushEvent(&event) > 0);
   166     }
   167     mouse->last_x = mouse->x;
   168     mouse->last_y = mouse->y;
   169     return posted;
   170 }
   171 
   172 int
   173 SDL_SendMouseButton(SDL_Window * window, Uint8 state, Uint8 button)
   174 {
   175     SDL_Mouse *mouse = SDL_GetMouse();
   176     int posted;
   177     Uint32 type;
   178 
   179     if (window) {
   180         SDL_SetMouseFocus(window);
   181     }
   182 
   183     /* Figure out which event to perform */
   184     switch (state) {
   185     case SDL_PRESSED:
   186         if (mouse->buttonstate & SDL_BUTTON(button)) {
   187             /* Ignore this event, no state change */
   188             return 0;
   189         }
   190         type = SDL_MOUSEBUTTONDOWN;
   191         mouse->buttonstate |= SDL_BUTTON(button);
   192         break;
   193     case SDL_RELEASED:
   194         if (!(mouse->buttonstate & SDL_BUTTON(button))) {
   195             /* Ignore this event, no state change */
   196             return 0;
   197         }
   198         type = SDL_MOUSEBUTTONUP;
   199         mouse->buttonstate &= ~SDL_BUTTON(button);
   200         break;
   201     default:
   202         /* Invalid state -- bail */
   203         return 0;
   204     }
   205 
   206     /* Post the event, if desired */
   207     posted = 0;
   208     if (SDL_GetEventState(type) == SDL_ENABLE) {
   209         SDL_Event event;
   210         event.type = type;
   211         event.button.state = state;
   212         event.button.button = button;
   213         event.button.x = mouse->x;
   214         event.button.y = mouse->y;
   215         event.button.windowID = mouse->focus ? mouse->focus->id : 0;
   216         posted = (SDL_PushEvent(&event) > 0);
   217     }
   218     return posted;
   219 }
   220 
   221 int
   222 SDL_SendMouseWheel(SDL_Window * window, int x, int y)
   223 {
   224     SDL_Mouse *mouse = SDL_GetMouse();
   225     int posted;
   226 
   227     if (window) {
   228         SDL_SetMouseFocus(window);
   229     }
   230 
   231     if (!x && !y) {
   232         return 0;
   233     }
   234 
   235     /* Post the event, if desired */
   236     posted = 0;
   237     if (SDL_GetEventState(SDL_MOUSEWHEEL) == SDL_ENABLE) {
   238         SDL_Event event;
   239         event.type = SDL_MOUSEWHEEL;
   240         event.wheel.windowID = mouse->focus ? mouse->focus->id : 0;
   241         event.wheel.x = x;
   242         event.wheel.y = y;
   243         posted = (SDL_PushEvent(&event) > 0);
   244     }
   245     return posted;
   246 }
   247 
   248 void
   249 SDL_MouseQuit(void)
   250 {
   251 }
   252 
   253 Uint8
   254 SDL_GetMouseState(int *x, int *y)
   255 {
   256     SDL_Mouse *mouse = SDL_GetMouse();
   257 
   258     if (x) {
   259         *x = mouse->x;
   260     }
   261     if (y) {
   262         *y = mouse->y;
   263     }
   264     return mouse->buttonstate;
   265 }
   266 
   267 Uint8
   268 SDL_GetRelativeMouseState(int *x, int *y)
   269 {
   270     SDL_Mouse *mouse = SDL_GetMouse();
   271 
   272     if (x) {
   273         *x = mouse->xdelta;
   274     }
   275     if (y) {
   276         *y = mouse->ydelta;
   277     }
   278     mouse->xdelta = 0;
   279     mouse->ydelta = 0;
   280     return mouse->buttonstate;
   281 }
   282 
   283 void
   284 SDL_WarpMouseInWindow(SDL_Window * window, int x, int y)
   285 {
   286     SDL_Mouse *mouse = SDL_GetMouse();
   287 
   288     if (mouse->WarpMouse) {
   289         mouse->WarpMouse(window, x, y);
   290     } else {
   291         SDL_SendMouseMotion(window, 0, x, y);
   292     }
   293 }
   294 
   295 int
   296 SDL_SetRelativeMouseMode(SDL_bool enabled)
   297 {
   298     SDL_Mouse *mouse = SDL_GetMouse();
   299 
   300     /* Flush pending mouse motion */
   301     SDL_FlushEvent(SDL_MOUSEMOTION);
   302 
   303     /* Set the relative mode */
   304     mouse->relative_mode = enabled;
   305 
   306     if (!enabled) {
   307         /* Restore the expected mouse position */
   308         SDL_WarpMouseInWindow(mouse->focus, mouse->x, mouse->y);
   309     }
   310 
   311     /* Update cursor visibility */
   312     SDL_SetCursor(NULL);
   313 
   314     return 0;
   315 }
   316 
   317 SDL_bool
   318 SDL_GetRelativeMouseMode()
   319 {
   320     SDL_Mouse *mouse = SDL_GetMouse();
   321 
   322     return mouse->relative_mode;
   323 }
   324 
   325 SDL_Cursor *
   326 SDL_CreateCursor(const Uint8 * data, const Uint8 * mask,
   327                  int w, int h, int hot_x, int hot_y)
   328 {
   329     SDL_Mouse *mouse = SDL_GetMouse();
   330     SDL_Surface *surface;
   331     SDL_Cursor *cursor;
   332     int x, y;
   333     Uint32 *pixel;
   334     Uint8 datab = 0, maskb = 0;
   335     const Uint32 black = 0xFF000000;
   336     const Uint32 white = 0xFFFFFFFF;
   337     const Uint32 transparent = 0x00000000;
   338 
   339     if (!mouse->CreateCursor) {
   340         SDL_SetError("Cursors are not currently supported");
   341         return NULL;
   342     }
   343 
   344     /* Sanity check the hot spot */
   345     if ((hot_x < 0) || (hot_y < 0) || (hot_x >= w) || (hot_y >= h)) {
   346         SDL_SetError("Cursor hot spot doesn't lie within cursor");
   347         return NULL;
   348     }
   349 
   350     /* Make sure the width is a multiple of 8 */
   351     w = ((w + 7) & ~7);
   352 
   353     /* Create the surface from a bitmap */
   354     surface =
   355         SDL_CreateRGBSurface(0, w, h, 32, 0x00FF0000, 0x0000FF00, 0x000000FF,
   356                              0xFF000000);
   357     if (!surface) {
   358         return NULL;
   359     }
   360     for (y = 0; y < h; ++y) {
   361         pixel = (Uint32 *) ((Uint8 *) surface->pixels + y * surface->pitch);
   362         for (x = 0; x < w; ++x) {
   363             if ((x % 8) == 0) {
   364                 datab = *data++;
   365                 maskb = *mask++;
   366             }
   367             if (maskb & 0x80) {
   368                 *pixel++ = (datab & 0x80) ? black : white;
   369             } else {
   370                 *pixel++ = (datab & 0x80) ? black : transparent;
   371             }
   372             datab <<= 1;
   373             maskb <<= 1;
   374         }
   375     }
   376 
   377     cursor = mouse->CreateCursor(surface, hot_x, hot_y);
   378     if (cursor) {
   379         cursor->next = mouse->cursors;
   380         mouse->cursors = cursor;
   381     }
   382 
   383     SDL_FreeSurface(surface);
   384 
   385     return cursor;
   386 }
   387 
   388 /* SDL_SetCursor(NULL) can be used to force the cursor redraw,
   389    if this is desired for any reason.  This is used when setting
   390    the video mode and when the SDL window gains the mouse focus.
   391  */
   392 void
   393 SDL_SetCursor(SDL_Cursor * cursor)
   394 {
   395     SDL_Mouse *mouse = SDL_GetMouse();
   396 
   397     /* Set the new cursor */
   398     if (cursor) {
   399         /* Make sure the cursor is still valid for this mouse */
   400         SDL_Cursor *found;
   401         for (found = mouse->cursors; found; found = found->next) {
   402             if (found == cursor) {
   403                 break;
   404             }
   405         }
   406         if (!found) {
   407             SDL_SetError("Cursor not associated with the current mouse");
   408             return;
   409         }
   410         mouse->cur_cursor = cursor;
   411     } else {
   412         cursor = mouse->cur_cursor;
   413     }
   414 
   415     if (cursor && mouse->cursor_shown && !mouse->relative_mode) {
   416         if (mouse->ShowCursor) {
   417             mouse->ShowCursor(cursor);
   418         }
   419     } else {
   420         if (mouse->ShowCursor) {
   421             mouse->ShowCursor(NULL);
   422         }
   423     }
   424 }
   425 
   426 SDL_Cursor *
   427 SDL_GetCursor(void)
   428 {
   429     SDL_Mouse *mouse = SDL_GetMouse();
   430 
   431     if (!mouse) {
   432         return NULL;
   433     }
   434     return mouse->cur_cursor;
   435 }
   436 
   437 void
   438 SDL_FreeCursor(SDL_Cursor * cursor)
   439 {
   440     SDL_Mouse *mouse = SDL_GetMouse();
   441     SDL_Cursor *curr, *prev;
   442 
   443     if (!cursor) {
   444         return;
   445     }
   446 
   447     if (cursor == mouse->def_cursor) {
   448         return;
   449     }
   450     if (cursor == mouse->cur_cursor) {
   451         SDL_SetCursor(mouse->def_cursor);
   452     }
   453 
   454     for (prev = NULL, curr = mouse->cursors; curr;
   455          prev = curr, curr = curr->next) {
   456         if (curr == cursor) {
   457             if (prev) {
   458                 prev->next = curr->next;
   459             } else {
   460                 mouse->cursors = curr->next;
   461             }
   462 
   463             if (mouse->FreeCursor) {
   464                 mouse->FreeCursor(curr);
   465             }
   466             return;
   467         }
   468     }
   469 }
   470 
   471 int
   472 SDL_ShowCursor(int toggle)
   473 {
   474     SDL_Mouse *mouse = SDL_GetMouse();
   475     SDL_bool shown;
   476 
   477     if (!mouse) {
   478         return 0;
   479     }
   480 
   481     shown = mouse->cursor_shown;
   482     if (toggle >= 0) {
   483         if (toggle) {
   484             mouse->cursor_shown = SDL_TRUE;
   485         } else {
   486             mouse->cursor_shown = SDL_FALSE;
   487         }
   488         if (mouse->cursor_shown != shown) {
   489             SDL_SetCursor(NULL);
   490         }
   491     }
   492     return shown;
   493 }
   494 
   495 /* vi: set ts=4 sw=4 expandtab: */