基於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 \n",joyNums);
        if (joyNums>=1)
        {
            MMRESULT joyreturn = joyGetPosEx(JOYSTICKID1, &joyinfoex);
            if(joyreturn == JOYERR_NOERROR)
            {
                printf("當前X坐標:%d \n", joyinfoex.dwXpos);
                printf("當前Y坐標:%d \n", joyinfoex.dwYpos);
                printf("當前Z坐標:%d \n", joyinfoex.dwZpos);
                printf("視點控制的當前位置:%d \n", joyinfoex.dwPOV);
                printf("32個操縱桿按鈕的當前狀態:%d \n", joyinfoex.dwButtons);
                printf("按下的當前按鈕編號:%d\n ", joyinfoex.dwButtonNumber);;
                printf("\n");
            }else
            {
                switch(joyreturn) 
                {
                case JOYERR_PARMS :
                    printf("bad parameters\n");
                    break;
                case JOYERR_NOCANDO :
                    printf("request not completed\n");
                    break;
                case JOYERR_UNPLUGGED :
                    printf("joystick is unplugged\n");
                    break;
                default:
                    printf("未知錯誤\n");
                    break;
                }
            }
        }

        if(kbhit()) break;
        Sleep(300);
    }
    return 0;
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM