Skip to content

Commit

Permalink
Merge pull request xbmc#5624 from zzattack/keymaps
Browse files Browse the repository at this point in the history
[buttontranslator] Group joystick keymaps by family
  • Loading branch information
MartijnKaijser committed Feb 10, 2015
2 parents 48a6862 + 623e3b5 commit e82d519
Show file tree
Hide file tree
Showing 10 changed files with 293 additions and 1,215 deletions.
1,269 changes: 157 additions & 1,112 deletions system/keymaps/joystick.Microsoft.Xbox.360.Controller.xml

Large diffs are not rendered by default.

3 changes: 0 additions & 3 deletions xbmc/Application.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -911,9 +911,6 @@ bool CApplication::CreateGUI()
if (!CButtonTranslator::GetInstance().Load())
return false;

//Initialize sdl joystick if available
CInputManager::GetInstance().InitializeInputs();

RESOLUTION_INFO info = g_graphicsContext.GetResInfo();
CLog::Log(LOGINFO, "GUI format %ix%i, Display %s",
info.iWidth,
Expand Down
165 changes: 116 additions & 49 deletions xbmc/input/ButtonTranslator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -652,7 +652,9 @@ bool CButtonTranslator::LoadKeymap(const std::string &keymapPath)
const char *szWindow = pWindow->Value();
if (szWindow)
{
if (strcmpi(szWindow, "global") == 0)
if (strcmpi(szWindow, "joystickFamily") == 0)
MapJoystickFamily(pWindow);
else if (strcmpi(szWindow, "global") == 0)
windowID = -1;
else
windowID = TranslateWindow(szWindow);
Expand Down Expand Up @@ -760,29 +762,84 @@ int CButtonTranslator::TranslateLircRemoteString(const char* szDevice, const cha
}

#if defined(HAS_SDL_JOYSTICK) || defined(HAS_EVENT_SERVER)
void CButtonTranslator::MapJoystickFamily(TiXmlNode *pNode)
{
TiXmlElement *pFamily = pNode->ToElement();
if (pFamily && pFamily->Attribute("name"))
{
std::string joyFamilyName = pFamily->Attribute("name");
JoystickFamily* joyFamily = &m_joystickFamilies[joyFamilyName];

TiXmlElement *pMember = pFamily->FirstChildElement();
while (pMember)
{
TiXmlNode* pName = pMember->FirstChild();
if (pName && pName->ValueStr() != "") {
boost::shared_ptr<CRegExp> re(new CRegExp(true, CRegExp::asciiOnly));
std::string joyRe = JoynameToRegex(pName->ValueStr());
if (!re->RegComp(joyRe, CRegExp::StudyRegExp))
{
CLog::Log(LOGNOTICE, "Invalid joystick regex specified: '%s'", pName->Value());
continue;
}
AddFamilyRegex(joyFamily, re);
}
pMember = pMember->NextSiblingElement();
}
}
else
{
CLog::Log(LOGNOTICE, "Ignoring nameless joystick family");
}
}

void CButtonTranslator::MapJoystickActions(int windowID, TiXmlNode *pJoystick)
{
string joyname = JOYSTICK_DEFAULT_MAP; // default global map name
vector<boost::shared_ptr<CRegExp> > joynames;
std::string joyFamilyName;
map<int, string> buttonMap;
map<int, string> axisMap;
AxesConfig axesConfig;
ActionMap hatMap;

TiXmlElement *pJoy = pJoystick->ToElement();
if (pJoy && pJoy->Attribute("name"))
joyname = pJoy->Attribute("name");
if (pJoy && pJoy->Attribute("name")) {
// transform loose name to new family, including altnames
std::string joyName = pJoy->Attribute("name");
joyFamilyName = joyName;
JoystickFamily* joyFamily = &m_joystickFamilies[joyFamilyName];

boost::shared_ptr<CRegExp> re(new CRegExp(true, CRegExp::asciiOnly));
std::string joyRe = JoynameToRegex(joyname);
if (!re->RegComp(joyRe, CRegExp::StudyRegExp))
{
CLog::Log(LOGNOTICE, "Invalid joystick regex specified: '%s'", joyname.c_str());
return;
}
AddFamilyRegex(joyFamily, re);

// add altnames to family
TiXmlElement *pNode = pJoystick->FirstChildElement();
while (pNode) {
const std::string &type = pNode->ValueStr();
if (type == "altname") {
std::string altName = pNode->FirstChild()->ValueStr();
boost::shared_ptr<CRegExp> altRe(new CRegExp(true, CRegExp::asciiOnly));
std::string altReStr = JoynameToRegex(altName);
if (!altRe->RegComp(altReStr, CRegExp::StudyRegExp))
CLog::Log(LOGNOTICE, "Ignoring invalid joystick altname regex: '%s'", altReStr.c_str());
else
AddFamilyRegex(joyFamily, altRe);
}
pNode = pNode->NextSiblingElement();
}

}
else if (pJoy && pJoy->Attribute("family"))
joyFamilyName = pJoy->Attribute("family");
else
CLog::Log(LOGNOTICE, "No Joystick name specified, loading default map");

boost::shared_ptr<CRegExp> re(new CRegExp(true, CRegExp::asciiOnly));
if (!re->RegComp(JoynameToRegex(joyname), CRegExp::StudyRegExp))
{
CLog::Log(LOGNOTICE, "Invalid joystick regex specified: '%s'", joyname.c_str());
return;
}
else
joynames.push_back(re);

// parse map
TiXmlElement *pButton = pJoystick->FirstChildElement();
Expand Down Expand Up @@ -856,30 +913,16 @@ void CButtonTranslator::MapJoystickActions(int windowID, TiXmlNode *pJoystick)
else
CLog::Log(LOGERROR, "Error reading joystick map element, unknown button type: %s", type.c_str());
}
else if (type == "altname")
{
boost::shared_ptr<CRegExp> altRe(new CRegExp(true, CRegExp::asciiOnly));
if (!altRe->RegComp(JoynameToRegex(action), CRegExp::StudyRegExp))
CLog::Log(LOGNOTICE, "Ignoring invalid joystick altname regex: '%s'", action.c_str());
else
joynames.push_back(altRe);
}
else
CLog::Log(LOGERROR, "Error reading joystick map element, Invalid id: %d", id);

pButton = pButton->NextSiblingElement();
}
vector<boost::shared_ptr<CRegExp> >::iterator it = joynames.begin();
while (it!=joynames.end())
{
MergeMap(*it, &m_joystickButtonMap, windowID, buttonMap);
MergeMap(*it, &m_joystickAxisMap, windowID, axisMap);
MergeMap(*it, &m_joystickHatMap, windowID, hatMap);
if (windowID == -1)
m_joystickAxesConfigs[*it] = axesConfig;
// CLog::Log(LOGDEBUG, "Found Joystick map for window %d using %s", windowID, it->c_str());
++it;
}
m_joystickButtonMap[joyFamilyName][windowID].insert(buttonMap.begin(), buttonMap.end());
m_joystickAxisMap[joyFamilyName][windowID].insert(axisMap.begin(), axisMap.end());
m_joystickHatMap[joyFamilyName][windowID].insert(hatMap.begin(), hatMap.end());
if (windowID == -1)
m_joystickAxesConfigs[joyFamilyName] = axesConfig;
}

std::string CButtonTranslator::JoynameToRegex(const std::string& joyName) const
Expand All @@ -895,34 +938,58 @@ std::string CButtonTranslator::JoynameToRegex(const std::string& joyName) const
return "\\Q" + joyName + "\\E";
}

void CButtonTranslator::MergeMap(boost::shared_ptr<CRegExp> joyName, JoystickMap *joystick, int windowID, const ActionMap &map)
bool CButtonTranslator::AddFamilyRegex(JoystickFamily* family, boost::shared_ptr<CRegExp> regex)
{
// find or create WindowMap entry, match on pattern equality
JoystickMap::iterator jit;
for (jit = joystick->begin(); jit != joystick->end(); ++jit)
// even though family is a set, this does not prevent the same regex
// from being added twice, so we manually match on pattern equality
JoystickFamily::iterator it;
for (it = family->begin(); it != family->end(); it++)
{
if (jit->first->GetPattern() == joyName->GetPattern())
break;
if ((*it)->GetPattern() == regex->GetPattern())
return false;
}
family->insert(regex);
return true;
}

const AxesConfig* CButtonTranslator::GetAxesConfigFor(const std::string& joyName) const
{
JoystickFamilyMap::const_iterator familyIt = FindJoystickFamily(joyName);
if (familyIt == m_joystickFamilies.end())
return NULL;
else {
std::map<std::string, AxesConfig>::const_iterator it = m_joystickAxesConfigs.find(familyIt->first);
if (it == m_joystickAxesConfigs.end())
return NULL;
else
return &it->second;
}
WindowMap *w = (jit == joystick->end()) ? &(*joystick)[joyName] : &jit->second;

// find or create ActionMap, and merge/overwrite new entries
ActionMap *a = &(*w)[windowID];
for (ActionMap::const_iterator it = map.begin(); it != map.end(); ++it)
(*a)[it->first] = it->second;
}

CButtonTranslator::JoystickMap::const_iterator CButtonTranslator::FindWindowMap(const std::string& joyName, const JoystickMap &maps) const
{
JoystickMap::const_iterator it;
for (it = maps.begin(); it != maps.end(); ++it)
JoystickFamilyMap::const_iterator familyIt = FindJoystickFamily(joyName);
if (familyIt == m_joystickFamilies.end())
return maps.end();
else
return maps.find(familyIt->first);
}

CButtonTranslator::JoystickFamilyMap::const_iterator CButtonTranslator::FindJoystickFamily(const std::string& joyName) const
{
// find the family corresponding to a joystick name
JoystickFamilyMap::const_iterator it;
for (it = m_joystickFamilies.begin(); it != m_joystickFamilies.end(); it++)
{
if (it->first->RegFind(joyName) >= 0)
JoystickFamily::const_iterator regexIt;
for (regexIt = it->second.begin(); regexIt != it->second.end(); regexIt++)
{
// CLog::Log(LOGDEBUG, "Regex %s matches joystick %s", it->first->GetPattern().c_str(), joyName.c_str());
break;
if ((*regexIt)->RegFind(joyName) >= 0)
{
// CLog::Log(LOGDEBUG, "Regex %s matches joystick %s", it->first->GetPattern().c_str(), joyName.c_str());
return it;
}
}
// CLog::Log(LOGDEBUG, "No match: %s for joystick %s", it->first->GetPattern().c_str(), joyName.c_str());
}
return it;
}
Expand Down
19 changes: 13 additions & 6 deletions xbmc/input/ButtonTranslator.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include <map>
#include <string>
#include <vector>
#include <set>
#include "system.h" // for HAS_EVENT_SERVER, HAS_SDL_JOYSTICK

#ifdef HAS_EVENT_SERVER
Expand Down Expand Up @@ -99,7 +100,7 @@ class CButtonTranslator
short inputType, int& action, std::string& strAction,
bool &fullrange);

const std::map<boost::shared_ptr<CRegExp>, AxesConfig>& GetAxesConfigs() { return m_joystickAxesConfigs; };
const AxesConfig* GetAxesConfigFor(const std::string& joyName) const;
#endif

bool TranslateTouchAction(int window, int touchAction, int touchPointers, int &action);
Expand All @@ -115,9 +116,11 @@ class CButtonTranslator
int GetActionCode(int window, int action);
int GetActionCode(int window, const CKey &key, std::string &strAction) const;
#if defined(HAS_SDL_JOYSTICK) || defined(HAS_EVENT_SERVER)
typedef std::set<boost::shared_ptr<CRegExp> > JoystickFamily;
typedef std::map<std::string, JoystickFamily> JoystickFamilyMap;
typedef std::map<int, std::string> ActionMap; // <button/axis, action>
typedef std::map<int, ActionMap > WindowMap; // <window, actionMap>
typedef std::map<boost::shared_ptr<CRegExp>, WindowMap> JoystickMap; // <joystick, windowMap>
typedef std::map<std::string, WindowMap> JoystickMap; // <family name, windowMap>
int GetActionCode(int window, int id, const WindowMap &wmap, std::string &strAction, bool &fullrange) const;
#endif
int GetFallbackWindow(int windowID);
Expand Down Expand Up @@ -146,14 +149,18 @@ class CButtonTranslator
std::map<std::string, lircButtonMap*> lircRemotesMap;

#if defined(HAS_SDL_JOYSTICK) || defined(HAS_EVENT_SERVER)
void MapJoystickFamily(TiXmlNode *pFamily);
void MapJoystickActions(int windowID, TiXmlNode *pJoystick);
std::string JoynameToRegex(const std::string& joyName) const;
bool AddFamilyRegex(JoystickFamily* family, boost::shared_ptr<CRegExp> regex);
void MergeMap(boost::shared_ptr<CRegExp> joyName, JoystickMap *joystick, int windowID, const ActionMap &actionMap);
JoystickMap::const_iterator FindWindowMap(const std::string& joyName, const JoystickMap &maps) const;
JoystickMap m_joystickButtonMap; // <joy name, button map>
JoystickMap m_joystickAxisMap; // <joy name, axis map>
JoystickMap m_joystickHatMap; // <joy name, hat map>
std::map<boost::shared_ptr<CRegExp>, AxesConfig> m_joystickAxesConfigs; // <joy name, axes config>
JoystickFamilyMap::const_iterator FindJoystickFamily(const std::string& joyName) const;
JoystickFamilyMap m_joystickFamilies;
JoystickMap m_joystickButtonMap; // <joy family, button map>
JoystickMap m_joystickAxisMap; // <joy family, axis map>
JoystickMap m_joystickHatMap; // <joy family, hat map>
std::map<std::string, AxesConfig> m_joystickAxesConfigs; // <joy family, axes config>
#endif

void MapTouchActions(int windowID, TiXmlNode *pTouch);
Expand Down
8 changes: 0 additions & 8 deletions xbmc/input/InputManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,14 +73,6 @@ CInputManager& CInputManager::GetInstance()
return inputManager;
}

void CInputManager::InitializeInputs()
{
#ifdef HAS_SDL_JOYSTICK
// Pass the mapping of axis to triggers to m_Joystick
m_Joystick.LoadAxesConfigs(CButtonTranslator::GetInstance().GetAxesConfigs());
#endif
}

void CInputManager::ReInitializeJoystick()
{
#ifdef HAS_SDL_JOYSTICK
Expand Down
5 changes: 0 additions & 5 deletions xbmc/input/InputManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,11 +79,6 @@ class CInputManager
*/
bool ProcessPeripherals(float frameTime);

/*!
* \brief Call once during application startup to initialize peripherals that need it
*/
void InitializeInputs();

void SetEnabledJoystick(bool enabled = true);

void ReInitializeJoystick();
Expand Down
18 changes: 4 additions & 14 deletions xbmc/input/SDLJoystick.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

#include "system.h"
#include "SDLJoystick.h"
#include "input/ButtonTranslator.h"
#include "peripherals/devices/PeripheralImon.h"
#include "settings/AdvancedSettings.h"
#include "settings/lib/Setting.h"
Expand Down Expand Up @@ -406,28 +407,17 @@ bool CJoystick::Reinitialize()
return true;
}

void CJoystick::LoadAxesConfigs(const std::map<boost::shared_ptr<CRegExp>, AxesConfig> &axesConfigs)
{
m_AxesConfigs.clear();
m_AxesConfigs.insert(axesConfigs.begin(), axesConfigs.end());
}

void CJoystick::ApplyAxesConfigs()
{
// load axes configuration from keymap
int axesCount = 0;
for (std::map<int, SDL_Joystick*>::const_iterator it = m_Joysticks.begin(); it != m_Joysticks.end(); ++it)
{
std::string joyName(SDL_JoystickName(it->second));
std::map<boost::shared_ptr<CRegExp>, AxesConfig>::const_iterator axesCfg;
for (axesCfg = m_AxesConfigs.begin(); axesCfg != m_AxesConfigs.end(); ++axesCfg)
{
if (axesCfg->first->RegFind(joyName) >= 0)
break;
}
if (axesCfg != m_AxesConfigs.end())
const AxesConfig* axesCfg = CButtonTranslator::GetInstance().GetAxesConfigFor(joyName);
if (axesCfg != NULL)
{
for (AxesConfig::const_iterator it = axesCfg->second.begin(); it != axesCfg->second.end(); ++it)
for (AxesConfig::const_iterator it = axesCfg->begin(); it != axesCfg->end(); ++it)
{
int axis = axesCount + it->axis - 1;
m_Axes[axis].trigger = it->isTrigger;
Expand Down
2 changes: 0 additions & 2 deletions xbmc/input/SDLJoystick.h
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,6 @@ class CJoystick : public ISettingCallback
float SetDeadzone(float val);
bool Reinitialize();
typedef std::vector<AxisConfig> AxesConfig; // [<axis, isTrigger, rest state value>]
void LoadAxesConfigs(const std::map<boost::shared_ptr<CRegExp>, AxesConfig>& axesConfigs);
void ApplyAxesConfigs();

private:
Expand Down Expand Up @@ -120,7 +119,6 @@ class CJoystick : public ISettingCallback
uint32_t m_pressTicksButton;
uint32_t m_pressTicksHat;
std::map<int, SDL_Joystick*> m_Joysticks;
std::map<boost::shared_ptr<CRegExp>, AxesConfig> m_AxesConfigs; // <joy, <axis num, isTrigger, restState> >
};

#endif
Expand Down
17 changes: 3 additions & 14 deletions xbmc/input/windows/WINJoystick.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -139,15 +139,10 @@ BOOL CALLBACK CJoystick::EnumJoysticksCallback( const DIDEVICEINSTANCE* pdidInst
p_this->m_devCaps.push_back(diDevCaps);

// load axes configuration from keymap
std::map<boost::shared_ptr<CRegExp>, AxesConfig>::const_iterator axesCfg;
for (axesCfg = p_this->m_AxesConfigs.begin(); axesCfg != p_this->m_AxesConfigs.end(); ++axesCfg)
const AxesConfig* axesCfg = CButtonTranslator::GetInstance().GetAxesConfigFor(joyName);
if (axesCfg != NULL)
{
if (axesCfg->first->RegFind(joyName) >= 0)
break;
}
if (axesCfg != p_this->m_AxesConfigs.end())
{
for (AxesConfig::const_iterator it = axesCfg->second.begin(); it != axesCfg->second.end(); ++it)
for (AxesConfig::const_iterator it = axesCfg->begin(); it != axesCfg->end(); ++it)
{
int axis = p_this->MapAxis(pJoystick, it->axis - 1);
p_this->m_Axes[axis].trigger = it->isTrigger;
Expand Down Expand Up @@ -521,12 +516,6 @@ void CJoystick::Acquire()
}
}

void CJoystick::LoadAxesConfigs(const std::map<boost::shared_ptr<CRegExp>, AxesConfig> &axesConfigs)
{
m_AxesConfigs.clear();
m_AxesConfigs.insert(axesConfigs.begin(), axesConfigs.end());
}

int CJoystick::JoystickIndex(const std::string &joyName) const
{
for (size_t i = 0; i < m_JoystickNames.size(); ++i)
Expand Down
Loading

0 comments on commit e82d519

Please sign in to comment.