diff --git a/.hgignore b/.hgignore
index 2e155dd..ffb94b6 100644
--- a/.hgignore
+++ b/.hgignore
@@ -8,4 +8,5 @@ Documentation/Artifacts/*
Documentation/Manual/_build/*
Configuration/Configuration/bin/**
Configuration/Configuration/obj/**
+Artifacts/**
diff --git a/Package/Environment/Common/collections/Arcade/settings.conf b/Package/Environment/Common/collections/Arcade/settings.conf
index 01390cd..70b157c 100644
--- a/Package/Environment/Common/collections/Arcade/settings.conf
+++ b/Package/Environment/Common/collections/Arcade/settings.conf
@@ -20,6 +20,13 @@ list.includeMissingItems = true
###############################################################################
list.extensions = zip
+###############################################################################
+# If a menu.xml file exists, it will display the menu alphabetically. To
+# not auto-sort the menu items alphabetically, set the following to false.
+# This does not apply to how your ROMs are sorted.
+###############################################################################
+list.menuSort = true
+
###############################################################################
# The executable to run when an item in a collection item is selected
###############################################################################
diff --git a/Package/Environment/Common/collections/Main/menu.txt b/Package/Environment/Common/collections/Main/menu.txt
new file mode 100644
index 0000000..4498c97
--- /dev/null
+++ b/Package/Environment/Common/collections/Main/menu.txt
@@ -0,0 +1,2 @@
+Sega Genesis
+Arcade
diff --git a/Package/Environment/Common/collections/Main/menu.xml b/Package/Environment/Common/collections/Main/menu.xml
deleted file mode 100644
index bf9a75a..0000000
--- a/Package/Environment/Common/collections/Main/menu.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-
diff --git a/Package/Environment/Common/collections/Main/settings.conf b/Package/Environment/Common/collections/Main/settings.conf
index 4756a24..c481326 100644
--- a/Package/Environment/Common/collections/Main/settings.conf
+++ b/Package/Environment/Common/collections/Main/settings.conf
@@ -4,3 +4,11 @@
# See Menu.xml to configure the menu
###############################################################################
+###############################################################################
+# If a menu.xml file exists, it will display the menu alphabetically. To
+# not auto-sort the menu items alphabetically, set the following to false.
+# This does not apply to how your ROMs are sorted.
+###############################################################################
+list.menuSort = true
+
+
diff --git a/Package/Environment/Common/collections/Sega Genesis/settings.conf b/Package/Environment/Common/collections/Sega Genesis/settings.conf
index b3cf701..cf69c62 100644
--- a/Package/Environment/Common/collections/Sega Genesis/settings.conf
+++ b/Package/Environment/Common/collections/Sega Genesis/settings.conf
@@ -21,6 +21,13 @@ list.includeMissingItems = true
###############################################################################
list.extensions = zip
+###############################################################################
+# If a menu.xml file exists, it will display the menu alphabetically. To
+# not auto-sort the menu items alphabetically, set the following to false.
+# This does not apply to how your ROMs are sorted.
+###############################################################################
+list.menuSort = true
+
###############################################################################
# The executable to run when an item in a collection item is selected
###############################################################################
diff --git a/Package/Environment/Common/controls.conf b/Package/Environment/Common/controls.conf
index 954b2d6..299347c 100644
--- a/Package/Environment/Common/controls.conf
+++ b/Package/Environment/Common/controls.conf
@@ -11,8 +11,56 @@ back = Escape
quit = Q
-# See below for a list of key codes that can be used for configuring the controls:
+##############################################################################
+# MOUSE CODES
+###################### ######################################################
+# Code # Description
+###################### ######################################################
+# mouseButtonLeft Left mouse click
+# mouseButtonMiddle Middle mouse click
+# mouseButtonRight Right mouse click
+# mouseButtonX1 ?
+# mouseButtonX2 ?
+##############################################################################
+# JOYSTICK/GAMEPAD CODES
+###################### ######################################################
+# Code # Description
+###################### ######################################################
+# X is joypad number (0 is first joystick/gamepad)
+# joyXHatYLeftUp Y=hat number (0 is the first dpad) (example joy0Hat0Up)
+# joyXHatYLeft
+# joyXHatYLeftDown
+# joyXHatYUp
+# joyXHatYDown
+# joyXHatYRightUp
+# joyXHatYRight
+# joyXHatYRightDown
+# joyXButtonY Y is button number (0 is first button)
+# Example: joy1button7 -> second joystick, 8th button
+# Open up the gamepad control panel in windows or use
+# "jstest" in linux
+#
+# joyXAxis0+ First POV stick, first axis positive direction
+# (axis 0 is usually x)
+# joyXAxis0- First POV stick, first axis positive direction
+# (axis 0 is usually x)
+# joyXAxis1+ First POV stick, second axis positive direction
+# (axis 0 is usually y)
+#joyXAxis1- First POV stick, second axis positive direction
+# (axis 0 is usually y)
+#
+# joyXAxis2+ Second POV stick, first axis positive direction
+# (axis 2 is usually x)
+# joyXAxis2- Second POV stick, first axis positive direction
+# (axis 2 is usually x)
+# joyXAxis3+ Second POV stick, second axis positive direction
+# (axis 3 is usually y)
+# joyXAxis3- Second POV stick, second axis positive direction
+# (axis 3 is usually y)
+
+##############################################################################
+# KEYBOARD CODES
###################### ######################################################
# Code # Description
###################### ######################################################
diff --git a/Package/Environment/Common/settings.conf b/Package/Environment/Common/settings.conf
index 0449473..38c073f 100644
--- a/Package/Environment/Common/settings.conf
+++ b/Package/Environment/Common/settings.conf
@@ -12,8 +12,8 @@
# Display
#######################################
fullscreen = no
-horizontal = stretch # or enter in the screen pixel width (i.e 1024)
-vertical = stretch # or enter in the screen pixel width (i.e 768)
+horizontal = 400 # or enter in the screen pixel width (i.e 1024)
+vertical = 300 # or enter in the screen pixel width (i.e 768)
layout = Default 16x9
hideMouse = yes
showParenthesis = yes
diff --git a/RetroFE/Source/CMakeLists.txt b/RetroFE/Source/CMakeLists.txt
index 224d20f..92d0625 100644
--- a/RetroFE/Source/CMakeLists.txt
+++ b/RetroFE/Source/CMakeLists.txt
@@ -92,6 +92,12 @@ set(RETROFE_HEADERS
"${RETROFE_DIR}/Source/Collection/Item.h"
"${RETROFE_DIR}/Source/Collection/MenuParser.h"
"${RETROFE_DIR}/Source/Control/UserInput.h"
+ "${RETROFE_DIR}/Source/Control/InputHandler.h"
+ "${RETROFE_DIR}/Source/Control/JoyAxisHandler.h"
+ "${RETROFE_DIR}/Source/Control/JoyButtonHandler.h"
+ "${RETROFE_DIR}/Source/Control/JoyHatHandler.h"
+ "${RETROFE_DIR}/Source/Control/KeyboardHandler.h"
+ "${RETROFE_DIR}/Source/Control/MouseButtonHandler.h"
"${RETROFE_DIR}/Source/Database/Configuration.h"
"${RETROFE_DIR}/Source/Database/DB.h"
"${RETROFE_DIR}/Source/Database/MetadataDatabase.h"
@@ -137,6 +143,11 @@ set(RETROFE_SOURCES
"${RETROFE_DIR}/Source/Collection/Item.cpp"
"${RETROFE_DIR}/Source/Collection/MenuParser.cpp"
"${RETROFE_DIR}/Source/Control/UserInput.cpp"
+ "${RETROFE_DIR}/Source/Control/JoyAxisHandler.cpp"
+ "${RETROFE_DIR}/Source/Control/JoyButtonHandler.cpp"
+ "${RETROFE_DIR}/Source/Control/JoyHatHandler.cpp"
+ "${RETROFE_DIR}/Source/Control/KeyboardHandler.cpp"
+ "${RETROFE_DIR}/Source/Control/MouseButtonHandler.cpp"
"${RETROFE_DIR}/Source/Database/Configuration.cpp"
"${RETROFE_DIR}/Source/Database/DB.cpp"
"${RETROFE_DIR}/Source/Database/MetadataDatabase.cpp"
diff --git a/RetroFE/Source/Collection/CollectionInfo.cpp b/RetroFE/Source/Collection/CollectionInfo.cpp
index 8475fa5..45ff5e7 100644
--- a/RetroFE/Source/Collection/CollectionInfo.cpp
+++ b/RetroFE/Source/Collection/CollectionInfo.cpp
@@ -25,77 +25,75 @@ CollectionInfo::CollectionInfo(std::string name,
std::string extensions,
std::string metadataType,
std::string metadataPath)
- : Name(name)
- , ListPath(listPath)
- , Extensions(extensions)
- , MetadataType(metadataType)
- , MetadataPath(metadataPath)
+ : name(name)
+ , listpath(listPath)
+ , metadataType(metadataType)
+ , menusort(true)
+ , metadataPath_(metadataPath)
+ , extensions_(extensions)
{
}
CollectionInfo::~CollectionInfo()
{
- std::vector- ::iterator it = Items.begin();
+ // remove items from the subcollections so their destructors do not
+ // delete the items since the parent collection will delete them.
+ std::vector::iterator subit;
+ for (subit != subcollections_.begin(); subit != subcollections_.end(); subit++)
+ {
+ CollectionInfo *info = *subit;
+ info->items.clear();
+ }
- while(it != Items.end())
+
+ std::vector
- ::iterator it = items.begin();
+ while(it != items.end())
{
delete *it;
- Items.erase(it);
- it = Items.begin();
+ items.erase(it);
+ it = items.begin();
}
}
-std::string CollectionInfo::GetName() const
+std::string CollectionInfo::settingsPath() const
{
- return Name;
+ return Utils::combinePath(Configuration::absolutePath, "collections", name);
}
-std::string CollectionInfo::GetSettingsPath() const
-{
- return Utils::CombinePath(Configuration::GetAbsolutePath(), "collections", GetName());
-}
-std::string CollectionInfo::GetListPath() const
+void CollectionInfo::extensionList(std::vector &extensionlist)
{
- return ListPath;
-}
-
-std::string CollectionInfo::GetMetadataType() const
-{
- return MetadataType;
-}
-
-std::string CollectionInfo::GetMetadataPath() const
-{
- return MetadataPath;
-}
-
-std::string CollectionInfo::GetExtensions() const
-{
- return Extensions;
-}
-
-void CollectionInfo::GetExtensions(std::vector &extensions)
-{
- std::istringstream ss(Extensions);
+ std::istringstream ss(extensions_);
std::string token;
while(std::getline(ss, token, ','))
{
- extensions.push_back(token);
+ extensionlist.push_back(token);
}
}
-std::vector
- *CollectionInfo::GetItems()
+
+void CollectionInfo::addSubcollection(CollectionInfo *newinfo)
{
- return &Items;
+ subcollections_.push_back(newinfo);
+
+ items.insert(items.begin(), newinfo->items.begin(), newinfo->items.end());
}
-bool CollectionInfo::ItemIsLess(Item const *lhs, Item const *rhs)
+bool CollectionInfo::hasSubcollections()
{
- return lhs->GetLCFullTitle() < rhs->GetLCFullTitle();
+ return (subcollections_.size() > 0);
}
-void CollectionInfo::SortItems()
+bool CollectionInfo::itemIsLess(Item *lhs, Item *rhs)
{
- std::sort(Items.begin(), Items.end(), ItemIsLess);
+ if(lhs->leaf && !rhs->leaf) return true;
+ if(!lhs->leaf && rhs->leaf) return false;
+ if(!lhs->collectionInfo->menusort && lhs->leaf && rhs->leaf) return false;
+ return lhs->lowercaseFullTitle() < rhs->lowercaseFullTitle();
+}
+
+
+void CollectionInfo::sortItems()
+{
+ std::sort(items.begin(), items.end(), itemIsLess);
}
diff --git a/RetroFE/Source/Collection/CollectionInfo.h b/RetroFE/Source/Collection/CollectionInfo.h
index 494f025..04bc908 100644
--- a/RetroFE/Source/Collection/CollectionInfo.h
+++ b/RetroFE/Source/Collection/CollectionInfo.h
@@ -25,23 +25,21 @@ class CollectionInfo
public:
CollectionInfo(std::string name, std::string listPath, std::string extensions, std::string metadataType, std::string metadataPath);
virtual ~CollectionInfo();
- std::string GetName() const;
- std::string GetSettingsPath() const;
- std::string GetListPath() const;
- std::string GetMetadataType() const;
- std::string GetMetadataPath() const;
- std::string GetExtensions() const;
- std::vector
- *GetItems();
- void SortItems();
- void GetExtensions(std::vector &extensions);
-
+ std::string settingsPath() const;
+ void sortItems();
+ void addSubcollection(CollectionInfo *info);
+ bool hasSubcollections();
+ void extensionList(std::vector &extensions);
+ std::string name;
+ std::string listpath;
+ std::string metadataType;
+ std::string launcher;
+ std::vector
- items;
+ bool menusort;
private:
- static bool ItemIsLess(Item const *lhs, Item const *rhs);
+ std::vector subcollections_;
+ std::string metadataPath_;
+ std::string extensions_;
+ static bool itemIsLess(Item *lhs, Item *rhs);
- std::string Name;
- std::string ListPath;
- std::string Extensions;
- std::string MetadataType;
- std::string MetadataPath;
- std::vector
- Items;
};
diff --git a/RetroFE/Source/Collection/CollectionInfoBuilder.cpp b/RetroFE/Source/Collection/CollectionInfoBuilder.cpp
index c1fefab..e7925ec 100644
--- a/RetroFE/Source/Collection/CollectionInfoBuilder.cpp
+++ b/RetroFE/Source/Collection/CollectionInfoBuilder.cpp
@@ -36,8 +36,8 @@
#include
CollectionInfoBuilder::CollectionInfoBuilder(Configuration &c, MetadataDatabase &mdb)
- : Conf(c)
- , MetaDB(mdb)
+ : conf_(c)
+ , metaDB_(mdb)
{
}
@@ -45,24 +45,24 @@ CollectionInfoBuilder::~CollectionInfoBuilder()
{
}
-bool CollectionInfoBuilder::CreateCollectionDirectory(std::string name)
+bool CollectionInfoBuilder::createCollectionDirectory(std::string name)
{
- std::string collectionPath = Utils::CombinePath(Configuration::GetAbsolutePath(), "collections", name);
+ std::string collectionPath = Utils::combinePath(Configuration::absolutePath, "collections", name);
std::vector paths;
paths.push_back(collectionPath);
- paths.push_back(Utils::CombinePath(collectionPath, "medium_artwork"));
- paths.push_back(Utils::CombinePath(collectionPath, "medium_artwork", "artwork_back"));
- paths.push_back(Utils::CombinePath(collectionPath, "medium_artwork", "artwork_front"));
- paths.push_back(Utils::CombinePath(collectionPath, "medium_artwork", "bezel"));
- paths.push_back(Utils::CombinePath(collectionPath, "medium_artwork", "logo"));
- paths.push_back(Utils::CombinePath(collectionPath, "medium_artwork", "medium_back"));
- paths.push_back(Utils::CombinePath(collectionPath, "medium_artwork", "medium_front"));
- paths.push_back(Utils::CombinePath(collectionPath, "medium_artwork", "screenshot"));
- paths.push_back(Utils::CombinePath(collectionPath, "medium_artwork", "screentitle"));
- paths.push_back(Utils::CombinePath(collectionPath, "medium_artwork", "video"));
- paths.push_back(Utils::CombinePath(collectionPath, "roms"));
- paths.push_back(Utils::CombinePath(collectionPath, "system_artwork"));
+ paths.push_back(Utils::combinePath(collectionPath, "medium_artwork"));
+ paths.push_back(Utils::combinePath(collectionPath, "medium_artwork", "artwork_back"));
+ paths.push_back(Utils::combinePath(collectionPath, "medium_artwork", "artwork_front"));
+ paths.push_back(Utils::combinePath(collectionPath, "medium_artwork", "bezel"));
+ paths.push_back(Utils::combinePath(collectionPath, "medium_artwork", "logo"));
+ paths.push_back(Utils::combinePath(collectionPath, "medium_artwork", "medium_back"));
+ paths.push_back(Utils::combinePath(collectionPath, "medium_artwork", "medium_front"));
+ paths.push_back(Utils::combinePath(collectionPath, "medium_artwork", "screenshot"));
+ paths.push_back(Utils::combinePath(collectionPath, "medium_artwork", "screentitle"));
+ paths.push_back(Utils::combinePath(collectionPath, "medium_artwork", "video"));
+ paths.push_back(Utils::combinePath(collectionPath, "roms"));
+ paths.push_back(Utils::combinePath(collectionPath, "system_artwork"));
for(std::vector::iterator it = paths.begin(); it != paths.end(); it++)
{
@@ -89,7 +89,7 @@ bool CollectionInfoBuilder::CreateCollectionDirectory(std::string name)
#endif
}
- std::string filename = Utils::CombinePath(collectionPath, "include.txt");
+ std::string filename = Utils::combinePath(collectionPath, "include.txt");
std::cout << "Creating file \"" << filename << "\"" << std::endl;
std::ofstream includeFile;
@@ -99,7 +99,7 @@ bool CollectionInfoBuilder::CreateCollectionDirectory(std::string name)
includeFile << "# by settings.conf will be used" << std::endl;
includeFile.close();
- filename = Utils::CombinePath(collectionPath, "exclude.txt");
+ filename = Utils::combinePath(collectionPath, "exclude.txt");
std::cout << "Creating file \"" << filename << "\"" << std::endl;
std::ofstream excludeFile;
excludeFile.open(filename.c_str());
@@ -107,51 +107,46 @@ bool CollectionInfoBuilder::CreateCollectionDirectory(std::string name)
includeFile << "# Add a list of files to hide on the menu (one filename per line, without the extension)." << std::endl;
excludeFile.close();
- filename = Utils::CombinePath(collectionPath, "settings.conf");
+ filename = Utils::combinePath(collectionPath, "settings.conf");
std::cout << "Creating file \"" << filename << "\"" << std::endl;
std::ofstream settingsFile;
settingsFile.open(filename.c_str());
settingsFile << "# Uncomment and edit the following line to use a different ROM path." << std::endl;
- settingsFile << "#list.path = " << Utils::CombinePath("%BASE_ITEM_PATH%", "%ITEM_COLLECTION_NAME%", "roms") << std::endl;
+ settingsFile << "#list.path = " << Utils::combinePath("%BASE_ITEM_PATH%", "%ITEM_COLLECTION_NAME%", "roms") << std::endl;
settingsFile << "list.includeMissingItems = false" << std::endl;
settingsFile << "list.extensions = zip" << std::endl;
+ settingsFile << "list.menuSort = yes" << std::endl;
+ settingsFile << std::endl;
settingsFile << "launcher = mame" << std::endl;
settingsFile << "metadata.type = MAME" << std::endl;
settingsFile << std::endl;
- settingsFile << "#media.screenshot = " << Utils::CombinePath("%BASE_MEDIA_PATH%", "%ITEM_COLLECTION_NAME%", "medium_artwork", "screenshot") << std::endl;
- settingsFile << "#media.screentitle = " << Utils::CombinePath("%BASE_MEDIA_PATH%", "%ITEM_COLLECTION_NAME%", "medium_artwork", "screentitle") << std::endl;
- settingsFile << "#media.artwork_back = " << Utils::CombinePath("%BASE_MEDIA_PATH%", "%ITEM_COLLECTION_NAME%", "medium_artwork", "artwork_back") << std::endl;
- settingsFile << "#media.artwork_front = " << Utils::CombinePath("%BASE_MEDIA_PATH%", "%ITEM_COLLECTION_NAME%", "medium_artwork", "artwork_front") << std::endl;
- settingsFile << "#media.logo = " << Utils::CombinePath("%BASE_MEDIA_PATH%", "%ITEM_COLLECTION_NAME%", "medium_artwork", "logo") << std::endl;
- settingsFile << "#media.medium_back = " << Utils::CombinePath("%BASE_MEDIA_PATH%", "%ITEM_COLLECTION_NAME%", "medium_artwork", "medium_back") << std::endl;
- settingsFile << "#media.medium_front = " << Utils::CombinePath("%BASE_MEDIA_PATH%", "%ITEM_COLLECTION_NAME%", "medium_artwork", "medium_front") << std::endl;
- settingsFile << "#media.screenshot = " << Utils::CombinePath("%BASE_MEDIA_PATH%", "%ITEM_COLLECTION_NAME%", "medium_artwork", "screenshot") << std::endl;
- settingsFile << "#media.screentitle = " << Utils::CombinePath("%BASE_MEDIA_PATH%", "%ITEM_COLLECTION_NAME%", "medium_artwork", "screentitle") << std::endl;
- settingsFile << "#media.video = " << Utils::CombinePath("%BASE_MEDIA_PATH%", "%ITEM_COLLECTION_NAME%", "medium_artwork", "video") << std::endl;
+ settingsFile << "#media.screenshot = " << Utils::combinePath("%BASE_MEDIA_PATH%", "%ITEM_COLLECTION_NAME%", "medium_artwork", "screenshot") << std::endl;
+ settingsFile << "#media.screentitle = " << Utils::combinePath("%BASE_MEDIA_PATH%", "%ITEM_COLLECTION_NAME%", "medium_artwork", "screentitle") << std::endl;
+ settingsFile << "#media.artwork_back = " << Utils::combinePath("%BASE_MEDIA_PATH%", "%ITEM_COLLECTION_NAME%", "medium_artwork", "artwork_back") << std::endl;
+ settingsFile << "#media.artwork_front = " << Utils::combinePath("%BASE_MEDIA_PATH%", "%ITEM_COLLECTION_NAME%", "medium_artwork", "artwork_front") << std::endl;
+ settingsFile << "#media.logo = " << Utils::combinePath("%BASE_MEDIA_PATH%", "%ITEM_COLLECTION_NAME%", "medium_artwork", "logo") << std::endl;
+ settingsFile << "#media.medium_back = " << Utils::combinePath("%BASE_MEDIA_PATH%", "%ITEM_COLLECTION_NAME%", "medium_artwork", "medium_back") << std::endl;
+ settingsFile << "#media.medium_front = " << Utils::combinePath("%BASE_MEDIA_PATH%", "%ITEM_COLLECTION_NAME%", "medium_artwork", "medium_front") << std::endl;
+ settingsFile << "#media.screenshot = " << Utils::combinePath("%BASE_MEDIA_PATH%", "%ITEM_COLLECTION_NAME%", "medium_artwork", "screenshot") << std::endl;
+ settingsFile << "#media.screentitle = " << Utils::combinePath("%BASE_MEDIA_PATH%", "%ITEM_COLLECTION_NAME%", "medium_artwork", "screentitle") << std::endl;
+ settingsFile << "#media.video = " << Utils::combinePath("%BASE_MEDIA_PATH%", "%ITEM_COLLECTION_NAME%", "medium_artwork", "video") << std::endl;
settingsFile.close();
- filename = Utils::CombinePath(collectionPath, "menu.xml");
+ filename = Utils::combinePath(collectionPath, "menu.txt");
std::cout << "Creating file \"" << filename << "\"" << std::endl;
std::ofstream menuFile;
menuFile.open(filename.c_str());
-
- menuFile << "" << std::endl;
menuFile.close();
return true;
}
+CollectionInfo *CollectionInfoBuilder::buildCollection(std::string name)
+{
+ return buildCollection(name, "");
+}
-CollectionInfo *CollectionInfoBuilder::BuildCollection(std::string name)
+CollectionInfo *CollectionInfoBuilder::buildCollection(std::string name, std::string mergedCollectionName)
{
std::string listItemsPathKey = "collections." + name + ".list.path";
std::string listFilterKey = "collections." + name + ".list.filter";
@@ -167,13 +162,14 @@ CollectionInfo *CollectionInfoBuilder::BuildCollection(std::string name)
std::string extensions;
std::string metadataType = name;
std::string metadataPath;
+
+ conf_.getCollectionAbsolutePath(name, listItemsPath);
- Conf.GetCollectionAbsolutePath(name, listItemsPath);
- (void)Conf.GetProperty(extensionsKey, extensions);
- (void)Conf.GetProperty(metadataTypeKey, metadataType);
- (void)Conf.GetProperty(metadataPathKey, metadataPath);
+ (void)conf_.getProperty(extensionsKey, extensions);
+ (void)conf_.getProperty(metadataTypeKey, metadataType);
+ (void)conf_.getProperty(metadataPathKey, metadataPath);
- if(!Conf.GetProperty(launcherKey, launcherName))
+ if(!conf_.getProperty(launcherKey, launcherName))
{
std::stringstream ss;
ss << "\""
@@ -183,18 +179,20 @@ CollectionInfo *CollectionInfoBuilder::BuildCollection(std::string name)
<< "). Your collection will be viewable, however you will not be able to "
<< "launch any of the items in your collection.";
- Logger::Write(Logger::ZONE_NOTICE, "Collections", ss.str());
+ Logger::write(Logger::ZONE_NOTICE, "Collections", ss.str());
}
CollectionInfo *collection = new CollectionInfo(name, listItemsPath, extensions, metadataType, metadataPath);
- ImportDirectory(collection);
+ (void)conf_.getProperty("collections." + collection->name + ".launcher", collection->launcher);
+
+ ImportDirectory(collection, mergedCollectionName);
return collection;
}
-bool CollectionInfoBuilder::ImportBasicList(CollectionInfo * /*info*/, std::string file, std::string launcher, std::map &list)
+bool CollectionInfoBuilder::ImportBasicList(CollectionInfo *info, std::string file, std::map &list)
{
std::ifstream includeStream(file.c_str());
@@ -207,7 +205,7 @@ bool CollectionInfoBuilder::ImportBasicList(CollectionInfo * /*info*/, std::stri
while(std::getline(includeStream, line))
{
- line = Utils::FilterComments(line);
+ line = Utils::filterComments(line);
if(!line.empty() && list.find(line) == list.end())
{
@@ -215,11 +213,10 @@ bool CollectionInfoBuilder::ImportBasicList(CollectionInfo * /*info*/, std::stri
line.erase( std::remove(line.begin(), line.end(), '\r'), line.end() );
- i->SetFullTitle(line);
- i->SetName(line);
- i->SetFullTitle(line);
- i->SetTitle(line);
- i->SetLauncher(launcher);
+ i->fullTitle = line;
+ i->name = line;
+ i->title = line;
+ i->collectionInfo = info;
list[line] = i;
}
@@ -228,36 +225,54 @@ bool CollectionInfoBuilder::ImportBasicList(CollectionInfo * /*info*/, std::stri
return true;
}
-bool CollectionInfoBuilder::ImportDirectory(CollectionInfo *info)
+bool CollectionInfoBuilder::ImportDirectory(CollectionInfo *info, std::string mergedCollectionName)
{
DIR *dp;
struct dirent *dirp;
- std::string path = info->GetListPath();
+ std::string path = info->listpath;
std::map includeFilter;
std::map excludeFilter;
- std::string includeFile = Utils::CombinePath(Configuration::GetAbsolutePath(), "collections", info->GetName(), "include.txt");
- std::string excludeFile = Utils::CombinePath(Configuration::GetAbsolutePath(), "collections", info->GetName(), "exclude.txt");
+ std::string includeFile = Utils::combinePath(Configuration::absolutePath, "collections", info->name, "include.txt");
+ std::string excludeFile = Utils::combinePath(Configuration::absolutePath, "collections", info->name, "exclude.txt");
+
std::string launcher;
bool showMissing = false;
- (void)Conf.GetProperty("collections." + info->GetName() + ".launcher", launcher);
- (void)Conf.GetProperty("collections." + info->GetName() + ".list.includeMissingItems", showMissing);
+ if(mergedCollectionName != "")
+ {
+
+ std::string mergedFile = Utils::combinePath(Configuration::absolutePath, "collections", mergedCollectionName, info->name + ".sub");
+ Logger::write(Logger::ZONE_INFO, "CollectionInfoBuilder", "Checking for \"" + mergedFile + "\"");
+ (void)conf_.getProperty("collections." + mergedCollectionName + ".list.includeMissingItems", showMissing);
+ ImportBasicList(info, mergedFile, includeFilter);
- ImportBasicList(info, includeFile, launcher, includeFilter);
- ImportBasicList(info, excludeFile, launcher, excludeFilter);
+ }
+ else
+ {
+ (void)conf_.getProperty("collections." + info->name + ".list.includeMissingItems", showMissing);
+ }
+
+ // If no merged file exists, or it is empty, attempt to use the include and exclude from the subcollection
+ // If this not a merged collection, the size will be 0 anyways and the code below will still execute
+ if(includeFilter.size() == 0)
+ {
+ Logger::write(Logger::ZONE_INFO, "CollectionInfoBuilder", "Checking for \"" + includeFile + "\"");
+ ImportBasicList(info, includeFile, includeFilter);
+ ImportBasicList(info, excludeFile, excludeFilter);
+ }
std::vector extensions;
std::vector::iterator extensionsIt;
- info->GetExtensions(extensions);
+ info->extensionList(extensions);
- Logger::Write(Logger::ZONE_INFO, "CollectionInfoBuilder", "Checking for \"" + includeFile + "\"");
dp = opendir(path.c_str());
+ Logger::write(Logger::ZONE_INFO, "CollectionInfoBuilder", "Scanning directory \"" + path + "\"");
if(dp == NULL)
{
- Logger::Write(Logger::ZONE_INFO, "CollectionInfoBuilder", "Could not read directory \"" + path + "\". Ignore if this is a menu.");
+ Logger::write(Logger::ZONE_INFO, "CollectionInfoBuilder", "Could not read directory \"" + path + "\". Ignore if this is a menu.");
return false;
}
@@ -267,7 +282,7 @@ bool CollectionInfoBuilder::ImportDirectory(CollectionInfo *info)
{
if(excludeFilter.find(it->first) == excludeFilter.end())
{
- info->GetItems()->push_back(it->second);
+ info->items.push_back(it->second);
}
}
}
@@ -295,11 +310,12 @@ bool CollectionInfoBuilder::ImportDirectory(CollectionInfo *info)
if(file.compare(start, comparator.length(), *extensionsIt) == 0)
{
Item *i = new Item();
- i->SetName(basename);
- i->SetFullTitle(basename);
- i->SetTitle(basename);
- i->SetLauncher(launcher);
- info->GetItems()->push_back(i);
+ i->name = basename;
+ i->fullTitle = basename;
+ i->title = basename;
+ i->collectionInfo = info;
+
+ info->items.push_back(i);
}
}
}
@@ -325,9 +341,7 @@ bool CollectionInfoBuilder::ImportDirectory(CollectionInfo *info)
excludeFilter.erase(it);
}
- MetaDB.InjectMetadata(info);
+ metaDB_.injectMetadata(info);
- info->SortItems();
-
return true;
}
diff --git a/RetroFE/Source/Collection/CollectionInfoBuilder.h b/RetroFE/Source/Collection/CollectionInfoBuilder.h
index a613b49..250f384 100644
--- a/RetroFE/Source/Collection/CollectionInfoBuilder.h
+++ b/RetroFE/Source/Collection/CollectionInfoBuilder.h
@@ -29,12 +29,13 @@ class CollectionInfoBuilder
public:
CollectionInfoBuilder(Configuration &c, MetadataDatabase &mdb);
virtual ~CollectionInfoBuilder();
- CollectionInfo *BuildCollection(std::string collectionName);
- static bool CreateCollectionDirectory(std::string collectionName);
+ CollectionInfo *buildCollection(std::string collectionName);
+ CollectionInfo *buildCollection(std::string collectionName, std::string mergedCollectionName);
+ static bool createCollectionDirectory(std::string collectionName);
private:
- Configuration &Conf;
- MetadataDatabase &MetaDB;
- bool ImportBasicList(CollectionInfo *info, std::string file, std::string launcher, std::map &list);
- bool ImportDirectory(CollectionInfo *info);
+ Configuration &conf_;
+ MetadataDatabase &metaDB_;
+ bool ImportBasicList(CollectionInfo *info, std::string file, std::map &list);
+ bool ImportDirectory(CollectionInfo *info, std::string mergedCollectionName);
};
diff --git a/RetroFE/Source/Collection/Item.cpp b/RetroFE/Source/Collection/Item.cpp
index ef54f2e..7f74e79 100644
--- a/RetroFE/Source/Collection/Item.cpp
+++ b/RetroFE/Source/Collection/Item.cpp
@@ -20,7 +20,8 @@
#include
Item::Item()
- : Leaf(true)
+ : collectionInfo(NULL)
+ , leaf(true)
{
}
@@ -28,142 +29,24 @@ Item::~Item()
{
}
-const std::string Item::GetFileName() const
+std::string Item::filename()
{
- return Utils::GetFileName(FilePath);
-}
-
-const std::string& Item::GetFilePath() const
-{
- return FilePath;
-}
-
-void Item::SetFilePath(const std::string& filepath)
-{
- FilePath = filepath;
-}
-
-const std::string& Item::GetLauncher() const
-{
- return Launcher;
-}
-
-void Item::SetLauncher(const std::string& launcher)
-{
- Launcher = launcher;
-}
-
-const std::string& Item::GetManufacturer() const
-{
- return Manufacturer;
-}
-
-void Item::SetManufacturer(const std::string& manufacturer)
-{
- Manufacturer = manufacturer;
-}
-
-const std::string& Item::GetGenre() const
-{
- return Genre;
-}
-
-void Item::SetGenre(const std::string& genre)
-{
- Genre = genre;
-}
-
-const std::string& Item::GetName() const
-{
- return Name;
-}
-
-void Item::SetName(const std::string& name)
-{
- Name = name;
-}
-
-std::string Item::GetNumberButtons() const
-{
- return NumberButtons;
+ return Utils::getFileName(filepath);
}
-void Item::SetNumberButtons(std::string numberbuttons)
+
+std::string Item::lowercaseTitle()
{
- NumberButtons = numberbuttons;
+ std::string lcstr = title;
+ std::transform(lcstr.begin(), lcstr.end(), lcstr.begin(), ::tolower);
+ return lcstr;
}
-std::string Item::GetNumberPlayers() const
+std::string Item::lowercaseFullTitle()
{
- return NumberPlayers;
+ std::string lcstr = fullTitle;
+ std::transform(lcstr.begin(), lcstr.end(), lcstr.begin(), ::tolower);
+ return lcstr;
}
-void Item::SetNumberPlayers(std::string numberplayers)
-{
- NumberPlayers = numberplayers;
-}
-
-const std::string& Item::GetTitle() const
-{
- return Title;
-}
-
-const std::string& Item::GetLCTitle() const
-{
- return LCTitle;
-}
-
-const std::string& Item::GetLCFullTitle() const
-{
- return LCFullTitle;
-}
-
-void Item::SetTitle(const std::string& title)
-{
- Title = title;
- LCTitle = Title;
- std::transform(LCTitle.begin(), LCTitle.end(), LCTitle.begin(), ::tolower);
-}
-
-const std::string& Item::GetYear() const
-{
- return Year;
-}
-
-void Item::SetYear(const std::string& year)
-{
- Year = year;
-}
-
-bool Item::IsLeaf() const
-{
- return Leaf;
-}
-
-void Item::SetIsLeaf(bool leaf)
-{
- Leaf = leaf;
-}
-
-const std::string& Item::GetFullTitle() const
-{
- return FullTitle;
-}
-
-void Item::SetFullTitle(const std::string& fulltitle)
-{
- FullTitle = fulltitle;
- LCFullTitle = fulltitle;
- std::transform(LCFullTitle.begin(), LCFullTitle.end(), LCFullTitle.begin(), ::tolower);
-}
-
-const std::string& Item::GetCloneOf() const
-{
- return CloneOf;
-}
-
-void Item::SetCloneOf(const std::string& cloneOf)
-{
- CloneOf = cloneOf;
-}
diff --git a/RetroFE/Source/Collection/Item.h b/RetroFE/Source/Collection/Item.h
index b157592..1826f50 100644
--- a/RetroFE/Source/Collection/Item.h
+++ b/RetroFE/Source/Collection/Item.h
@@ -16,54 +16,27 @@
#pragma once
#include
+#include "CollectionInfo.h"
class Item
{
public:
Item();
virtual ~Item();
- const std::string GetFileName() const;
- const std::string& GetFilePath() const;
- void SetFilePath(const std::string& filepath);
- const std::string& GetLauncher() const;
- void SetLauncher(const std::string& launcher);
- const std::string& GetManufacturer() const;
- void SetManufacturer(const std::string& manufacturer);
- const std::string& GetGenre() const;
- void SetGenre(const std::string& genre);
- const std::string& GetName() const;
- void SetName(const std::string& name);
- void SetNumberButtons(std::string numberbuttons);
- std::string GetNumberButtons() const;
- void SetNumberPlayers(std::string numberplayers);
- std::string GetNumberPlayers() const;
- const std::string& GetTitle() const;
- const std::string& GetLCTitle() const;
- void SetTitle(const std::string& title);
- const std::string& GetYear() const;
- void SetYear(const std::string& year);
- bool IsLeaf() const;
- void SetIsLeaf(bool leaf);
- const std::string& GetFullTitle() const;
- const std::string& GetLCFullTitle() const;
- void SetFullTitle(const std::string& fulltitle);
- const std::string& GetCloneOf() const;
- void SetCloneOf(const std::string& cloneOf);
-
-private:
- std::string Launcher;
- std::string FilePath;
- std::string Name;
- std::string Title;
- std::string LCTitle;
- std::string FullTitle;
- std::string LCFullTitle;
- std::string Year;
- std::string Manufacturer;
- std::string Genre;
- std::string CloneOf;
- std::string NumberPlayers;
- std::string NumberButtons;
- bool Leaf;
+ std::string filename();
+ std::string lowercaseTitle() ;
+ std::string lowercaseFullTitle();
+ std::string name;
+ std::string filepath;
+ std::string title;
+ std::string fullTitle;
+ std::string year;
+ std::string manufacturer;
+ std::string genre;
+ std::string cloneof;
+ std::string numberPlayers;
+ std::string numberButtons;
+ CollectionInfo *collectionInfo;
+ bool leaf;
};
diff --git a/RetroFE/Source/Collection/MenuParser.cpp b/RetroFE/Source/Collection/MenuParser.cpp
index 2174b66..f80bd5c 100644
--- a/RetroFE/Source/Collection/MenuParser.cpp
+++ b/RetroFE/Source/Collection/MenuParser.cpp
@@ -16,6 +16,7 @@
#include "MenuParser.h"
#include "CollectionInfo.h"
+#include "CollectionInfoBuilder.h"
#include "Item.h"
#include "../Utility/Log.h"
#include "../Utility/Utils.h"
@@ -26,9 +27,9 @@
#include
#include
-bool VectorSort(const Item *d1, const Item *d2)
+bool VectorSort(Item *d1, Item *d2)
{
- return d1->GetLCTitle() < d2->GetLCTitle();
+ return d1->lowercaseTitle() < d2->lowercaseTitle();
}
MenuParser::MenuParser()
@@ -39,16 +40,67 @@ MenuParser::~MenuParser()
{
}
-//todo: clean up this method, too much nesting
-bool MenuParser::GetMenuItems(CollectionInfo *collection)
+bool MenuParser::buildMenuItems(CollectionInfo *collection, bool sort)
+{
+
+ if(!buildTextMenu(collection, sort))
+ {
+ return buildLegacyXmlMenu(collection, sort);
+ }
+
+ return true;
+}
+
+bool MenuParser::buildTextMenu(CollectionInfo *collection, bool sort)
+{
+ std::string file = Utils::combinePath(Configuration::absolutePath, "collections", collection->name, "menu.txt");
+ std::ifstream includeStream(file.c_str());
+ std::vector
- menuItems;
+
+ if (!includeStream.good())
+ {
+ Logger::write(Logger::ZONE_INFO, "Menu", "File does not exist: \"" + file + "\"");
+ return false;
+ }
+
+ Logger::write(Logger::ZONE_INFO, "Menu", "Found: \"" + file + "\"");
+
+ std::string line;
+
+ while(std::getline(includeStream, line))
+ {
+ line = Utils::filterComments(line);
+
+ if(!line.empty())
+ {
+ std::string title = line;
+ Item *item = new Item();
+ item->title = title;
+ item->fullTitle = title;
+ item->name = title;
+ item->leaf = false;
+ item->collectionInfo = collection;
+
+ menuItems.push_back(item);
+ }
+ }
+
+
+ collection->menusort = sort;
+ collection->items.insert(collection->items.begin(), menuItems.begin(), menuItems.end());
+ collection->sortItems();
+
+ return true;
+}
+
+bool MenuParser::buildLegacyXmlMenu(CollectionInfo *collection, bool sort)
{
bool retVal = false;
//todo: magic string
- std::string menuFilename = Utils::CombinePath(Configuration::GetAbsolutePath(), "collections", collection->GetName(), "menu.xml");
+ std::string menuFilename = Utils::combinePath(Configuration::absolutePath, "collections", collection->name, "menu.xml");
rapidxml::xml_document<> doc;
rapidxml::xml_node<> * rootNode;
-
- Logger::Write(Logger::ZONE_INFO, "Menu", "Checking if menu exists at \"" + menuFilename + "\"");
+ std::vector
- menuItems;
try
{
@@ -57,6 +109,8 @@ bool MenuParser::GetMenuItems(CollectionInfo *collection)
// gracefully exit if there is no menu file for the pa
if(file.good())
{
+ Logger::write(Logger::ZONE_INFO, "Menu", "Found: \"" + menuFilename + "\"");
+ Logger::write(Logger::ZONE_INFO, "Menu", "Using legacy menu.xml file. Consider using the new menu.txt format");
std::vector buffer((std::istreambuf_iterator(file)), std::istreambuf_iterator());
buffer.push_back('\0');
@@ -68,46 +122,28 @@ bool MenuParser::GetMenuItems(CollectionInfo *collection)
for (rapidxml::xml_node<> * itemNode = rootNode->first_node("item"); itemNode; itemNode = itemNode->next_sibling())
{
rapidxml::xml_attribute<> *collectionAttribute = itemNode->first_attribute("collection");
- rapidxml::xml_attribute<> *importAttribute = itemNode->first_attribute("import");
if(!collectionAttribute)
{
retVal = false;
- Logger::Write(Logger::ZONE_ERROR, "Menu", "Menu item tag is missing collection attribute");
+ Logger::write(Logger::ZONE_ERROR, "Menu", "Menu item tag is missing collection attribute");
break;
}
- //todo: too much nesting! Ack!
- std::string import;
- if(importAttribute)
- {
- import = importAttribute->value();
- }
+ //todo, check for empty string
+ std::string title = collectionAttribute->value();
+ Item *item = new Item();
+ item->title = title;
+ item->fullTitle = title;
+ item->name = collectionAttribute->value();
+ item->leaf = false;
+ item->collectionInfo = collection;
- if(import != "true")
- {
- //todo, check for empty string
- std::string title = collectionAttribute->value();
- Item *item = new Item();
- item->SetTitle(title);
- item->SetFullTitle(title);
- item->SetName(collectionAttribute->value());
- item->SetIsLeaf(false);
- collection->GetItems()->push_back(item);
-
- }
- else
- {
- std::string collectionName = collectionAttribute->value();
- Logger::Write(Logger::ZONE_INFO, "Menu", "Loading collection into menu: " + collectionName);
-
- //todo: unsupported option with this refactor
- // need to append the collection
- }
+ menuItems.push_back(item);
}
+
- // todo: sorting should occur within the collection itself, not externally
- std::vector
- *items = collection->GetItems();
- std::sort( items->begin(), items->end(), VectorSort);
+ collection->menusort = sort;
+ collection->items.insert(collection->items.begin(), menuItems.begin(), menuItems.end());
retVal = true;
}
@@ -116,9 +152,8 @@ bool MenuParser::GetMenuItems(CollectionInfo *collection)
{
std::stringstream ss;
ss << "Unable to open menu file \"" << menuFilename << "\": " << e.what();
- Logger::Write(Logger::ZONE_ERROR, "Menu", ss.str());
+ Logger::write(Logger::ZONE_ERROR, "Menu", ss.str());
}
return retVal;
-
}
diff --git a/RetroFE/Source/Collection/MenuParser.h b/RetroFE/Source/Collection/MenuParser.h
index c349ebe..f81dc98 100644
--- a/RetroFE/Source/Collection/MenuParser.h
+++ b/RetroFE/Source/Collection/MenuParser.h
@@ -15,6 +15,7 @@
*/
#pragma once
+#include "CollectionInfoBuilder.h"
class CollectionInfo;
class MenuParser
@@ -22,6 +23,10 @@ class MenuParser
public:
MenuParser();
virtual ~MenuParser();
- bool GetMenuItems(CollectionInfo *cdb);
+ bool buildMenuItems(CollectionInfo *cdb, bool sort);
+
+private:
+ bool buildTextMenu(CollectionInfo *collection, bool sort);
+ bool buildLegacyXmlMenu(CollectionInfo *collection, bool sort);
};
diff --git a/RetroFE/Source/Control/InputHandler.h b/RetroFE/Source/Control/InputHandler.h
new file mode 100644
index 0000000..9996d4b
--- /dev/null
+++ b/RetroFE/Source/Control/InputHandler.h
@@ -0,0 +1,12 @@
+#pragma once
+
+#include
+
+class InputHandler
+{
+public:
+ virtual bool update(SDL_Event &e) = 0;
+ virtual bool pressed() = 0;
+ virtual void reset() = 0;
+};
+
diff --git a/RetroFE/Source/Control/JoyAxisHandler.cpp b/RetroFE/Source/Control/JoyAxisHandler.cpp
new file mode 100644
index 0000000..5f2677b
--- /dev/null
+++ b/RetroFE/Source/Control/JoyAxisHandler.cpp
@@ -0,0 +1,29 @@
+#include "JoyAxisHandler.h"
+
+JoyAxisHandler::JoyAxisHandler(SDL_JoystickID joyid, Uint8 axis, Sint16 min, Sint16 max)
+: joyid_(joyid)
+, axis_(axis)
+, min_(min)
+, max_(max)
+, pressed_(false)
+{
+}
+
+void JoyAxisHandler::reset()
+{
+ pressed_= false;
+}
+
+bool JoyAxisHandler::update(SDL_Event &e)
+{
+ if(e.type != SDL_JOYAXISMOTION || e.jaxis.which != joyid_ || e.jaxis.axis != axis_) return false;
+ pressed_ = (min_ <= e.jaxis.value && e.jaxis.value <= max_);
+
+ return true;
+}
+
+bool JoyAxisHandler::pressed()
+{
+ return pressed_;
+}
+
diff --git a/RetroFE/Source/Control/JoyAxisHandler.h b/RetroFE/Source/Control/JoyAxisHandler.h
new file mode 100644
index 0000000..55bee04
--- /dev/null
+++ b/RetroFE/Source/Control/JoyAxisHandler.h
@@ -0,0 +1,21 @@
+#pragma once
+
+#include "InputHandler.h"
+
+class JoyAxisHandler : public InputHandler
+{
+public:
+ JoyAxisHandler(SDL_JoystickID joyid, Uint8 axis, Sint16 min, Sint16 max);
+ bool update(SDL_Event &e);
+ bool pressed();
+ void reset();
+
+private:
+ SDL_JoystickID joyid_;
+ Uint8 axis_;
+ Sint16 min_;
+ Sint16 max_;
+
+ bool pressed_;
+};
+
diff --git a/RetroFE/Source/Control/JoyButtonHandler.cpp b/RetroFE/Source/Control/JoyButtonHandler.cpp
new file mode 100644
index 0000000..ff3e3ed
--- /dev/null
+++ b/RetroFE/Source/Control/JoyButtonHandler.cpp
@@ -0,0 +1,32 @@
+#include "JoyButtonHandler.h"
+
+JoyButtonHandler::JoyButtonHandler(SDL_JoystickID joynum, Uint8 button)
+: joynum_(joynum)
+, button_(button)
+, pressed_(false)
+{
+}
+
+void JoyButtonHandler::reset()
+{
+ pressed_= false;
+}
+
+bool JoyButtonHandler::update(SDL_Event &e)
+{
+ if(e.type != SDL_JOYBUTTONUP && e.type != SDL_JOYBUTTONDOWN) return false;
+
+ if(e.jbutton.which == joynum_ && e.jbutton.button == button_)
+ {
+ pressed_ = (e.type == SDL_JOYBUTTONDOWN) ? true : false;
+ return true;
+ }
+
+ return false;
+}
+
+bool JoyButtonHandler::pressed()
+{
+ return pressed_;
+}
+
diff --git a/RetroFE/Source/Control/JoyButtonHandler.h b/RetroFE/Source/Control/JoyButtonHandler.h
new file mode 100644
index 0000000..adee958
--- /dev/null
+++ b/RetroFE/Source/Control/JoyButtonHandler.h
@@ -0,0 +1,18 @@
+#pragma once
+
+#include "InputHandler.h"
+
+class JoyButtonHandler : public InputHandler
+{
+public:
+ JoyButtonHandler(SDL_JoystickID joynum, Uint8 button);
+ bool update(SDL_Event &e);
+ bool pressed();
+ void reset();
+
+private:
+ SDL_JoystickID joynum_;
+ Uint8 button_;
+ bool pressed_;
+};
+
diff --git a/RetroFE/Source/Control/JoyHatHandler.cpp b/RetroFE/Source/Control/JoyHatHandler.cpp
new file mode 100644
index 0000000..5b8c3c8
--- /dev/null
+++ b/RetroFE/Source/Control/JoyHatHandler.cpp
@@ -0,0 +1,28 @@
+#include "JoyHatHandler.h"
+
+JoyHatHandler::JoyHatHandler(SDL_JoystickID joynum, Uint8 hatnum, Uint8 direction)
+: joynum_(joynum)
+, hatnum_(hatnum)
+, direction_(direction)
+, pressed_(false)
+{
+}
+
+void JoyHatHandler::reset()
+{
+ pressed_= false;
+}
+
+bool JoyHatHandler::update(SDL_Event &e)
+{
+ if(e.type != SDL_JOYHATMOTION || e.jhat.which != joynum_ || e.jhat.hat != hatnum_) return false;
+
+ pressed_ = (e.jhat.value == direction_);
+ return true;
+}
+
+bool JoyHatHandler::pressed()
+{
+ return pressed_;
+}
+
diff --git a/RetroFE/Source/Control/JoyHatHandler.h b/RetroFE/Source/Control/JoyHatHandler.h
new file mode 100644
index 0000000..ad249db
--- /dev/null
+++ b/RetroFE/Source/Control/JoyHatHandler.h
@@ -0,0 +1,19 @@
+#pragma once
+
+#include "InputHandler.h"
+
+class JoyHatHandler : public InputHandler
+{
+public:
+ JoyHatHandler(SDL_JoystickID joynum, Uint8 hatnum, Uint8 direction);
+ bool update(SDL_Event &e);
+ bool pressed();
+ void reset();
+
+private:
+ SDL_JoystickID joynum_;
+ Uint8 hatnum_;
+ Uint8 direction_;
+ bool pressed_;
+};
+
diff --git a/RetroFE/Source/Control/KeyboardHandler.cpp b/RetroFE/Source/Control/KeyboardHandler.cpp
new file mode 100644
index 0000000..e7bb72b
--- /dev/null
+++ b/RetroFE/Source/Control/KeyboardHandler.cpp
@@ -0,0 +1,31 @@
+#include "KeyboardHandler.h"
+
+KeyboardHandler::KeyboardHandler(SDL_Scancode s)
+: scancode_(s)
+, pressed_(false)
+{
+}
+
+void KeyboardHandler::reset()
+{
+ pressed_= false;
+}
+
+bool KeyboardHandler::update(SDL_Event &e)
+{
+ if(e.type != SDL_KEYUP && e.type != SDL_KEYDOWN) return false;
+
+ if(e.key.keysym.scancode == scancode_)
+ {
+ pressed_ = (e.type == SDL_KEYDOWN);
+ return true;
+ }
+
+ return false;
+}
+
+bool KeyboardHandler::pressed()
+{
+ return pressed_;
+}
+
diff --git a/RetroFE/Source/Control/KeyboardHandler.h b/RetroFE/Source/Control/KeyboardHandler.h
new file mode 100644
index 0000000..b49097c
--- /dev/null
+++ b/RetroFE/Source/Control/KeyboardHandler.h
@@ -0,0 +1,17 @@
+#pragma once
+
+#include "InputHandler.h"
+
+class KeyboardHandler : public InputHandler
+{
+public:
+ KeyboardHandler(SDL_Scancode scancode);
+ bool update(SDL_Event &e);
+ bool pressed();
+ void reset();
+
+private:
+ SDL_Scancode scancode_;
+ bool pressed_;
+};
+
diff --git a/RetroFE/Source/Control/MouseButtonHandler.cpp b/RetroFE/Source/Control/MouseButtonHandler.cpp
new file mode 100644
index 0000000..0642ecf
--- /dev/null
+++ b/RetroFE/Source/Control/MouseButtonHandler.cpp
@@ -0,0 +1,31 @@
+#include "MouseButtonHandler.h"
+
+MouseButtonHandler::MouseButtonHandler(Uint8 button)
+: button_(button)
+, pressed_(false)
+{
+}
+
+void MouseButtonHandler::reset()
+{
+ pressed_= false;
+}
+
+bool MouseButtonHandler::update(SDL_Event &e)
+{
+ if(e.type != SDL_MOUSEBUTTONUP && e.type != SDL_MOUSEBUTTONDOWN) return false;
+
+ if(e.button.button == button_)
+ {
+ pressed_ = (e.type == SDL_MOUSEBUTTONDOWN) ? true : false;
+ return true;
+ }
+
+ return false;
+}
+
+bool MouseButtonHandler::pressed()
+{
+ return pressed_;
+}
+
diff --git a/RetroFE/Source/Control/MouseButtonHandler.h b/RetroFE/Source/Control/MouseButtonHandler.h
new file mode 100644
index 0000000..48fa476
--- /dev/null
+++ b/RetroFE/Source/Control/MouseButtonHandler.h
@@ -0,0 +1,17 @@
+#pragma once
+
+#include "InputHandler.h"
+
+class MouseButtonHandler : public InputHandler
+{
+public:
+ MouseButtonHandler(Uint8 button);
+ bool update(SDL_Event &e);
+ bool pressed();
+ void reset();
+
+private:
+ Uint8 button_;
+ bool pressed_;
+};
+
diff --git a/RetroFE/Source/Control/UserInput.cpp b/RetroFE/Source/Control/UserInput.cpp
index a24e2d0..8e5559c 100644
--- a/RetroFE/Source/Control/UserInput.cpp
+++ b/RetroFE/Source/Control/UserInput.cpp
@@ -17,17 +17,35 @@
#include "UserInput.h"
#include "../Database/Configuration.h"
#include "../Utility/Log.h"
+#include "../Utility/Utils.h"
+#include "JoyAxisHandler.h"
+#include "JoyButtonHandler.h"
+#include "JoyHatHandler.h"
+#include "KeyboardHandler.h"
+#include "MouseButtonHandler.h"
UserInput::UserInput(Configuration &c)
- : Config(c)
+ : config_(c)
{
+ for(unsigned int i = 0; i < KeyCodeMax; ++i)
+ {
+ keyHandlers_[i] = NULL;
+ lastKeyState_[i] = false;
+ }
}
UserInput::~UserInput()
{
+ for(std::vector::iterator it = joysticks_.begin(); it != joysticks_.end(); it++)
+ {
+ if(*it)
+ {
+ SDL_JoystickClose(*it);
+ }
+ }
}
-bool UserInput::Initialize()
+bool UserInput::initialize()
{
bool retVal = true;
@@ -59,46 +77,15 @@ bool UserInput::Initialize()
// retVal = MapKey("admin", KeyCodeAdminMode) && retVal;
// retVal = MapKey("remove", KeyCodeHideItem) && retVal;
+ for(int i = 0; i < SDL_NumJoysticks(); ++i)
+ {
+ joysticks_.push_back(SDL_JoystickOpen(i));
+ }
+
+
return retVal;
}
-SDL_Scancode UserInput::GetScancode(KeyCode_E key)
-{
- SDL_Scancode scancode = SDL_SCANCODE_UNKNOWN;
- std::map::iterator it = KeyMap.find(key);
-
- if(it != KeyMap.end())
- {
- scancode = it->second;
- }
-
- return scancode;
-}
-
-
-UserInput::KeyCode_E UserInput::GetKeycode(SDL_Scancode scancode)
-{
- KeyCode_E keycode = KeyCodeNull;
-
- std::map::iterator it = ReverseKeyMap.find(scancode);
-
- if(it != ReverseKeyMap.end())
- {
- keycode = it->second;
- }
-
- return keycode;
-}
-
-void UserInput::ResetKeyStates()
-{
- for(std::map::iterator it = KeyState.begin(); it != KeyState.end(); it++)
- {
- it->second = false;
- }
-}
-
-
bool UserInput::MapKey(std::string keyDescription, KeyCode_E key)
{
SDL_Scancode scanCode;
@@ -106,42 +93,151 @@ bool UserInput::MapKey(std::string keyDescription, KeyCode_E key)
std::string configKey = "controls." + keyDescription;
- if(!Config.GetProperty(configKey, description))
+ if(!config_.getProperty(configKey, description))
{
- Logger::Write(Logger::ZONE_ERROR, "Configuration", "Missing property " + configKey);
+ Logger::write(Logger::ZONE_ERROR, "Input", "Missing property " + configKey);
return false;
}
+
scanCode = SDL_GetScancodeFromName(description.c_str());
- if(scanCode == SDL_SCANCODE_UNKNOWN)
+ if(scanCode != SDL_SCANCODE_UNKNOWN)
{
- Logger::Write(Logger::ZONE_ERROR, "Configuration", "Unsupported property value for " + configKey + "(" + description + "). See Documentation/Keycodes.txt for valid inputs");
- return false;
+ Logger::write(Logger::ZONE_INFO, "Input", "Binding key " + configKey);
+ keyHandlers_[key] = new KeyboardHandler(scanCode);
+ return true;
}
+
+ description = Utils::toLower(description);
- KeyMap[key] = scanCode;
- ReverseKeyMap[scanCode] = key;
- KeyState[key] = false;
- return true;
+ if(description.find("mouse") == 0)
+ {
+ std::string mousedesc = Utils::replace(Utils::toLower(description), "mouse", "");
+ if(mousedesc.find("button") == 0)
+ {
+ int button = 0;
+ std::stringstream ss;
+ mousedesc = Utils::replace(mousedesc, "button", "");
+ if(mousedesc == "left") button = SDL_BUTTON_LEFT;
+ else if(mousedesc == "middle") button = SDL_BUTTON_MIDDLE;
+ else if(mousedesc == "right") button = SDL_BUTTON_RIGHT;
+ else if(mousedesc == "x1") button = SDL_BUTTON_X1;
+ else if(mousedesc == "x2") button = SDL_BUTTON_X2;
+
+ keyHandlers_[key] = new MouseButtonHandler(button);
+ Logger::write(Logger::ZONE_INFO, "Input", "Binding mouse button " + ss.str() );
+ return true;
+ }
+ }
+ else if(description.find("joy") == 0)
+ {
+ std::string joydesc = Utils::replace(Utils::toLower(description), "joy", "");
+ std::stringstream ssjoy;
+ ssjoy << joydesc.at(0);
+ int joynum;
+ ssjoy >> joynum;
+ joydesc = joydesc.erase(0, 1);
+
+
+ if(joydesc.find("button") == 0)
+ {
+ unsigned int button;
+ std::stringstream ss;
+ ss << Utils::replace(joydesc, "button", "");
+ ss >> button;
+ keyHandlers_[key] = new JoyButtonHandler(joynum, button);
+ Logger::write(Logger::ZONE_INFO, "Input", "Binding joypad button " + ss.str() );
+ return true;
+ }
+ else if(joydesc.find("hat") == 0)
+ {
+ Uint8 hat;
+
+ joydesc = Utils::replace(joydesc, "hat", "");
+ std::stringstream sshat;
+ sshat << joydesc.at(0);
+ int hatnum;
+ sshat >> hatnum;
+ joydesc = joydesc.erase(0, 1);
+
+ if(joydesc == "leftup") hat = SDL_HAT_LEFTUP;
+ else if(joydesc == "left") hat = SDL_HAT_LEFT;
+ else if(joydesc == "leftdown") hat = SDL_HAT_LEFTDOWN;
+ else if(joydesc == "up") hat = SDL_HAT_UP;
+ //else if(joydesc == "centered") hat = SDL_HAT_CENTERED;
+ else if(joydesc == "down") hat = SDL_HAT_DOWN;
+ else if(joydesc == "rightup") hat = SDL_HAT_RIGHTUP;
+ else if(joydesc == "right") hat = SDL_HAT_RIGHT;
+ else if(joydesc == "rightdown") hat = SDL_HAT_RIGHTDOWN;
+
+ keyHandlers_[key] = new JoyHatHandler(joynum, hatnum, hat);
+ Logger::write(Logger::ZONE_INFO, "Input", "Binding joypad hat " + joydesc );
+ return true;
+ }
+ else if(joydesc.find("axis") == 0)
+ {
+ // string is now axis0+
+ unsigned int axis;
+ Sint16 min;
+ Sint16 max;
+ joydesc = Utils::replace(joydesc, "axis", "");
+
+ // string is now 0+
+ if(joydesc.find("-") != std::string::npos)
+ {
+ min = -32768;
+ max = -1000;
+ joydesc = Utils::replace(joydesc, "-", "");
+ }
+ else if(joydesc.find("+") != std::string::npos)
+ {
+ min = 1000;
+ max = 32767;
+ joydesc = Utils::replace(joydesc, "+", "");
+ }
+
+ // string is now just the axis number
+ std::stringstream ss;
+ ss << joydesc;
+ ss >> axis;
+ Logger::write(Logger::ZONE_INFO, "Input", "Binding joypad axis " + ss.str() );
+ keyHandlers_[key] = new JoyAxisHandler(joynum, axis, min, max);
+ return true;
+ }
+ }
+ Logger::write(Logger::ZONE_ERROR, "Input", "Unsupported property value for " + configKey + "(" + description + "). See Documentation/Keycodes.txt for valid inputs");
+ return false;
}
-bool UserInput::SetKeyState(SDL_Scancode code, bool state)
+void UserInput::resetStates()
{
- KeyCode_E key = GetKeycode(code);
-
- if(key == KeyCodeNull) { return false; }
- if(KeyState.find(key) == KeyState.end()) { return false; }
-
- KeyState[key] = state;
- return true;
-
+ for(unsigned int i = 0; i < KeyCodeMax; ++i)
+ {
+ if(keyHandlers_[i])
+ {
+ keyHandlers_[i]->reset();
+ }
+ }
}
-bool UserInput::GetKeyState(KeyCode_E key)
+bool UserInput::update(SDL_Event &e)
{
- if(KeyState.find(key) == KeyState.end()) { return false; }
- return KeyState[key];
+ bool updated = false;
+ for(unsigned int i = 0; i < KeyCodeMax; ++i)
+ {
+ InputHandler *h = keyHandlers_[i];
+ if(h)
+ {
+ if(h->update(e)) updated = true;
+
+ lastKeyState_[i] = h->pressed();
+ }
+ }
+
+ return updated;
}
-
-
+bool UserInput::keystate(KeyCode_E code)
+{
+ return lastKeyState_[code];
+}
diff --git a/RetroFE/Source/Control/UserInput.h b/RetroFE/Source/Control/UserInput.h
index 0fe7840..610c995 100644
--- a/RetroFE/Source/Control/UserInput.h
+++ b/RetroFE/Source/Control/UserInput.h
@@ -14,11 +14,14 @@
* along with RetroFE. If not, see .
*/
#pragma once
-#include