操纵杆驱动程序项目
需要在 Windows 中用操纵杆控制东西?这是一个易于使用的驱动程序,可以帮助您做到这一点。
引言
当我想创建一个操纵杆驱动程序来通过插入计算机的操纵杆控制我的机器人时,我做的第一件事就是寻找一个简单的操纵杆驱动程序,它可以为我设置好一切,并提供我想要的读数,而无需我自己编写任何代码,甚至无需理解它是如何工作的。不幸的是,尽管在我之前有很多人在他们的程序和项目中使用了操纵杆,但我似乎找不到有人创建了我想要的东西并在线分享。
所以,如果其他人没有做到,我决定自己来做。因此,我开始了这个项目,旨在创建一个可移植且可重用的通用操纵杆驱动程序,任何人都可以使用它来轻松地在其程序中实现操纵杆控制。此驱动程序以 DirectX SDK 中的操纵杆示例程序为基础。
如果你知道你在做什么,编写一个简单的程序来获取操纵杆的一些读数并不难。但如果你不知道你在做什么,学习所有关于直接输入的内容以便创建自己的操纵杆驱动程序并不容易。鉴于我那时不知道,现在仍然不知道我在做什么,我决定改编 SDK 的示例代码,而不是从头编写驱动程序。这可能在最后对我来说更难,但是 SDK 的示例代码是一个非常全面且强大的程序,可以获取并接受您插入的任何操纵杆设备,从而给我带来了我认为比我原本能产生的更好的结果。
我的驱动程序只处理操纵杆相关的内容,因此已移除示例程序中的所有 GUI 相关代码,使其整体更小、更简单。
此驱动程序将您所有的操纵杆需求打包到一个 Joystick 类中,该类获取您所有的操纵杆读数。您可以读取 8 个可能的轴/滑块、四个可能的 POV/帽子和 128 个可能的按钮。
这是一个显示扭曲手柄操纵杆读数的测试 GUI。
修改版的用于测试方向盘组合的 GUI。
告诉我如何使用它!
步骤 1
下载文件并将 Joystick_Driver.h、Joystick_Driver.cpp 和 resource.h 添加到您的项目中。
第二步
确保链接器可以找到所有必需的外部依赖项:windows.h、commctrl.h、dinput.h、dinputd.h、assert.h 和 wbemidl.h 以及其他依赖项。如果您的项目在 Visual Studio 中,请右键单击您的项目并转到属性。在属性窗口中,转到...
配置属性 -> 链接器 -> 输入 -> 附加依赖项 -> 编辑
然后添加 dxguid.lib、dinput8.lib、comctl32.lib。
目前,我还没有尝试在其他 IDE 中使用它,但对于您可能尝试使用的任何 IDE,您都需要执行相同的操作。
步骤 3
现在是简单部分。
声明以下内容
Joystick* myJoystick; //pointer to joystick object
HWND hWnd; //window handler
在合适的位置进行初始化
myJoystick = new Joystick();
hWnd = //define a handle to the window of your application with the appropriate syntax
步骤 4
创建由定时器驱动的函数调用来运行操纵杆。
使用 `while` 循环是个坏主意。尤其是当您有一个 GUI 时,您不希望它冻结。
您可以使用 `while` 循环检查事情是否正常工作,但最终,您无论如何都需要一个由定时器驱动的函数调用。
将您的定时器配置为每秒触发 20-30 次,或者间隔 30ms-50ms。
步骤 5
在您的定时器驱动函数中,您可以像这样简单地操作:
Void timerFunct()
{
myJoystick->runJoystick(hWnd);
//only update readings while a joystick is available
if(myJoystick->getmsg() == WM_TIMER)
{
XAxis = myJoystick->getXAxis();
YAxis = myJoystick->getYAxis();
ZRot = myJoystick->getZRot();
Slider1 = myJoystick->getSlider0();
POV1 = myJoystick->getPOV0();
Button0 = myJoystick->getButton(0);
Button1 = myJoystick->getButton(1);
Button2 = myJoystick->getButton(2);
Button3 = myJoystick->getButton(3);
Button4 = myJoystick->getButton(4);
}
}
这应该能让您大致了解如何使用它。有关一个正常工作的示例,请参阅下一部分。
Windows 窗体应用程序示例
按照此示例设计一个窗体应用程序,并在您的 form.h 文件中需要的地方添加以下代码。
#include "Joystick_Driver.h"
public ref class Form1 : public System::Windows::Forms::Form
{
public:
Form1(void)
{
InitializeComponent();
this->JS = new Joystick();
this->hWnd = static_cast<HWND>(this->Handle.ToPointer());
}
~Form1()
{
if (components)
{
delete components;
}
}
//***********Here there be lots of************
//private: System::Windows::Forms::Stuff^ stuff;
//********************************************
private:
Joystick* JS; //pointer to joystick object
private:
HWND hWnd; //window handler
#pragma region Windows Form Designer generated code
void InitializeComponent(void)
{
//******** Here there be lots of ********
//this->stuff->stuff = stuff;
//***************************************
}
#pragma endregion
//your own functions go here
};
在设计视图中,向您的窗体添加一个定时器。
不要忘记设置定时器属性。
您现在将在您的窗体中有一个函数。
private: System::Void timer1_Tick(System::Object^ sender, System::EventArgs^ e) {
}
在设计视图中,双击 **运行** 和 **停止** 按钮,并使用这些按钮点击事件函数来启用和禁用定时器。
private: System::Void Run_Click(System::Object^ sender, System::EventArgs^ e)
{
this->timer1->Enabled = true;
}
private: System::Void Stop_Click(System::Object^ sender, System::EventArgs^ e)
{
this->timer1->Enabled = false;
}
将以下内容添加到定时器的 `tick` 函数中。
private: System::Void timer1_Tick(System::Object^ sender, System::EventArgs^ e)
{
this->JS->runJoystick(this->hWnd);
//only update readings on GUI while a joystick is available
if(this->JS->getmsg() == WM_TIMER)
{
this->XAxis->Text = (this->JS->getXAxis()).ToString();
this->YAxis->Text = (this->JS->getYAxis()).ToString();
this->ZAxis->Text = (this->JS->getZAxis()).ToString();
this->XRot->Text = (this->JS->getXRot()).ToString();
this->YRot->Text = (this->JS->getYRot()).ToString();
this->ZRot->Text = (this->JS->getZRot()).ToString();
this->Slider1->Text = (this->JS->getSlider0()).ToString();
this->Slider2->Text = (this->JS->getSlider1()).ToString();
this->POV1->Text = (this->JS->getPOV0()).ToString();
this->POV2->Text = (this->JS->getPOV1()).ToString();
this->POV3->Text = (this->JS->getPOV2()).ToString();
this->POV4->Text = (this->JS->getPOV3()).ToString();
this->Button0->Checked = this->JS->getButton(0);
this->Button1->Checked = this->JS->getButton(1);
this->Button2->Checked = this->JS->getButton(2);
this->Button3->Checked = this->JS->getButton(3);
this->Button4->Checked = this->JS->getButton(4);
this->Button5->Checked = this->JS->getButton(5);
this->Button6->Checked = this->JS->getButton(6);
this->Button7->Checked = this->JS->getButton(7);
this->Button8->Checked = this->JS->getButton(8);
this->Button9->Checked = this->JS->getButton(9);
this->Button10->Checked = this->JS->getButton(10);
this->Button11->Checked = this->JS->getButton(11);
this->Button12->Checked = this->JS->getButton(12);
this->Button13->Checked = this->JS->getButton(13);
this->Button14->Checked = this->JS->getButton(14);
this->Button15->Checked = this->JS->getButton(15);
this->Button16->Checked = this->JS->getButton(16);
this->Button17->Checked = this->JS->getButton(17);
this->Button18->Checked = this->JS->getButton(18);
}
}
运行程序
所有轴和滑块的读数应在 -1000 到 1000 的范围内。POV 将为所有 8 个方向提供 8 个不同的值,所有按钮将简单地读取 `true` 或 `false`。
关于功能的说明
您可能需要深入驱动程序并添加自己的代码才能执行某些操作。根据您的应用程序,您将不得不考虑...
断开操纵杆时会发生什么?
此时,驱动程序会自动查找另一个操纵杆,并接受它找到的任何操纵杆,无论是它重新插入的同一个操纵杆,还是已经插入或将要插入的另一个操纵杆。
断开操纵杆时读数会怎样?
您希望它们冻结在最后更新的值,还是希望所有值恢复到其默认的零位置?
此时,如果操纵杆断开连接,驱动程序会将读数冻结在最后读取的值。
当插入两个或更多操纵杆时会发生什么?
您可能希望能够选择一个操纵杆设备,或者可能希望在程序运行时在操纵杆之间切换,或者您可能希望两个或多个操纵杆同时工作。
目前,该驱动程序不支持多个操纵杆,但可以进行改编以支持。它会创建一个操纵杆设备列表并自动选择其中一个。所以您无法选择操纵杆。
您可以在程序运行时切换设备,但这需要您物理上拔下它们并重新插入。
如果您只想接受特定类型操纵杆的输入怎么办?
该驱动程序能够识别已连接操纵杆可用的轴和按钮,因此在某种程度上,您可以实现这一点。
历史
- 2013 年 2 月 10 日:初始版本