新增: 添加不同平台的通知显示函数

 新增: 实现 Windows、macOS 和 Linux 的通知显示
📝 修改: 调整命令历史记录相关注释
📝 修改: 增加工作目录管理逻辑
main
机械师 2025-09-12 17:50:53 +08:00
parent b8227c46d3
commit eb3a5aa939
4 changed files with 88 additions and 28 deletions

View File

@ -16,7 +16,7 @@ public:
void SaveSettings(); void SaveSettings();
void ApplySettings(); void ApplySettings();
// 新增:启动命令历史记录管理 // 启动命令历史记录管理
void AddCommandToHistory(const std::string& command); void AddCommandToHistory(const std::string& command);
void RemoveCommandFromHistory(int index); void RemoveCommandFromHistory(int index);
void ClearCommandHistory(); void ClearCommandHistory();
@ -27,6 +27,8 @@ public:
CLIProcess cli_process; CLIProcess cli_process;
char command_input[256]{}; char command_input[256]{};
char send_command[256]{}; char send_command[256]{};
char working_directory[256]{};
bool auto_working_dir;
bool auto_scroll_logs; bool auto_scroll_logs;
bool enable_colored_logs; bool enable_colored_logs;
int max_log_lines; int max_log_lines;

View File

@ -35,7 +35,13 @@ public:
// 设置回调函数 // 设置回调函数
void SetShowWindowCallback(const ShowWindowCallback &callback); void SetShowWindowCallback(const ShowWindowCallback &callback);
void SetExitCallback(const ExitCallback &callback); void SetExitCallback(const ExitCallback &callback);
#ifdef _WIN32
void ShowWindowsNotification(const std::wstring& title, const std::wstring& message);
#elif __APPLE__
void ShowMacNotification(const std::string& title, const std::string& message);
#else
void ShowLinuxNotification(const std::string& title, const std::string& message);
#endif
private: private:
void CreateMenu(); void CreateMenu();
void DestroyMenu(); void DestroyMenu();

View File

@ -7,6 +7,7 @@ AppState::AppState() :
show_main_window(true), show_main_window(true),
auto_start(false), auto_start(false),
auto_scroll_logs(true), auto_scroll_logs(true),
auto_working_dir(true),
enable_colored_logs(true), enable_colored_logs(true),
max_log_lines(1000), max_log_lines(1000),
stop_timeout_ms(5000), stop_timeout_ms(5000),
@ -77,7 +78,7 @@ std::string AppState::SerializeCommandHistory() const {
return oss.str(); return oss.str();
} }
// 新增:反序列化命令历史记录 // 反序列化命令历史记录
void AppState::DeserializeCommandHistory(const std::string& serialized) { void AppState::DeserializeCommandHistory(const std::string& serialized) {
command_history.clear(); command_history.clear();
if (serialized.empty()) return; if (serialized.empty()) return;
@ -185,6 +186,9 @@ void AppState::LoadSettings() {
if (key == "CommandInput") { if (key == "CommandInput") {
strncpy_s(command_input, value.c_str(), sizeof(command_input) - 1); strncpy_s(command_input, value.c_str(), sizeof(command_input) - 1);
} }
else if (key == "WorkingDirectory") {
strncpy_s(working_directory, value.c_str(), sizeof(working_directory) - 1);
}
else if (key == "MaxLogLines") { else if (key == "MaxLogLines") {
max_log_lines = std::stoi(value); max_log_lines = std::stoi(value);
max_log_lines = std::max(100, std::min(max_log_lines, 10000)); max_log_lines = std::max(100, std::min(max_log_lines, 10000));
@ -198,6 +202,9 @@ void AppState::LoadSettings() {
else if (key == "AutoStart") { else if (key == "AutoStart") {
auto_start = (value == "1"); auto_start = (value == "1");
} }
else if (key == "AutoWorkDirectory") {
auto_working_dir = (value == "1");
}
else if (key == "WebUrl") { else if (key == "WebUrl") {
strncpy_s(web_url, value.c_str(), sizeof(web_url) - 1); strncpy_s(web_url, value.c_str(), sizeof(web_url) - 1);
} }
@ -240,10 +247,12 @@ void AppState::SaveSettings() {
file << "[Settings]\n"; file << "[Settings]\n";
file << "CommandInput=" << command_input << "\n"; file << "CommandInput=" << command_input << "\n";
file << "WorkingDirectory=" << working_directory << "\n";
file << "MaxLogLines=" << max_log_lines << "\n"; file << "MaxLogLines=" << max_log_lines << "\n";
file << "AutoScrollLogs=" << (auto_scroll_logs ? "1" : "0") << "\n"; file << "AutoScrollLogs=" << (auto_scroll_logs ? "1" : "0") << "\n";
file << "EnableColoredLogs=" << (enable_colored_logs ? "1" : "0") << "\n"; file << "EnableColoredLogs=" << (enable_colored_logs ? "1" : "0") << "\n";
file << "AutoStart=" << (auto_start ? "1" : "0") << "\n"; file << "AutoStart=" << (auto_start ? "1" : "0") << "\n";
file << "AutoWorkDirectory=" << (auto_working_dir ? "1" : "0") << "\n";
file << "WebUrl=" << web_url << "\n"; file << "WebUrl=" << web_url << "\n";
// 停止命令相关配置的保存 // 停止命令相关配置的保存
@ -284,6 +293,11 @@ void AppState::ApplySettings() {
cli_process.SetEnvironmentVariables({}); cli_process.SetEnvironmentVariables({});
} }
// 新增:应用输出编码设置 if (strlen(working_directory)>0) {
cli_process.SetWorkingDirectory(working_directory);
}
cli_process.SetAutoWorkingDir(auto_working_dir);
// 应用输出编码设置
cli_process.SetOutputEncoding(output_encoding); cli_process.SetOutputEncoding(output_encoding);
} }

View File

@ -4,7 +4,6 @@
#ifdef _WIN32 #ifdef _WIN32
TrayIcon::TrayIcon(HWND hwnd, HICON icon) TrayIcon::TrayIcon(HWND hwnd, HICON icon)
: m_hwnd(hwnd), m_icon(icon), m_visible(false), m_menu(nullptr) { : m_hwnd(hwnd), m_icon(icon), m_visible(false), m_menu(nullptr) {
ZeroMemory(&m_nid, sizeof(m_nid)); ZeroMemory(&m_nid, sizeof(m_nid));
m_nid.cbSize = sizeof(m_nid); m_nid.cbSize = sizeof(m_nid);
m_nid.hWnd = m_hwnd; m_nid.hWnd = m_hwnd;
@ -53,14 +52,15 @@ void TrayIcon::Hide() {
} }
#ifdef _WIN32 #ifdef _WIN32
void TrayIcon::UpdateWebUrl(const std::wstring& url) { void TrayIcon::UpdateWebUrl(const std::wstring &url) {
m_web_url = url; m_web_url = url;
// 重新创建菜单以更新Web URL显示 // 重新创建菜单以更新Web URL显示
DestroyMenu(); DestroyMenu();
CreateMenu(); CreateMenu();
} }
#else #else
void TrayIcon::UpdateWebUrl(const std::string& url) { void TrayIcon::UpdateWebUrl(const std::string &url)
{
m_web_url = url; m_web_url = url;
// 重新创建菜单以更新Web URL显示 // 重新创建菜单以更新Web URL显示
DestroyMenu(); DestroyMenu();
@ -76,6 +76,32 @@ void TrayIcon::SetExitCallback(const ExitCallback &callback) {
m_exit_callback = callback; m_exit_callback = callback;
} }
#ifdef _WIN32
void TrayIcon::ShowWindowsNotification(const std::wstring &title, const std::wstring &message) {
NOTIFYICONDATA nid = m_nid;
nid.uFlags |= NIF_INFO;
wcsncpy_s(nid.szInfoTitle, title.c_str(), _TRUNCATE);
wcsncpy_s(nid.szInfo, message.c_str(), _TRUNCATE);
nid.dwInfoFlags = NIIF_INFO; // 信息图标,可选 NIIF_WARNING, NIIF_ERROR
Shell_NotifyIcon(NIM_MODIFY, &nid);
}
#elif __APPLE__
void TrayIcon::ShowMacNotification(const std::string &title, const std::string &message)
{
// 通过 AppleScript 或 Objective-C 桥接
std::string script = "display notification \"" + message + "\" with title \"" + title + "\"";
std::string cmd = "osascript -e '" + script + "'";
system(cmd.c_str());
}
#else
void TrayIcon::ShowLinuxNotification(const std::string &title, const std::string &message)
{
// 使用 notify-send 命令
std::string cmd = "notify-send \"" + title + "\" \"" + message + "\"";
system(cmd.c_str());
}
#endif
void TrayIcon::CreateMenu() { void TrayIcon::CreateMenu() {
#ifdef _WIN32 #ifdef _WIN32
if (m_menu) { if (m_menu) {
@ -174,47 +200,56 @@ LRESULT CALLBACK TrayIcon::WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM
void TrayIcon::UpdateStatus(const std::wstring &status, const std::wstring &pid) { void TrayIcon::UpdateStatus(const std::wstring &status, const std::wstring &pid) {
m_status = status; m_status = status;
m_pid = pid; m_pid = pid;
// 重新创建菜单以更新Status显示 // 重新创建菜单以更新Status显示
DestroyMenu(); DestroyMenu();
CreateMenu(); CreateMenu();
} }
#else #else
// macOS 特定实现 // macOS 特定实现
void TrayIcon::ShowMacTrayIcon() { void TrayIcon::ShowMacTrayIcon()
{
// 通过 Objective-C 接口显示托盘图标 // 通过 Objective-C 接口显示托盘图标
ShowMacTrayIconImpl(m_app_delegate, m_icon); ShowMacTrayIconImpl(m_app_delegate, m_icon);
} }
void TrayIcon::HideMacTrayIcon() { void TrayIcon::HideMacTrayIcon()
{
// 通过 Objective-C 接口隐藏托盘图标 // 通过 Objective-C 接口隐藏托盘图标
HideMacTrayIconImpl(m_app_delegate); HideMacTrayIconImpl(m_app_delegate);
} }
void TrayIcon::CreateMacMenu() { void TrayIcon::CreateMacMenu()
{
// 通过 Objective-C 接口创建菜单 // 通过 Objective-C 接口创建菜单
CreateMacMenuImpl(m_app_delegate, m_web_url.c_str()); CreateMacMenuImpl(m_app_delegate, m_web_url.c_str());
} }
void TrayIcon::DestroyMacMenu() { void TrayIcon::DestroyMacMenu()
{
// 通过 Objective-C 接口销毁菜单 // 通过 Objective-C 接口销毁菜单
DestroyMacMenuImpl(m_app_delegate); DestroyMacMenuImpl(m_app_delegate);
} }
void TrayIcon::OnMacMenuAction(int action) { void TrayIcon::OnMacMenuAction(int action)
switch (action) { {
switch (action)
{
case 1001: // 显示主窗口 case 1001: // 显示主窗口
if (m_show_window_callback) { if (m_show_window_callback)
{
m_show_window_callback(); m_show_window_callback();
} }
break; break;
case 1002: // 打开Web页面 case 1002: // 打开Web页面
if (!m_web_url.empty()) { if (!m_web_url.empty())
{
OpenWebPageMac(m_web_url.c_str()); OpenWebPageMac(m_web_url.c_str());
} }
break; break;
case 1003: // 退出 case 1003: // 退出
if (m_exit_callback) { if (m_exit_callback)
{
m_exit_callback(); m_exit_callback();
} }
break; break;
@ -222,18 +257,21 @@ void TrayIcon::OnMacMenuAction(int action) {
} }
// C 接口函数,供 Objective-C 调用 // C 接口函数,供 Objective-C 调用
extern "C" void TrayIconMenuCallback(void* tray_instance, int action) { extern "C" void TrayIconMenuCallback(void *tray_instance, int action)
if (tray_instance) { {
static_cast<TrayIcon*>(tray_instance)->OnMacMenuAction(action); if (tray_instance)
{
static_cast<TrayIcon *>(tray_instance)->OnMacMenuAction(action);
} }
} }
// 外部声明的 Objective-C 接口函数 // 外部声明的 Objective-C 接口函数
extern "C" { extern "C"
void ShowMacTrayIconImpl(void* app_delegate, void* icon); {
void HideMacTrayIconImpl(void* app_delegate); void ShowMacTrayIconImpl(void *app_delegate, void *icon);
void CreateMacMenuImpl(void* app_delegate, const char* web_url); void HideMacTrayIconImpl(void *app_delegate);
void DestroyMacMenuImpl(void* app_delegate); void CreateMacMenuImpl(void *app_delegate, const char *web_url);
void OpenWebPageMac(const char* url); void DestroyMacMenuImpl(void *app_delegate);
void OpenWebPageMac(const char *url);
} }
#endif #endif