1. 实现单次对话功能,支持语音录制和数据传输
2. 优化静音检测算法,改进RMS平滑处理 3. 添加自动化代理处理,支持点击、拖拽、输入等操作 4. 修复多屏幕环境下鼠标定位问题
This commit is contained in:
Vendored
+8
-4
@@ -29,15 +29,14 @@ if(APPLE)
|
||||
find_library(APPLICATIONSERVICES_LIBRARY ApplicationServices REQUIRED)
|
||||
target_link_libraries(autogui-cpp PUBLIC ${APPLICATIONSERVICES_LIBRARY})
|
||||
|
||||
# Windows平台
|
||||
# Windows平台
|
||||
elseif(WIN32)
|
||||
# 链接User32.lib (提供SendInput, GetCursorPos等API)
|
||||
target_link_libraries(autogui-cpp PUBLIC User32)
|
||||
|
||||
# Linux/Unix平台
|
||||
# Linux/Unix平台
|
||||
elseif(UNIX AND NOT APPLE)
|
||||
# Linux需要X11后端(Wayland尚未支持)
|
||||
# Linux需要X11后端
|
||||
find_package(X11 REQUIRED)
|
||||
# 查找Xtst库(XTest扩展)
|
||||
find_library(X11_Xtst_LIB Xtst)
|
||||
@@ -49,15 +48,20 @@ elseif(UNIX AND NOT APPLE)
|
||||
if(NOT X11_Xext_LIB)
|
||||
message(FATAL_ERROR "Xext library not found.")
|
||||
endif()
|
||||
# 查找XRandR库(Xrandr扩展)
|
||||
find_library(X11_Xrandr_LIB Xrandr)
|
||||
if(NOT X11_Xrandr_LIB)
|
||||
message(FATAL_ERROR "XRandR library not found. Install libxrandr-dev.")
|
||||
endif()
|
||||
# 链接所有必需的X11库
|
||||
target_link_libraries(autogui-cpp PUBLIC
|
||||
${X11_LIBRARIES}
|
||||
${X11_Xtst_LIB}
|
||||
${X11_Xext_LIB}
|
||||
${X11_Xrandr_LIB}
|
||||
)
|
||||
target_include_directories(autogui-cpp PUBLIC ${X11_INCLUDE_DIR})
|
||||
endif()
|
||||
|
||||
# 集成方式: add_subdirectory
|
||||
# 在你的项目CMakeLists.txt中:
|
||||
# add_subdirectory(autogui-cpp)
|
||||
|
||||
Vendored
+193
-14
@@ -10,11 +10,10 @@
|
||||
#include <iostream>
|
||||
#include <random>
|
||||
#include <thread>
|
||||
|
||||
#include <cstring>
|
||||
#ifndef M_PI
|
||||
# define M_PI 3.14159265358979323846
|
||||
#endif
|
||||
|
||||
namespace AutoGUI {
|
||||
|
||||
// 内部辅助函数
|
||||
@@ -33,6 +32,139 @@ Robot::Point getCurrentPosition() { return Robot::Mouse::GetPosition(); }
|
||||
|
||||
} // namespace
|
||||
|
||||
#if defined(__linux__)
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/extensions/Xrandr.h>
|
||||
#include <algorithm>
|
||||
|
||||
// 获取所有屏幕信息
|
||||
std::vector<ScreenInfo> getAllScreens() {
|
||||
std::vector<ScreenInfo> screens;
|
||||
Display* display = XOpenDisplay(nullptr);
|
||||
if (!display) return screens;
|
||||
|
||||
XRRScreenResources* resources = XRRGetScreenResources(display, DefaultRootWindow(display));
|
||||
if (resources) {
|
||||
for (int i = 0; i < resources->noutput; i++) {
|
||||
XRROutputInfo* output = XRRGetOutputInfo(display, resources, resources->outputs[i]);
|
||||
if (output && output->connection == RR_Connected && output->crtc) {
|
||||
XRRCrtcInfo* crtc = XRRGetCrtcInfo(display, resources, output->crtc);
|
||||
if (crtc) {
|
||||
ScreenInfo info;
|
||||
info.id = i;
|
||||
info.x = crtc->x;
|
||||
info.y = crtc->y;
|
||||
info.width = crtc->width;
|
||||
info.height = crtc->height;
|
||||
info.isPrimary = (output->name && strcmp(output->name, "primary") == 0);
|
||||
// 或者使用 XRRGetOutputPrimary 来判断
|
||||
screens.push_back(info);
|
||||
XRRFreeCrtcInfo(crtc);
|
||||
}
|
||||
XRRFreeOutputInfo(output);
|
||||
}
|
||||
}
|
||||
XRRFreeScreenResources(resources);
|
||||
}
|
||||
XCloseDisplay(display);
|
||||
return screens;
|
||||
}
|
||||
|
||||
// 获取当前鼠标所在的屏幕
|
||||
ScreenInfo getCurrentScreen() {
|
||||
auto screens = getAllScreens();
|
||||
if (screens.empty()) return {0, 0, 0, 1920, 1080, true};
|
||||
|
||||
// 获取当前鼠标位置(虚拟桌面绝对坐标)
|
||||
Robot::Point mouse = position();
|
||||
|
||||
// 找到包含该点的屏幕
|
||||
for (const auto& screen : screens) {
|
||||
if (mouse.x >= screen.x && mouse.x < screen.x + screen.width &&
|
||||
mouse.y >= screen.y && mouse.y < screen.y + screen.height) {
|
||||
return screen;
|
||||
}
|
||||
}
|
||||
|
||||
// 默认返回主屏或第一个屏幕
|
||||
auto it = std::find_if(screens.begin(), screens.end(),
|
||||
[](const ScreenInfo& s) { return s.isPrimary; });
|
||||
return (it != screens.end()) ? *it : screens[0];
|
||||
}
|
||||
|
||||
// 相对于当前屏幕移动
|
||||
void moveToOnCurrentScreen(int x, int y, double duration) {
|
||||
const ScreenInfo current = getCurrentScreen();
|
||||
// 转换为虚拟桌面绝对坐标
|
||||
int absX = current.x + x;
|
||||
int absY = current.y + y;
|
||||
moveTo(absX, absY, duration);
|
||||
}
|
||||
|
||||
// 获取当前屏幕尺寸
|
||||
Robot::Point getScreenSize(int screenId) {
|
||||
if (screenId == -1) {
|
||||
ScreenInfo current = getCurrentScreen();
|
||||
return {current.width, current.height};
|
||||
}
|
||||
auto screens = getAllScreens();
|
||||
for (const auto& s : screens) {
|
||||
if (s.id == screenId) return {s.width, s.height};
|
||||
}
|
||||
return {1920, 1080};
|
||||
}
|
||||
|
||||
#endif
|
||||
#if defined(_WIN32)
|
||||
#include <Windows.h>
|
||||
|
||||
std::vector<ScreenInfo> getAllScreens() {
|
||||
std::vector<ScreenInfo> screens;
|
||||
EnumDisplayMonitors(nullptr, nullptr,
|
||||
[](HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData) -> BOOL {
|
||||
auto* screens = reinterpret_cast<std::vector<ScreenInfo>*>(dwData);
|
||||
MONITORINFOEX info;
|
||||
info.cbSize = sizeof(info);
|
||||
if (GetMonitorInfo(hMonitor, &info)) {
|
||||
ScreenInfo si;
|
||||
si.id = screens->size();
|
||||
si.x = info.rcMonitor.left;
|
||||
si.y = info.rcMonitor.top;
|
||||
si.width = info.rcMonitor.right - info.rcMonitor.left;
|
||||
si.height = info.rcMonitor.bottom - info.rcMonitor.top;
|
||||
si.isPrimary = (info.dwFlags & MONITORINFOF_PRIMARY) != 0;
|
||||
screens->push_back(si);
|
||||
}
|
||||
return TRUE;
|
||||
}, reinterpret_cast<LPARAM>(&screens));
|
||||
return screens;
|
||||
}
|
||||
|
||||
ScreenInfo getCurrentScreen() {
|
||||
// 获取当前鼠标位置
|
||||
POINT pt;
|
||||
GetCursorPos(&pt);
|
||||
// 查找包含该点的显示器
|
||||
HMONITOR hMonitor = MonitorFromPoint(pt, MONITOR_DEFAULTTONEAREST);
|
||||
MONITORINFOEX info;
|
||||
info.cbSize = sizeof(info);
|
||||
GetMonitorInfo(hMonitor, &info);
|
||||
|
||||
ScreenInfo si;
|
||||
si.x = info.rcMonitor.left;
|
||||
si.y = info.rcMonitor.top;
|
||||
si.width = info.rcMonitor.right - info.rcMonitor.left;
|
||||
si.height = info.rcMonitor.bottom - info.rcMonitor.top;
|
||||
return si;
|
||||
}
|
||||
|
||||
void moveToOnCurrentScreen(int x, int y, double duration) {
|
||||
ScreenInfo current = getCurrentScreen();
|
||||
moveTo(current.x + x, current.y + y, duration);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
// 实现主要API函数
|
||||
void moveTo(int x, int y, double duration) {
|
||||
Robot::Point target{x, y};
|
||||
@@ -269,37 +401,84 @@ void sleep(double seconds) {
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(_WIN32)
|
||||
#include <Windows.h>
|
||||
|
||||
#elif defined(__APPLE__)
|
||||
#include <CoreGraphics/CoreGraphics.h>
|
||||
|
||||
#elif defined(__linux__)
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/extensions/Xrandr.h>
|
||||
#endif
|
||||
|
||||
// 平台特定函数实现
|
||||
Robot::Point size() {
|
||||
// 平台特定实现
|
||||
#ifdef _WIN32
|
||||
// Windows实现
|
||||
#include <Windows.h>
|
||||
int width = GetSystemMetrics(SM_CXSCREEN);
|
||||
int height = GetSystemMetrics(SM_CYSCREEN);
|
||||
return {width, height};
|
||||
|
||||
#elif defined(__APPLE__)
|
||||
// macOS实现
|
||||
#include <CoreGraphics/CoreGraphics.h>
|
||||
CGRect mainDisplayBounds = CGDisplayBounds(CGMainDisplayID());
|
||||
int width = static_cast<int>(CGRectGetWidth(mainDisplayBounds));
|
||||
int height = static_cast<int>(CGRectGetHeight(mainDisplayBounds));
|
||||
return {width, height};
|
||||
|
||||
#elif defined(__linux__)
|
||||
// Linux实现(X11)
|
||||
#include <X11/Xlib.h>
|
||||
|
||||
Display *display = XOpenDisplay(nullptr);
|
||||
if (display) {
|
||||
const Screen *screen = DefaultScreenOfDisplay(display);
|
||||
const int width = WidthOfScreen(screen);
|
||||
const int height = HeightOfScreen(screen);
|
||||
XCloseDisplay(display);
|
||||
return {width, height};
|
||||
if (!display) return {1920, 1080};
|
||||
|
||||
int width = 0, height = 0;
|
||||
|
||||
// 使用 XRRGetScreenResources (兼容 XRandR 1.2+,比 Current 版本兼容性更好)
|
||||
XRRScreenResources *resources = XRRGetScreenResources(display, DefaultRootWindow(display));
|
||||
if (resources) {
|
||||
RROutput target_output = None;
|
||||
|
||||
// 条件编译:只在 XRandR 1.3+ 时使用 Primary Output 功能
|
||||
#if defined(RANDR_MAJOR) && defined(RANDR_MINOR)
|
||||
#if RANDR_MAJOR > 1 || (RANDR_MAJOR == 1 && RANDR_MINOR >= 3)
|
||||
target_output = XRRGetOutputPrimary(display, DefaultRootWindow(display));
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// 如果没有获取到主显示器(或版本太低),使用第一个已连接的显示器
|
||||
if (target_output == None) {
|
||||
for (int i = 0; i < resources->noutput; i++) {
|
||||
XRROutputInfo *info = XRRGetOutputInfo(display, resources, resources->outputs[i]);
|
||||
if (info) {
|
||||
if (info->connection == 0) {
|
||||
target_output = resources->outputs[i];
|
||||
XRRFreeOutputInfo(info);
|
||||
break;
|
||||
}
|
||||
XRRFreeOutputInfo(info);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 获取选中显示器的分辨率
|
||||
if (target_output != None) {
|
||||
XRROutputInfo *output_info = XRRGetOutputInfo(display, resources, target_output);
|
||||
if (output_info && output_info->crtc) {
|
||||
XRRCrtcInfo *crtc_info = XRRGetCrtcInfo(display, resources, output_info->crtc);
|
||||
if (crtc_info) {
|
||||
width = static_cast<int>(crtc_info->width);
|
||||
height = static_cast<int>(crtc_info->height);
|
||||
XRRFreeCrtcInfo(crtc_info);
|
||||
}
|
||||
XRRFreeOutputInfo(output_info);
|
||||
}
|
||||
}
|
||||
XRRFreeScreenResources(resources);
|
||||
}
|
||||
return {1920, 1080}; // 默认值
|
||||
|
||||
XCloseDisplay(display);
|
||||
return (width > 0 && height > 0) ? Robot::Point{width, height} : Robot::Point{1920, 1080};
|
||||
|
||||
#else
|
||||
// 其他平台
|
||||
|
||||
Vendored
+21
@@ -125,6 +125,27 @@ inline bool isSpecialKey(const std::string& key) {
|
||||
return std::find(specialKeys.begin(), specialKeys.end(), lower) != specialKeys.end();
|
||||
}
|
||||
|
||||
// 解决多屏幕移动鼠标问题
|
||||
struct ScreenInfo {
|
||||
int id; // 屏幕ID
|
||||
int x, y; // 相对于虚拟桌面原点的偏移
|
||||
int width, height;// 屏幕尺寸
|
||||
bool isPrimary; // 是否主屏
|
||||
};
|
||||
|
||||
// 获取所有屏幕信息
|
||||
std::vector<ScreenInfo> getAllScreens();
|
||||
|
||||
// 获取当前鼠标所在的屏幕
|
||||
ScreenInfo getCurrentScreen();
|
||||
|
||||
// 相对于当前屏幕移动鼠标(以当前屏幕左上角为原点)
|
||||
void moveToOnCurrentScreen(int x, int y, double duration = 0.0);
|
||||
|
||||
// 获取指定屏幕的尺寸(替代原来的size(),支持多屏)
|
||||
Robot::Point getScreenSize(int screenId = -1); // -1表示当前屏幕
|
||||
|
||||
|
||||
// 主要 API 函数
|
||||
/**
|
||||
* @brief 移动鼠标到指定位置
|
||||
|
||||
@@ -53,7 +53,7 @@ make
|
||||
```
|
||||
|
||||
注意:本项目只是Yosuga的客户端部分,完整的还包括服务端
|
||||
- 服务端项目地址见:
|
||||
- 服务端项目地址见:https://github.com/Misakityan/Yosuga_server
|
||||
|
||||
当前支持平台(已测试过的):
|
||||
- Windows: Windows 10
|
||||
|
||||
@@ -27,7 +27,7 @@ private:
|
||||
static QMutex m_mutex;
|
||||
private slots:
|
||||
// 业务接收槽函数
|
||||
|
||||
void onRecordingFinished_Byte(const QByteArray &wavData);
|
||||
public:
|
||||
// 单例访问点
|
||||
static AppCore *getInstance();
|
||||
@@ -36,4 +36,7 @@ public:
|
||||
|
||||
~AppCore() override;
|
||||
|
||||
public:
|
||||
// 单次对话
|
||||
void SingleExchange();
|
||||
};
|
||||
@@ -9,6 +9,9 @@
|
||||
#include "AutoAgentHandle.h"
|
||||
#include "ScreenShotReqDataHandle.h"
|
||||
|
||||
#include "AudioInput.h"
|
||||
#include "NetWorkDO.h"
|
||||
#include "websocketmanager.h"
|
||||
// 初始化静态成员
|
||||
QScopedPointer<AppCore> AppCore::m_instance;
|
||||
QMutex AppCore::m_mutex;
|
||||
@@ -40,6 +43,15 @@ AppCore::AppCore(QObject *parent) : QObject(parent)
|
||||
AudioDataHandle::getInstance();
|
||||
AutoAgentHandle::getInstance();
|
||||
ScreenShotReqDataHandle::getInstance();
|
||||
// 注入发送接口
|
||||
NetworkDO::getInstance()->registerSender([](const QString& type, const QJsonObject& data){
|
||||
WebSocketClient::getInstance()->sendJson(type, data);
|
||||
});
|
||||
// TODO Test
|
||||
AudioInput::getInstance()->setAudioPath(QDir::currentPath(), "/temp.wav");
|
||||
// 连接必要的信号
|
||||
connect(AudioInput::getInstance(), &AudioInput::recordingFinished_Byte,
|
||||
this, &AppCore::onRecordingFinished_Byte); // 录音完成信号
|
||||
}
|
||||
|
||||
AppCore::~AppCore()
|
||||
@@ -52,3 +64,16 @@ AppCore::~AppCore()
|
||||
|
||||
qDebug() << "AppCore destroyed";
|
||||
}
|
||||
|
||||
void AppCore::SingleExchange() {
|
||||
// 开始录音,录音结束后会触发录音完成信号
|
||||
AudioInput::getInstance()->startAutoStopAudio(AudioInput::getInstance()->getSilenceThreshold(), 800);
|
||||
}
|
||||
|
||||
void AppCore::onRecordingFinished_Byte(const QByteArray &wavData) {
|
||||
// 将录音数据发送给服务端
|
||||
AudioDataTransferObject packet;
|
||||
packet.setData("isStream", false).setData("data", wavData.toBase64().data());
|
||||
NetworkDO::getInstance()->sendPacket(packet);
|
||||
}
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ public:
|
||||
// 静态工厂方法
|
||||
static ScreenShotDataTransferObject fromJson(const QJsonObject& json);
|
||||
|
||||
[[nodiscard]] QString type() const override { return "screenshot_req"; }
|
||||
[[nodiscard]] QString type() const override { return "screenshot_data"; }
|
||||
|
||||
// 序列化
|
||||
[[nodiscard]] QJsonObject toJson() const override; // 通过多态即可统一调用方式
|
||||
|
||||
@@ -72,7 +72,7 @@ void NetworkDO::onDataReceived(const QString& type, const QJsonObject& data)
|
||||
else if (type == "auto_agent") {
|
||||
emit autoAgentPacketReceived(AutoAgentDataObject::fromJson(data));
|
||||
}
|
||||
else if (type == "screenshot_req") {
|
||||
else if (type == "screenshot_data") {
|
||||
emit screenShotPacketReceived(ScreenShotDataTransferObject::fromJson(data));
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -34,7 +34,7 @@ ScreenShotDataTransferObject ScreenShotDataTransferObject::fromJson(const QJsonO
|
||||
|
||||
// 调用构造函数创建对象
|
||||
return ScreenShotDataTransferObject(owner, isSuccess, realtimeScreenShot,
|
||||
width, height, describeInfo);
|
||||
width, height, describeInfo, LLMResponse);
|
||||
}
|
||||
|
||||
// 序列化为 JSON
|
||||
|
||||
@@ -148,5 +148,7 @@ private:
|
||||
qreal m_silenceThreshold = 1200; /// 静音阈值
|
||||
int m_silenceDuration = 1500; /// 静音持续时间
|
||||
qreal m_smoothRms = 0.0; /// 平滑RMS值(用于防止低频杂波突然打断静音检测)
|
||||
|
||||
bool m_hasVoiceDetected = false; /// 是否已检测到人声
|
||||
};
|
||||
|
||||
|
||||
@@ -148,7 +148,7 @@ void AudioInput::onReadyRead()
|
||||
const qreal currentRms = calculateRMS(data);
|
||||
m_rmsValue = currentRms;
|
||||
// 计算平滑RMS (用于防止低频杂波突然打断静音检测)
|
||||
constexpr qreal alpha = 0.3; // 70% 历史权重, 30% 当前权重
|
||||
constexpr qreal alpha = 0.15; // 85% 历史权重, 15% 当前权重
|
||||
if (qFuzzyIsNull(m_smoothRms)) {
|
||||
// 如果是第一帧数据,直接赋值,避免从0开始慢慢爬升
|
||||
m_smoothRms = currentRms;
|
||||
@@ -163,13 +163,30 @@ void AudioInput::onReadyRead()
|
||||
qDebug() << "Raw:" << currentRms << " Smooth:" << m_smoothRms;
|
||||
|
||||
if (m_smoothRms < m_silenceThreshold) {
|
||||
// 静音状态
|
||||
if (!m_silenceTimer->isActive()) {
|
||||
m_silenceTimer->start(m_silenceDuration);
|
||||
// [当前是静音]
|
||||
|
||||
// 如果之前已经检测到过人声(说明是话说完了,或者是句间停顿)
|
||||
if (m_hasVoiceDetected) {
|
||||
// 启动/保持“短时”静音检测 (由 AppCore 传入,例如 500ms 或 1500ms)
|
||||
if (!m_silenceTimer->isActive()) {
|
||||
m_silenceTimer->start(m_silenceDuration);
|
||||
}
|
||||
// 如果 Timer 正在运行,就让它继续倒计时,超时会自动触发 stopAudio
|
||||
}
|
||||
else {
|
||||
// [还没有检测到过人声] (起始静音)
|
||||
// 这里不需要做额外操作,startAutoStopAudio 里设置的 5000ms 长定时器在跑
|
||||
// 允许用户深呼吸或准备
|
||||
}
|
||||
} else {
|
||||
// 有声音,重置定时器
|
||||
// [当前有声音]
|
||||
m_hasVoiceDetected = true; // 标记:已经有人说话了
|
||||
|
||||
// 重置静音定时器
|
||||
// 只要有人说话,就不断重置定时器,防止断录
|
||||
m_silenceTimer->stop();
|
||||
// 这里可以预设启动,也可以不启动,只要有声音就会一直 stop
|
||||
// 为了安全,设为 silenceDuration
|
||||
m_silenceTimer->start(m_silenceDuration);
|
||||
}
|
||||
}
|
||||
@@ -246,11 +263,20 @@ void AudioInput::startAutoStopAudio(const qreal silenceThreshold, const int sile
|
||||
m_silenceThreshold = silenceThreshold;
|
||||
m_silenceDuration = silenceDuration;
|
||||
|
||||
// 重置状态
|
||||
m_hasVoiceDetected = false;
|
||||
m_smoothRms = 0.0;
|
||||
startAudio();
|
||||
|
||||
// 延迟200ms是为了避开硬件启动时的爆音,但不需要立即启动短时倒计时
|
||||
// 延迟启动静音检测,给一点缓冲时间
|
||||
QTimer::singleShot(200, this, [this](){
|
||||
m_silenceTimer->start(m_silenceDuration);
|
||||
if(isAutoRecording) { // 确保还在录音状态
|
||||
// 如果还没检测到声音,给5秒的等待时间;如果检测到了,逻辑由onReadyRead接管
|
||||
if(!m_hasVoiceDetected) {
|
||||
m_silenceTimer->start(5000); // 5秒没声音就停止
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -285,8 +311,12 @@ void AudioInput::thresholdTimeout()
|
||||
// 防止浮点误差导致负数
|
||||
if (variance < 0) variance = 0;
|
||||
const double stdDev = std::sqrt(variance);
|
||||
|
||||
// 增加一个固定的偏移量 offset
|
||||
// 确保即使环境有轻微波动,也不会触发录音
|
||||
constexpr double offset = 80.0;
|
||||
// 阈值 = 均值 + 2 * 标准差
|
||||
const double bestThreshold = mean + 3 * stdDev;
|
||||
const double bestThreshold = mean + (3 * stdDev) + offset;
|
||||
m_silenceThreshold = std::max(bestThreshold, 150.0);
|
||||
m_silenceThreshold = std::min(m_silenceThreshold, 30000.0);
|
||||
qDebug() << "Auto Threshold Calc -> Mean:" << mean
|
||||
|
||||
@@ -42,24 +42,40 @@ AutoAgentHandle::~AutoAgentHandle()
|
||||
}
|
||||
|
||||
void AutoAgentHandle::onAutoAgentPacketReceived(const AutoAgentDataObject &packet) {
|
||||
qDebug() << "Received AutoAgent packet: " << packet.getAction();
|
||||
if (packet.getAction() == "click") { // 单击
|
||||
qDebug() << "Click: " << packet.getX1() << ", " << packet.getY1();
|
||||
AutoGUI::moveTo(packet.getX1(), packet.getY1(), 0.6);
|
||||
AutoGUI::moveToOnCurrentScreen(packet.getX1(), packet.getY1(), 0.6);
|
||||
AutoGUI::click(packet.getX1(), packet.getY1());
|
||||
}
|
||||
if (packet.getAction() == "left_double") { // 双击
|
||||
qDebug() << "Double click: " << packet.getX1() << ", " << packet.getY1();
|
||||
AutoGUI::moveTo(packet.getX1(), packet.getY1(), 0.6);
|
||||
AutoGUI::moveToOnCurrentScreen(packet.getX1(), packet.getY1(), 0.6);
|
||||
AutoGUI::leftDouble(packet.getX1(), packet.getY1());
|
||||
}
|
||||
if (packet.getAction() == "right_single") { // 右键单击
|
||||
qDebug() << "Right click: " << packet.getX1() << ", " << packet.getY1();
|
||||
AutoGUI::moveTo(packet.getX1(), packet.getY1(), 0.6);
|
||||
AutoGUI::moveToOnCurrentScreen(packet.getX1(), packet.getY1(), 0.6);
|
||||
AutoGUI::rightSingle(packet.getX1(), packet.getY1());
|
||||
}
|
||||
if (packet.getAction() == "drag") { // 拖拽
|
||||
qDebug() << "Drag: " << packet.getX1() << ", " << packet.getY1() << " to " << packet.getX2() << ", " << packet.getY2();
|
||||
AutoGUI::drag(packet.getX1(), packet.getY1(), packet.getX2(), packet.getY2(), 0.8);
|
||||
AutoGUI::drag(packet.getX1(), packet.getY1(), packet.getX2(), packet.getY2(), 1.2);
|
||||
}
|
||||
// TODO: 快捷键,输入文本,滚动待实现
|
||||
}
|
||||
if (packet.getAction() == "type") { // 输入文本
|
||||
qDebug() << "Type: " << packet.getContent();
|
||||
AutoGUI::type(packet.getContent().toStdString(), 0.08);
|
||||
}
|
||||
if (packet.getAction() == "scroll") { // 滚动
|
||||
qDebug() << "Scroll: " << packet.getX1() << ", " << packet.getY1() << packet.getDirection();
|
||||
if (packet.getDirection() == "up") {
|
||||
AutoGUI::moveToOnCurrentScreen(packet.getX1(), packet.getY1(), 0.1);
|
||||
AutoGUI::scroll(40, 1);
|
||||
}
|
||||
if (packet.getDirection() == "down") {
|
||||
AutoGUI::moveToOnCurrentScreen(packet.getX1(), packet.getY1(), 0.1);
|
||||
AutoGUI::scroll(40, -1);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -42,6 +42,7 @@ ScreenShotReqDataHandle::ScreenShotReqDataHandle(QObject *parent) : QObject(pare
|
||||
const QString sysText = QString("System: %1 OS Version: %2 Display Server: %3")
|
||||
.arg(sysInfo.osType, sysInfo.osVersion, sysInfo.displayServer);
|
||||
this->m_systemInfo = sysText;
|
||||
qDebug() << "当前平台信息为: " << sysText;
|
||||
}
|
||||
|
||||
ScreenShotReqDataHandle::~ScreenShotReqDataHandle()
|
||||
@@ -55,12 +56,14 @@ void ScreenShotReqDataHandle::onScreenShotPacketReceived(const ScreenShotDataTra
|
||||
const ScreenHelper::ScreenshotResult result = ScreenHelper::captureFocusedScreen(); // 获取当前屏幕截图
|
||||
if (!result.success) { // 如果截图失败
|
||||
// TODO: 考虑失败时候构造一个错误DTO给服务端
|
||||
qDebug() << "截图失败: " << result.errorMsg;
|
||||
return;
|
||||
}
|
||||
ScreenShotDataTransferObject reback; // 构造返回的DTO
|
||||
reback.setData("isSuccess", true).setData("RealTimeScreenShot", result.base64Data)
|
||||
.setData("Width", result.width).setData("Height", result.height)
|
||||
.setData("DescribeInfo", this->m_systemInfo);
|
||||
.setData("DescribeInfo", this->m_systemInfo).setData("LLMResponse", packet.LLMResponse());
|
||||
// 发送DTO
|
||||
NetworkDO::getInstance()->sendPacket(reback);
|
||||
qDebug() << "ScreenShot packet sent to:" << packet.owner();
|
||||
}
|
||||
|
||||
@@ -7,23 +7,22 @@
|
||||
* 基于Ela UI的菜单控件
|
||||
*/
|
||||
|
||||
#include "ElaMenu.h"
|
||||
#include <ElaMenu.h>
|
||||
#include <QMenu>
|
||||
#include <QAction>
|
||||
#include <QPoint>
|
||||
#include <QScopedPointer> // 智能指针
|
||||
|
||||
#include "Setting.h"
|
||||
#include "networkmanager.h"
|
||||
#include "socketmanager.h"
|
||||
|
||||
class Menu : public ElaMenu
|
||||
class Menu final : public ElaMenu
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit Menu(QWidget *parent = nullptr);
|
||||
~Menu();
|
||||
~Menu() override;
|
||||
void showMenu(const QPoint &pos);
|
||||
|
||||
signals:
|
||||
@@ -33,10 +32,11 @@ signals:
|
||||
|
||||
private:
|
||||
void createMenu();
|
||||
QAction *toggleThe; /// 切换主题(全局)
|
||||
QAction *startExchangeAction; /// 开启对话
|
||||
QAction *settingsAction; /// 设置
|
||||
QAction *closeAction; /// 关闭
|
||||
QAction *toggleThe; /// 切换主题(全局)
|
||||
QAction *startSingleExchangeAction; /// 开启单次对话
|
||||
QAction *startContinueExchangeAction; /// 开启连续对话
|
||||
QAction *settingsAction; /// 设置
|
||||
QAction *closeAction; /// 关闭
|
||||
|
||||
QScopedPointer<Setting> settingWindow; // 使用智能指针管理 Setting 窗口
|
||||
|
||||
|
||||
+15
-11
@@ -5,29 +5,29 @@
|
||||
#include <QTimer>
|
||||
|
||||
#include "TextRenderer.h"
|
||||
// #include "AudioInput.h"
|
||||
// #include "AudioOutput.h"
|
||||
#include "AppCore.h"
|
||||
|
||||
Menu::Menu(QWidget *parent)
|
||||
: ElaMenu(parent)
|
||||
{
|
||||
// 设置默认主题
|
||||
eTheme->setThemeMode(ElaThemeType::Dark);
|
||||
|
||||
createMenu();
|
||||
}
|
||||
|
||||
Menu::~Menu()
|
||||
{
|
||||
|
||||
Menu::~Menu() {
|
||||
AppCore::destroy(); // 显式销毁 AppCore
|
||||
}
|
||||
|
||||
void Menu::createMenu()
|
||||
{
|
||||
toggleThe = addAction("切换主题");
|
||||
|
||||
// 单次对话功能按钮
|
||||
startSingleExchangeAction = addAction("单次对话(测试)");
|
||||
|
||||
// 连续对话功能按钮
|
||||
startExchangeAction = addAction("连续对话(测试)");
|
||||
startContinueExchangeAction = addAction("连续对话(测试)");
|
||||
|
||||
// 添加设置按钮
|
||||
settingsAction = addAction("设置");
|
||||
@@ -42,10 +42,14 @@ void Menu::createMenu()
|
||||
toggleTheme();
|
||||
});
|
||||
|
||||
// TODO 连续对话功能,需要优化实现
|
||||
connect(startExchangeAction, &QAction::triggered, this, [this]() {
|
||||
// startExchange();
|
||||
qDebug() << "Start Exchange triggered";
|
||||
// 单次对话功能
|
||||
connect(startSingleExchangeAction, &QAction::triggered, this, []() {
|
||||
qDebug() << "Start SingleExchange triggered";
|
||||
AppCore::getInstance()->SingleExchange();
|
||||
});
|
||||
// 连续对话功能 TODO: 待开发
|
||||
connect(startContinueExchangeAction, &QAction::triggered, this, []() {
|
||||
qDebug() << "Start ContinueExchange triggered";
|
||||
});
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user