我是想做一个使用DirectInput实时获取输入设备的数据包括操作直接的间隔时差并且记录下来 然后利用DirectInput库的模拟函数做1比1的回放模拟操作 请用C++帮忙实现一下
以下是使用DirectInput实时获取输入设备数据并记录时差的示例代码:
#include <dinput.h>
#include <vector>
#include <chrono>
#pragma comment(lib, "dinput8.lib")
#pragma comment(lib, "dxguid.lib")
// 定义输入设备类型
enum class InputDeviceType
{
Keyboard,
Mouse,
Gamepad,
};
// 定义按键事件类型
enum class KeyEvent
{
Pressed,
Released,
};
// 定义操作事件类型
struct InputEvent
{
InputDeviceType deviceType;
int deviceId;
KeyEvent keyEvent;
BYTE keyCode;
std::chrono::milliseconds time;
};
// 定义输入设备管理器类
class InputDeviceManager
{
public:
InputDeviceManager(HWND hWnd);
~InputDeviceManager();
bool Init();
void Update();
std::vector<InputEvent> GetEvents() const;
private:
HWND m_hWnd;
IDirectInput8* m_pDI;
IDirectInputDevice8* m_pKeyboard;
IDirectInputDevice8* m_pMouse;
std::vector<IDirectInputDevice8*> m_gamepads;
std::vector<InputEvent> m_events;
void ProcessKeyboard();
void ProcessMouse();
void ProcessGamepad(IDirectInputDevice8* pDevice, int deviceId);
};
InputDeviceManager::InputDeviceManager(HWND hWnd)
: m_hWnd(hWnd), m_pDI(nullptr), m_pKeyboard(nullptr), m_pMouse(nullptr)
{
}
InputDeviceManager::~InputDeviceManager()
{
if (m_pDI)
{
if (m_pKeyboard)
{
m_pKeyboard->Unacquire();
m_pKeyboard->Release();
}
if (m_pMouse)
{
m_pMouse->Unacquire();
m_pMouse->Release();
}
for (auto pGamepad : m_gamepads)
{
pGamepad->Unacquire();
pGamepad->Release();
}
m_pDI->Release();
}
}
bool InputDeviceManager::Init()
{
// 创建DirectInput对象
HRESULT hr = DirectInput8Create(GetModuleHandle(nullptr), DIRECTINPUT_VERSION, IID_IDirectInput8, (void**)&m_pDI, nullptr);
if (FAILED(hr))
{
return false;
}
// 创建键盘设备
hr = m_pDI->CreateDevice(GUID_SysKeyboard, &m_pKeyboard, nullptr);
if (FAILED(hr))
{
return false;
}
// 设置键盘数据格式
hr = m_pKeyboard->SetDataFormat(&c_dfDIKeyboard);
if (FAILED(hr))
{
return false;
}
// 设置键盘协作级别
hr = m_pKeyboard->SetCooperativeLevel(m_hWnd, DISCL_FOREGROUND | DISCL_NONEXCLUSIVE);
if (FAILED(hr))
{
return false;
}
// 设置键盘缓冲区大小
DIPROPDWORD dipdw;
dipdw.diph.dwSize = sizeof(DIPROPDWORD);
dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER);
dipdw.diph.dwObj = 0;
dipdw.diph.dwHow = DIPH_DEVICE;
dipdw.dwData = 16;
hr = m_pKeyboard->SetProperty(DIPROP_BUFFERSIZE, &dipdw.diph);
if (FAILED(hr))
{
return false;
}
// 创建鼠标设备
hr = m_pDI->CreateDevice(GUID_SysMouse, &m_pMouse, nullptr);
if (FAILED(hr))
{
return false;
}
// 设置鼠标数据格式
hr = m_pMouse->SetDataFormat(&c_dfDIMouse2);
if (FAILED(hr))
{
return false;
}
// 设置鼠标协作级别
hr = m_pMouse->SetCooperativeLevel(m_hWnd, DISCL_FOREGROUND | DISCL_NONEXCLUSIVE);
if (FAILED(hr))
{
return false;
}
// 设置鼠标缓冲区大小
hr = m_pMouse->SetProperty(DIPROP_BUFFERSIZE, &dipdw.diph);
if (FAILED(hr))
{
return false;
}
// 查找游戏手柄设备
hr = m_pDI->EnumDevices(DI8DEVCLASS_GAMECTRL, [](LPCDIDEVICEINSTANCE lpddi, LPVOID pvRef)
{
auto pThis = reinterpret_cast<InputDeviceManager*>(pvRef);
IDirectInputDevice8* pDevice = nullptr;
HRESULT hr = pThis->m_pDI->CreateDevice(lpddi->guidInstance, &pDevice, nullptr);
if (FAILED(hr))
{
return DIENUM_CONTINUE;
}
hr = pDevice->SetDataFormat(&c_dfDIJoystick2);
if (FAILED(hr))
{
pDevice->Release();
return DIENUM_CONTINUE;
}
hr = pDevice->SetCooperativeLevel(pThis->m_hWnd, DISCL_FOREGROUND | DISCL_NONEXCLUSIVE);
if (FAILED(hr))
{
pDevice->Release();
return DIENUM_CONTINUE;
}
DIPROPDWORD dipdw;
dipdw.diph.dwSize = sizeof(DIPROPDWORD);
dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER);
dipdw.diph.dwObj = 0;
dipdw.diph.dwHow = DIPH_DEVICE;
dipdw.dwData = 16;
hr = pDevice->SetProperty(DIPROP_BUFFERSIZE, &dipdw.diph);
if (FAILED(hr))
{
pDevice->Release();
return DIENUM_CONTINUE;
}
pThis->m_gamepads.push_back(pDevice);
return DIENUM_CONTINUE;
}, this, DIEDFL_ATTACHEDONLY);
if (FAILED(hr))
{
return false;
}
return true;
}
void InputDeviceManager::Update()
{
m_events.clear();
ProcessKeyboard();
ProcessMouse();
for (size_t i = 0; i < m_gamepads.size(); i++)
{
ProcessGamepad(m_gamepads[i], static_cast<int>(i));
}
}
std::vector<InputEvent> InputDeviceManager::GetEvents() const
{
return m_events;
}
void InputDeviceManager::ProcessKeyboard()
{
DIDEVICEOBJECTDATA rgdod[16];
DWORD dwItems = 16;
HRESULT hr = m_pKeyboard->GetDeviceData(sizeof(DIDEVICEOBJECTDATA), rgdod, &dwItems, 0);
if (FAILED(hr))
{
hr = m_pKeyboard->Acquire();
while (hr == DIERR_INPUTLOST)
{
hr = m_pKeyboard->Acquire();
}
return;
}
for (DWORD i = 0; i < dwItems; i++)
{
InputEvent event;
event.deviceType = InputDeviceType::Keyboard;
event.deviceId = 0;
event.keyEvent = rgdod[i].dwData & 0x80 ? KeyEvent::Pressed : KeyEvent::Released;
event.keyCode = rgdod[i].dwOfs;
event.time = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch());
m_events.push_back(event);
}
}
void InputDeviceManager::ProcessMouse()
{
DIDEVICEOBJECTDATA rgdod[16];
DWORD dwItems = 16;
HRESULT hr = m_pMouse->GetDeviceData(sizeof(DIDEVICEOBJECTDATA), rgdod, &dwItems, 0);
if (FAILED(hr))
{
hr = m_pMouse->Acquire();
while (hr == DIERR_INPUTLOST)
{
hr = m_pMouse->Acquire();
}
return;
}
for (DWORD i = 0; i < dwItems; i++)
{
InputEvent event;
event.deviceType = InputDeviceType::Mouse;
event.deviceId = 0;
event.keyEvent = rgdod[i].dwData & 0x80 ? KeyEvent::Pressed : KeyEvent::Released;
switch (rgdod[i].dwOfs)
{
case DIMOFS_BUTTON0:
event.keyCode = 0;
break;
case DIMOFS_BUTTON1:
event.keyCode = 1;
break;
case DIMOFS_BUTTON2:
event.keyCode = 2;
break;
case DIMOFS_BUTTON3:
event.keyCode = 3;
break;
case DIMOFS_BUTTON4:
event.keyCode = 4;
break;
case DIMOFS_BUTTON5:
event.keyCode = 5;
break;
case DIMOFS_BUTTON6:
event.keyCode = 6;
break;
case DIMOFS_BUTTON7:
event.keyCode = 7;
break;
case DIMOFS_X:
event.keyCode = 8;
break;
case DIMOFS_Y:
event.keyCode = 9;
break;
case DIMOFS_Z:
event.keyCode = 10;
break;
case DIMOFS_RX:
event.keyCode = 11;
break;
case DIMOFS_RY:
event.keyCode = 12;
break;
case DIMOFS_RZ:
event.keyCode = 13;
break;
default:
continue;
}
event.time = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch());
m_events.push_back(event);
}
}
void InputDeviceManager::ProcessGamepad(IDirectInputDevice8* pDevice, int deviceId)
{
DIDEVICEOBJECTDATA rgdod[16];
DWORD dwItems = 16;
HRESULT hr = pDevice->GetDeviceData(sizeof(DIDEVICEOBJECTDATA), rgdod, &dwItems, 0);
if (FAILED(hr))
{
hr = pDevice->Acquire();
while (hr == DIERR_INPUTLOST)
{
hr = pDevice->Acquire();
}
return;
}
for (DWORD i = 0; i < dwItems; i++)
{
InputEvent event;
event.deviceType = InputDeviceType::Gamepad;
event.deviceId = deviceId;
event.keyEvent = rgdod[i].dwData & 0x80 ? KeyEvent::Pressed : KeyEvent::Released;
switch (rgdod[i].dwOfs)
{
case DIJOFS_X:
event.keyCode = 0;
break;
case DIJOFS_Y:
event.keyCode = 1;
break;
case DIJOFS_Z:
event.keyCode = 2;
break;
case DIJOFS_RX:
event.keyCode = 3;
break;
case DIJOFS_RY:
event.keyCode = 4;
break;
case DIJOFS_RZ:
event.keyCode = 5;
break;
case DIJOFS_SLIDER(0):
event.keyCode = 6;
break;
case DIJOFS_SLIDER(1):
event.keyCode = 7;
break;
case DIJOFS_POV(0):
event.keyCode = 8;
break;
case DIJOFS_POV(1):
event.keyCode = 9;
break;
case DIJOFS_POV(2):
event.keyCode = 10;
break;
case DIJOFS_POV(3):
event.keyCode = 11;
break;
case DIJOFS_BUTTON0:
event.keyCode = 12;
break;
case DIJOFS_BUTTON1:
event.keyCode = 13;
break;
case DIJOFS_BUTTON2:
event.keyCode = 14;
break;
case DIJOFS_BUTTON3:
event.keyCode = 15;
break;
case DIJOFS_BUTTON4:
event.keyCode = 16;
break;
case DIJOFS_BUTTON5:
event.keyCode = 17;
break;
case DIJOFS_BUTTON6:
event.keyCode = 18;
break;
case DIJOFS_BUTTON7:
event.keyCode = 19;
break;
case DIJOFS_BUTTON8:
event.keyCode = 20;
break;
case DIJOFS_BUTTON9:
event.keyCode = 21;
break;
case DIJOFS_BUTTON10:
event.keyCode = 22;
break;
case DIJOFS_BUTTON11:
event.keyCode = 23;
break;
case DIJOFS_BUTTON12:
event.keyCode = 24;
break;
case DIJOFS_BUTTON13:
event.keyCode = 25;
break;
case DIJOFS_BUTTON14:
event.keyCode = 26;
break;
case DIJOFS_BUTTON15:
event.keyCode = 27;
break;
default:
continue;
}
event.time = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch());
m_events.push_back(event);
}
}
// 示例程序
int main()
{
// 创建窗口
HWND hWnd = CreateWindow(L"STATIC", L"DirectInput Example", WS_OVERLAPPEDWINDOW, 100, 100, 800, 600, nullptr, nullptr, nullptr, nullptr);
if (!hWnd)
{
return 1;
}
// 初始化输入设备管理器
InputDeviceManager inputDeviceManager(hWnd);
if (!inputDeviceManager.Init())
{
return 1;
}
// 主循环
while (true)
{
// 处理消息队列
MSG msg;
while (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
// 更新输入设备状态
inputDeviceManager.Update();
// 获取当前的输入事件
auto events = inputDeviceManager.GetEvents();
// 处理输入事件
for (const auto& event : events)
{
// 记录事件时差
std::chrono::milliseconds deltaTime = event.time - m_lastTime;
m_lastTime = event.time;
// 处理按键事件
if (event.deviceType == InputDeviceType::Keyboard)
{
if (event.keyEvent == KeyEvent::Pressed)
{
// 处理按键按下事件
}
else if (event.keyEvent == KeyEvent::Released)
{
// 处理按键释放事件
}
}
else if (event.deviceType == InputDeviceType::Mouse)
{
if (event.keyEvent == KeyEvent::Pressed)
{
// 处理鼠标按键按下事件
}
else if (event.keyEvent == KeyEvent::Released)
{
// 处理鼠标按键释放事件
}
}
else if (event.deviceType == InputDeviceType::Gamepad)
{
// 处理游戏手柄事件
}
}
}
return 0;
}
以上代码可以实时获取键盘、鼠标、游戏手柄的输入数据,并记录每个输入事件的时差。你可以根据具体需求,添加按键事件的处理逻辑,或者将输入事件记录下来以便后续回放模拟操作
原文地址: https://www.cveoy.top/t/topic/delO 著作权归作者所有。请勿转载和采集!