2 // profile.cpp - Global profile storage/definition/manipulation
5 // (C) 2013 Underground Software
7 // JLH = James Hammons <jlhamm@acm.org>
10 // --- ---------- -------------------------------------------------------------
11 // JLH 05/01/2013 Created this file
21 #define MAX_DEVICES 64
24 Profile profile[MAX_PROFILES];
25 int controller1Profile;
26 int controller2Profile;
31 char deviceNames[MAX_DEVICES][128];
33 // This is so that new devices have something reasonable to show for default
34 uint32_t defaultMap[21] = {
35 'S', 'X', 'Z', 'C', '-','7', '4', '1', '0', '8', '5', '2', '=', '9', '6',
36 '3', 'L', 'K', 'J', 'O', 'P'
40 void ReadProfiles(QSettings * set)
42 // Assume no profiles, until we read them
45 // There is always at least one device present, and it's the keyboard
46 // (hey, we're PC centric here ;-)
48 strcpy(deviceNames[0], "Keyboard");
50 // Read the rest of the devices (if any)
51 numberOfDevices += set->beginReadArray("devices");
53 for(int i=1; i<numberOfDevices; i++)
55 set->setArrayIndex(i - 1);
56 strcpy(deviceNames[i], set->value("deviceName").toString().toAscii().data());
57 //printf("Read device name: %s\n", deviceNames[i]);
61 numberOfProfiles = set->beginReadArray("profiles");
62 //printf("Number of profiles: %u\n", numberOfProfiles);
64 for(int i=0; i<numberOfProfiles; i++)
66 set->setArrayIndex(i);
67 profile[i].device = set->value("deviceNum").toInt();
68 strcpy(profile[i].mapName, set->value("mapName").toString().toAscii().data());
69 profile[i].preferredController = set->value("preferredController").toInt();
71 for(int j=0; j<21; j++)
73 QString string = QString("map%1").arg(j);
74 profile[i].map[j] = set->value(string).toInt();
76 //printf("Profile #%u: device=%u (%s)\n", i, profile[i].device, deviceNames[profile[i].device]);
81 //printf("Number of profiles found: %u\n", numberOfProfiles);
82 // Set up a reasonable default if no profiles were found
83 if (numberOfProfiles == 0)
85 //printf("Setting up default profile...\n");
87 profile[0].device = 0; // Keyboard is always device #0
88 strcpy(profile[0].mapName, "Default");
89 profile[0].preferredController = CONTROLLER1;
91 for(int i=0; i<21; i++)
92 profile[0].map[i] = defaultMap[i];
97 void WriteProfiles(QSettings * set)
100 // Don't write anything for now...
103 // NB: Should only do this if something changed; otherwise, no need to do
105 set->beginWriteArray("devices");
107 for(int i=1; i<numberOfDevices; i++)
109 set->setArrayIndex(i - 1);
110 set->setValue("deviceName", deviceNames[i]);
114 set->beginWriteArray("profiles");
116 for(int i=0; i<numberOfProfiles; i++)
118 set->setArrayIndex(i);
119 set->setValue("deviceNum", profile[i].device);
120 set->setValue("mapName", profile[i].mapName);
121 set->setValue("preferredController", profile[i].preferredController);
123 for(int j=0; j<21; j++)
125 QString string = QString("map%1").arg(j);
126 set->setValue(string, profile[i].map[j]);
134 int FindDeviceNumberForName(const char * name)
136 for(int i=0; i<numberOfDevices; i++)
138 if (strcmp(deviceNames[i], name) == 0)
142 if (numberOfDevices == MAX_DEVICES)
145 // If the device wasn't found, it must be new; so add it to the list.
146 int deviceNum = numberOfDevices;
147 deviceNames[deviceNum][127] = 0;
148 strncpy(deviceNames[deviceNum], name, 127);
155 int FindMappingsForDevice(int deviceNum, QComboBox * combo)
159 for(int i=0; i<numberOfProfiles; i++)
161 if (profile[i].device == -1)
164 if (profile[i].device == deviceNum)
166 combo->addItem(profile[i].mapName, i);
171 // If no mappings were found, create a default one for it
174 profile[numberOfProfiles].device = deviceNum;
175 strcpy(profile[numberOfProfiles].mapName, "Default");
176 profile[numberOfProfiles].preferredController = CONTROLLER1;
178 for(int i=0; i<21; i++)
179 profile[numberOfProfiles].map[i] = defaultMap[i];
181 combo->addItem(profile[numberOfProfiles].mapName, numberOfProfiles);
190 bool ConnectProfileToController(int profileNum, int controllerNum)
192 if (profile[profileNum].device == -1)
195 if (controllerNum < 0 || controllerNum > 2)
198 uint32_t * dest = (controllerNum == 0 ? &vjs.p1KeyBindings[0] : &vjs.p2KeyBindings[0]);
200 for(int i=0; i<21; i++)
201 dest[i] = profile[profileNum].map[i];
203 printf("Successfully mapped device '%s' (%s) to controller #%u...\n", deviceNames[profile[profileNum].device], profile[profileNum].mapName, controllerNum);
209 // This is a pretty crappy way of doing autodetection. What it does is scan for
210 // keyboard profiles first, then look for plugged in gamepads next. If more
211 // than one plugged in gamepad matches a preferred controller slot, the last
212 // one found is chosen.
214 // There has to be a better way to do this, I just can't think of what it
215 // should be ATM... :-P
218 Also, there is a problem with this approach and having multiple devices
219 that are the same. Currently, if two of the same device are plugged in
220 and the profile is set to both controllers, it will broadcast buttons
221 pressed from either gamepad, no matter who is pressing them. This is
222 BAD(tm). [Not true, but there's a different problem described under 'How to
223 solve?', so GOOD(tm).]
225 Also, the gamepad logic doesn't distinguish inputs by controller, it just
226 grabs them all regardless. This is also BAD(tm). [Actually, it doesn't. It
227 properly segregates the inputs. So this is GOOD(tm).]
231 Seems there's yet ANOTHER dimension to all this: The physical gamepads
232 plugged into their ports. Now the device # can map these fine if they're
233 different, but we still run into problems with the handling in the MainWin
234 because it's hardwired to take pad 0 in slot 0 and pad 1 in slot 1. If you have
235 them configured other than this, you won't get anything. So we need to also
236 map the physical devices to their respective slots.
238 void AutoConnectProfiles(void)
240 int controller1Profile = -1;
241 int controller2Profile = -1;
243 // Nothing plugged in, we fall back to the default keyboard device profiles
244 // if (Gamepad::numJoysticks == 0)
246 // Check for Keyboard device first, if anything else is plugged in it will
247 // default to it instead
248 for(int i=0; i<numberOfProfiles; i++)
250 // Skip profile if it's not Keyboard device
251 if (profile[i].device != 0)
254 if (profile[i].preferredController & CONTROLLER1)
255 controller1Profile = i;
257 if (profile[i].preferredController & CONTROLLER2)
258 controller2Profile = i;
263 //printf("Number of gamepads found: %u\n", Gamepad::numJoysticks);
264 for(int i=0; i<Gamepad::numJoysticks; i++)
266 int deviceNum = FindDeviceNumberForName(Gamepad::GetJoystickName(i));
267 //printf("Attempting to find valid gamepad profile. Device=%u\n", deviceNum);
269 for(int j=0; j<numberOfProfiles; j++)
271 // Skip profile if it's not discovered device
272 if (profile[j].device != deviceNum)
275 if (profile[j].preferredController & CONTROLLER1)
276 controller1Profile = j;
278 if (profile[j].preferredController & CONTROLLER2)
279 controller2Profile = j;
284 if (controller1Profile != -1)
285 ConnectProfileToController(controller1Profile, 0);
287 if (controller2Profile != -1)
288 ConnectProfileToController(controller2Profile, 1);