source: abuse/trunk/src/sdl2port/event.cpp @ 731

Last change on this file since 731 was 731, checked in by jjsimpso, 8 years ago

sdlport: Add support for SDL2, inculding the game controller API. Configure
script will check for SDL2 and use it if present, otherwise it will fall
back to SDL v1. Some old SDL v1 features not implemented yet on SDL2, such
as saving screenshots.

core: Small change for SDL2 game controller API to disable the game
controller in the save/load game menu.

Summary of game controller API changes:

  • Enable with -gamepad
  • Tested with PS3 dualshock 3.
  • D-pad moves, right analog controls aiming
  • X: change weapon, []: jump, R1: fire, L1: special ability, /\:use/activate
  • All menu navigation requires the mouse, which is disabled during normal game play.
File size: 14.3 KB
Line 
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 "event.h"
33#include "timing.h"
34#include "sprite.h"
35#include "game.h"
36#include "setup.h"
37
38extern int get_key_binding(char const *dir, int i);
39extern int mouse_xscale, mouse_yscale;
40short mouse_buttons[5] = { 0, 0, 0, 0, 0 };
41SDL_GameController *controller;
42
43extern SDL_Window *window;
44extern flags_struct flags;
45
46// Pre-declarations
47void controller_to_mouse( Event &ev, SDL_Event *sdl_event );
48
49void EventHandler::SysInit()
50{
51    // enable game controller
52    // still needs to be detected to be used though
53    controller_enabled = true;
54
55    // Ignore activate events (still needed in SDL2?)
56    //SDL_EventState(SDL_ACTIVEEVENT, SDL_IGNORE);
57}
58
59void EventHandler::SysWarpMouse(ivec2 pos)
60{
61    SDL_WarpMouseInWindow(window, pos.x, pos.y);
62}
63
64//
65// IsPending()
66// Are there any events in the queue?
67//
68int EventHandler::IsPending()
69{
70    if (!m_pending && SDL_PollEvent(NULL))
71        m_pending = 1;
72
73    return m_pending;
74}
75
76//
77// Get and handle waiting events
78//
79void EventHandler::SysEvent(Event &ev)
80{
81    // No more events
82    m_pending = 0;
83
84    // NOTE : that the mouse status should be known
85    // even if another event has occurred.
86    ev.mouse_move.x = m_pos.x;
87    ev.mouse_move.y = m_pos.y;
88    //ev.mouse_button = m_button;
89
90    // Gather next event
91    SDL_Event sdlev;
92    if (!SDL_PollEvent(&sdlev))
93        return; // This should not happen
94
95    if((controller != NULL) && (the_game->state == RUN_STATE) && controller_enabled)
96    {
97        // controller axis events translated to mouse events
98        controller_to_mouse(ev, &sdlev);
99        printf("ev.mouse button = %d, mouse_buttons[0]=%d\n", ev.mouse_button, mouse_buttons[0]);
100    }
101    else
102    {
103        ev.mouse_button = m_button;
104       
105        // Sort the mouse out
106        int x, y;
107        uint8_t buttons = SDL_GetMouseState(&x, &y);
108        x = Min((x << 16) / mouse_xscale, main_screen->Size().x - 1);
109        y = Min((y << 16) / mouse_yscale, main_screen->Size().y - 1);
110        ev.mouse_move.x = x;
111        ev.mouse_move.y = y;
112        ev.type = EV_MOUSE_MOVE;
113       
114        // Left button
115        if((buttons & SDL_BUTTON(1)) && !mouse_buttons[1])
116        {
117            ev.type = EV_MOUSE_BUTTON;
118            mouse_buttons[1] = !mouse_buttons[1];
119            ev.mouse_button |= LEFT_BUTTON;
120        }
121        else if(!(buttons & SDL_BUTTON(1)) && mouse_buttons[1])
122        {
123            ev.type = EV_MOUSE_BUTTON;
124            mouse_buttons[1] = !mouse_buttons[1];
125            ev.mouse_button &= (0xff - LEFT_BUTTON);
126        }
127       
128        // Middle button
129        if((buttons & SDL_BUTTON(2)) && !mouse_buttons[2])
130        {
131            ev.type = EV_MOUSE_BUTTON;
132            mouse_buttons[2] = !mouse_buttons[2];
133            ev.mouse_button |= LEFT_BUTTON;
134            ev.mouse_button |= RIGHT_BUTTON;
135        }
136        else if(!(buttons & SDL_BUTTON(2)) && mouse_buttons[2])
137        {
138            ev.type = EV_MOUSE_BUTTON;
139            mouse_buttons[2] = !mouse_buttons[2];
140            ev.mouse_button &= (0xff - LEFT_BUTTON);
141            ev.mouse_button &= (0xff - RIGHT_BUTTON);
142        }
143       
144        // Right button
145        if((buttons & SDL_BUTTON(3)) && !mouse_buttons[3])
146        {
147            ev.type = EV_MOUSE_BUTTON;
148            mouse_buttons[3] = !mouse_buttons[3];
149            ev.mouse_button |= RIGHT_BUTTON;
150        }
151        else if(!(buttons & SDL_BUTTON(3)) && mouse_buttons[3])
152        {
153            ev.type = EV_MOUSE_BUTTON;
154            mouse_buttons[3] = !mouse_buttons[3];
155            ev.mouse_button &= (0xff - RIGHT_BUTTON);
156        }
157    }
158
159    m_pos = ivec2(ev.mouse_move.x, ev.mouse_move.y);
160    m_button = ev.mouse_button;
161
162    // Sort out other kinds of events
163    switch(sdlev.type)
164    {
165    case SDL_QUIT:
166        exit(0);
167        break;
168    case SDL_MOUSEBUTTONUP:
169        switch(sdlev.button.button)
170        {
171        case 4:        // Mouse wheel goes up...
172            ev.key = get_key_binding("b4", 0);
173            ev.type = EV_KEYRELEASE;
174            break;
175        case 5:        // Mouse wheel goes down...
176            ev.key = get_key_binding("b3", 0);
177            ev.type = EV_KEYRELEASE;
178            break;
179        }
180        break;
181    case SDL_MOUSEBUTTONDOWN:
182        switch(sdlev.button.button)
183        {
184        case 4:        // Mouse wheel goes up...
185            ev.key = get_key_binding("b4", 0);
186            ev.type = EV_KEY;
187            break;
188        case 5:        // Mouse wheel goes down...
189            ev.key = get_key_binding("b3", 0);
190            ev.type = EV_KEY;
191            break;
192        }
193        break;
194        case SDL_CONTROLLERBUTTONDOWN:
195        case SDL_CONTROLLERBUTTONUP:
196        {
197            if((sdlev.cbutton.button == SDL_CONTROLLER_BUTTON_RIGHTSHOULDER) ||
198               (sdlev.cbutton.button == SDL_CONTROLLER_BUTTON_LEFTSHOULDER))
199            {
200                // already handled these in controller_to_mouse()
201                break;
202            }
203            printf("Got controller button press\n");
204                   
205            if( sdlev.type == SDL_CONTROLLERBUTTONDOWN )
206            {
207                ev.type = EV_KEY;
208            }
209            else
210            {
211                ev.type = EV_KEYRELEASE;
212            }
213
214            // Default to EV_SPURIOUS
215            ev.key = EV_SPURIOUS;
216                   
217            switch (sdlev.cbutton.button)
218            {
219                case SDL_CONTROLLER_BUTTON_A:
220                    // change weapons
221                    ev.key = JK_INSERT;
222                    break;
223                case SDL_CONTROLLER_BUTTON_X:
224                    // jump
225                    ev.key = JK_UP;
226                    break;
227                case SDL_CONTROLLER_BUTTON_Y:
228                    // activate switch
229                    ev.key = JK_DOWN;
230                    break;
231                case SDL_CONTROLLER_BUTTON_START:
232                    break;
233                case SDL_CONTROLLER_BUTTON_DPAD_LEFT:
234                    // move left
235                    ev.key = JK_LEFT;
236                    break;
237                case SDL_CONTROLLER_BUTTON_DPAD_RIGHT:
238                    // move right
239                    ev.key = JK_RIGHT;
240                    break;
241                case SDL_CONTROLLER_BUTTON_DPAD_UP:
242                    // jump
243                    ev.key = JK_UP;
244                    break;
245                case SDL_CONTROLLER_BUTTON_DPAD_DOWN:
246                    // activate switch
247                    ev.key = JK_DOWN;
248                    break;
249                default:
250                    break;
251            }
252            break;
253        }
254    case SDL_KEYDOWN:
255    case SDL_KEYUP:
256        // Default to EV_SPURIOUS
257        ev.key = EV_SPURIOUS;
258        if(sdlev.type == SDL_KEYDOWN)
259        {
260            ev.type = EV_KEY;
261        }
262        else
263        {
264            ev.type = EV_KEYRELEASE;
265        }
266        switch(sdlev.key.keysym.sym)
267        {
268        case SDLK_DOWN:         ev.key = JK_DOWN; break;
269        case SDLK_UP:           ev.key = JK_UP; break;
270        case SDLK_LEFT:         ev.key = JK_LEFT; break;
271        case SDLK_RIGHT:        ev.key = JK_RIGHT; break;
272        case SDLK_LCTRL:        ev.key = JK_CTRL_L; break;
273        case SDLK_RCTRL:        ev.key = JK_CTRL_R; break;
274        case SDLK_LALT:         ev.key = JK_ALT_L; break;
275        case SDLK_RALT:         ev.key = JK_ALT_R; break;
276        case SDLK_LSHIFT:       ev.key = JK_SHIFT_L; break;
277        case SDLK_RSHIFT:       ev.key = JK_SHIFT_R; break;
278        case SDLK_NUMLOCKCLEAR: ev.key = JK_NUM_LOCK; break;
279        case SDLK_HOME:         ev.key = JK_HOME; break;
280        case SDLK_END:          ev.key = JK_END; break;
281        case SDLK_BACKSPACE:    ev.key = JK_BACKSPACE; break;
282        case SDLK_TAB:          ev.key = JK_TAB; break;
283        case SDLK_RETURN:       ev.key = JK_ENTER; break;
284        case SDLK_SPACE:        ev.key = JK_SPACE; break;
285        case SDLK_CAPSLOCK:     ev.key = JK_CAPS; break;
286        case SDLK_ESCAPE:       ev.key = JK_ESC; break;
287        case SDLK_F1:           ev.key = JK_F1; break;
288        case SDLK_F2:           ev.key = JK_F2; break;
289        case SDLK_F3:           ev.key = JK_F3; break;
290        case SDLK_F4:           ev.key = JK_F4; break;
291        case SDLK_F5:           ev.key = JK_F5; break;
292        case SDLK_F6:           ev.key = JK_F6; break;
293        case SDLK_F7:           ev.key = JK_F7; break;
294        case SDLK_F8:           ev.key = JK_F8; break;
295        case SDLK_F9:           ev.key = JK_F9; break;
296        case SDLK_F10:          ev.key = JK_F10; break;
297        case SDLK_INSERT:       ev.key = JK_INSERT; break;
298        case SDLK_KP_0:         ev.key = JK_INSERT; break;
299        case SDLK_PAGEUP:       ev.key = JK_PAGEUP; break;
300        case SDLK_PAGEDOWN:     ev.key = JK_PAGEDOWN; break;
301        case SDLK_KP_8:         ev.key = JK_UP; break;
302        case SDLK_KP_2:         ev.key = JK_DOWN; break;
303        case SDLK_KP_4:         ev.key = JK_LEFT; break;
304        case SDLK_KP_6:         ev.key = JK_RIGHT; break;
305        case SDLK_F11:
306            // Only handle key down
307            if(ev.type == EV_KEY)
308            {
309                // Toggle fullscreen
310                if(flags.fullscreen)
311                {
312                    flags.fullscreen = 0;
313                    SDL_SetWindowFullscreen(window, 0);
314                    SDL_SetWindowSize(window, flags.xres, flags.yres);
315                }
316                else
317                {
318                    flags.fullscreen = 1;
319                    SDL_SetWindowFullscreen(window, SDL_WINDOW_FULLSCREEN_DESKTOP);
320                }
321            }
322            ev.key = EV_SPURIOUS;
323            break;
324        case SDLK_F12:
325            // Only handle key down
326            if(ev.type == EV_KEY)
327            {
328                // Toggle grab mouse
329                if( SDL_GetWindowGrab(window) == SDL_TRUE )
330                {
331                    the_game->show_help( "Grab Mouse: OFF\n" );
332                    SDL_SetWindowGrab(window, SDL_FALSE);
333                }
334                else
335                {
336                    the_game->show_help( "Grab Mouse: ON\n" );
337                    SDL_SetWindowGrab(window, SDL_TRUE);
338                }
339            }
340            ev.key = EV_SPURIOUS;
341            break;
342        case SDLK_PRINTSCREEN:    // print-screen key
343            // Only handle key down
344            if(ev.type == EV_KEY)
345            {
346                // Grab a screenshot
347                // need to figure this out for SDL2
348                //SDL_SaveBMP(SDL_GetVideoSurface(), "screenshot.bmp");
349                //the_game->show_help("Screenshot saved to: screenshot.bmp.\n");
350            }
351            ev.key = EV_SPURIOUS;
352            break;
353        default:
354            ev.key = (int)sdlev.key.keysym.sym;
355            // Need to handle the case of shift being pressed
356            // There has to be a better way
357            if((sdlev.key.keysym.mod & KMOD_SHIFT) != 0)
358            {
359                if(sdlev.key.keysym.sym >= SDLK_a &&
360                    sdlev.key.keysym.sym <= SDLK_z)
361                {
362                    ev.key -= 32;
363                }
364                else if(sdlev.key.keysym.sym >= SDLK_1 &&
365                         sdlev.key.keysym.sym <= SDLK_5)
366                {
367                    ev.key -= 16;
368                }
369                else
370                {
371                    switch(sdlev.key.keysym.sym)
372                    {
373                    case SDLK_6:
374                        ev.key = SDLK_CARET; break;
375                    case SDLK_7:
376                    case SDLK_9:
377                    case SDLK_0:
378                        ev.key -= 17; break;
379                    case SDLK_8:
380                        ev.key = SDLK_ASTERISK; break;
381                    case SDLK_MINUS:
382                        ev.key = SDLK_UNDERSCORE; break;
383                    case SDLK_EQUALS:
384                        ev.key = SDLK_PLUS; break;
385                    case SDLK_COMMA:
386                        ev.key = SDLK_LESS; break;
387                    case SDLK_PERIOD:
388                        ev.key = SDLK_GREATER; break;
389                    case SDLK_SLASH:
390                        ev.key = SDLK_QUESTION; break;
391                    case SDLK_SEMICOLON:
392                        ev.key = SDLK_COLON; break;
393                    case SDLK_QUOTE:
394                        ev.key = SDLK_QUOTEDBL; break;
395                    default:
396                        break;
397                    }
398                }
399            }
400            break;
401        }
402    }
403}
404
405void controller_to_mouse( Event &ev, SDL_Event *sdl_event )
406{
407    Sint16 lr_axis, ud_axis;
408    int x, y;
409
410    lr_axis = SDL_GameControllerGetAxis(controller, (SDL_GameControllerAxis)2);
411    ud_axis = SDL_GameControllerGetAxis(controller, (SDL_GameControllerAxis)3);
412   
413    lr_axis /= 1024;
414    ud_axis /= -1024; // flip this axis
415
416    // convert to mouse position
417    float theta = 0.0;
418    float cos_theta;
419    float mag = sqrtf((lr_axis * lr_axis) + (ud_axis * ud_axis));
420    float udotv = 1.0 * lr_axis;
421
422    // give a little dead zone
423    if(mag > 0.001)
424    {
425        int radius;
426       
427        // calculate the aim angle in terms of a unit circle
428        cos_theta = udotv / mag;
429        theta = acosf(cos_theta);
430
431        if(ud_axis < 0) theta *= -1.0f;
432
433        // calculate the origin
434        if(the_game->first_view)
435        {
436            x = the_game->first_view->m_focus->x - the_game->first_view->xoff();
437            y = the_game->first_view->m_focus->y - the_game->first_view->yoff();
438
439            y -= 20;
440            radius = 75;
441        }
442        else
443        {
444            x = main_screen->Size().x / 2;
445            y = main_screen->Size().y / 2;
446            radius = 200;
447        }
448
449        x += (int)roundf(cosf(theta) * radius);
450        y += (int)roundf(sinf(theta) * -1.0 * radius);
451
452        if( x > main_screen->Size().x - 1 )
453        {
454            x = main_screen->Size().x - 1;
455        }
456        if( y > main_screen->Size().y - 1 )
457        {
458            y = main_screen->Size().y - 1;
459        }
460
461        ev.mouse_move.x = x;
462        ev.mouse_move.y = y;
463        ev.type = EV_MOUSE_MOVE;
464
465        //printf("right analog stick (%d,%d) theta = %2f\n", lr_axis, ud_axis, theta);
466    }
467   
468    // keep the state between calls
469    static int mouse_button_state = 0;
470
471    // restore previous state
472    ev.mouse_button = mouse_button_state;
473
474    if((sdl_event->type == SDL_CONTROLLERBUTTONDOWN) ||
475       (sdl_event->type == SDL_CONTROLLERBUTTONUP))       
476    {
477        switch (sdl_event->cbutton.button)
478        {
479            case SDL_CONTROLLER_BUTTON_RIGHTSHOULDER:
480                // Left button
481                ev.type = EV_MOUSE_BUTTON;
482                if(sdl_event->type == SDL_CONTROLLERBUTTONDOWN)
483                {
484                    ev.mouse_button |= LEFT_BUTTON;
485                }
486                else
487                {
488                    ev.mouse_button &= ( 0xff - LEFT_BUTTON );
489                }
490                break;
491            case SDL_CONTROLLER_BUTTON_LEFTSHOULDER:
492                // Right button
493                ev.type = EV_MOUSE_BUTTON;
494                if(sdl_event->type == SDL_CONTROLLERBUTTONDOWN)
495                {
496                    ev.mouse_button |= RIGHT_BUTTON;
497                }
498                else
499                {
500                    ev.mouse_button &= ( 0xff - RIGHT_BUTTON );
501                }
502                break;
503            default:
504                break;
505        }
506    }
507   
508    // save the current state
509    mouse_button_state = ev.mouse_button;
510}
Note: See TracBrowser for help on using the repository browser.