commit
ce83ebfc31
@ -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;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue