/*
* Copyright (C) 2005-2013 Team XBMC
* http://xbmc.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with XBMC; see the file COPYING. If not, see
* .
*
*/
#include "system.h"
#include "input/KeyboardLayoutConfiguration.h"
#include "utils/CharsetConverter.h"
#include "utils/log.h"
// Comment OUT, if not really debugging!!!
//#define DEBUG_KEYBOARD_GETCHAR
using namespace std;
CKeyboardLayoutConfiguration g_keyboardLayoutConfiguration;
CKeyboardLayoutConfiguration::CKeyboardLayoutConfiguration()
{
SetDefaults();
}
CKeyboardLayoutConfiguration::~CKeyboardLayoutConfiguration()
{
SetDefaults();
}
void CKeyboardLayoutConfiguration::SetDefaults()
{
m_changeXbmcCharRegardlessModifiers.clear();
m_changeXbmcCharWithRalt.clear();
m_deriveXbmcCharFromVkeyRegardlessModifiers.clear();
m_deriveXbmcCharFromVkeyWithShift.clear();
m_deriveXbmcCharFromVkeyWithRalt.clear();
}
bool CKeyboardLayoutConfiguration::Load(const CStdString& strFileName)
{
SetDefaults();
TiXmlDocument xmlDoc;
if (!xmlDoc.LoadFile(strFileName))
{
CLog::Log(LOGINFO, "unable to load %s: %s at line %d", strFileName.c_str(), xmlDoc.ErrorDesc(), xmlDoc.ErrorRow());
return false;
}
TiXmlElement* pRootElement = xmlDoc.RootElement();
CStdString strValue = pRootElement->Value();
if (strValue != CStdString("keyboard_layout"))
{
CLog::Log(LOGERROR, "%s Doesn't contain ", strFileName.c_str());
return false;
}
CLog::Log(LOGDEBUG, "reading char2char ");
const TiXmlElement* pMapChangeXbmcCharRegardlessModifiers = pRootElement->FirstChildElement("char2char");
readCharMapFromXML(pMapChangeXbmcCharRegardlessModifiers, m_changeXbmcCharRegardlessModifiers, ("char2char"));
CLog::Log(LOGDEBUG, "reading char2char_ralt ");
const TiXmlElement* pMapChangeXbmcCharWithRalt = pRootElement->FirstChildElement("char2char_ralt");
readCharMapFromXML(pMapChangeXbmcCharWithRalt, m_changeXbmcCharWithRalt, ("char2char_ralt"));
CLog::Log(LOGDEBUG, "reading vkey2char ");
const TiXmlElement* pMapDeriveXbmcCharFromVkeyRegardlessModifiers = pRootElement->FirstChildElement("vkey2char");
readByteMapFromXML(pMapDeriveXbmcCharFromVkeyRegardlessModifiers, m_deriveXbmcCharFromVkeyRegardlessModifiers, ("vkey2char"));
CLog::Log(LOGDEBUG, "reading vkey2char_shift ");
const TiXmlElement* pMapDeriveXbmcCharFromVkeyWithShift = pRootElement->FirstChildElement("vkey2char_shift");
readByteMapFromXML(pMapDeriveXbmcCharFromVkeyWithShift, m_deriveXbmcCharFromVkeyWithShift, ("vkey2char_shift"));
CLog::Log(LOGDEBUG, "reading vkey2char_ralt ");
const TiXmlElement* pMapDeriveXbmcCharFromVkeyWithRalt = pRootElement->FirstChildElement("vkey2char_ralt");
readByteMapFromXML(pMapDeriveXbmcCharFromVkeyWithRalt, m_deriveXbmcCharFromVkeyWithRalt, ("vkey2char_ralt"));
return true;
}
void CKeyboardLayoutConfiguration::readCharMapFromXML(const TiXmlElement* pXMLMap, map& charToCharMap, const char* mapRootElement)
{
if (pXMLMap && !pXMLMap->NoChildren())
{ // map keys
const TiXmlElement* pEntry = pXMLMap->FirstChildElement();
while (pEntry)
{
CStdString strInChar = pEntry->Attribute("inchar");
CStdString strOutChar = pEntry->Attribute("outchar");
if (strInChar.length() > 0 && strOutChar.length() > 0)
{
CStdStringW fromStr;
g_charsetConverter.utf8ToW(strInChar, fromStr);
CStdStringW toStr;
g_charsetConverter.utf8ToW(strOutChar, toStr);
if (fromStr.size()==1 && toStr.size()==1)
{
charToCharMap.insert(pair(fromStr[0], toStr[0]));
CLog::Log(LOGDEBUG, "insert map entry from %c to %c ", fromStr[0], toStr[0]);
}
else
{
CLog::Log(LOGERROR, "String from %ls or to %ls does not have the expected length of 1", fromStr.c_str(), toStr.c_str());
}
}
else
{
CLog::Log(LOGERROR, "map entry misses attribute or or content of them");
}
pEntry = pEntry->NextSiblingElement();
}
}
else
{
CLog::Log(LOGDEBUG, "XML-Configuration doesn't contain expected map root element %s", mapRootElement);
}
}
void CKeyboardLayoutConfiguration::readByteMapFromXML(const TiXmlElement* pXMLMap, map& charToCharMap, const char* mapRootElement)
{
if (pXMLMap && !pXMLMap->NoChildren())
{ // map keys
const TiXmlElement* pEntry = pXMLMap->FirstChildElement();
while (pEntry)
{
CStdString strInHex = pEntry->Attribute("inhex");
CStdString strOutChar = pEntry->Attribute("outchar");
if (strInHex.length() > 0 && strOutChar.length() > 0)
{
CStdString hexValue = strInHex;
CStdStringW toStr;
g_charsetConverter.utf8ToW(strOutChar, toStr);
int from;
if (sscanf(hexValue.c_str(), "%x", (unsigned int *)&from))
{
if (from != 0) // eats nearly any typing error as 0: catch it:
{
if (from < 256)
{
if (toStr.size()==1)
{
charToCharMap.insert(pair(from, toStr[0]));
CLog::Log(LOGDEBUG, "insert map entry from %d to %c ", from, toStr[0]);
}
else
{
CLog::Log(LOGERROR, "String to %ls does not have the expected length of >=1", toStr.c_str());
}
}
else
{
CLog::Log(LOGERROR, "From value %d was greater than 255! ", from);
}
}
else
{
CLog::Log(LOGERROR, "Scanned from-value %d as 0 probably a (typing?) error! ", from);
}
}
else
{
CLog::Log(LOGERROR, "Could not scan from-value %s (was no valid hex value) ", hexValue.c_str());
}
}
else
{
CLog::Log(LOGERROR, "map entry misses attribute or or content of them");
}
pEntry = pEntry->NextSiblingElement();
}
}
else
{
CLog::Log(LOGERROR, "XML-Configuration doesn't contain expected map root element %s", mapRootElement);
}
}
bool CKeyboardLayoutConfiguration::containsChangeXbmcCharRegardlessModifiers(WCHAR key)
{
bool result = m_changeXbmcCharRegardlessModifiers.find(key) != m_changeXbmcCharRegardlessModifiers.end();
#ifdef DEBUG_KEYBOARD_GETCHAR
CLog::Log(LOGDEBUG, "found containsChangeXbmcCharRegardlessModifiers key char %c: bool: %d ", key, result);
#endif
return result;
}
bool CKeyboardLayoutConfiguration::containsChangeXbmcCharWithRalt(WCHAR key)
{
bool result = m_changeXbmcCharWithRalt.find(key) != m_changeXbmcCharWithRalt.end();
#ifdef DEBUG_KEYBOARD_GETCHAR
CLog::Log(LOGDEBUG, "found containsChangeXbmcCharWithRalt key char %c: bool: %d ", key, result);
#endif
return result;
}
bool CKeyboardLayoutConfiguration::containsDeriveXbmcCharFromVkeyRegardlessModifiers(BYTE key)
{
bool result = m_deriveXbmcCharFromVkeyRegardlessModifiers.find(key) != m_deriveXbmcCharFromVkeyRegardlessModifiers.end();
#ifdef DEBUG_KEYBOARD_GETCHAR
CLog::Log(LOGDEBUG, "found containsDeriveXbmcCharFromVkeyRegardlessModifiers key vkey %d: bool: %d ", key, result);
#endif
return result;
}
bool CKeyboardLayoutConfiguration::containsDeriveXbmcCharFromVkeyWithShift(BYTE key)
{
bool result = m_deriveXbmcCharFromVkeyWithShift.find(key) != m_deriveXbmcCharFromVkeyWithShift.end();
#ifdef DEBUG_KEYBOARD_GETCHAR
CLog::Log(LOGDEBUG, "found containsDeriveXbmcCharFromVkeyWithShift key vkey %d: bool: %d ", key, result);
#endif
return result;
}
bool CKeyboardLayoutConfiguration::containsDeriveXbmcCharFromVkeyWithRalt(BYTE key)
{
bool result = m_deriveXbmcCharFromVkeyWithRalt.find(key) != m_deriveXbmcCharFromVkeyWithRalt.end();
#ifdef DEBUG_KEYBOARD_GETCHAR
CLog::Log(LOGDEBUG, "found containsDeriveXbmcCharFromVkeyWithRalt key vkey %d: bool: %d ", key, result);
#endif
return result;
}
WCHAR CKeyboardLayoutConfiguration::valueOfChangeXbmcCharRegardlessModifiers(WCHAR key)
{
WCHAR result = (m_changeXbmcCharRegardlessModifiers.find(key))->second;
#ifdef DEBUG_KEYBOARD_GETCHAR
CLog::Log(LOGDEBUG, "found valueOfChangeXbmcCharRegardlessModifiers for char key %c: char %c ", key, result);
#endif
return result;
}
WCHAR CKeyboardLayoutConfiguration::valueOfChangeXbmcCharWithRalt(WCHAR key)
{
WCHAR result = (m_changeXbmcCharWithRalt.find(key))->second;
#ifdef DEBUG_KEYBOARD_GETCHAR
CLog::Log(LOGDEBUG, "found valueOfChangeXbmcCharWithRalt for char key %c: char %c ", key, result);
#endif
return result;
}
WCHAR CKeyboardLayoutConfiguration::valueOfDeriveXbmcCharFromVkeyRegardlessModifiers(BYTE key)
{
WCHAR result = (m_deriveXbmcCharFromVkeyRegardlessModifiers.find(key))->second;
#ifdef DEBUG_KEYBOARD_GETCHAR
CLog::Log(LOGDEBUG, "found valueOfDeriveXbmcCharFromVkeyRegardlessModifiers for key vkey %d: char %c ", key, result);
#endif
return result;
}
WCHAR CKeyboardLayoutConfiguration::valueOfDeriveXbmcCharFromVkeyWithShift(BYTE key)
{
WCHAR result = (m_deriveXbmcCharFromVkeyWithShift.find(key))->second;
#ifdef DEBUG_KEYBOARD_GETCHAR
CLog::Log(LOGDEBUG, "found valueOfDeriveXbmcCharFromVkeyWithShift for key vkey %d: char %c ", key, result);
#endif
return result;
}
WCHAR CKeyboardLayoutConfiguration::valueOfDeriveXbmcCharFromVkeyWithRalt(BYTE key)
{
WCHAR result = (m_deriveXbmcCharFromVkeyWithRalt.find(key))->second;
#ifdef DEBUG_KEYBOARD_GETCHAR
CLog::Log(LOGDEBUG, "found valueOfDeriveXbmcCharFromVkeyWithRalt for key vkey %d: char %c ", key, result);
#endif
return result;
}