Init: Migrate SimpleRemoter (Since v1.3.1) to Gitea

This commit is contained in:
yuanyuanxiang
2026-04-19 19:55:01 +02:00
commit 5a325a202b
744 changed files with 235562 additions and 0 deletions

View File

@@ -0,0 +1,439 @@
// SearchBarDlg.cpp - 浮动搜索工具栏实现
#include "stdafx.h"
#include "SearchBarDlg.h"
#include "2015RemoteDlg.h"
IMPLEMENT_DYNAMIC(CSearchBarDlg, CDialogEx)
CSearchBarDlg::CSearchBarDlg(CMy2015RemoteDlg* pParent)
: CDialogLangEx(IDD_SEARCH_BAR, pParent)
, m_pParent(pParent)
, m_nCurrentIndex(-1)
{
m_brushEdit.CreateSolidBrush(RGB(60, 60, 60));
m_brushStatic.CreateSolidBrush(RGB(40, 40, 40));
}
CSearchBarDlg::~CSearchBarDlg()
{
m_brushEdit.DeleteObject();
m_brushStatic.DeleteObject();
}
void CSearchBarDlg::DoDataExchange(CDataExchange* pDX)
{
__super::DoDataExchange(pDX);
DDX_Control(pDX, IDC_SEARCH_EDIT, m_editSearch);
DDX_Control(pDX, IDC_SEARCH_COUNT, m_staticCount);
}
BEGIN_MESSAGE_MAP(CSearchBarDlg, CDialogEx)
ON_BN_CLICKED(IDC_SEARCH_PREV, &CSearchBarDlg::OnBnClickedPrev)
ON_BN_CLICKED(IDC_SEARCH_NEXT, &CSearchBarDlg::OnBnClickedNext)
ON_BN_CLICKED(IDC_SEARCH_CLOSE, &CSearchBarDlg::OnBnClickedClose)
ON_EN_CHANGE(IDC_SEARCH_EDIT, &CSearchBarDlg::OnEnChangeSearch)
ON_WM_TIMER()
ON_WM_ERASEBKGND()
ON_WM_CTLCOLOR()
END_MESSAGE_MAP()
BOOL CSearchBarDlg::OnInitDialog()
{
__super::OnInitDialog();
// 设置分层窗口样式(透明 + 不抢焦点)
ModifyStyleEx(0, WS_EX_LAYERED | WS_EX_NOACTIVATE);
SetLayeredWindowAttributes(0, 200, LWA_ALPHA);
// 子类化按钮为 CIconButton
m_btnPrev.SubclassDlgItem(IDC_SEARCH_PREV, this);
m_btnNext.SubclassDlgItem(IDC_SEARCH_NEXT, this);
m_btnClose.SubclassDlgItem(IDC_SEARCH_CLOSE, this);
// 设置图标
m_btnPrev.SetIconDrawFunc(CIconButton::DrawIconArrowLeft);
m_btnNext.SetIconDrawFunc(CIconButton::DrawIconArrowRight);
m_btnClose.SetIconDrawFunc(CIconButton::DrawIconClose);
m_btnClose.SetIsCloseButton(true);
// 创建工具提示
m_tooltip.Create(this);
m_tooltip.Activate(TRUE);
m_tooltip.AddTool(&m_btnPrev, _TR("上一个 (Shift+Enter)"));
m_tooltip.AddTool(&m_btnNext, _TR("下一个 (Enter)"));
m_tooltip.AddTool(&m_btnClose, _TR("关闭 (Esc)"));
// 设置输入框提示文本
m_editSearch.SetCueBanner(L"Search...", TRUE);
// 初始化计数文本
m_staticCount.SetWindowText(_T(""));
return TRUE;
}
BOOL CSearchBarDlg::PreTranslateMessage(MSG* pMsg)
{
if (m_tooltip.GetSafeHwnd()) {
m_tooltip.RelayEvent(pMsg);
}
if (pMsg->message == WM_KEYDOWN) {
if (pMsg->wParam == VK_ESCAPE) {
Hide();
return TRUE;
}
if (pMsg->wParam == VK_RETURN) {
if (GetKeyState(VK_SHIFT) & 0x8000) {
GotoPrev();
} else {
GotoNext();
}
return TRUE;
}
// F3 = 下一个, Shift+F3 = 上一个
if (pMsg->wParam == VK_F3) {
if (GetKeyState(VK_SHIFT) & 0x8000) {
GotoPrev();
} else {
GotoNext();
}
return TRUE;
}
}
return __super::PreTranslateMessage(pMsg);
}
BOOL CSearchBarDlg::OnEraseBkgnd(CDC* pDC)
{
CRect rect;
GetClientRect(&rect);
pDC->FillSolidRect(rect, RGB(40, 40, 40));
return TRUE;
}
HBRUSH CSearchBarDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
HBRUSH hbr = __super::OnCtlColor(pDC, pWnd, nCtlColor);
// 输入框深色背景
if (nCtlColor == CTLCOLOR_EDIT && pWnd->GetDlgCtrlID() == IDC_SEARCH_EDIT) {
pDC->SetTextColor(RGB(240, 240, 240));
pDC->SetBkColor(RGB(60, 60, 60));
return m_brushEdit;
}
// 静态文本(计数)- 使用实色背景避免重绘问题
if (nCtlColor == CTLCOLOR_STATIC) {
pDC->SetTextColor(RGB(180, 180, 180));
pDC->SetBkColor(RGB(40, 40, 40));
return m_brushStatic;
}
return hbr;
}
void CSearchBarDlg::Show()
{
if (!GetSafeHwnd()) {
Create(IDD_SEARCH_BAR, m_pParent);
}
UpdatePosition();
ShowWindow(SW_SHOWNOACTIVATE);
SetWindowPos(&wndTopMost, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
// 让输入框获得焦点并选中所有文本
m_editSearch.SetFocus();
m_editSearch.SetSel(0, -1);
}
void CSearchBarDlg::Hide()
{
KillTimer(TIMER_SEARCH); // 清理定时器
ShowWindow(SW_HIDE);
// 将焦点还给主窗口列表
if (m_pParent) {
m_pParent->SetFocus();
}
}
void CSearchBarDlg::InvalidateCache()
{
// 杀掉 pending 的搜索定时器,避免竞争条件
KillTimer(TIMER_SEARCH);
// 清空搜索缓存
m_strLastSearch.Empty();
m_Results.clear();
m_nCurrentIndex = -1;
// 如果搜索栏存在且可见,立即重新搜索并更新界面
if (GetSafeHwnd() && IsWindowVisible()) {
CString searchText;
m_editSearch.GetWindowText(searchText);
if (!searchText.IsEmpty()) {
DoSearch();
} else {
UpdateCountText();
}
}
}
void CSearchBarDlg::UpdatePosition()
{
if (!m_pParent || !GetSafeHwnd()) return;
CRect rcParent;
m_pParent->GetWindowRect(&rcParent);
CRect rcThis;
GetWindowRect(&rcThis);
// 居中显示
int x = rcParent.left + (rcParent.Width() - rcThis.Width()) / 2;
int y = rcParent.top + (rcParent.Height() - rcThis.Height()) / 2;
SetWindowPos(NULL, x, y, 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
}
void CSearchBarDlg::OnEnChangeSearch()
{
// 延迟搜索:重置定时器,避免每次输入都搜索
KillTimer(TIMER_SEARCH);
SetTimer(TIMER_SEARCH, SEARCH_DELAY_MS, NULL);
}
void CSearchBarDlg::OnTimer(UINT_PTR nIDEvent)
{
if (nIDEvent == TIMER_SEARCH) {
KillTimer(TIMER_SEARCH);
DoSearch();
}
__super::OnTimer(nIDEvent);
}
void CSearchBarDlg::DoSearch()
{
CString searchText;
m_editSearch.GetWindowText(searchText);
// 空文本时清空结果
if (searchText.IsEmpty()) {
m_Results.clear();
m_nCurrentIndex = -1;
m_strLastSearch.Empty();
UpdateCountText();
return;
}
// 相同文本不重复搜索注意Tab 切换时 m_strLastSearch 会被清空,强制重新搜索)
if (searchText == m_strLastSearch && !m_Results.empty()) {
return;
}
m_strLastSearch = searchText;
// 大小写不敏感
searchText.MakeLower();
m_Results.clear();
if (!m_pParent) return;
// 获取当前选中项的 clientID用于确定搜索起始位置
uint64_t selectedClientID = 0;
POSITION pos = m_pParent->m_CList_Online.GetFirstSelectedItemPosition();
if (pos) {
int nSelectedItem = m_pParent->m_CList_Online.GetNextSelectedItem(pos);
EnterCriticalSection(&m_pParent->m_cs);
context* selCtx = m_pParent->GetContextByListIndex(nSelectedItem);
if (selCtx) selectedClientID = selCtx->GetClientID();
LeaveCriticalSection(&m_pParent->m_cs);
}
// 加锁保护:访问 m_FilteredIndices, m_HostList, context
EnterCriticalSection(&m_pParent->m_cs);
// 遍历过滤后的列表,存储匹配项的 clientID而非索引
int count = (int)m_pParent->m_FilteredIndices.size();
for (int i = 0; i < count; i++) {
context* ctx = m_pParent->GetContextByListIndex(i);
if (!ctx) continue;
bool matched = false;
// 搜索各列IP(0), 地理位置(2), 计算机名/备注(3), 操作系统(4), 版本(8)
int cols[] = { 0, 2, 3, 4, 8 };
for (int col : cols) {
CString colText;
// 备注列特殊处理
if (col == 3) { // ONLINELIST_COMPUTER_NAME
colText = m_pParent->m_ClientMap->GetClientMapData(ctx->GetClientID(), MAP_NOTE);
if (colText.IsEmpty()) {
colText = ctx->GetClientData(col);
}
} else {
colText = ctx->GetClientData(col);
}
colText.MakeLower();
if (colText.Find(searchText) >= 0) {
matched = true;
break;
}
}
if (matched) {
m_Results.push_back(ctx->GetClientID());
}
}
LeaveCriticalSection(&m_pParent->m_cs);
// 定位到最接近当前选中项的结果
m_nCurrentIndex = -1;
if (!m_Results.empty()) {
m_nCurrentIndex = 0;
if (selectedClientID != 0) {
for (int i = 0; i < (int)m_Results.size(); i++) {
if (m_Results[i] == selectedClientID) {
m_nCurrentIndex = i;
break;
}
}
}
GotoResult(m_nCurrentIndex);
}
UpdateCountText();
}
void CSearchBarDlg::GotoPrev()
{
if (m_Results.empty()) return;
m_nCurrentIndex--;
if (m_nCurrentIndex < 0) {
m_nCurrentIndex = (int)m_Results.size() - 1; // 循环
}
GotoResult(m_nCurrentIndex);
UpdateCountText();
}
void CSearchBarDlg::GotoNext()
{
if (m_Results.empty()) return;
m_nCurrentIndex++;
if (m_nCurrentIndex >= (int)m_Results.size()) {
m_nCurrentIndex = 0; // 循环
}
GotoResult(m_nCurrentIndex);
UpdateCountText();
}
int CSearchBarDlg::FindListIndexByClientID(uint64_t clientID)
{
if (!m_pParent || clientID == 0) return -1;
// 加锁查找
EnterCriticalSection(&m_pParent->m_cs);
int count = (int)m_pParent->m_FilteredIndices.size();
for (int i = 0; i < count; i++) {
context* ctx = m_pParent->GetContextByListIndex(i);
if (ctx && ctx->GetClientID() == clientID) {
LeaveCriticalSection(&m_pParent->m_cs);
return i;
}
}
LeaveCriticalSection(&m_pParent->m_cs);
return -1;
}
void CSearchBarDlg::GotoResult(int index)
{
if (!m_pParent) return;
// 循环查找有效结果(避免递归导致栈溢出)
int attempts = 0;
int maxAttempts = (int)m_Results.size();
while (attempts < maxAttempts) {
if (index < 0 || index >= (int)m_Results.size()) {
m_nCurrentIndex = -1;
UpdateCountText();
return;
}
uint64_t clientID = m_Results[index];
int listIndex = FindListIndexByClientID(clientID);
if (listIndex >= 0) {
// 找到有效结果
m_nCurrentIndex = index;
// 取消所有选中
int nItem = -1;
while ((nItem = m_pParent->m_CList_Online.GetNextItem(-1, LVNI_SELECTED)) != -1) {
m_pParent->m_CList_Online.SetItemState(nItem, 0, LVIS_SELECTED | LVIS_FOCUSED);
}
// 选中并滚动到目标项
m_pParent->m_CList_Online.SetItemState(listIndex, LVIS_SELECTED | LVIS_FOCUSED, LVIS_SELECTED | LVIS_FOCUSED);
m_pParent->m_CList_Online.EnsureVisible(listIndex, FALSE);
return;
}
// 该主机不在当前列表中,移除并尝试下一个
m_Results.erase(m_Results.begin() + index);
if (m_Results.empty()) {
m_nCurrentIndex = -1;
UpdateCountText();
return;
}
// 调整索引继续查找
if (index >= (int)m_Results.size()) {
index = 0;
}
attempts++;
}
// 所有结果都失效
m_Results.clear();
m_nCurrentIndex = -1;
UpdateCountText();
}
void CSearchBarDlg::UpdateCountText()
{
CString text;
if (m_Results.empty()) {
CString searchText;
m_editSearch.GetWindowText(searchText);
if (!searchText.IsEmpty()) {
text = _T("Not found");
}
} else {
text.Format(_T("%d/%d"), m_nCurrentIndex + 1, (int)m_Results.size());
}
m_staticCount.SetWindowText(text);
m_staticCount.Invalidate();
m_staticCount.UpdateWindow();
}
void CSearchBarDlg::OnBnClickedPrev()
{
GotoPrev();
}
void CSearchBarDlg::OnBnClickedNext()
{
GotoNext();
}
void CSearchBarDlg::OnBnClickedClose()
{
Hide();
}