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