Initial commit
This commit is contained in:
283
engines/sword25/input/inputengine.cpp
Normal file
283
engines/sword25/input/inputengine.cpp
Normal file
@@ -0,0 +1,283 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This code is based on Broken Sword 2.5 engine
|
||||
*
|
||||
* Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdoerfer
|
||||
*
|
||||
* Licensed under GNU GPL v2
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common/algorithm.h"
|
||||
#include "common/events.h"
|
||||
#include "common/system.h"
|
||||
#include "common/util.h"
|
||||
|
||||
#include "sword25/sword25.h"
|
||||
#include "sword25/kernel/kernel.h"
|
||||
#include "sword25/kernel/inputpersistenceblock.h"
|
||||
#include "sword25/kernel/outputpersistenceblock.h"
|
||||
#include "sword25/input/inputengine.h"
|
||||
|
||||
namespace Sword25 {
|
||||
|
||||
#define DOUBLE_CLICK_TIME 500
|
||||
#define DOUBLE_CLICK_RECT_SIZE 4
|
||||
|
||||
InputEngine::InputEngine(Kernel *pKernel) :
|
||||
Service(pKernel),
|
||||
_currentState(0),
|
||||
_leftMouseDown(false),
|
||||
_rightMouseDown(false),
|
||||
_mouseX(0),
|
||||
_mouseY(0),
|
||||
_leftDoubleClick(false),
|
||||
_doubleClickTime(DOUBLE_CLICK_TIME),
|
||||
_doubleClickRectWidth(DOUBLE_CLICK_RECT_SIZE),
|
||||
_doubleClickRectHeight(DOUBLE_CLICK_RECT_SIZE),
|
||||
_lastLeftClickTime(0),
|
||||
_lastLeftClickMouseX(0),
|
||||
_lastLeftClickMouseY(0) {
|
||||
memset(_keyboardState[0], 0, sizeof(_keyboardState[0]));
|
||||
memset(_keyboardState[1], 0, sizeof(_keyboardState[1]));
|
||||
_leftMouseState[0] = false;
|
||||
_leftMouseState[1] = false;
|
||||
_rightMouseState[0] = false;
|
||||
_rightMouseState[1] = false;
|
||||
|
||||
if (!registerScriptBindings())
|
||||
error("Script bindings could not be registered.");
|
||||
else
|
||||
debugC(kDebugScript, "Script bindings registered.");
|
||||
}
|
||||
|
||||
InputEngine::~InputEngine() {
|
||||
unregisterScriptBindings();
|
||||
}
|
||||
|
||||
bool InputEngine::init() {
|
||||
// No initialisation needed
|
||||
return true;
|
||||
}
|
||||
|
||||
void InputEngine::update() {
|
||||
Common::Event event;
|
||||
|
||||
// We keep two sets of keyboard states: The current one, and that of
|
||||
// the previous frame. This allows us to detect which keys changed
|
||||
// state. Also, by keeping a single central keystate array, we
|
||||
// ensure that all script queries for key state during a single
|
||||
// frame get the same consistent replies.
|
||||
_currentState ^= 1;
|
||||
memcpy(_keyboardState[_currentState], _keyboardState[_currentState ^ 1], sizeof(_keyboardState[0]));
|
||||
|
||||
// Loop through processing any pending events
|
||||
bool handleEvents = true;
|
||||
while (handleEvents && g_system->getEventManager()->pollEvent(event)) {
|
||||
switch (event.type) {
|
||||
case Common::EVENT_LBUTTONDOWN:
|
||||
case Common::EVENT_LBUTTONUP:
|
||||
_leftMouseDown = event.type == Common::EVENT_LBUTTONDOWN;
|
||||
_mouseX = event.mouse.x;
|
||||
_mouseY = event.mouse.y;
|
||||
handleEvents = false;
|
||||
break;
|
||||
case Common::EVENT_RBUTTONDOWN:
|
||||
case Common::EVENT_RBUTTONUP:
|
||||
_rightMouseDown = event.type == Common::EVENT_RBUTTONDOWN;
|
||||
_mouseX = event.mouse.x;
|
||||
_mouseY = event.mouse.y;
|
||||
handleEvents = false;
|
||||
break;
|
||||
|
||||
case Common::EVENT_MOUSEMOVE:
|
||||
_mouseX = event.mouse.x;
|
||||
_mouseY = event.mouse.y;
|
||||
break;
|
||||
|
||||
case Common::EVENT_KEYDOWN:
|
||||
if (event.kbd.ascii != 0) {
|
||||
reportCharacter(event.kbd.ascii);
|
||||
}
|
||||
// fall through
|
||||
case Common::EVENT_KEYUP:
|
||||
alterKeyboardState(event.kbd.keycode, (event.type == Common::EVENT_KEYDOWN) ? 0x80 : 0);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
_leftMouseState[_currentState] = _leftMouseDown;
|
||||
_rightMouseState[_currentState] = _rightMouseDown;
|
||||
|
||||
testForLeftDoubleClick();
|
||||
}
|
||||
|
||||
bool InputEngine::isLeftMouseDown() {
|
||||
return _leftMouseDown;
|
||||
}
|
||||
|
||||
bool InputEngine::isRightMouseDown() {
|
||||
return _rightMouseDown;
|
||||
}
|
||||
|
||||
void InputEngine::testForLeftDoubleClick() {
|
||||
_leftDoubleClick = false;
|
||||
|
||||
// Only bother checking for a double click if the left mouse button was clicked
|
||||
if (wasLeftMouseDown()) {
|
||||
// Get the time now
|
||||
uint now = Kernel::getInstance()->getMilliTicks();
|
||||
|
||||
// A double click is signalled if
|
||||
// 1. The two clicks are close enough together
|
||||
// 2. The mouse cursor hasn't moved much
|
||||
if (now - _lastLeftClickTime <= _doubleClickTime &&
|
||||
ABS(_mouseX - _lastLeftClickMouseX) <= _doubleClickRectWidth / 2 &&
|
||||
ABS(_mouseY - _lastLeftClickMouseY) <= _doubleClickRectHeight / 2) {
|
||||
_leftDoubleClick = true;
|
||||
|
||||
// Reset the time and position of the last click, so that clicking is not
|
||||
// interpreted as the first click of a further double-click
|
||||
_lastLeftClickTime = 0;
|
||||
_lastLeftClickMouseX = 0;
|
||||
_lastLeftClickMouseY = 0;
|
||||
} else {
|
||||
// There is no double click. Remember the position and time of the click,
|
||||
// in case it's the first click of a double-click sequence
|
||||
_lastLeftClickTime = now;
|
||||
_lastLeftClickMouseX = _mouseX;
|
||||
_lastLeftClickMouseY = _mouseY;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void InputEngine::alterKeyboardState(int keycode, byte newState) {
|
||||
assert(keycode < ARRAYSIZE(_keyboardState[_currentState]));
|
||||
_keyboardState[_currentState][keycode] = newState;
|
||||
}
|
||||
|
||||
bool InputEngine::isLeftDoubleClick() {
|
||||
return _leftDoubleClick;
|
||||
}
|
||||
|
||||
bool InputEngine::wasLeftMouseDown() {
|
||||
return (_leftMouseState[_currentState] == false) && (_leftMouseState[_currentState ^ 1] == true);
|
||||
}
|
||||
|
||||
bool InputEngine::wasRightMouseDown() {
|
||||
return (_rightMouseState[_currentState] == false) && (_rightMouseState[_currentState ^ 1] == true);
|
||||
}
|
||||
|
||||
int InputEngine::getMouseX() {
|
||||
return _mouseX;
|
||||
}
|
||||
|
||||
int InputEngine::getMouseY() {
|
||||
return _mouseY;
|
||||
}
|
||||
|
||||
bool InputEngine::isKeyDown(uint keyCode) {
|
||||
assert(keyCode < ARRAYSIZE(_keyboardState[_currentState]));
|
||||
return (_keyboardState[_currentState][keyCode] & 0x80) != 0;
|
||||
}
|
||||
|
||||
bool InputEngine::wasKeyDown(uint keyCode) {
|
||||
assert(keyCode < ARRAYSIZE(_keyboardState[_currentState]));
|
||||
return ((_keyboardState[_currentState][keyCode] & 0x80) == 0) &&
|
||||
((_keyboardState[_currentState ^ 1][keyCode] & 0x80) != 0);
|
||||
}
|
||||
|
||||
void InputEngine::setMouseX(int posX) {
|
||||
_mouseX = posX;
|
||||
g_system->warpMouse(_mouseX, _mouseY);
|
||||
}
|
||||
|
||||
void InputEngine::setMouseY(int posY) {
|
||||
_mouseY = posY;
|
||||
g_system->warpMouse(_mouseX, _mouseY);
|
||||
}
|
||||
|
||||
void InputEngine::setCharacterCallback(CharacterCallback callback) {
|
||||
_characterCallback = callback;
|
||||
}
|
||||
|
||||
void InputEngine::setCommandCallback(CommandCallback callback) {
|
||||
_commandCallback = callback;
|
||||
}
|
||||
|
||||
void InputEngine::reportCharacter(byte character) {
|
||||
if (_characterCallback)
|
||||
(*_characterCallback)(character);
|
||||
}
|
||||
|
||||
void InputEngine::reportCommand(KEY_COMMANDS command) {
|
||||
if (_commandCallback)
|
||||
(*_commandCallback)(command);
|
||||
}
|
||||
|
||||
bool InputEngine::persist(OutputPersistenceBlock &writer) {
|
||||
// Write out the number of command callbacks and their names.
|
||||
// Note: We do this only for compatibility with older engines resp.
|
||||
// the original engine.
|
||||
writer.write((uint32)1);
|
||||
writer.writeString("LuaCommandCB");
|
||||
|
||||
// Write out the number of command callbacks and their names.
|
||||
// Note: We do this only for compatibility with older engines resp.
|
||||
// the original engine.
|
||||
writer.write((uint32)1);
|
||||
writer.writeString("LuaCharacterCB");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool InputEngine::unpersist(InputPersistenceBlock &reader) {
|
||||
Common::String callbackFunctionName;
|
||||
|
||||
// Read number of command callbacks and their names.
|
||||
// Note: We do this only for compatibility with older engines resp.
|
||||
// the original engine.
|
||||
uint32 commandCallbackCount;
|
||||
reader.read(commandCallbackCount);
|
||||
assert(commandCallbackCount == 1);
|
||||
|
||||
reader.readString(callbackFunctionName);
|
||||
assert(callbackFunctionName == "LuaCommandCB");
|
||||
|
||||
// Read number of character callbacks and their names.
|
||||
// Note: We do this only for compatibility with older engines resp.
|
||||
// the original engine.
|
||||
uint32 characterCallbackCount;
|
||||
reader.read(characterCallbackCount);
|
||||
assert(characterCallbackCount == 1);
|
||||
|
||||
reader.readString(callbackFunctionName);
|
||||
assert(callbackFunctionName == "LuaCharacterCB");
|
||||
|
||||
return reader.isGood();
|
||||
}
|
||||
|
||||
} // End of namespace Sword25
|
||||
318
engines/sword25/input/inputengine.h
Normal file
318
engines/sword25/input/inputengine.h
Normal file
@@ -0,0 +1,318 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This code is based on Broken Sword 2.5 engine
|
||||
*
|
||||
* Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdoerfer
|
||||
*
|
||||
* Licensed under GNU GPL v2
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* BS_InputEngine
|
||||
* -------------
|
||||
* This is the input interface engine that contains all the methods that an
|
||||
* input source must implement.
|
||||
* All input engines must be derived from this class.
|
||||
*
|
||||
* Autor: Alex Arnst
|
||||
*/
|
||||
|
||||
#ifndef SWORD25_INPUTENGINE_H
|
||||
#define SWORD25_INPUTENGINE_H
|
||||
|
||||
#include "common/keyboard.h"
|
||||
|
||||
#include "sword25/kernel/common.h"
|
||||
#include "sword25/kernel/service.h"
|
||||
#include "sword25/kernel/persistable.h"
|
||||
|
||||
namespace Sword25 {
|
||||
|
||||
/// Class definitions
|
||||
|
||||
class InputEngine : public Service, public Persistable {
|
||||
public:
|
||||
InputEngine(Kernel *pKernel);
|
||||
~InputEngine() override;
|
||||
|
||||
// NOTE: These codes are registered in inputengine_script.cpp
|
||||
// If you add or remove entries of this enum, you must also adjust
|
||||
// the above file.
|
||||
enum KEY_CODES {
|
||||
KEY_BACKSPACE = Common::KEYCODE_BACKSPACE,
|
||||
KEY_TAB = Common::KEYCODE_TAB,
|
||||
KEY_CLEAR = Common::KEYCODE_CLEAR,
|
||||
KEY_RETURN = Common::KEYCODE_RETURN,
|
||||
KEY_PAUSE = Common::KEYCODE_PAUSE,
|
||||
KEY_CAPSLOCK = Common::KEYCODE_CAPSLOCK,
|
||||
KEY_ESCAPE = Common::KEYCODE_ESCAPE,
|
||||
KEY_SPACE = Common::KEYCODE_SPACE,
|
||||
KEY_PAGEUP = Common::KEYCODE_PAGEUP,
|
||||
KEY_PAGEDOWN = Common::KEYCODE_PAGEDOWN,
|
||||
KEY_END = Common::KEYCODE_END,
|
||||
KEY_HOME = Common::KEYCODE_HOME,
|
||||
KEY_LEFT = Common::KEYCODE_LEFT,
|
||||
KEY_UP = Common::KEYCODE_UP,
|
||||
KEY_RIGHT = Common::KEYCODE_RIGHT,
|
||||
KEY_DOWN = Common::KEYCODE_DOWN,
|
||||
KEY_PRINTSCREEN = Common::KEYCODE_PRINT,
|
||||
KEY_INSERT = Common::KEYCODE_INSERT,
|
||||
KEY_DELETE = Common::KEYCODE_DELETE,
|
||||
KEY_0 = Common::KEYCODE_0,
|
||||
KEY_1 = Common::KEYCODE_1,
|
||||
KEY_2 = Common::KEYCODE_2,
|
||||
KEY_3 = Common::KEYCODE_3,
|
||||
KEY_4 = Common::KEYCODE_4,
|
||||
KEY_5 = Common::KEYCODE_5,
|
||||
KEY_6 = Common::KEYCODE_6,
|
||||
KEY_7 = Common::KEYCODE_7,
|
||||
KEY_8 = Common::KEYCODE_8,
|
||||
KEY_9 = Common::KEYCODE_9,
|
||||
KEY_A = Common::KEYCODE_a,
|
||||
KEY_B = Common::KEYCODE_b,
|
||||
KEY_C = Common::KEYCODE_c,
|
||||
KEY_D = Common::KEYCODE_d,
|
||||
KEY_E = Common::KEYCODE_e,
|
||||
KEY_F = Common::KEYCODE_f,
|
||||
KEY_G = Common::KEYCODE_g,
|
||||
KEY_H = Common::KEYCODE_h,
|
||||
KEY_I = Common::KEYCODE_i,
|
||||
KEY_J = Common::KEYCODE_j,
|
||||
KEY_K = Common::KEYCODE_k,
|
||||
KEY_L = Common::KEYCODE_l,
|
||||
KEY_M = Common::KEYCODE_m,
|
||||
KEY_N = Common::KEYCODE_n,
|
||||
KEY_O = Common::KEYCODE_o,
|
||||
KEY_P = Common::KEYCODE_p,
|
||||
KEY_Q = Common::KEYCODE_q,
|
||||
KEY_R = Common::KEYCODE_r,
|
||||
KEY_S = Common::KEYCODE_s,
|
||||
KEY_T = Common::KEYCODE_t,
|
||||
KEY_U = Common::KEYCODE_u,
|
||||
KEY_V = Common::KEYCODE_v,
|
||||
KEY_W = Common::KEYCODE_w,
|
||||
KEY_X = Common::KEYCODE_x,
|
||||
KEY_Y = Common::KEYCODE_y,
|
||||
KEY_Z = Common::KEYCODE_z,
|
||||
KEY_NUMPAD0 = Common::KEYCODE_KP0,
|
||||
KEY_NUMPAD1 = Common::KEYCODE_KP1,
|
||||
KEY_NUMPAD2 = Common::KEYCODE_KP2,
|
||||
KEY_NUMPAD3 = Common::KEYCODE_KP3,
|
||||
KEY_NUMPAD4 = Common::KEYCODE_KP4,
|
||||
KEY_NUMPAD5 = Common::KEYCODE_KP5,
|
||||
KEY_NUMPAD6 = Common::KEYCODE_KP6,
|
||||
KEY_NUMPAD7 = Common::KEYCODE_KP7,
|
||||
KEY_NUMPAD8 = Common::KEYCODE_KP8,
|
||||
KEY_NUMPAD9 = Common::KEYCODE_KP9,
|
||||
KEY_MULTIPLY = Common::KEYCODE_KP_MULTIPLY,
|
||||
KEY_ADD = Common::KEYCODE_KP_PLUS,
|
||||
KEY_SEPARATOR = Common::KEYCODE_EQUALS, // FIXME: This mapping is just a wild guess!!
|
||||
KEY_SUBTRACT = Common::KEYCODE_KP_MINUS,
|
||||
KEY_DECIMAL = Common::KEYCODE_KP_PERIOD,
|
||||
KEY_DIVIDE = Common::KEYCODE_KP_DIVIDE,
|
||||
KEY_F1 = Common::KEYCODE_F1,
|
||||
KEY_F2 = Common::KEYCODE_F2,
|
||||
KEY_F3 = Common::KEYCODE_F3,
|
||||
KEY_F4 = Common::KEYCODE_F4,
|
||||
KEY_F5 = Common::KEYCODE_F5,
|
||||
KEY_F6 = Common::KEYCODE_F6,
|
||||
KEY_F7 = Common::KEYCODE_F7,
|
||||
KEY_F8 = Common::KEYCODE_F8,
|
||||
KEY_F9 = Common::KEYCODE_F9,
|
||||
KEY_F10 = Common::KEYCODE_F10,
|
||||
KEY_F11 = Common::KEYCODE_F11,
|
||||
KEY_F12 = Common::KEYCODE_F12,
|
||||
KEY_NUMLOCK = Common::KEYCODE_NUMLOCK,
|
||||
KEY_SCROLL = Common::KEYCODE_SCROLLOCK,
|
||||
KEY_LSHIFT = Common::KEYCODE_LSHIFT,
|
||||
KEY_RSHIFT = Common::KEYCODE_RSHIFT,
|
||||
KEY_LCONTROL = Common::KEYCODE_LCTRL,
|
||||
KEY_RCONTROL = Common::KEYCODE_RCTRL
|
||||
};
|
||||
|
||||
// NOTE: These codes are registered in inputengine_script.cpp
|
||||
// If you add or remove entries of this enum, you must also adjust
|
||||
// the above file.
|
||||
enum KEY_COMMANDS {
|
||||
KEY_COMMAND_ENTER = 1,
|
||||
KEY_COMMAND_LEFT = 2,
|
||||
KEY_COMMAND_RIGHT = 3,
|
||||
KEY_COMMAND_HOME = 4,
|
||||
KEY_COMMAND_END = 5,
|
||||
KEY_COMMAND_BACKSPACE = 6,
|
||||
KEY_COMMAND_TAB = 7,
|
||||
KEY_COMMAND_INSERT = 8,
|
||||
KEY_COMMAND_DELETE = 9
|
||||
};
|
||||
|
||||
/// --------------------------------------------------------------
|
||||
/// THESE METHODS MUST BE IMPLEMENTED BY THE INPUT ENGINE
|
||||
/// --------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Initializes the input engine
|
||||
* @return Returns a true on success, otherwise false.
|
||||
*/
|
||||
bool init();
|
||||
|
||||
/**
|
||||
* Performs a "tick" of the input engine.
|
||||
*
|
||||
* This method should be called once per frame. It can be used by implementations
|
||||
* of the input engine that are not running in their own thread, or to perform
|
||||
* additional administrative tasks that are needed.
|
||||
*/
|
||||
void update();
|
||||
|
||||
/**
|
||||
* Returns true if the left mouse button is pressed
|
||||
*/
|
||||
bool isLeftMouseDown();
|
||||
|
||||
/**
|
||||
* Returns true if the right mouse button is pressed.
|
||||
*/
|
||||
bool isRightMouseDown();
|
||||
|
||||
/**
|
||||
* Returns true if the left mouse button was pressed and released.
|
||||
*
|
||||
* The difference between this and IsLeftMouseDown() is that this only returns
|
||||
* true when the left mouse button is released.
|
||||
*/
|
||||
bool wasLeftMouseDown();
|
||||
|
||||
/**
|
||||
* Returns true if the right mouse button was pressed and released.
|
||||
*
|
||||
* The difference between this and IsRightMouseDown() is that this only returns
|
||||
* true when the right mouse button is released.
|
||||
*/
|
||||
bool wasRightMouseDown();
|
||||
|
||||
/**
|
||||
* Returns true if the left mouse button double click was done
|
||||
*/
|
||||
bool isLeftDoubleClick();
|
||||
|
||||
/**
|
||||
* Returns the X position of the cursor in pixels
|
||||
*/
|
||||
int getMouseX();
|
||||
|
||||
/**
|
||||
* Returns the Y position of the cursor in pixels
|
||||
*/
|
||||
int getMouseY();
|
||||
|
||||
/**
|
||||
* Sets the X position of the cursor in pixels
|
||||
*/
|
||||
void setMouseX(int posX);
|
||||
|
||||
/**
|
||||
* Sets the Y position of the cursor in pixels
|
||||
*/
|
||||
void setMouseY(int posY);
|
||||
|
||||
/**
|
||||
* Returns true if a given key was pressed
|
||||
* @param KeyCode The key code to be checked
|
||||
* @return Returns true if the given key is done, otherwise false.
|
||||
*/
|
||||
bool isKeyDown(uint keyCode);
|
||||
|
||||
/**
|
||||
* Returns true if a certain key was pushed and released.
|
||||
*
|
||||
* The difference between IsKeyDown() is that this only returns true after the key
|
||||
* has been released. This method facilitates the retrieval of keys, and reading
|
||||
* strings that users type.
|
||||
* @param KeyCode The key code to be checked
|
||||
*/
|
||||
bool wasKeyDown(uint keyCode);
|
||||
|
||||
typedef void (*CharacterCallback)(int command);
|
||||
|
||||
/**
|
||||
* Registers a callback function for keyboard input.
|
||||
*
|
||||
* The callback that is registered with this function will be called whenever an
|
||||
* input key is pressed. A letter entry is different from the query using the
|
||||
* methods isKeyDown() and wasKeyDown() in the sense that are treated instead
|
||||
* of actual scan-coded letters. These were taken into account, among other things:
|
||||
* the keyboard layout, the condition the Shift and Caps Lock keys and the repetition
|
||||
* of longer holding the key.
|
||||
* The input of strings by the user through use of callbacks should be implemented.
|
||||
*/
|
||||
void setCharacterCallback(CharacterCallback callback);
|
||||
|
||||
typedef void (*CommandCallback)(int command);
|
||||
|
||||
/**
|
||||
* Registers a callback function for the input of commands that can have influence on the string input
|
||||
*
|
||||
* The callback that is registered with this function will be called whenever the input service
|
||||
* has a key that affects the character string input. This could be the following keys:
|
||||
* Enter, End, Left, Right, ...
|
||||
* The input of strings by the user through the use of callbacks should be implemented.
|
||||
*/
|
||||
void setCommandCallback(CommandCallback callback);
|
||||
|
||||
void reportCharacter(byte character);
|
||||
void reportCommand(KEY_COMMANDS command);
|
||||
|
||||
bool persist(OutputPersistenceBlock &writer) override;
|
||||
bool unpersist(InputPersistenceBlock &reader) override;
|
||||
|
||||
private:
|
||||
bool registerScriptBindings();
|
||||
void unregisterScriptBindings();
|
||||
|
||||
private:
|
||||
void testForLeftDoubleClick();
|
||||
void alterKeyboardState(int keycode, byte newState);
|
||||
|
||||
byte _keyboardState[2][512];
|
||||
bool _leftMouseState[2];
|
||||
bool _rightMouseState[2];
|
||||
uint _currentState;
|
||||
int _mouseX;
|
||||
int _mouseY;
|
||||
bool _leftMouseDown;
|
||||
bool _rightMouseDown;
|
||||
bool _leftDoubleClick;
|
||||
uint _doubleClickTime;
|
||||
int _doubleClickRectWidth;
|
||||
int _doubleClickRectHeight;
|
||||
uint _lastLeftClickTime;
|
||||
int _lastLeftClickMouseX;
|
||||
int _lastLeftClickMouseY;
|
||||
CommandCallback _commandCallback;
|
||||
CharacterCallback _characterCallback;
|
||||
};
|
||||
|
||||
} // End of namespace Sword25
|
||||
|
||||
#endif
|
||||
291
engines/sword25/input/inputengine_script.cpp
Normal file
291
engines/sword25/input/inputengine_script.cpp
Normal file
@@ -0,0 +1,291 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This code is based on Broken Sword 2.5 engine
|
||||
*
|
||||
* Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdoerfer
|
||||
*
|
||||
* Licensed under GNU GPL v2
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common/ptr.h"
|
||||
#include "common/str.h"
|
||||
#include "sword25/kernel/common.h"
|
||||
#include "sword25/kernel/kernel.h"
|
||||
#include "sword25/script/script.h"
|
||||
#include "sword25/script/luabindhelper.h"
|
||||
#include "sword25/script/luacallback.h"
|
||||
|
||||
#include "sword25/input/inputengine.h"
|
||||
|
||||
namespace Sword25 {
|
||||
|
||||
static void theCharacterCallback(int character);
|
||||
static void theCommandCallback(int command);
|
||||
|
||||
namespace {
|
||||
class CharacterCallbackClass : public LuaCallback {
|
||||
public:
|
||||
CharacterCallbackClass(lua_State *L) : LuaCallback(L) {}
|
||||
|
||||
Common::String _character;
|
||||
|
||||
protected:
|
||||
int preFunctionInvocation(lua_State *L) override {
|
||||
lua_pushstring(L, _character.c_str());
|
||||
return 1;
|
||||
}
|
||||
};
|
||||
|
||||
static CharacterCallbackClass *characterCallbackPtr = 0; // FIXME: should be turned into InputEngine member var
|
||||
|
||||
class CommandCallbackClass : public LuaCallback {
|
||||
public:
|
||||
CommandCallbackClass(lua_State *L) : LuaCallback(L) {
|
||||
_command = InputEngine::KEY_COMMAND_BACKSPACE;
|
||||
}
|
||||
|
||||
InputEngine::KEY_COMMANDS _command;
|
||||
|
||||
protected:
|
||||
int preFunctionInvocation(lua_State *L) override {
|
||||
lua_pushnumber(L, _command);
|
||||
return 1;
|
||||
}
|
||||
};
|
||||
|
||||
static CommandCallbackClass *commandCallbackPtr = 0; // FIXME: should be turned into InputEngine member var
|
||||
|
||||
}
|
||||
|
||||
static InputEngine *getIE() {
|
||||
Kernel *pKernel = Kernel::getInstance();
|
||||
assert(pKernel);
|
||||
InputEngine *pIE = pKernel->getInput();
|
||||
assert(pIE);
|
||||
return pIE;
|
||||
}
|
||||
|
||||
static int init(lua_State *L) {
|
||||
InputEngine *pIE = getIE();
|
||||
|
||||
lua_pushbooleancpp(L, pIE->init());
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int update(lua_State *L) {
|
||||
InputEngine *pIE = getIE();
|
||||
|
||||
pIE->update();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int isLeftMouseDown(lua_State *L) {
|
||||
InputEngine *pIE = getIE();
|
||||
|
||||
lua_pushbooleancpp(L, pIE->isLeftMouseDown());
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int isRightMouseDown(lua_State *L) {
|
||||
InputEngine *pIE = getIE();
|
||||
|
||||
lua_pushbooleancpp(L, pIE->isRightMouseDown());
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int wasLeftMouseDown(lua_State *L) {
|
||||
InputEngine *pIE = getIE();
|
||||
|
||||
lua_pushbooleancpp(L, pIE->wasLeftMouseDown());
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int wasRightMouseDown(lua_State *L) {
|
||||
InputEngine *pIE = getIE();
|
||||
|
||||
lua_pushbooleancpp(L, pIE->wasRightMouseDown());
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int isLeftDoubleClick(lua_State *L) {
|
||||
InputEngine *pIE = getIE();
|
||||
|
||||
lua_pushbooleancpp(L, pIE->isLeftDoubleClick());
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int getMouseX(lua_State *L) {
|
||||
InputEngine *pIE = getIE();
|
||||
|
||||
lua_pushnumber(L, pIE->getMouseX());
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int getMouseY(lua_State *L) {
|
||||
InputEngine *pIE = getIE();
|
||||
|
||||
lua_pushnumber(L, pIE->getMouseY());
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int isKeyDown(lua_State *L) {
|
||||
InputEngine *pIE = getIE();
|
||||
|
||||
lua_pushbooleancpp(L, pIE->isKeyDown((uint)luaL_checknumber(L, 1)));
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int wasKeyDown(lua_State *L) {
|
||||
InputEngine *pIE = getIE();
|
||||
|
||||
lua_pushbooleancpp(L, pIE->wasKeyDown((uint)luaL_checknumber(L, 1)));
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int setMouseX(lua_State *L) {
|
||||
InputEngine *pIE = getIE();
|
||||
|
||||
pIE->setMouseX((int)luaL_checknumber(L, 1));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int setMouseY(lua_State *L) {
|
||||
InputEngine *pIE = getIE();
|
||||
|
||||
pIE->setMouseY((int)luaL_checknumber(L, 1));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void theCharacterCallback(int character) {
|
||||
characterCallbackPtr->_character = static_cast<byte>(character);
|
||||
lua_State *L = static_cast<lua_State *>(Kernel::getInstance()->getScript()->getScriptObject());
|
||||
characterCallbackPtr->invokeCallbackFunctions(L, 1);
|
||||
}
|
||||
|
||||
static int registerCharacterCallback(lua_State *L) {
|
||||
luaL_checktype(L, 1, LUA_TFUNCTION);
|
||||
characterCallbackPtr->registerCallbackFunction(L, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int unregisterCharacterCallback(lua_State *L) {
|
||||
luaL_checktype(L, 1, LUA_TFUNCTION);
|
||||
characterCallbackPtr->unregisterCallbackFunction(L, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void theCommandCallback(int command) {
|
||||
commandCallbackPtr->_command = static_cast<InputEngine::KEY_COMMANDS>(command);
|
||||
lua_State *L = static_cast<lua_State *>(Kernel::getInstance()->getScript()->getScriptObject());
|
||||
commandCallbackPtr->invokeCallbackFunctions(L, 1);
|
||||
}
|
||||
|
||||
static int registerCommandCallback(lua_State *L) {
|
||||
luaL_checktype(L, 1, LUA_TFUNCTION);
|
||||
commandCallbackPtr->registerCallbackFunction(L, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int unregisterCommandCallback(lua_State *L) {
|
||||
luaL_checktype(L, 1, LUA_TFUNCTION);
|
||||
commandCallbackPtr->unregisterCallbackFunction(L, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const char *PACKAGE_LIBRARY_NAME = "Input";
|
||||
|
||||
static const luaL_reg PACKAGE_FUNCTIONS[] = {
|
||||
{"Init", init},
|
||||
{"Update", update},
|
||||
{"IsLeftMouseDown", isLeftMouseDown},
|
||||
{"IsRightMouseDown", isRightMouseDown},
|
||||
{"WasLeftMouseDown", wasLeftMouseDown},
|
||||
{"WasRightMouseDown", wasRightMouseDown},
|
||||
{"IsLeftDoubleClick", isLeftDoubleClick},
|
||||
{"GetMouseX", getMouseX},
|
||||
{"GetMouseY", getMouseY},
|
||||
{"SetMouseX", setMouseX},
|
||||
{"SetMouseY", setMouseY},
|
||||
{"IsKeyDown", isKeyDown},
|
||||
{"WasKeyDown", wasKeyDown},
|
||||
{"RegisterCharacterCallback", registerCharacterCallback},
|
||||
{"UnregisterCharacterCallback", unregisterCharacterCallback},
|
||||
{"RegisterCommandCallback", registerCommandCallback},
|
||||
{"UnregisterCommandCallback", unregisterCommandCallback},
|
||||
{0, 0}
|
||||
};
|
||||
|
||||
#define X(k) {"KEY_" #k, InputEngine::KEY_##k}
|
||||
#define Y(k) {"KEY_COMMAND_" #k, InputEngine::KEY_COMMAND_##k}
|
||||
static const lua_constant_reg PACKAGE_CONSTANTS[] = {
|
||||
X(BACKSPACE), X(TAB), X(CLEAR), X(RETURN), X(PAUSE), X(CAPSLOCK), X(ESCAPE), X(SPACE), X(PAGEUP), X(PAGEDOWN), X(END), X(HOME), X(LEFT),
|
||||
X(UP), X(RIGHT), X(DOWN), X(PRINTSCREEN), X(INSERT), X(DELETE), X(0), X(1), X(2), X(3), X(4), X(5), X(6), X(7), X(8), X(9), X(A), X(B),
|
||||
X(C), X(D), X(E), X(F), X(G), X(H), X(I), X(J), X(K), X(L), X(M), X(N), X(O), X(P), X(Q), X(R), X(S), X(T), X(U), X(V), X(W), X(X), X(Y),
|
||||
X(Z), X(NUMPAD0), X(NUMPAD1), X(NUMPAD2), X(NUMPAD3), X(NUMPAD4), X(NUMPAD5), X(NUMPAD6), X(NUMPAD7), X(NUMPAD8), X(NUMPAD9), X(MULTIPLY),
|
||||
X(ADD), X(SEPARATOR), X(SUBTRACT), X(DECIMAL), X(DIVIDE), X(F1), X(F2), X(F3), X(F4), X(F5), X(F6), X(F7), X(F8), X(F9), X(F10), X(F11),
|
||||
X(F12), X(NUMLOCK), X(SCROLL), X(LSHIFT), X(RSHIFT), X(LCONTROL), X(RCONTROL),
|
||||
Y(ENTER), Y(LEFT), Y(RIGHT), Y(HOME), Y(END), Y(BACKSPACE), Y(TAB), Y(INSERT), Y(DELETE),
|
||||
{0, 0}
|
||||
};
|
||||
#undef X
|
||||
#undef Y
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
bool InputEngine::registerScriptBindings() {
|
||||
Kernel *pKernel = Kernel::getInstance();
|
||||
assert(pKernel);
|
||||
ScriptEngine *pScript = pKernel->getScript();
|
||||
assert(pScript);
|
||||
lua_State *L = static_cast<lua_State *>(pScript->getScriptObject());
|
||||
assert(L);
|
||||
|
||||
if (!LuaBindhelper::addFunctionsToLib(L, PACKAGE_LIBRARY_NAME, PACKAGE_FUNCTIONS)) return false;
|
||||
if (!LuaBindhelper::addConstantsToLib(L, PACKAGE_LIBRARY_NAME, PACKAGE_CONSTANTS)) return false;
|
||||
|
||||
assert(characterCallbackPtr == 0);
|
||||
characterCallbackPtr = new CharacterCallbackClass(L);
|
||||
|
||||
assert(commandCallbackPtr == 0);
|
||||
commandCallbackPtr = new CommandCallbackClass(L);
|
||||
|
||||
setCharacterCallback(theCharacterCallback);
|
||||
setCommandCallback(theCommandCallback);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void InputEngine::unregisterScriptBindings() {
|
||||
delete characterCallbackPtr;
|
||||
characterCallbackPtr = 0;
|
||||
|
||||
delete commandCallbackPtr;
|
||||
commandCallbackPtr = 0;
|
||||
}
|
||||
|
||||
} // End of namespace Sword25
|
||||
Reference in New Issue
Block a user