feat: Added command line interface support (#1172)

System design has been discussed on discord

Should fix #948

---------

Co-authored-by: WerWolv <werwolv98@gmail.com>
This commit is contained in:
iTrooz
2023-07-13 14:08:23 +02:00
committed by GitHub
parent 8c0395bc7c
commit 1ed658bcdc
21 changed files with 636 additions and 143 deletions

View File

@@ -232,4 +232,10 @@ namespace hex {
EVENT_DEF(RequestOpenInfoPopup, const std::string);
EVENT_DEF(RequestOpenErrorPopup, const std::string);
EVENT_DEF(RequestOpenFatalPopup, const std::string);
/**
* @brief Send an event to the main Imhex instance
*/
EVENT_DEF(SendMessageToMainInstance, const std::string, const std::vector<u8>&);
}

View File

@@ -322,7 +322,10 @@ namespace hex {
/* Functions to interact with various ImHex system settings */
namespace System {
bool isMainInstance();
namespace impl {
void setMainInstanceStatus(bool status);
void setMainWindowPosition(i32 x, i32 y);
void setMainWindowSize(u32 width, u32 height);
@@ -331,8 +334,6 @@ namespace hex {
void setGlobalScale(float scale);
void setNativeScale(float scale);
void setProgramArguments(int argc, char **argv, char **envp);
void setBorderlessWindowMode(bool enabled);
void setCustomFontPath(const std::fs::path &path);
@@ -383,20 +384,6 @@ namespace hex {
void setTaskBarProgress(TaskProgressState state, TaskProgressType type, u32 progress);
/**
* @brief Gets the current program arguments
* @return The current program arguments
*/
const ProgramArguments &getProgramArguments();
/**
* @brief Gets a program argument
* @param index The index of the argument to get
* @return The argument at the given index
*/
std::optional<std::u8string> getProgramArgument(int index);
/**
* @brief Gets the current target FPS
* @return The current target FPS
@@ -545,6 +532,26 @@ namespace hex {
std::string getCommitBranch();
}
/**
* @brief Cross-instance messaging system
* This allows you to send messages to the "main" instance of ImHex running, from any other instance
*/
namespace Messaging {
namespace impl {
using MessagingHandler = std::function<void(const std::vector<u8> &)>;
std::map<std::string, MessagingHandler> &getHandlers();
void runHandler(const std::string &eventName, const std::vector<u8> &args);
}
/**
* @brief Register the handler for this specific event name
*/
void registerHandler(const std::string &eventName, const impl::MessagingHandler &handler);
}
}
}

View File

@@ -5,6 +5,7 @@
#include <hex/helpers/fmt.hpp>
#include <hex/helpers/fs.hpp>
#include <span>
#include <string>
#if defined(OS_WINDOWS)
@@ -17,6 +18,17 @@ struct ImGuiContext;
namespace hex {
struct SubCommand {
std::string commandKey;
std::string commandDesc;
std::function<void(const std::vector<std::string>&)> callback;
};
struct SubCommandList {
hex::SubCommand *subCommands;
size_t size;
};
class Plugin {
public:
explicit Plugin(const std::fs::path &path);
@@ -36,6 +48,8 @@ namespace hex {
[[nodiscard]] bool isLoaded() const;
[[nodiscard]] std::span<SubCommand> getSubCommands() const;
private:
using InitializePluginFunc = void (*)();
using GetPluginNameFunc = const char *(*)();
@@ -44,6 +58,7 @@ namespace hex {
using GetCompatibleVersionFunc = const char *(*)();
using SetImGuiContextFunc = void (*)(ImGuiContext *);
using IsBuiltinPluginFunc = bool (*)();
using GetSubCommandsFunc = SubCommandList* (*)();
#if defined(OS_WINDOWS)
HMODULE m_handle = nullptr;
@@ -61,6 +76,7 @@ namespace hex {
GetCompatibleVersionFunc m_getCompatibleVersionFunction = nullptr;
SetImGuiContextFunc m_setImGuiContextFunction = nullptr;
IsBuiltinPluginFunc m_isBuiltinPluginFunction = nullptr;
GetSubCommandsFunc m_getSubCommandsFunction = nullptr;
template<typename T>
[[nodiscard]] auto getPluginFunction(const std::string &symbol) {

View File

@@ -1,9 +1,14 @@
#pragma once
#include <string>
#include <imgui.h>
#include <imgui_internal.h>
#include <hex.hpp>
#include <hex/api/plugin_manager.hpp>
#include <wolv/utils/string.hpp>
/**
* This macro is used to define all the required entry points for a plugin.
@@ -21,3 +26,23 @@
GImGui = ctx; \
} \
extern "C" [[gnu::visibility("default")]] void initializePlugin()
/**
* This macro is used to define subcommands defined by the plugin
* A subcommand consists of a key, a description, and a callback
* The key is what the first argument to ImHex should be, prefixed by `--`
* For example, if the key if `help`, ImHex should be started with `--help` as its first argument to trigger the subcommand
* when the subcommand is triggerred, it's callback will be executed. The callback is executed BEFORE most of ImHex initialization
* so to do anything meaningful, you should subscribe to an event (like EventImHexStartupFinished) and run your code there.
*/
#define IMHEX_PLUGIN_SUBCOMMANDS() IMHEX_PLUGIN_SUBCOMMANDS_IMPL()
#define IMHEX_PLUGIN_SUBCOMMANDS_IMPL() \
extern std::vector<hex::SubCommand> g_subCommands; \
extern "C" [[gnu::visibility("default")]] hex::SubCommandList getSubCommands() { \
return hex::SubCommandList { \
g_subCommands.data(), \
g_subCommands.size() \
}; \
} \
std::vector<hex::SubCommand> g_subCommands

View File

@@ -0,0 +1,30 @@
#pragma once
#include<vector>
#include<string>
#include<functional>
namespace hex::subcommands {
/**
* @brief Internal method - takes all the arguments ImHex received from the command line,
* and determine which subcommands to run, with which arguments.
* In some cases, the subcommand or this function directly might exit the program
* (e.g. --help, or when forwarding providers to open to another instance)
* and so this function might not return
*/
void processArguments(const std::vector<std::string> &args);
/**
* @brief Forward the given command to the main instance (might be this instance)
* The callback will be executed after EventImHexStartupFinished
*/
void forwardSubCommand(const std::string &cmdName, const std::vector<std::string> &args);
using ForwardCommandHandler = std::function<void(const std::vector<std::string> &)>;
/**
* @brief Register the handler for this specific command name
*/
void registerSubCommand(const std::string &cmdName, const ForwardCommandHandler &handler);
}