• 基于Windows api手柄映射编程


    转:https://www.cnblogs.com/qyit/archive/2011/11/21/2257687.html

    一个手柄/键盘映射程序,无外乎就四部分:一、界面;二、接收;三、处理;四、输出。

    界面就不多说了。

    接收,就是接收手柄的输出。这部分有多种方法,比如windows API和DirectX,这里我们选前者。

    处理,就是将接收到的数据映射为输出数据。

    输出,就是向操作系统发送假的键盘事件,从而完成映射过程。

    接收部分:

    那么,我们先来进行知识的准备。为了完成接收部分,我们需要了解和手柄相关的windows API。其中常用的较重要的函数如下:

    joyGetDevCaps                  查询指定的游戏杆设备以确定其性能
    
    joyGetNumDevs                  返回系统支持的游戏杆设备的数量
    
    joyGetPos                       查询指定的游戏杆设备的位置和活动性
    
    joyGetPosEx                    查询一个游戏杆设备的位置和它的按扭状态
    
    joyGetThreshold                查询指定的游戏杆设备的当前移动阈值
    
    joyReleaseCapture              释放由JoySetCapture函数设置的在指定游戏杆设备上的捕获
    
    joySetCapture                  发送一个游戏杆消息到指定的窗口
    
    joySetThreshold                设置指定的游戏杆设备的移动阈值

    要使用这几个API,需要连接winmm.lib,包含mmsystem.h头文件。

    如果仅制作基本的映射功能,那么我们并不需要用到全部的函数。主要使用的是这个:

    MMRESULT joyGetPosEx(UINT uJoyID, LPJOYINFOEX pji) 

    这个函数可以主动取得游戏杆信息。

    参数uJoyID是指手柄的ID,对于单手柄编程,填写JOYSTICKID1即可。 

    参数pji是一个指向JOYINFOEX型结构体的指针。JOYINFOEX的定义如下:

    typedef struct joyinfoex_tag {
    
        DWORD dwSize;     /* size of structure */
    
        DWORD dwFlags;       /* flags to indicate what to return */
    
        DWORD dwXpos;                /* x position */
    
        DWORD dwYpos;                /* y position */
    
        DWORD dwZpos;                /* z position */
    
        DWORD dwRpos;     /* rudder/4th axis position */
    
        DWORD dwUpos;     /* 5th axis position */
    
        DWORD dwVpos;     /* 6th axis position */
    
        DWORD dwButtons;             /* button states */
    
        DWORD dwButtonNumber;        /* current button number pressed */
    
        DWORD dwPOV;                 /* point of view state */
    
        DWORD dwReserved1;
    
        DWORD dwReserved2;
    
    } JOYINFOEX, *PJOYINFOEX, NEAR *NPJOYINFOEX, FAR *LPJOYINFOEX;

    它包含了指定手柄当前的状态信息。我们主要用到的是其中的dwFlags,dwXpos,dwYpos以及dwButtons。这四个成员依次表示:获取状态,十字键X轴当前状态,十字键Y轴当前状态,功能键当前状态。

    我们在使用joyGetPosEx获得手柄状态前,先要把dwFlags设置为JOY_RETURNALL,即返回全部按键状态,这样才能同时获得十字键和功能键的信息。

    dwXpos和dwYpos的值分别代表了X轴和Y轴当前的状态。对于使用windows默认的自带手柄驱动的,按键情况和对应值如下:

    注意:如果安装了手柄驱动盘,值会随驱动不同而改变,请自行测定

    而dwButtons的每一位对应手柄的一个功能键状态,0表示抬起状态,1表示按下状态。(注意,是状态,不是动作)对应关系是从低位到高位对应功能键1至手柄功能键最高数。

    joyGetPosEx函数的返回值可能是以下几种:

    /* joystick error return values */
    
    #define JOYERR_NOERROR  (0)                /* no error */
    
    #define JOYERR_PARMS    (JOYERR_BASE+5)  /* bad parameters */
    
    #define JOYERR_NOCANDO  (JOYERR_BASE+6)  /*request not completed */
    
    #define JOYERR_UNPLUGGED (JOYERR_BASE+7) /*joystick is unplugged */

     根据它,我们可以判断电脑当前否有手柄连接。

    输出部分:

    键盘模拟部们,我们只需要使用一个很简单的函数keyevent

    void keybd_event(BYTE bVk,BYTE bScan,DWORD dwFlags,DWORD dwExtralnfo);

    参数:   

    bVk:定义一个虚拟键码。键码值必须在1~254之间。   

    bScan:定义该键的硬件扫描码。   

    dwFlags:定义函数操作的名个方面的一个标志位集。应用程序可使用如下一些预定义常数的组合设置标志位。   

    KEYEVENTF_EXETENDEDKEY:若指定该值,则扫描码前一个值为OXEO(224)的前缀字节。   

    KEYEVENTF_KEYUP:若指定该值,该键将被释放;若未指定该值,该键交被接下。 (其实就是一个是0一个是2,0表示键按下,1表示键弹起) 

    dwExtralnfo:定义与击键相关的附加的32位值。

    表面上看着好像很点乱,其实没那么复杂。

    给一个使用实例:

    #define KEY 要模拟的键的ASCII码
    keybd_event(KEY,MapVirtualKey(KEY, 0),0,0);

    注意,这里使用MapVirtualKey()函数是有必要的。对于很多游戏,单纯的使用keybd_event(KEY,0,0,0)的模式是不能被正确识别的,

    换句话说,游戏程序会把那些伪造的键盘信息过滤掉或根本不接受。但使用MapVirtualKey()后,大部分游戏就会识别到我们发送的键盘信息了。

    简单demo

    #include<stdio.h>
    #include<stdlib.h>
    #include<conio.h>
    #include<Windows.h>
    
    //添加joystick操作api的支持库
    #include<MMSystem.h>
    #pragma comment(lib, "Winmm.lib")
    
    int main(int argc, char* argv[])
    {
        JOYINFO joyinfo;    //定义joystick信息结构体
        JOYINFOEX joyinfoex;//定义joystick信息结构体
        joyinfoex.dwSize = sizeof(JOYINFOEX);
        joyinfoex.dwFlags = JOY_RETURNALL;
        while(1)
        {
            //读取手柄信息
            UINT joyNums;
            joyNums = joyGetNumDevs();
            //        printf("当前手柄数量:%d 
    ",joyNums);
            if (joyNums>=1)
            {
                MMRESULT joyreturn = joyGetPosEx(JOYSTICKID1, &joyinfoex);
                if(joyreturn == JOYERR_NOERROR)
                {
                    printf("当前X坐标:%d 
    ", joyinfoex.dwXpos);
                    printf("当前Y坐标:%d 
    ", joyinfoex.dwYpos);
                    printf("当前Z坐标:%d 
    ", joyinfoex.dwZpos);
                    printf("视点控制的当前位置:%d 
    ", joyinfoex.dwPOV);
                    printf("32个操纵杆按钮的当前状态:%d 
    ", joyinfoex.dwButtons);
                    printf("按下的当前按钮编号:%d
     ", joyinfoex.dwButtonNumber);;
                    printf("
    ");
                }else
                {
                    switch(joyreturn) 
                    {
                    case JOYERR_PARMS :
                        printf("bad parameters
    ");
                        break;
                    case JOYERR_NOCANDO :
                        printf("request not completed
    ");
                        break;
                    case JOYERR_UNPLUGGED :
                        printf("joystick is unplugged
    ");
                        break;
                    default:
                        printf("未知错误
    ");
                        break;
                    }
                }
            }
    
            if(kbhit()) break;
            Sleep(300);
        }
        return 0;
    }
  • 相关阅读:
    数据结构:数组、链表、栈、队列的理解
    JVM学习记录-JVM的内存结构管理和运行时数据区理解
    线程池ThreadPoolExecutor的一种扩展办法
    四级地址插件升级改造(京东商城地址选择插件)city-picker
    java8在Collection中新增加的方法removeIf
    使用lambda编程之延迟执行
    JSP的内置对象以及作用域。
    Netty 异步的、事件驱动的网络应用程序框架和工具
    Zookeeper 服务注册和发现
    Jetty 发布web服务
  • 原文地址:https://www.cnblogs.com/yangyuqing/p/10481630.html
Copyright © 2020-2023  润新知