鼠标键盘xml动作文件的加载过程

在xbmc初次启动中我们说到CApplication::CreateGUI()中的加载按键定义文件,这里我们拿keyboard.xml举例

bool CButtonTranslator::Load(bool AlwaysLoad)
{
  m_translatorMap.clear();

  // Directories to search for keymaps. They're applied in this order,
  // so keymaps in profile/keymaps/ override e.g. system/keymaps
  static const char* DIRS_TO_CHECK[] = {
    "special://xbmc/system/keymaps/","special://masterprofile/keymaps/","special://profile/keymaps/"
  };
  for (unsigned int dirIndex = 0; dirIndex < ARRAY_SIZE(DIRS_TO_CHECK); ++dirIndex)
  {
    if (XFILE::CDirectory::Exists(DIRS_TO_CHECK[dirIndex]))
    {
      CFileItemList files;
      XFILE::CDirectory::GetDirectory(DIRS_TO_CHECK[dirIndex],files,".xml");
      // Sort the list for filesystem based priorities,e.g. 01-keymap.xml,02-keymap-overrides.xml
      files.Sort(SortByFile,SortOrderAscending);
      for(int fileIndex = 0; fileIndex<files.Size(); ++fileIndex)
      {
        if (!files[fileIndex]->m_bIsFolder)
          success |= LoadKeymap(files[fileIndex]->GetPath());
      }

      // Load mappings for any HID devices we have connected
      std::list<std::string>::iterator it;
      for (it = m_deviceList.begin(); it != m_deviceList.end(); it++)
      {
        std::string devicedir = DIRS_TO_CHECK[dirIndex];
        devicedir.append(*it);
        devicedir.append("/");
        if( XFILE::CDirectory::Exists(devicedir) )
        {
          CFileItemList files;
          XFILE::CDirectory::GetDirectory(devicedir,".xml");
          // Sort the list for filesystem based priorities,02-keymap-overrides.xml
          files.Sort(SortByFile,SortOrderAscending);
          for(int fileIndex = 0; fileIndex<files.Size(); ++fileIndex)
          {
            if (!files[fileIndex]->m_bIsFolder)
              success |= LoadKeymap(files[fileIndex]->GetPath());
          }
        }
      }
    }
  }
}

接下来我们分析具体的加载keyboard.xml的加载,我们启动xbmc中会有这样的启动语句Debug Print: Loading special://xbmc/system/keymaps/keyboard.xml,就是在下面这个函数中输出的。

bool CButtonTranslator::LoadKeymap(const std::string &keymapPath)
{
  CXBMCTinyXML xmlDoc;

  CLog::Log(LOGINFO,"Loading %s",keymapPath.c_str());
  ...
  TiXmlElement* pRoot = xmlDoc.RootElement();
  std::string strValue = pRoot->Value(); //这个是xml头节点,应该为keymap
  ...
  // run through our window groups
  TiXmlNode* pWindow = pRoot->FirstChild();
  while (pWindow)
  {
    if (pWindow->Type() == TiXmlNode::TINYXML_ELEMENT)
    {
      int windowID = WINDOW_INVALID;
      const char *szWindow = pWindow->Value();
      if (szWindow)
      {
        if (strcmpi(szWindow,"global") == 0)   //如果节点名为global,设置windowID即窗口值为-1
          windowID = -1;
        else
          windowID = TranslateWindow(szWindow);
      }
      MapWindowActions(pWindow,windowID);
    }
    pWindow = pWindow->NextSibling();   //再读取下一个节点
  }

  return true;
}

接下来我们看一下MapWindowActions的读取

void CButtonTranslator::MapWindowActions(TiXmlNode *pWindow,int windowID)
{
  TiXmlNode* pDevice;

  const char* types[] = {"gamepad","remote","universalremote","keyboard","mouse","appcommand",NULL};
  for (int i = 0; types[i]; ++i)    //我们专门分析keyboard,即types[3]值为情况
  {
    std::string type(types[i]);
    if (HasDeviceType(pWindow,type))
    {
      buttonMap map;
      std::map<int,buttonMap>::iterator it = m_translatorMap.find(windowID);   //看translatorMap是否存在windowID的键值定义
      if (it != m_translatorMap.end())  //如果存在那么删除它
      {
        map = it->second;
        m_translatorMap.erase(it);
      }

      pDevice = pWindow->FirstChild(type);//从pWindow中查找keyboard关键词来作为设备标示

      TiXmlElement *pButton = pDevice->FirstChildElement();

      while (pButton)
      {
        uint32_t buttonCode=0;
        if (type == "gamepad")
            buttonCode = TranslateGamepadString(pButton->Value());
    ...
        else if (type == "keyboard")
            buttonCode = TranslateKeyboardButton(pButton);
    ...
        else if (type == "appcommand")
            buttonCode = TranslateAppCommand(pButton->Value());

        if (buttonCode && pButton->FirstChild())
          MapAction(buttonCode,pButton->FirstChild()->Value(),map);
        pButton = pButton->NextSiblingElement();
      }

      // add our map to our table
      if (!map.empty())
        m_translatorMap.insert(pair<int,buttonMap>( windowID,map));
    }
  }
  ...
}

我们分析keyboard.xml中的一条VolumeUp

uint32_t CButtonTranslator::TranslateKeyboardButton(TiXmlElement *pButton)
{
  uint32_t button_id = 0;
  const char *szButton = pButton->Value(); //szButton值为plus

  if (!szButton) 
    return 0;
  const std::string strKey = szButton;
  if (strKey == "key")
  {
   ...
  }
  else
    button_id = TranslateKeyboardString(szButton);
  ....
  return button_id;
}

到这里szButton是plus

uint32_t CButtonTranslator::TranslateKeyboardString(const char *szButton)
{
  uint32_t buttonCode = 0;
  XBMCKEYTABLE keytable;

  // Look up the key name
  if (KeyTableLookupName(szButton,&keytable))
  {
    buttonCode = keytable.vkey;
  }

  buttonCode |= KEY_VKEY;

  return buttonCode;
}

接下来就是XBMCKeyTable中查找对应keyname匹配

//xbmc/input/XBMC_keytable.cpp
bool KeyTableLookupName(const char* keyname,XBMCKEYTABLE* keytable)
{
  ...
  // We need the button name to be in lowercase变为小写字母
  std::string lkeyname = keyname;
  StringUtils::ToLower(lkeyname);

  // Look up the key name in XBMCKeyTable
  for (int i = 0; i < XBMCKeyTableSize; i++)
  { if (XBMCKeyTable[i].keyname)
    { if (strcmp(lkeyname.c_str(),XBMCKeyTable[i].keyname) == 0)
      { *keytable = XBMCKeyTable[i];
        return true;
      }
    }
  }
  return false;
}

static const XBMCKEYTABLE XBMCKeyTable[] ={
   ....,{ XBMCK_PLUS,'+',XBMCVK_PLUS,"plus" }
}

XBMCKEYTABLE结构体中第三个值是vkey,这样XBMCVK_VOLUME_UP的值0x2B与KEY_VKEY值0xF000或运算结果0xf02B,
我们回到MapWindowActions方法中的语句MapAction(buttonCode,map);
0xf02B成了buttonCode,这里的pButton->FirstChild()->Value()应为VolumeUp

void CButtonTranslator::MapAction(uint32_t buttonCode,const char *szAction,buttonMap &map)
{
  int action = ACTION_NONE;
  if (!TranslateActionString(szAction,action) || !buttonCode)
    return;   // no valid action,or an invalid buttoncode
  buttonMap::iterator it = map.find(buttonCode);
  if (it == map.end() || (*it).second.id != action || (*it).second.strID != szAction)
  {
    if (it != map.end())
      map.erase(it);
    CButtonAction button;
    button.id = action;
    button.strID = szAction;
    map.insert(pair<uint32_t,CButtonAction>(buttonCode,button));
  }
}
bool CButtonTranslator::TranslateActionString(const char *szAction,int &action)
{
  action = ACTION_NONE;
  std::string strAction = szAction;
  StringUtils::ToLower(strAction);
  if (CBuiltins::HasCommand(strAction)) 
    action = ACTION_BUILT_IN_FUNCTION;

  for (unsigned int index=0;index < ARRAY_SIZE(actions);++index)
  {
    if (strAction == actions[index].name)
    {
      action = actions[index].action;
      break;
    }
  }
  ...
  return true;
}

上面CBuiltins::HasCommand(strAction)用于判断strAction是否为命令,VolumeUp这里不是。
remote.xml中XBMC.ActivateWindow(MyMusic)就是,那action就是ACTION_BUILT_IN_FUNCTION。
我们分析遥控器音量加找到对应的action定义{“volumeup”,ACTION_VOLUME_UP}
button.name为volumeup,button.action为ACTION_VOLUME_UP

至此就读取了一个xml动作,buttonCode为0xf02B,button.id为ACTION_VOLUME_UP,button.strID为plus

map.insert(pair<uint32_t,button));

以此类推读取整个keyboard.xml,乃至其他的输入设备控制的xml文件。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


php输出xml格式字符串
J2ME Mobile 3D入门教程系列文章之一
XML轻松学习手册
XML入门的常见问题(一)
XML入门的常见问题(三)
XML轻松学习手册(2)XML概念
xml文件介绍及使用
xml编程(一)-xml语法
XML文件结构和基本语法
第2章 包装类
XML入门的常见问题(二)
Java对象的强、软、弱和虚引用
JS解析XML文件和XML字符串详解
java中枚举的详细使用介绍
了解Xml格式
XML入门的常见问题(四)
深入SQLite多线程的使用总结详解
PlayFramework完整实现一个APP(一)
XML和YAML的使用方法
XML轻松学习总节篇