Files
SimpleRemoter/server/2015Remote/ToolbarDlg.cpp
2026-04-19 22:55:21 +02:00

789 lines
27 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#include "stdafx.h"
#include "ToolbarDlg.h"
#include "2015Remote.h"
#include "2015RemoteDlg.h"
#include <ScreenSpyDlg.h>
#include <common/commands.h>
IMPLEMENT_DYNAMIC(CToolbarDlg, CDialogEx)
CToolbarDlg::CToolbarDlg(CScreenSpyDlg* pParent)
: CDialogLangEx(IDD_TOOLBAR_DLG, pParent)
{
m_pParent = pParent;
}
CToolbarDlg::~CToolbarDlg()
{
}
void CToolbarDlg::DoDataExchange(CDataExchange* pDX)
{
__super::DoDataExchange(pDX);
}
BEGIN_MESSAGE_MAP(CToolbarDlg, CDialogEx)
ON_BN_CLICKED(IDC_BTN_EXIT_FULLSCREEN, &CToolbarDlg::OnBnClickedExitFullscreen)
ON_BN_CLICKED(CONTROL_BTN_ID, &CToolbarDlg::OnBnClickedCtrl)
ON_BN_CLICKED(IDC_BTN_MINIMIZE, &CToolbarDlg::OnBnClickedMinimize)
ON_BN_CLICKED(IDC_BTN_CLOSE, &CToolbarDlg::OnBnClickedClose)
ON_BN_CLICKED(IDC_BTN_LOCK, &CToolbarDlg::OnBnClickedLock)
ON_BN_CLICKED(IDC_BTN_POSITION, &CToolbarDlg::OnBnClickedPosition)
ON_BN_CLICKED(IDC_BTN_OPACITY, &CToolbarDlg::OnBnClickedOpacity)
ON_BN_CLICKED(IDC_BTN_SWITCH_SCREEN, &CToolbarDlg::OnBnClickedSwitchScreen)
ON_BN_CLICKED(IDC_BTN_BLOCK_INPUT, &CToolbarDlg::OnBnClickedBlockInput)
ON_BN_CLICKED(IDC_BTN_STATUS_INFO, &CToolbarDlg::OnBnClickedStatusInfo)
ON_BN_CLICKED(IDC_BTN_QUALITY, &CToolbarDlg::OnBnClickedQuality)
ON_BN_CLICKED(IDC_BTN_RESTORE_CONSOLE, &CToolbarDlg::OnBnClickedRestoreConsole)
ON_BN_CLICKED(IDC_BTN_X, &CToolbarDlg::OnBnClickedX)
ON_BN_CLICKED(IDC_BTN_Y, &CToolbarDlg::OnBnClickedY)
ON_BN_CLICKED(IDC_BTN_Z, &CToolbarDlg::OnBnClickedZ)
ON_BN_CLICKED(IDC_BTN_SCREENSHOT, &CToolbarDlg::OnBnClickedScreenshot)
ON_WM_ERASEBKGND()
END_MESSAGE_MAP()
RECT CToolbarDlg::GetParentMonitorRect()
{
CWnd* pParent = GetParent();
if (pParent) {
HMONITOR hMonitor = MonitorFromWindow(pParent->GetSafeHwnd(), MONITOR_DEFAULTTONEAREST);
MONITORINFO mi = { sizeof(mi) };
if (GetMonitorInfo(hMonitor, &mi)) {
return mi.rcMonitor;
}
}
// 回退到主显示器
RECT rc = { 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN) };
return rc;
}
void CToolbarDlg::CheckMousePosition()
{
// 如果父窗口最小化,隐藏工具栏
CWnd* pParent = GetParent();
if (pParent && pParent->IsIconic()) {
if (m_bVisible) {
ShowWindow(SW_HIDE);
m_bVisible = false;
}
return;
}
// 如果工具栏已锁定,确保它可见(处理最小化恢复等情况)
if (m_bLocked) {
if (!m_bVisible) {
SlideIn();
}
return;
}
CPoint pt;
GetCursorPos(&pt);
RECT rcMonitor = GetParentMonitorRect();
int monLeft = rcMonitor.left;
int monRight = rcMonitor.right;
int monTop = rcMonitor.top;
int monBottom = rcMonitor.bottom;
int monWidth = monRight - monLeft;
int monHeight = monBottom - monTop;
int btnSize = 32, btnSpacing = 8, btnCount = 16;
if (m_nPosition <= 1) {
// 水平模式 (上/下)
int totalWidth = btnSize * btnCount + btnSpacing * (btnCount - 1);
int leftBound = monLeft + (monWidth - totalWidth) / 2;
int rightBound = monLeft + (monWidth + totalWidth) / 2;
if (m_nPosition == 0) {
// 工具栏在上方: 鼠标移到顶端时弹出
if (pt.y <= monTop + 2 && pt.x >= leftBound && pt.x <= rightBound) {
if (!m_bVisible) SlideIn();
}
else if (pt.y > monTop + m_nHeight + 10 || pt.x < leftBound - 50 || pt.x > rightBound + 50) {
if (m_bVisible) SlideOut();
}
} else {
// 工具栏在下方: 鼠标移到底端时弹出
if (pt.y >= monBottom - 2 && pt.x >= leftBound && pt.x <= rightBound) {
if (!m_bVisible) SlideIn();
}
else if (pt.y < monBottom - m_nHeight - 10 || pt.x < leftBound - 50 || pt.x > rightBound + 50) {
if (m_bVisible) SlideOut();
}
}
} else {
// 垂直模式 (左/右)
int vw = 40;
int totalHeight = btnSize * btnCount + btnSpacing * (btnCount - 1);
int topBound = monTop + (monHeight - totalHeight) / 2;
int bottomBound = monTop + (monHeight + totalHeight) / 2;
if (m_nPosition == 2) {
// 工具栏在左边: 鼠标移到左端时弹出
if (pt.x <= monLeft + 2 && pt.y >= topBound && pt.y <= bottomBound) {
if (!m_bVisible) SlideIn();
}
else if (pt.x > monLeft + vw + 10 || pt.y < topBound - 50 || pt.y > bottomBound + 50) {
if (m_bVisible) SlideOut();
}
} else {
// 工具栏在右边: 鼠标移到右端时弹出
if (pt.x >= monRight - 2 && pt.y >= topBound && pt.y <= bottomBound) {
if (!m_bVisible) SlideIn();
}
else if (pt.x < monRight - vw - 10 || pt.y < topBound - 50 || pt.y > bottomBound + 50) {
if (m_bVisible) SlideOut();
}
}
}
}
void CToolbarDlg::SlideIn()
{
if (m_bVisible) return;
m_bVisible = true;
RECT rcMonitor = GetParentMonitorRect();
int monLeft = rcMonitor.left;
int monTop = rcMonitor.top;
int monRight = rcMonitor.right;
int monBottom = rcMonitor.bottom;
int monWidth = monRight - monLeft;
int monHeight = monBottom - monTop;
int hw = 640; // 水平工具栏宽度 (与垂直高度一致)
int vw = 40;
int vh = 640;
// 从边缘展开(改变窗口大小),避免多显示器时跑到相邻屏幕
switch (m_nPosition) {
case 0: { // 从上方展开: 顶边固定在 monTop, 高度从1增长到 m_nHeight
int hx = monLeft + (monWidth - hw) / 2;
for (int h = 1; h <= m_nHeight; h += 10) {
SetWindowPos(&wndTopMost, hx, monTop, hw, h, SWP_SHOWWINDOW | SWP_NOACTIVATE);
UpdateWindow();
Sleep(10);
}
SetWindowPos(&wndTopMost, hx, monTop, hw, m_nHeight, SWP_NOACTIVATE);
break;
}
case 1: { // 从下方展开: 底边固定在 monBottom, 高度从1增长到 m_nHeight
int hx = monLeft + (monWidth - hw) / 2;
for (int h = 1; h <= m_nHeight; h += 10) {
SetWindowPos(&wndTopMost, hx, monBottom - h, hw, h, SWP_SHOWWINDOW | SWP_NOACTIVATE);
UpdateWindow();
Sleep(10);
}
SetWindowPos(&wndTopMost, hx, monBottom - m_nHeight, hw, m_nHeight, SWP_NOACTIVATE);
break;
}
case 2: { // 从左边展开: 左边固定在 monLeft, 宽度从1增长到 vw
int vy = monTop + (monHeight - vh) / 2;
for (int w = 1; w <= vw; w += 10) {
SetWindowPos(&wndTopMost, monLeft, vy, w, vh, SWP_SHOWWINDOW | SWP_NOACTIVATE);
UpdateWindow();
Sleep(10);
}
SetWindowPos(&wndTopMost, monLeft, vy, vw, vh, SWP_NOACTIVATE);
break;
}
case 3: { // 从右边展开: 右边固定在 monRight, 宽度从1增长到 vw
int vy = monTop + (monHeight - vh) / 2;
for (int w = 1; w <= vw; w += 10) {
SetWindowPos(&wndTopMost, monRight - w, vy, w, vh, SWP_SHOWWINDOW | SWP_NOACTIVATE);
UpdateWindow();
Sleep(10);
}
SetWindowPos(&wndTopMost, monRight - vw, vy, vw, vh, SWP_NOACTIVATE);
break;
}
}
}
void CToolbarDlg::SlideOut()
{
RECT rcMonitor = GetParentMonitorRect();
int monLeft = rcMonitor.left;
int monTop = rcMonitor.top;
int monRight = rcMonitor.right;
int monBottom = rcMonitor.bottom;
int monWidth = monRight - monLeft;
int monHeight = monBottom - monTop;
int hw = 640;
int vw = 40;
int vh = 640;
CWnd* btns[] = {
&m_btnExit, &m_btnControl,
&m_btnLock, &m_btnPosition,
&m_btnOpacity, &m_btnSwitchScreen,
&m_btnBlockInput, &m_btnStatusInfo,
&m_btnQuality, &m_btnRestoreConsole,
&m_btnX, &m_btnY, &m_btnZ,
&m_btnScreenshot,
&m_btnMinimize, &m_btnClose,
};
const int N = 16;
CRect btnRects[N];
for (int i = 0; i < N; i++) {
btns[i]->GetWindowRect(&btnRects[i]);
ScreenToClient(&btnRects[i]);
}
// 向边缘缩回,避免多显示器时跑到相邻屏幕
switch (m_nPosition) {
case 0: { // 向上缩回: 顶边固定, 底边从下向上收缩, 按钮跟随上移
int hx = monLeft + (monWidth - hw) / 2;
for (int h = m_nHeight; h >= 0; h -= 8) {
int realH = max(h, 1);
int offset = m_nHeight - realH;
for (int i = 0; i < N; i++)
btns[i]->SetWindowPos(NULL, btnRects[i].left, btnRects[i].top - offset, 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
SetWindowPos(&wndTopMost, hx, monTop, hw, realH, SWP_NOACTIVATE);
Sleep(50);
}
break;
}
case 1: { // 向下缩回: 底边固定, 顶边从上向下收缩, 按钮自然跟随
int hx = monLeft + (monWidth - hw) / 2;
for (int h = m_nHeight; h >= 0; h -= 8) {
SetWindowPos(&wndTopMost, hx, monBottom - max(h, 1), hw, max(h, 1), SWP_NOACTIVATE);
Sleep(50);
}
break;
}
case 2: { // 向左缩回: 左边固定, 右边从右向左收缩, 按钮跟随左移
int vy = monTop + (monHeight - vh) / 2;
for (int w = vw; w >= 0; w -= 8) {
int realW = max(w, 1);
int offset = vw - realW;
for (int i = 0; i < N; i++)
btns[i]->SetWindowPos(NULL, btnRects[i].left - offset, btnRects[i].top, 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
SetWindowPos(&wndTopMost, monLeft, vy, realW, vh, SWP_NOACTIVATE);
Sleep(50);
}
break;
}
case 3: { // 向右缩回: 右边固定, 左边从左向右收缩, 按钮自然跟随
int vy = monTop + (monHeight - vh) / 2;
for (int w = vw; w >= 0; w -= 8) {
SetWindowPos(&wndTopMost, monRight - max(w, 1), vy, max(w, 1), vh, SWP_NOACTIVATE);
Sleep(50);
}
break;
}
}
// 恢复按钮位置(下次 SlideIn 时位置正确)
for (int i = 0; i < N; i++)
btns[i]->SetWindowPos(NULL, btnRects[i].left, btnRects[i].top, 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
ShowWindow(SW_HIDE);
m_bVisible = false;
}
void CToolbarDlg::OnBnClickedExitFullscreen()
{
// 通知父窗口退出全屏
GetParent()->PostMessage(WM_COMMAND, ID_EXIT_FULLSCREEN, 0);
}
void CToolbarDlg::OnBnClickedCtrl()
{
CScreenSpyDlg* pParent = (CScreenSpyDlg*)GetParent();
pParent->m_bIsCtrl = !pParent->m_bIsCtrl;
pParent->UpdateCtrlStatus(pParent->m_bIsCtrl);
UpdateButtonIcons();
}
void CToolbarDlg::OnBnClickedClose()
{
GetParent()->PostMessage(WM_CLOSE);
}
BOOL CToolbarDlg::OnInitDialog()
{
__super::OnInitDialog();
// 加载用户设置
LoadSettings();
// 1. 设置分层窗口样式 (WS_EX_NOACTIVATE 防止工具栏点击时抢夺焦点)
ModifyStyleEx(0, WS_EX_LAYERED | WS_EX_NOACTIVATE);
// 2. 应用透明度设置
ApplyOpacity();
// 3. Subclass dialog buttons as CIconButton
m_btnExit.SubclassDlgItem(IDC_BTN_EXIT_FULLSCREEN, this);
m_btnControl.SubclassDlgItem(CONTROL_BTN_ID, this);
m_btnLock.SubclassDlgItem(IDC_BTN_LOCK, this);
m_btnPosition.SubclassDlgItem(IDC_BTN_POSITION, this);
m_btnOpacity.SubclassDlgItem(IDC_BTN_OPACITY, this);
m_btnSwitchScreen.SubclassDlgItem(IDC_BTN_SWITCH_SCREEN, this);
m_btnBlockInput.SubclassDlgItem(IDC_BTN_BLOCK_INPUT, this);
m_btnStatusInfo.SubclassDlgItem(IDC_BTN_STATUS_INFO, this);
m_btnQuality.SubclassDlgItem(IDC_BTN_QUALITY, this);
m_btnRestoreConsole.SubclassDlgItem(IDC_BTN_RESTORE_CONSOLE, this);
m_btnX.SubclassDlgItem(IDC_BTN_X, this);
m_btnY.SubclassDlgItem(IDC_BTN_Y, this);
m_btnZ.SubclassDlgItem(IDC_BTN_Z, this);
m_btnScreenshot.SubclassDlgItem(IDC_BTN_SCREENSHOT, this);
m_btnMinimize.SubclassDlgItem(IDC_BTN_MINIMIZE, this);
m_btnClose.SubclassDlgItem(IDC_BTN_CLOSE, this);
// Set static icons for buttons that don't change
m_btnExit.SetIconDrawFunc(CIconButton::DrawIconExitFullscreen);
m_btnSwitchScreen.SetIconDrawFunc(CIconButton::DrawIconSwitchScreen);
m_btnQuality.SetIconDrawFunc(CIconButton::DrawIconQuality);
m_btnRestoreConsole.SetIconDrawFunc(CIconButton::DrawIconRestoreConsole);
m_btnX.SetIconDrawFunc(CIconButton::DrawIconLetterX); // 切换窗口
// Y按钮图标在 UpdateButtonIcons 中根据音频状态动态设置
m_btnZ.SetIconDrawFunc(CIconButton::DrawIconLetterZ); // 预留按钮 Z
m_btnScreenshot.SetIconDrawFunc(CIconButton::DrawIconScreenshot);
m_btnMinimize.SetIconDrawFunc(CIconButton::DrawIconMinimize);
m_btnClose.SetIconDrawFunc(CIconButton::DrawIconClose);
m_btnClose.SetIsCloseButton(true);
// 4. Create tooltip
m_tooltip.Create(this);
m_tooltip.Activate(TRUE);
m_tooltip.SetMaxTipWidth(200);
CScreenSpyDlg* pParent = (CScreenSpyDlg*)GetParent();
m_tooltip.AddTool(&m_btnExit, _TR("退出全屏"));
m_tooltip.AddTool(&m_btnControl, pParent->m_bIsCtrl ? _TR("暂停控制") : _TR("控制屏幕"));
m_tooltip.AddTool(&m_btnLock, m_bLocked ? _TR("解锁") : _TR("锁定"));
m_tooltip.AddTool(&m_btnPosition, _TR("放下面"));
m_tooltip.AddTool(&m_btnOpacity, _TR("透明度"));
m_tooltip.AddTool(&m_btnSwitchScreen, _TR("切换屏幕"));
m_tooltip.AddTool(&m_btnBlockInput, _TR("锁定远程输入"));
m_tooltip.AddTool(&m_btnStatusInfo, m_bShowStatusInfo ? _TR("隐藏状态信息") : _TR("显示状态信息"));
m_tooltip.AddTool(&m_btnQuality, _TR("屏幕质量"));
m_tooltip.AddTool(&m_btnRestoreConsole, _TR("RDP会话归位"));
m_tooltip.AddTool(&m_btnX, _TR("切换窗口")); // 类似 Alt+Tab
m_tooltip.AddTool(&m_btnY, pParent->m_Settings.AudioEnabled ? _TR("关闭系统音频") : _TR("打开系统音频"));
m_tooltip.AddTool(&m_btnZ, _T("Z")); // 预留按钮
m_tooltip.AddTool(&m_btnScreenshot, _TR("截图"));
m_tooltip.AddTool(&m_btnMinimize, _TR("最小化"));
m_tooltip.AddTool(&m_btnClose, _TR("关闭"));
// 5. Set state-dependent icons and tooltips
UpdateButtonIcons();
// 6. 布局按钮
LayoutButtons();
// 如果是锁定状态,立即显示工具栏(否则锁定时无法触发显示)
if (m_bLocked) {
m_bVisible = true;
RECT rcMonitor = GetParentMonitorRect();
int monWidth = rcMonitor.right - rcMonitor.left;
int monHeight = rcMonitor.bottom - rcMonitor.top;
int hw = 640;
int vw = 40;
int vh = 640;
int hx = rcMonitor.left + (monWidth - hw) / 2;
switch (m_nPosition) {
case 0:
SetWindowPos(&wndTopMost, hx, rcMonitor.top, hw, m_nHeight, SWP_SHOWWINDOW | SWP_NOACTIVATE);
break;
case 1:
SetWindowPos(&wndTopMost, hx, rcMonitor.bottom - m_nHeight, hw, m_nHeight, SWP_SHOWWINDOW | SWP_NOACTIVATE);
break;
case 2: {
int vy = rcMonitor.top + (monHeight - vh) / 2;
SetWindowPos(&wndTopMost, rcMonitor.left, vy, vw, vh, SWP_SHOWWINDOW | SWP_NOACTIVATE);
break;
}
case 3: {
int vy = rcMonitor.top + (monHeight - vh) / 2;
SetWindowPos(&wndTopMost, rcMonitor.right - vw, vy, vw, vh, SWP_SHOWWINDOW | SWP_NOACTIVATE);
break;
}
}
}
return TRUE;
}
void CToolbarDlg::UpdateButtonIcons()
{
CScreenSpyDlg* pParent = (CScreenSpyDlg*)GetParent();
// Control button: Play (start control) or Pause (pause control)
if (pParent->m_bIsCtrl) {
m_btnControl.SetIconDrawFunc(CIconButton::DrawIconPause);
m_tooltip.UpdateTipText(_TR("暂停控制"), &m_btnControl);
} else {
m_btnControl.SetIconDrawFunc(CIconButton::DrawIconPlay);
m_tooltip.UpdateTipText(_TR("控制屏幕"), &m_btnControl);
}
m_btnControl.Invalidate(FALSE);
// Lock button
if (m_bLocked) {
m_btnLock.SetIconDrawFunc(CIconButton::DrawIconLock);
m_tooltip.UpdateTipText(_TR("解锁"), &m_btnLock);
} else {
m_btnLock.SetIconDrawFunc(CIconButton::DrawIconUnlock);
m_tooltip.UpdateTipText(_TR("锁定"), &m_btnLock);
}
m_btnLock.Invalidate(FALSE);
// Position button: show arrow indicating next position
switch (m_nPosition) {
case 0: // currently top, click goes to bottom
m_btnPosition.SetIconDrawFunc(CIconButton::DrawIconArrowDown);
m_tooltip.UpdateTipText(_TR("放下面"), &m_btnPosition);
break;
case 1: // currently bottom, click goes to left
m_btnPosition.SetIconDrawFunc(CIconButton::DrawIconArrowLeft);
m_tooltip.UpdateTipText(_TR("放左边"), &m_btnPosition);
break;
case 2: // currently left, click goes to right
m_btnPosition.SetIconDrawFunc(CIconButton::DrawIconArrowRight);
m_tooltip.UpdateTipText(_TR("放右边"), &m_btnPosition);
break;
default: // currently right, click goes to top
m_btnPosition.SetIconDrawFunc(CIconButton::DrawIconArrowUp);
m_tooltip.UpdateTipText(_TR("放上面"), &m_btnPosition);
break;
}
m_btnPosition.Invalidate(FALSE);
// Opacity button
switch (m_nOpacityLevel) {
case 1:
m_btnOpacity.SetIconDrawFunc(CIconButton::DrawIconOpacityMedium);
m_tooltip.UpdateTipText(_TR("透明75%"), &m_btnOpacity);
break;
case 2:
m_btnOpacity.SetIconDrawFunc(CIconButton::DrawIconOpacityLow);
m_tooltip.UpdateTipText(_TR("透明50%"), &m_btnOpacity);
break;
default:
m_btnOpacity.SetIconDrawFunc(CIconButton::DrawIconOpacityFull);
m_tooltip.UpdateTipText(_TR("透明度"), &m_btnOpacity);
break;
}
m_btnOpacity.Invalidate(FALSE);
// Block input button
if (m_bBlockInput) {
m_btnBlockInput.SetIconDrawFunc(CIconButton::DrawIconBlockInput);
m_tooltip.UpdateTipText(_TR("解除锁定输入"), &m_btnBlockInput);
} else {
m_btnBlockInput.SetIconDrawFunc(CIconButton::DrawIconUnblockInput);
m_tooltip.UpdateTipText(_TR("锁定远程输入"), &m_btnBlockInput);
}
m_btnBlockInput.Invalidate(FALSE);
// Status info button
if (m_bShowStatusInfo) {
m_btnStatusInfo.SetIconDrawFunc(CIconButton::DrawIconInfo);
m_tooltip.UpdateTipText(_TR("隐藏状态信息"), &m_btnStatusInfo);
} else {
m_btnStatusInfo.SetIconDrawFunc(CIconButton::DrawIconInfoHide);
m_tooltip.UpdateTipText(_TR("显示状态信息"), &m_btnStatusInfo);
}
m_btnStatusInfo.Invalidate(FALSE);
// Audio button (Y)
if (pParent->m_Settings.AudioEnabled) {
m_btnY.SetIconDrawFunc(CIconButton::DrawIconAudioOn);
m_tooltip.UpdateTipText(_TR("关闭系统音频"), &m_btnY);
} else {
m_btnY.SetIconDrawFunc(CIconButton::DrawIconAudioOff);
m_tooltip.UpdateTipText(_TR("打开系统音频"), &m_btnY);
}
m_btnY.Invalidate(FALSE);
}
void CToolbarDlg::LayoutButtons()
{
int btnSize = 32;
int btnSpacing = 8;
int btnCount = 16;
CWnd* btns[] = {
&m_btnExit,
&m_btnControl,
&m_btnLock,
&m_btnPosition,
&m_btnOpacity,
&m_btnSwitchScreen,
&m_btnBlockInput,
&m_btnStatusInfo,
&m_btnQuality,
&m_btnRestoreConsole,
&m_btnX, // 预留按钮 X
&m_btnY, // 预留按钮 Y
&m_btnZ, // 预留按钮 Z
&m_btnScreenshot,
&m_btnMinimize,
&m_btnClose,
};
int margin = (m_nHeight - btnSize) / 2; // 4px 边距
if (m_nPosition <= 1) {
// 水平布局 (上/下) — 窗口宽度为 320, 按钮从左边距开始排列
for (int i = 0; i < btnCount; i++) {
btns[i]->SetWindowPos(NULL, margin + i * (btnSize + btnSpacing), margin, btnSize, btnSize, SWP_NOZORDER);
}
} else {
// 垂直布局 (左/右) — 窗口宽度为 40, 按钮从上边距开始排列
for (int i = 0; i < btnCount; i++) {
btns[i]->SetWindowPos(NULL, margin, margin + i * (btnSize + btnSpacing), btnSize, btnSize, SWP_NOZORDER);
}
}
}
void CToolbarDlg::OnBnClickedMinimize()
{
// 隐藏工具栏自身并最小化父窗口
ShowWindow(SW_HIDE);
m_bVisible = false;
GetParent()->ShowWindow(SW_MINIMIZE);
}
BOOL CToolbarDlg::OnEraseBkgnd(CDC* pDC)
{
CRect rect;
GetClientRect(&rect);
pDC->FillSolidRect(rect, RGB(40, 40, 40));
return TRUE;
}
void CToolbarDlg::OnBnClickedLock()
{
m_bLocked = !m_bLocked;
UpdateButtonIcons();
SaveSettings();
}
void CToolbarDlg::OnBnClickedPosition()
{
m_nPosition = (m_nPosition + 1) % 4;
UpdateButtonIcons();
LayoutButtons();
UpdatePosition();
SaveSettings();
}
void CToolbarDlg::UpdatePosition()
{
RECT rcMonitor = GetParentMonitorRect();
int monWidth = rcMonitor.right - rcMonitor.left;
int monHeight = rcMonitor.bottom - rcMonitor.top;
int hw = 640;
int vw = 40;
int vh = 640;
int hx = rcMonitor.left + (monWidth - hw) / 2;
switch (m_nPosition) {
case 0:
SetWindowPos(&wndTopMost, hx, rcMonitor.top, hw, m_nHeight, SWP_NOACTIVATE);
break;
case 1:
SetWindowPos(&wndTopMost, hx, rcMonitor.bottom - m_nHeight, hw, m_nHeight, SWP_NOACTIVATE);
break;
case 2: {
int vy = rcMonitor.top + (monHeight - vh) / 2;
SetWindowPos(&wndTopMost, rcMonitor.left, vy, vw, vh, SWP_NOACTIVATE);
break;
}
case 3: {
int vy = rcMonitor.top + (monHeight - vh) / 2;
SetWindowPos(&wndTopMost, rcMonitor.right - vw, vy, vw, vh, SWP_NOACTIVATE);
break;
}
}
}
void CToolbarDlg::LoadSettings()
{
m_bLocked = THIS_CFG.GetInt("toolbar", "Locked", 0) != 0;
int pos = THIS_CFG.GetInt("toolbar", "Position", 0);
m_nPosition = (pos >= 0 && pos < 4) ? pos : 0;
int opa = THIS_CFG.GetInt("toolbar", "OpacityLevel", 0);
m_nOpacityLevel = (opa >= 0 && opa < 3) ? opa : 0;
m_bShowStatusInfo = THIS_CFG.GetInt("toolbar", "ShowStatusInfo", 1) != 0;
}
void CToolbarDlg::SaveSettings()
{
THIS_CFG.SetInt("toolbar", "Locked", m_bLocked ? 1 : 0);
THIS_CFG.SetInt("toolbar", "Position", m_nPosition);
THIS_CFG.SetInt("toolbar", "OpacityLevel", m_nOpacityLevel);
THIS_CFG.SetInt("toolbar", "ShowStatusInfo", m_bShowStatusInfo ? 1 : 0);
}
void CToolbarDlg::ApplyOpacity()
{
// 透明度级别: 0=100%(255), 1=75%(191), 2=50%(128)
BYTE opacity;
switch (m_nOpacityLevel) {
case 1:
opacity = 191;
break; // 75%
case 2:
opacity = 128;
break; // 50%
default:
opacity = 255;
break; // 100%
}
SetLayeredWindowAttributes(0, opacity, LWA_ALPHA);
}
void CToolbarDlg::OnBnClickedOpacity()
{
m_nOpacityLevel = (m_nOpacityLevel + 1) % 3;
ApplyOpacity();
UpdateButtonIcons();
SaveSettings();
// 同步状态信息窗口的透明度
CScreenSpyDlg* pParent = (CScreenSpyDlg*)GetParent();
if (pParent && pParent->m_pStatusInfoWnd) {
pParent->m_pStatusInfoWnd->SetOpacityLevel(m_nOpacityLevel);
}
}
void CToolbarDlg::OnBnClickedSwitchScreen()
{
GetParent()->PostMessage(WM_SYSCOMMAND, IDM_SWITCHSCREEN, 0);
}
void CToolbarDlg::OnBnClickedBlockInput()
{
GetParent()->PostMessage(WM_SYSCOMMAND, IDM_BLOCK_INPUT, 0);
}
void CToolbarDlg::OnBnClickedStatusInfo()
{
m_bShowStatusInfo = !m_bShowStatusInfo;
UpdateButtonIcons();
SaveSettings();
// 通知父窗口显示/隐藏状态窗口
GetParent()->PostMessage(WM_COMMAND,
m_bShowStatusInfo ? ID_SHOW_STATUS_INFO : ID_HIDE_STATUS_INFO, 0);
}
void CToolbarDlg::OnBnClickedQuality()
{
CMenu menu;
menu.CreatePopupMenu();
menu.AppendMenuL(MF_STRING, IDM_QUALITY_OFF, "关闭(&O)");
menu.AppendMenuL(MF_STRING, IDM_ADAPTIVE_QUALITY, "自适应(&A)");
menu.AppendMenu(MF_SEPARATOR);
menu.AppendMenuL(MF_STRING, IDM_QUALITY_ULTRA, "Ultra (25FPS, DIFF)");
menu.AppendMenuL(MF_STRING, IDM_QUALITY_HIGH, "High (20FPS, RGB565)");
menu.AppendMenuL(MF_STRING, IDM_QUALITY_GOOD, "Good (20FPS, H264)");
menu.AppendMenuL(MF_STRING, IDM_QUALITY_MEDIUM, "Medium (15FPS, H264)");
menu.AppendMenuL(MF_STRING, IDM_QUALITY_LOW, "Low (12FPS, H264)");
menu.AppendMenuL(MF_STRING, IDM_QUALITY_MINIMAL, "Minimal (8FPS, H264)");
// 勾选当前质量
CScreenSpyDlg* pParent = (CScreenSpyDlg*)GetParent();
if (pParent->m_Settings.QualityLevel == QUALITY_DISABLED) {
menu.CheckMenuItem(IDM_QUALITY_OFF, MF_CHECKED);
} else if (pParent->m_AdaptiveQuality.enabled) {
menu.CheckMenuItem(IDM_ADAPTIVE_QUALITY, MF_CHECKED);
} else if (pParent->m_AdaptiveQuality.currentLevel >= 0 && pParent->m_AdaptiveQuality.currentLevel < QUALITY_COUNT) {
menu.CheckMenuItem(IDM_QUALITY_ULTRA + pParent->m_AdaptiveQuality.currentLevel, MF_CHECKED);
}
// 弹出菜单
CRect rc;
m_btnQuality.GetWindowRect(&rc);
UINT cmd = menu.TrackPopupMenu(TPM_RETURNCMD | TPM_NONOTIFY, rc.right, rc.top, this);
if (cmd) {
GetParent()->PostMessage(WM_SYSCOMMAND, cmd, 0);
}
}
void CToolbarDlg::OnBnClickedRestoreConsole()
{
CScreenSpyDlg* pParent = (CScreenSpyDlg*)GetParent();
if (pParent) {
BeginWaitCursor();
BYTE bToken = CMD_RESTORE_CONSOLE;
pParent->m_ContextObject->Send2Client(&bToken, 1);
Sleep(1000); // 等待会话切换完成
EndWaitCursor();
}
}
void CToolbarDlg::OnBnClickedX()
{
// 切换窗口(类似 Alt+Tab
CScreenSpyDlg* pParent = (CScreenSpyDlg*)GetParent();
if (pParent && pParent->m_ContextObject) {
BYTE bToken = CMD_SWITCH_WINDOW;
pParent->m_ContextObject->Send2Client(&bToken, 1);
}
}
void CToolbarDlg::OnBnClickedY()
{
// 切换系统音频
CScreenSpyDlg* pParent = (CScreenSpyDlg*)GetParent();
if (pParent && pParent->m_ContextObject) {
// 切换音频状态
pParent->m_Settings.AudioEnabled = !pParent->m_Settings.AudioEnabled;
// 发送控制命令到客户端
pParent->SendAudioCtrl(pParent->m_Settings.AudioEnabled ? CYCLEAUDIO_ENABLE : CYCLEAUDIO_DISABLE, 1);
// 如果关闭音频,停止本地播放
if (!pParent->m_Settings.AudioEnabled) {
pParent->StopAudioPlayback();
}
// 更新系统菜单勾选状态
CMenu* SysMenu = pParent->GetSystemMenu(FALSE);
if (SysMenu) {
SysMenu->CheckMenuItem(IDM_AUDIO_TOGGLE, pParent->m_Settings.AudioEnabled ? MF_CHECKED : MF_UNCHECKED);
}
// 更新工具栏按钮图标
UpdateButtonIcons();
}
}
void CToolbarDlg::OnBnClickedZ()
{
// TODO: 预留按钮 Z 的响应函数
}
void CToolbarDlg::OnBnClickedScreenshot()
{
CScreenSpyDlg* pParent = (CScreenSpyDlg*)GetParent();
if (pParent) {
pParent->SaveSnapshot();
}
}
BOOL CToolbarDlg::PreTranslateMessage(MSG* pMsg)
{
if (m_tooltip.GetSafeHwnd()) {
m_tooltip.RelayEvent(pMsg);
}
// 不拦截这些消息,让它们继续传播到父窗口 (ScreenSpyDlg) 处理远程转发
switch (pMsg->message) {
case WM_MOUSEWHEEL:
case WM_MOUSEHWHEEL:
case WM_KEYDOWN:
case WM_KEYUP:
case WM_SYSKEYDOWN:
case WM_SYSKEYUP:
return FALSE;
}
return __super::PreTranslateMessage(pMsg);
}