1 #include <iostream>
2 #include <string>
3
4 #include "Common/File/FileUtil.h"
5 #include "Common/File/VFS/VFS.h"
6 #include "Common/StringUtils.h"
7 #include "Common/System/NativeApp.h"
8 #include "Common/System/System.h"
9
10 #include "Core/Config.h"
11 #include "SDL/SDLJoystick.h"
12
13 using namespace std;
14
SDLJoystickEventHandlerWrapper(void * userdata,SDL_Event * event)15 static int SDLJoystickEventHandlerWrapper(void* userdata, SDL_Event* event)
16 {
17 static_cast<SDLJoystick *>(userdata)->ProcessInput(*event);
18 return 0;
19 }
20
SDLJoystick(bool init_SDL)21 SDLJoystick::SDLJoystick(bool init_SDL ) : registeredAsEventHandler(false) {
22 SDL_SetHint(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS, "1");
23 if (init_SDL) {
24 SDL_Init(SDL_INIT_JOYSTICK | SDL_INIT_VIDEO | SDL_INIT_GAMECONTROLLER);
25 }
26
27 const char *dbPath = "gamecontrollerdb.txt";
28 cout << "loading control pad mappings from " << dbPath << ": ";
29
30 size_t size;
31 u8 *mappingData = VFSReadFile(dbPath, &size);
32 if (mappingData) {
33 SDL_RWops *rw = SDL_RWFromConstMem(mappingData, size);
34 // 1 to free the rw after use
35 if (SDL_GameControllerAddMappingsFromRW(rw, 1) == -1) {
36 cout << "Failed to read mapping data - corrupt?" << endl;
37 }
38 delete[] mappingData;
39 } else {
40 cout << "gamecontrollerdb.txt missing" << endl;
41 }
42 cout << "SUCCESS!" << endl;
43 setUpControllers();
44 }
45
setUpControllers()46 void SDLJoystick::setUpControllers() {
47 int numjoys = SDL_NumJoysticks();
48 for (int i = 0; i < numjoys; i++) {
49 setUpController(i);
50 }
51 if (controllers.size() > 0) {
52 cout << "pad 1 has been assigned to control pad: " << SDL_GameControllerName(controllers.front()) << endl;
53 }
54 }
55
setUpController(int deviceIndex)56 void SDLJoystick::setUpController(int deviceIndex) {
57 if (!SDL_IsGameController(deviceIndex)) {
58 cout << "Control pad device " << deviceIndex << " not supported by SDL game controller database, attempting to create default mapping..." << endl;
59 int cbGUID = 33;
60 char pszGUID[cbGUID];
61 SDL_Joystick* joystick = SDL_JoystickOpen(deviceIndex);
62 if (joystick) {
63 SDL_JoystickGetGUIDString(SDL_JoystickGetGUID(joystick), pszGUID, cbGUID);
64 // create default mapping - this is the PS3 dual shock mapping
65 const std::string safeName = ReplaceAll(SDL_JoystickName(joystick), ",", "");
66 std::string mapping = std::string(pszGUID) + "," + safeName + ",x:b3,a:b0,b:b1,y:b2,back:b8,guide:b10,start:b9,dpleft:b15,dpdown:b14,dpright:b16,dpup:b13,leftshoulder:b4,lefttrigger:a2,rightshoulder:b6,rightshoulder:b5,righttrigger:a5,leftstick:b7,leftstick:b11,rightstick:b12,leftx:a0,lefty:a1,rightx:a3,righty:a4";
67 if (SDL_GameControllerAddMapping(mapping.c_str()) == 1){
68 cout << "Added default mapping ok" << endl;
69 } else {
70 cout << "Failed to add default mapping" << endl;
71 }
72 SDL_JoystickClose(joystick);
73 } else {
74 cout << "Failed to get joystick identifier. Read-only device? Control pad device " + std::to_string(deviceIndex) << endl;
75 }
76 }
77 SDL_GameController *controller = SDL_GameControllerOpen(deviceIndex);
78 if (controller) {
79 if (SDL_GameControllerGetAttached(controller)) {
80 controllers.push_back(controller);
81 controllerDeviceMap[SDL_JoystickInstanceID(SDL_GameControllerGetJoystick(controller))] = deviceIndex;
82 cout << "found control pad: " << SDL_GameControllerName(controller) << ", loading mapping: ";
83 auto mapping = SDL_GameControllerMapping(controller);
84 if (mapping == NULL) {
85 //cout << "FAILED" << endl;
86 cout << "Could not find mapping in SDL2 controller database" << endl;
87 } else {
88 cout << "SUCCESS, mapping is:" << endl << mapping << endl;
89 }
90 } else {
91 SDL_GameControllerClose(controller);
92 }
93 }
94 }
95
~SDLJoystick()96 SDLJoystick::~SDLJoystick() {
97 if (registeredAsEventHandler) {
98 SDL_DelEventWatch(SDLJoystickEventHandlerWrapper, this);
99 }
100 for (auto & controller : controllers) {
101 SDL_GameControllerClose(controller);
102 }
103 }
104
registerEventHandler()105 void SDLJoystick::registerEventHandler() {
106 SDL_AddEventWatch(SDLJoystickEventHandlerWrapper, this);
107 registeredAsEventHandler = true;
108 }
109
getKeycodeForButton(SDL_GameControllerButton button)110 keycode_t SDLJoystick::getKeycodeForButton(SDL_GameControllerButton button) {
111 switch (button) {
112 case SDL_CONTROLLER_BUTTON_DPAD_UP:
113 return NKCODE_DPAD_UP;
114 case SDL_CONTROLLER_BUTTON_DPAD_DOWN:
115 return NKCODE_DPAD_DOWN;
116 case SDL_CONTROLLER_BUTTON_DPAD_LEFT:
117 return NKCODE_DPAD_LEFT;
118 case SDL_CONTROLLER_BUTTON_DPAD_RIGHT:
119 return NKCODE_DPAD_RIGHT;
120 case SDL_CONTROLLER_BUTTON_A:
121 return NKCODE_BUTTON_2;
122 case SDL_CONTROLLER_BUTTON_B:
123 return NKCODE_BUTTON_3;
124 case SDL_CONTROLLER_BUTTON_X:
125 return NKCODE_BUTTON_4;
126 case SDL_CONTROLLER_BUTTON_Y:
127 return NKCODE_BUTTON_1;
128 case SDL_CONTROLLER_BUTTON_RIGHTSHOULDER:
129 return NKCODE_BUTTON_5;
130 case SDL_CONTROLLER_BUTTON_LEFTSHOULDER:
131 return NKCODE_BUTTON_6;
132 case SDL_CONTROLLER_BUTTON_START:
133 return NKCODE_BUTTON_10;
134 case SDL_CONTROLLER_BUTTON_BACK:
135 return NKCODE_BUTTON_9; // select button
136 case SDL_CONTROLLER_BUTTON_GUIDE:
137 return NKCODE_BACK; // pause menu
138 case SDL_CONTROLLER_BUTTON_LEFTSTICK:
139 return NKCODE_BUTTON_THUMBL;
140 case SDL_CONTROLLER_BUTTON_RIGHTSTICK:
141 return NKCODE_BUTTON_THUMBR;
142 case SDL_CONTROLLER_BUTTON_INVALID:
143 default:
144 return NKCODE_UNKNOWN;
145 }
146 }
147
ProcessInput(SDL_Event & event)148 void SDLJoystick::ProcessInput(SDL_Event &event){
149 switch (event.type) {
150 case SDL_CONTROLLERBUTTONDOWN:
151 if (event.cbutton.state == SDL_PRESSED) {
152 auto code = getKeycodeForButton((SDL_GameControllerButton)event.cbutton.button);
153 if (code != NKCODE_UNKNOWN) {
154 KeyInput key;
155 key.flags = KEY_DOWN;
156 key.keyCode = code;
157 key.deviceId = DEVICE_ID_PAD_0 + getDeviceIndex(event.cbutton.which);
158 NativeKey(key);
159 }
160 }
161 break;
162 case SDL_CONTROLLERBUTTONUP:
163 if (event.cbutton.state == SDL_RELEASED) {
164 auto code = getKeycodeForButton((SDL_GameControllerButton)event.cbutton.button);
165 if (code != NKCODE_UNKNOWN) {
166 KeyInput key;
167 key.flags = KEY_UP;
168 key.keyCode = code;
169 key.deviceId = DEVICE_ID_PAD_0 + getDeviceIndex(event.cbutton.which);
170 NativeKey(key);
171 }
172 }
173 break;
174 case SDL_CONTROLLERAXISMOTION:
175 AxisInput axis;
176 axis.axisId = event.caxis.axis;
177 axis.value = event.caxis.value / 32767.0f;
178 if (axis.value > 1.0f) axis.value = 1.0f;
179 if (axis.value < -1.0f) axis.value = -1.0f;
180 axis.deviceId = DEVICE_ID_PAD_0 + getDeviceIndex(event.caxis.which);
181 axis.flags = 0;
182 NativeAxis(axis);
183 break;
184 case SDL_CONTROLLERDEVICEREMOVED:
185 // for removal events, "which" is the instance ID for SDL_CONTROLLERDEVICEREMOVED
186 for (auto it = controllers.begin(); it != controllers.end(); ++it) {
187 if (SDL_JoystickInstanceID(SDL_GameControllerGetJoystick(*it)) == event.cdevice.which) {
188 SDL_GameControllerClose(*it);
189 controllers.erase(it);
190 break;
191 }
192 }
193 break;
194 case SDL_CONTROLLERDEVICEADDED:
195 // for add events, "which" is the device index!
196 int prevNumControllers = controllers.size();
197 setUpController(event.cdevice.which);
198 if (prevNumControllers == 0 && controllers.size() > 0) {
199 cout << "pad 1 has been assigned to control pad: " << SDL_GameControllerName(controllers.front()) << endl;
200 }
201 break;
202 }
203 }
204
getDeviceIndex(int instanceId)205 int SDLJoystick::getDeviceIndex(int instanceId) {
206 auto it = controllerDeviceMap.find(instanceId);
207 if (it == controllerDeviceMap.end()) {
208 // could not find device
209 return -1;
210 }
211 return it->second;
212 }
213