Files
scummvm/engines/wintermute/base/base_keyboard_state.cpp
T

656 lines
18 KiB
C++

/* 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.
*
*/
/*
* This file is based on WME Lite.
* http://dead-code.org/redir.php?target=wmelite
* Copyright (c) 2011 Jan Nedoma
*/
#include "engines/wintermute/base/base_keyboard_state.h"
#include "engines/wintermute/base/scriptables/script_value.h"
#include "engines/wintermute/base/scriptables/script_stack.h"
#include "common/system.h"
#include "common/keyboard.h"
#define KEYSTATES_ARRAY_SIZE (Common::KEYCODE_UNDO + 1) // Hardcoded size for the common/keyboard.h enum
namespace Wintermute {
IMPLEMENT_PERSISTENT(BaseKeyboardState, false)
//////////////////////////////////////////////////////////////////////////
BaseKeyboardState::BaseKeyboardState(BaseGame *inGame) : BaseScriptable(inGame) {
_currentPrintable = false;
_currentCharCode = 0;
_currentKeyData = 0;
_currentShift = false;
_currentAlt = false;
_currentControl = false;
_keyStates = new uint8[KEYSTATES_ARRAY_SIZE];
for (int i = 0; i < KEYSTATES_ARRAY_SIZE; i++) {
_keyStates[i] = false;
}
}
//////////////////////////////////////////////////////////////////////////
BaseKeyboardState::~BaseKeyboardState() {
delete[] _keyStates;
}
void BaseKeyboardState::handleKeyPress(Common::Event *event) {
if (event->type == Common::EVENT_KEYDOWN) {
_keyStates[event->kbd.keycode] = true;
}
}
void BaseKeyboardState::handleKeyRelease(Common::Event *event) {
if (event->type == Common::EVENT_KEYUP) {
_keyStates[event->kbd.keycode] = false;
}
}
//////////////////////////////////////////////////////////////////////////
// high level scripting interface
//////////////////////////////////////////////////////////////////////////
bool BaseKeyboardState::scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack, const char *name) {
//////////////////////////////////////////////////////////////////////////
// IsKeyDown
//////////////////////////////////////////////////////////////////////////
if (strcmp(name, "IsKeyDown") == 0) {
stack->correctParams(1);
ScValue *val = stack->pop();
uint32 vKeyCode;
if (val->_type == VAL_STRING && strlen(val->getString()) > 0) {
// IsKeyDown(strings) checks if a key with given ASCII code is pressed
// Only 1st character of given string is used for the check
// This check must be case insensitive, which means that
// IsKeyDown("a") & IsKeyDown("A") are either both true or both false
const char *str = val->getString();
char temp = str[0];
if (temp >= 'A' && temp <= 'Z') {
temp += ('a' - 'A');
}
// Common::KeyCode is equal to ASCII code for any lowercase ASCII character
if (temp >= ' ' && temp <= '~') {
vKeyCode = (int)temp;
} else {
warning("Unhandled IsKeyDown(string): check for non-ASCII character");
vKeyCode = 0;
}
} else {
// IsKeyDown(int) checks if a key with given keycode is pressed
// For letters, single keycode is used for upper and lower case
// This mean that IsKeyDown(65) is true for both 'a' and Shift+'a'
// See "MSDN: Virtual-Key Codes" for more details on original WME keycodes
vKeyCode = vKeyToKeyCode(val->getInt());
}
bool isDown = _keyStates[vKeyCode];
stack->pushBool(isDown);
return STATUS_OK;
} else {
return BaseScriptable::scCallMethod(script, stack, thisStack, name);
}
}
//////////////////////////////////////////////////////////////////////////
ScValue *BaseKeyboardState::scGetProperty(const Common::String &name) {
_scValue->setNULL();
//////////////////////////////////////////////////////////////////////////
// Type
//////////////////////////////////////////////////////////////////////////
if (name == "Type") {
_scValue->setString("keyboard");
return _scValue;
}
//////////////////////////////////////////////////////////////////////////
// Key
//////////////////////////////////////////////////////////////////////////
else if (name == "Key") {
if (_currentPrintable) {
char key[2];
key[0] = (char)_currentCharCode;
key[1] = '\0';
_scValue->setString(key);
} else {
_scValue->setString("");
}
return _scValue;
}
//////////////////////////////////////////////////////////////////////////
// Printable
//////////////////////////////////////////////////////////////////////////
else if (name == "Printable") {
_scValue->setBool(_currentPrintable);
return _scValue;
}
//////////////////////////////////////////////////////////////////////////
// KeyCode
//////////////////////////////////////////////////////////////////////////
else if (name == "KeyCode") {
_scValue->setInt(_currentCharCode);
return _scValue;
}
//////////////////////////////////////////////////////////////////////////
// IsShift
//////////////////////////////////////////////////////////////////////////
else if (name == "IsShift") {
_scValue->setBool(_currentShift);
return _scValue;
}
//////////////////////////////////////////////////////////////////////////
// IsAlt
//////////////////////////////////////////////////////////////////////////
else if (name == "IsAlt") {
_scValue->setBool(_currentAlt);
return _scValue;
}
//////////////////////////////////////////////////////////////////////////
// IsControl
//////////////////////////////////////////////////////////////////////////
else if (name == "IsControl") {
_scValue->setBool(_currentControl);
return _scValue;
} else {
return BaseScriptable::scGetProperty(name);
}
}
//////////////////////////////////////////////////////////////////////////
bool BaseKeyboardState::scSetProperty(const char *name, ScValue *value) {
/*
//////////////////////////////////////////////////////////////////////////
// Name
//////////////////////////////////////////////////////////////////////////
if (strcmp(name, "Name") == 0) {
setName(value->getString());
if (_renderer) SetWindowText(_renderer->_window, _name);
return STATUS_OK;
}
else*/ return BaseScriptable::scSetProperty(name, value);
}
//////////////////////////////////////////////////////////////////////////
const char *BaseKeyboardState::scToString() {
return "[keyboard state]";
}
//////////////////////////////////////////////////////////////////////////
bool BaseKeyboardState::readKey(Common::Event *event) {
Common::KeyCode code = event->kbd.keycode;
if (event->type != Common::EVENT_KEYDOWN) {
_currentCharCode = 0;
_currentPrintable = false;
}
// use ASCII value if key pressed is an alphanumeric or punctuation key
// keys pressed on numpad are handled in next 2 blocks
else if (code > Common::KEYCODE_SPACE && code < Common::KEYCODE_DELETE) {
_currentCharCode = event->kbd.ascii;
_currentPrintable = true;
}
// use ASCII value for numpad '/', '*', '-', '+'
else if (code >= Common::KEYCODE_KP_DIVIDE && code <= Common::KEYCODE_KP_PLUS) {
_currentCharCode = event->kbd.ascii;
_currentPrintable = true;
}
// if NumLock is active, use ASCII for numpad keys '0'~'9' and '.'
// keys pressed on numpad without NumLock are considered as normal keycodes, handled in the next block
else if ((code >= Common::KEYCODE_KP0 && code <= Common::KEYCODE_KP_PERIOD) && ((event->kbd.flags & Common::KBD_NUM) != 0)) {
_currentCharCode = event->kbd.ascii;
_currentPrintable = true;
}
// use keyCodeToVKey mapping for all other events
// some keys are printable from those keys
else {
_currentCharCode = keyCodeToVKey(event);
_currentPrintable = code == Common::KEYCODE_BACKSPACE ||
code == Common::KEYCODE_TAB ||
code == Common::KEYCODE_RETURN ||
code == Common::KEYCODE_KP_ENTER ||
code == Common::KEYCODE_ESCAPE ||
code == Common::KEYCODE_SPACE;
}
//_currentKeyData = KeyData;
_currentControl = isControlDown();
_currentAlt = isAltDown();
_currentShift = isShiftDown();
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
bool BaseKeyboardState::persist(BasePersistenceManager *persistMgr) {
//if (!persistMgr->getIsSaving()) cleanup();
BaseScriptable::persist(persistMgr);
persistMgr->transferBool(TMEMBER(_currentAlt));
persistMgr->transferUint32(TMEMBER(_currentCharCode));
persistMgr->transferBool(TMEMBER(_currentControl));
persistMgr->transferUint32(TMEMBER(_currentKeyData));
persistMgr->transferBool(TMEMBER(_currentPrintable));
persistMgr->transferBool(TMEMBER(_currentShift));
if (!persistMgr->getIsSaving()) {
_keyStates = new uint8[323]; // Hardcoded size for the common/keyboard.h enum
for (int i = 0; i < 323; i++) {
_keyStates[i] = false;
}
}
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
bool BaseKeyboardState::isShiftDown() {
int mod = g_system->getEventManager()->getModifierState();
return (mod & Common::KBD_SHIFT);
}
//////////////////////////////////////////////////////////////////////////
bool BaseKeyboardState::isControlDown() {
int mod = g_system->getEventManager()->getModifierState();
return (mod & Common::KBD_CTRL);
}
//////////////////////////////////////////////////////////////////////////
bool BaseKeyboardState::isAltDown() {
int mod = g_system->getEventManager()->getModifierState();
return (mod & Common::KBD_ALT);
}
//////////////////////////////////////////////////////////////////////////
bool BaseKeyboardState::isCurrentPrintable() const {
return _currentPrintable;
}
//////////////////////////////////////////////////////////////////////////
enum VKeyCodes {
kVkBack = 8, //printable
kVkTab = 9, //printable
kVkClear = 12,
kVkReturn = 13, //printable
kVkPause = 19,
kVkCapital = 20,
kVkEscape = 27, //printable
kVkSpace = 32, //printable
kVkPrior = 33,
kVkNext = 34,
kVkEnd = 35,
kVkHome = 36,
kVkLeft = 37,
kVkUp = 38,
kVkRight = 39,
kVkDown = 40,
kVkPrint = 42,
kVkInsert = 45,
kVkDelete = 46,
kVkA = 65, //printable
kVkB = 66, //printable
kVkC = 67, //printable
kVkD = 68, //printable
kVkE = 69, //printable
kVkF = 70, //printable
kVkG = 71, //printable
kVkH = 72, //printable
kVkI = 73, //printable
kVkJ = 74, //printable
kVkK = 75, //printable
kVkL = 76, //printable
kVkM = 77, //printable
kVkN = 78, //printable
kVkO = 79, //printable
kVkP = 80, //printable
kVkQ = 81, //printable
kVkR = 82, //printable
kVkS = 83, //printable
kVkT = 84, //printable
kVkU = 85, //printable
kVkV = 86, //printable
kVkW = 87, //printable
kVkX = 88, //printable
kVkY = 89, //printable
kVkZ = 90, //printable
kVkNumpad0 = 96, //printable
kVkNumpad1 = 97, //printable
kVkNumpad2 = 98, //printable
kVkNumpad3 = 99, //printable
kVkNumpad4 = 100, //printable
kVkNumpad5 = 101, //printable
kVkNumpad6 = 102, //printable
kVkNumpad7 = 103, //printable
kVkNumpad8 = 104, //printable
kVkNumpad9 = 105, //printable
kVkMultiply = 106, //printable
kVkAdd = 107, //printable
kVkSeparator = 108, //printable
kVkSubtract = 109, //printable
kVkDecimal = 110, //printable
kVkDivide = 111, //printable
kVkF1 = 112,
kVkF2 = 113,
kVkF3 = 114,
kVkF4 = 115,
kVkF5 = 116,
kVkF6 = 117,
kVkF7 = 118,
kVkF8 = 119,
kVkF9 = 120,
kVkF10 = 121,
kVkF11 = 122,
kVkF12 = 123,
kVkNumLock = 144,
kVkScroll = 145
//TODO: shift, ctrl, menu, etc...
};
//////////////////////////////////////////////////////////////////////////
uint32 BaseKeyboardState::keyCodeToVKey(Common::Event *event) {
switch (event->kbd.keycode) {
case Common::KEYCODE_BACKSPACE:
return kVkBack;
case Common::KEYCODE_TAB:
return kVkTab;
case Common::KEYCODE_CLEAR:
case Common::KEYCODE_KP5:
return kVkClear;
case Common::KEYCODE_RETURN:
case Common::KEYCODE_KP_ENTER:
return kVkReturn;
case Common::KEYCODE_PAUSE:
return kVkPause;
case Common::KEYCODE_CAPSLOCK:
return kVkCapital;
case Common::KEYCODE_ESCAPE:
return kVkEscape;
case Common::KEYCODE_SPACE:
return kVkSpace;
case Common::KEYCODE_KP9:
case Common::KEYCODE_PAGEUP:
return kVkPrior;
case Common::KEYCODE_KP3:
case Common::KEYCODE_PAGEDOWN:
return kVkNext;
case Common::KEYCODE_END:
case Common::KEYCODE_KP1:
return kVkEnd;
case Common::KEYCODE_HOME:
case Common::KEYCODE_KP7:
return kVkHome;
case Common::KEYCODE_LEFT:
case Common::KEYCODE_KP4:
return kVkLeft;
case Common::KEYCODE_RIGHT:
case Common::KEYCODE_KP6:
return kVkRight;
case Common::KEYCODE_UP:
case Common::KEYCODE_KP8:
return kVkUp;
case Common::KEYCODE_DOWN:
case Common::KEYCODE_KP2:
return kVkDown;
case Common::KEYCODE_PRINT:
return kVkPrint;
case Common::KEYCODE_INSERT:
case Common::KEYCODE_KP0:
return kVkInsert;
case Common::KEYCODE_DELETE:
case Common::KEYCODE_KP_PERIOD:
return kVkDelete;
case Common::KEYCODE_F1:
return kVkF1;
case Common::KEYCODE_F2:
return kVkF2;
case Common::KEYCODE_F3:
return kVkF3;
case Common::KEYCODE_F4:
return kVkF4;
case Common::KEYCODE_F5:
return kVkF5;
case Common::KEYCODE_F6:
return kVkF6;
case Common::KEYCODE_F7:
return kVkF7;
case Common::KEYCODE_F8:
return kVkF8;
case Common::KEYCODE_F9:
return kVkF9;
case Common::KEYCODE_F10:
return kVkF10;
case Common::KEYCODE_F11:
return kVkF11;
case Common::KEYCODE_F12:
return kVkF12;
case Common::KEYCODE_NUMLOCK:
return kVkNumLock;
case Common::KEYCODE_SCROLLOCK:
return kVkScroll;
default:
// check if any non-sticky keys were used, otherwise key is unknown to us
if ((event->kbd.flags & Common::KBD_NON_STICKY) == 0) {
warning("Key pressed is not recognized, ASCII returned (%d '%c').", event->kbd.keycode, event->kbd.keycode);
}
// return ASCII if no match, since it could be used for typing
return event->kbd.ascii;
break;
}
}
//////////////////////////////////////////////////////////////////////////
Common::KeyCode BaseKeyboardState::vKeyToKeyCode(uint32 vkey) {
switch (vkey) {
case kVkBack:
return Common::KEYCODE_BACKSPACE;
case kVkTab:
return Common::KEYCODE_TAB;
case kVkClear:
return Common::KEYCODE_CLEAR;
case kVkReturn:
return Common::KEYCODE_RETURN;
case kVkPause:
return Common::KEYCODE_PAUSE;
case kVkCapital:
return Common::KEYCODE_CAPSLOCK;
case kVkEscape:
return Common::KEYCODE_ESCAPE;
case kVkSpace:
return Common::KEYCODE_SPACE;
case kVkPrior:
return Common::KEYCODE_PAGEUP;
case kVkNext:
return Common::KEYCODE_PAGEDOWN;
case kVkHome:
return Common::KEYCODE_HOME;
case kVkEnd:
return Common::KEYCODE_END;
case kVkLeft:
return Common::KEYCODE_LEFT;
case kVkRight:
return Common::KEYCODE_RIGHT;
case kVkUp:
return Common::KEYCODE_UP;
case kVkDown:
return Common::KEYCODE_DOWN;
case kVkPrint:
return Common::KEYCODE_PRINT;
case kVkInsert:
return Common::KEYCODE_INSERT;
case kVkDelete:
return Common::KEYCODE_DELETE;
case kVkA:
return Common::KEYCODE_a;
case kVkB:
return Common::KEYCODE_b;
case kVkC:
return Common::KEYCODE_c;
case kVkD:
return Common::KEYCODE_d;
case kVkE:
return Common::KEYCODE_e;
case kVkF:
return Common::KEYCODE_f;
case kVkG:
return Common::KEYCODE_g;
case kVkH:
return Common::KEYCODE_h;
case kVkI:
return Common::KEYCODE_i;
case kVkJ:
return Common::KEYCODE_j;
case kVkK:
return Common::KEYCODE_k;
case kVkL:
return Common::KEYCODE_l;
case kVkM:
return Common::KEYCODE_m;
case kVkN:
return Common::KEYCODE_n;
case kVkO:
return Common::KEYCODE_o;
case kVkP:
return Common::KEYCODE_p;
case kVkQ:
return Common::KEYCODE_q;
case kVkR:
return Common::KEYCODE_r;
case kVkS:
return Common::KEYCODE_s;
case kVkT:
return Common::KEYCODE_t;
case kVkU:
return Common::KEYCODE_u;
case kVkV:
return Common::KEYCODE_v;
case kVkW:
return Common::KEYCODE_w;
case kVkX:
return Common::KEYCODE_x;
case kVkY:
return Common::KEYCODE_y;
case kVkZ:
return Common::KEYCODE_z;
case kVkNumpad0:
return Common::KEYCODE_KP0;
case kVkNumpad1:
return Common::KEYCODE_KP1;
case kVkNumpad2:
return Common::KEYCODE_KP2;
case kVkNumpad3:
return Common::KEYCODE_KP3;
case kVkNumpad4:
return Common::KEYCODE_KP4;
case kVkNumpad5:
return Common::KEYCODE_KP5;
case kVkNumpad6:
return Common::KEYCODE_KP6;
case kVkNumpad7:
return Common::KEYCODE_KP7;
case kVkNumpad8:
return Common::KEYCODE_KP8;
case kVkNumpad9:
return Common::KEYCODE_KP9;
case kVkMultiply:
return Common::KEYCODE_KP_MULTIPLY;
case kVkAdd:
return Common::KEYCODE_KP_PLUS;
case kVkSeparator:
return Common::KEYCODE_KP_EQUALS;
case kVkSubtract:
return Common::KEYCODE_KP_MINUS;
case kVkDecimal:
return Common::KEYCODE_KP_PERIOD;
case kVkDivide:
return Common::KEYCODE_KP_DIVIDE;
case kVkF1:
return Common::KEYCODE_F1;
case kVkF2:
return Common::KEYCODE_F2;
case kVkF3:
return Common::KEYCODE_F3;
case kVkF4:
return Common::KEYCODE_F4;
case kVkF5:
return Common::KEYCODE_F5;
case kVkF6:
return Common::KEYCODE_F6;
case kVkF7:
return Common::KEYCODE_F7;
case kVkF8:
return Common::KEYCODE_F8;
case kVkF9:
return Common::KEYCODE_F9;
case kVkF10:
return Common::KEYCODE_F10;
case kVkF11:
return Common::KEYCODE_F11;
case kVkF12:
return Common::KEYCODE_F12;
case kVkNumLock:
return Common::KEYCODE_NUMLOCK;
case kVkScroll:
return Common::KEYCODE_SCROLLOCK;
default:
warning("Unknown VKEY: %d", vkey);
return (Common::KeyCode)(vkey < KEYSTATES_ARRAY_SIZE ? vkey : 0);
break;
}
}
} // End of namespace Wintermute