src/SAL_eventhandler.cpp

00001 /*
00002     SAL - Simple Application Library
00003     Copyright (C) 2006-2006 Kronon
00004 
00005     This library is free software; you can redistribute it and/or
00006     modify it under the terms of the GNU Lesser General Public
00007     License as published by the Free Software Foundation; either
00008     version 2.1 of the License, or (at your option) any later version.
00009 
00010     This library is distributed in the hope that it will be useful,
00011     but WITHOUT ANY WARRANTY; without even the implied warranty of
00012     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013     Lesser General Public License for more details.
00014 
00015     You should have received a copy of the GNU Lesser General Public
00016     License along with this library; if not, write to the Free Software
00017     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00018 
00019     Kronon
00020     kronon88@users.sourceforge.net
00021 */
00022 
00023 //SAL event handling
00024 //Created by Kronon
00025 
00026 //Doxy gen information
00027 
00034 #include "SAL_eventhandler.h"
00035 
00036 //Local variables
00037 SDL_Thread *keyboard_thread = NULL;
00038 bool keyboard_active;
00039 
00047 struct SAL_reg_key                                                      //A key that is registered to the event listener
00048 {
00049         Uint16 unicode;                                                 
00050         SAL_gui_object * object;                                
00051 };
00052 
00059 salList<SAL_reg_key> registered_keys;
00060 
00068 struct SAL_keyboard_item
00069 {
00070         SDLKey key;                                                             
00071         SDLMod mod;                                                             
00072         Uint32 life;                                                    
00073         SAL_gui_object * selected;                              
00074 };
00075 
00082 salList<SAL_keyboard_item> pend_keys;
00086 SDL_mutex *keyboard_mutex;                                      //Protects pend_keys list
00087 
00094 struct SAL_keyboard_items
00095 {
00096         int delay;                                                              
00097 };
00102 SAL_keyboard_items keyboard;
00103 
00110 struct SAL_mouse_items
00111 {
00112         SDL_Thread *thread;                                             
00113         bool active;                                                    
00114         char clicks;                                                    
00115         SAL_gui_object * selected;                              
00116         Uint16  x;                                                              
00117         Uint16 y;                                                               
00118         char button;                                                    
00119         int delay;                                                              
00120 };
00125 SAL_mouse_items mouse;
00126 
00135 //In: Point to pend_key in array, Uint16 unicode char
00136 //Out: Bool (match/no match)
00137 //Action: Look if unicode char of keyboard_item and wanted unicode char match
00138 bool remove_key(SAL_keyboard_item item, SAL_keyboard_item target)
00139 {
00140         return (item.key == target.key);
00141 }
00142 
00151 //In: default mouse delay time, default keyboard delay time
00152 //Out: Error_code
00153 //Action: Start event listener thread
00154 int SAL_start_event_listener(int & mouse_delay, int & keyboard_delay)
00155 {
00156         //Delay times
00157         mouse.delay = mouse_delay;
00158         keyboard.delay = keyboard_delay;
00159         
00160         //Load the event listener
00161         SAL_struct.internal.event.thread = SDL_CreateThread(SAL_event_listener, NULL);
00162         if(SAL_struct.internal.event.thread == NULL)
00163         {
00164 #ifdef SAL_DEBUG_ON
00165                 salError("Error: Event handler thread couldn't start");
00166 #endif
00167                 return -1;
00168         }
00169         return 0;
00170 }
00171 
00182 //In: Nothing realy
00183 //Out: Error_code
00184 //Action: Listen to the sdl events, convert them to a more useable standard, call defined action handlers
00185 int SAL_event_listener(void * unused)
00186 {
00187         //Set some vars
00188         mouse.thread = NULL;
00189         mouse.active = false;
00190         keyboard_mutex = SDL_CreateMutex();
00191         keyboard_active = false;
00192 
00193 #ifdef SAL_DEBUG_ON
00194         sleep(1);       //Debuger crashes in some case because it can't find the thread after termination
00195 #endif
00196     
00197         SDL_Event event;
00198     //We want to know new events as long as we don't quit
00199     while(SAL_struct.internal.checks.alive)
00200     {
00201         //Check the next event
00202         SDL_WaitEvent(&event);
00203         switch (event.type) 
00204         {
00205                 case SDL_MOUSEBUTTONDOWN:
00206                 {
00207                                 mouse.clicks++;
00208                 }
00209                 break;
00210                 case SDL_MOUSEBUTTONUP:
00211                 {
00212                         if(mouse.active)
00213                                 mouse.clicks++; //Total clicks is mouse_clicks / 2
00214                                 else
00215                                 {
00216                                         mouse.clicks = 2;
00217                                                 
00218                                         mouse.selected = NULL;
00219                                         SAL_search_object(event.button.x, event.button.y, mouse.selected);
00220                                                 
00221                                         //We need to register amount of clicks
00222                                         mouse.x = event.button.x;
00223                                         mouse.y = event.button.y;
00224                                         mouse.button = event.button.button;
00225                                         
00226                                         mouse.active = true;
00227                                         SDL_WaitThread(mouse.thread, NULL);                                     //Free's memory and solves a bug
00228                                         mouse.thread = SDL_CreateThread(SAL_mouse_listener, NULL);
00229         
00230                                         if(mouse.thread == NULL)
00231                                         {
00232 #ifdef SAL_DEBUG_ON
00233                                                         salError("Error: Mouse listener thread couldn't start");
00234 #endif
00235                                                         return -1;
00236                                         }
00237                                         
00238                                         if(mouse.selected)
00239                                         {
00240                                                 //Select object
00241                                                 mouse.selected->func->pressed(mouse.selected);
00242                                         }
00243                         }
00244                 }
00245                 break;
00246                 case SDL_KEYDOWN:
00247                 {
00248                         //Add key to key list
00249                                 SDL_mutexP(keyboard_mutex);
00250                                 SAL_gui_object * selected = NULL;
00251 #ifdef SAL_DEBUG_ON
00252                         printf("Key down = %i\n",event.key.keysym.sym);
00253 #endif
00254                         SAL_search_object(event.key.keysym.unicode, selected);
00255                         SAL_keyboard_item key = {event.key.keysym.sym,event.key.keysym.mod, SDL_GetTicks() + keyboard.delay, selected};
00256                         
00257                         pend_keys.append(key);
00258                         
00259                                 //Process event
00260                                 if(SAL_struct.internal.event.active_object == NULL)
00261                                 {
00262                                         if(SAL_struct.internal.event.action_handler.keyboard != NULL)
00263                                                 SAL_struct.internal.event.action_handler.keyboard(key.key, key.mod);
00264                                 }
00265                                 else
00266                                         SAL_struct.internal.event.active_object->func->key_down(SAL_struct.internal.event.active_object,key.key, key.mod);
00267                                         
00268                                         if(!keyboard_active)
00269                                         {
00270                                                 keyboard_active = true;
00271                                                 SDL_WaitThread(keyboard_thread, NULL);                                  //Free's memory and solves a bug
00272                                                 keyboard_thread = SDL_CreateThread(SAL_keyboard_listener, NULL);
00273                                         
00274                                                 if(keyboard_thread == NULL)
00275                                                 {
00276         #ifdef SAL_DEBUG_ON
00277                                                         salError("Error: Keyboard listener thread couldn't start");
00278         #endif
00279                                                         return -1;
00280                                                 }
00281                                         }
00282                                 SDL_mutexV(keyboard_mutex);
00283                         }
00284                 break;
00285                 case SDL_KEYUP:
00286                 {
00287                         //Remove key from polled keys
00288 #ifdef SAL_DEBUG_ON
00289                         printf("Key up   = %i\n",event.key.keysym.sym);
00290 #endif
00291                         SDL_mutexP(keyboard_mutex);
00292                         pend_keys.funcRemove(remove_key,(SAL_keyboard_item){(SDLKey)event.key.keysym.sym,(SDLMod)NULL,0,NULL},-1);
00293                         SDL_mutexV(keyboard_mutex);
00294                 }
00295                 break;
00296                         case SDL_QUIT:
00297                         {
00298                                 //SDL got an signal to quit, so lets exit the program the nice way
00299                                 salStop();
00300                                 break;
00301                         }
00302                 }
00303     }
00304     SDL_mutexP(keyboard_mutex);                 //Protect pend_keys list
00305     pend_keys.clear();
00306     SDL_mutexV(keyboard_mutex);
00307     
00308     SDL_WaitThread(keyboard_thread, NULL);
00309     SDL_DestroyMutex(keyboard_mutex);
00310     return 0;
00311 }
00312 
00321 //In: None
00322 //Out: Error_code
00323 //Action: After some time this get the ammount of clicks and executes the user defined mouse handler
00324 int SAL_mouse_listener(void * unused)
00325 {
00326         //Wait
00327         SDL_Delay(mouse.delay);
00328         
00329         if(mouse.selected)
00330         {
00331                 mouse.selected->func->released(mouse.selected);
00332                 if(SAL_struct.internal.event.action_handler.action != NULL)
00333                         SAL_struct.internal.event.action_handler.action(mouse.selected->id);
00334         }
00335         else if(SAL_struct.internal.event.action_handler.mouse != NULL)
00336                 SAL_struct.internal.event.action_handler.mouse(mouse.x, mouse.y, mouse.button, mouse.clicks);
00337         
00338         mouse.active = false;   //Safe?
00339         return 0;
00340 }
00341 
00350 //In: None
00351 //Out: Error_code
00352 //Action: Ass long as any button is pressed this thread generates "button presses(better name?)"
00353 int SAL_keyboard_listener(void * unused)
00354 {
00355         //pend_keys.setLoopBegin(); //Get the beginning of the array with pause times of keys with there corresponding key code
00356         SDL_mutexP(keyboard_mutex);                     //Protect pend_keys list
00357         while(!pend_keys.isEmpty()) //Only loop while there are keys
00358         {
00359                 //Save all active keys to array
00360                 //Check if all keys are still active in that array
00361                 SDL_mutexV(keyboard_mutex);                     //Free acces to pend_keys
00362                 SDL_Delay(keyboard.delay);                      //Key poll time
00363                 SDL_mutexP(keyboard_mutex);                     //Protect pend_keys list
00364                 
00365                 for(pend_keys.setLoopBegin(); pend_keys.inLoop(); )
00366                 {
00367 
00368 //                              if(SAL_search_object(pend_keys.getLoopEntry(), object) != -1)
00369 //                                      SAL_struct.internal.event.action_handler.action(object->id);
00370 //                              else
00371                         if(pend_keys.getLoopEntry().life < SDL_GetTicks())                              //Key needs to be stroken for at least some time
00372                         {
00373                                 if(SAL_struct.internal.event.active_object == NULL)
00374                                 {
00375                                         if(SAL_struct.internal.event.action_handler.keyboard != NULL)
00376                                                 SAL_struct.internal.event.action_handler.keyboard(pend_keys.getLoopEntry().key, pend_keys.getLoopEntry().mod);
00377                                 }
00378                                 else
00379                                                 SAL_struct.internal.event.active_object->func->key_down(SAL_struct.internal.event.active_object,pend_keys.getLoopEntry().key, pend_keys.getLoopEntry().mod);
00380                         }
00381                 }
00382         }
00383         keyboard_active = false;
00384         SDL_mutexV(keyboard_mutex);                             //Free acces ti pend_keys
00385         return 0;
00386 }
00387 
00397 //In: x coordinate, y coordinate, type of click, object id that is to be returned by this function
00398 //Out: Error_code
00399 //Action: Search corresponding block with x,y. Look if an object is located at the given coordinates and return it
00400 inline int SAL_search_object(int x, int y, SAL_gui_object *& target)
00401 {
00402         //Calcultate the ractangle the mouse is in and start searching from that rectangle
00403         //The window is devided in 5x5 rectangles
00404         //TODO: when the window resizes we need to change the contents of the blocks according to the new situation
00405         int blockX, blockY;
00406         blockX = x / (SAL_struct.internal.render.display->w / 5);
00407         blockY = y / (SAL_struct.internal.render.display->h / 5);
00408         
00409         //Open the block and search for objects
00410         for(SAL_struct.internal.event.select_matrix[blockX][blockY].setLoopBegin(); SAL_struct.internal.event.select_matrix[blockX][blockY].inLoop(); )
00411         {       
00412                 //Check left border
00413                 //Check Top border
00414                 //Check Right border
00415                 //Check bottom border
00416                 if(SAL_struct.internal.event.select_matrix[blockX][blockY].getLoopEntry()->x <= x && 
00417                         SAL_struct.internal.event.select_matrix[blockX][blockY].getLoopEntry()->y <= y &&
00418                         (SAL_struct.internal.event.select_matrix[blockX][blockY].getLoopEntry()->surface->w +
00419                         SAL_struct.internal.event.select_matrix[blockX][blockY].getLoopEntry()->x) >= x &&
00420                         (SAL_struct.internal.event.select_matrix[blockX][blockY].getLoopEntry()->surface->h +
00421                         SAL_struct.internal.event.select_matrix[blockX][blockY].getLoopEntry()->y) >= y)
00422                 {
00423                         target = SAL_struct.internal.event.select_matrix[blockX][blockY].getLoopEntry();        //Set object id
00424                         return 1;               //Found an object
00425                 }
00426         }
00427         
00428         return 0;                               //Found no object
00429 }
00430 
00439 //In: Keyboard character, object that is to be returned
00440 //Out: Error_code
00441 //  0:  Normal
00442 // -1:  No object registered with that code
00443 //Action: Search object that is connected to the given char
00444 int SAL_search_object(Uint16 unicode, SAL_gui_object *& target)
00445 {
00446     //Search for an object with unicode as fast key and return that object
00447     for(registered_keys.setLoopBegin(); registered_keys.inLoop(); )
00448     {
00449         if(registered_keys.getLoopEntry().unicode == unicode)
00450         {
00451                 target = registered_keys.getLoopEntry().object;
00452                 return 0;       
00453         }
00454     }
00455         return -1;
00456 } 
00457 
00464 //In: pointer to user defined action handler
00465 //Out: Error_code
00466 //  0:  Normal
00467 //Action: Connect user defined action handler to SAL library
00468 int salSetActionHandler(int (*action)(int action_id))
00469 {
00470         SAL_struct.internal.event.action_handler.action = action;
00471         return 0;
00472 }
00473 
00479 
00481 //In: pointer to user defined mouse handler
00482 //Out: Error_code
00483 //  0:  Normal
00484 //Action: Connect user defined mouse handler to SAL library
00485 int salSetMouseHandler(int (*mouse)(int x, int y, char button, char clicks))
00486 {
00487         SAL_struct.internal.event.action_handler.mouse = mouse;
00488         return 0;
00489 }
00490 
00497 //In: pointer to user defined keyboard handler
00498 //Out: Error_code
00499 //  0:  Normal
00500 //Action: Connect user defined keyboard handler to SAL library
00501 int salSetKeyboardHandler(int (*keyboard)(SDLKey key, SDLMod mod))
00502 {
00503         SAL_struct.internal.event.action_handler.keyboard = keyboard;
00504     return 0;
00505 }