diff options
-rw-r--r-- | backends/common/virtual-keyboard-parser.cpp | 97 | ||||
-rw-r--r-- | backends/common/virtual-keyboard-parser.h | 4 | ||||
-rw-r--r-- | backends/common/virtual-keyboard.cpp | 106 | ||||
-rw-r--r-- | backends/common/virtual-keyboard.h | 67 |
4 files changed, 220 insertions, 54 deletions
diff --git a/backends/common/virtual-keyboard-parser.cpp b/backends/common/virtual-keyboard-parser.cpp index 7b1e79e937..ed77bc215c 100644 --- a/backends/common/virtual-keyboard-parser.cpp +++ b/backends/common/virtual-keyboard-parser.cpp @@ -240,20 +240,20 @@ bool VirtualKeyboardParser::parserCallback_Event() { uint16 ascii = atoi(evtNode->values["ascii"].c_str()); byte flags = 0; - if (evtNode->values.contains("flags")) { - Common::StringTokenizer tok(evtNode->values["flags"], ", "); - for (Common::String fl = tok.nextToken(); !fl.empty(); fl = tok.nextToken()) { - if (fl == "ctrl" || fl == "control") - flags &= Common::KBD_CTRL; - else if (fl == "alt") - flags &= Common::KBD_ALT; - else if (fl == "shift") - flags &= Common::KBD_SHIFT; - } - } + if (evtNode->values.contains("flags")) + flags = parseFlags(evtNode->values["flags"]); evt.data = new Common::KeyState(code, ascii, flags); + } else if (type == "modifier") { + if (!evtNode->values.contains("flags")) + return parserError("Key modifier element must contain modifier attributes"); + + evt.type = VirtualKeyboard::kEventModifier; + byte *flags = new byte; + *(flags) = parseFlags(evtNode->values["flags"]); + evt.data = flags; + } else if (type == "switch_mode") { if (!evtNode->values.contains("mode")) return parserError("Switch mode event element must contain mode attribute"); @@ -335,29 +335,62 @@ bool VirtualKeyboardParser::parserCallback_Area() { if (!areaNode->values.contains("shape") || !areaNode->values.contains("coords") || !areaNode->values.contains("target")) return parserError("Area element must contain shape, coords and target attributes"); - Common::String shape = areaNode->values["shape"]; - if (shape == "rect") { - Common::Rect *rect = _mode->imageMap.createRectArea(areaNode->values["target"]); - int x1, y1, x2, y2; - if (!parseIntegerKey(areaNode->values["coords"].c_str(), 4, &x1, &y1, &x2, &y2)) - return parserError("Invalid coords for rect area"); - rect->left = x1; rect->top = y1; rect->right = x2; rect->bottom = y2; + Common::String& shape = areaNode->values["shape"]; + Common::String& target = areaNode->values["target"]; + Common::String& coords = areaNode->values["coords"]; + + if (target == "preview_area") { + if (shape != "rect") + return parserError("preview_area must be a rect area"); + _mode->previewArea = new Common::Rect(); + return parseRect(_mode->previewArea, coords); + } else if (shape == "rect") { + Common::Rect *rect = _mode->imageMap.createRectArea(target); + return parseRect(rect, coords); } else if (shape == "poly") { - Common::StringTokenizer tok (areaNode->values["coords"], ", "); - Common::Polygon *poly = _mode->imageMap.createPolygonArea(areaNode->values["target"]); - for (Common::String st = tok.nextToken(); !st.empty(); st = tok.nextToken()) { - int x, y; - if (sscanf(st.c_str(), "%d", &x) != 1) - return parserError("Invalid coords for polygon area"); - st = tok.nextToken(); - if (sscanf(st.c_str(), "%d", &y) != 1) - return parserError("Invalid coords for polygon area"); - poly->addPoint(x, y); - } - if (poly->getPointCount() < 3) + Common::Polygon *poly = _mode->imageMap.createPolygonArea(target); + return parsePolygon(poly, coords); + } + return parserError("Area shape '%s' not known", shape.c_str()); +} + +byte VirtualKeyboardParser::parseFlags(const String& flags) { + Common::StringTokenizer tok(flags, ", "); + byte val = 0; + for (Common::String fl = tok.nextToken(); !fl.empty(); fl = tok.nextToken()) { + if (fl == "ctrl" || fl == "control") + val &= Common::KBD_CTRL; + else if (fl == "alt") + val &= Common::KBD_ALT; + else if (fl == "shift") + val &= Common::KBD_SHIFT; + } + return val; +} + +bool VirtualKeyboardParser::parseRect(Common::Rect *rect, const String& coords) { + int x1, y1, x2, y2; + if (!parseIntegerKey(coords.c_str(), 4, &x1, &y1, &x2, &y2)) + return parserError("Invalid coords for rect area"); + rect->left = x1; rect->top = y1; rect->right = x2; rect->bottom = y2; + if (!rect->isValidRect()) + return parserError("Rect area is not a valid rectangle"); + return true; +} + +bool VirtualKeyboardParser::parsePolygon(Common::Polygon *poly, const String& coords) { + Common::StringTokenizer tok (coords, ", "); + for (Common::String st = tok.nextToken(); !st.empty(); st = tok.nextToken()) { + int x, y; + if (sscanf(st.c_str(), "%d", &x) != 1) return parserError("Invalid coords for polygon area"); - } else - return parserError("Area shape '%s' not known", shape.c_str()); + st = tok.nextToken(); + if (sscanf(st.c_str(), "%d", &y) != 1) + return parserError("Invalid coords for polygon area"); + poly->addPoint(x, y); + } + if (poly->getPointCount() < 3) + return parserError("Invalid coords for polygon area"); return true; } diff --git a/backends/common/virtual-keyboard-parser.h b/backends/common/virtual-keyboard-parser.h index cd2ea28faf..dfb7286191 100644 --- a/backends/common/virtual-keyboard-parser.h +++ b/backends/common/virtual-keyboard-parser.h @@ -203,6 +203,10 @@ protected: bool parserCallback_KeyboardClosed(); bool parserCallback_ModeClosed(); + byte parseFlags(const String& flags); + bool parseRect(Common::Rect *rect, const String& coords); + bool parsePolygon(Common::Polygon *poly, const String& coords); + Common::HashMap<Common::String, ParserCallback, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> _callbacks; Common::HashMap<Common::String, ParserCallback, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> _closedCallbacks; }; diff --git a/backends/common/virtual-keyboard.cpp b/backends/common/virtual-keyboard.cpp index 0a061df545..e6ef87b946 100644 --- a/backends/common/virtual-keyboard.cpp +++ b/backends/common/virtual-keyboard.cpp @@ -63,6 +63,7 @@ void VirtualKeyboard::reset() { _vAlignment = kAlignBottom; _keyQueue.clear(); _keyDown = 0; + _keyFlags = 0; _displaying = _drag = false; _firstRun = true; _lastScreenChanged = _system->getScreenChangeID(); @@ -196,13 +197,23 @@ void VirtualKeyboard::processClick(const Common::String& area) { Event evt = _currentMode->events[area]; switch (evt.type) { - case kEventKey: + case kEventKey: { // add virtual keypress to queue - _keyQueue.push(*(Common::KeyState*)evt.data); + Common::KeyState key = *(Common::KeyState*)evt.data; + key.flags ^= _keyFlags; + if ((key.keycode >= Common::KEYCODE_a) && (key.keycode <= Common::KEYCODE_z)) + key.ascii = (key.flags & Common::KBD_SHIFT) ? key.keycode - 32 : key.keycode; + _keyQueue.insertKey(key); + _keyFlags = 0; + break; + } + case kEventModifier: + _keyFlags ^= *(byte*)(evt.data); break; case kEventSwitchMode: // switch to new mode switchMode(*(Common::String *)evt.data); + _keyFlags = 0; break; case kEventClose: // close virtual keyboard @@ -247,7 +258,6 @@ void VirtualKeyboard::show() { _system->showOverlay(); _system->clearOverlay(); } - _overlayBackup.create(_system->getOverlayWidth(), _system->getOverlayHeight(), sizeof(OverlayColor)); _system->grabOverlay((OverlayColor*)_overlayBackup.pixels, _overlayBackup.w); setupCursor(); @@ -382,4 +392,94 @@ void VirtualKeyboard::removeCursor() { CursorMan.popCursorPalette(); } +VirtualKeyboard::Queue::Queue() { + _keyPos = _keys.begin(); + _strPos = 0; +} + +void VirtualKeyboard::Queue::insertKey(KeyState key) { + switch (key.keycode) { + case KEYCODE_LEFT: + moveLeft(); + return; + case KEYCODE_RIGHT: + moveRight(); + return; + case KEYCODE_BACKSPACE: + deleteKey(); + return; + } + + String keyStr; + if (key.keycode >= 32 && key.keycode <= 126) { + if (key.flags & KBD_CTRL) + keyStr += "Ctrl+"; + if (key.flags & KBD_ALT) + keyStr += "Alt+"; + if (key.flags & KBD_SHIFT && (key.ascii < 65 || key.ascii > 90)) + keyStr += "Shift+"; + keyStr += (char)key.ascii; + } + + const char *k = keyStr.c_str(); + while (char ch = *k++) + _str.insertChar(ch, _strPos++); + + VirtualKeyPress kp; + kp.key = key; + kp.strLen = keyStr.size(); + _keys.insert(_keyPos, kp); + _keyPos++; +} + +void VirtualKeyboard::Queue::deleteKey() { + if (_keyPos == _keys.begin()) + return; + List<VirtualKeyPress>::iterator it = _keyPos; + it--; + _strPos -= it->strLen; + while((it->strLen)-- > 0) + _str.deleteChar(_strPos); + _keys.erase(it); +} + +void VirtualKeyboard::Queue::moveLeft() { + if (_keyPos == _keys.begin()) + return; + _keyPos--; + _strPos -= _keyPos->strLen; +} + +void VirtualKeyboard::Queue::moveRight() { + List<VirtualKeyPress>::iterator it = _keyPos; + it++; + if (it == _keys.end()) + return; + _strPos += _keyPos->strLen; + _keyPos = it; +} + +KeyState VirtualKeyboard::Queue::pop() { + KeyState ret = _keys.begin()->key; + _keys.pop_front(); + return ret; +} + +void VirtualKeyboard::Queue::clear() { + _keys.clear(); + _keyPos = _keys.begin(); + _str.clear(); + _strPos = 0; +} + +bool VirtualKeyboard::Queue::empty() +{ + return _keys.empty(); +} + +String VirtualKeyboard::Queue::getString() +{ + return _str; +} + } // end of namespace Common diff --git a/backends/common/virtual-keyboard.h b/backends/common/virtual-keyboard.h index fc2300c24c..3494de1e47 100644 --- a/backends/common/virtual-keyboard.h +++ b/backends/common/virtual-keyboard.h @@ -33,7 +33,7 @@ class OSystem; #include "common/hash-str.h" #include "common/image-map.h" #include "common/keyboard.h" -#include "common/queue.h" +#include "common/list.h" #include "common/str.h" #include "graphics/surface.h" @@ -42,9 +42,10 @@ namespace Common { class VirtualKeyboardParser; class VirtualKeyboard { - +protected: enum EventType { kEventKey, + kEventModifier, kEventSwitchMode, kEventClose }; @@ -59,14 +60,16 @@ class VirtualKeyboard { typedef Common::HashMap<Common::String, Event, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> EventMap; struct Mode { - Common::String name; - Common::String resolution; - Common::String bitmapName; - Graphics::Surface *image; - OverlayColor transparentColor; - Common::ImageMap imageMap; - EventMap events; - Mode() : image(0) {} + Common::String name; + Common::String resolution; + Common::String bitmapName; + Graphics::Surface *image; + OverlayColor transparentColor; + Common::ImageMap imageMap; + EventMap events; + Common::Rect *previewArea; + + Mode() : image(0), previewArea(0) {} }; typedef Common::HashMap<Common::String, Mode, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> ModeMap; @@ -83,6 +86,31 @@ class VirtualKeyboard { kAlignBottom }; + struct VirtualKeyPress { + Common::KeyState key; + uint strLen; + }; + + class Queue { + public: + Queue(); + void insertKey(KeyState key); + void deleteKey(); + void moveLeft(); + void moveRight(); + KeyState pop(); + void clear(); + bool empty(); + String getString(); + + private: + List<VirtualKeyPress> _keys; + List<VirtualKeyPress>::iterator _keyPos; + + String _str; + uint _strPos; + }; + public: VirtualKeyboard(); virtual ~VirtualKeyboard(); @@ -122,15 +150,19 @@ public: return _loaded; } -protected: +protected: // TODO : clean up all this stuff OSystem *_system; + byte _keyFlags; + Queue _keyQueue; + KeyState *_keyDown; + + static const int SNAP_WIDTH = 10; friend class VirtualKeyboardParser; VirtualKeyboardParser *_parser; - // TODO : sort order of all this stuff void reset(); void deleteEventData(); void screenChanged(); @@ -139,7 +171,7 @@ protected: void move(int16 x, int16 y); void switchMode(Mode *newMode); void switchMode(const Common::String& newMode); - Common::String findArea(int16 x, int16 y); + String findArea(int16 x, int16 y); void processClick(const Common::String &area); void runLoop(); void redraw(); @@ -156,18 +188,15 @@ protected: Mode *_currentMode; int _lastScreenChanged; - Common::Rect _kbdBound; + Rect _kbdBound; HorizontalAlignment _hAlignment; VerticalAlignment _vAlignment; - Common::String _areaDown; - Common::Point _dragPoint; + String _areaDown; + Point _dragPoint; bool _drag; - Common::Queue<Common::KeyState> _keyQueue; - Common::KeyState *_keyDown; - static const int kCursorAnimateDelay = 250; int _cursorAnimateCounter; int _cursorAnimateTimer; |