X-Git-Url: http://shamusworld.gotdns.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Fgui%2Fprofile.cpp;h=5f1ca13035be6d23b1e2202ff99b83ff10f1bb7a;hb=d207b11e613703aff7d00191c4595b7359f29700;hp=71e694666f1567bab13d0fefb61a95b24b2ec5d5;hpb=d1e404e2f488610a99f844783dca15a7525c3813;p=virtualjaguar diff --git a/src/gui/profile.cpp b/src/gui/profile.cpp index 71e6946..5f1ca13 100644 --- a/src/gui/profile.cpp +++ b/src/gui/profile.cpp @@ -7,29 +7,49 @@ // JLH = James Hammons // // Who When What -// --- ---------- ------------------------------------------------------------- +// --- ---------- ------------------------------------------------------------ // JLH 05/01/2013 Created this file +// JLH 10/02/2014 Finally fixed stuff so it works the way it should +// +// This is a profile database with two parts: One, a list of devices, and two, +// a list of profiles each containing a pointer to the device list, and map +// name, a preferred slot #, and a key/button map. All the heavy lifting (incl. +// autoconnection of devices to profiles to slots) is done here. +// +// Basically, how this works is that we connect the device the user plugs into +// the computer to a profile in the database to a slot in the virtual Jaguar. +// Hopefully the configuration that the user gives us is sane enough for us to +// figure out how to do the right thing! By default, there is always a keyboard +// device plugged in; any other device that gets plugged in and wants to be in +// slot #0 can override it. This is so there is always a sane configuration if +// nothing is plugged in. +// +// Devices go into the database when the user plugs them in and runs VJ, and +// subsequently does anything to alter any of the existing profiles. Once a +// device has been seen, it can't be unseen! // - #include "profile.h" -#include +#include #include "gamepad.h" #include "log.h" #include "settings.h" +//#define DEBUG_PROFILES #define MAX_DEVICES 64 Profile profile[MAX_PROFILES]; +Profile profileBackup[MAX_PROFILES]; int controller1Profile; int controller2Profile; -int gamepad1Slot; -int gamepad2Slot; +int gamepadIDSlot1; +int gamepadIDSlot2; int numberOfProfiles; int numberOfDevices; char deviceNames[MAX_DEVICES][128]; +static int numberOfProfilesSave; // This is so that new devices have something reasonable to show for default uint32_t defaultMap[21] = { @@ -37,11 +57,30 @@ uint32_t defaultMap[21] = { '3', 'L', 'K', 'J', 'O', 'P' }; + // Function Prototypes -int ConnectProfileToDevice(int deviceNum); +int ConnectProfileToDevice(int deviceNum, int gamepadID = -1); int FindProfileForDevice(int deviceNum, int preferred, int * found); +// +// These two functions are mainly to support the controller configuration GUI. +// Could just as easily go there as well (and be better placed there). +// +void SaveProfiles(void) +{ + numberOfProfilesSave = numberOfProfiles; + memcpy(&profileBackup, &profile, sizeof(Profile) * MAX_PROFILES); +} + + +void RestoreProfiles(void) +{ + memcpy(&profile, &profileBackup, sizeof(Profile) * MAX_PROFILES); + numberOfProfiles = numberOfProfilesSave; +} + + void ReadProfiles(QSettings * set) { // Assume no profiles, until we read them @@ -58,40 +97,50 @@ void ReadProfiles(QSettings * set) for(int i=1; isetArrayIndex(i - 1); - strcpy(deviceNames[i], set->value("deviceName").toString().toAscii().data()); -//printf("Read device name: %s\n", deviceNames[i]); + strcpy(deviceNames[i], set->value("deviceName").toString().toUtf8().data()); +#ifdef DEBUG_PROFILES +printf("Read device name: %s\n", deviceNames[i]); +#endif } set->endArray(); numberOfProfiles = set->beginReadArray("profiles"); -//printf("Number of profiles: %u\n", numberOfProfiles); +#ifdef DEBUG_PROFILES +printf("Number of profiles: %u\n", numberOfProfiles); +#endif for(int i=0; isetArrayIndex(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(); + strcpy(profile[i].mapName, set->value("mapName").toString().toUtf8().data()); + profile[i].preferredSlot = set->value("preferredSlot").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]); +#ifdef DEBUG_PROFILES +printf("Profile #%u: device=%u (%s)\n", i, profile[i].device, deviceNames[profile[i].device]); +#endif } set->endArray(); -//printf("Number of profiles found: %u\n", numberOfProfiles); +#ifdef DEBUG_PROFILES +printf("Number of profiles found: %u\n", numberOfProfiles); +#endif // Set up a reasonable default if no profiles were found if (numberOfProfiles == 0) { -//printf("Setting up default profile...\n"); +#ifdef DEBUG_PROFILES +printf("Setting up default profile...\n"); +#endif numberOfProfiles++; profile[0].device = 0; // Keyboard is always device #0 strcpy(profile[0].mapName, "Default"); - profile[0].preferredController = CONTROLLER1; + profile[0].preferredSlot = CONTROLLER1; for(int i=0; i<21; i++) profile[0].map[i] = defaultMap[i]; @@ -123,7 +172,7 @@ void WriteProfiles(QSettings * set) set->setArrayIndex(i); set->setValue("deviceNum", profile[i].device); set->setValue("mapName", profile[i].mapName); - set->setValue("preferredController", profile[i].preferredController); + set->setValue("preferredSlot", profile[i].preferredSlot); for(int j=0; j<21; j++) { @@ -172,12 +221,22 @@ int FindDeviceNumberForName(const char * name) for(int i=0; iaddItem(QString("Keyboard::%1").arg(profile[j].mapName), j); found++; @@ -246,7 +306,7 @@ int FindUsableProfiles(QComboBox * combo) for(int j=0; jaddItem(QString("%1::%2").arg(Gamepad::GetJoystickName(i)).arg(profile[j].mapName), j); found++; @@ -260,6 +320,10 @@ int FindUsableProfiles(QComboBox * combo) bool ConnectProfileToController(int profileNum, int controllerNum) { + // Sanity checks... + if (profileNum < 0) + return false; + if (profile[profileNum].device == -1) return false; @@ -276,141 +340,150 @@ bool ConnectProfileToController(int profileNum, int controllerNum) } -// -// 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 -// /* -Here's the rules: If preferred Jaguar controller is not checked, the profile is -skipped. If one or the other is checked, it's put into that slot. If *both* are -checked, it will take over any slot that isn't claimed by another gamepad. If -there are ties, present it to the user *once* and ask them which gamepad should -be #1; don't ask again unless a), they change the profiles and b), the -situation warrants it. - -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. - - -Steps: - -1) Make a list of all devices attached to the system. - -2) Make a list of all profiles belonging to those devices, as long as they have - one or more Jaguar controllers that are "mapped to". - -3) See if there are any conflicts. If there are, see if the user has already - been asked to resolve and chosen a resolution; otherwise, ask the user to - resolve. - - a) Loop through all found profiles. If they are set to a single controller, - set it in the appropriate list (one list for controller 1, another for - controller 2). - - b) Loop through all found profiles. If they are set to both controllers, - ... (first stab at it:) - Check for list #1. If nothing there, assign it to list #1. - Else, check for List #2. If nothing there, assign to list #2. - [But the wording of it implies that it will assign it to both. - Does that mean we should make another combobox will all the possible - combinations laid out? Probably. Not many people will understand that - checking both means "assign to either one that's free".] - -4) Connect profiles to controllers, and set gamepad slots (for the MainWin - handler). - +One more stab at this... + + - Connect keyboard to slot #0. + - Loop thru all connected devices. For each device: + - Grab all profiles for the device. For each profile: + - Check to see what its preferred device is. + - If PD is slot #0, see if slot is already taken (gamepadIDSlot1 != -1). + If not taken, take it; otherwise put in list to tell user to solve the + conflict for us. + - If the slot is already taken and *it's the same device* as the one + we're looking at, set it in slot #1. + - If PD is slot #1, see if slot is already taken. If not, take it; + otherwise, put in list to tell user to solve conflict for us. + - If PD is slot #0 & #1, see if either is already taken. Try #0 first, + then try #1. If both are already taken, skip it. Do this *after* we've + connected devices with preferred slots. */ void AutoConnectProfiles(void) { - int foundProfiles[MAX_PROFILES]; - int controller1Profile = -1; - int controller2Profile = -1; - - // Check for Keyboard device profiles first, if anything else is plugged in - // it will default to it instead. -#if 0 - for(int i=0; i