SuperTuxKart
sdl_controller.hpp
1 // SuperTuxKart - a fun racing game with go-kart
2 // Copyright (C) 2020 SuperTuxKart-Team
3 //
4 // This program is free software; you can redistribute it and/or
5 // modify it under the terms of the GNU General Public License
6 // as published by the Free Software Foundation; either version 3
7 // of the License, or (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with this program; if not, write to the Free Software
16 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17 
18 #ifndef HEADER_SDL_CONTROLLER_HPP
19 #define HEADER_SDL_CONTROLLER_HPP
20 
21 #ifndef SERVER_ONLY
22 
23 #include <SDL_events.h>
24 #include <SDL_gamecontroller.h>
25 #include <SDL_joystick.h>
26 #include <IEventReceiver.h>
27 #include <bitset>
28 #include "utils/types.hpp"
29 
30 #include <SDL_version.h>
31 #include <SDL_haptic.h>
32 
33 class GamePadDevice;
34 
36 {
37 private:
38  SDL_GameController* m_game_controller;
39 
40  SDL_Joystick* m_joystick;
41 
42  GamePadDevice* m_gamepad;
43 
44  SDL_Haptic* m_haptic;
45  int m_auto_center;
46 
47  int m_buttons;
48 
49  int m_axes;
50 
51  int m_hats;
52 
53  SDL_JoystickID m_id;
54 
55  irr::SEvent m_irr_event;
56 
57  int16_t m_prev_axes[irr::SEvent::SJoystickEvent::NUMBER_OF_AXES];
58 
59  uint64_t m_last_power_level_time;
60 #ifdef ANDROID
61  void handleDirectScanCode(const SDL_Event& event);
62 #endif
63 
64  void updateAutoCenter(int state);
65 public:
66  // ------------------------------------------------------------------------
67  SDLController(int device_id);
68  // ------------------------------------------------------------------------
69  ~SDLController();
70  // ------------------------------------------------------------------------
71  const irr::SEvent& getEvent() const { return m_irr_event; }
72  // ------------------------------------------------------------------------
73  SDL_JoystickID getInstanceID() const { return m_id; }
74  // ------------------------------------------------------------------------
75  void handleAxisInputSense(const SDL_Event& event);
76  // ------------------------------------------------------------------------
77  bool handleAxis(const SDL_Event& event)
78  {
79  int axis_idx = event.jaxis.axis;
80  if (axis_idx > m_axes)
81  return false;
82  m_irr_event.JoystickEvent.Axis[axis_idx] = event.jaxis.value;
83  m_prev_axes[axis_idx] = event.jaxis.value;
84  uint32_t value = 1 << axis_idx;
85  m_irr_event.JoystickEvent.AxisChanged = value;
86  return true;
87  } // handleAxis
88  // ------------------------------------------------------------------------
89  bool handleHat(const SDL_Event& event)
90  {
91  if (event.jhat.hat > m_hats)
92  return false;
93  std::bitset<4> new_hat_status;
94  // Up, right, down and left (4 buttons)
95  switch (event.jhat.value)
96  {
97  case SDL_HAT_UP:
98  new_hat_status[0] = true;
99  break;
100  case SDL_HAT_RIGHTUP:
101  new_hat_status[0] = true;
102  new_hat_status[1] = true;
103  break;
104  case SDL_HAT_RIGHT:
105  new_hat_status[1] = true;
106  break;
107  case SDL_HAT_RIGHTDOWN:
108  new_hat_status[1] = true;
109  new_hat_status[2] = true;
110  break;
111  case SDL_HAT_DOWN:
112  new_hat_status[2] = true;
113  break;
114  case SDL_HAT_LEFTDOWN:
115  new_hat_status[2] = true;
116  new_hat_status[3] = true;
117  break;
118  case SDL_HAT_LEFT:
119  new_hat_status[3] = true;
120  break;
121  case SDL_HAT_LEFTUP:
122  new_hat_status[3] = true;
123  new_hat_status[0] = true;
124  break;
125  case SDL_HAT_CENTERED:
126  default:
127  break;
128  }
129  int hat_start = m_buttons - (m_hats * 4) + (event.jhat.hat * 4);
130  std::bitset<irr::SEvent::SJoystickEvent::NUMBER_OF_BUTTONS> states
131  (m_irr_event.JoystickEvent.ButtonStates);
132  for (unsigned i = 0; i < 4; i++)
133  {
134  int hat_button_id = i + hat_start;
135  states[hat_button_id] = new_hat_status[i];
136  }
137  m_irr_event.JoystickEvent.ButtonStates = (irr::u32)states.to_ulong();
138  m_irr_event.JoystickEvent.AxisChanged = 0;
139  return true;
140  } // handleHat
141  // ------------------------------------------------------------------------
142  bool handleButton(const SDL_Event& event)
143  {
144  if (event.jbutton.button > m_buttons)
145  {
146 #ifdef ANDROID
147  handleDirectScanCode(event);
148 #endif
149  return false;
150  }
151  bool pressed = event.jbutton.state == SDL_PRESSED;
152  std::bitset<irr::SEvent::SJoystickEvent::NUMBER_OF_BUTTONS> states
153  (m_irr_event.JoystickEvent.ButtonStates);
154  states[event.jbutton.button] = pressed;
155  m_irr_event.JoystickEvent.ButtonStates = (irr::u32)states.to_ulong();
156  m_irr_event.JoystickEvent.AxisChanged = 0;
157  return true;
158  } // handleButton
159  // ------------------------------------------------------------------------
160  SDL_GameController* getGameController() const { return m_game_controller; }
161  // ------------------------------------------------------------------------
162  void checkPowerLevel();
163  // ------------------------------------------------------------------------
164  void doRumble(float strength_low, float strength_high, uint32_t duration_ms);
165  GamePadDevice* getGamePadDevice() const { return m_gamepad; }
166 };
167 
168 #endif
169 
170 #endif
specialisation of Inputdevice for gamepad type devices
Definition: gamepad_device.hpp:33
Definition: sdl_controller.hpp:36
void handleAxisInputSense(const SDL_Event &event)
SDL only sends event when axis moves, so we need to send previously saved event for correct input sen...
Definition: sdl_controller.cpp:229
Declares the general types that are used by the network.