游戏手柄(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 ...
随机推荐
- [域|Domain] The trust relationship between this workstation and the primary domain failed 此工作站和主域间的信任关系失败
PS> $cred = Get-Credential domain.sample.com;Reset-ComputerMachinePassword -Credential $cred -Ser ...
- Tomcat6.0下的jsp、servlet和javabean的配置
第一步:下载jdk和tomcat: 第二步:安装和配置你的jdk和tomcat:执行jdk和tomcat的安装程序,然后设置按照路径进行安装即可.1.安装jdk以后,需要配置一下环境变量,在我的电脑- ...
- 名词解释:Linux内存管理之RSS和VSZ
Linux内存管理中不管是top命令还是pmap命令,都会有RSS和VSZ这两个名词,这里解释一下: RSS( Resident Set Size )常驻内存集合大小,表示相应进程在RAM中占用了多少 ...
- [沫沫金]JavaWeb企业信息系统,增加操作记录、数据库记录
背景 系统出现数据莫名丢失,业务人员的反馈无法复现问题.纠结了很久,最终老板发话要记录操作,通过日志进行分析重现 环境 SSH框架 目标 1.记录访问了那个方法,使用的参数及返回的内容 2.记录新增. ...
- spring中MessageSource的配置使用方法2--ReloadableResourceBundleMessageSource【转】
本文转载仅供自己学习收录,不做任何商业用途,如有需要可访问原地址:http://blog.csdn.net/qyf_5445/article/details/8124362 如何在spring mvc ...
- Apache Hadoop各版本发布的SVN地址
http://svn.apache.org/repos/asf/hadoop/common/tags
- web应用安全发展与介绍
安全与安全圈的认识 中国黑客的发展过程:1990年代初,部分人开始研究黑客技术 1997-1999年,黑客团队涌现,进入黄金时代, 21世纪初,黑客工具傻瓜化,门槛降低,黑客精神不在… 圈内熟知的安全 ...
- 20165318 2017-2018-2 《Java程序设计》第七周学习总结
20165318 2017-2018-2 <Java程序设计>第七周学习总结 目录 学习过程遇到的问题及总结 教材学习内容总结 第11章 JDBC与MySQL数据库 错题总结 第五周错题总 ...
- Java基础加强之并发(一)基本概念介绍
基本概念介绍 进程:它是内存中的一段独立的空间,可以负责当前应用程序的运行.当前这个进程负责调度当前程序中的所有运行细节. 线程:它是位于进程中,负责当前进程中的某个具备独立运行资格的空间. 进程是负 ...
- Odoo图片如何显示
转载请注明原文地址:https://www.cnblogs.com/cnodoo/p/9281423.html odoo没有专门的图片标签,但是可以通过widget来控制field标签来显示图片内容. ...