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