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