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