src/events/SDL_mouse.c
author Edgar Simo <bobbens@gmail.com>
Mon, 28 Jul 2008 10:26:21 +0000
branchgsoc2008_force_feedback
changeset 2549 491e43f427ee
parent 2152 003c1b5b07da
child 2710 44e49d3fa6cf
child 3760 64f346a83ed3
permissions -rw-r--r--
Put haptic defines in SDL_configs, patch by Alam.
     1 /*
     2     SDL - Simple DirectMedia Layer
     3     Copyright (C) 1997-2006 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 
    30 
    31 static int SDL_num_mice;
    32 static int SDL_current_mouse;
    33 static SDL_Mouse **SDL_mice;
    34 
    35 
    36 /* Public functions */
    37 int
    38 SDL_MouseInit(void)
    39 {
    40     return (0);
    41 }
    42 
    43 SDL_Mouse *
    44 SDL_GetMouse(int index)
    45 {
    46     if (index < 0 || index >= SDL_num_mice) {
    47         return NULL;
    48     }
    49     return SDL_mice[index];
    50 }
    51 
    52 int
    53 SDL_AddMouse(const SDL_Mouse * mouse, int index)
    54 {
    55     SDL_Mouse **mice;
    56     int selected_mouse;
    57 
    58     /* Add the mouse to the list of mice */
    59     if (index < 0 || index >= SDL_num_mice || SDL_mice[index]) {
    60         mice =
    61             (SDL_Mouse **) SDL_realloc(SDL_mice,
    62                                        (SDL_num_mice + 1) * sizeof(*mice));
    63         if (!mice) {
    64             SDL_OutOfMemory();
    65             return -1;
    66         }
    67 
    68         SDL_mice = mice;
    69         index = SDL_num_mice++;
    70     }
    71     SDL_mice[index] = (SDL_Mouse *) SDL_malloc(sizeof(*SDL_mice[index]));
    72     if (!SDL_mice[index]) {
    73         SDL_OutOfMemory();
    74         return -1;
    75     }
    76     *SDL_mice[index] = *mouse;
    77 
    78     /* Create the default cursor for the mouse */
    79     SDL_mice[index]->cursor_shown = SDL_TRUE;
    80     selected_mouse = SDL_SelectMouse(index);
    81     SDL_mice[index]->cur_cursor = NULL;
    82     SDL_mice[index]->def_cursor =
    83         SDL_CreateCursor(default_cdata, default_cmask, DEFAULT_CWIDTH,
    84                          DEFAULT_CHEIGHT, DEFAULT_CHOTX, DEFAULT_CHOTY);
    85     SDL_SetCursor(SDL_mice[index]->def_cursor);
    86     SDL_SelectMouse(selected_mouse);
    87 
    88     return index;
    89 }
    90 
    91 void
    92 SDL_DelMouse(int index)
    93 {
    94     SDL_Mouse *mouse = SDL_GetMouse(index);
    95 
    96     if (!mouse) {
    97         return;
    98     }
    99 
   100     mouse->def_cursor = NULL;
   101     while (mouse->cursors) {
   102         SDL_FreeCursor(mouse->cursors);
   103     }
   104 
   105     if (mouse->FreeMouse) {
   106         mouse->FreeMouse(mouse);
   107     }
   108     SDL_free(mouse);
   109 
   110     SDL_mice[index] = NULL;
   111 }
   112 
   113 void
   114 SDL_ResetMouse(int index)
   115 {
   116     SDL_Mouse *mouse = SDL_GetMouse(index);
   117 
   118     if (!mouse) {
   119         return;
   120     }
   121 
   122     /* FIXME */
   123 }
   124 
   125 void
   126 SDL_MouseQuit(void)
   127 {
   128     int i;
   129 
   130     for (i = 0; i < SDL_num_mice; ++i) {
   131         SDL_DelMouse(i);
   132     }
   133     SDL_num_mice = 0;
   134     SDL_current_mouse = 0;
   135 
   136     if (SDL_mice) {
   137         SDL_free(SDL_mice);
   138         SDL_mice = NULL;
   139     }
   140 }
   141 
   142 int
   143 SDL_GetNumMice(void)
   144 {
   145     return SDL_num_mice;
   146 }
   147 
   148 int
   149 SDL_SelectMouse(int index)
   150 {
   151     if (index >= 0 && index < SDL_num_mice) {
   152         SDL_current_mouse = index;
   153     }
   154     return SDL_current_mouse;
   155 }
   156 
   157 SDL_WindowID
   158 SDL_GetMouseFocusWindow()
   159 {
   160     SDL_Mouse *mouse = SDL_GetMouse(SDL_current_mouse);
   161 
   162     if (!mouse) {
   163         return 0;
   164     }
   165     return mouse->focus;
   166 }
   167 
   168 static int SDLCALL
   169 FlushMouseMotion(void *param, SDL_Event * event)
   170 {
   171     if (event->type == SDL_MOUSEMOTION
   172         && event->motion.which == (Uint8) SDL_current_mouse) {
   173         return 0;
   174     } else {
   175         return 1;
   176     }
   177 }
   178 
   179 int
   180 SDL_SetRelativeMouseMode(SDL_bool enabled)
   181 {
   182     SDL_Mouse *mouse = SDL_GetMouse(SDL_current_mouse);
   183 
   184     if (!mouse) {
   185         return -1;
   186     }
   187 
   188     /* Flush pending mouse motion */
   189     mouse->flush_motion = SDL_TRUE;
   190     SDL_PumpEvents();
   191     mouse->flush_motion = SDL_FALSE;
   192     SDL_FilterEvents(FlushMouseMotion, mouse);
   193 
   194     /* Set the relative mode */
   195     mouse->relative_mode = enabled;
   196 
   197     /* Update cursor visibility */
   198     SDL_SetCursor(NULL);
   199 
   200     if (!enabled) {
   201         /* Restore the expected mouse position */
   202         SDL_WarpMouseInWindow(mouse->focus, mouse->x, mouse->y);
   203     }
   204     return 0;
   205 }
   206 
   207 SDL_bool
   208 SDL_GetRelativeMouseMode()
   209 {
   210     SDL_Mouse *mouse = SDL_GetMouse(SDL_current_mouse);
   211 
   212     if (!mouse) {
   213         return SDL_FALSE;
   214     }
   215     return mouse->relative_mode;
   216 }
   217 
   218 Uint8
   219 SDL_GetMouseState(int *x, int *y)
   220 {
   221     SDL_Mouse *mouse = SDL_GetMouse(SDL_current_mouse);
   222 
   223     if (!mouse) {
   224         if (x) {
   225             *x = 0;
   226         }
   227         if (y) {
   228             *y = 0;
   229         }
   230         return 0;
   231     }
   232 
   233     if (x) {
   234         *x = mouse->x;
   235     }
   236     if (y) {
   237         *y = mouse->y;
   238     }
   239     return mouse->buttonstate;
   240 }
   241 
   242 Uint8
   243 SDL_GetRelativeMouseState(int *x, int *y)
   244 {
   245     SDL_Mouse *mouse = SDL_GetMouse(SDL_current_mouse);
   246 
   247     if (!mouse) {
   248         if (x) {
   249             *x = 0;
   250         }
   251         if (y) {
   252             *y = 0;
   253         }
   254         return 0;
   255     }
   256 
   257     if (x) {
   258         *x = mouse->xdelta;
   259     }
   260     if (y) {
   261         *y = mouse->ydelta;
   262     }
   263     mouse->xdelta = 0;
   264     mouse->ydelta = 0;
   265     return mouse->buttonstate;
   266 }
   267 
   268 void
   269 SDL_SetMouseFocus(int index, SDL_WindowID windowID)
   270 {
   271     SDL_Mouse *mouse = SDL_GetMouse(index);
   272     int i;
   273     SDL_bool focus;
   274 
   275     if (!mouse || (mouse->focus == windowID)) {
   276         return;
   277     }
   278 
   279     /* See if the current window has lost focus */
   280     if (mouse->focus) {
   281         focus = SDL_FALSE;
   282         for (i = 0; i < SDL_num_mice; ++i) {
   283             SDL_Mouse *check;
   284             if (i != index) {
   285                 check = SDL_GetMouse(i);
   286                 if (check && check->focus == mouse->focus) {
   287                     focus = SDL_TRUE;
   288                     break;
   289                 }
   290             }
   291         }
   292         if (!focus) {
   293             SDL_SendWindowEvent(mouse->focus, SDL_WINDOWEVENT_LEAVE, 0, 0);
   294         }
   295     }
   296 
   297     mouse->focus = windowID;
   298 
   299     if (mouse->focus) {
   300         focus = SDL_FALSE;
   301         for (i = 0; i < SDL_num_mice; ++i) {
   302             SDL_Mouse *check;
   303             if (i != index) {
   304                 check = SDL_GetMouse(i);
   305                 if (check && check->focus == mouse->focus) {
   306                     focus = SDL_TRUE;
   307                     break;
   308                 }
   309             }
   310         }
   311         if (!focus) {
   312             SDL_SendWindowEvent(mouse->focus, SDL_WINDOWEVENT_ENTER, 0, 0);
   313         }
   314     }
   315 }
   316 
   317 int
   318 SDL_SendMouseMotion(int index, int relative, int x, int y)
   319 {
   320     SDL_Mouse *mouse = SDL_GetMouse(index);
   321     int posted;
   322     int xrel;
   323     int yrel;
   324 
   325     if (!mouse || mouse->flush_motion) {
   326         return 0;
   327     }
   328 
   329     if (relative) {
   330         /* Push the cursor around */
   331         xrel = x;
   332         yrel = y;
   333         x = (mouse->x + xrel);
   334         y = (mouse->y + yrel);
   335     } else {
   336         xrel = x - mouse->x;
   337         yrel = y - mouse->y;
   338     }
   339 
   340     /* Drop events that don't change state */
   341     if (!xrel && !yrel) {
   342 #if 0
   343         printf("Mouse event didn't change state - dropped!\n");
   344 #endif
   345         return 0;
   346     }
   347 
   348     /* Update internal mouse state */
   349     if (!mouse->relative_mode) {
   350         mouse->x = x;
   351         mouse->y = y;
   352     }
   353     mouse->xdelta += xrel;
   354     mouse->ydelta += yrel;
   355 
   356     /* Move the mouse cursor, if needed */
   357     if (mouse->cursor_shown && !mouse->relative_mode &&
   358         mouse->MoveCursor && mouse->cur_cursor) {
   359         mouse->MoveCursor(mouse->cur_cursor);
   360     }
   361 
   362     /* Post the event, if desired */
   363     posted = 0;
   364     if (SDL_ProcessEvents[SDL_MOUSEMOTION] == SDL_ENABLE) {
   365         SDL_Event event;
   366         event.motion.type = SDL_MOUSEMOTION;
   367         event.motion.which = (Uint8) index;
   368         event.motion.state = mouse->buttonstate;
   369         event.motion.x = mouse->x;
   370         event.motion.y = mouse->y;
   371         event.motion.xrel = xrel;
   372         event.motion.yrel = yrel;
   373         event.motion.windowID = mouse->focus;
   374         posted = (SDL_PushEvent(&event) > 0);
   375     }
   376     return posted;
   377 }
   378 
   379 int
   380 SDL_SendMouseButton(int index, Uint8 state, Uint8 button)
   381 {
   382     SDL_Mouse *mouse = SDL_GetMouse(index);
   383     int posted;
   384     Uint8 type;
   385 
   386     if (!mouse) {
   387         return 0;
   388     }
   389 
   390     /* Figure out which event to perform */
   391     switch (state) {
   392     case SDL_PRESSED:
   393         if (mouse->buttonstate & SDL_BUTTON(button)) {
   394             /* Ignore this event, no state change */
   395             return 0;
   396         }
   397         type = SDL_MOUSEBUTTONDOWN;
   398         mouse->buttonstate |= SDL_BUTTON(button);
   399         break;
   400     case SDL_RELEASED:
   401         if (!(mouse->buttonstate & SDL_BUTTON(button))) {
   402             /* Ignore this event, no state change */
   403             return 0;
   404         }
   405         type = SDL_MOUSEBUTTONUP;
   406         mouse->buttonstate &= ~SDL_BUTTON(button);
   407         break;
   408     default:
   409         /* Invalid state -- bail */
   410         return 0;
   411     }
   412 
   413     /* Post the event, if desired */
   414     posted = 0;
   415     if (SDL_ProcessEvents[type] == SDL_ENABLE) {
   416         SDL_Event event;
   417         event.type = type;
   418         event.button.which = (Uint8) index;
   419         event.button.state = state;
   420         event.button.button = button;
   421         event.button.x = mouse->x;
   422         event.button.y = mouse->y;
   423         event.button.windowID = mouse->focus;
   424         posted = (SDL_PushEvent(&event) > 0);
   425     }
   426     return posted;
   427 }
   428 
   429 int
   430 SDL_SendMouseWheel(int index, int x, int y)
   431 {
   432     SDL_Mouse *mouse = SDL_GetMouse(index);
   433     int posted;
   434 
   435     if (!mouse || (!x && !y)) {
   436         return 0;
   437     }
   438 
   439     /* Post the event, if desired */
   440     posted = 0;
   441     if (SDL_ProcessEvents[SDL_MOUSEWHEEL] == SDL_ENABLE) {
   442         SDL_Event event;
   443         event.type = SDL_MOUSEWHEEL;
   444         event.wheel.which = (Uint8) index;
   445         event.wheel.x = x;
   446         event.wheel.y = y;
   447         event.wheel.windowID = mouse->focus;
   448         posted = (SDL_PushEvent(&event) > 0);
   449     }
   450     return posted;
   451 }
   452 
   453 void
   454 SDL_WarpMouseInWindow(SDL_WindowID windowID, int x, int y)
   455 {
   456     SDL_Mouse *mouse = SDL_GetMouse(SDL_current_mouse);
   457 
   458     if (!mouse) {
   459         return;
   460     }
   461 
   462     if (mouse->WarpMouse) {
   463         mouse->WarpMouse(mouse, windowID, x, y);
   464     } else {
   465         SDL_SetMouseFocus(SDL_current_mouse, windowID);
   466         SDL_SendMouseMotion(SDL_current_mouse, 0, x, y);
   467     }
   468 }
   469 
   470 SDL_Cursor *
   471 SDL_CreateCursor(const Uint8 * data, const Uint8 * mask,
   472                  int w, int h, int hot_x, int hot_y)
   473 {
   474     SDL_Mouse *mouse = SDL_GetMouse(SDL_current_mouse);
   475     SDL_Surface *surface;
   476     SDL_Cursor *cursor;
   477     int x, y;
   478     Uint32 *pixel;
   479     Uint8 datab, maskb;
   480     const Uint32 black = 0xFF000000;
   481     const Uint32 white = 0xFFFFFFFF;
   482     const Uint32 transparent = 0x00000000;
   483 
   484     if (!mouse) {
   485         SDL_SetError("No mice are initialized");
   486         return NULL;
   487     }
   488 
   489     if (!mouse->CreateCursor) {
   490         SDL_SetError("Current mouse doesn't have cursor support");
   491         return NULL;
   492     }
   493 
   494     /* Sanity check the hot spot */
   495     if ((hot_x < 0) || (hot_y < 0) || (hot_x >= w) || (hot_y >= h)) {
   496         SDL_SetError("Cursor hot spot doesn't lie within cursor");
   497         return NULL;
   498     }
   499 
   500     /* Make sure the width is a multiple of 8 */
   501     w = ((w + 7) & ~7);
   502 
   503     /* Create the surface from a bitmap */
   504     surface =
   505         SDL_CreateRGBSurface(0, w, h, 32, 0x00FF0000, 0x0000FF00, 0x000000FF,
   506                              0xFF000000);
   507     if (!surface) {
   508         return NULL;
   509     }
   510     for (y = 0; y < h; ++y) {
   511         pixel = (Uint32 *) ((Uint8 *) surface->pixels + y * surface->pitch);
   512         for (x = 0; x < w; ++x) {
   513             if ((x % 8) == 0) {
   514                 datab = *data++;
   515                 maskb = *mask++;
   516             }
   517             if (maskb & 0x80) {
   518                 *pixel++ = (datab & 0x80) ? black : white;
   519             } else {
   520                 *pixel++ = (datab & 0x80) ? black : transparent;
   521             }
   522             datab <<= 1;
   523             maskb <<= 1;
   524         }
   525     }
   526 
   527     cursor = mouse->CreateCursor(surface, hot_x, hot_y);
   528     if (cursor) {
   529         cursor->mouse = mouse;
   530         cursor->next = mouse->cursors;
   531         mouse->cursors = cursor;
   532     }
   533 
   534     SDL_FreeSurface(surface);
   535 
   536     return cursor;
   537 }
   538 
   539 /* SDL_SetCursor(NULL) can be used to force the cursor redraw,
   540    if this is desired for any reason.  This is used when setting
   541    the video mode and when the SDL window gains the mouse focus.
   542  */
   543 void
   544 SDL_SetCursor(SDL_Cursor * cursor)
   545 {
   546     SDL_Mouse *mouse = SDL_GetMouse(SDL_current_mouse);
   547 
   548     if (!mouse) {
   549         SDL_SetError("No mice are initialized");
   550         return;
   551     }
   552 
   553     /* Set the new cursor */
   554     if (cursor) {
   555         /* Make sure the cursor is still valid for this mouse */
   556         SDL_Cursor *found;
   557         for (found = mouse->cursors; found; found = found->next) {
   558             if (found == cursor) {
   559                 break;
   560             }
   561         }
   562         if (!found) {
   563             SDL_SetError("Cursor not associated with the current mouse");
   564             return;
   565         }
   566         mouse->cur_cursor = cursor;
   567     } else {
   568         cursor = mouse->cur_cursor;
   569     }
   570 
   571     if (cursor && mouse->cursor_shown && !mouse->relative_mode) {
   572         if (mouse->ShowCursor) {
   573             mouse->ShowCursor(cursor);
   574         }
   575     } else {
   576         if (mouse->ShowCursor) {
   577             mouse->ShowCursor(NULL);
   578         }
   579     }
   580 }
   581 
   582 SDL_Cursor *
   583 SDL_GetCursor(void)
   584 {
   585     SDL_Mouse *mouse = SDL_GetMouse(SDL_current_mouse);
   586 
   587     if (!mouse) {
   588         return NULL;
   589     }
   590     return mouse->cur_cursor;
   591 }
   592 
   593 void
   594 SDL_FreeCursor(SDL_Cursor * cursor)
   595 {
   596     SDL_Mouse *mouse;
   597     SDL_Cursor *curr, *prev;
   598 
   599     if (!cursor) {
   600         return;
   601     }
   602     mouse = cursor->mouse;
   603 
   604     if (cursor == mouse->def_cursor) {
   605         return;
   606     }
   607     if (cursor == mouse->cur_cursor) {
   608         SDL_SetCursor(mouse->def_cursor);
   609     }
   610 
   611     for (prev = NULL, curr = mouse->cursors; curr;
   612          prev = curr, curr = curr->next) {
   613         if (curr == cursor) {
   614             if (prev) {
   615                 prev->next = curr->next;
   616             } else {
   617                 mouse->cursors = curr->next;
   618             }
   619 
   620             if (mouse->FreeCursor) {
   621                 mouse->FreeCursor(curr);
   622             }
   623             return;
   624         }
   625     }
   626 }
   627 
   628 int
   629 SDL_ShowCursor(int toggle)
   630 {
   631     SDL_Mouse *mouse = SDL_GetMouse(SDL_current_mouse);
   632     SDL_bool shown;
   633 
   634     if (!mouse) {
   635         return 0;
   636     }
   637 
   638     shown = mouse->cursor_shown;
   639     if (toggle >= 0) {
   640         if (toggle) {
   641             mouse->cursor_shown = SDL_TRUE;
   642         } else {
   643             mouse->cursor_shown = SDL_FALSE;
   644         }
   645         if (mouse->cursor_shown != shown) {
   646             SDL_SetCursor(NULL);
   647         }
   648     }
   649     return shown;
   650 }
   651 
   652 /* vi: set ts=4 sw=4 expandtab: */