游戏手柄(JoyStick)编程学习笔记(2)
在我的上一篇博客中(http://blog.csdn.net/liyuanbhu/article/details/51714045),介绍了通过 multimedia joystick API 来访问游戏手柄的基本方法。
最后说到了利用 joySetCapture 函数监听手柄事件的方式并不是非常的好用。建议大家字节写个监听线程,有针对性的监听需要的事件。这里,我把我以前写的一份代码放上来。代码是基于 Qt 的,监听了按键、摇杆和视觉头盔的状态,在状态发生改变时发出Qt 的信号。
按键对应两个信号:
void Joy_ButtonPressed(int i);
void Joy_ButtonReleased(int i);
摇杆分为两种模式:SWITCH_MODE 和 COORDINATE_MODE
SWITCH_MODE 模式下,输出四个方向的开关量。对应的信号是:
void Joy_MoveForward();
void Joy_MoveBackward();
void Joy_MoveForwardStop();
void Joy_MoveBackwardStop();
void Joy_MoveLeft();
void Joy_MoveRight();
void Joy_MoveLeftStop();
void Joy_MoveRightStop();
COORDINATE_MODE 模式直接输出坐标值(只有在摇杆位置发生变化时才会有输出)。
void Joy_Position(int x, int y);
视觉头盔模拟了摇杆的开关量模式。对应的信号同样是:
void Joy_MoveForward();
void Joy_MoveBackward();
void Joy_MoveForwardStop();
void Joy_MoveBackwardStop();
void Joy_MoveLeft();
void Joy_MoveRight();
void Joy_MoveLeftStop();
void Joy_MoveRightStop();
具体的代码不用过多介绍,主要就是几个状态机。下面贴出代码来。
首先是头文件:
#ifndef JOYSTICK_H
#define JOYSTICK_H
#include <QObject>
#include <QThread>
#include <Windows.h>
#include <Mmsystem.h>
class JoyStick;
/**
* @brief The JoyStickThread class
* @details 内部类,定时轮询 JoyStick 的状态。
*/
class JoyStickThread : public QThread
{
public:
explicit JoyStickThread();
void setJoyStick(JoyStick *joystick);
void run();
void stop();
private:
void Coordinate_StateMachine(int xPos, int yPos);
void AxisX_StateMachine(int xPos);
void AxisY_StateMachine(int yPos);
void Button_StateMachine(int button);
void POV_StateMachine_Axis(int pov);
void POV_StateMachine(int pov);
int old_xPos;
int old_yPos;
int old_pov;
bool pov_forward;
bool pov_backward;
bool pov_left;
bool pov_right;
bool pov_center;
int m_button[16];
JoyStick *m_joystick;
bool m_run;
};
class JoyStick : public QObject
{
Q_OBJECT
public:
enum MODE{SWITCH_MODE, COORDINATE_MODE};
/**
* @brief JoyStick
* @param mode SWITCH_MODE 模式时,摇杆输出开关量。COORDINATE_MODE 模式时,输出摇杆的位置。
* @param parent
*/
explicit JoyStick(enum MODE mode = SWITCH_MODE, QObject *parent = 0);
enum MODE mode() const {return m_mode;}
~JoyStick();
/**
* @brief listen
* @return 启动监听线程,之后就可以接收手柄的各种消息了。
*/
bool listen();
/**
* @brief stop 停止监听线程,不需要接收手柄消息时可以调用这个函数。
*/
void stop();
signals:
/// JoyStick 的摇杆的各种信号。
/// 高级些的手柄是可以返回摇杆的坐标值的。
/// 这里模仿的是工业摇杆,输出的都是开关量。
/// 前后左右四组开关量。
void Joy_MoveForward();
void Joy_MoveBackward();
void Joy_MoveForwardStop();
void Joy_MoveBackwardStop();
void Joy_MoveLeft();
void Joy_MoveRight();
void Joy_MoveLeftStop();
void Joy_MoveRightStop();
/// JoyStick 的摇杆位置。
void Joy_Position(int x, int y);
/**
* @brief Joy_ButtonPressed 当手柄上某个按键被按下时发出这个信号
* @param i 用来标志是哪个按键被按下了。
*/
void Joy_ButtonPressed(int i);
/**
* @brief Joy_ButtonReleased 当手柄上某个按键被释放时发出这个信号
* @param i 用来标志是哪个按键被释放了。
*/
void Joy_ButtonReleased(int i);
/// 以下是视觉头盔的各种信号
void Joy_POVForward();
void Joy_POVBackward();
void Joy_POVLeft();
void Joy_POVRight();
void Joy_POVForwardLeft();
void Joy_POVForwardRight();
void Joy_POVBackwardLeft();
void Joy_POVBackwardRight();
/**
* @brief Joy_POVCentered 当视觉头盔从前8种状态恢复到默认状态时发出这个信号。
*/
void Joy_POVCentered();
private:
enum MODE m_mode;
bool m_valid;
JoyStickThread m_thread;
};
#endif // JOYSTICK_H
下面是cpp 文件:
#include "joystick.h"
#include <Windows.h>
#include <QDebug>
JoyStick::JoyStick(enum MODE mode, QObject *parent) : QObject(parent)
{
m_mode = mode;
m_valid = false;
m_thread.setJoyStick(this);
JOYINFO joyinfo;
if( joyGetNumDevs() > 0 && joyGetPos(JOYSTICKID1, &joyinfo) != JOYERR_UNPLUGGED )
{
qDebug() << "JoyStick Init success!";
m_valid = true;
}
}
JoyStick::~JoyStick()
{
m_thread.stop();
m_thread.wait();
}
bool JoyStick::listen()
{
m_thread.start();
return true;
}
void JoyStick::stop()
{
if(m_thread.isRunning())
{
m_thread.stop();
m_thread.wait();
}
}
JoyStickThread::JoyStickThread()
{
m_run = 1;
old_xPos = 32767;
old_yPos = 32767;
for(int i = 0; i < 16; i++)
{
m_button[i] = 0;
}
old_pov = JOY_POVCENTERED;
pov_forward = false;
pov_backward = false;
pov_left = false;
pov_right = false;
pov_center = true;
}
void JoyStickThread::stop()
{
m_run = 0;
}
void JoyStickThread::setJoyStick(JoyStick *joystick)
{
m_joystick = joystick;
}
void JoyStickThread::run()
{
//JOYINFO joyinfo;
JOYINFOEX joyinfoex;
joyinfoex.dwSize = sizeof(JOYINFOEX);
joyinfoex.dwFlags = JOY_RETURNALL;
while(m_run)
{
// if(joyGetPos(JOYSTICKID1, &joyinfo) == JOYERR_NOERROR)
// {
// //qDebug() << joyinfo.wXpos;
// AxisX_StateMachine(joyinfo.wXpos);
// AxisY_StateMachine(joyinfo.wYpos);
// Button_StateMachine(joyinfo.wButtons);
// }
if(joyGetPosEx(JOYSTICKID1, &joyinfoex) == JOYERR_NOERROR)
{
if(m_joystick->mode() == JoyStick::SWITCH_MODE)
{
AxisX_StateMachine(joyinfoex.dwXpos);
AxisY_StateMachine(joyinfoex.dwYpos);
}
else
{
Coordinate_StateMachine(joyinfoex.dwXpos, joyinfoex.dwYpos);
}
Button_StateMachine(joyinfoex.dwButtons);
POV_StateMachine_Axis(joyinfoex.dwPOV);
}
msleep(50);
}
}
void JoyStickThread::POV_StateMachine(int pov)
{
if(pov != old_pov)
{
//qDebug() << pov;
if( pov == JOY_POVFORWARD )
{
emit m_joystick->Joy_POVForward();
}
if( pov == JOY_POVFORWARD + 4500 )
{
emit m_joystick->Joy_POVForwardRight();
}
if( pov == JOY_POVRIGHT )
{
emit m_joystick->Joy_POVRight();
}
if( pov == JOY_POVRIGHT + 4500 )
{
emit m_joystick->Joy_POVBackwardRight();
}
if( pov == JOY_POVBACKWARD )
{
emit m_joystick->Joy_POVBackward();
}
if( pov == JOY_POVBACKWARD + 4500 )
{
emit m_joystick->Joy_POVBackwardLeft();
}
if( pov == JOY_POVLEFT )
{
emit m_joystick->Joy_POVLeft();
}
if( pov == JOY_POVLEFT + 4500 )
{
emit m_joystick->Joy_POVForwardLeft();
}
if( pov == JOY_POVCENTERED )
{
emit m_joystick->Joy_POVCentered();
}
old_pov = pov;
}
}
void JoyStickThread::POV_StateMachine_Axis(int pov)
{
if(pov != old_pov)
{
//qDebug() << pov;
if( pov == JOY_POVFORWARD )
{
if(pov_forward == false)
{
pov_forward = true;
emit m_joystick->Joy_MoveForward();
//qDebug() << "JOY_POVFORWARD";
}
if(pov_left == true)
{
emit m_joystick->Joy_MoveLeftStop();
//qDebug() << "JOY_POVLEFT RETURN";
}
if(pov_right == true)
{
emit m_joystick->Joy_MoveRightStop();
//qDebug() << "JOY_POVRIGHT RETURN";
}
pov_left = false;
pov_right = false;
}
if( pov == JOY_POVFORWARD + 4500 )
{
if(pov_forward == false)
{
pov_forward = true;
emit m_joystick->Joy_MoveForward();
//qDebug() << "JOY_POVFORWARD";
}
if(pov_right == false)
{
pov_right = true;
emit m_joystick->Joy_MoveRight();
//qDebug() << "JOY_POVRIGHT";
}
}
if( pov == JOY_POVRIGHT )
{
if(pov_right == false)
{
pov_right = true;
emit m_joystick->Joy_MoveRight();
//qDebug() << "JOY_POVRIGHT";
}
if(pov_forward == true)
{
emit m_joystick->Joy_MoveForwardStop();
//qDebug() << "JOY_POVFORWARD RETURN";
}
if(pov_backward == true)
{
emit m_joystick->Joy_MoveBackwardStop();
//qDebug() << "JOY_POVBACKWARD RETURN";
}
pov_forward = false;
pov_backward = false;
}
if( pov == JOY_POVRIGHT + 4500 )
{
if(pov_right == false)
{
pov_right = true;
emit m_joystick->Joy_MoveRight();
// qDebug() << "JOY_POVRIGHT";
}
if(pov_backward == false)
{
pov_backward = true;
emit m_joystick->Joy_MoveBackward();
// qDebug() << "JOY_POVBACKWARD";
}
}
if( pov == JOY_POVBACKWARD )
{
if(pov_backward == false)
{
pov_backward = true;
emit m_joystick->Joy_MoveBackward();
//qDebug() << "JOY_POVBACKWARD";
}
if(pov_left == true)
{
emit m_joystick->Joy_MoveLeftStop();
//qDebug() << "JOY_POVLEFT RETURN";
}
if(pov_right == true)
{
emit m_joystick->Joy_MoveRightStop();
//qDebug() << "JOY_POVRIGHT RETURN";
}
pov_left = false;
pov_right = false;
}
if( pov == JOY_POVBACKWARD + 4500 )
{
if(pov_backward == false)
{
pov_backward = true;
emit m_joystick->Joy_MoveBackward();
//qDebug() << "JOY_POVBACKWARD";
}
if(pov_left == false)
{
pov_left = true;
emit m_joystick->Joy_MoveLeft();
// qDebug() << "JOY_POVLEFT";
}
}
if( pov == JOY_POVLEFT )
{
if(pov_left == false)
{
pov_left = true;
emit m_joystick->Joy_MoveLeft();
//qDebug() << "JOY_POVLEFT";
}
if(pov_forward == true)
{
emit m_joystick->Joy_MoveForwardStop();
//qDebug() << "JOY_POVFORWARD RETURN";
}
if(pov_backward == true)
{
emit m_joystick->Joy_MoveBackwardStop();
//qDebug() << "JOY_POVBACKWARD RETURN";
}
pov_backward = false;
pov_forward = false;
}
if( pov == JOY_POVLEFT + 4500 )
{
if(pov_left == false)
{
pov_left = true;
emit m_joystick->Joy_MoveLeft();
//qDebug() << "JOY_POVLEFT";
}
if(pov_forward == false)
{
pov_forward = true;
emit m_joystick->Joy_MoveForward();
//qDebug() << "JOY_POVFORWARD";
}
}
if( pov == JOY_POVCENTERED )
{
if(pov_forward == true)
{
emit m_joystick->Joy_MoveForwardStop();
//qDebug() << "JOY_POVFORWARD RETURN";
}
if(pov_backward == true)
{
emit m_joystick->Joy_MoveBackwardStop();
//qDebug() << "JOY_POVBACKWARD RETURN";
}
if(pov_left == true)
{
emit m_joystick->Joy_MoveLeftStop();
//qDebug() << "JOY_POVLEFT RETURN";
}
if(pov_right == true)
{
emit m_joystick->Joy_MoveRightStop();
//qDebug() << "JOY_POVRIGHT RETURN";
}
pov_forward = false;
pov_right = false;
pov_left = false;
pov_backward = false;
//qDebug() << "JOY_POVCENTERED";
}
old_pov = pov;
}
}
void JoyStickThread::Button_StateMachine(int button)
{
//if( button )
//qDebug() << QString::number(button, 16);
const int mask[16] = {1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768};
for(int i = 0; i < 12; i++)
{
int n = button & mask[i];
if(n ^ m_button[i])
{
m_button[i] = n;
if( n )
{
emit m_joystick->Joy_ButtonPressed(i + 1);
//qDebug() << "ButtonPressed(" << i + 1 << ")";
}
else
{
emit m_joystick->Joy_ButtonReleased(i + 1);
//qDebug() << "ButtonReleased(" << i + 1 << ")";;
}
}
}
}
void JoyStickThread::Coordinate_StateMachine(int xPos, int yPos)
{
if(xPos == old_xPos && yPos == old_yPos)
{
return;
}
old_xPos = xPos;
old_yPos = yPos;
emit m_joystick->Joy_Position(xPos, yPos);
}
void JoyStickThread::AxisX_StateMachine(int xPos)
{
if(xPos == old_xPos) return;
switch(xPos)
{
case 0:
emit m_joystick->Joy_MoveLeft();
break;
case 32767:
if(old_xPos == 0)
{
emit m_joystick->Joy_MoveLeftStop();
}
else
{
emit m_joystick->Joy_MoveRightStop();
}
break;
case 65535:
emit m_joystick->Joy_MoveRight();
break;
}
old_xPos = xPos;
}
void JoyStickThread::AxisY_StateMachine(int yPos)
{
if(yPos == old_yPos) return;
switch(yPos)
{
case 0:
emit m_joystick->Joy_MoveForward();
break;
case 32767:
if(old_xPos == 0)
{
emit m_joystick->Joy_MoveForwardStop();
}
else
{
emit m_joystick->Joy_MoveBackwardStop();
}
break;
case 65535:
emit m_joystick->Joy_MoveBackward();
break;
}
old_yPos = yPos;
}
具体的使用方法很简答,建立对象后,只要调用 listen() 函数开始监听就可以了。
当然在监听之前,还要连接好需要的信号和槽。
游戏手柄(JoyStick)编程学习笔记(2)的更多相关文章
- JAVA GUI编程学习笔记目录
2014年暑假JAVA GUI编程学习笔记目录 1.JAVA之GUI编程概述 2.JAVA之GUI编程布局 3.JAVA之GUI编程Frame窗口 4.JAVA之GUI编程事件监听机制 5.JAVA之 ...
- Linux Shell编程学习笔记——目录(附笔记资源下载)
LinuxShell编程学习笔记目录附笔记资源下载 目录(?)[-] 写在前面 第一部分 Shell基础编程 第二部分 Linux Shell高级编程技巧 资源下载 写在前面 最近花了些时间学习She ...
- DirectX 11游戏编程学习笔记之8: 第6章Drawing in Direct3D(在Direct3D中绘制)(习题解答)
本文由哈利_蜘蛛侠原创,转载请注明出处.有问题欢迎联系2024958085@qq.com 注:我给的电子版是700多页,而实体书是800多页,所以我在提到相关概念的时候 ...
- 多线程编程学习笔记——async和await(一)
接上文 多线程编程学习笔记——任务并行库(一) 接上文 多线程编程学习笔记——任务并行库(二) 接上文 多线程编程学习笔记——任务并行库(三) 接上文 多线程编程学习笔记——任务并行库(四) 通过前面 ...
- 多线程编程学习笔记——async和await(二)
接上文 多线程编程学习笔记——async和await(一) 三. 对连续的异步任务使用await操作符 本示例学习如何阅读有多个await方法方法时,程序的实际流程是怎么样的,理解await的异步 ...
- 多线程编程学习笔记——async和await(三)
接上文 多线程编程学习笔记——async和await(一) 接上文 多线程编程学习笔记——async和await(二) 五. 处理异步操作中的异常 本示例学习如何在异步函数中处理异常,学习如何对多 ...
- 多线程编程学习笔记——使用异步IO(一)
接上文 多线程编程学习笔记——使用并发集合(一) 接上文 多线程编程学习笔记——使用并发集合(二) 接上文 多线程编程学习笔记——使用并发集合(三) 假设以下场景,如果在客户端运行程序,最的事情之一是 ...
- 多线程编程学习笔记——编写一个异步的HTTP服务器和客户端
接上文 多线程编程学习笔记——使用异步IO 二. 编写一个异步的HTTP服务器和客户端 本节展示了如何编写一个简单的异步HTTP服务器. 1.程序代码如下. using System; using ...
- 多线程编程学习笔记——异步调用WCF服务
接上文 多线程编程学习笔记——使用异步IO 接上文 多线程编程学习笔记——编写一个异步的HTTP服务器和客户端 接上文 多线程编程学习笔记——异步操作数据库 本示例描述了如何创建一个WCF服务,并宿主 ...
- 【Visual C++】游戏编程学习笔记之四:透明动画实现
本系列文章由@二货梦想家张程 所写,转载请注明出处. 本文章链接:http://blog.csdn.net/terence1212/article/details/44224963 作者:ZeeCod ...
随机推荐
- 从MySQL向Greenplum集群中导入数据
我们要从MySQL当中导出数据到Greenplum当中,按照以下步骤就可以 1:将MySQL当中的表导出外部文件 以schema_name.table_name为例 select product_id ...
- Java中对文件的序列化和反序列化
public class ObjectSaver { public static void main(String[] args) throws Exception { /*其中的 D:\\objec ...
- C# 数据上传(自用笔记)
#region 数据上传 [HttpPost] public ActionResult UploadFile() { HttpFileCollectionBase files = Request.Fi ...
- .net网站转到出错页是如何实现的
<customErrors mode="On" defaultRedirect="GenericErrorPage.htm"><error s ...
- [翻译] CoreImage-with-EAGLContext
CoreImage-with-EAGLContext https://github.com/anaglik/CoreImage-with-EAGLContext Simple example of d ...
- Linux which/whereis/locate命令详解
which 查看可执行文件的位置,从全局环境变量PATH里面查找对应的路径,默认是找 bash内所规范的目录 whereis 查看文件的位置,配合参数-b,用于程序名的搜索,从linux数据库查找. ...
- "函中函" -------------------- func2(func) -------------- 函数名可以当做函数的参数
def func(): print("吃了么")def func2(fn): print("我是func2") fn() # 执⾏传递过来的fn # 即 fn替 ...
- XtraEditors二、ComboBox、ComboBoxEdit、CheckedComboBoxEdit
https://documentation.devexpress.com/WindowsForms/DevExpress.XtraEditors.ComboBoxEdit.class 1.使用Winf ...
- python第十一课——转换结构
3.转换函数:int():float():str():list():tuple():set():dict():bool(): 案例: #演示各个转换函数的使用: 数值型-->字符型使用:str( ...
- [Violet]天使玩偶/SJY摆棋子
题目 \(KD-tree\)做最近点对的复杂度好像是假的吧,怎么看也看不出来是\(O(\sqrt{n})\)啊 首先\(KD-tree\)长得和平衡树还是很像的,每个节点都存储了一个\(k\)维空间上 ...