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