游戏手柄(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 ...
随机推荐
- win7 下安装oracle 10 g
首先下对版本,Oracle 10g支持Win7版: http://download.oracle.com/otn/nt/oracle10g/10203/10203_vista_w2k8_x86_pro ...
- [翻译] NSDate-TimeAgo
NSDate-TimeAgo https://github.com/kevinlawler/NSDate-TimeAgo NSDate+TimeAgo has merged with DateTool ...
- 铁乐学python_day18-19_面向对象编程1
以下笔记绝大部分(百分之80或以上)摘自我的授课老师之一:老男孩教育中的景老师. 她上课讲的知识点由浅入深,引人入胜,听她的课完全不会感觉到困阿,而且不知不觉中就感觉掌握了. 她的博客是: http: ...
- javascript改写 <select>checked的选中,并不会出发change事件,太好了!
<html> <title>测试select标签的分别用程序checked.用户手动checked</title> <body> 第一级菜单: < ...
- openoffice centos7.4 安装
其他是配置好java环境后操作 1.下载软件 http://www.openoffice.org/download/other.html 2.安装 tar xf Apache_OpenOffice_4 ...
- ZT 9种排序
9种排序 2012-09-19 14:58 66人阅读 评论(0) 收藏 编辑 删除 algorithmfpfilemergeintegerfloat [cpp] view plaincopy #in ...
- adb shell 运行时报错"adb server version (26) doesn't match this client (39); killing..."的解决方案
adb即 Android Debug Bridge 是一个通用的命令行工具,可用于通过PC端对连接的Android模拟器设备或连接至电脑的真实物理设备进行命令行操作.目前,许多软件均会借助 adb 工 ...
- JS BOM简列
JS BOM BOM 也叫浏览器对象模型,它提供了很多对象,用于访问浏览器的功能.BOM 缺少规范,每个浏览器提供商又按照自己想法去扩展它,那么浏览器共有对象就成了事实的标准.所以,BOM 本身是没有 ...
- 基于easyui开发Web版Activiti流程定制器详解(二)——文件列表
上一篇我们介绍了目录结构,这篇给大家整理一个文件列表以及详细说明,方便大家查找文件. 由于设计器文件主要保存在wf/designer和js/designer目录下,所以主要针对这两个目录进行详细说明. ...
- 学习python第三天单行函数
1.去重:distinct关键字 需求:查看公司一共有多少部门? select department_id from employees;此代码会查出107条记录,存在部门重复的问题! select ...