Keyboard.cpp

Go to the documentation of this file.
00001 ////////////////////////////////////////////////////////////////////////////////
00002 //    Scorched3D (c) 2000-2009
00003 //
00004 //    This file is part of Scorched3D.
00005 //
00006 //    Scorched3D is free software; you can redistribute it and/or modify
00007 //    it under the terms of the GNU General Public License as published by
00008 //    the Free Software Foundation; either version 2 of the License, or
00009 //    (at your option) any later version.
00010 //
00011 //    Scorched3D is distributed in the hope that it will be useful,
00012 //    but WITHOUT ANY WARRANTY; without even the implied warranty of
00013 //    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014 //    GNU General Public License for more details.
00015 //
00016 //    You should have received a copy of the GNU General Public License
00017 //    along with Scorched3D; if not, write to the Free Software
00018 //    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00019 ////////////////////////////////////////////////////////////////////////////////
00020 
00021 #include <common/Keyboard.h>
00022 #include <common/Defines.h>
00023 #include <XML/XMLFile.h>
00024 
00025 bool Keyboard::dvorak_ = false;
00026 
00027 Keyboard *Keyboard::instance_ = 0;
00028 
00029 Keyboard *Keyboard::instance()
00030 {
00031         if (!instance_)
00032         {
00033                 instance_ = new Keyboard;
00034         }
00035 
00036         return instance_;
00037 }
00038 
00039 Keyboard::Keyboard() : keybHistCnt_(0), mHighSurrogate(0)
00040 {
00041 
00042 }
00043 
00044 Keyboard::~Keyboard()
00045 {
00046 
00047 }
00048 
00049 bool Keyboard::init()
00050 {
00051         SDL_EnableUNICODE(1);
00052         SDL_EnableKeyRepeat(250, 100);
00053         return true;
00054 }
00055 
00056 unsigned int Keyboard::getKeyboardState()
00057 {
00058         // Ingore capslock, numlock and scroll lock
00059         const unsigned int keymask = KMOD_LSHIFT | KMOD_RSHIFT | KMOD_LCTRL | KMOD_RCTRL |
00060                 KMOD_LALT | KMOD_RALT | KMOD_LMETA | KMOD_RMETA;
00061 
00062         return SDL_GetModState() & keymask;
00063 }
00064 
00065 char *Keyboard::getkeyboardbuffer(unsigned int &bufCnt)
00066 {
00067         bufCnt = SDLK_LAST;
00068         return (char *) SDL_GetKeyState(NULL);
00069 }
00070  
00071 KeyboardHistory::HistoryElement *Keyboard::getkeyboardhistory(unsigned int &histCnt)
00072 {
00073         histCnt = keybHistCnt_;
00074         keybHistCnt_=0;
00075 
00076         return keybHist_;
00077 }
00078  
00079 #define UTF16_IS_HIGH_SURROGATE(U) ((Uint16)((U) - 0xD800) < 0x0400)
00080 #define UTF16_IS_LOW_SURROGATE(U)  ((Uint16)((U) - 0xDC00) < 0x0400)
00081 #define UTF16_SURROGATE_PAIR_TO_UTF32(H,L) (((H) << 10) + (L) - (0xD800 << 10) - 0xDC00 + 0x00010000)
00082 
00083 void Keyboard::raiseUnicodeUTF16(Uint16 utf16, SDLKey key)
00084 {
00085         // Check we have enough space in the array
00086         if (keybHistCnt_ >= MAX_KEYBDHIST) return;
00087 
00088         KeyboardHistory::HistoryElement newElement =
00089         {
00090                 key,
00091                 utf16
00092         };
00093 
00094         // Add characater and symbol to history
00095         keybHist_[keybHistCnt_++] = newElement;
00096 }
00097 
00098 void Keyboard::handleUnicodeUTF16(Uint16 utf16, SDLKey key)
00099 {
00100         // Note that we could discard unpaired surrogates, but I'm
00101         // following the Unicode Consortium's recommendation here;
00102         // that is, to preserve those unpaired surrogates in UTF-32
00103         // values.  _To_preserve_ means to pass to the callback in our
00104         // context.
00105 
00106         if (mHighSurrogate == 0)
00107         {
00108                 if (UTF16_IS_HIGH_SURROGATE(utf16))
00109                 {
00110                         mHighSurrogate = utf16;
00111                 }
00112                 else
00113                 {
00114                         raiseUnicodeUTF16(utf16, key);
00115                 }
00116         }
00117         else
00118         {
00119                 if (UTF16_IS_LOW_SURROGATE(utf16))
00120                 {
00121                         /* A legal surrogate pair.  */                  
00122                         raiseUnicodeUTF16(UTF16_SURROGATE_PAIR_TO_UTF32(mHighSurrogate, utf16), key);
00123                         mHighSurrogate = 0;
00124                 }
00125                 else if (UTF16_IS_HIGH_SURROGATE(utf16))
00126                 {
00127                         /* Two consecutive high surrogates.  */
00128                         raiseUnicodeUTF16(mHighSurrogate, key);
00129                         mHighSurrogate = utf16;
00130                 }
00131                 else
00132                 {
00133                         /* A non-low-surrogate preceeded by a high surrogate. */
00134                         raiseUnicodeUTF16(mHighSurrogate, key);
00135                         mHighSurrogate = 0;
00136                         raiseUnicodeUTF16(utf16, key);
00137                 }
00138         }
00139 }
00140 
00141 void Keyboard::processKeyboardEvent(SDL_Event &event)
00142 {
00143         // Check we are adding the correct key type
00144         if (event.type != SDL_KEYDOWN) return;
00145 
00146         handleUnicodeUTF16(event.key.keysym.unicode, event.key.keysym.sym);
00147 }
00148 
00149 bool &Keyboard::getDvorak()
00150 {
00151         return dvorak_;
00152 }
00153 
00154 void Keyboard::clear()
00155 {
00156         std::map<std::string, KeyboardKey *>::iterator itor;
00157         for (itor = keyMap_.begin();
00158                 itor != keyMap_.end();
00159                 itor++)
00160         {
00161                 delete (*itor).second;
00162         }
00163         keyMap_.clear();
00164         keyList_.clear();
00165         commandKeys_.clear();   
00166 }
00167 
00168 bool Keyboard::saveKeyFile()
00169 {
00170         XMLNode keysNode("keys");
00171         std::list<std::string>::iterator itor;
00172         for (itor = keyList_.begin();
00173                 itor != keyList_.end();
00174                 itor++)
00175         {
00176                 KeyboardKey *key = getKey((*itor).c_str());
00177                 if (!key || !key->getChanged()) continue;
00178 
00179                 XMLNode *keyNode = new XMLNode("keyentry");
00180                 if (key->getNameIsCommand())
00181                         keyNode->addChild(new XMLNode("command", key->getName()));
00182                 else keyNode->addChild(new XMLNode("name", key->getName()));
00183                 keyNode->addChild(new XMLNode("title", key->getTitle()));
00184                 keyNode->addChild(new XMLNode("description", key->getDescription()));
00185                 keyNode->addChild(new XMLNode("group", S3D::formatStringBuffer("%i", key->getGroup())));
00186 
00187                 std::vector<KeyboardKey::KeyEntry> &keys = key->getKeys();
00188                 std::vector<KeyboardKey::KeyEntry>::iterator subitor;
00189                 for (subitor = keys.begin();
00190                         subitor != keys.end();
00191                         subitor++)
00192                 {
00193                         KeyboardKey::KeyEntry &subentry = (*subitor);
00194                         const char *name = "";
00195                         const char *state = "";
00196                         KeyboardKey::translateKeyNameValue(subentry.key, name);
00197                         KeyboardKey::translateKeyStateValue(subentry.state, state);
00198                         XMLNode *subnode = new XMLNode("key", name);
00199                         if (strcmp(state, "NONE") != 0) subnode->addParameter(
00200                                 new XMLNode("state", state, XMLNode::XMLParameterType));
00201                         keyNode->addChild(subnode);
00202                 }
00203 
00204                 keysNode.addChild(keyNode);
00205         }
00206 
00207         std::string fileName = S3D::getSettingsFile("keys.xml");
00208         if (!keysNode.writeToFile(fileName)) return false;
00209 
00210         return true;
00211 }
00212 
00213 bool Keyboard::loadKeyFile(bool loadDefaults)
00214 {
00215         // Empty the current keys
00216         clear();
00217 
00218         // Load the master list of keys
00219         if (!loadKeyFile(S3D::getDataFile("data/keys.xml"), true)) return false;
00220 
00221         // Replace with any custom keys
00222         std::string fileName = S3D::getSettingsFile("keys.xml");
00223         if (S3D::fileExists(fileName) && !loadDefaults)
00224         {
00225                 if (!loadKeyFile(fileName, false)) return false;
00226         }
00227 
00228         // Build the command list
00229         std::map<std::string, KeyboardKey *>::iterator keyItor;
00230         for (keyItor = keyMap_.begin();
00231                 keyItor != keyMap_.end();
00232                 keyItor++)
00233         {
00234                 KeyboardKey *key = keyItor->second;             
00235 
00236                 // Add a command
00237                 if (key->getNameIsCommand()) commandKeys_.push_back(key);
00238 
00239                 // Find if this key is already in use
00240                 std::map<std::string, KeyboardKey *>::iterator dupeItor;
00241                 for (dupeItor = keyMap_.begin();
00242                         dupeItor != keyMap_.end();
00243                         dupeItor++)
00244                 {
00245                         KeyboardKey *dupe = dupeItor->second;
00246                         if (dupe == key) continue;
00247 
00248                         std::vector<KeyboardKey::KeyEntry> &dupeKeys = dupe->getKeys();
00249                         std::vector<KeyboardKey::KeyEntry>::iterator itor;
00250                         for (itor = dupeKeys.begin();
00251                                 itor != dupeKeys.end();
00252                                 itor++)
00253                         {
00254                                 KeyboardKey::KeyEntry &entry = *itor;
00255                                 int keyIndex = key->keyIndex(entry.key, entry.state);
00256                                 if (keyIndex != -1)
00257                                 {
00258                                         const char *keyName = "", *stateName = "";
00259                                         KeyboardKey::translateKeyNameValue(entry.key, keyName);
00260                                         KeyboardKey::translateKeyStateValue(entry.state, stateName);
00261 
00262                                         S3D::dialogMessage("Keyboard", S3D::formatStringBuffer(
00263                                                 "Warning: Key \"%s\" and state \"%s\" defined for \"%s\" was also defined for \"%s\"",
00264                                                 keyName, stateName, key->getName(), dupe->getName()));
00265                                         
00266                                         key->removeKey(keyIndex);
00267                                 }
00268                         }
00269                 }
00270         }
00271 
00272         return true;
00273 }
00274 
00275 bool Keyboard::loadKeyFile(const std::string &fileName, bool masterFile)
00276 {
00277         // Load key definition file
00278         XMLFile file;
00279     if (!file.readFile(fileName))
00280         {
00281                 S3D::dialogMessage("Keyboard", S3D::formatStringBuffer(
00282                                           "Failed to parse \"%s\"\n%s", 
00283                                           fileName.c_str(),
00284                                           file.getParserError()));
00285                 return false;
00286         }
00287 
00288         // Check file exists
00289         if (!file.getRootNode())
00290         {
00291                 S3D::dialogMessage("Keyboard", S3D::formatStringBuffer(
00292                                           "Failed to find key definition file \"%s\"",
00293                                           fileName.c_str()));
00294                 return false;           
00295         }
00296 
00297         // Itterate all of the keys in the file
00298     std::list<XMLNode *>::iterator childrenItor;
00299         std::list<XMLNode *> &children = file.getRootNode()->getChildren();
00300     for (childrenItor = children.begin();
00301                  childrenItor != children.end();
00302                  childrenItor++)
00303     {
00304                 // Parse the key entry
00305         XMLNode *currentNode = (*childrenItor);
00306                 if (strcmp(currentNode->getName(), "keyentry"))
00307                 {
00308                         S3D::dialogMessage("Keyboard",
00309                                                   "Failed to find keyentry node");
00310                         return false;
00311                 }
00312 
00313                 // Get the name of the key
00314                 const char *keyName = 0;
00315                 bool command = false;
00316                 XMLNode *nameNode;
00317                 XMLNode *commandNode;
00318                 if (currentNode->getNamedChild("name", nameNode, false))
00319                 {
00320                         keyName = nameNode->getContent();
00321                         command = false;
00322                 }
00323                 else if (currentNode->getNamedChild("command", commandNode, false))
00324                 {
00325                         keyName = commandNode->getContent();
00326                         command = true;
00327                 }
00328                 else
00329                 {
00330                         S3D::dialogMessage("Keyboard",
00331                                                   "Failed to find name node");
00332                         return false;
00333                 }
00334 
00335                 if (masterFile)
00336                 {
00337                         // We have already seen this key entry, 
00338                         // and we are loading the master key file.
00339                         std::map<std::string, KeyboardKey *>::iterator findItor =
00340                                 keyMap_.find(keyName);
00341                         if (findItor != keyMap_.end())
00342                         {
00343                                 // Delete it to make space for the new entry.
00344                                 delete findItor->second;
00345                                 keyMap_.erase(findItor);
00346                         }
00347                 }
00348                 else
00349                 {
00350                         // We have already seen this key entry, 
00351                         // and we are loading custom keys.
00352                         // Only load custom key entries for keys that we have already
00353                         // seen in the master file
00354                         std::map<std::string, KeyboardKey *>::iterator findItor =
00355                                 keyMap_.find(keyName);
00356                         if (findItor != keyMap_.end())
00357                         {
00358                                 // Delete it to make space for the new entry.
00359                                 delete findItor->second;
00360                                 keyMap_.erase(findItor);                
00361                         }
00362                         else
00363                         {
00364                                 // This is not in the master file
00365                                 // Ignore it
00366                                 continue;
00367                         }
00368                 }
00369                 
00370                 // Get the description for the key
00371                 XMLNode *descNode;
00372                 if (!currentNode->getNamedChild("description", descNode)) return false;
00373                 const char *keyDesc = descNode->getContent();
00374 
00375                 // Get the group
00376                 int group = 0;
00377                 if (!currentNode->getNamedChild("group", group)) return false;
00378 
00379                 // Get the title
00380                 XMLNode *titleNode;
00381                 if (!currentNode->getNamedChild("title", titleNode)) return false;
00382                 const char *keyTitle = titleNode->getContent();
00383 
00384                 // Add all the key names
00385                 XMLNode *currentKey = 0;
00386                 std::list<std::string> keyNames, keyStateNames;
00387                 while (currentNode->getNamedChild("key", currentKey, false))
00388                 {
00389                         const char *state = "NONE";
00390                         XMLNode *stateNode;
00391                         if (currentKey->getNamedParameter("state", stateNode, false)) 
00392                         state = stateNode->getContent();
00393 
00394                         // Add a key and state
00395                         keyNames.push_back(currentKey->getContent());
00396                         keyStateNames.push_back(state);
00397                 }
00398 
00399                 // Create the key
00400                 KeyboardKey *newKey = new KeyboardKey(keyName, keyTitle, keyDesc, group, command);
00401                 if (!newKey->addKeys(keyNames, keyStateNames)) return false;
00402                 if (masterFile) newKey->setChanged(false);
00403 
00404                 // Add to the list of pre-defined keys
00405                 keyMap_[keyName] = newKey;
00406                 if (masterFile) keyList_.push_back(keyName);
00407                 if (!currentNode->failChildren()) return false;
00408         }
00409 
00410         return true;
00411 }
00412 
00413 KeyboardKey *Keyboard::getKey(const char *name)
00414 {
00415         static KeyboardKey defaultKey("None", "None", "None", 0, false);
00416 
00417         std::map<std::string, KeyboardKey *>::iterator itor =
00418                 keyMap_.find(name);
00419         if (itor != keyMap_.end()) return (*itor).second;
00420 
00421         S3D::dialogMessage("Keyboard", S3D::formatStringBuffer(
00422                                   "Failed to find key for key name \"%s\"",
00423                                   name));       
00424         return &defaultKey;
00425 }
00426 

Generated on Mon Feb 16 15:14:48 2009 for Scorched3D by  doxygen 1.5.3