Browse Source

Enhance FileSystem class to also able to execute console command.

Yao Wei Tjong 姚伟忠 11 years ago
parent
commit
5ce5be8d66

+ 5 - 1
Bin/Data/LuaScripts/26_ConsoleInput.lua

@@ -49,6 +49,8 @@ function Start()
 
     -- Show the console by default, make it large
     console.numRows = graphics.height / 16
+    console.numBufferedRows = 2 * console.numRows;
+    console.commandInterpreter = "LuaScript";
     console.visible = true
     
     -- Show OS mouse cursor
@@ -65,7 +67,9 @@ function Start()
 end
 
 function HandleConsoleCommand(eventType, eventData)
-    HandleInput(eventData:GetString("Command"))
+    if eventData:GetString("Id") == "LuaScript" then
+        HandleInput(eventData:GetString("Command"))
+    end
 end
 
 function HandleUpdate(eventType, eventData)

+ 4 - 1
Bin/Data/Scripts/26_ConsoleInput.as

@@ -50,6 +50,8 @@ void Start()
 
     // Show the console by default, make it large
     console.numRows = graphics.height / 16;
+    console.numBufferedRows = 2 * console.numRows;
+    console.commandInterpreter = "ScriptEventInvoker";
     console.visible = true;
     
     // Show OS mouse cursor
@@ -67,7 +69,8 @@ void Start()
 
 void HandleConsoleCommand(StringHash eventType, VariantMap& eventData)
 {
-    HandleInput(eventData["Command"].GetString());
+    if (eventData["Id"].GetString() == "ScriptEventInvoker")
+        HandleInput(eventData["Command"].GetString());
 }
 
 void HandleUpdate(StringHash eventType, VariantMap& eventData)

+ 1 - 0
Source/Engine/Engine/Console.cpp

@@ -290,6 +290,7 @@ bool Console::PopulateInterpreter()
 void Console::HandleInterpreterSelected(StringHash eventType, VariantMap& eventData)
 {
     commandInterpreter_ = static_cast<Text*>(interpreters_->GetSelectedItem())->GetText();
+    lineEdit_->SetFocus(true);
 }
 
 void Console::HandleTextFinished(StringHash eventType, VariantMap& eventData)

+ 48 - 6
Source/Engine/IO/FileSystem.cpp

@@ -24,6 +24,7 @@
 #include "ArrayPtr.h"
 #include "Context.h"
 #include "CoreEvents.h"
+#include "EngineEvents.h"
 #include "File.h"
 #include "FileSystem.h"
 #include "IOEvents.h"
@@ -66,9 +67,27 @@ extern "C" const char* SDL_IOS_GetResourceDir();
 namespace Urho3D
 {
 
-int DoSystemCommand(const String& commandLine)
+int DoSystemCommand(const String& commandLine, bool redirectStdOutToLog)
 {
-    return system(commandLine.CString());
+    if (!redirectStdOutToLog)
+        return system(commandLine.CString());
+
+    #ifdef _MSC_VER
+    #define popen _popen
+    #define pclose _pclose
+    #endif
+
+    // Use popen/pclose to capture the stdout of the command
+    FILE *file = popen(commandLine.CString(), "r");
+    if (!file)
+        return -1;
+    char buffer[128];
+    while (!feof(file))
+    {
+        if (fgets(buffer, 128, file))
+            LOGRAW(String(buffer));
+    }
+    return pclose(file);
 }
 
 int DoSystemRun(const String& fileName, const Vector<String>& arguments)
@@ -171,7 +190,7 @@ public:
     /// The function to run in the thread.
     virtual void ThreadFunction()
     {
-        exitCode_ = DoSystemCommand(commandLine_);
+        exitCode_ = DoSystemCommand(commandLine_, false);
         completed_ = true;
     }
     
@@ -209,9 +228,13 @@ private:
 
 FileSystem::FileSystem(Context* context) :
     Object(context),
-    nextAsyncExecID_(1)
+    nextAsyncExecID_(1),
+    executeConsoleCommands_(false)
 {
     SubscribeToEvent(E_BEGINFRAME, HANDLER(FileSystem, HandleBeginFrame));
+
+    // Subscribe to console commands
+    SetExecuteConsoleCommands(true);
 }
 
 FileSystem::~FileSystem()
@@ -273,10 +296,22 @@ bool FileSystem::CreateDir(const String& pathName)
     return success;
 }
 
-int FileSystem::SystemCommand(const String& commandLine)
+void FileSystem::SetExecuteConsoleCommands(bool enable)
+{
+    if (enable == executeConsoleCommands_)
+        return;
+
+    executeConsoleCommands_ = enable;
+    if (enable)
+        SubscribeToEvent(E_CONSOLECOMMAND, HANDLER(FileSystem, HandleConsoleCommand));
+    else
+        UnsubscribeFromEvent(E_CONSOLECOMMAND);
+}
+
+int FileSystem::SystemCommand(const String& commandLine, bool redirectStdOutToLog)
 {
     if (allowedPaths_.Empty())
-        return DoSystemCommand(commandLine);
+        return DoSystemCommand(commandLine, redirectStdOutToLog);
     else
     {
         LOGERROR("Executing an external command is not allowed");
@@ -742,6 +777,13 @@ void FileSystem::HandleBeginFrame(StringHash eventType, VariantMap& eventData)
     }
 }
 
+void FileSystem::HandleConsoleCommand(StringHash eventType, VariantMap& eventData)
+{
+    using namespace ConsoleCommand;
+    if (eventData[P_ID].GetString() == GetTypeName())
+        SystemCommand(eventData[P_COMMAND].GetString(), true);
+}
+
 void SplitPath(const String& fullPath, String& pathName, String& fileName, String& extension, bool lowercaseExtension)
 {
     String fullPathCopy = GetInternalPath(fullPath);

+ 9 - 1
Source/Engine/IO/FileSystem.h

@@ -53,8 +53,10 @@ public:
     bool SetCurrentDir(const String& pathName);
     /// Create a directory.
     bool CreateDir(const String& pathName);
+    /// Set whether to execute engine console commands as OS-specific system command.
+    void SetExecuteConsoleCommands(bool enable);
     /// Run a program using the command interpreter, block until it exits and return the exit code. Will fail if any allowed paths are defined.
-    int SystemCommand(const String& commandLine);
+    int SystemCommand(const String& commandLine, bool redirectStdOutToLog = false);
     /// Run a specific program, block until it exits and return the exit code. Will fail if any allowed paths are defined.
     int SystemRun(const String& fileName, const Vector<String>& arguments);
     /// Run a program using the command interpreter asynchronously. Return a request ID or M_MAX_UNSIGNED if failed. The exit code will be posted together with the request ID in an AsyncExecFinished event. Will fail if any allowed paths are defined.
@@ -74,6 +76,8 @@ public:
     
     /// Return the absolute current working directory.
     String GetCurrentDir() const;
+    /// Return whether is executing engine console commands as OS-specific system command.
+    bool GetExecuteConsoleCommands() const { return executeConsoleCommands_; }
     /// Return whether paths have been registered.
     bool HasRegisteredPaths() const { return allowedPaths_.Size() > 0; }
     /// Check if a path is allowed to be accessed. If no paths are registered, all are allowed.
@@ -96,6 +100,8 @@ private:
     void ScanDirInternal(Vector<String>& result, String path, const String& startPath, const String& filter, unsigned flags, bool recursive) const;
     /// Handle begin frame event to check for completed async executions.
     void HandleBeginFrame(StringHash eventType, VariantMap& eventData);
+    /// Handle a console command event.
+    void HandleConsoleCommand(StringHash eventType, VariantMap& eventData);
     
     /// Allowed directories.
     HashSet<String> allowedPaths_;
@@ -105,6 +111,8 @@ private:
     List<AsyncExecRequest*> asyncExecQueue_;
     /// Next async execution ID.
     unsigned nextAsyncExecID_;
+    /// Flag for executing engine console commands as OS-specific system command. Default to true.
+    bool executeConsoleCommands_;
 };
 
 /// Split a full path to path, filename and extension. The extension will be converted to lowercase by default.

+ 2 - 2
Source/Engine/LuaScript/LuaScript.cpp

@@ -67,7 +67,7 @@ namespace Urho3D
 LuaScript::LuaScript(Context* context) :
     Object(context),
     luaState_(0),
-    executeConsoleCommands_(true)
+    executeConsoleCommands_(false)
 {
     RegisterLuaScriptLibrary(context_);
 
@@ -108,7 +108,7 @@ LuaScript::LuaScript(Context* context) :
     SubscribeToEvent(E_POSTUPDATE, HANDLER(LuaScript, HandlePostUpdate));
 
     // Subscribe to console commands
-    SubscribeToEvent(E_CONSOLECOMMAND, HANDLER(LuaScript, HandleConsoleCommand));
+    SetExecuteConsoleCommands(true);
     
     // Record the internally handled script functions so that UnsubscribeFromAllEvents doesn't destroy them
     internalEvents_.Push(E_POSTUPDATE);

+ 2 - 2
Source/Engine/LuaScript/LuaScript.h

@@ -66,7 +66,7 @@ public:
     void ScriptUnsubscribeFromEvent(void* sender, const String& eventName, const String& functionName = String::EMPTY);
     /// Script unsubscribe from a specific sender's all events.
     void ScriptUnsubscribeFromEvents(void* sender);
-    /// Set whether to execute engine console commands as script code. Default true.
+    /// Set whether to execute engine console commands as script code.
     void SetExecuteConsoleCommands(bool enable);
 
     /// Return Lua state.
@@ -113,7 +113,7 @@ private:
     HashMap<Object*, HashMap<StringHash, LuaFunctionVector> > objectHandleFunctions_;
     /// Internally used events, which should not be unsubscribed from.
     PODVector<StringHash> internalEvents_;
-    /// Flag for executing engine console commands as script code.
+    /// Flag for executing engine console commands as script code. Default to true.
     bool executeConsoleCommands_;
 };
 

+ 3 - 1
Source/Engine/LuaScript/pkgs/IO/FileSystem.pkg

@@ -8,7 +8,8 @@ class FileSystem : public Object
 {
     bool SetCurrentDir(const String pathName);
     bool CreateDir(const String pathName);
-    int SystemCommand(const String commandLine);
+    void SetExecuteConsoleCommands(bool enable);
+    int SystemCommand(const String commandLine, bool redirectStdOutToLog = false);
     int SystemRun(const String fileName, const Vector<String>& arguments);
     unsigned SystemCommandAsync(const String commandLine);
     unsigned SystemRunAsync(const String fileName, const Vector<String>& arguments);
@@ -18,6 +19,7 @@ class FileSystem : public Object
     bool Delete(const String fileName);
     void RegisterPath(const String pathName);
     String GetCurrentDir() const;
+    bool GetExecuteConsoleCommands() const;
     bool HasRegisteredPaths() const;
     bool CheckAccess(const String pathName) const;
     unsigned GetLastModifiedTime(const String fileName) const;

+ 3 - 1
Source/Engine/Script/IOAPI.cpp

@@ -331,7 +331,7 @@ void RegisterFileSystem(asIScriptEngine* engine)
     engine->RegisterObjectMethod("FileSystem", "uint GetLastModifiedTime(const String&in) const", asMETHOD(FileSystem, GetLastModifiedTime), asCALL_THISCALL);
     engine->RegisterObjectMethod("FileSystem", "Array<String>@ ScanDir(const String&in, const String&in, uint, bool) const", asFUNCTION(FileSystemScanDir), asCALL_CDECL_OBJLAST);
     engine->RegisterObjectMethod("FileSystem", "bool CreateDir(const String&in)", asMETHOD(FileSystem, CreateDir), asCALL_THISCALL);
-    engine->RegisterObjectMethod("FileSystem", "int SystemCommand(const String&in)", asMETHOD(FileSystem, SystemCommand), asCALL_THISCALL);
+    engine->RegisterObjectMethod("FileSystem", "int SystemCommand(const String&in, bool redirectStdOutToLog = false)", asMETHOD(FileSystem, SystemCommand), asCALL_THISCALL);
     engine->RegisterObjectMethod("FileSystem", "int SystemRun(const String&in, Array<String>@+)", asFUNCTION(FileSystemSystemRun), asCALL_CDECL_OBJLAST);
     engine->RegisterObjectMethod("FileSystem", "uint SystemCommandAsync(const String&in)", asMETHOD(FileSystem, SystemCommandAsync), asCALL_THISCALL);
     engine->RegisterObjectMethod("FileSystem", "uint SystemRunAsync(const String&in, Array<String>@+)", asFUNCTION(FileSystemSystemRunAsync), asCALL_CDECL_OBJLAST);
@@ -341,6 +341,8 @@ void RegisterFileSystem(asIScriptEngine* engine)
     engine->RegisterObjectMethod("FileSystem", "bool Delete(const String&in)", asMETHOD(FileSystem, Delete), asCALL_THISCALL);
     engine->RegisterObjectMethod("FileSystem", "String get_currentDir() const", asMETHOD(FileSystem, GetCurrentDir), asCALL_THISCALL);
     engine->RegisterObjectMethod("FileSystem", "void set_currentDir(const String&in)", asMETHOD(FileSystem, SetCurrentDir), asCALL_THISCALL);
+    engine->RegisterObjectMethod("FileSystem", "void set_executeConsoleCommands(bool)", asMETHOD(FileSystem, SetExecuteConsoleCommands), asCALL_THISCALL);
+    engine->RegisterObjectMethod("FileSystem", "bool get_executeConsoleCommands() const", asMETHOD(FileSystem, GetExecuteConsoleCommands), asCALL_THISCALL);
     engine->RegisterObjectMethod("FileSystem", "String get_programDir() const", asMETHOD(FileSystem, GetProgramDir), asCALL_THISCALL);
     engine->RegisterObjectMethod("FileSystem", "String get_userDocumentsDir() const", asMETHOD(FileSystem, GetUserDocumentsDir), asCALL_THISCALL);
     engine->RegisterGlobalFunction("FileSystem@+ get_fileSystem()", asFUNCTION(GetFileSystem), asCALL_CDECL);

+ 2 - 2
Source/Engine/Script/Script.cpp

@@ -153,7 +153,7 @@ Script::Script(Context* context) :
     scriptEngine_(0),
     immediateContext_(0),
     scriptNestingLevel_(0),
-    executeConsoleCommands_(true)
+    executeConsoleCommands_(false)
 {
     scriptEngine_ = asCreateScriptEngine(ANGELSCRIPT_VERSION);
     if (!scriptEngine_)
@@ -199,7 +199,7 @@ Script::Script(Context* context) :
     RegisterEngineAPI(scriptEngine_);
 
     // Subscribe to console commands
-    SubscribeToEvent(E_CONSOLECOMMAND, HANDLER(Script, HandleConsoleCommand));
+    SetExecuteConsoleCommands(true);
 }
 
 Script::~Script()

+ 2 - 2
Source/Engine/Script/Script.h

@@ -67,7 +67,7 @@ public:
     void SetDefaultScriptFile(ScriptFile* file);
     /// Set immediate mode scene.
     void SetDefaultScene(Scene* scene);
-    /// Set whether to execute engine console commands as script code. Default true.
+    /// Set whether to execute engine console commands as script code.
     void SetExecuteConsoleCommands(bool enable);
     /// Print the whole script API (all registered classes, methods and properties) to the log. No-ops when URHO3D_LOGGING not defined.
     void DumpAPI(DumpMode mode= DOXYGEN);
@@ -121,7 +121,7 @@ private:
     HashMap<const char*, asIObjectType*> objectTypes_;
     /// Current script execution nesting level.
     unsigned scriptNestingLevel_;
-    /// Flag for executing engine console commands as script code.
+    /// Flag for executing engine console commands as script code. Default to true.
     bool executeConsoleCommands_;
 };
 

+ 4 - 2
Source/Samples/26_ConsoleInput/ConsoleInput.cpp

@@ -78,6 +78,8 @@ void ConsoleInput::Start()
     // subscriber for the console command event
     Console* console = GetSubsystem<Console>();
     console->SetNumRows(GetSubsystem<Graphics>()->GetHeight() / 16);
+    console->SetNumBufferedRows(2 * console->GetNumRows());
+    console->SetCommandInterpreter(GetTypeName());
     console->SetVisible(true);
     
     // Show OS mouse cursor
@@ -96,8 +98,8 @@ void ConsoleInput::Start()
 void ConsoleInput::HandleConsoleCommand(StringHash eventType, VariantMap& eventData)
 {
     using namespace ConsoleCommand;
-    
-    HandleInput(eventData[P_COMMAND].GetString());
+    if (eventData[P_ID].GetString() == GetTypeName())
+        HandleInput(eventData[P_COMMAND].GetString());
 }
 
 void ConsoleInput::HandleUpdate(StringHash eventType, VariantMap& eventData)