aboutsummaryrefslogtreecommitdiff
path: root/engines/agi/keyboard.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'engines/agi/keyboard.cpp')
-rw-r--r--engines/agi/keyboard.cpp792
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);