]> Shamusworld >> Repos - virtualjaguar/blobdiff - src/gui/profile.cpp
Fixed updated joystick handling, first major stab at gamepad profiles.
[virtualjaguar] / src / gui / profile.cpp
diff --git a/src/gui/profile.cpp b/src/gui/profile.cpp
new file mode 100644 (file)
index 0000000..05d173d
--- /dev/null
@@ -0,0 +1,290 @@
+//
+// profile.cpp - Global profile storage/definition/manipulation
+//
+// by James Hammons
+// (C) 2013 Underground Software
+//
+// JLH = James Hammons <jlhamm@acm.org>
+//
+// Who  When        What
+// ---  ----------  -------------------------------------------------------------
+// JLH  05/01/2013  Created this file
+//
+
+
+#include "profile.h"
+#include <QtGui>
+#include "gamepad.h"
+#include "settings.h"
+
+
+#define MAX_DEVICES  64
+
+
+Profile profile[MAX_PROFILES];
+int controller1Profile;
+int controller2Profile;
+int gamepad1Slot;
+int gamepad2Slot;
+int numberOfProfiles;
+int numberOfDevices;
+char deviceNames[MAX_DEVICES][128];
+
+// This is so that new devices have something reasonable to show for default
+uint32_t defaultMap[21] = {
+       'S', 'X', 'Z', 'C', '-','7', '4', '1', '0', '8', '5', '2', '=', '9', '6',
+       '3', 'L', 'K', 'J', 'O', 'P'
+};
+
+
+void ReadProfiles(QSettings * set)
+{
+       // Assume no profiles, until we read them
+       numberOfProfiles = 0;
+
+       // There is always at least one device present, and it's the keyboard
+       // (hey, we're PC centric here ;-)
+       numberOfDevices = 1;
+       strcpy(deviceNames[0], "Keyboard");
+
+       // Read the rest of the devices (if any)
+       numberOfDevices += set->beginReadArray("devices");
+
+       for(int i=1; i<numberOfDevices; i++)
+       {
+               set->setArrayIndex(i - 1);
+               strcpy(deviceNames[i], set->value("deviceName").toString().toAscii().data());
+//printf("Read device name: %s\n", deviceNames[i]);
+       }
+
+       set->endArray();
+       numberOfProfiles = set->beginReadArray("profiles");
+//printf("Number of profiles: %u\n", numberOfProfiles);
+
+       for(int i=0; i<numberOfProfiles; i++)
+       {
+               set->setArrayIndex(i);
+               profile[i].device = set->value("deviceNum").toInt();
+               strcpy(profile[i].mapName, set->value("mapName").toString().toAscii().data());
+               profile[i].preferredController = set->value("preferredController").toInt();
+
+               for(int j=0; j<21; j++)
+               {
+                       QString string = QString("map%1").arg(j);
+                       profile[i].map[j] = set->value(string).toInt();
+               }
+//printf("Profile #%u: device=%u (%s)\n", i, profile[i].device, deviceNames[profile[i].device]);
+       }
+
+       set->endArray();
+
+//printf("Number of profiles found: %u\n", numberOfProfiles);
+       // Set up a reasonable default if no profiles were found
+       if (numberOfProfiles == 0)
+       {
+//printf("Setting up default profile...\n");
+               numberOfProfiles++;
+               profile[0].device = 0;  // Keyboard is always device #0
+               strcpy(profile[0].mapName, "Default");
+               profile[0].preferredController = CONTROLLER1;
+
+               for(int i=0; i<21; i++)
+                       profile[0].map[i] = defaultMap[i];
+       }
+}
+
+
+void WriteProfiles(QSettings * set)
+{
+#if 0
+       // Don't write anything for now...
+       return;
+#endif
+       // NB: Should only do this if something changed; otherwise, no need to do
+       //     this.
+       set->beginWriteArray("devices");
+
+       for(int i=1; i<numberOfDevices; i++)
+       {
+               set->setArrayIndex(i - 1);
+               set->setValue("deviceName", deviceNames[i]);
+       }
+
+       set->endArray();
+       set->beginWriteArray("profiles");
+
+       for(int i=0; i<numberOfProfiles; i++)
+       {
+               set->setArrayIndex(i);
+               set->setValue("deviceNum", profile[i].device);
+               set->setValue("mapName", profile[i].mapName);
+               set->setValue("preferredController", profile[i].preferredController);
+
+               for(int j=0; j<21; j++)
+               {
+                       QString string = QString("map%1").arg(j);
+                       set->setValue(string, profile[i].map[j]);
+               }
+       }
+
+       set->endArray();
+}
+
+
+int FindDeviceNumberForName(const char * name)
+{
+       for(int i=0; i<numberOfDevices; i++)
+       {
+               if (strcmp(deviceNames[i], name) == 0)
+                       return i;
+       }
+
+       if (numberOfDevices == MAX_DEVICES)
+               return -1;
+
+       // If the device wasn't found, it must be new; so add it to the list.
+       int deviceNum = numberOfDevices;
+       deviceNames[deviceNum][127] = 0;
+       strncpy(deviceNames[deviceNum], name, 127);
+       numberOfDevices++;
+
+       return deviceNum;
+}
+
+
+int FindMappingsForDevice(int deviceNum, QComboBox * combo)
+{
+       int found = 0;
+
+       for(int i=0; i<numberOfProfiles; i++)
+       {
+               if (profile[i].device == -1)
+                       continue;
+
+               if (profile[i].device == deviceNum)
+               {
+                       combo->addItem(profile[i].mapName, i);
+                       found++;
+               }
+       }
+
+       // If no mappings were found, create a default one for it
+       if (found == 0)
+       {
+               profile[numberOfProfiles].device = deviceNum;
+               strcpy(profile[numberOfProfiles].mapName, "Default");
+               profile[numberOfProfiles].preferredController = CONTROLLER1;
+
+               for(int i=0; i<21; i++)
+                       profile[numberOfProfiles].map[i] = defaultMap[i];
+
+               combo->addItem(profile[numberOfProfiles].mapName, numberOfProfiles);
+               numberOfProfiles++;
+               found++;
+       }
+
+       return found;
+}
+
+
+bool ConnectProfileToController(int profileNum, int controllerNum)
+{
+       if (profile[profileNum].device == -1)
+               return false;
+
+       if (controllerNum < 0 || controllerNum > 2)
+               return false;
+
+       uint32_t * dest = (controllerNum == 0 ? &vjs.p1KeyBindings[0] : &vjs.p2KeyBindings[0]);
+
+       for(int i=0; i<21; i++)
+               dest[i] = profile[profileNum].map[i];
+
+printf("Successfully mapped device '%s' (%s) to controller #%u...\n", deviceNames[profile[profileNum].device], profile[profileNum].mapName, controllerNum);
+       return true;
+}
+
+
+//
+// This is a pretty crappy way of doing autodetection. What it does is scan for
+// keyboard profiles first, then look for plugged in gamepads next. If more
+// than one plugged in gamepad matches a preferred controller slot, the last
+// one found is chosen.
+//
+// There has to be a better way to do this, I just can't think of what it
+// should be ATM... :-P
+//
+/*
+Also, there is a problem with this approach and having multiple devices
+that are the same. Currently, if two of the same device are plugged in
+and the profile is set to both controllers, it will broadcast buttons
+pressed from either gamepad, no matter who is pressing them. This is
+BAD(tm). [Not true, but there's a different problem described under 'How to
+solve?', so GOOD(tm).]
+
+Also, the gamepad logic doesn't distinguish inputs by controller, it just
+grabs them all regardless. This is also BAD(tm). [Actually, it doesn't. It
+properly segregates the inputs. So this is GOOD(tm).]
+
+How to solve?
+
+Seems there's yet ANOTHER dimension to all this: The physical gamepads
+plugged into their ports. Now the device # can map these fine if they're
+different, but we still run into problems with the handling in the MainWin
+because it's hardwired to take pad 0 in slot 0 and pad 1 in slot 1. If you have
+them configured other than this, you won't get anything. So we need to also
+map the physical devices to their respective slots.
+*/
+void AutoConnectProfiles(void)
+{
+       int controller1Profile = -1;
+       int controller2Profile = -1;
+
+       // Nothing plugged in, we fall back to the default keyboard device profiles
+//     if (Gamepad::numJoysticks == 0)
+       {
+// Check for Keyboard device first, if anything else is plugged in it will
+// default to it instead
+               for(int i=0; i<numberOfProfiles; i++)
+               {
+                       // Skip profile if it's not Keyboard device
+                       if (profile[i].device != 0)
+                               continue;
+
+                       if (profile[i].preferredController & CONTROLLER1)
+                               controller1Profile = i;
+
+                       if (profile[i].preferredController & CONTROLLER2)
+                               controller2Profile = i;
+               }
+       }
+//     else
+       {
+//printf("Number of gamepads found: %u\n", Gamepad::numJoysticks);
+               for(int i=0; i<Gamepad::numJoysticks; i++)
+               {
+                       int deviceNum = FindDeviceNumberForName(Gamepad::GetJoystickName(i));
+//printf("Attempting to find valid gamepad profile. Device=%u\n", deviceNum);
+
+                       for(int j=0; j<numberOfProfiles; j++)
+                       {
+                               // Skip profile if it's not discovered device
+                               if (profile[j].device != deviceNum)
+                                       continue;
+
+                               if (profile[j].preferredController & CONTROLLER1)
+                                       controller1Profile = j;
+
+                               if (profile[j].preferredController & CONTROLLER2)
+                                       controller2Profile = j;
+                       }
+               }
+       }
+
+       if (controller1Profile != -1)
+               ConnectProfileToController(controller1Profile, 0);
+
+       if (controller2Profile != -1)
+               ConnectProfileToController(controller2Profile, 1);
+}
+