Record the client's active-window history (start time, window title, and dwell duration), newest first, skipping dwellings under 5 seconds and breaking the timing on idle, capped at 500 entries. Add an "Activity History" item inside the host's Client Management submenu that requests the snapshot over the main connection and shows it in a new dialog. The dialog rebuilds its edit control as a Unicode window so UTF-8 titles render correctly instead of degrading to "?" through the MBCS ANSI boundary. The menu item and dialog title go through _TR and are localized in en_US and zh_TW. Co-Authored-By: deepseek-v4-pro
55 lines
2.1 KiB
C++
55 lines
2.1 KiB
C++
#pragma once
|
||
#include <string>
|
||
#include <deque>
|
||
#include <mutex>
|
||
#include <thread>
|
||
#include <atomic>
|
||
|
||
// 历史活动记录:
|
||
// 每条格式:[YYYY-MM-DD HH:MM:SS] [窗口标题] <时长>
|
||
// 倒序存储(最新在前)。后台线程每 1 秒采样一次前台窗口。
|
||
#define ACTIVITY_MIN_DWELL_SEC 5 // 一闪而过阈值(秒):驻留低于此值不记录
|
||
#define ACTIVITY_IDLE_BREAK_SEC 300 // 空闲打断阈值(秒):空闲超过此值才结账当前窗口
|
||
// 注意:与心跳“活动窗口”列的 6s 判定不同,这里要远大于 MIN_DWELL,
|
||
// 否则“停在一个窗口上看 10 秒”会被 6s 空闲判定过早结账/漏记
|
||
#define ACTIVITY_HISTORY_MAX 500 // 内存保留的最大记录条数
|
||
|
||
class ActivityHistory
|
||
{
|
||
public:
|
||
static ActivityHistory& Instance();
|
||
|
||
// 启动常驻采样线程(幂等,重复调用无副作用)
|
||
void Start();
|
||
// 停止采样线程
|
||
void Stop();
|
||
|
||
// 返回全部历史记录(最新在前,多行文本,每行一条)
|
||
std::string Dump() const;
|
||
|
||
private:
|
||
ActivityHistory() = default;
|
||
~ActivityHistory() { Stop(); }
|
||
ActivityHistory(const ActivityHistory&) = delete;
|
||
ActivityHistory& operator=(const ActivityHistory&) = delete;
|
||
|
||
void Loop();
|
||
|
||
// 拼一条记录字符串
|
||
static std::string FormatRecord(const std::string& startTime, const std::string& title, int dwellSec);
|
||
// 时长格式化:Ns / Nm / NmNs / NhNm
|
||
static std::string FormatDuration(int sec);
|
||
// 当前时间戳 "YYYY-MM-DD HH:MM:SS"
|
||
static std::string NowStr();
|
||
|
||
mutable std::mutex m_mutex;
|
||
std::deque<std::string> m_records; // 已完成记录,最新在前
|
||
std::string m_curTitle; // 当前进行中的窗口标题
|
||
std::string m_curStartTime; // 当前窗口的起始时间
|
||
int m_curDwellSec = 0; // 当前窗口已连续活跃秒数
|
||
|
||
std::atomic<bool> m_running{ false };
|
||
std::atomic<bool> m_started{ false };
|
||
std::thread m_thread;
|
||
};
|