diff options
Diffstat (limited to 'backends/vkeybd/virtual-keyboard.cpp')
-rw-r--r-- | backends/vkeybd/virtual-keyboard.cpp | 390 |
1 files changed, 390 insertions, 0 deletions
diff --git a/backends/vkeybd/virtual-keyboard.cpp b/backends/vkeybd/virtual-keyboard.cpp new file mode 100644 index 0000000000..fab2d80d30 --- /dev/null +++ b/backends/vkeybd/virtual-keyboard.cpp @@ -0,0 +1,390 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * 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 + * of the License, 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 this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#include "backends/vkeybd/virtual-keyboard.h" +#include "backends/vkeybd/virtual-keyboard-gui.h" +#include "backends/vkeybd/virtual-keyboard-parser.h" +#include "backends/vkeybd/keycode-descriptions.h" +#include "common/config-manager.h" +#include "common/fs.h" +#include "graphics/imageman.h" +#include "common/unzip.h" + +#define KEY_START_CHAR ('[') +#define KEY_END_CHAR (']') + +namespace Common { + +VirtualKeyboard::VirtualKeyboard() : _currentMode(0) { + assert(g_system); + _system = g_system; + + _parser = new VirtualKeyboardParser(this); + _kbdGUI = new VirtualKeyboardGUI(this); + _submitKeys = _loaded = false; + +} + +VirtualKeyboard::~VirtualKeyboard() { + deleteEvents(); + delete _kbdGUI; + delete _parser; +} + +void VirtualKeyboard::deleteEvents() { + ModeMap::iterator it_m; + VKEventMap::iterator it_e; + for (it_m = _modes.begin(); it_m != _modes.end(); it_m++) { + VKEventMap *evt = &(it_m->_value.events); + for (it_e = evt->begin(); it_e != evt->end(); it_e++) + delete it_e->_value; + } +} + +void VirtualKeyboard::reset() { + deleteEvents(); + _modes.clear(); + _initialMode = _currentMode = 0; + _hAlignment = kAlignCentre; + _vAlignment = kAlignBottom; + _keyQueue.clear(); + _loaded = false; + _kbdGUI->reset(); +} + +bool VirtualKeyboard::loadKeyboardPack(String packName) { + + _kbdGUI->initSize(_system->getOverlayWidth(), _system->getOverlayHeight()); + + FilesystemNode *vkDir = 0; + if (ConfMan.hasKey("vkeybdpath")) { + vkDir = new FilesystemNode(ConfMan.get("vkeybdpath")); + } else if (ConfMan.hasKey("extrapath")) { + vkDir = new FilesystemNode(ConfMan.get("extrapath")); + } else { // use current directory + vkDir = new FilesystemNode("."); + } + + if (vkDir->getChild(packName + ".xml").exists()) { + // uncompressed keyboard pack + + if (!_parser->loadFile(vkDir->getChild(packName + ".xml"))) + return false; + + } else if (vkDir->getChild(packName + ".zip").exists()) { + // compressed keyboard pack +#ifdef USE_ZLIB + ZipArchive arch(vkDir->getChild(packName + ".zip").getPath().c_str()); + if (arch.hasFile(packName + ".xml")) { + if (!_parser->loadStream(arch.openFile(packName + ".xml"))) + return false; + } else { + warning("Could not find %s.xml file in %s.zip keyboard pack", packName.c_str(), packName.c_str()); + return false; + } + ImageMan.addArchive(vkDir->getChild(packName + ".zip").getPath().c_str()); +#else + return false; +#endif + } else { + warning("Keyboard pack not found"); + return false; + } + + _parser->setParseMode(VirtualKeyboardParser::kParseFull); + _loaded = _parser->parse(); + if (_loaded) + printf("Keyboard pack '%s' loaded successfully!\n", packName.c_str()); + + return _loaded; +} + +bool VirtualKeyboard::checkModeResolutions() +{ + _parser->setParseMode(VirtualKeyboardParser::kParseCheckResolutions); + _loaded = _parser->parse(); + if (_currentMode) _kbdGUI->initMode(_currentMode); + return _loaded; +} + +String VirtualKeyboard::findArea(int16 x, int16 y) { + return _currentMode->imageMap.findMapArea(x, y); +} + +void VirtualKeyboard::processAreaClick(const String& area) { + if (!_currentMode->events.contains(area)) return; + VKEvent *evt = _currentMode->events[area]; + + switch (evt->type) { + case kVKEventKey: { + // add virtual keypress to queue + _keyQueue.insertKey(*(KeyState*)evt->data); + break; + } + case kVKEventModifier: + _keyQueue.toggleFlags(*(byte*)(evt->data)); + break; + case kVKEventSwitchMode: + // switch to new mode + switchMode((char *)evt->data); + _keyQueue.clearFlags(); + break; + case kVKEventSubmit: + close(true); + break; + case kVKEventCancel: + close(false); + break; + case kVKEventClear: + _keyQueue.clear(); + break; + case kVKEventDelete: + _keyQueue.deleteKey(); + break; + case kVKEventMoveLeft: + _keyQueue.moveLeft(); + break; + case kVKEventMoveRight: + _keyQueue.moveRight(); + break; + } +} + +void VirtualKeyboard::switchMode(Mode *newMode) { + _kbdGUI->initMode(newMode); + _currentMode = newMode; +} + +void VirtualKeyboard::switchMode(const String& newMode) { + if (!_modes.contains(newMode)) { + warning("Keyboard mode '%s' unknown", newMode.c_str()); + return; + } + switchMode(&_modes[newMode]); +} + +void VirtualKeyboard::handleMouseDown(int16 x, int16 y) { + _areaDown = findArea(x, y); + if (_areaDown.empty()) + _kbdGUI->startDrag(x, y); +} + +void VirtualKeyboard::handleMouseUp(int16 x, int16 y) { + if (!_areaDown.empty() && _areaDown == findArea(x, y)) { + processAreaClick(_areaDown); + _areaDown.clear(); + } + _kbdGUI->endDrag(); +} + +void VirtualKeyboard::show() { + if (_loaded) _kbdGUI->checkScreenChanged(); + if (!_loaded) { + warning("Virtual keyboard not loaded"); + return; + } + + switchMode(_initialMode); + _kbdGUI->run(); + + if (_submitKeys) { + EventManager *eventMan = _system->getEventManager(); + assert(eventMan); + + // push keydown & keyup events into the event manager + Event evt; + evt.synthetic = false; + while (!_keyQueue.empty()) { + evt.kbd = _keyQueue.pop(); + evt.type = EVENT_KEYDOWN; + eventMan->pushEvent(evt); + evt.type = EVENT_KEYUP; + eventMan->pushEvent(evt); + } + } else { + _keyQueue.clear(); + } +} + +void VirtualKeyboard::close(bool submit) { + _submitKeys = submit; + _kbdGUI->close(); +} + +bool VirtualKeyboard::isDisplaying() { + return _kbdGUI->isDisplaying(); +} + +VirtualKeyboard::KeyPressQueue::KeyPressQueue() { + _keyPos = _keys.end(); + _strPos = 0; + _strChanged = false; + _flags = 0; +} + +void VirtualKeyboard::KeyPressQueue::toggleFlags(byte fl) { + _flags ^= fl; + _flagsStr.clear(); + if (_flags) { + _flagsStr = KEY_START_CHAR; + if (_flags & KBD_CTRL) + _flagsStr += "Ctrl+"; + if (_flags & KBD_ALT) + _flagsStr += "Alt+"; + if (_flags & KBD_SHIFT) + _flagsStr += "Shift+"; + } + _strChanged = true; +} + +void VirtualKeyboard::KeyPressQueue::clearFlags() { + _flags = 0; + _flagsStr.clear(); + _strChanged = true; +} + +void VirtualKeyboard::KeyPressQueue::insertKey(KeyState key) { + _strChanged = true; + key.flags ^= _flags; + if ((key.keycode >= KEYCODE_a) && (key.keycode <= KEYCODE_z)) + key.ascii = (key.flags & KBD_SHIFT) ? key.keycode - 32 : key.keycode; + clearFlags(); + + String keyStr; + if (key.flags & KBD_CTRL) keyStr += "Ctrl+"; + if (key.flags & KBD_ALT) keyStr += "Alt+"; + + if (key.ascii >= 32 && key.ascii <= 255) { + if (key.flags & KBD_SHIFT && (key.ascii < 65 || key.ascii > 90)) + keyStr += "Shift+"; + keyStr += (char)key.ascii; + } else { + if (key.flags & KBD_SHIFT) keyStr += "Shift+"; + if (key.keycode >= 0 && key.keycode < keycodeDescTableSize) + keyStr += keycodeDescTable[key.keycode]; + } + + if (keyStr.empty()) keyStr += "???"; + + _keysStr.insertChar(KEY_START_CHAR, _strPos++); + const char *k = keyStr.c_str(); + while (char ch = *k++) + _keysStr.insertChar(ch, _strPos++); + _keysStr.insertChar(KEY_END_CHAR, _strPos++); + + VirtualKeyPress kp; + kp.key = key; + kp.strLen = keyStr.size() + 2; + _keys.insert(_keyPos, kp); +} + +void VirtualKeyboard::KeyPressQueue::deleteKey() { + if (_keyPos == _keys.begin()) + return; + List<VirtualKeyPress>::iterator it = _keyPos; + it--; + _strPos -= it->strLen; + while((it->strLen)-- > 0) + _keysStr.deleteChar(_strPos); + _keys.erase(it); + _strChanged = true; +} + +void VirtualKeyboard::KeyPressQueue::moveLeft() { + if (_keyPos == _keys.begin()) + return; + _keyPos--; + _strPos -= _keyPos->strLen; + _strChanged = true; +} + +void VirtualKeyboard::KeyPressQueue::moveRight() { + if (_keyPos == _keys.end()) + return; + _strPos += _keyPos->strLen; + _keyPos++; + _strChanged = true; +} + +KeyState VirtualKeyboard::KeyPressQueue::pop() { + bool front = (_keyPos == _keys.begin()); + VirtualKeyPress kp = *(_keys.begin()); + _keys.pop_front(); + + if (front) + _keyPos = _keys.begin(); + else + _strPos -= kp.strLen; + + while (kp.strLen-- > 0) + _keysStr.deleteChar(0); + + return kp.key; +} + +void VirtualKeyboard::KeyPressQueue::clear() { + _keys.clear(); + _keyPos = _keys.end(); + _keysStr.clear(); + _strPos = 0; + clearFlags(); + _strChanged = true; +} + +bool VirtualKeyboard::KeyPressQueue::empty() +{ + return _keys.empty(); +} + +String VirtualKeyboard::KeyPressQueue::getString() +{ + if (_keysStr.empty()) + return _flagsStr; + if (_flagsStr.empty()) + return _keysStr; + if (_strPos == _keysStr.size()) + return _keysStr + _flagsStr; + + uint len = _keysStr.size() + _flagsStr.size(); + char *str = new char[len]; + memcpy(str, _keysStr.c_str(), _strPos); + memcpy(str + _strPos, _flagsStr.c_str(), _flagsStr.size()); + memcpy(str + _strPos + _flagsStr.size(), _keysStr.c_str() + _strPos, _keysStr.size() - _strPos); + String ret(str, len); + delete[] str; + return ret; +} + +uint VirtualKeyboard::KeyPressQueue::getInsertIndex() { + return _strPos + _flagsStr.size(); +} + +bool VirtualKeyboard::KeyPressQueue::hasStringChanged() { + bool ret = _strChanged; + _strChanged = false; + return ret; +} + +} // end of namespace Common |