mirror of
https://github.com/OpenSpace/OpenSpace.git
synced 2026-02-21 12:29:04 -06:00
Moved the lua command input to separete class
- Added functionality for keeping the input history
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -9,6 +9,7 @@ ext/SGCT
|
||||
# generated glsl files
|
||||
*.gglsl
|
||||
*.OpenSpaceGenerated.glsl
|
||||
shaders/generated/*
|
||||
|
||||
# CMake stuff
|
||||
CMakeCache.txt
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
#include <openspace/interaction/interactionhandler.h>
|
||||
#include <openspace/rendering/renderengine.h>
|
||||
#include <openspace/engine/configurationmanager.h>
|
||||
#include <openspace/interaction/luaconsole.h>
|
||||
//#include <ghoul/misc/dictionary.h>
|
||||
|
||||
#include <ghoul/opencl/clcontext.h>
|
||||
@@ -92,6 +93,8 @@ public:
|
||||
void encode();
|
||||
void decode();
|
||||
|
||||
void setInputCommand(bool b);
|
||||
|
||||
private:
|
||||
OpenSpaceEngine(std::string programName);
|
||||
~OpenSpaceEngine();
|
||||
@@ -117,14 +120,7 @@ private:
|
||||
sgct::SharedVector<char> _synchronizationBuffer;
|
||||
|
||||
bool _inputCommand;
|
||||
size_t _inputPosition;
|
||||
std::vector<std::string> _commandsHistory;
|
||||
size_t _activeCommand;
|
||||
std::vector<std::string> _commands;
|
||||
|
||||
void renderActiveCommand();
|
||||
void handleCommandInput(int key, int action);
|
||||
void addToCommand(std::string c);
|
||||
LuaConsole* _console;
|
||||
};
|
||||
|
||||
#define OsEng (openspace::OpenSpaceEngine::ref())
|
||||
|
||||
@@ -1,3 +1,27 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
* without restriction, including without limitation the rights to use, copy, modify, *
|
||||
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
|
||||
* permit persons to whom the Software is furnished to do so, subject to the following *
|
||||
* conditions: *
|
||||
* *
|
||||
* The above copyright notice and this permission notice shall be included in all copies *
|
||||
* or substantial portions of the Software. *
|
||||
* *
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
|
||||
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
|
||||
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
|
||||
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
|
||||
****************************************************************************************/
|
||||
|
||||
#ifndef INTERACTIONHANDLER_H
|
||||
#define INTERACTIONHANDLER_H
|
||||
|
||||
|
||||
60
include/openspace/interaction/luaconsole.h
Normal file
60
include/openspace/interaction/luaconsole.h
Normal file
@@ -0,0 +1,60 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
* without restriction, including without limitation the rights to use, copy, modify, *
|
||||
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
|
||||
* permit persons to whom the Software is furnished to do so, subject to the following *
|
||||
* conditions: *
|
||||
* *
|
||||
* The above copyright notice and this permission notice shall be included in all copies *
|
||||
* or substantial portions of the Software. *
|
||||
* *
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
|
||||
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
|
||||
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
|
||||
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
|
||||
****************************************************************************************/
|
||||
|
||||
#ifndef LUACONSOLE_H
|
||||
#define LUACONSOLE_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace openspace {
|
||||
|
||||
class LuaConsole {
|
||||
public:
|
||||
LuaConsole();
|
||||
~LuaConsole();
|
||||
|
||||
void keyboardCallback(int key, int action);
|
||||
void charCallback(unsigned int codepoint);
|
||||
|
||||
void render();
|
||||
|
||||
unsigned int commandInputButton();
|
||||
unsigned int ignoreCodepoint();
|
||||
|
||||
|
||||
private:
|
||||
void addToCommand(std::string c);
|
||||
std::string UnicodeToUTF8(unsigned int codepoint);
|
||||
|
||||
size_t _inputPosition;
|
||||
std::vector<std::string> _commandsHistory;
|
||||
size_t _activeCommand;
|
||||
std::vector<std::string> _commands;
|
||||
|
||||
};
|
||||
|
||||
} // namespace openspace
|
||||
|
||||
#endif
|
||||
@@ -42,6 +42,7 @@
|
||||
#include <ghoul/lua/lua_helper.h>
|
||||
#include <ghoul/cmdparser/commandlineparser.h>
|
||||
#include <ghoul/cmdparser/singlecommand.h>
|
||||
#include <ghoul/filesystem/cachemanager.h>
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
@@ -57,136 +58,10 @@ namespace {
|
||||
const std::string _sgctDefaultConfigFile = "${SGCT}/single.xml";
|
||||
|
||||
const std::string _sgctConfigArgumentCommand = "-config";
|
||||
|
||||
#ifdef WIN32
|
||||
const unsigned int CommandInputButton = SGCT_KEY_BACKSLASH; // Button left of 1 and abobe TAB
|
||||
const unsigned int IgnoreCodepoint = 167; // Correesponding codepoint
|
||||
#else
|
||||
const unsigned int CommandInputButton = SGCT_KEY_GRAVE_ACCENT; // Button left of 1 and abobe TAB
|
||||
const unsigned int IgnoreCodepoint = 167; // Correesponding codepoint
|
||||
|
||||
// Dangerus as fuck
|
||||
bool exec(const std::string& cmd, std::string& value)
|
||||
{
|
||||
FILE* pipe = popen(cmd.c_str(), "r");
|
||||
if (!pipe)
|
||||
return false;
|
||||
|
||||
const int buffer_size = 1024;
|
||||
char buffer[buffer_size];
|
||||
value = "";
|
||||
while(!feof(pipe))
|
||||
{
|
||||
if(fgets(buffer, buffer_size, pipe) != NULL)
|
||||
{
|
||||
value += buffer;
|
||||
}
|
||||
}
|
||||
pclose(pipe);
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
struct {
|
||||
std::string configurationName;
|
||||
} commandlineArgumentPlaceholders;
|
||||
|
||||
// TODO: Put this functio nsomewhere appropriate
|
||||
// get text from clipboard
|
||||
std::string getClipboardText()
|
||||
{
|
||||
#ifdef WIN32
|
||||
// Try opening the clipboard
|
||||
if (!OpenClipboard(nullptr))
|
||||
return "";
|
||||
|
||||
// Get handle of clipboard object for ANSI text
|
||||
HANDLE hData = GetClipboardData(CF_TEXT);
|
||||
if (hData == nullptr)
|
||||
return "";
|
||||
|
||||
// Lock the handle to get the actual text pointer
|
||||
char * pszText = static_cast<char*>(GlobalLock(hData));
|
||||
if (pszText == nullptr)
|
||||
return "";
|
||||
|
||||
// Save text in a string class instance
|
||||
std::string text(pszText);
|
||||
|
||||
// Release the lock
|
||||
GlobalUnlock(hData);
|
||||
|
||||
// Release the clipboard
|
||||
CloseClipboard();
|
||||
|
||||
text.erase(std::remove(text.begin(), text.end(), '\r'), text.end());
|
||||
return text;
|
||||
#else
|
||||
std::string text;
|
||||
if(exec("xclip -o -sel c -f", text))
|
||||
return text.substr(0, text.length()-1);
|
||||
return ""; // remove a line ending
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
// TODO: Put this function somewhere appropriate
|
||||
// set text to clipboard
|
||||
bool setClipboardText(std::string text)
|
||||
{
|
||||
#ifdef WIN32
|
||||
char *ptrData = nullptr;
|
||||
HANDLE hData = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, text.length() + 1);
|
||||
|
||||
ptrData = (char*)GlobalLock(hData);
|
||||
memcpy(ptrData, text.c_str(), text.length() + 1);
|
||||
|
||||
GlobalUnlock(hData);
|
||||
|
||||
if (!OpenClipboard(nullptr))
|
||||
return false;
|
||||
|
||||
if (!EmptyClipboard())
|
||||
return false;
|
||||
|
||||
SetClipboardData(CF_TEXT, hData);
|
||||
|
||||
CloseClipboard();
|
||||
|
||||
return true;
|
||||
#else
|
||||
std::stringstream cmd;
|
||||
cmd << "echo \"" << text << "\" | xclip -i -sel c -f";
|
||||
std::string buf;
|
||||
return exec(cmd.str(), buf);
|
||||
#endif
|
||||
}
|
||||
|
||||
std::string UnicodeToUTF8(unsigned int codepoint){
|
||||
std::string out;
|
||||
|
||||
if (codepoint <= 0x7f)
|
||||
out.append(1, static_cast<char>(codepoint));
|
||||
else if (codepoint <= 0x7ff)
|
||||
{
|
||||
out.append(1, static_cast<char>(0xc0 | ((codepoint >> 6) & 0x1f)));
|
||||
out.append(1, static_cast<char>(0x80 | (codepoint & 0x3f)));
|
||||
}
|
||||
else if (codepoint <= 0xffff)
|
||||
{
|
||||
out.append(1, static_cast<char>(0xe0 | ((codepoint >> 12) & 0x0f)));
|
||||
out.append(1, static_cast<char>(0x80 | ((codepoint >> 6) & 0x3f)));
|
||||
out.append(1, static_cast<char>(0x80 | (codepoint & 0x3f)));
|
||||
}
|
||||
else
|
||||
{
|
||||
out.append(1, static_cast<char>(0xf0 | ((codepoint >> 18) & 0x07)));
|
||||
out.append(1, static_cast<char>(0x80 | ((codepoint >> 12) & 0x3f)));
|
||||
out.append(1, static_cast<char>(0x80 | ((codepoint >> 6) & 0x3f)));
|
||||
out.append(1, static_cast<char>(0x80 | (codepoint & 0x3f)));
|
||||
}
|
||||
return out;
|
||||
}
|
||||
}
|
||||
|
||||
using namespace ghoul::cmdparser;
|
||||
@@ -198,13 +73,14 @@ OpenSpaceEngine* OpenSpaceEngine::_engine = nullptr;
|
||||
OpenSpaceEngine::OpenSpaceEngine(std::string programName)
|
||||
: _commandlineParser(programName, true)
|
||||
, _inputCommand(false)
|
||||
, _inputPosition(0)
|
||||
, _activeCommand(0)
|
||||
, _commands({""})
|
||||
, _console(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
OpenSpaceEngine::~OpenSpaceEngine() {
|
||||
if (_console)
|
||||
delete _console;
|
||||
|
||||
SpiceManager::deinitialize();
|
||||
Time::deinitialize();
|
||||
DeviceIdentifier::deinit();
|
||||
@@ -331,6 +207,8 @@ bool OpenSpaceEngine::create(int argc, char** argv,
|
||||
// Create the cachemanager
|
||||
FileSys.createCacheManager("${CACHE}");
|
||||
|
||||
_engine->_console = new LuaConsole();
|
||||
|
||||
// Determining SGCT configuration file
|
||||
LDEBUG("Determining SGCT configuration file");
|
||||
std::string sgctConfigurationPath = _sgctDefaultConfigFile;
|
||||
@@ -541,48 +419,10 @@ void OpenSpaceEngine::render() {
|
||||
// If currently writing a command, render it to screen
|
||||
sgct::SGCTWindow* w = sgct::Engine::instance()->getActiveWindowPtr();
|
||||
if (sgct::Engine::instance()->isMaster() && !w->isUsingFisheyeRendering() && _inputCommand) {
|
||||
renderActiveCommand();
|
||||
_console->render();
|
||||
}
|
||||
}
|
||||
|
||||
void OpenSpaceEngine::renderActiveCommand() {
|
||||
|
||||
const int font_size = 10;
|
||||
int x1, xSize, y1, ySize;
|
||||
sgct::Engine::instance()->getActiveWindowPtr()->getCurrentViewportPixelCoords(x1, y1, xSize, ySize);
|
||||
int startY = ySize - 2 * font_size;
|
||||
startY = startY - font_size * 10 * 2;
|
||||
|
||||
const int font_with = font_size*0.7;
|
||||
const glm::vec4 red(1, 0, 0, 1);
|
||||
const glm::vec4 green(0, 1, 0, 1);
|
||||
const glm::vec4 white(1, 1, 1, 1);
|
||||
const sgct_text::Font* font = sgct_text::FontManager::instance()->getFont(constants::fonts::keyMono, font_size);
|
||||
Freetype::print(font, 10, startY, red, "$");
|
||||
Freetype::print(font, 10 + font_size, startY, white, "%s", _commands.at(_activeCommand).c_str());
|
||||
|
||||
size_t n = std::count(_commands.at(_activeCommand).begin(), _commands.at(_activeCommand).begin() + _inputPosition, '\n');
|
||||
size_t p = _commands.at(_activeCommand).find_last_of('\n', _inputPosition);
|
||||
size_t linepos = _inputPosition;
|
||||
|
||||
if (n>0) {
|
||||
if (p == _inputPosition) {
|
||||
p = _commands.at(_activeCommand).find_last_of('\n', _inputPosition - 1);
|
||||
if (p != std::string::npos) {
|
||||
linepos -= p + 1;
|
||||
}
|
||||
else {
|
||||
linepos = _inputPosition - 1;
|
||||
}
|
||||
}
|
||||
else{
|
||||
linepos -= p + 1;
|
||||
}
|
||||
}
|
||||
char buffer[10];
|
||||
sprintf(buffer, "%%%lus", linepos + 1);
|
||||
Freetype::print(font, 10 + static_cast<float>(font_size)*0.5, startY - (font_size)*(n + 1)*3.0 / 2.0, green, buffer, "^");
|
||||
}
|
||||
|
||||
void OpenSpaceEngine::postDraw() {
|
||||
if (sgct::Engine::instance()->isMaster())
|
||||
@@ -606,16 +446,9 @@ void OpenSpaceEngine::postDraw() {
|
||||
#endif
|
||||
}
|
||||
|
||||
void OpenSpaceEngine::addToCommand(std::string c) {
|
||||
size_t length = c.length();
|
||||
_commands.at(_activeCommand).insert(_inputPosition, c);
|
||||
_inputPosition += length;
|
||||
}
|
||||
|
||||
void OpenSpaceEngine::keyboardCallback(int key, int action) {
|
||||
if (sgct::Engine::instance()->isMaster()) {
|
||||
|
||||
if (key == CommandInputButton && (action == SGCT_PRESS || action == SGCT_REPEAT)) {
|
||||
if (key == _console->commandInputButton() && (action == SGCT_PRESS || action == SGCT_REPEAT)) {
|
||||
_inputCommand = !_inputCommand;
|
||||
}
|
||||
|
||||
@@ -623,132 +456,14 @@ void OpenSpaceEngine::keyboardCallback(int key, int action) {
|
||||
_interactionHandler.keyboardCallback(key, action);
|
||||
}
|
||||
else {
|
||||
handleCommandInput(key, action);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OpenSpaceEngine::handleCommandInput(int key, int action) {
|
||||
if (action == SGCT_PRESS || action == SGCT_REPEAT) {
|
||||
const size_t windowIndex = sgct::Engine::instance()->getFocusedWindowIndex();
|
||||
const bool mod_CONTROL = sgct::Engine::instance()->getKey(windowIndex, SGCT_KEY_LEFT_CONTROL) ||
|
||||
sgct::Engine::instance()->getKey(windowIndex, SGCT_KEY_RIGHT_CONTROL);
|
||||
const bool mod_SHIFT = sgct::Engine::instance()->getKey(windowIndex, SGCT_KEY_LEFT_SHIFT) ||
|
||||
sgct::Engine::instance()->getKey(windowIndex, SGCT_KEY_RIGHT_SHIFT);
|
||||
|
||||
// Paste from clipboard
|
||||
if (key == SGCT_KEY_V) {
|
||||
if (mod_CONTROL) {
|
||||
addToCommand(getClipboardText());
|
||||
}
|
||||
}
|
||||
|
||||
// Copy to clipboard
|
||||
if (key == SGCT_KEY_C) {
|
||||
if (mod_CONTROL) {
|
||||
setClipboardText(_commands.at(_activeCommand));
|
||||
}
|
||||
}
|
||||
|
||||
// Go to the previous character
|
||||
if (key == SGCT_KEY_LEFT) {
|
||||
if (_inputPosition > 0)
|
||||
_inputPosition -= 1;
|
||||
}
|
||||
|
||||
// Go to the next character
|
||||
if (key == SGCT_KEY_RIGHT) {
|
||||
if (_inputPosition < _commands.at(_activeCommand).length())
|
||||
++_inputPosition;
|
||||
}
|
||||
|
||||
// Go to previous command
|
||||
if (key == SGCT_KEY_UP) {
|
||||
if (_activeCommand > 0)
|
||||
--_activeCommand;
|
||||
_inputPosition = _commands.at(_activeCommand).length();
|
||||
}
|
||||
|
||||
// Go to next command (the last is empty)
|
||||
if (key == SGCT_KEY_DOWN) {
|
||||
if (_activeCommand < _commands.size()-1)
|
||||
++_activeCommand;
|
||||
_inputPosition = _commands.at(_activeCommand).length();
|
||||
}
|
||||
|
||||
// Remove character before _inputPosition
|
||||
if (key == SGCT_KEY_BACKSPACE) {
|
||||
if (_inputPosition > 0) {
|
||||
_commands.at(_activeCommand).erase(_inputPosition - 1, 1);
|
||||
--_inputPosition;
|
||||
}
|
||||
}
|
||||
|
||||
// Remove character after _inputPosition
|
||||
if (key == SGCT_KEY_DELETE) {
|
||||
if (_inputPosition <= _commands.at(_activeCommand).size()) {
|
||||
_commands.at(_activeCommand).erase(_inputPosition, 1);
|
||||
}
|
||||
}
|
||||
|
||||
// Go to the beginning of command string
|
||||
if (key == SGCT_KEY_HOME) {
|
||||
_inputPosition = 0;
|
||||
}
|
||||
|
||||
// Go to the end of command string
|
||||
if (key == SGCT_KEY_END) {
|
||||
_inputPosition = _commands.at(_activeCommand).size();
|
||||
}
|
||||
|
||||
if (key == SGCT_KEY_ENTER) {
|
||||
|
||||
// SHIFT+ENTER == new line
|
||||
if (mod_SHIFT) {
|
||||
addToCommand("\n");
|
||||
}
|
||||
// CTRL+ENTER == Debug print the command
|
||||
else if (mod_CONTROL) {
|
||||
LDEBUG("Active command from next line:\n" << _commands.at(_activeCommand));
|
||||
}
|
||||
// ENTER == run lua script
|
||||
else {
|
||||
if (_commands.at(_activeCommand) != "") {
|
||||
|
||||
_scriptEngine.runScript(_commands.at(_activeCommand));
|
||||
_commandsHistory.push_back(_commands.at(_activeCommand));
|
||||
_commands = _commandsHistory;
|
||||
_commands.push_back("");
|
||||
_activeCommand = _commands.size() - 1;
|
||||
_inputPosition = 0;
|
||||
}
|
||||
else {
|
||||
_commands = _commandsHistory;
|
||||
_commands.push_back("");
|
||||
_inputCommand = false;
|
||||
}
|
||||
}
|
||||
_console->keyboardCallback(key, action);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OpenSpaceEngine::charCallback(unsigned int codepoint) {
|
||||
|
||||
// SGCT_KEY_BACKSLASH == 92 but that corresponds to codepoint 167
|
||||
if (_inputCommand && codepoint != IgnoreCodepoint) {
|
||||
|
||||
#ifndef WIN32
|
||||
const size_t windowIndex = sgct::Engine::instance()->getFocusedWindowIndex();
|
||||
const bool mod_CONTROL = sgct::Engine::instance()->getKey(windowIndex, SGCT_KEY_LEFT_CONTROL) ||
|
||||
sgct::Engine::instance()->getKey(windowIndex, SGCT_KEY_RIGHT_CONTROL);
|
||||
|
||||
const int codepoint_C = 99;
|
||||
const int codepoint_V = 118;
|
||||
if(mod_CONTROL && (codepoint == codepoint_C || codepoint == codepoint_V)) {
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
addToCommand(UnicodeToUTF8(codepoint));
|
||||
if (_inputCommand) {
|
||||
_console->charCallback(codepoint);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -795,6 +510,10 @@ void OpenSpaceEngine::decode()
|
||||
//#endif
|
||||
}
|
||||
|
||||
void OpenSpaceEngine::setInputCommand(bool b) {
|
||||
_inputCommand = b;
|
||||
}
|
||||
|
||||
void OpenSpaceEngine::externalControlCallback(const char* receivedChars,
|
||||
int size, int clientId)
|
||||
{
|
||||
|
||||
@@ -1,3 +1,26 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
* without restriction, including without limitation the rights to use, copy, modify, *
|
||||
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
|
||||
* permit persons to whom the Software is furnished to do so, subject to the following *
|
||||
* conditions: *
|
||||
* *
|
||||
* The above copyright notice and this permission notice shall be included in all copies *
|
||||
* or substantial portions of the Software. *
|
||||
* *
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
|
||||
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
|
||||
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
|
||||
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
|
||||
****************************************************************************************/
|
||||
|
||||
// open space includes
|
||||
#include <ghoul/logging/logmanager.h>
|
||||
|
||||
391
src/interaction/luaconsole.cpp
Normal file
391
src/interaction/luaconsole.cpp
Normal file
@@ -0,0 +1,391 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
* without restriction, including without limitation the rights to use, copy, modify, *
|
||||
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
|
||||
* permit persons to whom the Software is furnished to do so, subject to the following *
|
||||
* conditions: *
|
||||
* *
|
||||
* The above copyright notice and this permission notice shall be included in all copies *
|
||||
* or substantial portions of the Software. *
|
||||
* *
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
|
||||
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
|
||||
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
|
||||
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
|
||||
****************************************************************************************/
|
||||
|
||||
#include <openspace/interaction/luaconsole.h>
|
||||
#include <openspace/util/constants.h>
|
||||
#include <openspace/engine/openspaceengine.h>
|
||||
|
||||
#include <ghoul/filesystem/filesystem.h>
|
||||
#include <ghoul/logging/logmanager.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <sgct.h>
|
||||
|
||||
namespace {
|
||||
const std::string _loggerCat = "LuaConsole";
|
||||
const std::string _filename = "${TEMPORARY}/history";
|
||||
|
||||
#if !defined(WIN32)
|
||||
// Dangerus as fuck (if malicious input)
|
||||
bool exec(const std::string& cmd, std::string& value)
|
||||
{
|
||||
FILE* pipe = popen(cmd.c_str(), "r");
|
||||
if (!pipe)
|
||||
return false;
|
||||
|
||||
const int buffer_size = 1024;
|
||||
char buffer[buffer_size];
|
||||
value = "";
|
||||
while (!feof(pipe))
|
||||
{
|
||||
if (fgets(buffer, buffer_size, pipe) != NULL)
|
||||
{
|
||||
value += buffer;
|
||||
}
|
||||
}
|
||||
pclose(pipe);
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
// TODO: Put this functio nsomewhere appropriate
|
||||
// get text from clipboard
|
||||
std::string getClipboardText() {
|
||||
#if defined(WIN32)
|
||||
// Try opening the clipboard
|
||||
if (!OpenClipboard(nullptr))
|
||||
return "";
|
||||
|
||||
// Get handle of clipboard object for ANSI text
|
||||
HANDLE hData = GetClipboardData(CF_TEXT);
|
||||
if (hData == nullptr)
|
||||
return "";
|
||||
|
||||
// Lock the handle to get the actual text pointer
|
||||
char * pszText = static_cast<char*>(GlobalLock(hData));
|
||||
if (pszText == nullptr)
|
||||
return "";
|
||||
|
||||
// Save text in a string class instance
|
||||
std::string text(pszText);
|
||||
|
||||
// Release the lock
|
||||
GlobalUnlock(hData);
|
||||
|
||||
// Release the clipboard
|
||||
CloseClipboard();
|
||||
|
||||
text.erase(std::remove(text.begin(), text.end(), '\r'), text.end());
|
||||
return text;
|
||||
#elif defined(__APPLE__)
|
||||
std::string text;
|
||||
if (exec("pbpaste", text))
|
||||
return text.substr(0, text.length() - 1);
|
||||
return ""; // remove a line ending
|
||||
#else
|
||||
std::string text;
|
||||
if (exec("xclip -o -sel c -f", text))
|
||||
return text.substr(0, text.length() - 1);
|
||||
return ""; // remove a line ending
|
||||
#endif
|
||||
}
|
||||
|
||||
// TODO: Put this function somewhere appropriate
|
||||
// set text to clipboard
|
||||
bool setClipboardText(std::string text)
|
||||
{
|
||||
#if defined(WIN32)
|
||||
char *ptrData = nullptr;
|
||||
HANDLE hData = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, text.length() + 1);
|
||||
|
||||
ptrData = (char*)GlobalLock(hData);
|
||||
memcpy(ptrData, text.c_str(), text.length() + 1);
|
||||
|
||||
GlobalUnlock(hData);
|
||||
|
||||
if (!OpenClipboard(nullptr))
|
||||
return false;
|
||||
|
||||
if (!EmptyClipboard())
|
||||
return false;
|
||||
|
||||
SetClipboardData(CF_TEXT, hData);
|
||||
|
||||
CloseClipboard();
|
||||
|
||||
return true;
|
||||
#elif defined(__APPLE__)
|
||||
std::stringstream cmd;
|
||||
cmd << "echo \"" << text << "\" | pbcopy";
|
||||
std::string buf;
|
||||
return exec(cmd.str(), buf);
|
||||
#else
|
||||
std::stringstream cmd;
|
||||
cmd << "echo \"" << text << "\" | xclip -i -sel c -f";
|
||||
std::string buf;
|
||||
return exec(cmd.str(), buf);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
namespace openspace {
|
||||
|
||||
LuaConsole::LuaConsole()
|
||||
: _inputPosition(0)
|
||||
, _activeCommand(0)
|
||||
{
|
||||
FILE* file = fopen(absPath(_filename).c_str(), "rb");
|
||||
if (file) {
|
||||
size_t n;
|
||||
fread(&n, sizeof(size_t), 1, file);
|
||||
for (size_t i = 0; i < n; ++i) {
|
||||
size_t length;
|
||||
fread(&length, sizeof(size_t), 1, file);
|
||||
char* tmp = new char[length + 1];
|
||||
fread(tmp, sizeof(char), length, file);
|
||||
tmp[length] = '\0';
|
||||
_commandsHistory.emplace_back(tmp);
|
||||
delete[] tmp;
|
||||
}
|
||||
fclose(file);
|
||||
_commands = _commandsHistory;
|
||||
}
|
||||
_commands.push_back("");
|
||||
_activeCommand = _commands.size() - 1;
|
||||
}
|
||||
|
||||
LuaConsole::~LuaConsole() {
|
||||
FILE* file = fopen(absPath(_filename).c_str(), "wb");
|
||||
if (file) {
|
||||
size_t n = _commandsHistory.size();
|
||||
fwrite(&n, sizeof(size_t), 1, file);
|
||||
for (auto s : _commandsHistory) {
|
||||
size_t length = s.length();
|
||||
fwrite(&length, sizeof(size_t), 1, file);
|
||||
fwrite(s.c_str(), sizeof(char), length, file);
|
||||
}
|
||||
fclose(file);
|
||||
}
|
||||
}
|
||||
|
||||
void LuaConsole::keyboardCallback(int key, int action) {
|
||||
if (action == SGCT_PRESS || action == SGCT_REPEAT) {
|
||||
const size_t windowIndex = sgct::Engine::instance()->getFocusedWindowIndex();
|
||||
const bool mod_CONTROL = sgct::Engine::instance()->getKey(windowIndex, SGCT_KEY_LEFT_CONTROL) ||
|
||||
sgct::Engine::instance()->getKey(windowIndex, SGCT_KEY_RIGHT_CONTROL);
|
||||
const bool mod_SHIFT = sgct::Engine::instance()->getKey(windowIndex, SGCT_KEY_LEFT_SHIFT) ||
|
||||
sgct::Engine::instance()->getKey(windowIndex, SGCT_KEY_RIGHT_SHIFT);
|
||||
|
||||
// Paste from clipboard
|
||||
if (key == SGCT_KEY_V) {
|
||||
if (mod_CONTROL) {
|
||||
addToCommand(getClipboardText());
|
||||
}
|
||||
}
|
||||
|
||||
// Copy to clipboard
|
||||
if (key == SGCT_KEY_C) {
|
||||
if (mod_CONTROL) {
|
||||
setClipboardText(_commands.at(_activeCommand));
|
||||
}
|
||||
}
|
||||
|
||||
// Go to the previous character
|
||||
if (key == SGCT_KEY_LEFT) {
|
||||
if (_inputPosition > 0)
|
||||
_inputPosition -= 1;
|
||||
}
|
||||
|
||||
// Go to the next character
|
||||
if (key == SGCT_KEY_RIGHT) {
|
||||
if (_inputPosition < _commands.at(_activeCommand).length())
|
||||
++_inputPosition;
|
||||
}
|
||||
|
||||
// Go to previous command
|
||||
if (key == SGCT_KEY_UP) {
|
||||
if (_activeCommand > 0)
|
||||
--_activeCommand;
|
||||
_inputPosition = _commands.at(_activeCommand).length();
|
||||
}
|
||||
|
||||
// Go to next command (the last is empty)
|
||||
if (key == SGCT_KEY_DOWN) {
|
||||
if (_activeCommand < _commands.size() - 1)
|
||||
++_activeCommand;
|
||||
_inputPosition = _commands.at(_activeCommand).length();
|
||||
}
|
||||
|
||||
// Remove character before _inputPosition
|
||||
if (key == SGCT_KEY_BACKSPACE) {
|
||||
if (_inputPosition > 0) {
|
||||
_commands.at(_activeCommand).erase(_inputPosition - 1, 1);
|
||||
--_inputPosition;
|
||||
}
|
||||
}
|
||||
|
||||
// Remove character after _inputPosition
|
||||
if (key == SGCT_KEY_DELETE) {
|
||||
if (_inputPosition <= _commands.at(_activeCommand).size()) {
|
||||
_commands.at(_activeCommand).erase(_inputPosition, 1);
|
||||
}
|
||||
}
|
||||
|
||||
// Go to the beginning of command string
|
||||
if (key == SGCT_KEY_HOME) {
|
||||
_inputPosition = 0;
|
||||
}
|
||||
|
||||
// Go to the end of command string
|
||||
if (key == SGCT_KEY_END) {
|
||||
_inputPosition = _commands.at(_activeCommand).size();
|
||||
}
|
||||
|
||||
if (key == SGCT_KEY_ENTER) {
|
||||
|
||||
// SHIFT+ENTER == new line
|
||||
if (mod_SHIFT) {
|
||||
addToCommand("\n");
|
||||
}
|
||||
// CTRL+ENTER == Debug print the command
|
||||
else if (mod_CONTROL) {
|
||||
LDEBUG("Active command from next line:\n" << _commands.at(_activeCommand));
|
||||
}
|
||||
// ENTER == run lua script
|
||||
else {
|
||||
if (_commands.at(_activeCommand) != "") {
|
||||
|
||||
OsEng.scriptEngine().runScript(_commands.at(_activeCommand));
|
||||
_commandsHistory.push_back(_commands.at(_activeCommand));
|
||||
_commands = _commandsHistory;
|
||||
_commands.push_back("");
|
||||
_activeCommand = _commands.size() - 1;
|
||||
_inputPosition = 0;
|
||||
}
|
||||
else {
|
||||
_commands = _commandsHistory;
|
||||
_commands.push_back("");
|
||||
OsEng.setInputCommand(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LuaConsole::charCallback(unsigned int codepoint) {
|
||||
if (codepoint == ignoreCodepoint())
|
||||
return;
|
||||
|
||||
#ifndef WIN32
|
||||
const size_t windowIndex = sgct::Engine::instance()->getFocusedWindowIndex();
|
||||
const bool mod_CONTROL = sgct::Engine::instance()->getKey(windowIndex, SGCT_KEY_LEFT_CONTROL) ||
|
||||
sgct::Engine::instance()->getKey(windowIndex, SGCT_KEY_RIGHT_CONTROL);
|
||||
|
||||
const int codepoint_C = 99;
|
||||
const int codepoint_V = 118;
|
||||
if (mod_CONTROL && (codepoint == codepoint_C || codepoint == codepoint_V)) {
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
addToCommand(UnicodeToUTF8(codepoint));
|
||||
|
||||
}
|
||||
|
||||
void LuaConsole::render() {
|
||||
const int font_size = 10;
|
||||
int x1, xSize, y1, ySize;
|
||||
sgct::Engine::instance()->getActiveWindowPtr()->getCurrentViewportPixelCoords(x1, y1, xSize, ySize);
|
||||
int startY = ySize - 2 * font_size;
|
||||
startY = startY - font_size * 10 * 2;
|
||||
|
||||
const int font_with = font_size*0.7;
|
||||
const glm::vec4 red(1, 0, 0, 1);
|
||||
const glm::vec4 green(0, 1, 0, 1);
|
||||
const glm::vec4 white(1, 1, 1, 1);
|
||||
const sgct_text::Font* font = sgct_text::FontManager::instance()->getFont(constants::fonts::keyMono, font_size);
|
||||
Freetype::print(font, 10, startY, red, "$");
|
||||
Freetype::print(font, 10 + font_size, startY, white, "%s", _commands.at(_activeCommand).c_str());
|
||||
|
||||
size_t n = std::count(_commands.at(_activeCommand).begin(), _commands.at(_activeCommand).begin() + _inputPosition, '\n');
|
||||
size_t p = _commands.at(_activeCommand).find_last_of('\n', _inputPosition);
|
||||
size_t linepos = _inputPosition;
|
||||
|
||||
if (n>0) {
|
||||
if (p == _inputPosition) {
|
||||
p = _commands.at(_activeCommand).find_last_of('\n', _inputPosition - 1);
|
||||
if (p != std::string::npos) {
|
||||
linepos -= p + 1;
|
||||
}
|
||||
else {
|
||||
linepos = _inputPosition - 1;
|
||||
}
|
||||
}
|
||||
else{
|
||||
linepos -= p + 1;
|
||||
}
|
||||
}
|
||||
char buffer[10];
|
||||
sprintf(buffer, "%%%lus", linepos + 1);
|
||||
Freetype::print(font, 10 + static_cast<float>(font_size)*0.5, startY - (font_size)*(n + 1)*3.0 / 2.0, green, buffer, "^");
|
||||
}
|
||||
|
||||
unsigned int LuaConsole::commandInputButton(){
|
||||
// Button left of 1 and abobe TAB
|
||||
#ifdef WIN32
|
||||
return SGCT_KEY_BACKSLASH;
|
||||
#else
|
||||
return SGCT_KEY_GRAVE_ACCENT;
|
||||
#endif
|
||||
}
|
||||
|
||||
unsigned int LuaConsole::ignoreCodepoint() {
|
||||
// Correesponding codepoint for commandInputButton()
|
||||
return 167;
|
||||
}
|
||||
|
||||
void LuaConsole::addToCommand(std::string c) {
|
||||
size_t length = c.length();
|
||||
_commands.at(_activeCommand).insert(_inputPosition, c);
|
||||
_inputPosition += length;
|
||||
}
|
||||
|
||||
std::string LuaConsole::UnicodeToUTF8(unsigned int codepoint) {
|
||||
std::string out;
|
||||
|
||||
if (codepoint <= 0x7f)
|
||||
out.append(1, static_cast<char>(codepoint));
|
||||
else if (codepoint <= 0x7ff)
|
||||
{
|
||||
out.append(1, static_cast<char>(0xc0 | ((codepoint >> 6) & 0x1f)));
|
||||
out.append(1, static_cast<char>(0x80 | (codepoint & 0x3f)));
|
||||
}
|
||||
else if (codepoint <= 0xffff)
|
||||
{
|
||||
out.append(1, static_cast<char>(0xe0 | ((codepoint >> 12) & 0x0f)));
|
||||
out.append(1, static_cast<char>(0x80 | ((codepoint >> 6) & 0x3f)));
|
||||
out.append(1, static_cast<char>(0x80 | (codepoint & 0x3f)));
|
||||
}
|
||||
else
|
||||
{
|
||||
out.append(1, static_cast<char>(0xf0 | ((codepoint >> 18) & 0x07)));
|
||||
out.append(1, static_cast<char>(0x80 | ((codepoint >> 12) & 0x3f)));
|
||||
out.append(1, static_cast<char>(0x80 | ((codepoint >> 6) & 0x3f)));
|
||||
out.append(1, static_cast<char>(0x80 | (codepoint & 0x3f)));
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
} // namespace openspace
|
||||
Reference in New Issue
Block a user