[内核编程] 4.4 从请求中打印出按键信息

4.4 从请求中打印出按键信息

4.4.1 从缓冲区中获得KEYBOARD_INPUT_DATA

请求完成后,读到的信息在Irp_AssociatedIrp.SystemBuffer中。这里需要介绍一下这个缓冲区中的数据格式。这个缓冲区中可能含有n个KEYBOARD_INPUT_DATA 结构(这个结构在WDK的头文件中有定义)。

typedef struct _KEYBOARD_INPUT_DATA{
    //头文件里的解释是这样的:对设备\Device\KeyboardPort0,这个
    //值是0;对\Device\KeyboardPort1,这个值是 1,依次类推
    USHORT  UnitId;
    //扫描码
    USHORT  MakeCode;
    //一个标记。标记这是一个键释放还是其他的扫描码
    USHORT  Flags;
    //保留
    USHORT  Reserved;
    //扩展信息
    ULOG  ExtraInformation;
}KEYBOARD_INPUT_DATA,*PKEYBOARD_INPUT_DATA;

下面是Flags可能的取值。并不是完全明白。

#define KEY_MAKE 0
#define KEY_BREAK 1
#define KEY_E0 2
#define KEY_E1 4
#define KEY_TERMSRV_SET_LED 8
#define KEY_TERMSRV_SHADOW 0x10
#define KEY_TERMSRV_VKPACKET 0x20

至少有多少个这样的结构,取决于输入缓冲区到底有多长。实际上,这种结构的个数应该为:
                                size = buf_len / sizeof(KEYBOARD_INPUT_DATA);

 

4.4.2 从KEBOARD_INPUT_DATA中得到键

KEYBOARD_INPUT_DATA下面的MakeCode就是扫描码。对于Flags,这里只需考虑KEY_BREAK(0)——按下,和KEY_BREAK(非0)——弹起,两种可能。

相关处理代码在c2pReadComplete函数中:

         KeyData = (PKEYBOARD_INPUT_DATA)buf;
        // 获得这个缓冲区的长度。一般的说返回值有多长都保存在
        // Information中。
        buf_len = Irp->IoStatus.Information;
        numKeys = buf_len / sizeof(KEYBOARD_INPUT_DATA);
        //… 这里可以做进一步的处理。我这里很简单的打印出所有的扫
        // 描码。
        //for(i=0;i<buf_len;++i)
        for(i=0;i<numKeys;++i)
        {
            //DbgPrint("ctrl2cap: %2x\r\n", buf[i]);
            DbgPrint("\n");
            DbgPrint("numKeys : %d",numKeys);
            DbgPrint("ScanCode: %x ", KeyData->MakeCode ); 
            DbgPrint("%s\n", KeyData->Flags ?"Up" : "Down" );
            print_keystroke((UCHAR)KeyData->MakeCode);

            if( KeyData->MakeCode == CAPS_LOCK) 
            { 
                KeyData->MakeCode = LCONTROL; 
            } 
        }    

 

4.4.3 从MakeCode到实际字符

// flags for keyboard status
#define    S_SHIFT                1
#define    S_CAPS                2
#define    S_NUM                4

//这是一个标记,用来保存当前键盘的状态。其中有3个位,分别表示
//Caps Lock 键、Num Lock 键 和 Shift 键是否按下了
static int kb_status = S_NUM;
void __stdcall print_keystroke(UCHAR sch)
{
    UCHAR    ch = 0;
    int        off = 0;

    if ((sch & 0x80) == 0)    //make
    {
        //如果按下了字母或者数字等可见字符
        if ((sch < 0x47) || 
            ((sch >= 0x47 && sch < 0x54) && (kb_status & S_NUM))) // Num Lock
        {
            //最终得到哪个字符必须由Caps Lock 和 Num Lock 及 Shift这几个键
            //的状态来决定,所以写在一张表中
            ch = asciiTbl[off+sch];
        }

        switch (sch)
        {
        //Caps Lock 键和 Num Lock键类似,都是“按下两次”等于没按过一样的“反复键”
        //所以这里用异或来设置标志。也就是说,按一次起作用,再按一次就不起作用了
        case 0x3A:
            kb_status ^= S_CAPS;
            break;
        
        //注意 Shift键的特点
        //(1)Shift键有两个,左右各一个,扫描码互不相同
        //(2)Shift键是按下起作用,弹起则作用消失,所以这里用或来设置标记
        case 0x2A:
        case 0x36:
            kb_status |= S_SHIFT;
            break;
        
        //Num Lock 键
        case 0x45:
            kb_status ^= S_NUM;
        }
    }
    else        //break
    {
        if (sch == 0xAA || sch == 0xB6)
            kb_status &= ~S_SHIFT;
    }

    if (ch >= 0x20 && ch < 0x7F)
    {
        DbgPrint("%C \n",ch);
    }

}

 

posted @ 2014-11-02 11:50  .....?  阅读(1008)  评论(0编辑  收藏  举报