X-Git-Url: http://shamusworld.gotdns.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Fgui%2Fprofile.cpp;h=434d01d8ac0918d7d183cb96ab816a3fae99de94;hb=5b056aa1b8278aff14df2dacb5df2787d2eb8bdf;hp=05d173d84407f716eda3c4adf6a29bf7dc5f5ced;hpb=69effddb777c2009d32f70e3315d5570973446ef;p=virtualjaguar diff --git a/src/gui/profile.cpp b/src/gui/profile.cpp index 05d173d..434d01d 100644 --- a/src/gui/profile.cpp +++ b/src/gui/profile.cpp @@ -7,25 +7,45 @@ // 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 "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]; @@ -37,6 +57,27 @@ uint32_t defaultMap[21] = { }; +// Function Prototypes +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) +{ + memcpy(&profileBackup, &profile, sizeof(Profile) * MAX_PROFILES); +} + + +void RestoreProfiles(void) +{ + memcpy(&profile, &profileBackup, sizeof(Profile) * MAX_PROFILES); +} + + void ReadProfiles(QSettings * set) { // Assume no profiles, until we read them @@ -54,39 +95,49 @@ void ReadProfiles(QSettings * set) { set->setArrayIndex(i - 1); strcpy(deviceNames[i], set->value("deviceName").toString().toAscii().data()); -//printf("Read device name: %s\n", deviceNames[i]); +#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(); + 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]; @@ -118,7 +169,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++) { @@ -131,17 +182,58 @@ void WriteProfiles(QSettings * set) } +int GetFreeProfile(void) +{ + // Check for too many, return -1 if so + if (numberOfProfiles == MAX_PROFILES) + return -1; + + int profileNum = numberOfProfiles; + numberOfProfiles++; + return profileNum; +} + + +void DeleteProfile(int profileToDelete) +{ + // Sanity check + if (profileToDelete >= numberOfProfiles) + return; + + // Trivial case: Profile at end of the array + if (profileToDelete == (numberOfProfiles - 1)) + { + numberOfProfiles--; + return; + } + +// memmove(dest, src, bytesToMove); + memmove(&profile[profileToDelete], &profile[profileToDelete + 1], ((numberOfProfiles - 1) - profileToDelete) * sizeof(Profile)); + numberOfProfiles--; +} + + int FindDeviceNumberForName(const char * name) { for(int i=0; iaddItem(QString("Keyboard::%1").arg(profile[j].mapName), j); + found++; + } + } + + // Check for connected host devices next + for(int i=0; iaddItem(QString("%1::%2").arg(Gamepad::GetJoystickName(i)).arg(profile[j].mapName), j); + found++; + } + } + } + + return found; +} + + bool ConnectProfileToController(int profileNum, int controllerNum) { + // Sanity checks... + if (profileNum < 0) + return false; + if (profile[profileNum].device == -1) return false; @@ -200,91 +332,218 @@ bool ConnectProfileToController(int profileNum, int controllerNum) 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); + WriteLog("PROFILE: 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. +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 controller1Profile = -1; - int controller2Profile = -1; +// int foundProfiles[MAX_PROFILES]; + controller1Profile = -1; + controller2Profile = -1; + gamepadIDSlot1 = -1; + gamepadIDSlot2 = -1; + + // Connect the keyboard automagically only if no gamepads are plugged in. + // Otherwise, check after all other devices have been checked, then try to + // add it in. + if (Gamepad::numJoysticks == 0) + { + ConnectProfileToDevice(0); + return; + } - // Nothing plugged in, we fall back to the default keyboard device profiles -// if (Gamepad::numJoysticks == 0) + // Connect the profiles that prefer a slot, if any. + // N.B.: Conflicts are detected, but ignored. 1st controller to grab a + // preferred slot gets it. :-P + for(int i=0; i