diff --git a/TrafficMonitor/CommonData.h b/TrafficMonitor/CommonData.h index 5d6f6b322..704423d11 100644 --- a/TrafficMonitor/CommonData.h +++ b/TrafficMonitor/CommonData.h @@ -397,7 +397,12 @@ struct GeneralSettingData hardware_monitor_item &= ~item_type; } - StringSet connections_hide; //用于保存哪些网络要从“选择网络连接”子菜单项中隐藏 + StringSet connections_hide; //用于保存哪些网络要从”选择网络连接”子菜单项中隐藏 + + // Global hotkey + bool hotkey_enabled{ true }; // 全局热键功能开关 + UINT hotkey_modifiers{ MOD_CONTROL | MOD_SHIFT }; // 热键修饰键(MOD_ALT | MOD_CONTROL | MOD_SHIFT | MOD_WIN) + UINT hotkey_vk{ VK_F11 }; // 热键虚拟键码 }; //定义监控时间间隔有效的最大值和最小值 diff --git a/TrafficMonitor/GeneralSettingsDlg.cpp b/TrafficMonitor/GeneralSettingsDlg.cpp index 00bc373e4..c9085a7a4 100644 --- a/TrafficMonitor/GeneralSettingsDlg.cpp +++ b/TrafficMonitor/GeneralSettingsDlg.cpp @@ -195,6 +195,7 @@ void CGeneralSettingsDlg::DoDataExchange(CDataExchange* pDX) DDX_Control(pDX, IDC_SELECT_CPU_COMBO, m_select_cpu_combo); DDX_Control(pDX, IDC_PLUGIN_MANAGE_BUTTON, m_plugin_manager_btn); DDX_Control(pDX, IDC_SELECT_CONNECTIONS_BUTTON, m_select_connection_btn); + DDX_Control(pDX, IDC_HOTKEY_BUTTON, m_hotkey_button); } void CGeneralSettingsDlg::SetControlEnable() @@ -215,6 +216,7 @@ void CGeneralSettingsDlg::SetControlEnable() EnableDlgCtrl(IDC_RESET_AUTO_RUN_BUTTON, m_data.auto_run); EnableDlgCtrl(IDC_AUTO_RUN_METHOD_REGESTRY_RADIO, m_data.auto_run); EnableDlgCtrl(IDC_AUTO_RUN_METHOD_TASK_SCHEDULE_RADIO, m_data.auto_run); + m_hotkey_button.EnableWindow(m_data.hotkey_enabled); } @@ -248,6 +250,8 @@ BEGIN_MESSAGE_MAP(CGeneralSettingsDlg, CTabDlg) ON_MESSAGE(WM_SPIN_EDIT_POS_CHANGED, &CGeneralSettingsDlg::OnSpinEditPosChanged) ON_BN_CLICKED(IDC_AUTO_RUN_METHOD_REGESTRY_RADIO, &CGeneralSettingsDlg::OnBnClickedAutoRunMethodRegestryRadio) ON_BN_CLICKED(IDC_AUTO_RUN_METHOD_TASK_SCHEDULE_RADIO, &CGeneralSettingsDlg::OnBnClickedAutoRunMethodTaskScheduleRadio) + ON_BN_CLICKED(IDC_HOTKEY_ENABLE_CHECK, &CGeneralSettingsDlg::OnBnClickedHotkeyEnableCheck) + ON_BN_CLICKED(IDC_HOTKEY_BUTTON, &CGeneralSettingsDlg::OnBnClickedHotkeyButton) END_MESSAGE_MAP() @@ -442,6 +446,11 @@ BOOL CGeneralSettingsDlg::OnInitDialog() m_plugin_manager_btn.SetIcon(theApp.GetMenuIcon(IDI_PLUGINS)); m_select_connection_btn.SetIcon(theApp.GetMenuIcon(IDI_CONNECTION)); + //初始化热键控件 + CheckDlgButton(IDC_HOTKEY_ENABLE_CHECK, m_data.hotkey_enabled); + SetHotKeyButtonText(); + m_hotkey_button.EnableWindow(m_data.hotkey_enabled); + return TRUE; // return TRUE unless you set the focus to a control // 异常: OCX 属性页应返回 FALSE } @@ -567,13 +576,121 @@ void CGeneralSettingsDlg::OnBnClickedShowAllConnectionCheck() BOOL CGeneralSettingsDlg::PreTranslateMessage(MSG* pMsg) { - // TODO: 在此添加专用代码和/或调用基类 + // 热键捕获模式 + if (m_hotkey_capturing) + { + if (pMsg->message == WM_KEYDOWN || pMsg->message == WM_SYSKEYDOWN) + { + UINT vk = static_cast(pMsg->wParam); + + // ESC 取消捕获 + if (vk == VK_ESCAPE) + { + EndHotKeyCapture(true); + return TRUE; + } + + // 过滤纯修饰键 + if (vk != VK_CONTROL && vk != VK_MENU && vk != VK_SHIFT && + vk != VK_LWIN && vk != VK_RWIN && + vk != VK_LCONTROL && vk != VK_RCONTROL && + vk != VK_LMENU && vk != VK_RMENU && + vk != VK_LSHIFT && vk != VK_RSHIFT) + { + // 获取当前修饰键状态 + UINT modifiers = 0; + if (GetKeyState(VK_CONTROL) & 0x8000) modifiers |= MOD_CONTROL; + if (GetKeyState(VK_MENU) & 0x8000) modifiers |= MOD_ALT; + if (GetKeyState(VK_SHIFT) & 0x8000) modifiers |= MOD_SHIFT; + if (GetKeyState(VK_LWIN) & 0x8000 || GetKeyState(VK_RWIN) & 0x8000) + modifiers |= MOD_WIN; + + if (modifiers != 0) + { + OnHotKeyCaptured(modifiers, vk); + return TRUE; + } + } + return TRUE; // 捕获期间拦截所有按键 + } + // 点击按钮外区域取消捕获 + if (pMsg->message == WM_LBUTTONDOWN || pMsg->message == WM_RBUTTONDOWN) + { + HWND hwndButton = m_hotkey_button.GetSafeHwnd(); + if (pMsg->hwnd != hwndButton) + { + EndHotKeyCapture(true); + } + } + } + if (pMsg->message == WM_MOUSEMOVE) m_toolTip.RelayEvent(pMsg); return CTabDlg::PreTranslateMessage(pMsg); } +void CGeneralSettingsDlg::SetHotKeyButtonText() +{ + CString text; + + if (m_data.hotkey_modifiers & MOD_CONTROL) text += _T("Ctrl+"); + if (m_data.hotkey_modifiers & MOD_ALT) text += _T("Alt+"); + if (m_data.hotkey_modifiers & MOD_SHIFT) text += _T("Shift+"); + if (m_data.hotkey_modifiers & MOD_WIN) text += _T("Win+"); + + // 使用 MapVirtualKey + GetKeyNameText 获取按键名称 + UINT scan_code = MapVirtualKeyW(m_data.hotkey_vk, MAPVK_VK_TO_VSC); + if (m_data.hotkey_vk == VK_INSERT || m_data.hotkey_vk == VK_DELETE || + m_data.hotkey_vk == VK_HOME || m_data.hotkey_vk == VK_END || + m_data.hotkey_vk == VK_PRIOR || m_data.hotkey_vk == VK_NEXT || + m_data.hotkey_vk == VK_LEFT || m_data.hotkey_vk == VK_RIGHT || + m_data.hotkey_vk == VK_UP || m_data.hotkey_vk == VK_DOWN) + { + scan_code |= 0x100; // 扩展键标志 + } + wchar_t key_name_buf[64]{}; + GetKeyNameTextW(scan_code << 16, key_name_buf, 64); + + text += key_name_buf; + m_hotkey_button.SetWindowText(text); +} + +void CGeneralSettingsDlg::StartHotKeyCapture() +{ + m_hotkey_capturing = true; + m_hotkey_button.GetWindowText(m_hotkey_original_text); + m_hotkey_button.SetWindowText(CCommon::LoadText(IDS_PRESS_HOTKEY, _T("Press a key combination..."))); + m_hotkey_button.SetFocus(); +} + +void CGeneralSettingsDlg::EndHotKeyCapture(bool cancelled) +{ + m_hotkey_capturing = false; + if (cancelled) + m_hotkey_button.SetWindowText(m_hotkey_original_text); + else + SetHotKeyButtonText(); +} + +void CGeneralSettingsDlg::OnHotKeyCaptured(UINT modifiers, UINT vk) +{ + m_data.hotkey_modifiers = modifiers; + m_data.hotkey_vk = vk; + EndHotKeyCapture(false); +} + +void CGeneralSettingsDlg::OnBnClickedHotkeyButton() +{ + StartHotKeyCapture(); +} + +void CGeneralSettingsDlg::OnBnClickedHotkeyEnableCheck() +{ + m_data.hotkey_enabled = (IsDlgButtonChecked(IDC_HOTKEY_ENABLE_CHECK) != 0); + SetControlEnable(); +} + afx_msg LRESULT CGeneralSettingsDlg::OnSpinEditPosChanged(WPARAM wParam, LPARAM lParam) { CSpinButtonCtrl* pSpin = (CSpinButtonCtrl*)wParam; diff --git a/TrafficMonitor/GeneralSettingsDlg.h b/TrafficMonitor/GeneralSettingsDlg.h index acec0447b..faaad4c4c 100644 --- a/TrafficMonitor/GeneralSettingsDlg.h +++ b/TrafficMonitor/GeneralSettingsDlg.h @@ -13,6 +13,11 @@ class CGeneralSettingsDlg : public CTabDlg CGeneralSettingsDlg(CWnd* pParent = NULL); // standard constructor virtual ~CGeneralSettingsDlg(); + void SetHotKeyButtonText(); + void StartHotKeyCapture(); + void EndHotKeyCapture(bool cancelled); + void OnHotKeyCaptured(UINT modifiers, UINT vk); + static void CheckTaskbarDisplayItem(); //选项设置数据 @@ -52,6 +57,9 @@ class CGeneralSettingsDlg : public CTabDlg CComboBox2 m_select_cpu_combo; CButton m_plugin_manager_btn; CButton m_select_connection_btn; + CButton m_hotkey_button; + bool m_hotkey_capturing{ false }; + CString m_hotkey_original_text; virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support @@ -102,6 +110,8 @@ class CGeneralSettingsDlg : public CTabDlg afx_msg void OnBnClickedSelectConnectionsButton(); afx_msg void OnBnClickedResetAutoRunButton(); afx_msg void OnEnChangeMonitorSpanEdit(); + afx_msg void OnBnClickedHotkeyEnableCheck(); + afx_msg void OnBnClickedHotkeyButton(); protected: public: afx_msg void OnBnClickedAutoRunMethodRegestryRadio(); diff --git a/TrafficMonitor/SkinFile.cpp b/TrafficMonitor/SkinFile.cpp index c888d54ae..ae98d628b 100644 --- a/TrafficMonitor/SkinFile.cpp +++ b/TrafficMonitor/SkinFile.cpp @@ -16,8 +16,12 @@ CSkinFile::CSkinFile() CSkinFile::~CSkinFile() { - SAFE_DELETE(m_background_png_s); - SAFE_DELETE(m_background_png_l); + for (auto* img : m_background_png_s) + SAFE_DELETE(img); + m_background_png_s.clear(); + for (auto* img : m_background_png_l) + SAFE_DELETE(img); + m_background_png_l.clear(); } static CSkinFile::LayoutItem LayoutItemFromXmlNode(tinyxml2::XMLElement* ele) @@ -127,21 +131,60 @@ bool CSkinFile::Load(const wstring& skin_name) wstring path_dir = file_path_helper.GetDir(); - //载入png背景图 + //载入png背景图(支持多帧动画) m_is_png = true; - //先尝试加载png格式,失败则加载bmp格式 - SAFE_DELETE(m_background_png_s); - m_background_png_s = new Gdiplus::Image((path_dir + BACKGROUND_IMAGE_S_PNG).c_str()); - if (m_background_png_s->GetLastStatus() != Gdiplus::Ok) + //先清理旧帧 + for (auto* img : m_background_png_s) + SAFE_DELETE(img); + m_background_png_s.clear(); + for (auto* img : m_background_png_l) + SAFE_DELETE(img); + m_background_png_l.clear(); + m_animation_start_time = GetTickCount64(); + + // 辅助lambda:尝试加载多帧PNG(background_0.png, background_1.png, ...) + // 若background_0.png不存在则回退到background.png单帧 + auto LoadMultiFramePng = [&](const wstring& base_name, std::vector& out_frames) -> bool { + // 先尝试多帧格式 background_0.png + wstring frame0_path = path_dir + base_name + L"_0.png"; + if (CCommon::FileExist(frame0_path.c_str())) + { + for (int i = 0; ; i++) + { + wstring frame_path = path_dir + base_name + L"_" + std::to_wstring(i) + L".png"; + if (!CCommon::FileExist(frame_path.c_str())) + break; + auto* img = new Gdiplus::Image(frame_path.c_str()); + if (img->GetLastStatus() == Gdiplus::Ok) + out_frames.push_back(img); + else + { + delete img; + break; + } + } + return !out_frames.empty(); + } + // 回退到单帧 background.png + wstring single_path = path_dir + base_name + L".png"; + if (CCommon::FileExist(single_path.c_str())) + { + auto* img = new Gdiplus::Image(single_path.c_str()); + if (img->GetLastStatus() == Gdiplus::Ok) + { + out_frames.push_back(img); + return true; + } + delete img; + } + return false; + }; + + if (!LoadMultiFramePng(L"background", m_background_png_s)) m_is_png = false; - } - SAFE_DELETE(m_background_png_l); - m_background_png_l = new Gdiplus::Image((path_dir + BACKGROUND_IMAGE_L_PNG).c_str()); - if (m_background_png_l->GetLastStatus() != Gdiplus::Ok) - { + if (!LoadMultiFramePng(L"background_l", m_background_png_l)) m_is_png = false; - } //png背景图加载失败,使用bmp背景图 if (!m_is_png) @@ -398,6 +441,23 @@ void CSkinFile::SetAlpha(int alpha) m_alpha = alpha; } +Gdiplus::Image* CSkinFile::GetCurrentBackgroundFrame(bool show_more_info) +{ + auto& frames = show_more_info ? m_background_png_l : m_background_png_s; + if (frames.empty()) + return nullptr; + if (frames.size() == 1) + return frames.front(); + + // 基于时间戳选择帧,帧率 10fps,独立于数据刷新率 + ULONGLONG now = GetTickCount64(); + if (m_animation_start_time == 0) + m_animation_start_time = now; + ULONGLONG elapsed = now - m_animation_start_time; + size_t frame_idx = static_cast(elapsed / 33) % frames.size(); + return frames[frame_idx]; +} + void CSkinFile::SetSettingData(const SkinSettingData& setting_data) { //如果字体有变化,则重新创建字体 @@ -429,8 +489,10 @@ void CSkinFile::DrawPreview(CDC* pDC, CRect rect) if (IsPNG()) //png背景使用GDI+绘制 { CDrawCommonEx gdiplus_drawer(pDC); - gdiplus_drawer.DrawImage(m_background_png_s, rect_s.TopLeft(), rect_s.Size(), IDrawCommon::StretchMode::STRETCH); - gdiplus_drawer.DrawImage(m_background_png_l, rect_l.TopLeft(), rect_l.Size(), IDrawCommon::StretchMode::STRETCH); + Gdiplus::Image* preview_s = m_background_png_s.empty() ? nullptr : m_background_png_s.front(); + Gdiplus::Image* preview_l = m_background_png_l.empty() ? nullptr : m_background_png_l.front(); + if (preview_s) gdiplus_drawer.DrawImage(preview_s, rect_s.TopLeft(), rect_s.Size(), IDrawCommon::StretchMode::STRETCH); + if (preview_l) gdiplus_drawer.DrawImage(preview_l, rect_l.TopLeft(), rect_l.Size(), IDrawCommon::StretchMode::STRETCH); } else { @@ -576,8 +638,9 @@ void CSkinFile::DrawInfo(CDC* pDC, bool show_more_info) //绘制背景 CDrawCommonEx gdiplus_drawer; gdiplus_drawer.Create(CDC::FromHandle(hdcMemory)); - Gdiplus::Image* background_image{ show_more_info ? m_background_png_l : m_background_png_s }; - gdiplus_drawer.DrawImage(background_image, CPoint(0, 0), rect.Size(), CDrawCommon::StretchMode::FILL); + Gdiplus::Image* background_image{ GetCurrentBackgroundFrame(show_more_info) }; + if (background_image) + gdiplus_drawer.DrawImage(background_image, CPoint(0, 0), rect.Size(), CDrawCommon::StretchMode::FILL); //保存完全透明的像素点 std::set alpha_points; diff --git a/TrafficMonitor/SkinFile.h b/TrafficMonitor/SkinFile.h index 903b29a6f..da0feb399 100644 --- a/TrafficMonitor/SkinFile.h +++ b/TrafficMonitor/SkinFile.h @@ -138,6 +138,9 @@ class CSkinFile static void DrawSkinText(IDrawCommon& drawer, DrawStr draw_str, CRect rect, COLORREF color, Alignment align); + // 获取当前应显示的背景帧(按帧序列循环) + Gdiplus::Image* GetCurrentBackgroundFrame(bool show_more_info); + //绘制主界面中除背景图外所有显示项目 void DrawItemsInfo(IDrawCommon& drawer, Layout& layout, CFont& font) const; @@ -151,8 +154,9 @@ class CSkinFile CImage m_background_s; CImage m_background_l; bool m_is_png{}; - Gdiplus::Image* m_background_png_s{}; - Gdiplus::Image* m_background_png_l{}; + std::vector m_background_png_s; // 小布局背景帧(至少1帧) + std::vector m_background_png_l; // 大布局背景帧(至少1帧) + ULONGLONG m_animation_start_time{}; // 动画起始时间戳 int m_alpha{ 255 }; //不透明度,仅当背景为png时有效 SkinSettingData m_setting_data; bool m_is_error{ false }; diff --git a/TrafficMonitor/TrafficMonitor.cpp b/TrafficMonitor/TrafficMonitor.cpp index 17b32cb5e..d8a2f54c4 100644 --- a/TrafficMonitor/TrafficMonitor.cpp +++ b/TrafficMonitor/TrafficMonitor.cpp @@ -83,6 +83,11 @@ void CTrafficMonitorApp::LoadConfig() ini.GetStringList(L"general", L"connections_hide", connections_hide, std::vector{}); m_general_data.connections_hide.FromVector(connections_hide); + //Global hotkey + m_general_data.hotkey_enabled = ini.GetBool(L"general", L"hotkey_enabled", true); + m_general_data.hotkey_modifiers = static_cast(ini.GetInt(L"general", L"hotkey_modifiers", MOD_CONTROL | MOD_SHIFT)); + m_general_data.hotkey_vk = static_cast(ini.GetInt(L"general", L"hotkey_vk", VK_F11)); + //Windows10颜色模式设置 bool is_windows10_light_theme = CWindowsSettingHelper::IsWindows10LightTheme(); if (is_windows10_light_theme) @@ -303,6 +308,11 @@ void CTrafficMonitorApp::SaveConfig() ini.WriteInt(L"general", L"hardware_monitor_item", m_general_data.hardware_monitor_item); ini.WriteStringList(L"general", L"connections_hide", m_general_data.connections_hide.ToVector()); + //Global hotkey + ini.WriteBool(L"general", L"hotkey_enabled", m_general_data.hotkey_enabled); + ini.WriteInt(L"general", L"hotkey_modifiers", static_cast(m_general_data.hotkey_modifiers)); + ini.WriteInt(L"general", L"hotkey_vk", static_cast(m_general_data.hotkey_vk)); + //主窗口设置 ini.WriteInt(L"config", L"transparency", m_cfg_data.m_transparency); ini.WriteBool(L"config", L"always_on_top", m_main_wnd_data.m_always_on_top); diff --git a/TrafficMonitor/TrafficMonitor.rc b/TrafficMonitor/TrafficMonitor.rc index d47601cd6..456560456 100644 Binary files a/TrafficMonitor/TrafficMonitor.rc and b/TrafficMonitor/TrafficMonitor.rc differ diff --git a/TrafficMonitor/TrafficMonitor.vcxproj b/TrafficMonitor/TrafficMonitor.vcxproj index 8af662c88..9f4321451 100644 --- a/TrafficMonitor/TrafficMonitor.vcxproj +++ b/TrafficMonitor/TrafficMonitor.vcxproj @@ -301,7 +301,7 @@ $(IntDir);%(AdditionalIncludeDirectories) - print_compile_time.bat + call "$(ProjectDir)print_compile_time.bat" $(UM_IncludePath);%(AdditionalIncludeDirectories) @@ -340,7 +340,7 @@ $(IntDir);%(AdditionalIncludeDirectories) - print_compile_time.bat + call "$(ProjectDir)print_compile_time.bat" $(UM_IncludePath);%(AdditionalIncludeDirectories) @@ -379,7 +379,7 @@ $(IntDir);%(AdditionalIncludeDirectories) - print_compile_time.bat + call "$(ProjectDir)print_compile_time.bat" $(UM_IncludePath);%(AdditionalIncludeDirectories) @@ -418,7 +418,7 @@ $(IntDir);%(AdditionalIncludeDirectories) - print_compile_time.bat + call "$(ProjectDir)print_compile_time.bat" $(UM_IncludePath);%(AdditionalIncludeDirectories) @@ -456,7 +456,7 @@ $(IntDir);%(AdditionalIncludeDirectories) - print_compile_time.bat + call "$(ProjectDir)print_compile_time.bat" $(UM_IncludePath);%(AdditionalIncludeDirectories) @@ -494,7 +494,7 @@ $(IntDir);%(AdditionalIncludeDirectories) - print_compile_time.bat + call "$(ProjectDir)print_compile_time.bat" $(UM_IncludePath);%(AdditionalIncludeDirectories) @@ -538,7 +538,7 @@ $(IntDir);%(AdditionalIncludeDirectories) - print_compile_time.bat + call "$(ProjectDir)print_compile_time.bat" $(UM_IncludePath);%(AdditionalIncludeDirectories) @@ -581,7 +581,7 @@ $(IntDir);%(AdditionalIncludeDirectories) - print_compile_time.bat + call "$(ProjectDir)print_compile_time.bat" $(UM_IncludePath);%(AdditionalIncludeDirectories) @@ -624,7 +624,7 @@ $(IntDir);%(AdditionalIncludeDirectories) - print_compile_time.bat + call "$(ProjectDir)print_compile_time.bat" $(UM_IncludePath);%(AdditionalIncludeDirectories) @@ -667,7 +667,7 @@ $(IntDir);%(AdditionalIncludeDirectories) - print_compile_time.bat + call "$(ProjectDir)print_compile_time.bat" $(UM_IncludePath);%(AdditionalIncludeDirectories) @@ -709,7 +709,7 @@ $(IntDir);%(AdditionalIncludeDirectories) - print_compile_time.bat + call "$(ProjectDir)print_compile_time.bat" $(UM_IncludePath);%(AdditionalIncludeDirectories) @@ -751,7 +751,7 @@ $(IntDir);%(AdditionalIncludeDirectories) - print_compile_time.bat + call "$(ProjectDir)print_compile_time.bat" $(UM_IncludePath);%(AdditionalIncludeDirectories) diff --git a/TrafficMonitor/TrafficMonitorDlg.cpp b/TrafficMonitor/TrafficMonitorDlg.cpp index e7952e9df..67264af9b 100644 --- a/TrafficMonitor/TrafficMonitorDlg.cpp +++ b/TrafficMonitor/TrafficMonitorDlg.cpp @@ -127,6 +127,7 @@ BEGIN_MESSAGE_MAP(CTrafficMonitorDlg, CDialog) ON_COMMAND(ID_PLUGIN_DETAIL_TASKBAR, &CTrafficMonitorDlg::OnPluginDetailTaksbar) ON_WM_POWERBROADCAST() ON_WM_DWMCOLORIZATIONCOLORCHANGED() + ON_MESSAGE(WM_HOTKEY, &CTrafficMonitorDlg::OnHotKey) END_MESSAGE_MAP() @@ -742,6 +743,9 @@ void CTrafficMonitorDlg::ApplySettings(COptionsDlg& optionsDlg) bool is_show_notify_icon_changed = (optionsDlg.m_tab3_dlg.m_data.show_notify_icon != theApp.m_general_data.show_notify_icon); bool is_connections_hide_changed = (optionsDlg.m_tab3_dlg.m_data.connections_hide.data() != theApp.m_general_data.connections_hide.data()); bool d2d_turned_on = (theApp.m_taskbar_data.disable_d2d && !optionsDlg.m_tab2_dlg.m_data.disable_d2d); + bool is_hotkey_changed = (optionsDlg.m_tab3_dlg.m_data.hotkey_enabled != theApp.m_general_data.hotkey_enabled + || optionsDlg.m_tab3_dlg.m_data.hotkey_modifiers != theApp.m_general_data.hotkey_modifiers + || optionsDlg.m_tab3_dlg.m_data.hotkey_vk != theApp.m_general_data.hotkey_vk); //需要重新关闭再打开任务栏窗口的情况 bool taskbar_changed = (theApp.m_taskbar_data.show_taskbar_wnd_in_secondary_display != optionsDlg.m_tab2_dlg.m_data.show_taskbar_wnd_in_secondary_display || theApp.m_taskbar_data.secondary_display_index != optionsDlg.m_tab2_dlg.m_data.secondary_display_index @@ -860,6 +864,10 @@ void CTrafficMonitorDlg::ApplySettings(COptionsDlg& optionsDlg) CSkinManager::Instance().Save(); } + //如果热键设置变化了,重新注册全局热键 + if (is_hotkey_changed) + RegisterGlobalHotKey(); + theApp.SaveConfig(); theApp.SaveGlobalConfig(); } @@ -1113,6 +1121,7 @@ BOOL CTrafficMonitorDlg::OnInitDialog() SetTimer(MAIN_TIMER, 1000, NULL); SetTimer(MONITOR_TIMER, theApp.m_general_data.monitor_time_span, NULL); + SetTimer(ANIMATION_TIMER, 33, NULL); // 动画刷新定时器 30fps AfxBeginThread(MonitorThreadCallback, (LPVOID)this); //初始化窗口位置 @@ -1141,6 +1150,9 @@ BOOL CTrafficMonitorDlg::OnInitDialog() SetTimer(TASKBAR_TIMER, 100, NULL); + //注册全局热键 + RegisterGlobalHotKey(); + return TRUE; // 除非将焦点设置到控件,否则返回 TRUE } @@ -1974,6 +1986,11 @@ void CTrafficMonitorDlg::OnTimer(UINT_PTR nIDEvent) KillTimer(DELETE_NOTIFY_ICON_TIMER); } + if (nIDEvent == ANIMATION_TIMER) + { + Invalidate(FALSE); // 驱动动画帧刷新 + } + CDialog::OnTimer(nIDEvent); } @@ -2412,6 +2429,9 @@ void CTrafficMonitorDlg::OnDestroy() { CDialog::OnDestroy(); + //注销全局热键 + UnregisterGlobalHotKey(); + //程序退出时删除通知栏图标 ::Shell_NotifyIcon(NIM_DELETE, &m_ntIcon); @@ -2577,6 +2597,48 @@ void CTrafficMonitorDlg::OnShowMainWnd() theApp.SaveConfig(); } +void CTrafficMonitorDlg::RegisterGlobalHotKey() +{ + UnregisterGlobalHotKey(); + + if (!theApp.m_general_data.hotkey_enabled) + return; + + UINT modifiers = 0; + if (theApp.m_general_data.hotkey_modifiers & MOD_ALT) + modifiers |= MOD_ALT; + if (theApp.m_general_data.hotkey_modifiers & MOD_CONTROL) + modifiers |= MOD_CONTROL; + if (theApp.m_general_data.hotkey_modifiers & MOD_SHIFT) + modifiers |= MOD_SHIFT; + if (theApp.m_general_data.hotkey_modifiers & MOD_WIN) + modifiers |= MOD_WIN; + modifiers |= MOD_NOREPEAT; + + if (::RegisterHotKey(m_hWnd, 1, modifiers, theApp.m_general_data.hotkey_vk)) + { + m_hotkey_registered = true; + } +} + +void CTrafficMonitorDlg::UnregisterGlobalHotKey() +{ + if (m_hotkey_registered) + { + ::UnregisterHotKey(m_hWnd, 1); + m_hotkey_registered = false; + } +} + +LRESULT CTrafficMonitorDlg::OnHotKey(WPARAM wParam, LPARAM lParam) +{ + if (wParam == 1) + { + OnShowMainWnd(); + } + return 0; +} + void CTrafficMonitorDlg::OnChangeSkin() { diff --git a/TrafficMonitor/TrafficMonitorDlg.h b/TrafficMonitor/TrafficMonitorDlg.h index 7a5e5b905..65d2ce3ef 100644 --- a/TrafficMonitor/TrafficMonitorDlg.h +++ b/TrafficMonitor/TrafficMonitorDlg.h @@ -109,6 +109,7 @@ class CTrafficMonitorDlg : public CDialog unsigned int m_taskbar_timer_cnt{0}; //适用于TaskBarDlg的定时器触发次数(自程序启动以来的秒数) unsigned int m_monitor_time_cnt{}; int m_zero_speed_cnt{}; //如果检测不到网速,该变量就会自加 + bool m_hotkey_registered{ false }; int m_insert_to_taskbar_cnt{}; //用来统计尝试嵌入任务栏的次数 int m_cannot_insert_to_task_bar_warning{ true }; //指示是否会在无法嵌入任务栏时弹出提示框 @@ -237,6 +238,9 @@ class CTrafficMonitorDlg : public CDialog afx_msg void OnAppAbout(); afx_msg void OnShowCpuMemory2(); afx_msg void OnShowMainWnd(); + void RegisterGlobalHotKey(); + void UnregisterGlobalHotKey(); + afx_msg LRESULT OnHotKey(WPARAM wParam, LPARAM lParam); afx_msg void OnChangeSkin(); afx_msg LRESULT OnTaskBarCreated(WPARAM wParam, LPARAM lParam); //afx_msg void OnSetFont(); diff --git a/TrafficMonitor/language.h b/TrafficMonitor/language.h index 659fc2b0f..805f094ab 100644 --- a/TrafficMonitor/language.h +++ b/TrafficMonitor/language.h @@ -218,6 +218,9 @@ #define IDS_PLUGIN_NEW_VERSION_INFO L"IDS_PLUGIN_NEW_VERSION_INFO" #define IDS_TRAFFICMONITOR_PLUGIN_NITIFICATION L"IDS_TRAFFICMONITOR_PLUGIN_NITIFICATION" #define IDS_SKIN_FILE_ERROR_INFO L"IDS_SKIN_FILE_ERROR_INFO" +#define IDS_HOTKEY_ENABLE L"IDS_HOTKEY_ENABLE" +#define IDS_PRESS_HOTKEY L"IDS_PRESS_HOTKEY" +#define IDS_HOTKEY_REGISTER_FAILED L"IDS_HOTKEY_REGISTER_FAILED" #define TXT_OK L"TXT_OK" #define TXT_CANCEL L"TXT_CANCEL" diff --git a/TrafficMonitor/language/English.ini b/TrafficMonitor/language/English.ini index 2d62d80d5..39779ec91 100644 --- a/TrafficMonitor/language/English.ini +++ b/TrafficMonitor/language/English.ini @@ -222,6 +222,9 @@ IDS_RESTORE_FROM_SLEEP_LOG = "The system has been restored from hibernation, the IDS_PLUGIN_NEW_VERSION_INFO = "Update available, latest version: <%1%>" IDS_TRAFFICMONITOR_PLUGIN_NITIFICATION = "TrafficMonitor Plugin Notification" IDS_SKIN_FILE_ERROR_INFO = "Skin file parse failed!" +IDS_HOTKEY_ENABLE = "Enable global hotkey (show/hide main window)" +IDS_PRESS_HOTKEY = "Press a key combination..." +IDS_HOTKEY_REGISTER_FAILED = "Failed to register the global hotkey. The hotkey may already be in use by another application." TXT_OK = "OK" TXT_CANCEL = "Cancel" @@ -295,6 +298,7 @@ TXT_MAIN_BOARD = "Main board" TXT_SELECT_HDD_STATIC = "Select the hard disk to be monitored:" TXT_SELECT_CPU_STATIC = "Select the CPU temperature to be monitored:" TXT_ADVANCED = "Advanced" +TXT_HOTKEY_ENABLE = "Enable global hotkey (show/hide main window)" TXT_SHOW_ALL_CONNECTION_CHECK = "Show all network connections" TXT_SELECT_CONNECTIONS_BUTTON = "&Select the connection to monitor..." TXT_CPU_ACQUISITION_METHOD = "CPU usage acquisition method:" diff --git a/TrafficMonitor/language/Simplified_Chinese.ini b/TrafficMonitor/language/Simplified_Chinese.ini index 592e8d5cd..1585ed810 100644 --- a/TrafficMonitor/language/Simplified_Chinese.ini +++ b/TrafficMonitor/language/Simplified_Chinese.ini @@ -222,6 +222,9 @@ IDS_RESTORE_FROM_SLEEP_LOG = "系统已从休眠状态恢复,已重新初始 IDS_PLUGIN_NEW_VERSION_INFO = "有更新,最新版本:<%1%>" IDS_TRAFFICMONITOR_PLUGIN_NITIFICATION = "TrafficMonitor 插件通知" IDS_SKIN_FILE_ERROR_INFO = "皮肤文件解析失败!" +IDS_HOTKEY_ENABLE = "启用全局热键(显示/隐藏主窗口)" +IDS_PRESS_HOTKEY = "按下按键组合..." +IDS_HOTKEY_REGISTER_FAILED = "注册全局热键失败,该热键可能已被其他程序占用。" TXT_OK = "确定" TXT_CANCEL = "取消" @@ -295,6 +298,7 @@ TXT_MAIN_BOARD = "主板" TXT_SELECT_HDD_STATIC = "选择监控的硬盘:" TXT_SELECT_CPU_STATIC = "选择监控的CPU温度:" TXT_ADVANCED = "高级" +TXT_HOTKEY_ENABLE = "启用全局热键(显示/隐藏主窗口)" TXT_SHOW_ALL_CONNECTION_CHECK = "显示所有网络连接" TXT_SELECT_CONNECTIONS_BUTTON = "选择要监控的网络连接(&S)..." TXT_CPU_ACQUISITION_METHOD = "CPU使用率获取方式:" diff --git a/TrafficMonitor/resource.h b/TrafficMonitor/resource.h index f6a70b924..2dd64dd56 100644 --- a/TrafficMonitor/resource.h +++ b/TrafficMonitor/resource.h @@ -462,13 +462,16 @@ #define ID_PLUGIN_COMMAND_MAX 33664 #define ID_RESTORE_DEFAULT 33665 +#define IDC_HOTKEY_ENABLE_CHECK 1223 +#define IDC_HOTKEY_BUTTON 1224 + // Next default values for new objects -// +// #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NEXT_RESOURCE_VALUE 349 #define _APS_NEXT_COMMAND_VALUE 33666 -#define _APS_NEXT_CONTROL_VALUE 1221 +#define _APS_NEXT_CONTROL_VALUE 1225 #define _APS_NEXT_SYMED_VALUE 101 #endif #endif diff --git a/TrafficMonitor/stdafx.h b/TrafficMonitor/stdafx.h index c67c801de..111f01050 100644 --- a/TrafficMonitor/stdafx.h +++ b/TrafficMonitor/stdafx.h @@ -89,6 +89,7 @@ using std::ofstream; #define RESTART_TASKBAR_TIMER 1240 #define INIT_CONNECT_TIMER 1241 #define DPI_CHANGE_TIMER 1242 +#define ANIMATION_TIMER 1243 //背景动画定时器(驱动多帧皮肤刷新) #define MAX_INSERT_TO_TASKBAR_CNT 200 //尝试嵌入任务栏的最大次数 #define WARN_INSERT_TO_TASKBAR_CNT 20 //尝试嵌入任务栏的警告次数