/* 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: https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/trunk/backends/platform/psp/osys_psp.cpp $ * $Id: osys_psp.cpp 43618 2009-08-21 22:44:49Z joostp $ * */ // Todo: handle events that should fire because of shift going off // Solution: handle shift on a button-by-button basis, only allowing it when the button is up. Also a inputmap-wide button. At buttonup, shiftstate is inspected per button. //#define __PSP_DEBUG_FUNCS__ /* Uncomment for debugging the stack */ //#define __PSP_DEBUG_PRINT__ /* Uncomment for debug prints */ #include "backends/platform/psp/trace.h" #include "backends/platform/psp/input.h" // Defines for working with PSP buttons #define CHANGED(x) (_buttonsChanged & (x)) #define PRESSED(x) ((_buttonsChanged & (x)) && (pad.Buttons & (x))) #define UNPRESSED(x) ((_buttonsChanged & (x)) && !(pad.Buttons & (x))) #define DOWN(x) (pad.Buttons & (x)) #define UP(x) (!(pad.Buttons & (x))) #define PSP_DPAD (PSP_CTRL_DOWN|PSP_CTRL_UP|PSP_CTRL_LEFT|PSP_CTRL_RIGHT) #define PSP_4BUTTONS (PSP_CTRL_CROSS | PSP_CTRL_CIRCLE | PSP_CTRL_TRIANGLE | PSP_CTRL_SQUARE) #define PSP_TRIGGERS (PSP_CTRL_LTRIGGER | PSP_CTRL_RTRIGGER) #define PAD_CHECK_TIME 53 void InputHandler::init() { sceCtrlSetSamplingCycle(0); // set sampling to vsync. n = n usecs sceCtrlSetSamplingMode(1); // analog } bool InputHandler::getAllInputs(Common::Event &event) { DEBUG_ENTER_FUNC(); uint32 time = g_system->getMillis(); // may not be necessary with read if (time - _lastPadCheckTime < PAD_CHECK_TIME) { return false; } _lastPadCheckTime = time; SceCtrlData pad; sceCtrlPeekBufferPositive(&pad, 1); // Peek ignores sleep. Read sleeps thread bool haveEvent; memset(&event, 0, sizeof(event)); if (_keyboard->isVisible()) haveEvent = _keyboard->processInput(event, pad); else haveEvent = getEvent(event, pad); if (haveEvent) { PSP_DEBUG_PRINT("Have event[%s]\n", haveEvent ? "true" : "false"); PSP_DEBUG_PRINT("event.type[%d]\n", event.type); } return haveEvent; } bool InputHandler::getEvent(Common::Event &event, SceCtrlData &pad) { DEBUG_ENTER_FUNC(); _buttonsChanged = pad.Buttons ^ _prevButtons; bool haveEvent = false; // Collect events from different sources haveEvent = getDpadEvent(event, pad); if (!haveEvent) haveEvent = getButtonEvent(event, pad); if (!haveEvent) haveEvent = getNubEvent(event, pad); _prevButtons = pad.Buttons; return haveEvent; } bool InputHandler::getDpadEvent(Common::Event &event, SceCtrlData &pad) { DEBUG_ENTER_FUNC(); int newDpadX = 0, newDpadY = 0; bool haveEvent = false; if (DOWN(PSP_CTRL_UP)) { newDpadY++; if (DOWN(PSP_CTRL_RTRIGGER)) // Shifting causes diagonals newDpadX++; } if (DOWN(PSP_CTRL_RIGHT)) { newDpadX++; if (DOWN(PSP_CTRL_RTRIGGER)) newDpadY--; } if (DOWN(PSP_CTRL_DOWN)) { newDpadY--; if (DOWN(PSP_CTRL_RTRIGGER)) newDpadX--; } if (DOWN(PSP_CTRL_LEFT)) { newDpadX--; if (DOWN(PSP_CTRL_RTRIGGER)) newDpadY++; } if (newDpadX != _dpadX || newDpadY != _dpadY) { if (_dpadX == 0 && _dpadY == 0) { // We were in the middle so we pressed dpad event.type = Common::EVENT_KEYDOWN; event.kbd.keycode = translateDpad(newDpadX, newDpadY); event.kbd.ascii = event.kbd.keycode - Common::KEYCODE_KP0 + '0'; // Get ascii _dpadX = newDpadX; _dpadY = newDpadY; } else if (newDpadX == 0 && newDpadY == 0) {// We're now centered so we unpressed dpad event.type = Common::EVENT_KEYUP; event.kbd.keycode = translateDpad(_dpadX, _dpadY); event.kbd.ascii = event.kbd.keycode - Common::KEYCODE_KP0 + '0'; _dpadX = newDpadX; _dpadY = newDpadY; } else { // we moved from one pressed dpad direction to another one event.type = Common::EVENT_KEYUP; // first release the last dpad direction event.kbd.keycode = translateDpad(_dpadX, _dpadY); event.kbd.ascii = event.kbd.keycode - Common::KEYCODE_KP0 + '0'; _dpadX = 0; // so that we'll pick up a new dpad movement the next round _dpadY = 0; } PSP_DEBUG_PRINT("Keypad event. DpadX[%d], DpadY[%d]\n", _dpadX, _dpadY); haveEvent = true; } return haveEvent; } inline Common::KeyCode InputHandler::translateDpad(int x, int y) { DEBUG_ENTER_FUNC(); Common::KeyCode key; if (x == -1) { if (y == -1) key = Common::KEYCODE_KP1; else if (y == 0) key = Common::KEYCODE_KP4; else /* y == 1 */ key = Common::KEYCODE_KP7; } else if (x == 0) { if (y == -1) key = Common::KEYCODE_KP2; else /* y == 1 */ key = Common::KEYCODE_KP8; } else {/* x == 1 */ if (y == -1) key = Common::KEYCODE_KP3; else if (y == 0) key = Common::KEYCODE_KP6; else /* y == 1 */ key = Common::KEYCODE_KP9; } return key; } bool InputHandler::getButtonEvent(Common::Event &event, SceCtrlData &pad) { DEBUG_ENTER_FUNC(); bool haveEvent = false; if (PRESSED(PSP_CTRL_SELECT)) _keyboard->setVisible(true); else if (CHANGED(PSP_4BUTTONS | PSP_TRIGGERS | PSP_CTRL_START)) { if (CHANGED(PSP_CTRL_CROSS)) { event.type = DOWN(PSP_CTRL_CROSS) ? Common::EVENT_LBUTTONDOWN : Common::EVENT_LBUTTONUP; event.mouse.x = _cursor->getX(); // Could this have to do with SCI enter problem? event.mouse.y = _cursor->getY(); PSP_DEBUG_PRINT("%s\n", event.type == Common::EVENT_LBUTTONDOWN ? "LButtonDown" : "LButtonUp"); } else if (CHANGED(PSP_CTRL_CIRCLE)) { event.type = DOWN(PSP_CTRL_CIRCLE) ? Common::EVENT_RBUTTONDOWN : Common::EVENT_RBUTTONUP; event.mouse.x = _cursor->getX(); event.mouse.y = _cursor->getY(); PSP_DEBUG_PRINT("%s\n", event.type == Common::EVENT_LBUTTONDOWN ? "RButtonDown" : "RButtonUp"); } else { //any of the other buttons. event.type = _buttonsChanged & pad.Buttons ? Common::EVENT_KEYDOWN : Common::EVENT_KEYUP; event.kbd.ascii = 0; event.kbd.flags = 0; if (CHANGED(PSP_CTRL_LTRIGGER)) { event.kbd.keycode = Common::KEYCODE_ESCAPE; event.kbd.ascii = 27; } else if (CHANGED(PSP_CTRL_START)) { event.kbd.keycode = Common::KEYCODE_F5; event.kbd.ascii = Common::ASCII_F5; if (DOWN(PSP_CTRL_RTRIGGER)) { event.kbd.flags |= Common::KBD_CTRL; // Main menu to allow RTL } } else if (CHANGED(PSP_CTRL_SQUARE)) { event.kbd.keycode = Common::KEYCODE_PERIOD; event.kbd.ascii = '.'; } else if (CHANGED(PSP_CTRL_TRIANGLE)) { event.kbd.keycode = Common::KEYCODE_RETURN; event.kbd.ascii = '\r'; } else if (DOWN(PSP_CTRL_RTRIGGER)) { // An event event.kbd.flags |= Common::KBD_SHIFT; } PSP_DEBUG_PRINT("Ascii[%d]. Key %s.\n", event.kbd.ascii, event.type == Common::EVENT_KEYDOWN ? "down" : "up"); } haveEvent = true; } return haveEvent; } bool InputHandler::getNubEvent(Common::Event &event, SceCtrlData &pad) { DEBUG_ENTER_FUNC(); bool haveEvent = false; int32 analogStepX = pad.Lx; // Goes up to 255. int32 analogStepY = pad.Ly; int32 oldX = _cursor->getX(); int32 oldY = _cursor->getY(); analogStepX = modifyNubAxisMotion(analogStepX); analogStepY = modifyNubAxisMotion(analogStepY); if (analogStepX != 0 || analogStepY != 0) { PSP_DEBUG_PRINT("raw x[%d], y[%d]\n", analogStepX, analogStepY); // If no movement then this has no effect if (DOWN(PSP_CTRL_RTRIGGER)) { // Fine control mode for analog if (analogStepX != 0) { if (analogStepX > 0) _cursor->increaseXY(2, 0); else _cursor->increaseXY(-2, 0); } if (analogStepY != 0) { if (analogStepY > 0) _cursor->increaseXY(0, 2); else _cursor->increaseXY(0, -2); } } else { // Regular speed movement _cursor->increaseXY(analogStepX, 0); _cursor->increaseXY(0, analogStepY); } int32 newX = _cursor->getX(); int32 newY = _cursor->getY(); if ((oldX != newX) || (oldY != newY)) { event.type = Common::EVENT_MOUSEMOVE; event.mouse.x = newX; event.mouse.y = newY; haveEvent = true; PSP_DEBUG_PRINT("Nub event. X[%d], Y[%d]\n", newX, newY); } } return haveEvent; } inline int32 InputHandler::modifyNubAxisMotion(int32 input) { DEBUG_ENTER_FUNC(); const int MIN_NUB_MOTION = 30; input -= 128; // Center on 0. if (input < -MIN_NUB_MOTION - 1) input += MIN_NUB_MOTION + 1; // reduce the velocity else if (input > MIN_NUB_MOTION) input -= MIN_NUB_MOTION; // same else // between these points, dampen the response to 0 input = 0; return input; }