精华内容
下载资源
问答
  • 多个按键同时按下的实现方法,目前实现了左、右、上、下、Enter按键以及左+上+Enter的实现,读者可以自行拓展该程序。
  • 想写判断哪些方向键同时按下的逻辑,结果发现 Qt 的按键事件只能取到单个键值,而QKeyEvent::modifiers() 又只能获取 Ctrl 或者 Shift 这种辅助按键。一番百度之后,发现可以使用容器保存按键值,在keyPressEvent ...

    1.思路

    想写个判断哪些方向键同时按下的逻辑,结果发现 Qt 的按键事件只能取到单个键值,而 QKeyEvent::modifiers() 又只能获取 Ctrl 或者 Shift 这种辅助按键。一番百度之后,发现可以使用容器保存按键值,在 keyPressEvent 添加按键值,在 keyReleaseEvent 移除按键值。

    不过单单处理按键的按下和弹起还不够,还需要注意一些事项:

    A.弹起其中一个按键时,按键事件的触发会停顿一下。所以,不能在按键事件里直接处理逻辑,需要加个定时器来遍历我们的键值容器;

    B.按键长按时会重复触发按下和弹起两个事件,这可能导致我们的键值容器在遍历时值不对(比如长按触发按键事件,导致定时器触发时我们的容器正好弹出键值就为空了)。所以,我们要单独判断下 QKeyEvent 的 isAutoRepeat,如果是自动重复触发就不处理。

    实现效果,以移动方块为例(两个方向键同时按下就是斜着移动):

    分别展示 QWidget 和 QML 的示例。

    2.QWidget 代码

    #ifndef UNIT4MOVE_H
    #define UNIT4MOVE_H
    
    #include <QOpenGLWidget>
    #include <QOpenGLFunctions_4_0_Compatibility>
    #include <QMatrix4x4>
    #include <QVector3D>
    #include <QTimer>
    
    //按键移动物体
    class Unit4Move : public QOpenGLWidget, protected QOpenGLFunctions_4_0_Compatibility
    {
        Q_OBJECT
    public:
        explicit Unit4Move(QWidget *parent = nullptr);
    
    protected:
        //设置OpenGL资源和状态。在第一次调用resizeGL或paintGL之前被调用一次
        void initializeGL() override;
        //渲染OpenGL场景,每当需要更新小部件时使用
        void paintGL() override;
        //设置OpenGL视口、投影等,每当尺寸大小改变时调用
        void resizeGL(int width, int height) override;
    
        //按键按下
        void keyPressEvent(QKeyEvent *event) override;
        //按键释放
        void keyReleaseEvent(QKeyEvent *event) override;
        //设置切换显示的时候获取焦点
        void showEvent(QShowEvent *event) override;
    
    private:
        //顶点列表
        QList<QVector3D> vertexList;
        //移动
        float xOffset=0;
        float yOffset=0;
        //当前按键按下的列表
        //因为Qt按键事件只能判断出一个键值和辅助键值的组合,
        //所以自己保存按下的按键
        QSet<int> pressedKeys;
        //刷新定时器
        QTimer *updateTimer;
    };
    
    #endif // UNIT4MOVE_H
    

     

    #include "Unit4Move.h"
    
    #include <QPainter>
    #include <QVector3D>
    #include <QtMath>
    #include <QKeyEvent>
    #include <QDebug>
    
    Unit4Move::Unit4Move(QWidget *parent)
        : QOpenGLWidget(parent)
    {
        //默认没得焦点,没法接收按键
        setFocusPolicy(Qt::StrongFocus);
    
        //多个按键按下还有一个问题,就是最后那个按键弹起后就不会重复触发了
        //所以刷新我们可以用定时器来判断容器列表,release时判断为空就关,press就开
        updateTimer=new QTimer(this);
        connect(updateTimer,&QTimer::timeout,[this]{
            //qDebug()<<"timeout"<<pressedKeys;
            if(pressedKeys.isEmpty()){
                updateTimer->stop();
                return;
            }
            for(int key:pressedKeys)
            {
                switch (key) {
                case Qt::Key_Up:
                    yOffset+=0.1f;
                    break;
                case Qt::Key_Down:
                    yOffset-=0.1f;
                    break;
                case Qt::Key_Left:
                    xOffset-=0.1f;
                    break;
                case Qt::Key_Right:
                    xOffset+=0.1f;
                    break;
                default:
                    break;
                }
            }
            update();
        });
    }
    
    void Unit4Move::initializeGL()
    {
        //此为Qt接口:为当前上下文初始化OpenGL函数解析
        initializeOpenGLFunctions();
    
        //初始化
        //矩形分为两个三角
        vertexList=QList<QVector3D>{
        {0.5f,0.5f,0.0f},
        {-0.5f,0.5f,0.0f},
        {-0.5f,-0.5f,0.0f},
        {-0.5f,-0.5f,0.0f},
        {0.5f,-0.5f,0.0f},
        {0.5f,0.5f,0.0f} };
    
        //窗口清除的颜色
        glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
    }
    
    void Unit4Move::paintGL()
    {
        //清除颜色缓冲区
        glClear(GL_COLOR_BUFFER_BIT);
    
        //【给opengl设置矩阵】
        //当前矩阵为模型矩阵
        glMatrixMode(GL_MODELVIEW);
        //重置当前指定的矩阵为单位矩阵,恢复坐标系
        //OpenGL是状态机,会保存之前的状态
        glLoadIdentity();
        glOrtho(-5,5,-5,5,-15,15);
        glTranslatef(xOffset,yOffset,0);
        glRotatef(45,0,0,1);
    
        //填充颜色
        glColor3f(0.0f,0.5f,1.0f);
        //绘制三角(坐标范围默认为[-1,1])
        glBegin(GL_TRIANGLES);
        for(const QVector3D &vertex:vertexList){
            glVertex3f(vertex.x(),vertex.y(),vertex.z());
        }
        glEnd();
    
        //绘制文本
        QPainter painter(this);
        painter.setPen(QColor(255,255,255));
        painter.drawText(20,40,"点击获取焦点后,按方向键移动!");
    }
    
    void Unit4Move::resizeGL(int width, int height)
    {
        //视口,靠左下角缩放
        glViewport(0,0,width,height);
    }
    
    void Unit4Move::keyPressEvent(QKeyEvent *event)
    {   
        QOpenGLWidget::keyPressEvent(event);
        //按键按下,key值放入容器,如果是长按触发的repeat就不判断
        if(!event->isAutoRepeat())
            pressedKeys.insert(event->key());
        //判断是否运行,不然一直触发就一直不能timeout
        if(!updateTimer->isActive())
            updateTimer->start(100);
    }
    
    void Unit4Move::keyReleaseEvent(QKeyEvent *event)
    {
        QOpenGLWidget::keyReleaseEvent(event);
        //按键释放,从容器中移除,如果是长按触发的repeat就不判断
        if(!event->isAutoRepeat())
            pressedKeys.remove(event->key());
        if(pressedKeys.isEmpty()){
            updateTimer->stop();
        }
    }
    
    void Unit4Move::showEvent(QShowEvent *event)
    {
        QOpenGLWidget::showEvent(event);
        setFocus();
    }
    

    3.QML 代码

    import QtQuick 2.12
    import QtQuick.Window 2.12
    import QtQuick.Controls 2.12
    
    Window {
        visible: true
        width: 640
        height: 480
        title: qsTr("GongJianBo")
    
        //存储当前按下的键值,使用ES6的集合类型
        property variant pressedKeys:new Set()
    
        Rectangle{
            id: item
            //anchors.centerIn: parent
            x:100
            y:100
            width: 100
            height: 100
            color: "green"
    
            focus: true
            //按键按下
            Keys.onPressed: {
                //键值放入set
                if(!event.isAutoRepeat){
                    pressedKeys.add(event.key)
                }
                if(!timer.running){
                    timer.start()
                }
            }
            //按键释放
            Keys.onReleased: {
                //键值弹出set
                if(!event.isAutoRepeat){
                    pressedKeys.delete(event.key)
                }
                if(pressedKeys.size<=0){
                    timer.stop()
                }
            }
        }
    
        Timer{
            id:timer
            repeat: true
            interval: 50
            onTriggered: {
                //console.log(pressedKeys.size)
                if(pressedKeys.size<=0){
                    timer.stop()
                    return
                }
    
                //遍历存储的键值,实现同时处理多个按键按下状态
                for(let key of pressedKeys)
                {
                    switch (key) {
                    case Qt.Key_Up:
                        item.y-=5;
                        break;
                    case Qt.Key_Down:
                        item.y+=5;
                        break;
                    case Qt.Key_Left:
                        item.x-=5;
                        break;
                    case Qt.Key_Right:
                        item.x+=5;
                        break;
                    default:
                        break;
                    }
                }
            }
        }
    }
    

     

    展开全文
  • c#实现多个按键同时按下检测

    千次阅读 2011-05-29 14:00:00
    在C#中实现了多个按键同时按下的检测

        下面的方法在C#中实现了三个按键同时按下的检测,更多按键按下同样可以检测。

        在PreviewKeyDown事件中检测按键按下:

            private void Form1_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e)
            {
                switch (e.KeyValue)
                {
                    case 'A':
                        if (key1down == false)
                            MessageBox.Show("A down");
                        key1down = true;             // 按键"A"按下此标志为true,直到放开
                        break;
                    case 'B':
                        if (key2down == false)
                            MessageBox.Show("B down");
                        key2down = true;            // 按键"B"按下此标志为true,直到放开
                        break;
                    case 'C':
                        if (key3down == false)
                            MessageBox.Show("C down");
                        key3down = true;            // 按键"C"按下此标志为true,直到放开
                        break;
                }
            }

     

        在KeyUp事件中检测按键放开:
            private void Form1_KeyUp(object sender, KeyEventArgs e)
            {
                switch (e.KeyValue)
                {
                    case 'A':
                            MessageBox.Show("A up");
                        key1down = false;           // 按键"A"放开此标志为false
                        break;
                    case 'B':
                            MessageBox.Show("B up");
                        key2down = false;          // 按键"A"放开此标志为false
                        break;
                    case 'C':
                            MessageBox.Show("C up");
                        key3down = false;          // 按键"A"放开此标志为false
                        break;
                }
            }

    展开全文
  • public void input() { int keystate = getKeyStates(); //右键跟上键同时按下的状态 int ru = GameCanvas.RIGHT_PRESSED | GameCanvas.UP_PRESSED; //保存状态结果 int result = 0

    public void input()
        {
            int keystate = getKeyStates();
            

            //右键跟上键同时按下的状态
            int ru = GameCanvas.RIGHT_PRESSED | GameCanvas.UP_PRESSED;

            //保存状态结果
            int result = 0;
           

            //如果右键跟上键中有任意一键被按下
            if ((result = keystate & ru) != 0)
            {

                //如果只有右键被按下
                if (result == GameCanvas.RIGHT_PRESSED)
                {
                    System.out.println("Right");
                }
                else if (result == GameCanvas.UP_PRESSED) //只有左键被按下
                {
                    System.out.println("Up");
                }
                else
                {
                    System.out.println("Left and up"); //两键同时被按下
                }
            }

    }

    展开全文
  • 做一小程序前的问题,得到sololie,kiboisme两位兄台的帮助,谢分,此贴谢 kiboisme哥,另开新贴 谢 sololie哥!
  • getch() 函数,用于返回用户输入的字符。...如果需要平滑的按键输入,或者同时按多个按键,就不能用 getch() 了,需要使用另一个 Windows API 函数:GetAsyncKeyState()。该函数原型如下: SHORT Ge...

    getch() 函数,用于返回用户输入的字符。当连续按键时,该函数返回第一个字符和第二个字符之间,默认有 0.5 秒的延时,并且之后的连续字符,默认是每秒钟 15 次输入。这两个数值可以在控制面板中设置。

    如果需要平滑的按键输入,或者同时按下多个按键,就不能用 getch() 了,需要使用另一个 Windows API 函数:GetAsyncKeyState()。该函数原型如下:

    SHORT GetAsyncKeyState(
    	int vKey		// virtual-key code
    );
    

    vKey 是要检测的按键的虚拟键码,常用的如 VK_UP、VK_DOWN 等,分别表示方向键的上、下等。需要注意:对于 26 个字母的键码,可以直接写 ‘A’、‘B’……,而不要写 VK_A、VK_B。数字键也是,请直接写 ‘0’、‘1’……。全部的 256 种虚拟键码,请参考 MSDN 中的 Virtual-Key Codes。

    返回的 SHORT 值,如果最高位为 1,表示该键被按下;否则表示该键弹起。该函数的最低位还可以用来检测开关键(比如大小写锁定键)的状态。作为按键处理,还可以使用 GetKeyState、GetKeyboardState 等函数,详细请参考 MSDN 手册中的 Keyboard Input Functions 部分。

    下面给一个简单的例子,该范例是用键盘的上下左右键移动一个圆,并且可以通过左 Shift 放大、左 Ctrl 缩小,几个按键可以同时灵活地控制圆。代码如下:

    // 程序名称:同时检测多个按键及平滑按键输入的范例
    // 编译环境:Visual C++ 6.0 / 2010,EasyX 惊蛰版
    //
    #include <graphics.h>
    
    /
    // 定义常量、枚举量、结构体、全局变量
    /
    
    #define	CMD_UP			1
    #define	CMD_DOWN		2
    #define	CMD_LEFT		4
    #define	CMD_RIGHT		8
    #define	CMD_ZOOMIN		16
    #define	CMD_ZOOMOUT		32
    #define	CMD_QUIT		64
    
    // 声明圆的坐标和半径
    int g_x, g_y, g_r;
    
    
    
    /
    // 函数声明
    /
    
    void Init();						// 初始化
    void Quit();						// 退出
    int  GetCommand();					// 获取控制命令
    void DispatchCommand(int _cmd);		// 分发控制命令
    void OnUp();						// 上移
    void OnDown();						// 下移
    void OnLeft();						// 左移
    void OnRight();						// 右移
    void OnZoomIn();					// 放大
    void OnZoomOut();					// 缩小
    
    
    
    /
    // 函数定义
    /
    
    // 主函数
    void main()
    {
    	Init();
    
    	int c;
    	do
    	{
    		c = GetCommand();
    		DispatchCommand(c);
    		Sleep(10);
    	}while(!(c & CMD_QUIT));
    
    	Quit();
    }
    
    // 初始化
    void Init()
    {
    	// 设置绘图屏幕和绘图模式
    	initgraph(640, 480);
    	setwritemode(R2_XORPEN);
    
    	// 设置圆的初始位置和大小
    	g_x = 320;
    	g_y = 240;
    	g_r = 20;
    
    	// 显示操作说明
    	setfont(14, 0, _T("宋体"));
    	outtextxy(20, 270, _T("操作说明"));
    	outtextxy(20, 290, _T("上:上移"));
    	outtextxy(20, 310, _T("下:下移"));
    	outtextxy(20, 330, _T("左:左移"));
    	outtextxy(20, 350, _T("右:右移"));
    	outtextxy(20, 370, _T("左 Shift:放大"));
    	outtextxy(20, 390, _T("左 Ctrl:缩小"));
    	outtextxy(20, 410, _T("ESC:退出"));
    	outtextxy(20, 450, _T("注:可以同时按多个键,但能同时按下的键的数量,受键盘硬件限制"));
    
    	// 画圆
    	circle(g_x, g_y, g_r);
    }
    
    // 退出
    void Quit()
    {
    	closegraph();
    }
    
    // 获取控制命令
    int GetCommand()
    {
    	int c = 0;
    
    	if (GetAsyncKeyState(VK_LEFT) & 0x8000)		c |= CMD_LEFT;
    	if (GetAsyncKeyState(VK_RIGHT) & 0x8000)	c |= CMD_RIGHT;
    	if (GetAsyncKeyState(VK_UP) & 0x8000)		c |= CMD_UP;
    	if (GetAsyncKeyState(VK_DOWN) & 0x8000)		c |= CMD_DOWN;
    	if (GetAsyncKeyState(VK_LSHIFT) & 0x8000)	c |= CMD_ZOOMIN;
    	if (GetAsyncKeyState(VK_LCONTROL) & 0x8000)	c |= CMD_ZOOMOUT;
    	if (GetAsyncKeyState(VK_ESCAPE) & 0x8000)	c |= CMD_QUIT;
    
    	return c;
    }
    
    // 分发控制命令
    void DispatchCommand(int _cmd)
    {
    	if (_cmd & CMD_UP)			OnUp();
    	if (_cmd & CMD_DOWN)		OnDown();
    	if (_cmd & CMD_LEFT)		OnLeft();
    	if (_cmd & CMD_RIGHT)		OnRight();
    	if (_cmd & CMD_ZOOMIN)		OnZoomIn();
    	if (_cmd & CMD_ZOOMOUT)		OnZoomOut();
    }
    
    // 上移
    void OnUp()
    {
    	circle(g_x, g_y, g_r);
    	if (g_y <= 0) g_y = 480; else g_y-=2;
    	circle(g_x, g_y, g_r);
    }
    
    // 下移
    void OnDown()
    {
    	circle(g_x, g_y, g_r);
    	if (g_y >= 480) g_y = 0; else g_y+=2;
    	circle(g_x, g_y, g_r);
    }
    
    // 左移
    void OnLeft()
    {
    	circle(g_x, g_y, g_r);
    	if (g_x <= 0) g_x = 640; else g_x-=2;
    	circle(g_x, g_y, g_r);
    }
    
    // 右移
    void OnRight()
    {
    	circle(g_x, g_y, g_r);
    	if (g_x >= 640) g_x = 0; else g_x+=2;
    	circle(g_x, g_y, g_r);
    }
    
    // 放大
    void OnZoomIn()
    {
    	circle(g_x, g_y, g_r);
    	if (g_r < 100) g_r++;
    	circle(g_x, g_y, g_r);
    }
    
    // 缩小
    void OnZoomOut()
    {
    	circle(g_x, g_y, g_r);
    	if (g_r > 10) g_r--;
    	circle(g_x, g_y, g_r);
    }
    

    再额外说一个小问题:由于 GetAsyncKeyState() 函数获取的按键状态是直接取自硬件,并非取自消息队列。所以,即便程序处非活动状态,GetAsyncKeyState() 仍然可以正确获取按键状态。所以会有这样一个问题:比如你写了一个打字练习的小游戏,在游戏中途切换到另一个应用去发邮件,你会看到发邮件录入文字时,你的打字练习小游戏仍然会接受键盘输入。很明显,这时候需要判当前应用是否处于活动状态。解决方法有多种,例如,通过 Windows API 函数 GetForegroundWindow() 获取到当前前景窗口的句柄,再和 EasyX 窗口的句柄对比,如果相同,就表示 EasyX 的窗口处于活动状态,从而解决非活动状态的按键处理问题。

    展开全文
  • 求助,Java如何响应同时按多个键盘按键? 现在写个小游戏,当人物有移动和发射子弹的功能。 但是在移动的过程中发射子弹,人物就会停下来。 我想同时响应两个按键,互不影响。 还想问一下, 测试时感觉操作很...
  • JavaScript捕获同时多个按键-非组合键

    千次阅读 2017-07-18 15:11:18
    用户同时按下两个或多个按键时,如何判断用户按下了哪些键: 比如如何判断用户同时按下了‘A’和‘H’键 segmentd 的 Clark 提供的思路: Ctl,alt是有专门判断的属性的。如果是其他的组合,我有想法,就是keydown...
  •  在产品开发中,假设我们要在APP的某个页面中,同时按多个按键进入工厂测试模式。又假设我们要写一个魂斗罗或者超级玛丽的游戏,我们需要按方向键让小人走,按某个键跳或者射击,这都需要先后检测按键是否按下。 ...
  • 自动按键 鼠标自动按键 可以添加 多个按键同时按 鼠标定位功能 ~
  • 苹果键盘的一个或多个按键没有响应怎么解决??请先使用“虚拟键盘”测试键盘按键是否在下时正常响应。具体步骤,请参考下方:选取苹果菜单 >“系统偏好设置”然后选择“语言与地区”。点“键盘偏好设置”...
  • 情景引入 ...一. 处理对象八方向的移动... 同时响应多按键.(如音乐类游戏,同时按下F和J按键才算击中)(注意是同时相应,而不是拿什么标识来处理那个按下了!那个未按下) 相关解决方案 ...
  • 一开始单片机将行线(P10~P13)全部输出低电平,此时读入列线数据,若列线全为高电平则没有键下,当列线有出现低电平时调用延时程序以此来去除按键抖动。延时完成后再判断是否有低电平,如果此时读入列线数据还是...
  • appweight有时候需要响应多出的按键,如多个按钮在同一个weight要同时响应这么多个按钮的时间 肯定不能像在activity里面处理,而是通过类似广播机制的方法来处理。通过对自己发送action,自己接受action, 自己...
  • FPGA 多按键抖动检测

    2020-08-05 09:40:17
    用Verilog HDL语言实现FPGA按键检测,可同时检测四个按键。有任意按键按下时,开始20ms计时,若按键发生抖动就重新计时,当按键状态稳定20ms后读取按键值,支持多按键同时按下。
  • This post introduces a key presser on Linux with xvkb. But how to simulate pressing multiple keys together on Linux?... 但是如何在Linux上模拟同时按多个键? That is, I would like to have multi...
  • 下时,如果我下“o”,我会得到一“o”的新闻和发布流,但没有更的“w”事件。您需要设置一小型状态机,并绑定到按键按键释放事件。这将让您跟踪哪些键已下,哪些键未下。然后,每次你画一框架...
  • 这次更新基于STM32F103的4*5矩阵按键,测试通过。 多个按键同时按下,有效值以最后一个释放的按键值为准。
  • 接触过的按键驱动中,大部分是使用延时函数消抖,或者...在讲解之前,先说明一下按键,短,长按,单击,击分别是如何区分的。这里非常感谢张俊老师编著的《匠人手机》这本书中关于按键的讲解,给了我很大的启发...
  • 行列扫描支持多按键原理图,主要特点是支持同时多个按键按下。普通设计不支持3个及以上按键下。
  • stm32按键 长按 短 函数 二

    千次阅读 2019-11-30 22:57:21
    在学习过程中,遇到了要使用很多个按键的情况,(没有同时按下的处理,没有用矩阵键盘)。一增加一个新按键,需要改动的地方太多,在网上看了一篇博客 https://blog.csdn.net/jiejiemcu/article/details/83097992 ...
  • STM32F103 4*5矩阵按键,调试成功

    千次阅读 2016-04-10 11:02:42
    这次更新基于STM32F103的4*5矩阵按键,测试通过。 多个按键同时按下,有效值以最后一个释放的按键值为准。 代码下载链接: http://download.csdn.net/detail/db_winner/9486348
  • 本文讲述基于MDK RTX系统的一种独立按键键值检测,能够实现按键检测,同时多个按键按下检测,长按按键检测功能,并具有软件防抖功能。 #define KEY_START_HOLD_TIME 200 //长按时间,2秒 //键值 enum{ K_IDLE...
  • 起初我以为键盘坏了,特意上浏览器搜索"键盘部分按键无效怎么办",输入完文字习惯性下"Enter",这时候居然好了…(一阵无言),后来次测试方向只有VSCode中部分按键无效,其他应用完好,不信你看,我打几回车 ...
  • 在实时交互程序中尤其是游戏程序中经常要判断的多个键同时按下的...但事件响应时的 event 中只有一个 keycode,因此单纯的在一个事件中是无法处理多个按键状态的。不过把它们组合起来使用就可以实现了。基本原理如下:
  • 也可设置一个宏按键,执行多个点击命令,下此按键可在多个位置同时点击,达到一键多用的效果。   使用宏按键功能最便捷的方法是用安卓模拟器在电脑上操作。因为大部分模拟器都是免费的,而重新...
  • HashMap按键排序和值排序

    热门讨论 2018-03-25 21:25:28
    走进Map map是键值对的集合接口,他的实现...最常用的map,他根据key的hashcode值来存储数据,根据key可以直接获取他的value,同时它具有很快的访问速度..HashMap最多只允许一条记录的key值为null,允许条记录的value...
  • 前面有朋友大概了问了这样一个问题:我想在STM8单片机上,不跑操作系统,在需要处理一些业务逻辑时,还需要检测按键短按、长按、多个按键同时按下,我要如何实现?不跑操作系统,...
  • Sp-star Mk101 MK101采用了相比传统全尺寸减配更加紧凑精简风格同时照顾到用户习惯,INS/DEL...选了黑黄灰配色还是非常抓眼球了整体布局和980类似,但是可以看到了Ins和Del的按键和屏幕一枚值得注意的是这两个按...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 434
精华内容 173
关键字:

多个按键同时按