diff options
-rw-r--r-- | backends/events/webossdl/webossdl-events.cpp | 314 | ||||
-rw-r--r-- | backends/events/webossdl/webossdl-events.h | 67 |
2 files changed, 284 insertions, 97 deletions
diff --git a/backends/events/webossdl/webossdl-events.cpp b/backends/events/webossdl/webossdl-events.cpp index 76c4fd7976..778f41dd7e 100644 --- a/backends/events/webossdl/webossdl-events.cpp +++ b/backends/events/webossdl/webossdl-events.cpp @@ -22,13 +22,10 @@ #ifdef WEBOS -// Allow use of stuff in <time.h> -#define FORBIDDEN_SYMBOL_EXCEPTION_time_h - #include "common/scummsys.h" #include "common/system.h" -#include "sys/time.h" -#include "time.h" +#include "common/str.h" +#include "common/translation.h" #include "backends/events/webossdl/webossdl-events.h" #include "gui/message.h" @@ -36,20 +33,6 @@ #include "PDL.h" /** - * Construct a new WebOSSdlEventSource. - */ -WebOSSdlEventSource::WebOSSdlEventSource() : - _gestureDown(false), - _screenDownTime(0), - _dragStartTime(0), - _motionPtrIndex(-1), - _dragDiffX(0), _dragDiffY(0), - _dragging(false), - _curX(0), _curY(0) { - -} - -/** * WebOS devices only have a Shift key and a CTRL key. There is also an Alt * key (the orange key) but this is already processed by WebOS to change the * mode of the keys so ScummVM must not use this key as a modifier. Instead @@ -76,7 +59,7 @@ void WebOSSdlEventSource::SDLModToOSystemKeyFlags(SDLMod mod, * Before calling the original SDL implementation this method checks if the * gesture area is pressed down. * - * @param ev The SDL event + * @param ev The SDL event * @param event The ScummVM event. * @return True if event was processed, false if not. */ @@ -113,7 +96,7 @@ bool WebOSSdlEventSource::handleKeyDown(SDL_Event &ev, Common::Event &event) { * Before calling the original SDL implementation this method checks if the * gesture area has been released. * - * @param ev The SDL event + * @param ev The SDL event * @param event The ScummVM event. * @return True if event was processed, false if not. */ @@ -141,23 +124,52 @@ bool WebOSSdlEventSource::handleKeyUp(SDL_Event &ev, Common::Event &event) { /** * Handles mouse button press. * - * @param ev The SDL event + * @param ev The SDL event * @param event The ScummVM event. * @return True if event was processed, false if not. */ -bool WebOSSdlEventSource::handleMouseButtonDown(SDL_Event &ev, Common::Event &event) { - if (_motionPtrIndex == -1) { - _motionPtrIndex = ev.button.which; - _dragDiffX = 0; - _dragDiffY = 0; - _screenDownTime = g_system->getMillis(); +bool WebOSSdlEventSource::handleMouseButtonDown(SDL_Event &ev, + Common::Event &event) { + _dragDiffX[ev.button.which] = 0; + _dragDiffY[ev.button.which] = 0; + _fingerDown[ev.button.which] = true; + _screenDownTime[ev.button.which] = g_system->getMillis(); - // Start dragging when pressing the screen shortly after a tap. - if (g_system->getMillis() - _dragStartTime < 250) { + if (ev.button.which == 0) { + // Do a click when the finger lifts unless we leave the range + _doClick = true; + // Queue up dragging if auto-drag mode is on + if (_autoDragMode) + _queuedDragTime = g_system->getMillis() + QUEUED_DRAG_DELAY; + // Turn drag mode on instantly for a double-tap + else if (g_system->getMillis() - _dragStartTime < 400) { _dragging = true; event.type = Common::EVENT_LBUTTONDOWN; processMouseEvent(event, _curX, _curY); } + // If we're not in touchpad mode, move the cursor to the tap + if (!_touchpadMode) { + int screenX = g_system->getOverlayWidth(); + int screenY = g_system->getOverlayHeight(); + _curX = MIN(screenX, MAX(0, 0 + ev.motion.x)); + _curY = MIN(screenY, MAX(0, 0 + ev.motion.y)); + // If we're already clicking, hold it until after the move. + if (event.type == Common::EVENT_LBUTTONDOWN) { + processMouseEvent(event, _curX, _curY); + g_system->getEventManager()->pushEvent(event); + } + // Move the mouse + event.type = Common::EVENT_MOUSEMOVE; + processMouseEvent(event, _curX, _curY); + } + // Watch for a double-tap-triggered drag + _dragStartTime = g_system->getMillis(); + } + // Kill any queued drag event if a second finger goes down + else if (ev.button.which == 1) { + if (_queuedDragTime > 0) + _queuedDragTime = 0; + _doClick = false; } return true; } @@ -165,74 +177,58 @@ bool WebOSSdlEventSource::handleMouseButtonDown(SDL_Event &ev, Common::Event &ev /** * Handles mouse button release. * - * @param ev The SDL event + * @param ev The SDL event * @param event The ScummVM event. * @return True if event was processed, false if not. */ -bool WebOSSdlEventSource::handleMouseButtonUp(SDL_Event &ev, Common::Event &event) { - if (_motionPtrIndex == ev.button.which) { - _motionPtrIndex = -1; - - int screenY = g_system->getOverlayHeight(); - - // 60% of the screen height for menu dialog/keyboard - if (ABS(_dragDiffY) >= ABS(screenY*0.6)) { - if (_dragDiffY >= 0) { - int gblPDKVersion = PDL_GetPDKVersion(); - // check for correct PDK Version - if (gblPDKVersion >= 300) { - PDL_SetKeyboardState(PDL_TRUE); - return true; - } - } else { - if (g_engine && !g_engine->isPaused()) { - g_engine->openMainMenuDialog(); - return true; - } - } - } - - // When drag mode was active then simply send a mouse up event - if (_dragging) { +bool WebOSSdlEventSource::handleMouseButtonUp(SDL_Event &ev, + Common::Event &event) { + // Only react if the finger hasn't been virtually lifted already + if (_fingerDown[ev.button.which]) { + // No matter what, if it's the first finger that's lifted when + // we're dragging, just lift the mouse button. + if (ev.button.which == 0 && _dragging) { event.type = Common::EVENT_LBUTTONUP; processMouseEvent(event, _curX, _curY); _dragging = false; - return true; } - - // When mouse was moved 5 pixels or less then emulate a mouse button - // click. - if (ABS(_dragDiffX) < 6 && ABS(_dragDiffY) < 6) { - int duration = g_system->getMillis() - _screenDownTime; - - // When screen was pressed for less than 500ms then emulate a - // left mouse click. - if (duration < 500) { + else { + // If it was the first finger and the click hasn't been + // canceled, it's a click. + if (ev.button.which == 0 && _doClick && + !_fingerDown[1] && !_fingerDown[2]) { event.type = Common::EVENT_LBUTTONUP; processMouseEvent(event, _curX, _curY); g_system->getEventManager()->pushEvent(event); event.type = Common::EVENT_LBUTTONDOWN; - _dragStartTime = g_system->getMillis(); + if (_queuedDragTime > 0) + _queuedDragTime = 0; } - // When screen was pressed for less than 1000ms then emulate a + // If the first finger's down and the second taps, it's a // right mouse click. - else if (duration < 1000) { + else if (ev.button.which == 1 && + _fingerDown[0] && _fingerDown[1] && !_fingerDown[2]) { event.type = Common::EVENT_RBUTTONUP; processMouseEvent(event, _curX, _curY); g_system->getEventManager()->pushEvent(event); event.type = Common::EVENT_RBUTTONDOWN; } - // When screen was pressed for more than 1000ms then emulate a - // middle mouse click. - else { + // If two fingers are down and a third taps, it's a middle + // click -- but lift the second finger so it doesn't register + // as a right click. + else if (ev.button.which == 2 && + _fingerDown[0] && _fingerDown[1]) { event.type = Common::EVENT_MBUTTONUP; processMouseEvent(event, _curX, _curY); g_system->getEventManager()->pushEvent(event); event.type = Common::EVENT_MBUTTONDOWN; + _fingerDown[1] = false; } } + // Officially lift the finger that was raised. + _fingerDown[ev.button.which] = false; } return true; } @@ -240,22 +236,178 @@ bool WebOSSdlEventSource::handleMouseButtonUp(SDL_Event &ev, Common::Event &even /** * Handles mouse motion. * - * @param ev The SDL event + * @param ev The SDL event * @param event The ScummVM event. * @return True if event was processed, false if not. */ -bool WebOSSdlEventSource::handleMouseMotion(SDL_Event &ev, Common::Event &event) { - if (ev.motion.which == _motionPtrIndex) { +bool WebOSSdlEventSource::handleMouseMotion(SDL_Event &ev, + Common::Event &event) { + if (_fingerDown[ev.motion.which]) { + _dragDiffX[ev.motion.which] += ev.motion.xrel; + _dragDiffY[ev.motion.which] += ev.motion.yrel; int screenX = g_system->getOverlayWidth(); int screenY = g_system->getOverlayHeight(); - _curX = MIN(screenX, MAX(0, _curX + ev.motion.xrel)); - _curY = MIN(screenY, MAX(0, _curY + ev.motion.yrel)); - _dragDiffX += ev.motion.xrel; - _dragDiffY += ev.motion.yrel; - event.type = Common::EVENT_MOUSEMOVE; - processMouseEvent(event, _curX, _curY); + + switch (ev.motion.which) { + case 0: + // If our dragDiff goes too many pixels in either direction, + // kill the future click and any queued drag event. + if (_doClick && (ABS(_dragDiffX[0]) > 5 || + ABS(_dragDiffY[0]) > 5)) { + _doClick = false; + if (_queuedDragTime > 0) + _queuedDragTime = 0; + } + // If only one finger is on the screen and moving, that's + // the mouse pointer. + if (!_fingerDown[1] && !_fingerDown[2]) { + if (_touchpadMode) { + _curX = MIN(screenX, MAX(0, _curX + ev.motion.xrel)); + _curY = MIN(screenY, MAX(0, _curY + ev.motion.yrel)); + } else { + _curX = MIN(screenX, MAX(0, 0 + ev.motion.x)); + _curY = MIN(screenY, MAX(0, 0 + ev.motion.y)); + } + event.type = Common::EVENT_MOUSEMOVE; + processMouseEvent(event, _curX, _curY); + } + break; + case 1: + // Check for a two-finger swipe + if (_fingerDown[0] && !_fingerDown[2]) { + // Check for a vertical 20% swipe + if (ABS(_dragDiffY[0]) > screenY * 0.2 && + ABS(_dragDiffY[1]) > screenY * 0.2) { + // Virtually lift fingers to prevent repeat triggers + _fingerDown[0] = _fingerDown[1] = false; + if (_dragDiffY[0] < 0 && _dragDiffY[1] < 0) { + // A swipe up triggers the keyboard, if it exists + int gblPDKVersion = PDL_GetPDKVersion(); + if (gblPDKVersion >= 300) + PDL_SetKeyboardState(PDL_TRUE); + } else if (_dragDiffY[0] > 0 && _dragDiffY[1] > 0){ + // A swipe down triggers the menu + if (g_engine && !g_engine->isPaused()) + g_engine->openMainMenuDialog(); + } + return true; + } + // Check for a horizontal 15% swipe + if (ABS(_dragDiffX[0]) > screenX * 0.15 && + ABS(_dragDiffX[1]) > screenX * 0.15) { + // Virtually lift fingers to prevent repeat triggers + _fingerDown[0] = _fingerDown[1] = false; + if (_dragDiffX[0] < 0 && _dragDiffX[1] < 0) { + // A swipe left presses escape + event.type = Common::EVENT_KEYDOWN; + event.kbd.flags = 0; + event.kbd.keycode = Common::KEYCODE_ESCAPE; + event.kbd.ascii = Common::ASCII_ESCAPE; + _queuedEscapeUpTime = g_system->getMillis() + + QUEUED_KEY_DELAY; + } else if (_dragDiffX[0] > 0 && _dragDiffX[1] > 0) { + // A swipe right toggles touchpad mode + _touchpadMode = !_touchpadMode; + g_system->showMouse(_touchpadMode); + Common::String dialogMsg(_("Touchpad mode is now ")); + dialogMsg += (_touchpadMode ? _("ON") : _("OFF")); + dialogMsg += ".\n"; + dialogMsg += + _("Swipe two fingers to the right to toggle."); + GUI::TimedMessageDialog dialog(dialogMsg, 1500); + dialog.runModal(); + } + return true; + } + } + break; + case 2: + // Check for a three-finger 15% swipe + if (_fingerDown[0] && _fingerDown[1]) { + // Swipe to the right toggles Auto-drag + if (_dragDiffX[0] > screenX * 0.15 && + _dragDiffX[1] > screenX * 0.15 && + _dragDiffX[2] > screenX * 0.15) { + // Virtually lift fingers to prevent repeat triggers + _fingerDown[0] = _fingerDown[1] = _fingerDown[2] = false; + // Toggle Auto-drag mode + _autoDragMode = !_autoDragMode; + Common::String dialogMsg(_("Auto-drag mode is now ")); + dialogMsg += (_autoDragMode ? _("ON") : _("OFF")); + dialogMsg += ".\n"; + dialogMsg += _( + "Swipe three fingers to the right to toggle."); + GUI::TimedMessageDialog dialog(dialogMsg, 1500); + dialog.runModal(); + return true; + } + // Swipe down to emulate spacebar (pause) + else if (_dragDiffY[0] > screenY * 0.15 && + _dragDiffY[1] > screenY * 0.15 && + _dragDiffY[2] > screenY * 0.15) { + // Virtually lift fingers to prevent repeat triggers + _fingerDown[0] = _fingerDown[1] = _fingerDown[2] = false; + // Press space + event.type = Common::EVENT_KEYDOWN; + event.kbd.flags = 0; + event.kbd.keycode = Common::KEYCODE_SPACE; + event.kbd.ascii = Common::ASCII_SPACE; + _queuedSpaceUpTime = g_system->getMillis() + + QUEUED_KEY_DELAY; + } + } + } } return true; } +/** + * Before calling the original SDL implementation, this method loads in + * queued events. + * + * @param event The ScummVM event + */ +bool WebOSSdlEventSource::pollEvent(Common::Event &event) { + uint32 curTime = g_system->getMillis(); + + // Run down the priority list for queued events. The built-in + // event queue runs events on the next poll, which causes many + // WebOS devices to ignore certain inputs. Allowing keys to + // stay "down" longer is enough to register the press. + if (_queuedEscapeUpTime != 0 && curTime >= _queuedEscapeUpTime) { + event.type = Common::EVENT_KEYUP; + event.kbd.flags = 0; + event.kbd.keycode = Common::KEYCODE_ESCAPE; + event.kbd.ascii = Common::ASCII_ESCAPE; + _queuedEscapeUpTime = 0; + return true; + } + else if (_queuedSpaceUpTime != 0 && curTime >= _queuedSpaceUpTime) { + event.type = Common::EVENT_KEYUP; + event.kbd.flags = 0; + event.kbd.keycode = Common::KEYCODE_SPACE; + event.kbd.ascii = Common::ASCII_SPACE; + _queuedSpaceUpTime = 0; + return true; + } + else if (_queuedDragTime != 0 && curTime >= _queuedDragTime) { + event.type = Common::EVENT_LBUTTONDOWN; + _dragging = true; + processMouseEvent(event, _curX, _curY); + _queuedDragTime = 0; + return true; + } + + // Having a mouse pointer on screen when not in Touchpad mode is poor + // interface design, because the user won't know whether to tap buttons + // or drag the pointer to them. On the first poll, set the appropriate + // pointer visibility. + if (_firstPoll) { + g_system->showMouse(_touchpadMode); + _firstPoll = false; + } + + return SdlEventSource::pollEvent(event); +} + #endif diff --git a/backends/events/webossdl/webossdl-events.h b/backends/events/webossdl/webossdl-events.h index ad69fa27e4..a623a133b8 100644 --- a/backends/events/webossdl/webossdl-events.h +++ b/backends/events/webossdl/webossdl-events.h @@ -30,38 +30,73 @@ */ class WebOSSdlEventSource : public SdlEventSource { public: - WebOSSdlEventSource(); + enum { + MAX_FINGERS = 3 + }; + WebOSSdlEventSource() : + _gestureDown(false), + _dragStartTime(0), + _dragging(false), + _curX(0), _curY(0), + _touchpadMode(false), + _autoDragMode(true), + _doClick(true), + _queuedDragTime(0), _queuedEscapeUpTime(0), _queuedSpaceUpTime(0), + _firstPoll(true), + QUEUED_KEY_DELAY(250), QUEUED_DRAG_DELAY(500) { + for (int i = 0; i < MAX_FINGERS; i++) { + _fingerDown[i] = false; + _screenDownTime[i] = _dragDiffX[i] = _dragDiffY[i] = 0; + } + }; protected: // Inidicates if gesture area is pressed down or not. bool _gestureDown; - - // The timestamp when screen was pressed down. - uint32 _screenDownTime; - + + // The timestamp when screen was pressed down for each finger. + uint32 _screenDownTime[MAX_FINGERS]; + // The timestamp when a possible drag operation was triggered. uint32 _dragStartTime; - - // The index of the motion pointer. - int _motionPtrIndex; - - // The maximum horizontal motion during dragging (For tap recognition). - int _dragDiffX; - - // The maximum vertical motion during dragging (For tap recognition). - int _dragDiffY; - + + // The distance each finger traveled from touch to release. + int _dragDiffX[MAX_FINGERS], _dragDiffY[MAX_FINGERS]; + // Indicates if we are in drag mode. bool _dragging; - + // The current mouse position on the screen. int _curX, _curY; + // Indicates if we're in touchpad mode or tap-to-move mode. + bool _touchpadMode; + + // Indicates if we're in automatic drag mode. + bool _autoDragMode; + + // Tracks which fingers are currently touching the screen. + bool _fingerDown[MAX_FINGERS]; + + // Indicates if a click should be executed when the first finger is lifted + bool _doClick; + + // Indicates whether the event poll has been run before + bool _firstPoll; + + // Event queues + uint32 _queuedDragTime, _queuedEscapeUpTime, _queuedSpaceUpTime; + + // Standard event queue delays in milliseconds + const int QUEUED_KEY_DELAY; + const int QUEUED_DRAG_DELAY; + virtual void SDLModToOSystemKeyFlags(SDLMod mod, Common::Event &event); virtual bool handleKeyDown(SDL_Event &ev, Common::Event &event); virtual bool handleKeyUp(SDL_Event &ev, Common::Event &event); virtual bool handleMouseButtonDown(SDL_Event &ev, Common::Event &event); virtual bool handleMouseButtonUp(SDL_Event &ev, Common::Event &event); virtual bool handleMouseMotion(SDL_Event &ev, Common::Event &event); + virtual bool pollEvent(Common::Event &event); }; #endif |