/* 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. * */ #include #include #include "common/translation.h" #include "base/main.h" #include "backends/platform/tizen/form.h" #include "backends/platform/tizen/system.h" using namespace Tizen::Base::Collection; using namespace Tizen::Base::Runtime; using namespace Tizen::Ui::Controls; // round down small Y touch values to 1 to allow the // cursor to be positioned at the top of the screen #define MIN_TOUCH_Y 20 // block for up to 2.5 seconds during shutdown to // allow the game thread to exit gracefully. #define EXIT_SLEEP_STEP 10 #define EXIT_SLEEP 250 // // TizenAppForm // TizenAppForm::TizenAppForm() : _gestureMode(false), _osdMessage(NULL), _gameThread(NULL), _eventQueueLock(NULL), _state(kInitState), _buttonState(kLeftButton), _shortcut(kEscapeKey) { } result TizenAppForm::Construct() { TizenSystem *tizenSystem = NULL; result r = Form::Construct(FORM_STYLE_NORMAL); if (!IsFailed(r)) { tizenSystem = new TizenSystem(this); r = tizenSystem != NULL ? E_SUCCESS : E_OUT_OF_MEMORY; } if (!IsFailed(r)) { r = tizenSystem->Construct(); } if (!IsFailed(r)) { _gameThread = new Thread(); r = _gameThread != NULL ? E_SUCCESS : E_OUT_OF_MEMORY; } if (!IsFailed(r)) { r = _gameThread->Construct(*this); } if (!IsFailed(r)) { _eventQueueLock = new Mutex(); r = _eventQueueLock != NULL ? E_SUCCESS : E_OUT_OF_MEMORY; } if (!IsFailed(r)) { r = _eventQueueLock->Create(); } if (!IsFailed(r)) { g_system = tizenSystem; } else { AppLog("Form startup failed"); delete tizenSystem; delete _gameThread; _gameThread = NULL; } return r; } TizenAppForm::~TizenAppForm() { logEntered(); if (_gameThread && _state != kErrorState) { terminate(); _gameThread->Stop(); if (_state != kErrorState) { _gameThread->Join(); } delete _gameThread; _gameThread = NULL; } delete _eventQueueLock; _eventQueueLock = NULL; logLeaving(); } // // abort the game thread // void TizenAppForm::terminate() { if (_state == kActiveState) { ((TizenSystem *)g_system)->setMute(true); _eventQueueLock->Acquire(); Common::Event e; e.type = Common::EVENT_QUIT; _eventQueue.push(e); _state = kClosingState; _eventQueueLock->Release(); // block while thread ends AppLog("waiting for shutdown"); for (int i = 0; i < EXIT_SLEEP_STEP && _state == kClosingState; i++) { Thread::Sleep(EXIT_SLEEP); } if (_state == kClosingState) { // failed to terminate - Join() will freeze _state = kErrorState; } } } void TizenAppForm::exitSystem() { _state = kErrorState; if (_gameThread) { _gameThread->Stop(); delete _gameThread; _gameThread = NULL; } } result TizenAppForm::OnInitializing(void) { logEntered(); AddOrientationEventListener(*this); AddTouchEventListener(*this); SetMultipointTouchEnabled(true); SetFormBackEventListener(this); SetFormMenuEventListener(this); // set focus to enable receiving key events SetEnabled(true); SetFocusable(true); SetFocus(); return E_SUCCESS; } result TizenAppForm::OnDraw(void) { logEntered(); return E_SUCCESS; } void TizenAppForm::OnOrientationChanged(const Control &source, OrientationStatus orientationStatus) { logEntered(); if (_state == kInitState) { _state = kActiveState; _gameThread->Start(); } } Tizen::Base::Object *TizenAppForm::Run() { logEntered(); scummvm_main(0, 0); if (_state == kActiveState) { Tizen::App::Application::GetInstance()->SendUserEvent(USER_MESSAGE_EXIT, NULL); } _state = kDoneState; return NULL; } bool TizenAppForm::pollEvent(Common::Event &event) { bool result = false; _eventQueueLock->Acquire(); if (!_eventQueue.empty()) { event = _eventQueue.pop(); result = true; } if (_osdMessage) { TizenSystem *system = (TizenSystem *)g_system; TizenGraphicsManager *graphics = system->getGraphics(); if (graphics) { graphics->displayMessageOnOSD(_osdMessage); _osdMessage = NULL; } } _eventQueueLock->Release(); return result; } void TizenAppForm::pushEvent(Common::EventType type, const Point ¤tPosition) { TizenSystem *system = (TizenSystem *)g_system; TizenGraphicsManager *graphics = system->getGraphics(); if (graphics) { // graphics could be NULL at startup or when // displaying the system error screen Common::Event e; e.type = type; e.mouse.x = currentPosition.x; e.mouse.y = currentPosition.y > MIN_TOUCH_Y ? currentPosition.y : 1; bool moved = graphics->moveMouse(e.mouse.x, e.mouse.y); _eventQueueLock->Acquire(); if (moved && type != Common::EVENT_MOUSEMOVE) { Common::Event moveEvent; moveEvent.type = Common::EVENT_MOUSEMOVE; moveEvent.mouse = e.mouse; _eventQueue.push(moveEvent); } _eventQueue.push(e); _eventQueueLock->Release(); } } void TizenAppForm::pushKey(Common::KeyCode keycode) { if (_eventQueueLock) { Common::Event e; e.kbd.keycode = keycode; e.kbd.ascii = keycode; e.kbd.flags = 0; _eventQueueLock->Acquire(); e.type = Common::EVENT_KEYDOWN; _eventQueue.push(e); e.type = Common::EVENT_KEYUP; _eventQueue.push(e); _eventQueueLock->Release(); } } void TizenAppForm::setButtonShortcut() { switch (_buttonState) { case kLeftButton: setMessage(_s("Right Click Once")); _buttonState = kRightButtonOnce; break; case kRightButtonOnce: setMessage(_s("Right Click")); _buttonState = kRightButton; break; case kRightButton: setMessage(_s("Move Only")); _buttonState = kMoveOnly; break; case kMoveOnly: setMessage(_s("Left Click")); _buttonState = kLeftButton; break; } } void TizenAppForm::setMessage(const char *message) { if (_eventQueueLock) { _eventQueueLock->Acquire(); _osdMessage = message; _eventQueueLock->Release(); } } void TizenAppForm::setShortcut() { logEntered(); // cycle to the next shortcut switch (_shortcut) { case kControlMouse: setMessage(_s("Escape Key")); _shortcut = kEscapeKey; break; case kEscapeKey: setMessage(_s("Game Menu")); _shortcut = kGameMenu; break; case kGameMenu: setMessage(_s("Show Keypad")); _shortcut = kShowKeypad; break; case kShowKeypad: setMessage(_s("Control Mouse")); _shortcut = kControlMouse; break; } } void TizenAppForm::invokeShortcut() { logEntered(); switch (_shortcut) { case kControlMouse: setButtonShortcut(); break; case kEscapeKey: pushKey(Common::KEYCODE_ESCAPE); break; case kGameMenu: _buttonState = kLeftButton; pushKey(Common::KEYCODE_F5); break; case kShowKeypad: showKeypad(); break; } } void TizenAppForm::showKeypad() { // display the soft keyboard if (_state == kActiveState) { _buttonState = kLeftButton; Common::Event e; e.type = Common::EVENT_VIRTUAL_KEYBOARD; if (_eventQueueLock) { _eventQueueLock->Acquire(); _eventQueue.push(e); _eventQueueLock->Release(); } } } int TizenAppForm::getTouchCount() { Tizen::Ui::TouchEventManager *touch = Tizen::Ui::TouchEventManager::GetInstance(); IListT *touchList = touch->GetTouchInfoListN(); int touchCount = touchList->GetCount(); touchList->RemoveAll(); delete touchList; return touchCount; } void TizenAppForm::OnTouchDoublePressed(const Control &source, const Point ¤tPosition, const TouchEventInfo &touchInfo) { if (_buttonState != kMoveOnly) { pushEvent(_buttonState == kLeftButton ? Common::EVENT_LBUTTONDOWN : Common::EVENT_RBUTTONDOWN, currentPosition); } } void TizenAppForm::OnTouchFocusIn(const Control &source, const Point ¤tPosition, const TouchEventInfo &touchInfo) { } void TizenAppForm::OnTouchFocusOut(const Control &source, const Point ¤tPosition, const TouchEventInfo &touchInfo) { } void TizenAppForm::OnTouchLongPressed(const Control &source, const Point ¤tPosition, const TouchEventInfo &touchInfo) { logEntered(); if (_buttonState != kLeftButton) { pushKey(Common::KEYCODE_RETURN); } } void TizenAppForm::OnTouchMoved(const Control &source, const Point ¤tPosition, const TouchEventInfo &touchInfo) { if (!_gestureMode) { pushEvent(Common::EVENT_MOUSEMOVE, currentPosition); } } void TizenAppForm::OnTouchPressed(const Control &source, const Point ¤tPosition, const TouchEventInfo &touchInfo) { if (getTouchCount() > 1) { _gestureMode = true; } else if (_buttonState != kMoveOnly) { pushEvent(_buttonState == kLeftButton ? Common::EVENT_LBUTTONDOWN : Common::EVENT_RBUTTONDOWN, currentPosition); } } void TizenAppForm::OnTouchReleased(const Control &source, const Point ¤tPosition, const TouchEventInfo &touchInfo) { if (_gestureMode) { int touchCount = getTouchCount(); if (touchCount == 1) { setShortcut(); } else { if (touchCount == 2) { invokeShortcut(); } _gestureMode = false; } } else if (_buttonState != kMoveOnly) { pushEvent(_buttonState == kLeftButton ? Common::EVENT_LBUTTONUP : Common::EVENT_RBUTTONUP, currentPosition); if (_buttonState == kRightButtonOnce) { _buttonState = kLeftButton; } // flick to skip dialog if (touchInfo.IsFlicked()) { pushKey(Common::KEYCODE_PERIOD); } } } void TizenAppForm::OnFormBackRequested(Form &source) { logEntered(); if (_state == kActiveState) { invokeShortcut(); } } void TizenAppForm::OnFormMenuRequested(Form &source) { logEntered(); if (_state == kActiveState) { setShortcut(); } }