Compare commits
4 Commits
Video_Medi
...
master
Author | SHA1 | Date |
---|---|---|
|
ce83ebfc31 | 1 month ago |
|
9b50f5868f | 2 months ago |
|
9cd84530eb | 2 months ago |
|
9a18ef852b | 3 months ago |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,164 @@
|
|||||||
|
#include "DirectInputJoystick.h"
|
||||||
|
#include <QDebug>
|
||||||
|
|
||||||
|
DirectInputJoystick::DirectInputJoystick(QObject *parent) : QObject(parent) {
|
||||||
|
// 确保 COM 库在主线程初始化
|
||||||
|
CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED);
|
||||||
|
}
|
||||||
|
|
||||||
|
DirectInputJoystick::~DirectInputJoystick() {
|
||||||
|
cleanup();
|
||||||
|
CoUninitialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DirectInputJoystick::initialize() {
|
||||||
|
HRESULT hr = DirectInput8Create(
|
||||||
|
GetModuleHandle(nullptr),
|
||||||
|
DIRECTINPUT_VERSION,
|
||||||
|
IID_IDirectInput8,
|
||||||
|
(VOID**)&m_pDirectInput,
|
||||||
|
nullptr
|
||||||
|
);
|
||||||
|
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
emit errorOccurred("无法创建 DirectInput 对象");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 枚举所有摇杆设备
|
||||||
|
hr = m_pDirectInput->EnumDevices(
|
||||||
|
DI8DEVCLASS_GAMECTRL,
|
||||||
|
enumJoysticksCallback,
|
||||||
|
this,
|
||||||
|
DIEDFL_ATTACHEDONLY
|
||||||
|
);
|
||||||
|
|
||||||
|
return SUCCEEDED(hr);
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL CALLBACK DirectInputJoystick::enumJoysticksCallback(const DIDEVICEINSTANCE* instance, VOID* context) {
|
||||||
|
DirectInputJoystick* joystick = static_cast<DirectInputJoystick*>(context);
|
||||||
|
return joystick->setupDevice();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DirectInputJoystick::setupDevice() {
|
||||||
|
if (!m_pDirectInput) return false;
|
||||||
|
|
||||||
|
// 创建设备
|
||||||
|
HRESULT hr = m_pDirectInput->CreateDevice(
|
||||||
|
GUID_Joystick,
|
||||||
|
&m_pJoystick,
|
||||||
|
nullptr
|
||||||
|
);
|
||||||
|
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
emit errorOccurred("无法创建摇杆设备");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置数据格式
|
||||||
|
hr = m_pJoystick->SetDataFormat(&c_dfDIJoystick);
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
emit errorOccurred("设置数据格式失败");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置协作级别
|
||||||
|
hr = m_pJoystick->SetCooperativeLevel(
|
||||||
|
nullptr, // 无窗口句柄
|
||||||
|
DISCL_BACKGROUND | DISCL_NONEXCLUSIVE
|
||||||
|
);
|
||||||
|
|
||||||
|
// 枚举轴并设置范围
|
||||||
|
hr = m_pJoystick->EnumObjects(enumAxesCallback, this, DIDFT_AXIS);
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
emit errorOccurred("枚举摇杆轴失败");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建事件对象
|
||||||
|
m_hEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr);
|
||||||
|
hr = m_pJoystick->SetEventNotification(m_hEvent);
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
emit errorOccurred("设置事件通知失败");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL CALLBACK DirectInputJoystick::enumAxesCallback(const DIDEVICEOBJECTINSTANCE* doi, VOID* context) {
|
||||||
|
DirectInputJoystick* joystick = static_cast<DirectInputJoystick*>(context);
|
||||||
|
DIPROPRANGE diprg;
|
||||||
|
diprg.diph.dwSize = sizeof(DIPROPRANGE);
|
||||||
|
diprg.diph.dwHeaderSize = sizeof(DIPROPHEADER);
|
||||||
|
diprg.diph.dwHow = DIPH_BYID;
|
||||||
|
diprg.diph.dwObj = doi->dwType;
|
||||||
|
diprg.lMin = -1000;
|
||||||
|
diprg.lMax = 1000;
|
||||||
|
|
||||||
|
HRESULT hr = joystick->m_pJoystick->SetProperty(DIPROP_RANGE, &diprg.diph);
|
||||||
|
return SUCCEEDED(hr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DirectInputJoystick::startListening() {
|
||||||
|
if (!m_pJoystick || m_isRunning) return;
|
||||||
|
|
||||||
|
m_isRunning = true;
|
||||||
|
m_workerThread = QThread::create([this]() {
|
||||||
|
m_pJoystick->Acquire();
|
||||||
|
|
||||||
|
while (m_isRunning) {
|
||||||
|
WaitForSingleObject(m_hEvent, INFINITE);
|
||||||
|
|
||||||
|
DIJOYSTATE state;
|
||||||
|
HRESULT hr = m_pJoystick->GetDeviceState(sizeof(DIJOYSTATE), &state);
|
||||||
|
if (SUCCEEDED(hr)) {
|
||||||
|
// 处理轴数据
|
||||||
|
double x = state.lX / 1000.0;
|
||||||
|
double y = state.lY / 1000.0;
|
||||||
|
double z = state.lZ / 1000.0;
|
||||||
|
emit axisChanged(0, x);
|
||||||
|
emit axisChanged(1, y);
|
||||||
|
emit axisChanged(2, z);
|
||||||
|
|
||||||
|
// 处理按钮
|
||||||
|
for (int i = 0; i < 32; ++i) {
|
||||||
|
if(lastState.rgbButtons[i]!=state.rgbButtons[i])
|
||||||
|
{
|
||||||
|
bool pressed = (state.rgbButtons[i] & 0x80) != 0;
|
||||||
|
|
||||||
|
emit buttonChanged(i, pressed);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
if(lastState.rgdwPOV[0]!=state.rgdwPOV[0])
|
||||||
|
{
|
||||||
|
emit directionChanged(state.rgdwPOV[0]/100);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lastState = state;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
connect(m_workerThread, &QThread::finished, m_workerThread, &QThread::deleteLater);
|
||||||
|
m_workerThread->start();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DirectInputJoystick::cleanup() {
|
||||||
|
m_isRunning = false;
|
||||||
|
if (m_hEvent) {
|
||||||
|
CloseHandle(m_hEvent);
|
||||||
|
m_hEvent = nullptr;
|
||||||
|
}
|
||||||
|
if (m_pJoystick) {
|
||||||
|
m_pJoystick->Unacquire();
|
||||||
|
m_pJoystick->Release();
|
||||||
|
m_pJoystick = nullptr;
|
||||||
|
}
|
||||||
|
if (m_pDirectInput) {
|
||||||
|
m_pDirectInput->Release();
|
||||||
|
m_pDirectInput = nullptr;
|
||||||
|
}
|
||||||
|
}
|
Binary file not shown.
Before Width: | Height: | Size: 7.7 KiB |
Binary file not shown.
Before Width: | Height: | Size: 5.8 KiB |
@ -1,28 +0,0 @@
|
|||||||
#include <QByteArray>
|
|
||||||
class ProtocolPodTJ
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
static QByteArray encode(const QByteArray& cmd, const QByteArray& loadData = QByteArray::fromHex("00000000"));
|
|
||||||
|
|
||||||
|
|
||||||
public:
|
|
||||||
//控制指令
|
|
||||||
QByteArray cmdLeft(uint16_t sliderValue);
|
|
||||||
QByteArray cmdRight(uint16_t sliderValue);
|
|
||||||
QByteArray cmdUp(uint16_t sliderValue);
|
|
||||||
QByteArray cmdDown(uint16_t sliderValue);
|
|
||||||
QByteArray cmdZoom(uint8_t model, uint8_t speed);
|
|
||||||
QByteArray cmdLaser(uint8_t fre);
|
|
||||||
|
|
||||||
//数字引导
|
|
||||||
QByteArray digitalGuid(uint8_t directionAngle, uint8_t pitchAngle);
|
|
||||||
|
|
||||||
//伺服控制
|
|
||||||
QByteArray cmdServo(int pointX, int pointY);
|
|
||||||
|
|
||||||
//目标跟踪
|
|
||||||
QByteArray targetTracking(uint16_t dir, uint16_t pitch);
|
|
||||||
|
|
||||||
private:
|
|
||||||
static quint8 calculateXOR(const QByteArray& data, int begin, int end);
|
|
||||||
};
|
|
@ -1,201 +0,0 @@
|
|||||||
#include "switchbutton.h"
|
|
||||||
#include <QDebug>
|
|
||||||
|
|
||||||
WBSwitchButton::WBSwitchButton(QWidget* parent)
|
|
||||||
: QWidget{ parent }
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
bool WBSwitchButton::getSwitch() {
|
|
||||||
return mOnOff;
|
|
||||||
}
|
|
||||||
|
|
||||||
void WBSwitchButton::setSwitch(bool onoff) {
|
|
||||||
if (mWaitSigModel) return;
|
|
||||||
/// 状态切换
|
|
||||||
mOnOff = onoff;
|
|
||||||
/// 发送信号
|
|
||||||
sigSwitchChanged(mOnOff);
|
|
||||||
/// 动画-背景颜色
|
|
||||||
QPropertyAnimation* colorAnimation = new QPropertyAnimation(this, "pBackColor");
|
|
||||||
colorAnimation->setDuration(mAnimationPeriod);
|
|
||||||
colorAnimation->setStartValue(mBackColor);
|
|
||||||
colorAnimation->setEndValue(mOnOff ? mBackOnColor : mBackOffColor);
|
|
||||||
colorAnimation->start(QAbstractAnimation::DeletionPolicy::DeleteWhenStopped); //停止后删除
|
|
||||||
/// 动画-开关按钮位置
|
|
||||||
QVariantAnimation* posAnimation = new QVariantAnimation(this);
|
|
||||||
posAnimation->setDuration(mAnimationPeriod);
|
|
||||||
posAnimation->setStartValue(mButtonRect.topLeft());
|
|
||||||
posAnimation->setEndValue(mOnOff ? mRightPos : mLeftPos);
|
|
||||||
connect(posAnimation, &QPropertyAnimation::valueChanged, [=](const QVariant& value) {
|
|
||||||
mButtonRect.moveTo(value.toPointF());
|
|
||||||
update();
|
|
||||||
});
|
|
||||||
posAnimation->start(QAbstractAnimation::DeletionPolicy::DeleteWhenStopped); //停止后删除
|
|
||||||
}
|
|
||||||
|
|
||||||
void WBSwitchButton::setSwitchForWaitModel(bool onoff)
|
|
||||||
{
|
|
||||||
if (!mWaitSigModel) return;
|
|
||||||
if (mOnOff == onoff) {
|
|
||||||
/// 表示值未改变先运行按钮位置动画
|
|
||||||
QVariantAnimation* posAnimation = new QVariantAnimation(this);
|
|
||||||
posAnimation->setDuration(mAnimationPeriod);
|
|
||||||
posAnimation->setStartValue(mOnOff ? mLeftPos : mRightPos);
|
|
||||||
posAnimation->setEndValue(mOnOff ? mRightPos : mLeftPos);
|
|
||||||
connect(posAnimation, &QVariantAnimation::valueChanged, [=](const QVariant& value) {
|
|
||||||
mButtonRect.moveTo(value.toPointF());
|
|
||||||
update();
|
|
||||||
});
|
|
||||||
posAnimation->start(QAbstractAnimation::DeletionPolicy::DeleteWhenStopped); //停止后删除
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
/// 状态切换
|
|
||||||
mOnOff = onoff;
|
|
||||||
/// 发送信号
|
|
||||||
sigSwitchChanged(mOnOff);
|
|
||||||
/// 后运行背景颜色动画
|
|
||||||
QPropertyAnimation* colorAnimation = new QPropertyAnimation(this, "pBackColor");
|
|
||||||
colorAnimation->setDuration(mAnimationPeriod);
|
|
||||||
colorAnimation->setStartValue(mBackColor);
|
|
||||||
colorAnimation->setEndValue(mOnOff ? mBackOnColor : mBackOffColor);
|
|
||||||
colorAnimation->start(QAbstractAnimation::DeletionPolicy::DeleteWhenStopped); //停止后删除
|
|
||||||
connect(colorAnimation, &QPropertyAnimation::valueChanged, [=](const QVariant& value) {
|
|
||||||
update();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
void WBSwitchButton::setEnabled(bool enable) {
|
|
||||||
QWidget::setEnabled(enable);
|
|
||||||
mEnable = enable;
|
|
||||||
emit sigEnableChanged(mEnable);
|
|
||||||
update();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool WBSwitchButton::getEnabled()
|
|
||||||
{
|
|
||||||
return mEnable;
|
|
||||||
}
|
|
||||||
|
|
||||||
void WBSwitchButton::setAnimationPeriod(int period) {
|
|
||||||
mAnimationPeriod = period;
|
|
||||||
}
|
|
||||||
|
|
||||||
void WBSwitchButton::setPrecisionClick(bool flag) {
|
|
||||||
mPrecisionClickFlagh = flag;
|
|
||||||
}
|
|
||||||
|
|
||||||
void WBSwitchButton::setWaitModel(bool flag)
|
|
||||||
{
|
|
||||||
mWaitSigModel = flag;
|
|
||||||
}
|
|
||||||
|
|
||||||
void WBSwitchButton::setButtonColor(QColor color) {
|
|
||||||
mButtonColor = color;
|
|
||||||
update();
|
|
||||||
}
|
|
||||||
|
|
||||||
void WBSwitchButton::setBackOnColor(QColor color) {
|
|
||||||
mBackOnColor = color;
|
|
||||||
update();
|
|
||||||
}
|
|
||||||
|
|
||||||
void WBSwitchButton::setBackOffColor(QColor color) {
|
|
||||||
mBackOffColor = color;
|
|
||||||
update();
|
|
||||||
}
|
|
||||||
|
|
||||||
void WBSwitchButton::setEdgeColor(QColor color) {
|
|
||||||
mEdgeColor = color;
|
|
||||||
update();
|
|
||||||
}
|
|
||||||
|
|
||||||
void WBSwitchButton::paintEvent(QPaintEvent* event) {
|
|
||||||
Q_UNUSED(event)
|
|
||||||
QPainter painter(this);
|
|
||||||
painter.setRenderHint(QPainter::Antialiasing, true);
|
|
||||||
painter.setPen(Qt::NoPen);
|
|
||||||
|
|
||||||
/// 绘制边缘颜色
|
|
||||||
QPainterPath path;
|
|
||||||
path.addRect(this->rect());
|
|
||||||
path.addRoundedRect(this->rect(), mRadius, mRadius);
|
|
||||||
path.setFillRule(Qt::OddEvenFill);
|
|
||||||
painter.setBrush(mEdgeColor);
|
|
||||||
painter.drawPath(path);
|
|
||||||
|
|
||||||
/// 绘制背景颜色
|
|
||||||
painter.setBrush(mBackColor);
|
|
||||||
painter.drawRoundedRect(this->rect(), mRadius, mRadius);
|
|
||||||
|
|
||||||
/// 绘制圆形按钮
|
|
||||||
painter.setBrush(mButtonColor);
|
|
||||||
painter.drawEllipse(mButtonRect);
|
|
||||||
|
|
||||||
/// 绘制按钮阴影
|
|
||||||
painter.setBrush(Qt::NoBrush);
|
|
||||||
QColor color(Qt::black);
|
|
||||||
int count = (this->height() - mButtonRect.height()) / 2;
|
|
||||||
float stepColor = (0.15 - 0.0) / count;
|
|
||||||
for (int i = mButtonRect.height() / 2 + 1; i < this->height() / 2; i++) {
|
|
||||||
color.setAlphaF(0.15 - stepColor * (i - mButtonRect.height() / 2));
|
|
||||||
painter.setPen(color);
|
|
||||||
painter.drawEllipse(mButtonRect.center(), i, i);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 失能显示,添加一层蒙层
|
|
||||||
if (!mEnable) {
|
|
||||||
QColor disable(Qt::black);
|
|
||||||
disable.setAlphaF(0.5);
|
|
||||||
painter.setBrush(disable);
|
|
||||||
painter.drawRoundedRect(this->rect(), mRadius, mRadius);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void WBSwitchButton::resizeEvent(QResizeEvent* event) {
|
|
||||||
Q_UNUSED(event)
|
|
||||||
/// 更新按钮大小、圆角大小、动画两个位置
|
|
||||||
int size = qMin(this->width(), this->height());
|
|
||||||
mRadius = size / 2;
|
|
||||||
float width = size * 3 / 4;
|
|
||||||
float border = (size - width) / 2;
|
|
||||||
mLeftPos = QPoint(border, border);
|
|
||||||
mRightPos = QPoint(this->width() - border - width, border);
|
|
||||||
mButtonRect.setWidth(width);
|
|
||||||
mButtonRect.setHeight(width);
|
|
||||||
mButtonRect.moveTo(mOnOff ? mRightPos : mLeftPos);
|
|
||||||
mBackColor = mOnOff ? mBackOnColor : mBackOffColor;
|
|
||||||
update();
|
|
||||||
}
|
|
||||||
|
|
||||||
void WBSwitchButton::mouseReleaseEvent(QMouseEvent* event) {
|
|
||||||
if (mWaitSigModel) {
|
|
||||||
/// 先运行按钮位置动画
|
|
||||||
QVariantAnimation* posAnimation = new QVariantAnimation(this);
|
|
||||||
posAnimation->setDuration(mAnimationPeriod);
|
|
||||||
posAnimation->setStartValue(mOnOff ? mRightPos : mLeftPos);
|
|
||||||
posAnimation->setEndValue(mOnOff ? mLeftPos : mRightPos);
|
|
||||||
connect(posAnimation, &QVariantAnimation::valueChanged, [=](const QVariant& value) {
|
|
||||||
mButtonRect.moveTo(value.toPointF());
|
|
||||||
update();
|
|
||||||
});
|
|
||||||
posAnimation->start(QAbstractAnimation::DeletionPolicy::DeleteWhenStopped); //停止后删除
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!mEnable) return;
|
|
||||||
if (mButtonRect.contains(event->pos()) || !mPrecisionClickFlagh) {
|
|
||||||
setSwitch(!mOnOff);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void WBSwitchButton::enterEvent(QEvent* event) {
|
|
||||||
Q_UNUSED(event)
|
|
||||||
mHover = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void WBSwitchButton::leaveEvent(QEvent* event) {
|
|
||||||
Q_UNUSED(event)
|
|
||||||
mHover = false;
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in New Issue