Initial commit
This commit is contained in:
718
engines/agi/keyboard.cpp
Normal file
718
engines/agi/keyboard.cpp
Normal file
@@ -0,0 +1,718 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common/events.h"
|
||||
#include "gui/predictivedialog.h"
|
||||
|
||||
#include "agi/agi.h"
|
||||
#include "agi/graphics.h"
|
||||
#include "agi/keyboard.h"
|
||||
#include "agi/menu.h"
|
||||
#include "agi/text.h"
|
||||
|
||||
namespace Agi {
|
||||
|
||||
//
|
||||
// IBM-PC keyboard scancodes
|
||||
//
|
||||
const uint8 scancodeTable[26] = {
|
||||
30, // A
|
||||
48, // B
|
||||
46, // C
|
||||
32, // D
|
||||
18, // E
|
||||
33, // F
|
||||
34, // G
|
||||
35, // H
|
||||
23, // I
|
||||
36, // J
|
||||
37, // K
|
||||
38, // L
|
||||
50, // M
|
||||
49, // N
|
||||
24, // O
|
||||
25, // P
|
||||
16, // Q
|
||||
19, // R
|
||||
31, // S
|
||||
20, // T
|
||||
22, // U
|
||||
47, // V
|
||||
17, // W
|
||||
45, // X
|
||||
21, // Y
|
||||
44 // Z
|
||||
};
|
||||
|
||||
void AgiEngine::processScummVMEvents() {
|
||||
Common::Event event;
|
||||
int key = 0;
|
||||
|
||||
while (_eventMan->pollEvent(event)) {
|
||||
switch (event.type) {
|
||||
case Common::EVENT_PREDICTIVE_DIALOG:
|
||||
showPredictiveDialog();
|
||||
break;
|
||||
case Common::EVENT_LBUTTONDOWN:
|
||||
if (_game.mouseEnabled) {
|
||||
key = AGI_MOUSE_BUTTON_LEFT;
|
||||
_mouse.button = kAgiMouseButtonLeft;
|
||||
keyEnqueue(key);
|
||||
_mouse.pos.x = event.mouse.x;
|
||||
_mouse.pos.y = event.mouse.y;
|
||||
}
|
||||
break;
|
||||
case Common::EVENT_RBUTTONDOWN:
|
||||
if (_game.mouseEnabled) {
|
||||
key = AGI_MOUSE_BUTTON_RIGHT;
|
||||
_mouse.button = kAgiMouseButtonRight;
|
||||
keyEnqueue(key);
|
||||
_mouse.pos.x = event.mouse.x;
|
||||
_mouse.pos.y = event.mouse.y;
|
||||
}
|
||||
break;
|
||||
case Common::EVENT_WHEELUP:
|
||||
if (_game.mouseEnabled) {
|
||||
key = AGI_MOUSE_WHEEL_UP;
|
||||
keyEnqueue(key);
|
||||
}
|
||||
break;
|
||||
case Common::EVENT_WHEELDOWN:
|
||||
if (_game.mouseEnabled) {
|
||||
key = AGI_MOUSE_WHEEL_DOWN;
|
||||
keyEnqueue(key);
|
||||
}
|
||||
break;
|
||||
case Common::EVENT_MOUSEMOVE:
|
||||
if (_game.mouseEnabled) {
|
||||
_mouse.pos.x = event.mouse.x;
|
||||
_mouse.pos.y = event.mouse.y;
|
||||
|
||||
if (!_game.mouseFence.isEmpty()) {
|
||||
if (_mouse.pos.x < _game.mouseFence.left)
|
||||
_mouse.pos.x = _game.mouseFence.left;
|
||||
if (_mouse.pos.x > _game.mouseFence.right)
|
||||
_mouse.pos.x = _game.mouseFence.right;
|
||||
if (_mouse.pos.y < _game.mouseFence.top)
|
||||
_mouse.pos.y = _game.mouseFence.top;
|
||||
if (_mouse.pos.y > _game.mouseFence.bottom)
|
||||
_mouse.pos.y = _game.mouseFence.bottom;
|
||||
|
||||
_system->warpMouse(_mouse.pos.x, _mouse.pos.y);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
case Common::EVENT_LBUTTONUP:
|
||||
case Common::EVENT_RBUTTONUP:
|
||||
if (_game.mouseEnabled) {
|
||||
_mouse.button = kAgiMouseButtonUp;
|
||||
_mouse.pos.x = event.mouse.x;
|
||||
_mouse.pos.y = event.mouse.y;
|
||||
}
|
||||
break;
|
||||
case Common::EVENT_KEYDOWN:
|
||||
key = event.kbd.ascii;
|
||||
if (event.kbd.keycode >= Common::KEYCODE_KP0 && event.kbd.keycode <= Common::KEYCODE_KP9) {
|
||||
if (!(event.kbd.flags & Common::KBD_NUM)) {
|
||||
// HACK: Num-Lock not enabled
|
||||
// We shouldn't get a valid ascii code in these cases. We fix it here, so that cursor keys
|
||||
// on the numpad work properly.
|
||||
key = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (_game._vm->getLanguage() == Common::HE_ISR && key >= 0x05d0 && key <= 0x05ea) {
|
||||
// convert to WIN-1255
|
||||
key = key - 0x05d0 + 0xe0;
|
||||
}
|
||||
|
||||
if (_game._vm->getLanguage() == Common::RU_RUS) {
|
||||
// Convert UTF16 to CP866
|
||||
if (key >= 0x400 && key <= 0x4ff) {
|
||||
if (key >= 0x440)
|
||||
key = key - 0x410 + 0xb0;
|
||||
else
|
||||
key = key - 0x410 + 0x80;
|
||||
}
|
||||
}
|
||||
|
||||
if (_game._vm->getLanguage() == Common::FR_FRA) {
|
||||
// Convert to CP858
|
||||
if (key >= 0x80 && key <= 0xff) {
|
||||
switch (key) {
|
||||
case 0xe9:
|
||||
key = 0x82;
|
||||
break;
|
||||
case 0xe8:
|
||||
key = 0x8a;
|
||||
break;
|
||||
case 0xe7:
|
||||
key = 0x87;
|
||||
break;
|
||||
case 0xe0:
|
||||
key = 0x85;
|
||||
break;
|
||||
case 0xf9:
|
||||
key = 0x97;
|
||||
break;
|
||||
case 0xf4:
|
||||
key = 0x93;
|
||||
break;
|
||||
case 0xee:
|
||||
key = 0x8c;
|
||||
break;
|
||||
case 0xef:
|
||||
key = 0x8b;
|
||||
break;
|
||||
case 0xea:
|
||||
key = 0x88;
|
||||
break;
|
||||
case 0xeb:
|
||||
key = 0x89;
|
||||
break;
|
||||
case 0xe2:
|
||||
key = 0x83;
|
||||
break;
|
||||
case 0xe4:
|
||||
key = 0x84;
|
||||
break;
|
||||
case 0xfb:
|
||||
key = 0x96;
|
||||
break;
|
||||
case 0xfc:
|
||||
key = 0x81;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((key) && (key <= 0xFF)) {
|
||||
// No special key, directly accept it
|
||||
// Is ISO-8859-1, we need lower 128 characters only, which is plain ASCII, so no mapping required
|
||||
if (Common::isAlpha(key)) {
|
||||
// Key is A-Z.
|
||||
// Map Ctrl-A to 1, Ctrl-B to 2, etc.
|
||||
if (event.kbd.flags & Common::KBD_CTRL) {
|
||||
key = toupper(key) - 'A' + 1;
|
||||
} else if (event.kbd.flags & Common::KBD_ALT) {
|
||||
// Map Alt-A, Alt-B etc. to special scancode values according to an internal scancode table.
|
||||
key = scancodeTable[toupper(key) - 'A'] << 8;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
key = 0;
|
||||
switch (event.kbd.keycode) {
|
||||
case Common::KEYCODE_LEFT:
|
||||
case Common::KEYCODE_KP4:
|
||||
if (_allowSynthetic || !event.kbdRepeat)
|
||||
key = AGI_KEY_LEFT;
|
||||
break;
|
||||
case Common::KEYCODE_RIGHT:
|
||||
case Common::KEYCODE_KP6:
|
||||
if (_allowSynthetic || !event.kbdRepeat)
|
||||
key = AGI_KEY_RIGHT;
|
||||
break;
|
||||
case Common::KEYCODE_UP:
|
||||
case Common::KEYCODE_KP8:
|
||||
if (_allowSynthetic || !event.kbdRepeat)
|
||||
key = AGI_KEY_UP;
|
||||
break;
|
||||
case Common::KEYCODE_DOWN:
|
||||
case Common::KEYCODE_KP2:
|
||||
if (_allowSynthetic || !event.kbdRepeat)
|
||||
key = AGI_KEY_DOWN;
|
||||
break;
|
||||
case Common::KEYCODE_PAGEUP:
|
||||
case Common::KEYCODE_KP9:
|
||||
if (_allowSynthetic || !event.kbdRepeat)
|
||||
key = AGI_KEY_UP_RIGHT;
|
||||
break;
|
||||
case Common::KEYCODE_PAGEDOWN:
|
||||
case Common::KEYCODE_KP3:
|
||||
if (_allowSynthetic || !event.kbdRepeat)
|
||||
key = AGI_KEY_DOWN_RIGHT;
|
||||
break;
|
||||
case Common::KEYCODE_HOME:
|
||||
case Common::KEYCODE_KP7:
|
||||
if (_allowSynthetic || !event.kbdRepeat)
|
||||
key = AGI_KEY_UP_LEFT;
|
||||
break;
|
||||
case Common::KEYCODE_END:
|
||||
case Common::KEYCODE_KP1:
|
||||
if (_allowSynthetic || !event.kbdRepeat)
|
||||
key = AGI_KEY_DOWN_LEFT;
|
||||
break;
|
||||
case Common::KEYCODE_KP5:
|
||||
key = AGI_KEY_STATIONARY;
|
||||
break;
|
||||
case Common::KEYCODE_F1:
|
||||
key = AGI_KEY_F1;
|
||||
break;
|
||||
case Common::KEYCODE_F2:
|
||||
key = AGI_KEY_F2;
|
||||
break;
|
||||
case Common::KEYCODE_F3:
|
||||
key = AGI_KEY_F3;
|
||||
break;
|
||||
case Common::KEYCODE_F4:
|
||||
key = AGI_KEY_F4;
|
||||
break;
|
||||
case Common::KEYCODE_F5:
|
||||
key = AGI_KEY_F5;
|
||||
break;
|
||||
case Common::KEYCODE_F6:
|
||||
key = AGI_KEY_F6;
|
||||
break;
|
||||
case Common::KEYCODE_F7:
|
||||
key = AGI_KEY_F7;
|
||||
break;
|
||||
case Common::KEYCODE_F8:
|
||||
key = AGI_KEY_F8;
|
||||
break;
|
||||
case Common::KEYCODE_F9:
|
||||
key = AGI_KEY_F9;
|
||||
break;
|
||||
case Common::KEYCODE_F10:
|
||||
key = AGI_KEY_F10;
|
||||
break;
|
||||
case Common::KEYCODE_F11:
|
||||
key = AGI_KEY_F11;
|
||||
break;
|
||||
case Common::KEYCODE_F12:
|
||||
key = AGI_KEY_F12;
|
||||
break;
|
||||
case Common::KEYCODE_KP_ENTER:
|
||||
key = AGI_KEY_ENTER;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
switch (event.kbd.keycode) {
|
||||
case Common::KEYCODE_LEFT:
|
||||
case Common::KEYCODE_RIGHT:
|
||||
case Common::KEYCODE_UP:
|
||||
case Common::KEYCODE_DOWN:
|
||||
case Common::KEYCODE_HOME:
|
||||
case Common::KEYCODE_END:
|
||||
case Common::KEYCODE_PAGEUP:
|
||||
case Common::KEYCODE_PAGEDOWN:
|
||||
case Common::KEYCODE_KP4:
|
||||
case Common::KEYCODE_KP6:
|
||||
case Common::KEYCODE_KP8:
|
||||
case Common::KEYCODE_KP2:
|
||||
case Common::KEYCODE_KP9:
|
||||
case Common::KEYCODE_KP3:
|
||||
case Common::KEYCODE_KP7:
|
||||
case Common::KEYCODE_KP1:
|
||||
_keyHoldModeLastKey = event.kbd.keycode;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (key)
|
||||
keyEnqueue(key);
|
||||
break;
|
||||
|
||||
case Common::EVENT_KEYUP:
|
||||
if (_keyHoldMode) {
|
||||
// Original AGI actually created direction events in here
|
||||
// but only in case the last pressed cursor key was released, in other cases it did nothing.
|
||||
// So when you pressed and held down left and then pressed up, and then released left,
|
||||
// direction wouldn't be changed at all.
|
||||
//
|
||||
// We don't create direction events in here, that's why we create a stationary event instead,
|
||||
// which will result in a direction change to 0 in handleController().
|
||||
switch (event.kbd.keycode) {
|
||||
case Common::KEYCODE_LEFT:
|
||||
case Common::KEYCODE_RIGHT:
|
||||
case Common::KEYCODE_UP:
|
||||
case Common::KEYCODE_DOWN:
|
||||
case Common::KEYCODE_HOME:
|
||||
case Common::KEYCODE_END:
|
||||
case Common::KEYCODE_PAGEUP:
|
||||
case Common::KEYCODE_PAGEDOWN:
|
||||
case Common::KEYCODE_KP4:
|
||||
case Common::KEYCODE_KP6:
|
||||
case Common::KEYCODE_KP8:
|
||||
case Common::KEYCODE_KP2:
|
||||
case Common::KEYCODE_KP9:
|
||||
case Common::KEYCODE_KP3:
|
||||
case Common::KEYCODE_KP7:
|
||||
case Common::KEYCODE_KP1:
|
||||
if (_keyHoldModeLastKey == event.kbd.keycode) {
|
||||
keyEnqueue(AGI_KEY_STATIONARY);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Raw key grabber.
|
||||
* poll_keyboard() is the raw key grabber (above the gfx driver, that is).
|
||||
* It handles console keys and insulates AGI from the console. In the main
|
||||
* loop, handle_keys() handles keyboard input and ego movement.
|
||||
*/
|
||||
int AgiEngine::doPollKeyboard() {
|
||||
int key = 0;
|
||||
|
||||
// If a key is ready, rip it
|
||||
if (isKeypress()) {
|
||||
key = getKeypress();
|
||||
|
||||
debugC(3, kDebugLevelInput, "key %02x pressed", key);
|
||||
}
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
bool AgiEngine::handleMouseClicks(uint16 &key) {
|
||||
// No mouse click? -> exit
|
||||
if (key != AGI_MOUSE_BUTTON_LEFT)
|
||||
return false;
|
||||
|
||||
if (!cycleInnerLoopIsActive()) {
|
||||
// Only do this, when no inner loop is currently active
|
||||
Common::Rect displayLineRect = _gfx->getFontRectForDisplayScreen(0, 0, FONT_COLUMN_CHARACTERS, 1);
|
||||
// Common::Rect displayLineRect(_gfx->getDisplayScreenWidth(), _gfx->getDisplayFontHeight());
|
||||
|
||||
if (displayLineRect.contains(_mouse.pos)) {
|
||||
// Mouse is inside first line of the screen
|
||||
if (getFlag(VM_FLAG_MENUS_ACCESSIBLE) && _menu->isAvailable()) {
|
||||
_menu->delayedExecuteViaMouse();
|
||||
key = 0; // eat event
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (_text->promptIsEnabled()) {
|
||||
// Prompt is currently enabled
|
||||
int16 promptRow = _text->promptRow_Get();
|
||||
|
||||
displayLineRect.moveTo(0, promptRow * _gfx->getDisplayFontHeight());
|
||||
|
||||
if (displayLineRect.contains(_mouse.pos)) {
|
||||
// and user clicked within the line of the prompt
|
||||
if (_game.predictiveDlgOnMouseClick) {
|
||||
showPredictiveDialog();
|
||||
}
|
||||
|
||||
key = 0; // eat event
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (cycleInnerLoopIsActive()) {
|
||||
// inner loop active, check what kind of loop it is. Then process / forward it
|
||||
switch (_game.cycleInnerLoopType) {
|
||||
case CYCLE_INNERLOOP_GETSTRING:
|
||||
case CYCLE_INNERLOOP_GETNUMBER: {
|
||||
// process in here
|
||||
int16 stringRow, stringColumn, stringMaxLen;
|
||||
|
||||
_text->stringPos_Get(stringRow, stringColumn);
|
||||
stringMaxLen = _text->stringGetMaxLen();
|
||||
|
||||
Common::Rect displayRect = _gfx->getFontRectForDisplayScreen(stringColumn, stringRow, stringMaxLen, 1);
|
||||
if (displayRect.contains(_mouse.pos)) {
|
||||
// user clicked inside the input space
|
||||
if (_game.predictiveDlgOnMouseClick) {
|
||||
showPredictiveDialog();
|
||||
}
|
||||
|
||||
key = 0; // eat event
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CYCLE_INNERLOOP_INVENTORY:
|
||||
// TODO: forward
|
||||
break;
|
||||
|
||||
case CYCLE_INNERLOOP_MENU_VIA_KEYBOARD:
|
||||
_menu->mouseEvent(key);
|
||||
key = 0; // eat event
|
||||
break;
|
||||
|
||||
case CYCLE_INNERLOOP_SYSTEMUI_SELECTSAVEDGAMESLOT:
|
||||
// TODO: forward
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AgiEngine::handleController(uint16 key) {
|
||||
ScreenObjEntry *screenObjEgo = &_game.screenObjTable[SCREENOBJECTS_EGO_ENTRY];
|
||||
|
||||
if (key == 0) // nothing pressed
|
||||
return false;
|
||||
|
||||
// This previously skipped processing, when ESC was pressed and called menu directly.
|
||||
// This original approach was bad, because games check different flags before actually allowing the
|
||||
// user to enter the menu. We checked a few common flags, like for example the availability of the prompt.
|
||||
// But this stopped the user being able to enter the menu, when the original interpreter actually allowed it.
|
||||
// We now instead implement this feature using another way for those platforms.
|
||||
if (key == AGI_KEY_ESCAPE) {
|
||||
// Escape pressed, user probably wants to trigger the menu
|
||||
// For PC, just passing ASCII code for ESC will normally trigger a controller
|
||||
// and the scripts will then trigger the menu
|
||||
switch (getPlatform()) {
|
||||
case Common::kPlatformAmiga:
|
||||
case Common::kPlatformApple2GS:
|
||||
case Common::kPlatformAtariST:
|
||||
// For these platforms, the button ESC normally triggered "pause"
|
||||
// But users could at the same time trigger the menu by clicking on the status line
|
||||
// We check, if menu is currently available and supposed to be accessible.
|
||||
// If yes, we do a delayed trigger now, otherwise we continue processing the key just like normal.
|
||||
//
|
||||
// This is probably the solution with the highest compatibility.
|
||||
// Several games also look for special keys see AGI_MENU_TRIGGER_*
|
||||
// And then there's also Mixed Up Mother Goose, which actually hooks the ESC key for the regular menu
|
||||
//
|
||||
// We risk in here of course, that we let the user access the menu, when it shouldn't be possible.
|
||||
// I'm not 100% sure if those other interpreters really only check VM_FLAG_MENUS_ACCESSIBLE
|
||||
// Needs further investigation.
|
||||
if (getFlag(VM_FLAG_MENUS_ACCESSIBLE) && _menu->isAvailable()) {
|
||||
// menu is supposed to be accessible and is also available
|
||||
_menu->delayedExecuteViaKeyboard();
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
// Otherwise go on and look for the ESC controller
|
||||
}
|
||||
|
||||
if ((getGameID() == GID_MH1 || getGameID() == GID_MH2) && (key == AGI_KEY_ENTER) &&
|
||||
(!_text->promptIsEnabled())) {
|
||||
key = 0x20; // Set Enter key to Space in Manhunter when prompt is disabled
|
||||
}
|
||||
|
||||
debugC(3, kDebugLevelInput, "key = %04x", key);
|
||||
|
||||
for (uint16 curMapping = 0; curMapping < MAX_CONTROLLER_KEYMAPPINGS; curMapping++) {
|
||||
if (_game.controllerKeyMapping[curMapping].keycode == key) {
|
||||
debugC(3, kDebugLevelInput, "event %d: key press", _game.controllerKeyMapping[curMapping].controllerSlot);
|
||||
_game.controllerOccurred[_game.controllerKeyMapping[curMapping].controllerSlot] = true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
int16 newDirection = 0;
|
||||
|
||||
switch (key) {
|
||||
case AGI_KEY_UP:
|
||||
newDirection = 1;
|
||||
break;
|
||||
case AGI_KEY_DOWN:
|
||||
newDirection = 5;
|
||||
break;
|
||||
case AGI_KEY_LEFT:
|
||||
newDirection = 7;
|
||||
break;
|
||||
case AGI_KEY_RIGHT:
|
||||
newDirection = 3;
|
||||
break;
|
||||
case AGI_KEY_UP_RIGHT:
|
||||
newDirection = 2;
|
||||
break;
|
||||
case AGI_KEY_DOWN_RIGHT:
|
||||
newDirection = 4;
|
||||
break;
|
||||
case AGI_KEY_UP_LEFT:
|
||||
newDirection = 8;
|
||||
break;
|
||||
case AGI_KEY_DOWN_LEFT:
|
||||
newDirection = 6;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (_game.playerControl) {
|
||||
if (!(getFeatures() & GF_AGIMOUSE)) {
|
||||
// Handle mouse button events
|
||||
if (!_game.mouseHidden) {
|
||||
if (key == AGI_MOUSE_BUTTON_LEFT) {
|
||||
if (getGameID() == GID_PQ1 && getVar(VM_VAR_CURRENT_ROOM) == 116) {
|
||||
// WORKAROUND: Special handling for mouse clicks in the newspaper
|
||||
// screen of PQ1. Fixes bug #4908.
|
||||
newDirection = 3; // fake a right arrow key (next page)
|
||||
|
||||
} else {
|
||||
// Click-to-walk mouse interface
|
||||
//v->flags |= fAdjEgoXY;
|
||||
// setting fAdjEgoXY here will at least break "climbing the log" in SQ2
|
||||
// in case you walked to the log by using the mouse, so don't!!!
|
||||
int16 egoDestinationX = _mouse.pos.x;
|
||||
int16 egoDestinationY = _mouse.pos.y;
|
||||
_gfx->translateDisplayPosToGameScreen(egoDestinationX, egoDestinationY);
|
||||
|
||||
screenObjEgo->motionType = kMotionEgo;
|
||||
if (egoDestinationX < (screenObjEgo->xSize / 2)) {
|
||||
screenObjEgo->move_x = -1;
|
||||
} else {
|
||||
screenObjEgo->move_x = egoDestinationX - (screenObjEgo->xSize / 2);
|
||||
}
|
||||
screenObjEgo->move_y = egoDestinationY;
|
||||
screenObjEgo->move_stepSize = screenObjEgo->stepSize;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (newDirection || key == AGI_KEY_STATIONARY) {
|
||||
// TODO: not sure, what original AGI did with AdjEgoXY
|
||||
screenObjEgo->flags &= ~fAdjEgoXY;
|
||||
if (screenObjEgo->direction == newDirection) {
|
||||
setVar(VM_VAR_EGO_DIRECTION, 0);
|
||||
} else {
|
||||
setVar(VM_VAR_EGO_DIRECTION, newDirection);
|
||||
}
|
||||
if (_game.playerControl) {
|
||||
screenObjEgo->motionType = kMotionNormal;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AgiEngine::showPredictiveDialog() {
|
||||
GUI::PredictiveDialog predictiveDialog;
|
||||
|
||||
runDialog(predictiveDialog);
|
||||
|
||||
Common::String predictiveResult(predictiveDialog.getResult());
|
||||
uint16 predictiveResultLen = predictiveResult.size();
|
||||
if (predictiveResultLen) {
|
||||
// User actually entered something
|
||||
for (int16 resultPos = 0; resultPos < predictiveResultLen; resultPos++) {
|
||||
keyEnqueue(predictiveResult[resultPos]);
|
||||
}
|
||||
if (!cycleInnerLoopIsActive()) {
|
||||
if (_text->promptIsEnabled()) {
|
||||
// add ENTER, when the input is probably meant for the prompt
|
||||
keyEnqueue(AGI_KEY_ENTER);
|
||||
}
|
||||
} else {
|
||||
switch (_game.cycleInnerLoopType) {
|
||||
case CYCLE_INNERLOOP_GETSTRING:
|
||||
case CYCLE_INNERLOOP_GETNUMBER:
|
||||
// add ENTER, when the input is probably meant for GetString/GetNumber
|
||||
keyEnqueue(AGI_KEY_ENTER);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int AgiEngine::waitKey() {
|
||||
int key = 0;
|
||||
|
||||
clearKeyQueue();
|
||||
|
||||
debugC(3, kDebugLevelInput, "waiting...");
|
||||
while (!(shouldQuit() || _restartGame || getFlag(VM_FLAG_RESTORE_JUST_RAN))) {
|
||||
wait(10);
|
||||
key = doPollKeyboard();
|
||||
if (key == AGI_KEY_ENTER || key == AGI_KEY_ESCAPE || key == AGI_MOUSE_BUTTON_LEFT)
|
||||
break;
|
||||
}
|
||||
return key;
|
||||
}
|
||||
|
||||
int AgiEngine::waitAnyKey() {
|
||||
int key = 0;
|
||||
|
||||
clearKeyQueue();
|
||||
|
||||
debugC(3, kDebugLevelInput, "waiting... (any key)");
|
||||
while (!(shouldQuit() || _restartGame)) {
|
||||
wait(10);
|
||||
key = doPollKeyboard();
|
||||
if (key)
|
||||
break;
|
||||
}
|
||||
return key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Waits on any key to be pressed or for a finished sound.
|
||||
* This is used on platforms where sound playback would block the
|
||||
* interpreter until the sound finished or was interrupted.
|
||||
*/
|
||||
void AgiEngine::waitAnyKeyOrFinishedSound() {
|
||||
clearKeyQueue();
|
||||
|
||||
while (!(shouldQuit() || _restartGame || !_sound->isPlaying())) {
|
||||
wait(10);
|
||||
if (doPollKeyboard()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool AgiEngine::isKeypress() {
|
||||
processScummVMEvents();
|
||||
return _keyQueueStart != _keyQueueEnd;
|
||||
}
|
||||
|
||||
int AgiEngine::getKeypress() {
|
||||
int k;
|
||||
|
||||
while (_keyQueueStart == _keyQueueEnd) // block
|
||||
wait(10);
|
||||
|
||||
keyDequeue(k);
|
||||
|
||||
return k;
|
||||
}
|
||||
|
||||
void AgiEngine::clearKeyQueue() {
|
||||
while (isKeypress()) {
|
||||
getKeypress();
|
||||
}
|
||||
}
|
||||
|
||||
} // End of namespace Agi
|
||||
Reference in New Issue
Block a user