ResidualVM logo ResidualVM website - Forums - Contact us BuildBot - Doxygen - Wiki curved edge

virtual-keyboard.cpp

Go to the documentation of this file.
00001 /* ScummVM - Graphic Adventure Engine
00002  *
00003  * ScummVM is the legal property of its developers, whose names
00004  * are too numerous to list here. Please refer to the COPYRIGHT
00005  * file distributed with this source distribution.
00006  *
00007  * This program is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU General Public License
00009  * as published by the Free Software Foundation; either version 2
00010  * of the License, or (at your option) any later version.
00011  *
00012  * This program is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU General Public License
00018  * along with this program; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00020  *
00021  */
00022 
00023 #include "common/scummsys.h"
00024 
00025 #ifdef ENABLE_VKEYBD
00026 
00027 #include "backends/vkeybd/virtual-keyboard.h"
00028 
00029 #include "backends/vkeybd/virtual-keyboard-gui.h"
00030 #include "backends/vkeybd/virtual-keyboard-parser.h"
00031 #include "backends/vkeybd/keycode-descriptions.h"
00032 #include "common/config-manager.h"
00033 #include "common/textconsole.h"
00034 #include "common/unzip.h"
00035 
00036 #define KEY_START_CHAR ('[')
00037 #define KEY_END_CHAR (']')
00038 
00039 namespace Common {
00040 
00041 VirtualKeyboard::VirtualKeyboard() :
00042         _currentMode(nullptr),
00043         _fileArchive(nullptr, DisposeAfterUse::NO) {
00044     assert(g_system);
00045     _system = g_system;
00046 
00047     _parser = new VirtualKeyboardParser(this);
00048     _kbdGUI = new VirtualKeyboardGUI(this);
00049     _submitKeys = _loaded = false;
00050 }
00051 
00052 VirtualKeyboard::~VirtualKeyboard() {
00053     deleteEvents();
00054     delete _kbdGUI;
00055     delete _parser;
00056 }
00057 
00058 void VirtualKeyboard::deleteEvents() {
00059     for (ModeMap::iterator it_m = _modes.begin(); it_m != _modes.end(); ++it_m) {
00060         VKEventMap &evt = it_m->_value.events;
00061         for (VKEventMap::iterator it_e = evt.begin(); it_e != evt.end(); ++it_e)
00062             delete it_e->_value;
00063     }
00064 }
00065 
00066 void VirtualKeyboard::reset() {
00067     deleteEvents();
00068     _modes.clear();
00069     _initialMode = _currentMode = 0;
00070     _hAlignment = kAlignCenter;
00071     _vAlignment = kAlignBottom;
00072     _keyQueue.clear();
00073     _loaded = false;
00074     _kbdGUI->reset();
00075 }
00076 
00077 bool VirtualKeyboard::openPack(const String &packName, Archive *searchPath, DisposeAfterUse::Flag disposeSearchPath) {
00078     if (searchPath->hasFile(packName + ".xml")) {
00079         _fileArchive.reset(searchPath, disposeSearchPath);
00080 
00081         // uncompressed keyboard pack
00082         if (!_parser->loadStream(searchPath->createReadStreamForMember(packName + ".xml"))) {
00083             _fileArchive.reset();
00084             return false;
00085         }
00086 
00087         return true;
00088     }
00089 
00090     if (searchPath->hasFile(packName + ".zip")) {
00091         // compressed keyboard pack
00092         Archive *zip = makeZipArchive(searchPath->createReadStreamForMember(packName + ".zip"));
00093         _fileArchive.reset(zip, DisposeAfterUse::YES);
00094         if (_fileArchive && _fileArchive->hasFile(packName + ".xml")) {
00095             if (!_parser->loadStream(_fileArchive->createReadStreamForMember(packName + ".xml"))) {
00096                 _fileArchive.reset();
00097                 return false;
00098             }
00099         } else {
00100             warning("Could not find %s.xml file in %s.zip virtual keyboard pack", packName.c_str(), packName.c_str());
00101             _fileArchive.reset();
00102             return false;
00103         }
00104 
00105         return true;
00106     }
00107 
00108     return false;
00109 }
00110 
00111 bool VirtualKeyboard::loadKeyboardPack(const String &packName) {
00112     _kbdGUI->initSize(_system->getOverlayWidth(), _system->getOverlayHeight());
00113 
00114     _fileArchive.reset();
00115     _loaded = false;
00116 
00117     bool opened = false;
00118     if (ConfMan.hasKey("vkeybdpath"))
00119         opened = openPack(packName, new FSDirectory(ConfMan.get("vkeybdpath")), DisposeAfterUse::YES);
00120     else if (ConfMan.hasKey("extrapath"))
00121         opened = openPack(packName, new FSDirectory(ConfMan.get("extrapath")), DisposeAfterUse::YES);
00122 
00123     // fallback to SearchMan
00124     if (!opened)
00125         opened = openPack(packName, &SearchMan, DisposeAfterUse::NO);
00126 
00127     if (opened) {
00128         _parser->setParseMode(VirtualKeyboardParser::kParseFull);
00129         _loaded = _parser->parse();
00130 
00131         if (_loaded) {
00132             debug("Virtual keyboard pack '%s' loaded successfully", packName.c_str());
00133         } else {
00134             warning("Error parsing the virtual keyboard pack '%s'", packName.c_str());
00135 
00136             _fileArchive.reset();
00137         }
00138     } else {
00139         warning("Virtual keyboard disabled due to missing pack file");
00140     }
00141 
00142     return _loaded;
00143 }
00144 
00145 bool VirtualKeyboard::checkModeResolutions() {
00146     _parser->setParseMode(VirtualKeyboardParser::kParseCheckResolutions);
00147     _loaded = _parser->parse();
00148     if (_currentMode)
00149         _kbdGUI->initMode(_currentMode);
00150     return _loaded;
00151 }
00152 
00153 String VirtualKeyboard::findArea(int16 x, int16 y) {
00154     return _currentMode->imageMap.findMapArea(x, y);
00155 }
00156 
00157 void VirtualKeyboard::processAreaClick(const String &area) {
00158     if (!_currentMode->events.contains(area))
00159         return;
00160 
00161     VKEvent *evt = _currentMode->events[area];
00162 
00163     switch (evt->type) {
00164     case kVKEventKey:
00165         // add virtual keypress to queue
00166         _keyQueue.insertKey(*(KeyState *)evt->data);
00167         break;
00168     case kVKEventModifier:
00169         _keyQueue.toggleFlags(*(byte *)(evt->data));
00170         break;
00171     case kVKEventSwitchMode:
00172         // switch to new mode
00173         switchMode((char *)evt->data);
00174         _keyQueue.clearFlags();
00175         break;
00176     case kVKEventSubmit:
00177         close(true);
00178         break;
00179     case kVKEventCancel:
00180         close(false);
00181         break;
00182     case kVKEventClear:
00183         _keyQueue.clear();
00184         break;
00185     case kVKEventDelete:
00186         _keyQueue.deleteKey();
00187         break;
00188     case kVKEventMoveLeft:
00189         _keyQueue.moveLeft();
00190         break;
00191     case kVKEventMoveRight:
00192         _keyQueue.moveRight();
00193         break;
00194     }
00195 }
00196 
00197 void VirtualKeyboard::switchMode(Mode *newMode) {
00198     _kbdGUI->initMode(newMode);
00199     _currentMode = newMode;
00200 }
00201 
00202 void VirtualKeyboard::switchMode(const String &newMode) {
00203     if (!_modes.contains(newMode)) {
00204         warning("Virtual keyboard mode '%s' unknown", newMode.c_str());
00205     } else {
00206         switchMode(&_modes[newMode]);
00207     }
00208 }
00209 
00210 void VirtualKeyboard::handleMouseDown(int16 x, int16 y) {
00211     _areaDown = findArea(x, y);
00212     if (_areaDown.empty())
00213         _kbdGUI->startDrag(x, y);
00214 }
00215 
00216 void VirtualKeyboard::handleMouseUp(int16 x, int16 y) {
00217     if (!_areaDown.empty() && _areaDown == findArea(x, y)) {
00218         processAreaClick(_areaDown);
00219         _areaDown.clear();
00220     }
00221     _kbdGUI->endDrag();
00222 }
00223 
00224 void VirtualKeyboard::show() {
00225     if (!_loaded) {
00226         debug(1, "VirtualKeyboard::show() - Virtual keyboard not loaded");
00227         return;
00228     } else {
00229         _kbdGUI->checkScreenChanged();
00230     }
00231 
00232     switchMode(_initialMode);
00233     _kbdGUI->run();
00234 
00235     if (_submitKeys) {
00236         EventManager *eventMan = _system->getEventManager();
00237         assert(eventMan);
00238 
00239         // push keydown & keyup events into the event manager
00240         Event evt;
00241         while (!_keyQueue.empty()) {
00242             evt.kbd = _keyQueue.pop();
00243             evt.type = EVENT_KEYDOWN;
00244             eventMan->pushEvent(evt);
00245             evt.type = EVENT_KEYUP;
00246             eventMan->pushEvent(evt);
00247         }
00248     } else {
00249         _keyQueue.clear();
00250     }
00251 }
00252 
00253 void VirtualKeyboard::close(bool submit) {
00254     _submitKeys = submit;
00255     _kbdGUI->close();
00256 }
00257 
00258 bool VirtualKeyboard::isDisplaying() {
00259     return _kbdGUI->isDisplaying();
00260 }
00261 
00262 VirtualKeyboard::KeyPressQueue::KeyPressQueue() {
00263     _keyPos = _keys.end();
00264     _strPos = 0;
00265     _strChanged = false;
00266     _flags = 0;
00267 }
00268 
00269 void VirtualKeyboard::KeyPressQueue::toggleFlags(byte fl) {
00270     _flags ^= fl;
00271     _flagsStr.clear();
00272     if (_flags) {
00273         _flagsStr = KEY_START_CHAR;
00274         if (_flags & KBD_CTRL)
00275             _flagsStr += "Ctrl+";
00276         if (_flags & KBD_ALT)
00277             _flagsStr += "Alt+";
00278         if (_flags & KBD_SHIFT)
00279             _flagsStr += "Shift+";
00280     }
00281     _strChanged = true;
00282 }
00283 
00284 void VirtualKeyboard::KeyPressQueue::clearFlags() {
00285     _flags = 0;
00286     _flagsStr.clear();
00287     _strChanged = true;
00288 }
00289 
00290 void VirtualKeyboard::KeyPressQueue::insertKey(KeyState key) {
00291     _strChanged = true;
00292     key.flags ^= _flags;
00293     if ((key.keycode >= KEYCODE_a) && (key.keycode <= KEYCODE_z))
00294         key.ascii = (key.flags & KBD_SHIFT) ? key.keycode - 32 : key.keycode;
00295     clearFlags();
00296 
00297     String keyStr;
00298     if (key.flags & KBD_CTRL) keyStr += "Ctrl+";
00299     if (key.flags & KBD_ALT) keyStr += "Alt+";
00300 
00301     if (key.ascii >= 32 && key.ascii <= 255) {
00302         if (key.flags & KBD_SHIFT && (key.ascii < 65 || key.ascii > 90))
00303             keyStr += "Shift+";
00304         keyStr += (char)key.ascii;
00305     } else {
00306         if (key.flags & KBD_SHIFT) keyStr += "Shift+";
00307         if (key.keycode >= 0 && key.keycode < keycodeDescTableSize)
00308             keyStr += keycodeDescTable[key.keycode];
00309     }
00310 
00311     if (keyStr.empty()) keyStr += "???";
00312 
00313     _keysStr.insertChar(KEY_START_CHAR, _strPos++);
00314     const char *k = keyStr.c_str();
00315     while (char ch = *k++)
00316         _keysStr.insertChar(ch, _strPos++);
00317     _keysStr.insertChar(KEY_END_CHAR, _strPos++);
00318 
00319     VirtualKeyPress kp;
00320     kp.key = key;
00321     kp.strLen = keyStr.size() + 2;
00322     _keys.insert(_keyPos, kp);
00323 }
00324 
00325 void VirtualKeyboard::KeyPressQueue::deleteKey() {
00326     if (_keyPos == _keys.begin())
00327         return;
00328     KeyPressList::iterator it = _keyPos;
00329     it--;
00330     _strPos -= it->strLen;
00331     while ((it->strLen)-- > 0)
00332         _keysStr.deleteChar(_strPos);
00333     _keys.erase(it);
00334     _strChanged = true;
00335 }
00336 
00337 void VirtualKeyboard::KeyPressQueue::moveLeft() {
00338     if (_keyPos == _keys.begin())
00339         return;
00340     _keyPos--;
00341     _strPos -= _keyPos->strLen;
00342     _strChanged = true;
00343 }
00344 
00345 void VirtualKeyboard::KeyPressQueue::moveRight() {
00346     if (_keyPos == _keys.end())
00347         return;
00348     _strPos += _keyPos->strLen;
00349     _keyPos++;
00350     _strChanged = true;
00351 }
00352 
00353 KeyState VirtualKeyboard::KeyPressQueue::pop() {
00354     bool front = (_keyPos == _keys.begin());
00355     VirtualKeyPress kp = *(_keys.begin());
00356     _keys.pop_front();
00357 
00358     if (front)
00359         _keyPos = _keys.begin();
00360     else
00361         _strPos -= kp.strLen;
00362 
00363     while (kp.strLen-- > 0)
00364         _keysStr.deleteChar(0);
00365 
00366     return kp.key;
00367 }
00368 
00369 void VirtualKeyboard::KeyPressQueue::clear() {
00370     _keys.clear();
00371     _keyPos = _keys.end();
00372     _keysStr.clear();
00373     _strPos = 0;
00374     clearFlags();
00375     _strChanged = true;
00376 }
00377 
00378 bool VirtualKeyboard::KeyPressQueue::empty() {
00379     return _keys.empty();
00380 }
00381 
00382 String VirtualKeyboard::KeyPressQueue::getString() {
00383     if (_keysStr.empty())
00384         return _flagsStr;
00385     if (_flagsStr.empty())
00386         return _keysStr;
00387     if (_strPos == _keysStr.size())
00388         return _keysStr + _flagsStr;
00389 
00390     uint len = _keysStr.size() + _flagsStr.size();
00391     char *str = new char[len];
00392     memcpy(str, _keysStr.c_str(), _strPos);
00393     memcpy(str + _strPos, _flagsStr.c_str(), _flagsStr.size());
00394     memcpy(str + _strPos + _flagsStr.size(), _keysStr.c_str() + _strPos, _keysStr.size() - _strPos);
00395     String ret(str, len);
00396     delete[] str;
00397     return ret;
00398 }
00399 
00400 uint VirtualKeyboard::KeyPressQueue::getInsertIndex() {
00401     return _strPos + _flagsStr.size();
00402 }
00403 
00404 bool VirtualKeyboard::KeyPressQueue::hasStringChanged() {
00405     bool ret = _strChanged;
00406     _strChanged = false;
00407     return ret;
00408 }
00409 
00410 } // End of namespace Common
00411 
00412 #endif // #ifdef ENABLE_VKEYBD


Generated on Sat Feb 16 2019 05:01:11 for ResidualVM by doxygen 1.7.1
curved edge   curved edge