游戏手柄(JoyStick)编程控制的一个简单代码(Qt)

最近买到一种USB 接口的三轴 8 个按键的Joystick。下面这个样子。
三轴 Joystick
用在最近做的一个工控项目上效果还不错。这里把代码公开了。
Joystick 的控制我以前写过两篇博客:
http://blog.csdn.net/liyuanbhu/article/details/51714045
http://blog.csdn.net/liyuanbhu/article/details/54809858

第一篇博客中把原理基本都讲清楚了。所以这里就只贴代码了。
代码的基本思路就是建立一个监听线程,轮询 joystick 的状态。不同的状态输出不同的结果。因为我的项目中都是只用到一个Joystick,所以代码也没考虑多个 Joystick 的情况。

#ifndef JOYSTICK_H
#define JOYSTICK_H

#include <QThread>

/**
  * 3 轴 8 按键 Joystick 的驱动程序。
  * 使用的是微软的 multimedia joystick API。
  * 没有使用更流行的 DirectInput 技术。
 */
class JoystickThread : public QThread
{
    Q_OBJECT
public:
    explicit JoystickThread(QObject *parent = Q_NULLPTR);
    /**
     * @brief run 启动监听线程
     */
    void run();
    /**
     * @brief stop 停止监听线程
     */
    void stop();

signals:
    /// 手柄 XY 轴的输出信号
    /// 需 enableSignal(true), enableXYSignal(true) 才有效
    void Joy_MoveForward();
    void Joy_MoveBackward();
    void Joy_MoveForwardStop();
    void Joy_MoveBackwardStop();
    void Joy_MoveLeft();
    void Joy_MoveRight();
    void Joy_MoveLeftStop();
    void Joy_MoveRightStop();

    /// 手柄 Z 轴的输出信号
    /// 需 enableSignal(true), enableZSignal(true) 才有效
    void Joy_MoveClockWise();
    void Joy_MoveCCW();
    void Joy_MoveClockWiseStop();
    void Joy_MoveCCWStop();

    /// 手柄按键的输出信号
    /// 需 enableSignal(true), enableButtionSignal(true) 才有效
    void Joy_Button1Pressed();
    void Joy_Button2Pressed();
    void Joy_Button3Pressed();
    void Joy_Button4Pressed();
    void Joy_Button5Pressed();
    void Joy_Button6Pressed();
    void Joy_Button7Pressed();
    void Joy_Button8Pressed();
    void Joy_Button1Released();
    void Joy_Button2Released();
    void Joy_Button3Released();
    void Joy_Button4Released();
    void Joy_Button5Released();
    void Joy_Button6Released();
    void Joy_Button7Released();
    void Joy_Button8Released();
public slots:
    /**
     * @brief setXYThreshold 设置 XY 手柄的开启阈值。
     * 由于手柄使用时间长了会由于机械问题在原点停不住。所以需要有个开启阈值。
     * @param x  x 阈值
     * @param y  y 阈值
     */
    void setXYThreshold(int x, int y);
    /**
     * @brief setZThreshold 设置 Z 手柄的开启阈值。
     * @param z  z 阈值
     */
    void setZThreshold(int z);
    /**
     * @brief enableSignal 可以用这个函数关闭所有的信号
     * @param on
     */
    void enableSignal(bool on) {m_signal = on;}
    /**
     * @brief enableXYSignal XY 手柄的使能控制,只有enableSignal(true)时才有效。
     * 相当于对手柄的信号有两级控制,第一级是全局使能,第二级是这里的使能。
     * @param on
     */
    void enableXYSignal(bool on) {m_xy_signal = on;}
    void enableZSignal(bool on) {m_z_signal = on;}
    void enableButtionSignal(bool on ){m_button_signal = on;}

    /**
     * @brief setMonitorInterval 设置内部轮询的时间间隔
     * @param interval 单位 ms,范围 20 - 10000。
     */
    void setMonitorInterval(int interval);
private:
    int Axis_stateMachine(int pos, int threshold, int &old_pos);
    void AxisX_StateMachine(int xPos);
    void AxisY_StateMachine(int yPos);
    void AxisZ_StateMachine(int zPos);
    void Button_StateMachine(int button);

    int m_xThreshold;
    int m_yThreshold;
    int m_zThreshold;

    int old_xPos;
    int old_yPos;
    int old_zPos;
    int m_button[8];

    bool m_run;
    bool m_valid;

    bool m_signal;
    bool m_xy_signal;
    bool m_z_signal;
    bool m_button_signal;

    int m_monitor_interval;
};

#endif // JOYSTICK_H
#include "Joystick3D.h"
#include <Windows.h>
#include <QDebug>


JoystickThread::JoystickThread(QObject *parent)
    :QThread(parent),
      m_valid(false),
      m_run(true),
      m_xThreshold(5000),
      m_yThreshold(5000),
      m_zThreshold(5000),
      old_xPos(0),
      old_yPos(0),
      old_zPos(0),
      m_signal(false),
      m_xy_signal(false),
      m_z_signal(false),
      m_button_signal(false),
      m_monitor_interval(50)
{
    JOYINFO joyinfo;
    if( joyGetNumDevs() > 0 && joyGetPos(JOYSTICKID1, &joyinfo) != JOYERR_UNPLUGGED )
    {
        m_valid = true;
        qDebug() << "m_valid = true";
    }

    for(int i = 0; i < 8; i++)
    {
        m_button[i] = 0;
    }
}

void JoystickThread::stop()
{
   m_run = 0;
   wait();
}

void JoystickThread::setXYThreshold(int x, int y)
{
    m_xThreshold = abs(x);
    m_yThreshold = abs(y);
}

void JoystickThread::setZThreshold(int z)
{
    m_zThreshold = abs(z);
}

void JoystickThread::run()
{
    JOYINFOEX joyinfoex;
    joyinfoex.dwSize = sizeof(JOYINFOEX);
    joyinfoex.dwFlags = JOY_RETURNALL;
    while(m_valid && m_run)
    {
        if(joyGetPosEx(JOYSTICKID1, &joyinfoex) == JOYERR_NOERROR)
        {
            AxisX_StateMachine(joyinfoex.dwXpos);
            AxisY_StateMachine(joyinfoex.dwYpos);
            AxisZ_StateMachine(joyinfoex.dwZpos);
            Button_StateMachine(joyinfoex.dwButtons);
        }

        msleep(m_monitor_interval);
    }
}

void JoystickThread::setMonitorInterval(int interval)
{
    m_monitor_interval = qBound(20, interval, 10000);
}

int JoystickThread::Axis_stateMachine(int pos, int threshold, int &old_pos)
{
    pos = pos - 32767;
    if(abs(pos) <= threshold)
    {
        pos = 0;
    }
    else if (pos > threshold)
    {
        pos = 1;
    }
    else
    {
        pos = -1;
    }
    if(pos == old_pos) return 0;
    int ret;
    switch(pos)
    {
    case -1:
        ret = -1;
        break;
    case 0:
        if(old_pos == -1)
        {
            ret = -2;
        }
        else
        {
            ret = 2;
        }
        break;
    case 1:
        ret = 1;
        break;
    }
    //qDebug() << "o = " << old_pos << ", " << pos << ", ret =" << ret;
    old_pos = pos;
    return ret;
}

void JoystickThread::AxisX_StateMachine(int xPos)
{
    int ret = Axis_stateMachine(xPos, m_xThreshold, old_xPos);
    if(!m_signal || !m_xy_signal) return;
    switch(ret)
    {
    case -1:
        emit Joy_MoveLeft();
        break;
    case -2:
        emit Joy_MoveLeftStop();
        break;
    case 2:
        emit Joy_MoveRightStop();
        break;
    case 1:
        emit Joy_MoveRight();
        break;
    default:
        break;
    }
}

void JoystickThread::AxisY_StateMachine(int yPos)
{
    int ret = Axis_stateMachine(yPos, m_yThreshold, old_yPos);
    if(!m_signal || !m_xy_signal) return;
    switch(ret)
    {
    case -1:
        emit Joy_MoveForward();
        break;
    case -2:
        emit Joy_MoveForwardStop();
        break;
    case 2:
        emit Joy_MoveBackwardStop();
        break;
    case 1:
        emit Joy_MoveBackward();
        break;
    default:
        break;
    }
}

void JoystickThread::AxisZ_StateMachine(int zPos)
{
    int ret = Axis_stateMachine(zPos, m_zThreshold, old_zPos);
    if(ret == 0) return;
    //qDebug() << zPos - 32767 << ", " << ret;
    if(!m_signal || !m_z_signal) return;
    switch(ret)
    {
    case -1:
        emit Joy_MoveCCW();
        break;
    case -2:
        emit Joy_MoveCCWStop();
        break;
    case 2:
        emit Joy_MoveClockWiseStop();
        break;
    case 1:
        emit Joy_MoveClockWise();
        break;
    default:
        break;
    }
}

void JoystickThread::Button_StateMachine(int button)
{
    const int mask[8] = {1, 2, 4, 8, 16, 32, 64, 128};
    for(int i = 0; i < 8; i++)
    {
        int n = button & mask[i];
        if(n ^ m_button[i]) // 如果当前 button 与以前的 button 不同
        {
            m_button[i] = n;
            if(!m_signal || !m_button_signal) continue;
            if( n )
            {
                qDebug() << "Joy_Button" << i+1 << "Pressed()";
                switch (i + 1)
                {
                case 1:
                    emit Joy_Button1Pressed();
                    break;
                case 2:
                    emit Joy_Button2Pressed();
                    break;
                case 3:
                    emit Joy_Button3Pressed();
                    break;
                case 4:
                    emit Joy_Button4Pressed();
                    break;
                case 5:
                    emit Joy_Button5Pressed();
                    break;
                case 6:
                    emit Joy_Button6Pressed();
                    break;
                case 7:
                    emit Joy_Button7Pressed();
                    break;
                case 8:
                    emit Joy_Button8Pressed();
                    break;
                default:
                    break;
                }
            }
            else
            {
                qDebug() << "Joy_Button" << i+1 << "Released()";
                switch (i + 1)
                {
                case 1:
                    emit Joy_Button1Released();
                    break;
                case 2:
                    emit Joy_Button2Released();
                    break;
                case 3:
                    emit Joy_Button3Released();
                    break;
                case 4:
                    emit Joy_Button4Released();
                    break;
                case 5:
                    emit Joy_Button5Released();
                    break;
                case 6:
                    emit Joy_Button6Released();
                    break;
                case 7:
                    emit Joy_Button7Released();
                    break;
                case 8:
                    emit Joy_Button8Released();
                    break;
                default:
                    break;
                }
            }
        }
    }
}
相关推荐
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页