zoukankan      html  css  js  c++  java
  • cocos2dx 在windows上实现键盘输入

     

    cocos2d主要面向的是触摸屏幕设备的,在WINDOWS下的定位感觉多多少少就是相当于一个模拟器,因此并没有太多的PC下重要的键盘支持。然而响应键盘消息对于调试来说可以提供不少方便。下边就通过更改cocos2d-x的源码来添加键盘消息响应。

     

    一,打开cocos2dxincludeCCLayer.h

    在CCLayer类的public下添加

    1
    virtual  void  processWin32KeyPress( UINT  message, WPARAM  wParam, LPARAM  lParam) {}
    1
      

    二,打开cocos2dxplatformwin32CCEGLView_win32.h

    在CCEGLView类的定义上边声明

    1
    class  CCLayer;

    在CCEGLView类的private下添加变量

    1
    CCLayer *m_pLayWin32Key;

    在public下添加函数

    1
    2
    3
    4
    void  SetWin32KeyLayer(CCLayer *pLayer)
    {
         m_pLayWin32Key = pLayer;
    }
    1
      

    三,打开cocos2dxplatformwin32CCEGLView_win32.cpp

    在文件开始部分添加

    1
    #include "CCLayer.h"

    在CCEGLView构造函数中初始化CCLayer(NULL)

    在WindowProc函数的开始部分添加

    1
    2
    3
    4
    if (NULL != m_pLayWin32Key)
    {
         m_pLayWin32Key->processWin32KeyPress(message, wParam, lParam);
    }
    1
      

    四,重新生成libcocos2d将新生成的libcocos2d.lib和libcocos2d.dll放到相应位置

    这样就可以在自己的程序中捕获win32的消息了。只需要在某个Layer的初始化部分添加

    1
    CCDirector::sharedDirector()->getOpenGLView()->SetWin32KeyLayer( this );

    然后重新继承虚函数processWin32KeyPress,就可以处理消息了。当然在Layer销毁前别忘记调用

    1
    CCDirector::sharedDirector()->getOpenGLView()->SetWin32KeyLayer(NULL);
    1
      

    另外,前几天想到了一个更加方便的办法

    在模拟键盘的源文件中添加以下宏

    1
    2
    3
    4
    5
    #if(CC_TARGET_PLATFORM == CC_PLATFORM_WIN32)
    #include <windows.h>
    #define KEY_DOWN(vk_code) (GetAsyncKeyState(vk_code) & 0x8000 ? 1 : 0)
    #define KEY_UP(vk_code) (GetAsyncKeyState(vk_code) & 0x8000 ? 0 : 1)
    #endif

    然后在UPDATE函数中调用

    1
    2
    3
    4
    5
    6
    #if(CC_TARGET_PLATFORM == CC_PLATFORM_WIN32)   
    if (KEY_DOWN(VK_DOWN))
    {
         // do something
    }
    #endif

    这里响应的是下箭头键,需要响应其他键可以参考WinUser.h中其他虚拟键的宏。


    要注意的是如何添加字符输入呢:

    void HelloWorld:: processWin32KeyPress(UINT message,
    WPARAM wParam,
    LPARAM lParam)
    {
    WPARAM keyChar = 0x20;
    switch (message)
        {
    case WM_LBUTTONDOWN:{
    CCLog("WM_LBUTTONDOWN");
    break;
    }
    case WM_CHAR:{
                keyChar = wParam;
                CCLog("WM_CHAR: %d", keyChar);//字符输入部分
    break;
             } 
    }
    }


    windows sdk 键盘输入:

    因为大多数的PC只有一个键盘,所以所有运行中的WINDOWS程序必须共用它。WINDOWS 将负责把击键消息送到具有输入焦点的那个应用程序中去。尽管屏幕上可能同时有几个应用程序窗口,但一个时刻仅有一个窗口有输入焦点。有输入焦点的那个应用程序的标题条总是高亮度显示的。 实际上您可以从两个角度来看键盘消息:一是您可以把它看成是一大堆的按键消息的集合,在这种情况下,当您按下一个键时,WINDOWS就会发送一个WM_KEYDOWN给有输入焦点的那个应用程序,提醒它有一个键被按下。当您释放键时,WINDOWS又会发送一个WM_KYEUP消息,告诉有一个键被释放。您把每一个键当成是一个按钮;另一种情况是:您可以把键盘看成是字符输入设备。当您按下“a”键时,WINDOWS发送一个WM_CHAR消息给有输入焦点的应用程序,告诉它“a”键被按下。实际上WINDOWS 内部发送WM_KEYDOWN和WWM_KEYUP消息给有输入焦点的应用程序,而这些消息将通过调用TranslateMessage翻译成WM_CHAR消息。WINDOWS窗口过程函数将决定是否处理所收到的消息,一般说来您不大会去处理WM_KEYDOWN、WM_KEYUP消息,在消息循环中TranslateMessage函数会把上述消息转换成WM_CHAR消息。在我们的课程中将只处理WM_CHAR。

    例子: (见光盘FirstWindow4)

    #include "Windows.h"
    #include "tchar.h"

    HWND hWinMain;
    TCHAR szClassName[] = _T("MyClass");
    TCHAR szCaptionMain[] = _T("My First Window!");
    TCHAR FontName[] = _T("script");
    WNDCLASSEX stdWndClass;
    WPARAM keyChar = 0x20; //0x20是空格的ascii码,保证没有按键的时候程序正常显示。
    LRESULT CALLBACK ProcWinMain(   HWND hWnd, 
                           UINT Msg, 
                           WPARAM wParam, 
                           LPARAM lParam 
    )
    {
        PAINTSTRUCT stPs;
        HDC hDC;
        HFONT hFont,hOldFont;
        switch(Msg)
        {
            case WM_PAINT:
            {
                hDC = BeginPaint(hWnd,&stPs);
                hFont = CreateFont(24,16,0,0,400,0,0,0,OEM_CHARSET,OUT_DEFAULT_PRECIS,
                    CLIP_DEFAULT_PRECIS,DEFAULT_QUALITY,DEFAULT_PITCH | FF_SCRIPT,FontName);

                hOldFont = (HFONT)SelectObject(hDC,hFont);
                SetTextColor(hDC,RGB(200,200,50));
                SetBkColor(hDC,RGB(0,0,255));
                TextOut(hDC,0,0,(char *)&keyChar,1);
                SelectObject(hDC,hOldFont);
                EndPaint(hWnd,&stPs);
            }
            break;

            case WM_CHAR:
                {
                    keyChar = wParam;
                    InvalidateRect(hWnd,NULL,TRUE);
                }
                break;
            case WM_DESTROY:
            {
                PostQuitMessage(NULL);
            }
            break;

            default:
                return DefWindowProc(hWnd, Msg, wParam, lParam ); 
        }
        return 0;
    }

    int WINAPI WinMain(     HINSTANCE hInstance,
                            HINSTANCE hPrevInstance,
                            LPSTR lpCmdLine,
                            int nCmdShow
    )
    {
        MSG stMsg;
        WNDCLASSEX stdWndClass;
        RtlZeroMemory(&stdWndClass, sizeof(stdWndClass));
        stdWndClass.hCursor = LoadCursor(0,IDC_ARROW);
        stdWndClass.cbSize = sizeof(stdWndClass);
        stdWndClass.style = CS_HREDRAW|CS_VREDRAW;
        stdWndClass.lpfnWndProc = ProcWinMain;
        stdWndClass.hbrBackground = (HBRUSH)COLOR_WINDOW;
        stdWndClass.lpszClassName = szClassName;
        stdWndClass.hInstance = hInstance;

        RegisterClassEx(&stdWndClass);

        hWinMain = CreateWindowEx(WS_EX_CLIENTEDGE,szClassName,szCaptionMain,
           WS_OVERLAPPEDWINDOW,100,100,600,400,NULL,NULL,hInstance,NULL);

        if(!hWinMain)
            return 0;
        
        ShowWindow(hWinMain,SW_SHOWNORMAL);
        UpdateWindow(hWinMain);


        while(GetMessage(&stMsg,NULL,0,0))
        {
            TranslateMessage(&stMsg);
            DispatchMessage(&stMsg);
        }

        return stMsg.wParam;
    }

    分析:


    WPARAM keyChar = 0x20; 
    这个变量将保存从键盘接收到的字符。因为它是在窗口过程中通过WPARAM型变量传送的,所以我们简单地把它定义为WPARAM型。由于我们的窗口在初次刷新时(也即刚被创建的那一次)是没有键盘输入的所以我们把他设成空格符(20h),这样显示时您就什么都看不见。

                case WM_CHAR:
                {
                      keyChar = wParam;
                      InvalidateRect(hWnd,NULL,TRUE);
                }

    这一段是用来处理WM_CHAR消息的。它把接收到的字符放入变量keyChar 中,接着调用InvalidateRect,而InvalidateRect使得窗口的客户区无效,这样它会发出WM_PAINT消息,而WM_PAINT消息迫使WINDOWS重新绘制它的客户区。该函数的语法如下:

    BOOL InvalidateRect(

                                     HWND hWnd// handle to window 

                                     CONST RECT* lpRect// rectangle coordinates 

                                     BOOL bErase // erase state 

                                    );

    lpRect是指向客户区我们想要其无效的一个正方形结构体的指针。如果该值等于NULL,则整个客户区都无效;布尔值bErase告诉WINDOWS是否擦除背景,如果是TRUE,则WINDOWS在调用BeginPaint函数时把背景擦掉。 所以我们此处的做法是:我们将保存所有有关重绘客户区的数据,然后发送WM_PAINT消息,处理该消息的程序段然后根据相关数据重新绘制客户区。尽管这么做事有点像走了弯路,但WINDOWS要处理那么庞大的消息群,没有一定的规矩可不行。 实际上我们完全可以通过调用GetDC 获得设备上下文句柄,然后绘制字符,然后再调用ReleaseDC释放设备上下文句柄,毫无疑问这样也能在客户区绘制出正确的字符。但是如果这之后接收到WM_PAINT消息要处理时,客户区会重新刷新,而我们这稍前所绘制的字符就会消失掉。所以为了让字符一直正确地显示,就必须把它们放到WM_PAINT的处理过程中处理。而在本消息处理中发送WM_PAINT消息即可。

        TextOut(hDC,0,0,(char *)&keyChar,1);

    在调用InvalidateRect时,WM_PAINT消息被发送到了WINDOWS窗口处理过程,程序流程转移到处理WM_PAINT消息的程序段,然后调用BeginPaint得到设备上下文的句柄,再调用TextOut在客户区的(0,0)处输出保存的按键字符。这样无论您按什么键都能在客户区的左上角显示,不仅如此,无论您怎么缩放窗口(迫使WINDOWS重新绘制它的客户区),字符都会在正确的地方显示,所以必须把所有重要的绘制动作都放到处理WM_PAINT消息的程序段中去。

  • 相关阅读:
    VUEX
    使用element框架 增加router路由
    VUE目录
    elementUI 创建
    VUE组件(父子组件)
    VUE操作DOM获取HTML、删除HTML、插入HTML
    VUE网络交互axios(网络请求库)
    VUE 或者JS 常用数据类型及方法:字符串、数组、对象
    VUE实际案例--计数器(商城数量加减)
    VUE学习 --数据类型、el挂点、指令等
  • 原文地址:https://www.cnblogs.com/riasky/p/3435909.html
Copyright © 2011-2022 走看看