• hge source explor 0x5 input module


    Input Module

      前面提到输入事件,那么对输入事件分类,分类如下

    /*
    ** HGE Input Event type constants
    */
    #define INPUT_KEYDOWN          1
    #define INPUT_KEYUP            2
    #define INPUT_MBUTTONDOWN      3
    #define INPUT_MBUTTONUP        4
    #define INPUT_MOUSEMOVE        5
    #define INPUT_MOUSEWHEEL       6

      接下来看每个函数


    _InputInit

      在引擎中初始化鼠标和键盘信息,在引擎 的初始化过程(构造函数)中会遇到(system.cpp:hge_impl)。

    void HGE_Impl::_InputInit()
    {
        POINT    pt;
        GetCursorPos(&pt);
        ScreenToClient(hwnd, &pt);
        Xpos = (float)pt.x;
        Ypos = (float)pt.y;
    
        memset(&keyz, 0, sizeof(keyz));
    }
    _InputInit

    _UpdateMouse

      这个函数会在主循环(system.cpp:system_start)中被调用,每一帧都更新鼠标的信息。

      1.更新获得鼠标的位置;2.判断如果鼠标被按下(bCaptured==true)同时在游戏窗口内,则设置标志bMouseOver(鼠标是否在游戏窗口内)。

    void HGE_Impl::_UpdateMouse()
    {
        POINT    pt;
        RECT    rc;
    
        GetCursorPos(&pt);
        GetClientRect(hwnd, &rc);
        MapWindowPoints(hwnd, NULL, (LPPOINT)&rc, 2);
    
        if(bCaptured || (PtInRect(&rc, pt) && WindowFromPoint(pt)==hwnd))
            bMouseOver=true;
        else
            bMouseOver=false;
    }
    _UpdateMouse

    _BuildEvent(int type, int key, int scan, int flags, int x, int y)  核心!核心!核心!

      在这个函数中,根据type的不同选填不同的参数,创建不同的事件,填写事件结构,在window的消息处理函数中调用。(system.cpp:WindowProc)

    • 将事件类型设置为传递过来的类型;键码设置为0;鼠标位置更新为传递进来的x,y
    • GetKeyboardState(kbstate)获取当时的键盘信息
    • 按键按下类型:如果重复按下则不更新,否则更新引擎所管理的按键信息(全局)
    • 按键弹起类型:更新按键信息弹起信息
    • 滚轮类型:是的情况下,按键设置为0,将滚轮属性定位key值;否的情况下,则将按键属性更新为key值,否则为0
    • 鼠标按键按下类型:设置按键信息;设置焦点
    • 鼠标按键弹起类型:设置按键信息,取消焦点;重新设置鼠标坐标,更新鼠标位置信息
    • 对于功能键的属性的按键的更新
    • 如果传递进来的x=-1,则为按键类型的事件,现在讲事件的鼠标信息更新;否则判断鼠标是否出界,并更新鼠标位置
    • 将事件加入输入事件队列
    • 更新引擎所掌握的鼠标位置、按键信息
    void HGE_Impl::_BuildEvent(int type, int key, int scan, int flags, int x, int y)
    {
        CInputEventList *last, *eptr=new CInputEventList;
        unsigned char kbstate[256];
        POINT pt;
    
        eptr->event.type=type;
        eptr->event.chr=0;
        pt.x=x; pt.y=y;
    
        GetKeyboardState(kbstate);
        if(type==INPUT_KEYDOWN)
        {
            if((flags & HGEINP_REPEAT) == 0) keyz[key] |= 1;
            ToAscii(key, scan, kbstate, (unsigned short *)&eptr->event.chr, 0);
        }
        if(type==INPUT_KEYUP)
        {
            keyz[key] |= 2;
            ToAscii(key, scan, kbstate, (unsigned short *)&eptr->event.chr, 0);
        }
        if(type==INPUT_MOUSEWHEEL)
        {
            eptr->event.key=0; eptr->event.wheel=key;
            ScreenToClient(hwnd,&pt);
        }
        else { eptr->event.key=key; eptr->event.wheel=0; }
    
        if(type==INPUT_MBUTTONDOWN)
        {
            keyz[key] |= 1;
            SetCapture(hwnd);
            bCaptured=true;
        }
        if(type==INPUT_MBUTTONUP)
        {
            keyz[key] |= 2;
            ReleaseCapture();
            Input_SetMousePos(Xpos, Ypos);
            pt.x=(int)Xpos; pt.y=(int)Ypos;
            bCaptured=false;
        }
        
        if(kbstate[VK_SHIFT] & 0x80) flags|=HGEINP_SHIFT;
        if(kbstate[VK_CONTROL] & 0x80) flags|=HGEINP_CTRL;
        if(kbstate[VK_MENU] & 0x80) flags|=HGEINP_ALT;
        if(kbstate[VK_CAPITAL] & 0x1) flags|=HGEINP_CAPSLOCK;
        if(kbstate[VK_SCROLL] & 0x1) flags|=HGEINP_SCROLLLOCK;
        if(kbstate[VK_NUMLOCK] & 0x1) flags|=HGEINP_NUMLOCK;
        eptr->event.flags=flags;
    
        if(pt.x==-1) { eptr->event.x=Xpos;eptr->event.y=Ypos; }
        else
        {
            if(pt.x<0) pt.x=0;
            if(pt.y<0) pt.y=0;
            if(pt.x>=nScreenWidth) pt.x=nScreenWidth-1;
            if(pt.y>=nScreenHeight) pt.y=nScreenHeight-1;
    
            eptr->event.x=(float)pt.x;
            eptr->event.y=(float)pt.y;
        }
    
        eptr->next=0; 
    
        if(!queue) queue=eptr;
        else
        {
            last=queue;
            while(last->next) last=last->next;
            last->next=eptr;
        }
    
        if(eptr->event.type==INPUT_KEYDOWN || eptr->event.type==INPUT_MBUTTONDOWN)
        {
            VKey=eptr->event.key;Char=eptr->event.chr;
        }
        else if(eptr->event.type==INPUT_MOUSEMOVE)
        {
            Xpos=eptr->event.x;Ypos=eptr->event.y;
        }
        else if(eptr->event.type==INPUT_MOUSEWHEEL)
        {
            Zpos+=eptr->event.wheel;
        }
    }
    _BuildEvent

    _ClearQueue

      清理输入事件队列,清理键盘,在主循环中会被调用。

    void HGE_Impl::_ClearQueue()
    {
        CInputEventList *nexteptr, *eptr=queue;
    
        memset(&keyz, 0, sizeof(keyz));
        
        while(eptr)
        {
            nexteptr=eptr->next;
            delete eptr;
            eptr=nexteptr;
        }
    
        queue=0; VKey=0; Char=0; Zpos=0;
    }
    _ClearQueue

    Input_GetEvent(hgeInputEvent *event)

      获取输入事件队列的第一个事件。

    bool CALL HGE_Impl::Input_GetEvent(hgeInputEvent *event)
    {
        CInputEventList *eptr;
    
        if(queue)
        {
            eptr=queue;
            memcpy(event, &eptr->event, sizeof(hgeInputEvent));
            queue=eptr->next;
            delete eptr;
            return true;
        }
        
        return false;
    }
    Input_GetEvent

     Input_GetMousePos(float *x, float *y)

      获取鼠标当前的位置信息。

    void CALL HGE_Impl::Input_GetMousePos(float *x, float *y)
    {
        *x=Xpos; *y=Ypos;
    }
    Input_GetMousePos

     Input_SetMousePos(float x, float y)

      设置鼠标位置:需要先ClientToScreen,再SetCursorPos。

    void CALL HGE_Impl::Input_SetMousePos(float x, float y)
    {
        POINT pt;
        pt.x=(long)x; pt.y=(long)y;
        ClientToScreen(hwnd, &pt);
        SetCursorPos(pt.x,pt.y);
    }
    Input_SetMousePos

     Input_GetMouseWheel

      获取鼠标的滚轮信息。

    int CALL HGE_Impl::Input_GetMouseWheel()
    {
        return Zpos;
    }
    Input_GetMouseWheel

     Input_IsMouseOver

       返回鼠标是否在游戏窗口上。

    bool CALL HGE_Impl::Input_IsMouseOver()
    {
        return bMouseOver;
    }
    Input_IsMouseOver

    Input_GetKeyState(int key)

      返回键盘按键key是否被按键,在这里并没有调用引擎管理的当前键盘的状态来获取,而是直接通过GetKeyState(key)&0x8000来获取即时信息。

    bool CALL HGE_Impl::Input_GetKeyState(int key)
    {
        return ((GetKeyState(key) & 0x8000) != 0);
    }
    Input_GetKeyState

     Input_KeyDown

       按键是否被按下,这里按键按下是通过查看引擎管理的键盘信息来查看。

    bool CALL HGE_Impl::Input_KeyDown(int key)
    {
        return (keyz[key] & 1) != 0;
    }
    Input_KeyDown

     Input_KeyUp

      按键是否弹起,这里也是通过引擎管理的键盘信息来查看。

    bool CALL HGE_Impl::Input_KeyUp(int key)
    {
        return (keyz[key] & 2) != 0;
    }
    Input_KeyUp

     Input_GetKeyName

      获取某一个按键的名字。

    char* CALL HGE_Impl::Input_GetKeyName(int key)
    {
        return KeyNames[key];
    }
    Input_GetKeyName

     Input_GetKey

      获取当前被触发的按键。   

    int CALL HGE_Impl::Input_GetKey()
    {
        return VKey;
    }
    Input_GetKey

     Input_GetChar

      获取当前被触发按键的键码 。

    int CALL HGE_Impl::Input_GetChar()
    {
        return Char;
    }
    Input_GetChar

  • 相关阅读:
    android 11中报new Handler()已过时
    My WelcomeApplet
    设计模式(五):抽象工厂方法(多个工厂方法的组合)
    [Redis知识体系] 一文全面总结Redis知识体系
    RocketMq的事务消息发送方法,消息零丢失的实现方式,代码流程讲解,干货分享
    充血枚举的用法
    Rocketmq的启动jvm配置解析-runbroker.sh
    springboot+mybatis整合,基本框架
    rabbitmq单机入门安装教程(ubuntu环境 亲测有效)
    常用表单验证插件
  • 原文地址:https://www.cnblogs.com/yoru/p/5506925.html
Copyright © 2020-2023  润新知