diff options
Diffstat (limited to 'engines/agi/keyboard.cpp')
-rw-r--r-- | engines/agi/keyboard.cpp | 792 |
1 files changed, 469 insertions, 323 deletions
diff --git a/engines/agi/keyboard.cpp b/engines/agi/keyboard.cpp index 0aa521bdc8..7ed67949b5 100644 --- a/engines/agi/keyboard.cpp +++ b/engines/agi/keyboard.cpp @@ -20,12 +20,14 @@ * */ +#include "common/events.h" +#include "gui/predictivedialog.h" + #include "agi/agi.h" #include "agi/graphics.h" #include "agi/keyboard.h" -#ifdef __DS__ -#include "wordcompletion.h" -#endif +#include "agi/menu.h" +#include "agi/text.h" namespace Agi { @@ -33,49 +35,257 @@ 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 + 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::initWords() { - _game.numEgoWords = 0; -} +void AgiEngine::processScummVMEvents() { + Common::Event event; + int key = 0; -void AgiEngine::cleanInput() { - while (_game.numEgoWords) - free(_game.egoWords[--_game.numEgoWords].word); -} + 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; + + g_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: + if (event.kbd.hasFlags(Common::KBD_CTRL | Common::KBD_SHIFT) && event.kbd.keycode == Common::KEYCODE_d) { + _console->attach(); + break; + } + + 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; + } + } -void AgiEngine::getString(int x, int y, int len, int str) { - newInputMode(INPUT_GETSTRING); - _stringdata.x = x; - _stringdata.y = y; - _stringdata.len = len; - _stringdata.str = str; + 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.synthetic) + key = AGI_KEY_LEFT; + break; + case Common::KEYCODE_RIGHT: + case Common::KEYCODE_KP6: + if (_allowSynthetic || !event.synthetic) + key = AGI_KEY_RIGHT; + break; + case Common::KEYCODE_UP: + case Common::KEYCODE_KP8: + if (_allowSynthetic || !event.synthetic) + key = AGI_KEY_UP; + break; + case Common::KEYCODE_DOWN: + case Common::KEYCODE_KP2: + if (_allowSynthetic || !event.synthetic) + key = AGI_KEY_DOWN; + break; + case Common::KEYCODE_PAGEUP: + case Common::KEYCODE_KP9: + if (_allowSynthetic || !event.synthetic) + key = AGI_KEY_UP_RIGHT; + break; + case Common::KEYCODE_PAGEDOWN: + case Common::KEYCODE_KP3: + if (_allowSynthetic || !event.synthetic) + key = AGI_KEY_DOWN_RIGHT; + break; + case Common::KEYCODE_HOME: + case Common::KEYCODE_KP7: + if (_allowSynthetic || !event.synthetic) + key = AGI_KEY_UP_LEFT; + break; + case Common::KEYCODE_END: + case Common::KEYCODE_KP1: + if (_allowSynthetic || !event.synthetic) + 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; + } + } + if (key) + keyEnqueue(key); + break; + + case Common::EVENT_KEYUP: + if (_keyHoldMode) { + // Original AGI actually created direction events in here + // We don't do that, 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: + keyEnqueue(AGI_KEY_STATIONARY); + break; + default: + break; + } + } + break; + + default: + break; + } + } } /** @@ -97,308 +307,259 @@ int AgiEngine::doPollKeyboard() { return key; } -int AgiEngine::handleController(int key) { - VtEntry *v = &_game.viewTable[0]; - int i; - - // AGI 3.149 games, The Black Cauldron and King's Quest 4 need KEY_ESCAPE to use menus - // Games with the GF_ESCPAUSE flag need KEY_ESCAPE to pause the game - if (key == 0 || - (key == KEY_ESCAPE && getVersion() != 0x3149 && getGameID() != GID_BC && getGameID() != GID_KQ4 && !(getFeatures() & GF_ESCPAUSE)) ) +bool AgiEngine::handleMouseClicks(uint16 &key) { + // No mouse click? -> exit + if (key != AGI_MOUSE_BUTTON_LEFT) return false; - if ((getGameID() == GID_MH1 || getGameID() == GID_MH2) && (key == KEY_ENTER) && - (_game.inputMode == INPUT_NONE)) { - key = 0x20; // Set Enter key to Space in Manhunter when there's no text input - } - - debugC(3, kDebugLevelInput, "key = %04x", key); - - for (i = 0; i < MAX_CONTROLLERS; i++) { - if (_game.controllers[i].keycode == key) { - debugC(3, kDebugLevelInput, "event %d: key press", _game.controllers[i].controller); - _game.controllerOccured[_game.controllers[i].controller] = true; - return true; - } - } - - if (key == BUTTON_LEFT) { - if ((getflag(fMenusWork) || (getFeatures() & GF_MENUS)) && _mouse.y <= CHAR_LINES) { - newInputMode(INPUT_MENU); - return true; - } - } - - // Show predictive dialog if the user clicks on input area - if (key == BUTTON_LEFT && - (int)_mouse.y >= _game.lineUserInput * CHAR_LINES && - (int)_mouse.y <= (_game.lineUserInput + 1) * CHAR_LINES) { - GUI::PredictiveDialog _predictiveDialog; - _predictiveDialog.runModal(); - strcpy(_predictiveResult, _predictiveDialog.getResult()); - if (strcmp(_predictiveResult, "")) { - if (_game.inputMode == INPUT_NONE) { - for (int n = 0; _predictiveResult[n]; n++) - keyEnqueue(_predictiveResult[n]); - } else { - strcpy((char *)_game.inputBuffer, _predictiveResult); - handleKeys(KEY_ENTER); + 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 (predictiveDialog()) { - if (_game.inputMode == INPUT_NONE) { - for (int n = 0; _predictiveResult[n]; n++) - keyEnqueue(_predictiveResult[n]); - } else { - strcpy((char *)_game.inputBuffer, _predictiveResult); - handleKeys(KEY_ENTER); - } - } - */ - return true; - } - if (_game.playerControl) { - int d = 0; + if (_text->promptIsEnabled()) { + // Prompt is currently enabled + int16 promptRow = _text->promptRow_Get(); - if (!KEY_ASCII(key)) { - switch (key) { - case KEY_UP: - d = 1; - break; - case KEY_DOWN: - d = 5; - break; - case KEY_LEFT: - d = 7; - break; - case KEY_RIGHT: - d = 3; - break; - case KEY_UP_RIGHT: - d = 2; - break; - case KEY_DOWN_RIGHT: - d = 4; - break; - case KEY_UP_LEFT: - d = 8; - break; - case KEY_DOWN_LEFT: - d = 6; - break; - } - } + displayLineRect.moveTo(0, promptRow * _gfx->getDisplayFontHeight()); - if (!(getFeatures() & GF_AGIMOUSE)) { - // Handle mouse button events - if (key == BUTTON_LEFT) { - if (getGameID() == GID_PQ1 && _game.vars[vCurRoom] == 116) { - // WORKAROUND: Special handling for mouse clicks in the newspaper - // screen of PQ1. Fixes bug #3018770. - d = 3; // fake a right arrow key (next page) - } else { - // Click-to-walk mouse interface - v->flags |= fAdjEgoXY; - v->parm1 = WIN_TO_PIC_X(_mouse.x); - v->parm2 = WIN_TO_PIC_Y(_mouse.y); - return true; - } - } - } + if (displayLineRect.contains(_mouse.pos)) { + // and user clicked within the line of the prompt + showPredictiveDialog(); - if (d || key == KEY_STATIONARY) { - v->flags &= ~fAdjEgoXY; - v->direction = v->direction == d ? 0 : d; - return true; + key = 0; // eat event + return true; + } } } - return false; -} + 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; -void AgiEngine::handleGetstring(int key) { - static int pos = 0; // Cursor position - static char buf[40]; + _text->stringPos_Get(stringRow, stringColumn); + stringMaxLen = _text->stringGetMaxLen(); - if (KEY_ASCII(key) == 0) - return; + Common::Rect displayRect = _gfx->getFontRectForDisplayScreen(stringColumn, stringRow, stringMaxLen, 1); + if (displayRect.contains(_mouse.pos)) { + // user clicked inside the input space + showPredictiveDialog(); - debugC(3, kDebugLevelInput, "handling key: %02x", key); - - switch (key) { - case BUTTON_LEFT: - if ((int)_mouse.y >= _stringdata.y * CHAR_LINES && - (int)_mouse.y <= (_stringdata.y + 1) * CHAR_LINES) { - GUI::PredictiveDialog _predictiveDialog; - _predictiveDialog.runModal(); - strcpy(_predictiveResult, _predictiveDialog.getResult()); - if (strcmp(_predictiveResult, "")) { - strcpy(_game.strings[_stringdata.str], _predictiveResult); - newInputMode(INPUT_NORMAL); - _gfx->printCharacter(_stringdata.x + strlen(_game.strings[_stringdata.str]) + 1, - _stringdata.y, ' ', _game.colorFg, _game.colorBg); - return; + key = 0; // eat event + return true; } - /* - if (predictiveDialog()) { - strcpy(_game.strings[_stringdata.str], _predictiveResult); - newInputMode(INPUT_NORMAL); - _gfx->printCharacter(_stringdata.x + strlen(_game.strings[_stringdata.str]) + 1, - _stringdata.y, ' ', _game.colorFg, _game.colorBg); - return; - } - */ + break; } - break; - case KEY_ENTER: - debugC(3, kDebugLevelInput, "KEY_ENTER"); - _game.hasPrompt = 0; - buf[pos] = 0; - - strcpy(_game.strings[_stringdata.str], buf); - debugC(3, kDebugLevelInput, "buffer=[%s]", buf); - buf[pos = 0] = 0; - - newInputMode(INPUT_NORMAL); - _gfx->printCharacter(_stringdata.x + strlen(_game.strings[_stringdata.str]) + 1, - _stringdata.y, ' ', _game.colorFg, _game.colorBg); - return; - case KEY_ESCAPE: - debugC(3, kDebugLevelInput, "KEY_ESCAPE"); - _game.hasPrompt = 0; - buf[pos = 0] = 0; - - strcpy(_game.strings[_stringdata.str], buf); - newInputMode(INPUT_NORMAL); - - // newInputMode(INPUT_MENU); - break; - case KEY_BACKSPACE: // 0x08 - if (!pos) + case CYCLE_INNERLOOP_INVENTORY: + // TODO: forward break; - _gfx->printCharacter(_stringdata.x + (pos + 1), _stringdata.y, - ' ', _game.colorFg, _game.colorBg); - pos--; - buf[pos] = 0; - break; - default: - if (key < 0x20 || key > 0x7f) + case CYCLE_INNERLOOP_MENU_VIA_KEYBOARD: + _menu->mouseEvent(key); + key = 0; // eat event break; - if (pos >= _stringdata.len) + case CYCLE_INNERLOOP_SYSTEMUI_SELECTSAVEDGAMESLOT: + // TODO: forward break; - buf[pos++] = key; - buf[pos] = 0; - - // Echo - _gfx->printCharacter(_stringdata.x + pos, _stringdata.y, buf[pos - 1], - _game.colorFg, _game.colorBg); - - break; + default: + break; + } } - - // print cursor - _gfx->printCharacter(_stringdata.x + pos + 1, _stringdata.y, - (char)_game.cursorChar, _game.colorFg, _game.colorBg); + return false; } -void AgiEngine::handleKeys(int key) { - uint8 *p = NULL; - int c = 0; - static uint8 formattedEntry[40]; - int l = _game.lineUserInput; - int fg = _game.colorFg, bg = _game.colorBg; - int promptLength = strlen(agiSprintf(_game.strings[0])); - - setvar(vWordNotFound, 0); +bool AgiEngine::handleController(uint16 key) { + ScreenObjEntry *screenObjEgo = &_game.screenObjTable[SCREENOBJECTS_EGO_ENTRY]; - debugC(3, kDebugLevelInput, "handling key: %02x", key); + if (key == 0) // nothing pressed + return false; - switch (key) { - case KEY_ENTER: - debugC(3, kDebugLevelInput, "KEY_ENTER"); - _game.keypress = 0; - - // Remove all leading spaces - for (p = _game.inputBuffer; *p && *p == 0x20; p++) - ; - - // Copy to internal buffer - for (; *p && c < 40-1; p++) { - // Squash spaces - if (*p == 0x20 && *(p + 1) == 0x20) { - p++; - continue; + // 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; } - formattedEntry[c++] = tolower(*p); + default: + break; } - formattedEntry[c++] = 0; + // Otherwise go on and look for the ESC controller + } - // Handle string only if it's not empty - if (formattedEntry[0]) { - strcpy((char *)_game.echoBuffer, (const char *)_game.inputBuffer); - strcpy(_lastSentence, (const char *)formattedEntry); - dictionaryWords(_lastSentence); - } + // AGI 3.149 games, The Black Cauldron and King's Quest 4 need KEY_ESCAPE to use menus + // Games with the GF_ESCPAUSE flag need KEY_ESCAPE to pause the game + // (key == KEY_ESCAPE && getVersion() != 0x3149 && getGameID() != GID_BC && getGameID() != GID_KQ4 && !(getFeatures() & GF_ESCPAUSE)) ) + // return false; - // Clear to start a new line - _game.hasPrompt = 0; - _game.inputBuffer[_game.cursorPos = 0] = 0; - debugC(3, kDebugLevelInput | kDebugLevelText, "clear lines"); - clearLines(l, l + 1, bg); - flushLines(l, l + 1); -#ifdef __DS__ - DS::findWordCompletions((char *) _game.inputBuffer); -#endif + 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 + } - break; - case KEY_ESCAPE: - debugC(3, kDebugLevelInput, "KEY_ESCAPE"); - newInputMode(INPUT_MENU); - break; - case KEY_BACKSPACE: - // Ignore backspace at start of line - if (_game.cursorPos == 0) - break; + debugC(3, kDebugLevelInput, "key = %04x", key); - // erase cursor - _gfx->printCharacter(_game.cursorPos + promptLength, l, ' ', fg, bg); - _game.inputBuffer[--_game.cursorPos] = 0; + 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.controllerOccured[_game.controllerKeyMapping[curMapping].controllerSlot] = true; + return true; + } + } - // Print cursor - _gfx->printCharacter(_game.cursorPos + promptLength, l, _game.cursorChar, fg, bg); + int16 newDirection = 0; -#ifdef __DS__ - DS::findWordCompletions((char *) _game.inputBuffer); -#endif + 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: - // Ignore invalid keystrokes - if (key < 0x20 || key > 0x7f) - break; + break; + } - // Maximum input size reached - if (_game.cursorPos >= getvar(vMaxInputChars)) - 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 #3018770. + 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; + } + } + } + } + } - _game.inputBuffer[_game.cursorPos++] = key; - _game.inputBuffer[_game.cursorPos] = 0; + 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; + } -#ifdef __DS__ - DS::findWordCompletions((char *) _game.inputBuffer); -#endif + return false; +} - // echo - _gfx->printCharacter(_game.cursorPos + promptLength - 1, l, _game.inputBuffer[_game.cursorPos - 1], fg, bg); +bool AgiEngine::showPredictiveDialog() { + GUI::PredictiveDialog predictiveDialog; - // Print cursor - _gfx->printCharacter(_game.cursorPos + promptLength, l, _game.cursorChar, fg, bg); - break; + inGameTimerPause(); + predictiveDialog.runModal(); + inGameTimerResume(); + + Common::String predictiveResult(predictiveDialog.getResult()); + uint16 predictiveResultLen = predictiveResult.size(); + if (predictiveResult.size()) { + // 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() { @@ -407,22 +568,12 @@ int AgiEngine::waitKey() { clearKeyQueue(); debugC(3, kDebugLevelInput, "waiting..."); - while (!(shouldQuit() || _restartGame || getflag(fRestoreJustRan))) { - pollTimer(); + while (!(shouldQuit() || _restartGame || getFlag(VM_FLAG_RESTORE_JUST_RAN))) { + wait(10); key = doPollKeyboard(); - if (key == KEY_ENTER || key == KEY_ESCAPE || key == BUTTON_LEFT) + if (key == AGI_KEY_ENTER || key == AGI_KEY_ESCAPE || key == AGI_MOUSE_BUTTON_LEFT) break; - - pollTimer(); - updateTimer(); - - _gfx->doUpdate(); } - - // Have to clear it as original did not set this variable, and we do it in doPollKeyboard() - // Fixes bug #2823759 - _game.keypress = 0; - return key; } @@ -433,29 +584,24 @@ int AgiEngine::waitAnyKey() { debugC(3, kDebugLevelInput, "waiting... (any key)"); while (!(shouldQuit() || _restartGame)) { - pollTimer(); + wait(10); key = doPollKeyboard(); if (key) break; - _gfx->doUpdate(); } - - // Have to clear it as original did not set this variable, and we do it in doPollKeyboard() - _game.keypress = 0; - return key; } bool AgiEngine::isKeypress() { - processEvents(); + processScummVMEvents(); return _keyQueueStart != _keyQueueEnd; } int AgiEngine::getKeypress() { int k; - while (_keyQueueStart == _keyQueueEnd) // block - pollTimer(); + while (_keyQueueStart == _keyQueueEnd) // block + wait(10); keyDequeue(k); |