1 /*
2  *  Abuse - dark 2D side-scrolling platform game
3  *  Copyright (c) 2001 Anthony Kruize <trandor@labyrinth.net.au>
4  *  Copyright (c) 2005-2011 Sam Hocevar <sam@hocevar.net>
5  *
6  *  This program is free software; you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License as published by
8  *  the Free Software Foundation; either version 2 of the License, or
9  *  (at your option) any later version.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software Foundation,
18  *  Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
19  */
20 
21 #if defined HAVE_CONFIG_H
22 #   include "config.h"
23 #endif
24 
25 #include <SDL.h>
26 
27 #include "common.h"
28 
29 #include "image.h"
30 #include "palette.h"
31 #include "video.h"
32 #include "mouse.h"
33 #include "event.h"
34 #include "timing.h"
35 #include "sprite.h"
36 #include "game.h"
37 
38 extern int get_key_binding( char const *dir, int i );
39 extern int mouse_xscale, mouse_yscale;
40 short mouse_buttons[5] = { 0, 0, 0, 0, 0 };
41 
42 // Pre-declarations
43 void handle_mouse( event &ev );
44 
45 //
46 // Constructor
47 //
event_handler(image * screen,palette * pal)48 event_handler::event_handler( image *screen, palette *pal )
49 {
50     CHECK( screen && pal );
51     mouse = new JCMouse( screen, pal );
52     mhere = mouse->exsist();
53     last_keystat = get_key_flags();
54     ewaiting = 0;
55 
56     // Ignore activate events
57     SDL_EventState( SDL_ACTIVEEVENT, SDL_IGNORE );
58 }
59 
60 //
61 // Destructor
62 //
~event_handler()63 event_handler::~event_handler()
64 {
65     delete mouse;
66 }
67 
68 //
69 // flush_screen()
70 // Redraw the screen
71 //
flush_screen()72 void event_handler::flush_screen()
73 {
74     update_dirty( screen );
75 }
76 
77 //
78 // get_key_flags()
79 // Return the flag for the key modifiers
80 //
get_key_flags()81 int event_handler::get_key_flags()
82 {
83     SDLMod key_flag;
84 
85     key_flag = SDL_GetModState();
86 
87     return ( ( key_flag & KMOD_SHIFT ) != 0 ) << 3 |
88            ( ( key_flag & KMOD_CTRL ) != 0 ) << 2 |
89            ( ( key_flag & KMOD_ALT ) != 0 ) << 1;
90 }
91 
92 //
93 // event_waiting()
94 // Are there any events in the queue?
95 //
event_waiting()96 int event_handler::event_waiting()
97 {
98     if( ewaiting )
99     {
100         return 1;
101     }
102     if( SDL_PollEvent( NULL ) )
103     {
104         ewaiting = 1;
105     }
106     return ewaiting;
107 }
108 
109 //
110 // add_redraw()
111 // Add a redraw rectangle.
112 //
add_redraw(int X1,int Y1,int X2,int Y2,void * Start)113 void event_handler::add_redraw( int X1, int Y1, int X2, int Y2, void *Start )
114 {
115     event *ev;
116     ev = new event;
117     ev->type = EV_REDRAW;
118     ev->redraw.x1 = X1;
119     ev->redraw.x2 = X2;
120     ev->redraw.y1 = Y1;
121     ev->redraw.y2 = Y2;
122     ev->redraw.start = Start;
123     events.add_end(ev);
124 }
125 
126 //
127 // get_event()
128 // Get and handle waiting events
129 //
get_event(event & ev)130 void event_handler::get_event( event &ev )
131 {
132     event *ep;
133     while( !ewaiting )
134     {
135         event_waiting();
136 
137         if (!ewaiting)
138         {
139             // Sleep for 1 millisecond if there are no events
140             Timer tmp; tmp.WaitMs(1);
141         }
142     }
143 
144     ep = (event *)events.first();
145     if( ep )
146     {
147         ev = *ep;
148         events.unlink(ep);
149         delete ep;
150         ewaiting = events.first() != NULL;
151     }
152     else
153     {
154         // NOTE : that the mouse status should be known
155         // even if another event has occurred.
156         ev.mouse_move.x = mouse->x();
157         ev.mouse_move.y = mouse->y();
158         ev.mouse_button = mouse->button();
159 
160         // Gather events
161         SDL_Event event;
162         if( SDL_PollEvent( &event ) )
163         {
164             // always sort the mouse out
165             handle_mouse( ev );
166             mouse->update( ev.mouse_move.x, ev.mouse_move.y, ev.mouse_button );
167 
168             switch( event.type )
169             {
170                 case SDL_QUIT:
171                 {
172                     exit(0);
173                     break;
174                 }
175                 case SDL_MOUSEBUTTONUP:
176                 {
177                     switch( event.button.button )
178                     {
179                         case 4:        // Mouse wheel goes up...
180                         {
181                             ev.key = get_key_binding( "b4", 0 );
182                             ev.type = EV_KEYRELEASE;
183                             break;
184                         }
185                         case 5:        // Mouse wheel goes down...
186                         {
187                             ev.key = get_key_binding( "b3", 0 );
188                             ev.type = EV_KEYRELEASE;
189                             break;
190                         }
191                     }
192                     break;
193                 }
194                 case SDL_MOUSEBUTTONDOWN:
195                 {
196                     switch( event.button.button )
197                     {
198                         case 4:        // Mouse wheel goes up...
199                         {
200                             ev.key = get_key_binding( "b4", 0 );
201                             ev.type = EV_KEY;
202                             break;
203                         }
204                         case 5:        // Mouse wheel goes down...
205                         {
206                             ev.key = get_key_binding( "b3", 0 );
207                             ev.type = EV_KEY;
208                             break;
209                         }
210                     }
211                     break;
212                 }
213                 case SDL_KEYDOWN:
214                 case SDL_KEYUP:
215                 {
216                     // Default to EV_SPURIOUS
217                     ev.key = EV_SPURIOUS;
218                     if( event.type == SDL_KEYDOWN )
219                     {
220                         ev.type = EV_KEY;
221                     }
222                     else
223                     {
224                         ev.type = EV_KEYRELEASE;
225                     }
226                     switch( event.key.keysym.sym )
227                     {
228                         case SDLK_DOWN:            ev.key = JK_DOWN; break;
229                         case SDLK_UP:            ev.key = JK_UP; break;
230                         case SDLK_LEFT:            ev.key = JK_LEFT; break;
231                         case SDLK_RIGHT:        ev.key = JK_RIGHT; break;
232                         case SDLK_LCTRL:        ev.key = JK_CTRL_L; break;
233                         case SDLK_RCTRL:        ev.key = JK_CTRL_R; break;
234                         case SDLK_LALT:            ev.key = JK_ALT_L; break;
235                         case SDLK_RALT:            ev.key = JK_ALT_R; break;
236                         case SDLK_LSHIFT:        ev.key = JK_SHIFT_L; break;
237                         case SDLK_RSHIFT:        ev.key = JK_SHIFT_R; break;
238                         case SDLK_NUMLOCK:        ev.key = JK_NUM_LOCK; break;
239                         case SDLK_HOME:            ev.key = JK_HOME; break;
240                         case SDLK_END:            ev.key = JK_END; break;
241                         case SDLK_BACKSPACE:    ev.key = JK_BACKSPACE; break;
242                         case SDLK_TAB:            ev.key = JK_TAB; break;
243                         case SDLK_RETURN:        ev.key = JK_ENTER; break;
244                         case SDLK_SPACE:        ev.key = JK_SPACE; break;
245                         case SDLK_CAPSLOCK:        ev.key = JK_CAPS; break;
246                         case SDLK_ESCAPE:        ev.key = JK_ESC; break;
247                         case SDLK_F1:            ev.key = JK_F1; break;
248                         case SDLK_F2:            ev.key = JK_F2; break;
249                         case SDLK_F3:            ev.key = JK_F3; break;
250                         case SDLK_F4:            ev.key = JK_F4; break;
251                         case SDLK_F5:            ev.key = JK_F5; break;
252                         case SDLK_F6:            ev.key = JK_F6; break;
253                         case SDLK_F7:            ev.key = JK_F7; break;
254                         case SDLK_F8:            ev.key = JK_F8; break;
255                         case SDLK_F9:            ev.key = JK_F9; break;
256                         case SDLK_F10:            ev.key = JK_F10; break;
257                         case SDLK_INSERT:        ev.key = JK_INSERT; break;
258                         case SDLK_KP0:            ev.key = JK_INSERT; break;
259                         case SDLK_PAGEUP:        ev.key = JK_PAGEUP; break;
260                         case SDLK_PAGEDOWN:        ev.key = JK_PAGEDOWN; break;
261                         case SDLK_KP8:            ev.key = JK_UP; break;
262                         case SDLK_KP2:            ev.key = JK_DOWN; break;
263                         case SDLK_KP4:            ev.key = JK_LEFT; break;
264                         case SDLK_KP6:            ev.key = JK_RIGHT; break;
265                         case SDLK_F11:
266                         {
267                             // Only handle key down
268                             if( ev.type == EV_KEY )
269                             {
270                                 // Toggle fullscreen
271                                 SDL_WM_ToggleFullScreen( SDL_GetVideoSurface() );
272                             }
273                             ev.key = EV_SPURIOUS;
274                             break;
275                         }
276                         case SDLK_F12:
277                         {
278                             // Only handle key down
279                             if( ev.type == EV_KEY )
280                             {
281                                 // Toggle grab mouse
282                                 if( SDL_WM_GrabInput( SDL_GRAB_QUERY ) == SDL_GRAB_ON )
283                                 {
284                                     the_game->show_help( "Grab Mouse: OFF\n" );
285                                     SDL_WM_GrabInput( SDL_GRAB_OFF );
286                                 }
287                                 else
288                                 {
289                                     the_game->show_help( "Grab Mouse: ON\n" );
290                                     SDL_WM_GrabInput( SDL_GRAB_ON );
291                                 }
292                             }
293                             ev.key = EV_SPURIOUS;
294                             break;
295                         }
296                         case SDLK_PRINT:    // print-screen key
297                         {
298                             // Only handle key down
299                             if( ev.type == EV_KEY )
300                             {
301                                 // Grab a screenshot
302                                 SDL_SaveBMP( SDL_GetVideoSurface(), "screenshot.bmp" );
303                                 the_game->show_help( "Screenshot saved to: screenshot.bmp.\n" );
304                             }
305                             ev.key = EV_SPURIOUS;
306                             break;
307                         }
308                         default:
309                         {
310                             ev.key = (int)event.key.keysym.sym;
311                             // Need to handle the case of shift being pressed
312                             // There has to be a better way
313                             if( (event.key.keysym.mod & KMOD_SHIFT) != 0 )
314                             {
315                                 if( event.key.keysym.sym >= SDLK_a &&
316                                     event.key.keysym.sym <= SDLK_z )
317                                 {
318                                     ev.key -= 32;
319                                 }
320                                 else if( event.key.keysym.sym >= SDLK_1 &&
321                                          event.key.keysym.sym <= SDLK_5 )
322                                 {
323                                     ev.key -= 16;
324                                 }
325                                 else
326                                 {
327                                     switch( event.key.keysym.sym )
328                                     {
329                                         case SDLK_6:
330                                             ev.key = SDLK_CARET; break;
331                                         case SDLK_7:
332                                         case SDLK_9:
333                                         case SDLK_0:
334                                             ev.key -= 17; break;
335                                         case SDLK_8:
336                                             ev.key = SDLK_ASTERISK; break;
337                                         case SDLK_MINUS:
338                                             ev.key = SDLK_UNDERSCORE; break;
339                                         case SDLK_EQUALS:
340                                             ev.key = SDLK_PLUS; break;
341                                         case SDLK_COMMA:
342                                             ev.key = SDLK_LESS; break;
343                                         case SDLK_PERIOD:
344                                             ev.key = SDLK_GREATER; break;
345                                         case SDLK_SLASH:
346                                             ev.key = SDLK_QUESTION; break;
347                                         case SDLK_SEMICOLON:
348                                             ev.key = SDLK_COLON; break;
349                                         case SDLK_QUOTE:
350                                             ev.key = SDLK_QUOTEDBL; break;
351                                         default:
352                                             break;
353                                     }
354                                 }
355                             }
356                         }
357                     }
358                     break;
359                 }
360             }
361         }
362         // No more events
363         ewaiting = 0;
364     }
365 }
366 
367 //
368 // Handle mouse motion and button presses
369 // We don't handle the mousewheel here as
370 // SDL_GetMouseState doesn't seem to be
371 // able to detect that.
372 //
handle_mouse(event & ev)373 void handle_mouse( event &ev )
374 {
375     Uint8 buttons;
376     int x, y;
377 
378     // always sort the mouse out
379     buttons = SDL_GetMouseState( &x, &y );
380     x = (x << 16) / mouse_xscale;
381     y = (y << 16) / mouse_yscale;
382     if( x > screen->Size().x - 1 )
383     {
384         x = screen->Size().x - 1;
385     }
386     if( y > screen->Size().y - 1 )
387     {
388         y = screen->Size().y - 1;
389     }
390     ev.mouse_move.x = x;
391     ev.mouse_move.y = y;
392     ev.type = EV_MOUSE_MOVE;
393 
394     // Left button
395     if( (buttons & SDL_BUTTON(1)) && !mouse_buttons[1] )
396     {
397         ev.type = EV_MOUSE_BUTTON;
398         mouse_buttons[1] = !mouse_buttons[1];
399         ev.mouse_button |= LEFT_BUTTON;
400     }
401     else if( !(buttons & SDL_BUTTON(1)) && mouse_buttons[1] )
402     {
403         ev.type = EV_MOUSE_BUTTON;
404         mouse_buttons[1] = !mouse_buttons[1];
405         ev.mouse_button &= ( 0xff - LEFT_BUTTON );
406     }
407 
408     // Middle button
409     if( (buttons & SDL_BUTTON(2)) && !mouse_buttons[2] )
410     {
411         ev.type = EV_MOUSE_BUTTON;
412         mouse_buttons[2] = !mouse_buttons[2];
413         ev.mouse_button |= LEFT_BUTTON;
414         ev.mouse_button |= RIGHT_BUTTON;
415     }
416     else if( !(buttons & SDL_BUTTON(2)) && mouse_buttons[2] )
417     {
418         ev.type = EV_MOUSE_BUTTON;
419         mouse_buttons[2] = !mouse_buttons[2];
420         ev.mouse_button &= ( 0xff - LEFT_BUTTON );
421         ev.mouse_button &= ( 0xff - RIGHT_BUTTON );
422     }
423 
424     // Right button
425     if( (buttons & SDL_BUTTON(3)) && !mouse_buttons[3] )
426     {
427         ev.type = EV_MOUSE_BUTTON;
428         mouse_buttons[3] = !mouse_buttons[3];
429         ev.mouse_button |= RIGHT_BUTTON;
430     }
431     else if( !(buttons & SDL_BUTTON(3)) && mouse_buttons[3] )
432     {
433         ev.type = EV_MOUSE_BUTTON;
434         mouse_buttons[3] = !mouse_buttons[3];
435         ev.mouse_button &= ( 0xff - RIGHT_BUTTON );
436     }
437 }
438